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