Home | History | Annotate | Line # | Download | only in vr
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
     67 int	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  */
     98 static int	vrpiumatch(struct device *, struct cfdata *, void *);
     99 static void	vrpiuattach(struct device *, struct device *, void *);
    100 static void	vrc4173piuattach(struct device *, struct device *, void *);
    101 static void	vrpiu_init(struct vrpiu_softc *, void *);
    102 
    103 static void	vrpiu_write(struct vrpiu_softc *, int, unsigned short);
    104 static u_short	vrpiu_read(struct vrpiu_softc *, int);
    105 
    106 static int	vrpiu_intr(void *);
    107 static void	vrpiu_tp_intr(struct vrpiu_softc *);
    108 static void	vrpiu_ad_intr(struct vrpiu_softc *);
    109 #ifdef DEBUG
    110 static void	vrpiu_dump_cntreg(unsigned int);
    111 #endif
    112 
    113 static int	vrpiu_tp_enable(void *);
    114 static int	vrpiu_tp_ioctl(void *, u_long, caddr_t, int, struct proc *);
    115 static void	vrpiu_tp_disable(void *);
    116 static void	vrpiu_tp_up(struct vrpiu_softc *);
    117 static void	vrpiu_tp_timeout(void *);
    118 int		vrpiu_ad_enable(void *);
    119 void		vrpiu_ad_disable(void *);
    120 static void	vrpiu_start_powerstate(void *);
    121 static void	vrpiu_calc_powerstate(struct vrpiu_softc *);
    122 static void	vrpiu_send_battery_event(struct vrpiu_softc *);
    123 static void	vrpiu_power(int, void *);
    124 static u_int	scan_interval(u_int data);
    125 
    126 /* mra is defined in mra.c */
    127 int 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  */
    133 CFATTACH_DECL(vrpiu, sizeof(struct vrpiu_softc),
    134     vrpiumatch, vrpiuattach, NULL, NULL);
    135 CFATTACH_DECL(vrc4173piu, sizeof(struct vrpiu_softc),
    136     vrpiumatch, vrc4173piuattach, NULL, NULL);
    137 
    138 const struct wsmouse_accessops vrpiu_accessops = {
    139 	vrpiu_tp_enable,
    140 	vrpiu_tp_ioctl,
    141 	vrpiu_tp_disable,
    142 };
    143 
    144 int vrpiu_ad_poll_interval = VRPIU_AD_POLL_INTERVAL;
    145 
    146 /*
    147  * function definitions
    148  */
    149 static inline void
    150 vrpiu_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 
    156 static inline u_short
    157 vrpiu_read(struct vrpiu_softc *sc, int port)
    158 {
    159 
    160 	return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, port));
    161 }
    162 
    163 static inline u_short
    164 vrpiu_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 
    170 static int
    171 vrpiumatch(struct device *parent, struct cfdata *cf, void *aux)
    172 {
    173 
    174 	return (1);
    175 }
    176 
    177 static void
    178 vrpiuattach(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 
    188 static void
    189 vrc4173piuattach(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 
    199 static void
    200 vrpiu_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  */
    342 static u_int
    343 scan_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 
    361 int
    362 vrpiu_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 
    410 void
    411 vrpiu_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 
    431 int
    432 vrpiu_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 
    482 void
    483 vrpiu_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 
    503 int
    504 vrpiu_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  */
    558 void
    559 vrpiu_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  */
    600 void
    601 vrpiu_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 
    733 void
    734 vrpiu_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 */
    752 void
    753 vrpiu_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  */
    771 int
    772 vrpiu_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 
    782 void
    783 vrpiu_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 
    800 void
    801 vrpiu_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 
    822 static void
    823 vrpiu_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 
    838 static void
    839 vrpiu_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
    906 void
    907 vrpiu_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