vrpiu.c revision 1.1 1 /* $NetBSD: vrpiu.c,v 1.1 1999/12/28 03:15:18 takemura Exp $ */
2
3 /*
4 * Copyright (c) 1999 Shin Takemura All rights reserved.
5 * Copyright (c) 1999 PocketBSD Project. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/device.h>
33 #include <sys/kernel.h>
34
35 #include <dev/wscons/wsconsio.h>
36 #include <dev/wscons/wsmousevar.h>
37
38 #include <machine/bus.h>
39
40 #include <hpcmips/vr/vripvar.h>
41 #include <hpcmips/vr/cmureg.h>
42 #include <hpcmips/vr/vrpiuvar.h>
43 #include <hpcmips/vr/vrpiureg.h>
44
45 /*
46 * contant and macro definitions
47 */
48 #define VRPIUDEBUG
49 #ifdef VRPIUDEBUG
50 int vrpiu_debug = 0;
51 #define DPRINTF(arg) if (vrpiu_debug) printf arg;
52 #else
53 #define DPRINTF(arg)
54 #endif
55
56 #define SCALE (1024*1024)
57
58 /*
59 * data types
60 */
61 /* struct vrpiu_softc is defined in vrpiuvar.h */
62
63 /*
64 * function prototypes
65 */
66 static int vrpiumatch __P((struct device *, struct cfdata *, void *));
67 static void vrpiuattach __P((struct device *, struct device *, void *));
68
69 static void vrpiu_write __P((struct vrpiu_softc *, int, unsigned short));
70 static u_short vrpiu_read __P((struct vrpiu_softc *, int));
71
72 static int vrpiu_intr __P((void *));
73 static void vrpiu_reset_param __P((struct vrpiu_softc *sc));
74 static void vrpiu_timeout __P((void *));
75 #ifdef DEBUG
76 static void vrpiu_dump_cntreg __P((unsigned int cmd));
77 #endif
78
79 static int vrpiu_enable __P((void *));
80 static int vrpiu_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
81 static void vrpiu_disable __P((void *));
82
83 /* mra is defined in mra.c */
84 int mra_Y_AX1_BX2_C __P((int *y, int ys, int *x1, int x1s, int *x2, int x2s,
85 int n, int scale, int *a, int *b, int *c));
86
87 /*
88 * static or global variables
89 */
90 struct cfattach vrpiu_ca = {
91 sizeof(struct vrpiu_softc), vrpiumatch, vrpiuattach
92 };
93
94 const struct wsmouse_accessops vrpiu_accessops = {
95 vrpiu_enable,
96 vrpiu_ioctl,
97 vrpiu_disable,
98 };
99
100 /*
101 * function definitions
102 */
103 static inline void
104 vrpiu_write(sc, port, val)
105 struct vrpiu_softc *sc;
106 int port;
107 unsigned short val;
108 {
109 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
110 }
111
112 static inline u_short
113 vrpiu_read(sc, port)
114 struct vrpiu_softc *sc;
115 int port;
116 {
117 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, port);
118 }
119
120 static int
121 vrpiumatch(parent, cf, aux)
122 struct device *parent;
123 struct cfdata *cf;
124 void *aux;
125 {
126 return 1;
127 }
128
129 static void
130 vrpiuattach(parent, self, aux)
131 struct device *parent;
132 struct device *self;
133 void *aux;
134 {
135 struct vrpiu_softc *sc = (struct vrpiu_softc *)self;
136 struct vrip_attach_args *va = aux;
137 struct wsmousedev_attach_args wsmaa;
138
139 bus_space_tag_t iot = va->va_iot;
140 bus_space_handle_t ioh;
141
142 if (bus_space_map(iot, va->va_addr, 1, 0, &ioh)) {
143 printf(": can't map bus space\n");
144 return;
145 }
146
147 sc->sc_iot = iot;
148 sc->sc_ioh = ioh;
149 sc->sc_vrip = va->va_vc;
150
151 /*
152 * disable device until vrpiu_enable called
153 */
154 sc->sc_stat = VRPIU_STAT_DISABLE;
155
156 vrpiu_reset_param(sc);
157 #if 1
158 /*
159 * XXX, calibrate parameters
160 */
161 {
162 static struct sample {
163 int xraw, yraw, x, y;
164 } D[] = {
165 /* samples got on my MC-R500 */
166 { 502, 486, 320, 120 },
167 { 55, 109, 0, 0 },
168 { 54, 913, 0, 239 },
169 { 973, 924, 639, 239 },
170 { 975, 123, 639, 0 },
171 };
172 int s = sizeof(*D);
173 int n = sizeof(D)/s;
174
175 sc->sc_prmxs = 640;
176 sc->sc_prmys = 240;
177
178 if (mra_Y_AX1_BX2_C(&D->x, s, &D->xraw, s, &D->yraw, s, n,
179 SCALE, &sc->sc_prmax, &sc->sc_prmbx,
180 &sc->sc_prmcx) ||
181 mra_Y_AX1_BX2_C(&D->y, s, &D->xraw, s, &D->yraw, s, n,
182 SCALE, &sc->sc_prmay,
183 &sc->sc_prmby, &sc->sc_prmcy)) {
184 printf(": MRA error");
185 vrpiu_reset_param(sc);
186 } else {
187 DPRINTF(("Ax=%d Bx=%d Cx=%d\n",
188 sc->sc_prmax, sc->sc_prmbx, sc->sc_prmcx));
189 DPRINTF(("Ay=%d By=%d Cy=%d\n",
190 sc->sc_prmay, sc->sc_prmby, sc->sc_prmcy));
191 }
192 }
193 #endif
194
195 /* install interrupt handler and enable interrupt */
196 if (!(sc->sc_handler =
197 vrip_intr_establish(va->va_vc, va->va_intr, IPL_TTY,
198 vrpiu_intr, sc))) {
199 printf (": can't map interrupt line.\n");
200 return;
201 }
202
203 /* mask level2 interrupt, stop scan sequencer and mask clock to piu */
204 vrpiu_disable(sc);
205
206 printf("\n");
207
208 wsmaa.accessops = &vrpiu_accessops;
209 wsmaa.accesscookie = sc;
210
211 /*
212 * attach the wsmouse
213 */
214 sc->sc_wsmousedev = config_found(self, &wsmaa, wsmousedevprint);
215 }
216
217 int
218 vrpiu_enable(v)
219 void *v;
220 {
221 struct vrpiu_softc *sc = v;
222 int s;
223 unsigned int cnt;
224
225 DPRINTF(("%s(%d): vrpiu_enable()\n", __FILE__, __LINE__));
226 if (sc->sc_stat != VRPIU_STAT_DISABLE)
227 return EBUSY;
228
229 /* supply clock to PIU */
230 __vrcmu_supply(CMUMSKPIU, 1);
231
232 /* Scan interval 0x7FF is maximum value */
233 vrpiu_write(sc, PIUSIVL_REG_W, 0x7FF);
234
235 s = spltty();
236
237 /* clear interrupt status */
238 vrpiu_write(sc, PIUINT_REG_W, PIUINT_ALLINTR);
239
240 /* Disable -> Standby */
241 cnt = PIUCNT_PIUPWR |
242 PIUCNT_PIUMODE_COORDINATE |
243 PIUCNT_PADATSTART | PIUCNT_PADATSTOP;
244 vrpiu_write(sc, PIUCNT_REG_W, cnt);
245
246 /* save pen status, touch or release */
247 cnt = vrpiu_read(sc, PIUCNT_REG_W);
248
249 /* Level2 interrupt register setting */
250 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 1);
251
252 /*
253 * Enable scan sequencer operation
254 * Standby -> WaitPenTouch
255 */
256 cnt |= PIUCNT_PIUSEQEN;
257 vrpiu_write(sc, PIUCNT_REG_W, cnt);
258
259 /* transit status DISABLE -> TOUCH or RELEASE */
260 sc->sc_stat = (cnt & PIUCNT_PENSTC) ?
261 VRPIU_STAT_TOUCH : VRPIU_STAT_RELEASE;
262
263 sc->sc_timeout = 1;
264
265 splx(s);
266
267 return 0;
268 }
269
270 void
271 vrpiu_disable(v)
272 void *v;
273 {
274 struct vrpiu_softc *sc = v;
275 int s;
276
277 DPRINTF(("%s(%d): vrpiu_disable()\n", __FILE__, __LINE__));
278
279 /* Set level2 interrupt register to mask interrupts */
280 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 0);
281
282 sc->sc_stat = VRPIU_STAT_DISABLE;
283
284 /* Disable scan sequencer operation and power off */
285 vrpiu_write(sc, PIUCNT_REG_W, 0);
286
287 /* mask clock to PIU */
288 __vrcmu_supply(CMUMSKPIU, 1);
289
290 s = spltty();
291 if (!sc->sc_timeout) {
292 untimeout(vrpiu_timeout, sc);
293 }
294 splx(s);
295 }
296
297 int
298 vrpiu_ioctl(v, cmd, data, flag, p)
299 void *v;
300 u_long cmd;
301 caddr_t data;
302 int flag;
303 struct proc *p;
304 {
305 struct vrpiu_softc *sc = v;
306
307 DPRINTF(("%s(%d): vrpiu_ioctl(%08lx)\n", __FILE__, __LINE__, cmd));
308
309 switch (cmd) {
310 case WSMOUSEIO_GTYPE:
311 *(u_int *)data = WSMOUSE_TYPE_PS2;
312 break;
313
314 case WSMOUSEIO_SRES:
315 printf("%s(%d): WSMOUSRIO_SRES is not supported",
316 __FILE__, __LINE__);
317 break;
318
319 default:
320 return (-1);
321 }
322 return (0);
323 }
324
325 /*
326 * PIU interrupt handler.
327 */
328 int
329 vrpiu_intr(arg)
330 void *arg;
331 {
332 struct vrpiu_softc *sc = arg;
333 unsigned int cnt, i;
334 unsigned int intrstat, page;
335 int tpx0, tpx1, tpy0, tpy1;
336 int x, y, xraw, yraw;
337
338 intrstat = vrpiu_read(sc, PIUINT_REG_W);
339
340 if (sc->sc_stat == VRPIU_STAT_DISABLE) {
341 /*
342 * the device isn't enabled. just clear interrupt.
343 */
344 vrpiu_write(sc, PIUINT_REG_W, intrstat);
345 return (0);
346 }
347
348 page = (intrstat & PIUINT_OVP) ? 1 : 0;
349 if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
350 tpx0 = vrpiu_read(sc, PIUPB(page, 0));
351 tpx1 = vrpiu_read(sc, PIUPB(page, 1));
352 tpy0 = vrpiu_read(sc, PIUPB(page, 2));
353 tpy1 = vrpiu_read(sc, PIUPB(page, 3));
354 }
355
356 if (intrstat & PIUINT_PADDLOSTINTR) {
357 page = page ? 0 : 1;
358 for (i = 0; i < 4; i++)
359 vrpiu_read(sc, PIUPB(page, i));
360 }
361
362 cnt = vrpiu_read(sc, PIUCNT_REG_W);
363 #ifdef DEBUG
364 if (vrpiu_debug)
365 vrpiu_dump_cntreg(cnt);
366 #endif
367
368 /* clear interrupt status */
369 vrpiu_write(sc, PIUINT_REG_W, intrstat);
370
371 #if 0
372 DPRINTF(("vrpiu_intr: OVP=%d", page));
373 if (intrstat & PIUINT_PADCMDINTR)
374 DPRINTF((" CMD"));
375 if (intrstat & PIUINT_PADADPINTR)
376 DPRINTF((" A/D"));
377 if (intrstat & PIUINT_PADPAGE1INTR)
378 DPRINTF((" PAGE1"));
379 if (intrstat & PIUINT_PADPAGE0INTR)
380 DPRINTF((" PAGE0"));
381 if (intrstat & PIUINT_PADDLOSTINTR)
382 DPRINTF((" DLOST"));
383 if (intrstat & PIUINT_PENCHGINTR)
384 DPRINTF((" PENCHG"));
385 DPRINTF(("\n"));
386 #endif
387 if (cnt & PIUCNT_PENSTC) {
388 if (sc->sc_stat == VRPIU_STAT_RELEASE) {
389 /*
390 * pen touch
391 */
392 DPRINTF(("PEN TOUCH\n"));
393 sc->sc_stat = VRPIU_STAT_TOUCH;
394 if (sc->sc_timeout) {
395 sc->sc_timeout = 0;
396 sc->sc_releasecount = 0;
397 timeout(vrpiu_timeout, sc, hz/3);
398 }
399 }
400 } else {
401 if (sc->sc_stat == VRPIU_STAT_TOUCH ||
402 sc->sc_stat == VRPIU_STAT_DRAG) {
403 /*
404 * pen release
405 */
406 DPRINTF(("RELEASE\n"));
407 sc->sc_stat = VRPIU_STAT_RELEASE;
408 if (!sc->sc_timeout) {
409 if (++sc->sc_releasecount == 2) {
410 untimeout(vrpiu_timeout, sc);
411 sc->sc_timeout = 1;
412 DPRINTF(("TAP!\n"));
413 /* button 0 DOWN */
414 wsmouse_input(sc->sc_wsmousedev,
415 (1 << 0),
416 0, 0, 0);
417 /* button 0 UP */
418 wsmouse_input(sc->sc_wsmousedev,
419 0, 0, 0, 0);
420 }
421 }
422 }
423 }
424
425 if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
426 if (!((tpx0 & PIUPB_VALID) && (tpx1 & PIUPB_VALID) &&
427 (tpy0 & PIUPB_VALID) && (tpy1 & PIUPB_VALID))) {
428 printf("vrpiu: internal error, data is not valid!\n");
429 } else {
430 tpx0 &= PIUPB_PADDATA_MASK;
431 tpx1 &= PIUPB_PADDATA_MASK;
432 tpy0 &= PIUPB_PADDATA_MASK;
433 tpy1 &= PIUPB_PADDATA_MASK;
434 #define ISVALID(n, c, m) ((c) - (m) < (n) && (n) < (c) + (m))
435 if (ISVALID(tpx0 + tpx1, 1024, 200) &&
436 ISVALID(tpx0 + tpx1, 1024, 200)) {
437 #if 0
438 DPRINTF(("%04x %04x %04x %04x\n",
439 tpx0, tpx1, tpy0, tpy1));
440 DPRINTF(("%3d %3d (%4d %4d)->", tpx0, tpy0,
441 tpx0 + tpx1, tpy0 + tpy1);
442 #endif
443 xraw = tpy1 * 1024 / (tpy0 + tpy1);
444 yraw = tpx1 * 1024 / (tpx0 + tpx1);
445 DPRINTF(("%3d %3d", xraw, yraw));
446
447 x = (sc->sc_prmax*xraw + sc->sc_prmbx*yraw) /
448 SCALE + sc->sc_prmcx;
449 y = (sc->sc_prmay*xraw + sc->sc_prmby*yraw) /
450 SCALE + sc->sc_prmcy;
451 if (x < 0) x = 0;
452 if (y < 0) y = 0;
453 if (sc->sc_prmxs <= x)
454 x = sc->sc_prmxs - 1;
455 if (sc->sc_prmys <= y)
456 y = sc->sc_prmys - 1;
457 DPRINTF(("->%4d %4d", x, y));
458 if (sc->sc_stat == VRPIU_STAT_TOUCH) {
459 sc->sc_stat = VRPIU_STAT_DRAG;
460 sc->sc_x = x;
461 sc->sc_y = y;
462 } else
463 if (sc->sc_stat == VRPIU_STAT_DRAG) {
464 DPRINTF((" delta %d %d",
465 x - sc->sc_x, y - sc->sc_y));
466 wsmouse_input(sc->sc_wsmousedev,
467 0, /* all buttons up */
468 x - sc->sc_x, /* dx */
469 y - sc->sc_y, /* dy */
470 0); /* dz */
471 sc->sc_x = x;
472 sc->sc_y = y;
473 }
474 DPRINTF(("\n"));
475 }
476 }
477 }
478
479 if (intrstat & PIUINT_PADDLOSTINTR) {
480 cnt |= PIUCNT_PIUSEQEN;
481 vrpiu_write(sc, PIUCNT_REG_W, cnt);
482 }
483
484 return 0;
485 }
486
487 void
488 vrpiu_reset_param(sc)
489 struct vrpiu_softc *sc;
490 {
491 sc->sc_prmax = SCALE;
492 sc->sc_prmbx = 0;
493 sc->sc_prmcx = 0;
494 sc->sc_prmxs = PIUPB_PADDATA_MAX;
495 sc->sc_prmay = 0;
496 sc->sc_prmby = SCALE;
497 sc->sc_prmcy = 0;
498 sc->sc_prmys = PIUPB_PADDATA_MAX;
499 }
500
501 void
502 vrpiu_timeout(arg)
503 void *arg;
504 {
505 struct vrpiu_softc *sc = arg;
506 sc->sc_timeout = 1;
507 }
508
509 #ifdef DEBUG
510 void
511 vrpiu_dump_cntreg(cnt)
512 unsigned int cnt;
513 {
514 printf("%s", (cnt & PIUCNT_PENSTC) ? "Touch" : "Release");
515 printf(" state=");
516 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_CmdScan)
517 printf("CmdScan");
518 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_IntervalNextScan)
519 printf("IntervalNextScan");
520 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_PenDataScan)
521 printf("PenDataScan");
522 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_WaitPenTouch)
523 printf("WaitPenTouch");
524 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_RFU)
525 printf("???");
526 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_ADPortScan)
527 printf("ADPortScan");
528 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Standby)
529 printf("Standby");
530 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Disable)
531 printf("Disable");
532 if (cnt & PIUCNT_PADATSTOP)
533 printf(" AutoStop");
534 if (cnt & PIUCNT_PADATSTART)
535 printf(" AutoStart");
536 if (cnt & PIUCNT_PADSCANSTOP)
537 printf(" Stop");
538 if (cnt & PIUCNT_PADSCANSTART)
539 printf(" Start");
540 if (cnt & PIUCNT_PADSCANTYPE)
541 printf(" ScanPressure");
542 if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_ADCONVERTER)
543 printf(" A/D");
544 if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_COORDINATE)
545 printf(" Coordinate");
546 if (cnt & PIUCNT_PIUSEQEN)
547 printf(" SeqEn");
548 if ((cnt & PIUCNT_PIUPWR) == 0)
549 printf(" PowerOff");
550 if ((cnt & PIUCNT_PADRST) == 0)
551 printf(" Reset");
552 printf("\n");
553 }
554 #endif
555