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