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