vrpiu.c revision 1.5 1 /* $NetBSD: vrpiu.c,v 1.5 2000/06/13 05:59:55 matt 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 #include <machine/platid.h>
40 #include <machine/platid_mask.h>
41
42 #include <hpcmips/dev/tpcalibvar.h>
43 #include <hpcmips/vr/vripvar.h>
44 #include <hpcmips/vr/cmureg.h>
45 #include <hpcmips/vr/vrpiuvar.h>
46 #include <hpcmips/vr/vrpiureg.h>
47
48 /*
49 * contant and macro definitions
50 */
51 #define VRPIUDEBUG
52 #ifdef VRPIUDEBUG
53 int vrpiu_debug = 0;
54 #define DPRINTF(arg) if (vrpiu_debug) printf arg;
55 #else
56 #define DPRINTF(arg)
57 #endif
58
59 /*
60 * data types
61 */
62 /* struct vrpiu_softc is defined in vrpiuvar.h */
63
64 /*
65 * function prototypes
66 */
67 static int vrpiumatch __P((struct device *, struct cfdata *, void *));
68 static void vrpiuattach __P((struct device *, struct device *, void *));
69
70 static void vrpiu_write __P((struct vrpiu_softc *, int, unsigned short));
71 static u_short vrpiu_read __P((struct vrpiu_softc *, int));
72
73 static int vrpiu_intr __P((void *));
74 #ifdef DEBUG
75 static void vrpiu_dump_cntreg __P((unsigned int cmd));
76 #endif
77
78 static int vrpiu_enable __P((void *));
79 static int vrpiu_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
80 static void vrpiu_disable __P((void *));
81
82 /* mra is defined in mra.c */
83 int mra_Y_AX1_BX2_C __P((int *y, int ys, int *x1, int x1s, int *x2, int x2s,
84 int n, int scale, int *a, int *b, int *c));
85
86 /*
87 * static or global variables
88 */
89 struct cfattach vrpiu_ca = {
90 sizeof(struct vrpiu_softc), vrpiumatch, vrpiuattach
91 };
92
93 const struct wsmouse_accessops vrpiu_accessops = {
94 vrpiu_enable,
95 vrpiu_ioctl,
96 vrpiu_disable,
97 };
98
99 /*
100 * function definitions
101 */
102 static inline void
103 vrpiu_write(sc, port, val)
104 struct vrpiu_softc *sc;
105 int port;
106 unsigned short val;
107 {
108 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
109 }
110
111 static inline u_short
112 vrpiu_read(sc, port)
113 struct vrpiu_softc *sc;
114 int port;
115 {
116 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, port);
117 }
118
119 static int
120 vrpiumatch(parent, cf, aux)
121 struct device *parent;
122 struct cfdata *cf;
123 void *aux;
124 {
125 return 1;
126 }
127
128 static void
129 vrpiuattach(parent, self, aux)
130 struct device *parent;
131 struct device *self;
132 void *aux;
133 {
134 struct vrpiu_softc *sc = (struct vrpiu_softc *)self;
135 struct vrip_attach_args *va = aux;
136 struct wsmousedev_attach_args wsmaa;
137
138 bus_space_tag_t iot = va->va_iot;
139 bus_space_handle_t ioh;
140
141 if (bus_space_map(iot, va->va_addr, 1, 0, &ioh)) {
142 printf(": can't map bus space\n");
143 return;
144 }
145
146 sc->sc_iot = iot;
147 sc->sc_ioh = ioh;
148 sc->sc_vrip = va->va_vc;
149
150 /*
151 * disable device until vrpiu_enable called
152 */
153 sc->sc_stat = VRPIU_STAT_DISABLE;
154
155 tpcalib_init(&sc->sc_tpcalib);
156 #if 1
157 /*
158 * XXX, calibrate parameters
159 */
160 {
161 int i;
162 static const struct {
163 platid_mask_t *mask;
164 struct wsmouse_calibcoords coords;
165 } calibrations[] = {
166 { &platid_mask_MACH_NEC_MCR_700A,
167 { 0, 0, 799, 599,
168 4,
169 { { 115, 80, 0, 0 },
170 { 115, 966, 0, 599 },
171 { 912, 80, 799, 0 },
172 { 912, 966, 799, 599 } } } },
173
174 { NULL, /* samples got on my MC-R500 */
175 { 0, 0, 639, 239,
176 5,
177 { { 502, 486, 320, 120 },
178 { 55, 109, 0, 0 },
179 { 54, 913, 0, 239 },
180 { 973, 924, 639, 239 },
181 { 975, 123, 639, 0 } } } },
182 };
183 for (i = 0; ; i++) {
184 if (calibrations[i].mask == NULL
185 || platid_match(&platid, calibrations[i].mask))
186 break;
187 }
188 tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
189 (caddr_t)&calibrations[i].coords, 0, 0);
190 }
191 #endif
192
193 /* install interrupt handler and enable interrupt */
194 if (!(sc->sc_handler =
195 vrip_intr_establish(va->va_vc, va->va_intr, IPL_TTY,
196 vrpiu_intr, sc))) {
197 printf (": can't map interrupt line.\n");
198 return;
199 }
200
201 /* mask level2 interrupt, stop scan sequencer and mask clock to piu */
202 vrpiu_disable(sc);
203
204 printf("\n");
205
206 wsmaa.accessops = &vrpiu_accessops;
207 wsmaa.accesscookie = sc;
208
209 /*
210 * attach the wsmouse
211 */
212 sc->sc_wsmousedev = config_found(self, &wsmaa, wsmousedevprint);
213 }
214
215 int
216 vrpiu_enable(v)
217 void *v;
218 {
219 struct vrpiu_softc *sc = v;
220 int s;
221 unsigned int cnt;
222
223 DPRINTF(("%s(%d): vrpiu_enable()\n", __FILE__, __LINE__));
224 if (sc->sc_stat != VRPIU_STAT_DISABLE)
225 return EBUSY;
226
227 /* supply clock to PIU */
228 __vrcmu_supply(CMUMSKPIU, 1);
229
230 /* Scan interval 0x7FF is maximum value */
231 vrpiu_write(sc, PIUSIVL_REG_W, 0x7FF);
232
233 s = spltty();
234
235 /* clear interrupt status */
236 vrpiu_write(sc, PIUINT_REG_W, PIUINT_ALLINTR);
237
238 /* Disable -> Standby */
239 cnt = PIUCNT_PIUPWR |
240 PIUCNT_PIUMODE_COORDINATE |
241 PIUCNT_PADATSTART | PIUCNT_PADATSTOP;
242 vrpiu_write(sc, PIUCNT_REG_W, cnt);
243
244 /* save pen status, touch or release */
245 cnt = vrpiu_read(sc, PIUCNT_REG_W);
246
247 /* Level2 interrupt register setting */
248 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 1);
249
250 /*
251 * Enable scan sequencer operation
252 * Standby -> WaitPenTouch
253 */
254 cnt |= PIUCNT_PIUSEQEN;
255 vrpiu_write(sc, PIUCNT_REG_W, cnt);
256
257 /* transit status DISABLE -> TOUCH or RELEASE */
258 sc->sc_stat = (cnt & PIUCNT_PENSTC) ?
259 VRPIU_STAT_TOUCH : VRPIU_STAT_RELEASE;
260
261 splx(s);
262
263 return 0;
264 }
265
266 void
267 vrpiu_disable(v)
268 void *v;
269 {
270 struct vrpiu_softc *sc = v;
271
272 DPRINTF(("%s(%d): vrpiu_disable()\n", __FILE__, __LINE__));
273
274 /* Set level2 interrupt register to mask interrupts */
275 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 0);
276
277 sc->sc_stat = VRPIU_STAT_DISABLE;
278
279 /* Disable scan sequencer operation and power off */
280 vrpiu_write(sc, PIUCNT_REG_W, 0);
281
282 /* mask clock to PIU */
283 __vrcmu_supply(CMUMSKPIU, 1);
284 }
285
286 int
287 vrpiu_ioctl(v, cmd, data, flag, p)
288 void *v;
289 u_long cmd;
290 caddr_t data;
291 int flag;
292 struct proc *p;
293 {
294 struct vrpiu_softc *sc = v;
295
296 DPRINTF(("%s(%d): vrpiu_ioctl(%08lx)\n", __FILE__, __LINE__, cmd));
297
298 switch (cmd) {
299 case WSMOUSEIO_GTYPE:
300 *(u_int *)data = WSMOUSE_TYPE_TPANEL;
301 break;
302
303 case WSMOUSEIO_SRES:
304 printf("%s(%d): WSMOUSRIO_SRES is not supported",
305 __FILE__, __LINE__);
306 break;
307
308 case WSMOUSEIO_SCALIBCOORDS:
309 case WSMOUSEIO_GCALIBCOORDS:
310 return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, p);
311
312 default:
313 return (-1);
314 }
315 return (0);
316 }
317
318 /*
319 * PIU interrupt handler.
320 */
321 int
322 vrpiu_intr(arg)
323 void *arg;
324 {
325 struct vrpiu_softc *sc = arg;
326 unsigned int cnt, i;
327 unsigned int intrstat, page;
328 int tpx0, tpx1, tpy0, tpy1;
329 int x, y, xraw, yraw;
330
331 intrstat = vrpiu_read(sc, PIUINT_REG_W);
332
333 if (sc->sc_stat == VRPIU_STAT_DISABLE) {
334 /*
335 * the device isn't enabled. just clear interrupt.
336 */
337 vrpiu_write(sc, PIUINT_REG_W, intrstat);
338 return (0);
339 }
340
341 page = (intrstat & PIUINT_OVP) ? 1 : 0;
342 if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
343 tpx0 = vrpiu_read(sc, PIUPB(page, 0));
344 tpx1 = vrpiu_read(sc, PIUPB(page, 1));
345 tpy0 = vrpiu_read(sc, PIUPB(page, 2));
346 tpy1 = vrpiu_read(sc, PIUPB(page, 3));
347 }
348
349 if (intrstat & PIUINT_PADDLOSTINTR) {
350 page = page ? 0 : 1;
351 for (i = 0; i < 4; i++)
352 vrpiu_read(sc, PIUPB(page, i));
353 }
354
355 cnt = vrpiu_read(sc, PIUCNT_REG_W);
356 #ifdef DEBUG
357 if (vrpiu_debug)
358 vrpiu_dump_cntreg(cnt);
359 #endif
360
361 /* clear interrupt status */
362 vrpiu_write(sc, PIUINT_REG_W, intrstat);
363
364 #if 0
365 DPRINTF(("vrpiu_intr: OVP=%d", page));
366 if (intrstat & PIUINT_PADCMDINTR)
367 DPRINTF((" CMD"));
368 if (intrstat & PIUINT_PADADPINTR)
369 DPRINTF((" A/D"));
370 if (intrstat & PIUINT_PADPAGE1INTR)
371 DPRINTF((" PAGE1"));
372 if (intrstat & PIUINT_PADPAGE0INTR)
373 DPRINTF((" PAGE0"));
374 if (intrstat & PIUINT_PADDLOSTINTR)
375 DPRINTF((" DLOST"));
376 if (intrstat & PIUINT_PENCHGINTR)
377 DPRINTF((" PENCHG"));
378 DPRINTF(("\n"));
379 #endif
380 if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
381 if (!((tpx0 & PIUPB_VALID) && (tpx1 & PIUPB_VALID) &&
382 (tpy0 & PIUPB_VALID) && (tpy1 & PIUPB_VALID))) {
383 printf("vrpiu: internal error, data is not valid!\n");
384 } else {
385 tpx0 &= PIUPB_PADDATA_MASK;
386 tpx1 &= PIUPB_PADDATA_MASK;
387 tpy0 &= PIUPB_PADDATA_MASK;
388 tpy1 &= PIUPB_PADDATA_MASK;
389 #define ISVALID(n, c, m) ((c) - (m) < (n) && (n) < (c) + (m))
390 if (ISVALID(tpx0 + tpx1, 1024, 200) &&
391 ISVALID(tpx0 + tpx1, 1024, 200)) {
392 #if 0
393 DPRINTF(("%04x %04x %04x %04x\n",
394 tpx0, tpx1, tpy0, tpy1));
395 DPRINTF(("%3d %3d (%4d %4d)->", tpx0, tpy0,
396 tpx0 + tpx1, tpy0 + tpy1));
397 #endif
398 xraw = tpy1 * 1024 / (tpy0 + tpy1);
399 yraw = tpx1 * 1024 / (tpx0 + tpx1);
400 DPRINTF(("%3d %3d", xraw, yraw));
401
402 tpcalib_trans(&sc->sc_tpcalib,
403 xraw, yraw, &x, &y);
404
405 DPRINTF(("->%4d %4d", x, y));
406 wsmouse_input(sc->sc_wsmousedev,
407 (cnt & PIUCNT_PENSTC) ? 1 : 0,
408 x, /* x */
409 y, /* y */
410 0, /* z */
411 WSMOUSE_INPUT_ABSOLUTE_X |
412 WSMOUSE_INPUT_ABSOLUTE_Y);
413 DPRINTF(("\n"));
414 }
415 }
416 }
417
418 if (cnt & PIUCNT_PENSTC) {
419 if (sc->sc_stat == VRPIU_STAT_RELEASE) {
420 /*
421 * pen touch
422 */
423 DPRINTF(("PEN TOUCH\n"));
424 sc->sc_stat = VRPIU_STAT_TOUCH;
425 /*
426 * We should not report button down event while
427 * we don't know where it occur.
428 */
429 }
430 } else {
431 if (sc->sc_stat == VRPIU_STAT_TOUCH) {
432 /*
433 * pen release
434 */
435 DPRINTF(("RELEASE\n"));
436 sc->sc_stat = VRPIU_STAT_RELEASE;
437 /* button 0 UP */
438 wsmouse_input(sc->sc_wsmousedev,
439 0,
440 0, 0, 0, 0);
441 }
442 }
443
444 if (intrstat & PIUINT_PADDLOSTINTR) {
445 cnt |= PIUCNT_PIUSEQEN;
446 vrpiu_write(sc, PIUCNT_REG_W, cnt);
447 }
448
449 return 0;
450 }
451
452 #ifdef DEBUG
453 void
454 vrpiu_dump_cntreg(cnt)
455 unsigned int cnt;
456 {
457 printf("%s", (cnt & PIUCNT_PENSTC) ? "Touch" : "Release");
458 printf(" state=");
459 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_CmdScan)
460 printf("CmdScan");
461 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_IntervalNextScan)
462 printf("IntervalNextScan");
463 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_PenDataScan)
464 printf("PenDataScan");
465 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_WaitPenTouch)
466 printf("WaitPenTouch");
467 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_RFU)
468 printf("???");
469 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_ADPortScan)
470 printf("ADPortScan");
471 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Standby)
472 printf("Standby");
473 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Disable)
474 printf("Disable");
475 if (cnt & PIUCNT_PADATSTOP)
476 printf(" AutoStop");
477 if (cnt & PIUCNT_PADATSTART)
478 printf(" AutoStart");
479 if (cnt & PIUCNT_PADSCANSTOP)
480 printf(" Stop");
481 if (cnt & PIUCNT_PADSCANSTART)
482 printf(" Start");
483 if (cnt & PIUCNT_PADSCANTYPE)
484 printf(" ScanPressure");
485 if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_ADCONVERTER)
486 printf(" A/D");
487 if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_COORDINATE)
488 printf(" Coordinate");
489 if (cnt & PIUCNT_PIUSEQEN)
490 printf(" SeqEn");
491 if ((cnt & PIUCNT_PIUPWR) == 0)
492 printf(" PowerOff");
493 if ((cnt & PIUCNT_PADRST) == 0)
494 printf(" Reset");
495 printf("\n");
496 }
497 #endif
498