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