xref: /netbsd/sys/arch/hpcmips/vr/vrpiu.c (revision bf9ec67e)
1 /*	$NetBSD: vrpiu.c,v 1.23 2002/03/17 19:40:41 atatat Exp $	*/
2 
3 /*
4  * Copyright (c) 1999-2002 TAKEMURA Shin All rights reserved.
5  * Copyright (c) 2000-2001 SATO Kazumi, All rights reserved.
6  * Copyright (c) 1999-2001 PocketBSD Project. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 
31 /*
32  * A/D polling part written by SATO Kazumi.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/kernel.h>
39 #include <sys/callout.h>
40 #include <sys/boot_flag.h>
41 
42 #include <dev/wscons/wsconsio.h>
43 #include <dev/wscons/wsmousevar.h>
44 
45 #include <machine/bus.h>
46 #include <machine/platid.h>
47 #include <machine/platid_mask.h>
48 #include <machine/config_hook.h>
49 
50 #include <dev/hpc/tpcalibvar.h>
51 
52 #include <dev/hpc/hpcbatteryvar.h>
53 #include <dev/hpc/hpcbatterytable.h>
54 
55 #include <hpcmips/vr/vrcpudef.h>
56 #include <hpcmips/vr/vripif.h>
57 #include <hpcmips/vr/cmureg.h>
58 #include <hpcmips/vr/vrpiuvar.h>
59 #define	PIUB_REG_OFFSSET	0
60 #include <hpcmips/vr/vrpiureg.h>
61 
62 /*
63  * contant and macro definitions
64  */
65 #define VRPIUDEBUG
66 #ifdef VRPIUDEBUG
67 int	vrpiu_debug = 0;
68 #define	DPRINTF(arg) if (vrpiu_debug) printf arg;
69 #define	VPRINTF(arg) if (bootverbose || vrpiu_debug) printf arg;
70 #else
71 #define	DPRINTF(arg)
72 #define	VPRINTF(arg) if (bootverbose) printf arg;
73 #endif
74 
75 #ifndef VRPIU_NO_ADHOC_BATTERY_EVENT
76 #define VRPIU_ADHOC_BATTERY_EVENT	/* currently... */
77 #endif /* VRPIU_NO_ADHOC_BATTERY_EVENT */
78 
79 #ifndef VRPIU_AD_POLL_INTERVAL
80 #define VRPIU_AD_POLL_INTERVAL	60	/* interval is 60 sec */
81 #endif /* VRPIU_AD_POLL_INTERTVAL */
82 
83 #define	PIUSIVL_SCANINTVAL_MIN	333			/* 10msec	*/
84 #define	PIUSIVL_SCANINTVAL_MAX	PIUSIVL_SCANINTVAL_MASK	/* 60msec	*/
85 #define VRPIU_TP_SCAN_TIMEOUT	(hz/10)		/* timeout is 100msec	*/
86 
87 #define TP_INTR	(PIUINT_ALLINTR & ~PIUINT_PADADPINTR)
88 #define AD_INTR	(PIUINT_PADADPINTR)
89 
90 /*
91  * data types
92  */
93 /* struct vrpiu_softc is defined in vrpiuvar.h */
94 
95 /*
96  * function prototypes
97  */
98 static int	vrpiumatch(struct device *, struct cfdata *, void *);
99 static void	vrpiuattach(struct device *, struct device *, void *);
100 
101 static void	vrpiu_write(struct vrpiu_softc *, int, unsigned short);
102 static u_short	vrpiu_read(struct vrpiu_softc *, int);
103 
104 static int	vrpiu_intr(void *);
105 static void	vrpiu_tp_intr(struct vrpiu_softc *);
106 static void	vrpiu_ad_intr(struct vrpiu_softc *);
107 #ifdef DEBUG
108 static void	vrpiu_dump_cntreg(unsigned int);
109 #endif
110 
111 static int	vrpiu_tp_enable(void *);
112 static int	vrpiu_tp_ioctl(void *, u_long, caddr_t, int, struct proc *);
113 static void	vrpiu_tp_disable(void *);
114 static void	vrpiu_tp_up(struct vrpiu_softc *);
115 static void	vrpiu_tp_timeout(void *);
116 int		vrpiu_ad_enable(void *);
117 void		vrpiu_ad_disable(void *);
118 static void	vrpiu_start_powerstate(void *);
119 static void	vrpiu_calc_powerstate(struct vrpiu_softc *);
120 static void	vrpiu_send_battery_event(struct vrpiu_softc *);
121 static void	vrpiu_power(int, void *);
122 static u_int	scan_interval(u_int data);
123 
124 /* mra is defined in mra.c */
125 int mra_Y_AX1_BX2_C(int *y, int ys, int *x1, int x1s, int *x2, int x2s,
126     int n, int scale, int *a, int *b, int *c);
127 
128 /*
129  * static or global variables
130  */
131 struct cfattach vrpiu_ca = {
132 	sizeof(struct vrpiu_softc), vrpiumatch, vrpiuattach
133 };
134 
135 const struct wsmouse_accessops vrpiu_accessops = {
136 	vrpiu_tp_enable,
137 	vrpiu_tp_ioctl,
138 	vrpiu_tp_disable,
139 };
140 
141 int vrpiu_ad_poll_interval = VRPIU_AD_POLL_INTERVAL;
142 
143 /*
144  * function definitions
145  */
146 static inline void
147 vrpiu_write(struct vrpiu_softc *sc, int port, unsigned short val)
148 {
149 
150 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
151 }
152 
153 static inline u_short
154 vrpiu_read(struct vrpiu_softc *sc, int port)
155 {
156 
157 	return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, port));
158 }
159 
160 static inline u_short
161 vrpiu_buf_read(struct vrpiu_softc *sc, int port)
162 {
163 
164 	return (bus_space_read_2(sc->sc_iot, sc->sc_buf_ioh, port));
165 }
166 
167 static int
168 vrpiumatch(struct device *parent, struct cfdata *cf, void *aux)
169 {
170 
171 	return (1);
172 }
173 
174 static void
175 vrpiuattach(struct device *parent, struct device *self, void *aux)
176 {
177 	struct vrpiu_softc *sc = (struct vrpiu_softc *)self;
178 	struct vrip_attach_args *va = aux;
179 	struct wsmousedev_attach_args wsmaa;
180 	int res;
181 	bus_space_tag_t iot = va->va_iot;
182 	struct platid_data *p;
183 
184 	if (va->va_parent_ioh != NULL)
185 		res = bus_space_subregion(iot, va->va_parent_ioh, va->va_addr,
186 		    va->va_size, &sc->sc_ioh);
187 	else
188 		res = bus_space_map(iot, va->va_addr, va->va_size, 0,
189 		    &sc->sc_ioh);
190 	if (res != 0) {
191 		printf(": can't map bus space\n");
192 		return;
193 	}
194 	if (va->va_parent_ioh != NULL)
195 		res = bus_space_subregion(iot, va->va_parent_ioh, va->va_addr2,
196 		    va->va_size2, &sc->sc_buf_ioh);
197 	else
198 		res = bus_space_map(iot, va->va_addr2, va->va_size2, 0,
199 		    &sc->sc_buf_ioh);
200 	if (res != 0) {
201 		printf(": can't map second bus space\n");
202 		return;
203 	}
204 
205 	sc->sc_iot = iot;
206 	sc->sc_unit = va->va_unit;
207 	sc->sc_vrip = va->va_vc;
208 
209 	sc->sc_interval = scan_interval(WSMOUSE_RES_DEFAULT);
210 	if ((p = platid_search_data(&platid, hpcbattery_parameters)) == NULL)
211 		sc->sc_battery_spec = NULL;
212 	else
213 		sc->sc_battery_spec  = p->data;
214 
215 	/*
216 	 * disable device until vrpiu_enable called
217 	 */
218 	sc->sc_tpstat = VRPIU_TP_STAT_DISABLE;
219 
220 	/* initialize touch panel timeout structure	*/
221 	callout_init(&sc->sc_tptimeout);
222 
223 	/* initialize calibration context	*/
224 	tpcalib_init(&sc->sc_tpcalib);
225 #if 1
226 	/*
227 	 * XXX, calibrate parameters
228 	 */
229 	{
230 		int i;
231 		static const struct {
232 			platid_mask_t *mask;
233 			struct wsmouse_calibcoords coords;
234 		} calibrations[] = {
235 			{ &platid_mask_MACH_NEC_MCR_700,
236 			  { 0, 0, 799, 599,
237 			    4,
238 			    { { 115,  80,   0,   0 },
239 			      { 115, 966,   0, 599 },
240 			      { 912,  80, 799,   0 },
241 			      { 912, 966, 799, 599 } } } },
242 			{ &platid_mask_MACH_NEC_MCR_700A,
243 			  { 0, 0, 799, 599,
244 			    4,
245 			    { { 115,  80,   0,   0 },
246 			      { 115, 966,   0, 599 },
247 			      { 912,  80, 799,   0 },
248 			      { 912, 966, 799, 599 } } } },
249 			{ &platid_mask_MACH_NEC_MCR_730,
250 			  { 0, 0, 799, 599,
251 			    4,
252 			    { { 115,  80,   0,   0 },
253 			      { 115, 966,   0, 599 },
254 			      { 912,  80, 799,   0 },
255 			      { 912, 966, 799, 599 } } } },
256 			{ NULL,		/* samples got on my MC-R500 */
257 			  { 0, 0, 639, 239,
258 			    5,
259 			    { { 502, 486, 320, 120 },
260 			      {  55, 109,   0,   0 },
261 			      {  54, 913,   0, 239 },
262 			      { 973, 924, 639, 239 },
263 			      { 975, 123, 639,   0 } } } },
264 		};
265 		for (i = 0; ; i++) {
266 			if (calibrations[i].mask == NULL
267 			    || platid_match(&platid, calibrations[i].mask))
268 				break;
269 		}
270 		tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
271 		    (caddr_t)&calibrations[i].coords, 0, 0);
272 	}
273 #endif
274 
275 	/* install interrupt handler and enable interrupt */
276 	if (!(sc->sc_handler =
277 	    vrip_intr_establish(sc->sc_vrip, sc->sc_unit, 0, IPL_TTY,
278 		vrpiu_intr, sc))) {
279 		printf (": can't map interrupt line.\n");
280 		return;
281 	}
282 
283 	/* mask level2 interrupt, stop scan sequencer and mask clock to piu */
284 	vrpiu_tp_disable(sc);
285 
286 	printf("\n");
287 
288 	wsmaa.accessops = &vrpiu_accessops;
289 	wsmaa.accesscookie = sc;
290 
291 	/*
292 	 * attach the wsmouse
293 	 */
294 	sc->sc_wsmousedev = config_found(self, &wsmaa, wsmousedevprint);
295 
296 	/*
297 	 * power management events
298 	 */
299 	sc->sc_power_hook = powerhook_establish(vrpiu_power, sc);
300 
301 	/*
302 	 * init A/D port polling.
303 	 */
304 	sc->sc_battery.n_values = 3;
305 	sc->sc_battery.value[0] = -1;
306 	sc->sc_battery.value[1] = -1;
307 	sc->sc_battery.value[2] = -1;
308 	sc->sc_battery.nextpoll = hz*vrpiu_ad_poll_interval;
309 	callout_init(&sc->sc_adpoll);
310 	callout_reset(&sc->sc_adpoll, hz, vrpiu_start_powerstate, sc);
311 }
312 
313 /*
314  * calculate interval value
315  *  input: WSMOUSE_RES_MIN - WSMOUSE_RES_MAX
316  * output: value for PIUSIVL_REG
317  */
318 static u_int
319 scan_interval(u_int data)
320 {
321 	int scale;
322 
323 	if (data < WSMOUSE_RES_MIN)
324 		data = WSMOUSE_RES_MIN;
325 
326 	if (WSMOUSE_RES_MAX < data)
327 		data = WSMOUSE_RES_MAX;
328 
329 	scale = WSMOUSE_RES_MAX - WSMOUSE_RES_MIN;
330 	data += WSMOUSE_RES_MIN;
331 
332 	return PIUSIVL_SCANINTVAL_MIN +
333 	    (PIUSIVL_SCANINTVAL_MAX - PIUSIVL_SCANINTVAL_MIN) *
334 	    (scale - data) / scale;
335 }
336 
337 int
338 vrpiu_ad_enable(void *v)
339 {
340 	struct vrpiu_softc *sc = v;
341 	int s;
342 	unsigned int cnt;
343 
344 	DPRINTF(("%s(%d): vrpiu_ad_enable(): interval=0x%03x\n",
345 	    __FILE__, __LINE__, sc->sc_interval));
346 	if (sc->sc_adstat != VRPIU_AD_STAT_DISABLE)
347 		return EBUSY;
348 
349 	/* supply clock to PIU */
350 	vrip_power(sc->sc_vrip, sc->sc_unit, 1);
351 
352 	/* set scan interval */
353 	vrpiu_write(sc, PIUSIVL_REG_W, sc->sc_interval);
354 
355 	s = spltty();
356 
357 	/* clear interrupt status */
358 	vrpiu_write(sc, PIUINT_REG_W, AD_INTR);
359 
360 	/* Disable -> Standby */
361 	cnt = PIUCNT_PIUPWR |
362 	    PIUCNT_PIUMODE_COORDINATE |
363 	    PIUCNT_PADATSTART | PIUCNT_PADATSTOP;
364 	vrpiu_write(sc, PIUCNT_REG_W, cnt);
365 
366 	/* Level2 interrupt register setting */
367 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AD_INTR, 1);
368 
369 	/* save pen status, touch or release */
370 	cnt = vrpiu_read(sc, PIUCNT_REG_W);
371 
372 	/*
373 	 * Enable scan sequencer operation
374 	 * Standby -> WaitPenTouch
375 	 */
376 	cnt |= PIUCNT_PIUSEQEN;
377 	vrpiu_write(sc, PIUCNT_REG_W, cnt);
378 
379 	sc->sc_adstat = VRPIU_AD_STAT_ENABLE;
380 
381 	splx(s);
382 
383 	return 0;
384 }
385 
386 void
387 vrpiu_ad_disable(void *v)
388 {
389 	struct vrpiu_softc *sc = v;
390 
391 	DPRINTF(("%s(%d): vrpiu_ad_disable()\n", __FILE__, __LINE__));
392 
393 	/* Set level2 interrupt register to mask interrupts */
394 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AD_INTR, 0);
395 
396 	sc->sc_adstat = VRPIU_AD_STAT_DISABLE;
397 
398 	if (sc->sc_tpstat == VRPIU_TP_STAT_DISABLE){
399 		/* Disable scan sequencer operation and power off */
400 		vrpiu_write(sc, PIUCNT_REG_W, 0);
401 
402 		/* mask clock to PIU */
403 		vrip_power(sc->sc_vrip, sc->sc_unit, 0);
404 	}
405 }
406 
407 int
408 vrpiu_tp_enable(void *v)
409 {
410 	struct vrpiu_softc *sc = v;
411 	int s;
412 	unsigned int cnt;
413 
414 	DPRINTF(("%s(%d): vrpiu_tp_enable(): interval=0x%03x\n",
415 	    __FILE__, __LINE__, sc->sc_interval));
416 	if (sc->sc_tpstat != VRPIU_TP_STAT_DISABLE)
417 		return EBUSY;
418 
419 	/* supply clock to PIU */
420 	vrip_power(sc->sc_vrip, sc->sc_unit, 1);
421 
422 	/* set scan interval */
423 	vrpiu_write(sc, PIUSIVL_REG_W, sc->sc_interval);
424 
425 	s = spltty();
426 
427 	/* clear interrupt status */
428 	vrpiu_write(sc, PIUINT_REG_W, TP_INTR);
429 
430 	/* Disable -> Standby */
431 	cnt = PIUCNT_PIUPWR |
432 	    PIUCNT_PIUMODE_COORDINATE |
433 	    PIUCNT_PADATSTART | PIUCNT_PADATSTOP;
434 	vrpiu_write(sc, PIUCNT_REG_W, cnt);
435 
436 	/* Level2 interrupt register setting */
437 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, TP_INTR, 1);
438 
439 	/* save pen status, touch or release */
440 	cnt = vrpiu_read(sc, PIUCNT_REG_W);
441 
442 	/*
443 	 * Enable scan sequencer operation
444 	 * Standby -> WaitPenTouch
445 	 */
446 	cnt |= PIUCNT_PIUSEQEN;
447 	vrpiu_write(sc, PIUCNT_REG_W, cnt);
448 
449 	/* transit status DISABLE -> TOUCH or RELEASE */
450 	sc->sc_tpstat = (cnt & PIUCNT_PENSTC) ?
451 	    VRPIU_TP_STAT_TOUCH : VRPIU_TP_STAT_RELEASE;
452 
453 	splx(s);
454 
455 	return 0;
456 }
457 
458 void
459 vrpiu_tp_disable(void *v)
460 {
461 	struct vrpiu_softc *sc = v;
462 
463 	DPRINTF(("%s(%d): vrpiu_tp_disable()\n", __FILE__, __LINE__));
464 
465 	/* Set level2 interrupt register to mask interrupts */
466 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, TP_INTR, 0);
467 
468 	sc->sc_tpstat = VRPIU_TP_STAT_DISABLE;
469 
470 	if (sc->sc_adstat == VRPIU_AD_STAT_DISABLE){
471 		/* Disable scan sequencer operation and power off */
472 		vrpiu_write(sc, PIUCNT_REG_W, 0);
473 
474 		/* mask clock to PIU */
475 		vrip_power(sc->sc_vrip, sc->sc_unit, 0);
476 	}
477 }
478 
479 int
480 vrpiu_tp_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
481 {
482 	struct vrpiu_softc *sc = v;
483 
484 	DPRINTF(("%s(%d): vrpiu_tp_ioctl(%08lx)\n", __FILE__, __LINE__, cmd));
485 
486 	switch (cmd) {
487 	case WSMOUSEIO_GTYPE:
488 		*(u_int *)data = WSMOUSE_TYPE_TPANEL;
489 		break;
490 
491 	case WSMOUSEIO_SRES:
492 	{
493 		int tp_enable;
494 		int ad_enable;
495 
496 		tp_enable = (sc->sc_tpstat != VRPIU_TP_STAT_DISABLE);
497 		ad_enable = (sc->sc_adstat != VRPIU_AD_STAT_DISABLE);
498 
499 		if (tp_enable)
500 			vrpiu_tp_disable(sc);
501 		if (ad_enable)
502 			vrpiu_ad_disable(sc);
503 
504 		sc->sc_interval = scan_interval(*(u_int *)data);
505 		DPRINTF(("%s(%d): WSMOUSEIO_SRES: *data=%d, interval=0x%03x\n",
506 		    __FILE__, __LINE__, *(u_int *)data, sc->sc_interval));
507 
508 		if (sc->sc_interval < PIUSIVL_SCANINTVAL_MIN)
509 			sc->sc_interval = PIUSIVL_SCANINTVAL_MIN;
510 
511 		if (PIUSIVL_SCANINTVAL_MAX < sc->sc_interval)
512 			sc->sc_interval = PIUSIVL_SCANINTVAL_MAX;
513 
514 		if (tp_enable)
515 			vrpiu_tp_enable(sc);
516 		if (ad_enable)
517 			vrpiu_ad_enable(sc);
518 	}
519 	break;
520 
521 	case WSMOUSEIO_SCALIBCOORDS:
522 	case WSMOUSEIO_GCALIBCOORDS:
523 		return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, p);
524 
525 	default:
526 		return (EPASSTHROUGH);
527 	}
528 	return (0);
529 }
530 
531 /*
532  * PIU AD interrupt handler.
533  */
534 void
535 vrpiu_ad_intr(struct vrpiu_softc *sc)
536 {
537 	unsigned int i;
538 	unsigned int intrstat;
539 
540 	intrstat = vrpiu_read(sc, PIUINT_REG_W);
541 
542 	if (sc->sc_adstat == VRPIU_AD_STAT_DISABLE) {
543 		/*
544 		 * the device isn't enabled. just clear interrupt.
545 		 */
546 		vrpiu_write(sc, PIUINT_REG_W, AD_INTR);
547 		return;
548 	}
549 
550 	if (intrstat & PIUINT_PADADPINTR) {
551 		sc->sc_battery.value[0] = (unsigned int)
552 		    vrpiu_buf_read(sc, PIUAB(0));
553 		sc->sc_battery.value[1] = (unsigned int)
554 		    vrpiu_buf_read(sc, PIUAB(1));
555 		sc->sc_battery.value[2] = (unsigned int)
556 		    vrpiu_buf_read(sc, PIUAB(2));
557 	}
558 
559 	if (intrstat & PIUINT_PADADPINTR) {
560 		for (i = 0; i < 3; i++) {
561 			if (sc->sc_battery.value[i] & PIUAB_VALID)
562 				sc->sc_battery.value[i] &= PIUAB_PADDATA_MASK;
563 			else
564 				sc->sc_battery.value[i] = 0;
565 		}
566 		vrpiu_calc_powerstate(sc);
567 	}
568 	vrpiu_write(sc, PIUINT_REG_W, AD_INTR);
569 
570 	return;
571 }
572 /*
573  * PIU TP interrupt handler.
574  */
575 void
576 vrpiu_tp_intr(struct vrpiu_softc *sc)
577 {
578 	unsigned int cnt, i;
579 	unsigned int intrstat, page;
580 	int tpx0, tpx1, tpy0, tpy1;
581 	int x, y, xraw, yraw;
582 
583 	intrstat = vrpiu_read(sc, PIUINT_REG_W);
584 
585 	if (sc->sc_tpstat == VRPIU_TP_STAT_DISABLE) {
586 		/*
587 		 * the device isn't enabled. just clear interrupt.
588 		 */
589 		vrpiu_write(sc, PIUINT_REG_W, intrstat & TP_INTR);
590 		return;
591 	}
592 
593 	page = (intrstat & PIUINT_OVP) ? 1 : 0;
594 	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
595 		tpx0 = vrpiu_buf_read(sc, PIUPB(page, 0));
596 		tpx1 = vrpiu_buf_read(sc, PIUPB(page, 1));
597 		tpy0 = vrpiu_buf_read(sc, PIUPB(page, 2));
598 		tpy1 = vrpiu_buf_read(sc, PIUPB(page, 3));
599 	}
600 
601 	if (intrstat & PIUINT_PADDLOSTINTR) {
602 		page = page ? 0 : 1;
603 		for (i = 0; i < 4; i++)
604 			vrpiu_buf_read(sc, PIUPB(page, i));
605 	}
606 
607 	cnt = vrpiu_read(sc, PIUCNT_REG_W);
608 #ifdef DEBUG
609 	if (vrpiu_debug)
610 		vrpiu_dump_cntreg(cnt);
611 #endif
612 
613 	/* clear interrupt status */
614 	vrpiu_write(sc, PIUINT_REG_W, intrstat & TP_INTR);
615 
616 #if 0
617 	DPRINTF(("vrpiu_intr: OVP=%d", page));
618 	if (intrstat & PIUINT_PADCMDINTR)
619 		DPRINTF((" CMD"));
620 	if (intrstat & PIUINT_PADADPINTR)
621 		DPRINTF((" A/D"));
622 	if (intrstat & PIUINT_PADPAGE1INTR)
623 		DPRINTF((" PAGE1"));
624 	if (intrstat & PIUINT_PADPAGE0INTR)
625 		DPRINTF((" PAGE0"));
626 	if (intrstat & PIUINT_PADDLOSTINTR)
627 		DPRINTF((" DLOST"));
628 	if (intrstat & PIUINT_PENCHGINTR)
629 		DPRINTF((" PENCHG"));
630 	DPRINTF(("\n"));
631 #endif
632 	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
633 		/*
634 		 * just ignore scan data if status isn't Touch.
635 		 */
636 		if (sc->sc_tpstat == VRPIU_TP_STAT_TOUCH) {
637 			/* reset tp scan timeout	*/
638 			callout_reset(&sc->sc_tptimeout, VRPIU_TP_SCAN_TIMEOUT,
639 			    vrpiu_tp_timeout, sc);
640 
641 			if (!((tpx0 & PIUPB_VALID) && (tpx1 & PIUPB_VALID) &&
642 			    (tpy0 & PIUPB_VALID) && (tpy1 & PIUPB_VALID))) {
643 				printf("vrpiu: internal error,"
644 				    " data is not valid!\n");
645 			} else {
646 				tpx0 &= PIUPB_PADDATA_MASK;
647 				tpx1 &= PIUPB_PADDATA_MASK;
648 				tpy0 &= PIUPB_PADDATA_MASK;
649 				tpy1 &= PIUPB_PADDATA_MASK;
650 #define ISVALID(n, c, m)	((c) - (m) < (n) && (n) < (c) + (m))
651 				if (ISVALID(tpx0 + tpx1, 1024, 200) &&
652 				    ISVALID(tpy0 + tpy1, 1024, 200)) {
653 #if 0
654 					DPRINTF(("%04x %04x %04x %04x\n",
655 					    tpx0, tpx1, tpy0, tpy1));
656 					DPRINTF(("%3d %3d (%4d %4d)->", tpx0,
657 					    tpy0, tpx0 + tpx1, tpy0 + tpy1));
658 #endif
659 					xraw = tpy1 * 1024 / (tpy0 + tpy1);
660 					yraw = tpx1 * 1024 / (tpx0 + tpx1);
661 					DPRINTF(("%3d %3d", xraw, yraw));
662 
663 					tpcalib_trans(&sc->sc_tpcalib, xraw,
664 					    yraw, &x, &y);
665 
666 					DPRINTF(("->%4d %4d", x, y));
667 					wsmouse_input(sc->sc_wsmousedev,
668 					    1, /* button 0 down */
669 					    x, /* x */
670 					    y, /* y */
671 					    0, /* z */
672 					    WSMOUSE_INPUT_ABSOLUTE_X |
673 					    WSMOUSE_INPUT_ABSOLUTE_Y);
674 					DPRINTF(("\n"));
675 				}
676 			}
677 		}
678 	}
679 
680 	if (cnt & PIUCNT_PENSTC) {
681 		if (sc->sc_tpstat == VRPIU_TP_STAT_RELEASE) {
682 			/*
683 			 * pen touch
684 			 */
685 			DPRINTF(("PEN TOUCH\n"));
686 			sc->sc_tpstat = VRPIU_TP_STAT_TOUCH;
687 			/*
688 			 * We should not report button down event while
689 			 * we don't know where it occur.
690 			 */
691 
692 			/* set tp scan timeout	*/
693 			callout_reset(&sc->sc_tptimeout, VRPIU_TP_SCAN_TIMEOUT,
694 			    vrpiu_tp_timeout, sc);
695 		}
696 	} else {
697 		vrpiu_tp_up(sc);
698 	}
699 
700 	if (intrstat & PIUINT_PADDLOSTINTR) {
701 		cnt |= PIUCNT_PIUSEQEN;
702 		vrpiu_write(sc, PIUCNT_REG_W, cnt);
703 	}
704 
705 	return;
706 }
707 
708 void
709 vrpiu_tp_up(struct vrpiu_softc *sc)
710 {
711 	if (sc->sc_tpstat == VRPIU_TP_STAT_TOUCH) {
712 		/*
713 		 * pen release
714 		 */
715 		DPRINTF(("RELEASE\n"));
716 		sc->sc_tpstat = VRPIU_TP_STAT_RELEASE;
717 
718 		/* clear tp scan timeout	*/
719 		callout_stop(&sc->sc_tptimeout);
720 
721 		/* button 0 UP */
722 		wsmouse_input(sc->sc_wsmousedev, 0, 0, 0, 0, 0);
723 	}
724 }
725 
726 /* touch panel timeout handler */
727 void
728 vrpiu_tp_timeout(void *v)
729 {
730 	struct vrpiu_softc *sc = (struct vrpiu_softc *)v;
731 
732 #ifdef VRPIUDEBUG
733 	{
734 		unsigned int cnt = vrpiu_read(sc, PIUCNT_REG_W);
735 		DPRINTF(("TIMEOUT: stat=%s  reg=%s\n",
736 		    (sc->sc_tpstat == VRPIU_TP_STAT_TOUCH)?"touch":"release",
737 		    (cnt & PIUCNT_PENSTC)?"touch":"release"));
738 	}
739 #endif
740 	vrpiu_tp_up(sc);
741 }
742 
743 /*
744  * PIU interrupt handler.
745  */
746 int
747 vrpiu_intr(void *arg)
748 {
749         struct vrpiu_softc *sc = arg;
750 
751 	vrpiu_ad_intr(sc);
752 	vrpiu_tp_intr(sc);
753 
754 	return 0;
755 }
756 
757 void
758 vrpiu_start_powerstate(void *v)
759 {
760 	int mask;
761 	struct vrpiu_softc *sc = (struct vrpiu_softc *)v;
762 
763 	vrpiu_ad_enable(sc);
764 	mask = vrpiu_read(sc, PIUAMSK_REG_W);
765 	mask &= 0xff8f; /* XXX */
766 	vrpiu_write(sc, PIUAMSK_REG_W, mask);
767 	vrpiu_write(sc, PIUASCN_REG_W, PIUACN_ADPSSTART);
768 	/*
769 	 * restart next A/D polling
770 	 */
771 	callout_reset(&sc->sc_adpoll, hz*vrpiu_ad_poll_interval,
772 	    vrpiu_start_powerstate, sc);
773 }
774 
775 void
776 vrpiu_calc_powerstate(struct vrpiu_softc *sc)
777 {
778 	extern void vrgiu_diff_io(void);
779 	vrpiu_ad_disable(sc);
780 	VPRINTF(("vrpiu:AD: %d, %d, %d\n",
781 	    sc->sc_battery.value[0],
782 	    sc->sc_battery.value[1],
783 	    sc->sc_battery.value[2]));
784 	sc->sc_battery.nextpoll = hz*vrpiu_ad_poll_interval;
785 	vrpiu_send_battery_event(sc);
786 	/*
787 	 * restart next A/D polling if change polling timming.
788 	 */
789 	if (sc->sc_battery.nextpoll != hz*vrpiu_ad_poll_interval)
790 		callout_reset(&sc->sc_adpoll, sc->sc_battery.nextpoll,
791 		    vrpiu_start_powerstate, sc);
792 	if (bootverbose)
793 		vrgiu_diff_io();
794 
795 }
796 
797 static void
798 vrpiu_power(int why, void *arg)
799 {
800 	struct vrpiu_softc *sc = arg;
801 
802 	switch (why) {
803 	case PWR_STANDBY:
804 	case PWR_SUSPEND:
805 		break;
806 	case PWR_RESUME:
807 		callout_reset(&sc->sc_adpoll, hz,
808 		    vrpiu_start_powerstate, sc);
809 		break;
810 	}
811 }
812 
813 static void
814 vrpiu_send_battery_event(struct vrpiu_softc *sc)
815 {
816 #ifdef VRPIU_ADHOC_BATTERY_EVENT
817 	static int batteryhigh = 0;
818 	static int batterylow = 0;
819 	static int critical = 0;
820 
821 	if (sc->sc_battery_spec == NULL
822 	    || sc->sc_battery_spec->main_port == -1)
823 		return;
824 
825 	if (sc->sc_battery.value[sc->sc_battery_spec->main_port]
826 	    <= sc->sc_battery_spec->dc_critical) {
827 		batteryhigh = 0;
828 		config_hook_call(CONFIG_HOOK_PMEVENT,
829 		    CONFIG_HOOK_PMEVENT_BATTERY,
830 		    (void *)CONFIG_HOOK_BATT_CRITICAL);
831 		batterylow = 3;
832 		if (critical) {
833 			config_hook_call(CONFIG_HOOK_PMEVENT,
834 			    CONFIG_HOOK_PMEVENT_SUSPENDREQ,
835 			    (void *)0);
836 			critical = 0;
837 			batterylow = 0;
838 		}
839 		critical++;
840 	} else if (sc->sc_battery.value[sc->sc_battery_spec->main_port]
841 	    <= sc->sc_battery_spec->dc_20p) {
842 		batteryhigh = 0;
843 		if (batterylow == 1)
844 			config_hook_call(CONFIG_HOOK_PMEVENT,
845 			    CONFIG_HOOK_PMEVENT_BATTERY,
846 			    (void *)CONFIG_HOOK_BATT_20P);
847 		config_hook_call(CONFIG_HOOK_PMEVENT,
848 		    CONFIG_HOOK_PMEVENT_BATTERY,
849 		    (void *)CONFIG_HOOK_BATT_LOW);
850 		batterylow = 2;
851 	} else if (sc->sc_battery.value[sc->sc_battery_spec->main_port]
852 	    <= sc->sc_battery_spec->dc_50p) {
853 		batteryhigh = 0;
854 		if (batterylow == 0) {
855 			batterylow = 1;
856 			config_hook_call(CONFIG_HOOK_PMEVENT,
857 			    CONFIG_HOOK_PMEVENT_BATTERY,
858 			    (void *)CONFIG_HOOK_BATT_50P);
859 		}
860 	} else if (sc->sc_battery.value[sc->sc_battery_spec->main_port]
861 	    >= sc->sc_battery_spec->ac_80p) {
862 		batterylow = 0;
863 		if (batteryhigh == 0) {
864 			batteryhigh = 1;
865 			config_hook_call(CONFIG_HOOK_PMEVENT,
866 			    CONFIG_HOOK_PMEVENT_BATTERY,
867 			    (void *)CONFIG_HOOK_BATT_80P);
868 			config_hook_call(CONFIG_HOOK_PMEVENT,
869 			    CONFIG_HOOK_PMEVENT_BATTERY,
870 			    (void *)CONFIG_HOOK_BATT_HIGH);
871 		}
872 	}
873 #else /* VRPIU_ADHOC_BATTERY_EVENT */
874 	config_hook_call(CONFIG_HOOK_SET,
875 	    CONFIG_HOOK_BATTERYVAL,
876 	    (void *)&sc->sc_battery);
877 #endif /* VRPIU_ADHOC_BATTERY_EVENT */
878 }
879 
880 #ifdef DEBUG
881 void
882 vrpiu_dump_cntreg(unsigned int cnt)
883 {
884 	printf("%s", (cnt & PIUCNT_PENSTC) ? "Touch" : "Release");
885 	printf(" state=");
886 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_CmdScan)
887 		printf("CmdScan");
888 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_IntervalNextScan)
889 		printf("IntervalNextScan");
890 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_PenDataScan)
891 		printf("PenDataScan");
892 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_WaitPenTouch)
893 		printf("WaitPenTouch");
894 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_RFU)
895 		printf("???");
896 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_ADPortScan)
897 		printf("ADPortScan");
898 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Standby)
899 		printf("Standby");
900 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Disable)
901 		printf("Disable");
902 	if (cnt & PIUCNT_PADATSTOP)
903 		printf(" AutoStop");
904 	if (cnt & PIUCNT_PADATSTART)
905 		printf(" AutoStart");
906 	if (cnt & PIUCNT_PADSCANSTOP)
907 		printf(" Stop");
908 	if (cnt & PIUCNT_PADSCANSTART)
909 		printf(" Start");
910 	if (cnt & PIUCNT_PADSCANTYPE)
911 		printf(" ScanPressure");
912 	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_ADCONVERTER)
913 		printf(" A/D");
914 	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_COORDINATE)
915 		printf(" Coordinate");
916 	if (cnt & PIUCNT_PIUSEQEN)
917 		printf(" SeqEn");
918 	if ((cnt & PIUCNT_PIUPWR) == 0)
919 		printf(" PowerOff");
920 	if ((cnt & PIUCNT_PADRST) == 0)
921 		printf(" Reset");
922 	printf("\n");
923 }
924 #endif
925