vrpiu.c revision 1.22
1/*	$NetBSD: vrpiu.c,v 1.22 2002/03/10 10:13:32 takemura 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
67int	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 */
98static int	vrpiumatch(struct device *, struct cfdata *, void *);
99static void	vrpiuattach(struct device *, struct device *, void *);
100
101static void	vrpiu_write(struct vrpiu_softc *, int, unsigned short);
102static u_short	vrpiu_read(struct vrpiu_softc *, int);
103
104static int	vrpiu_intr(void *);
105static void	vrpiu_tp_intr(struct vrpiu_softc *);
106static void	vrpiu_ad_intr(struct vrpiu_softc *);
107#ifdef DEBUG
108static void	vrpiu_dump_cntreg(unsigned int);
109#endif
110
111static int	vrpiu_tp_enable(void *);
112static int	vrpiu_tp_ioctl(void *, u_long, caddr_t, int, struct proc *);
113static void	vrpiu_tp_disable(void *);
114static void	vrpiu_tp_up(struct vrpiu_softc *);
115static void	vrpiu_tp_timeout(void *);
116int		vrpiu_ad_enable(void *);
117void		vrpiu_ad_disable(void *);
118static void	vrpiu_start_powerstate(void *);
119static void	vrpiu_calc_powerstate(struct vrpiu_softc *);
120static void	vrpiu_send_battery_event(struct vrpiu_softc *);
121static void	vrpiu_power(int, void *);
122static u_int	scan_interval(u_int data);
123
124/* mra is defined in mra.c */
125int 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 */
131struct cfattach vrpiu_ca = {
132	sizeof(struct vrpiu_softc), vrpiumatch, vrpiuattach
133};
134
135const struct wsmouse_accessops vrpiu_accessops = {
136	vrpiu_tp_enable,
137	vrpiu_tp_ioctl,
138	vrpiu_tp_disable,
139};
140
141int vrpiu_ad_poll_interval = VRPIU_AD_POLL_INTERVAL;
142
143/*
144 * function definitions
145 */
146static inline void
147vrpiu_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
153static inline u_short
154vrpiu_read(struct vrpiu_softc *sc, int port)
155{
156
157	return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, port));
158}
159
160static inline u_short
161vrpiu_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
167static int
168vrpiumatch(struct device *parent, struct cfdata *cf, void *aux)
169{
170
171	return (1);
172}
173
174static void
175vrpiuattach(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 */
318static u_int
319scan_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
337int
338vrpiu_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
386void
387vrpiu_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
407int
408vrpiu_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
458void
459vrpiu_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
479int
480vrpiu_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 (-1);
527	}
528	return (0);
529}
530
531/*
532 * PIU AD interrupt handler.
533 */
534void
535vrpiu_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 */
575void
576vrpiu_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
708void
709vrpiu_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 */
727void
728vrpiu_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 */
746int
747vrpiu_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
757void
758vrpiu_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
775void
776vrpiu_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
797static void
798vrpiu_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
813static void
814vrpiu_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
881void
882vrpiu_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