Home | History | Annotate | Line # | Download | only in vr
vrpiu.c revision 1.28
      1 /*	$NetBSD: vrpiu.c,v 1.28 2003/01/05 08:41:54 takemura Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1999-2003 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 	case WSMOUSEIO_GETID:
    548 		return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, p);
    549 
    550 	default:
    551 		return (EPASSTHROUGH);
    552 	}
    553 	return (0);
    554 }
    555 
    556 /*
    557  * PIU AD interrupt handler.
    558  */
    559 void
    560 vrpiu_ad_intr(struct vrpiu_softc *sc)
    561 {
    562 	unsigned int i;
    563 	unsigned int intrstat;
    564 
    565 	intrstat = vrpiu_read(sc, PIUINT_REG_W);
    566 
    567 	if (sc->sc_adstat == VRPIU_AD_STAT_DISABLE) {
    568 		/*
    569 		 * the device isn't enabled. just clear interrupt.
    570 		 */
    571 		vrpiu_write(sc, PIUINT_REG_W, AD_INTR);
    572 		return;
    573 	}
    574 
    575 	if (intrstat & PIUINT_PADADPINTR) {
    576 		sc->sc_battery.value[0] = (unsigned int)
    577 		    vrpiu_buf_read(sc, PIUAB(0));
    578 		sc->sc_battery.value[1] = (unsigned int)
    579 		    vrpiu_buf_read(sc, PIUAB(1));
    580 		sc->sc_battery.value[2] = (unsigned int)
    581 		    vrpiu_buf_read(sc, PIUAB(2));
    582 	}
    583 
    584 	if (intrstat & PIUINT_PADADPINTR) {
    585 		for (i = 0; i < 3; i++) {
    586 			if (sc->sc_battery.value[i] & PIUAB_VALID)
    587 				sc->sc_battery.value[i] &=
    588 					sc->sc_ab_paddata_mask;
    589 			else
    590 				sc->sc_battery.value[i] = 0;
    591 		}
    592 		vrpiu_calc_powerstate(sc);
    593 	}
    594 	vrpiu_write(sc, PIUINT_REG_W, AD_INTR);
    595 
    596 	return;
    597 }
    598 /*
    599  * PIU TP interrupt handler.
    600  */
    601 void
    602 vrpiu_tp_intr(struct vrpiu_softc *sc)
    603 {
    604 	unsigned int cnt, i;
    605 	unsigned int intrstat, page;
    606 	int tpx0, tpx1, tpy0, tpy1;
    607 	int x, y, xraw, yraw;
    608 
    609 	intrstat = vrpiu_read(sc, PIUINT_REG_W);
    610 
    611 	if (sc->sc_tpstat == VRPIU_TP_STAT_DISABLE) {
    612 		/*
    613 		 * the device isn't enabled. just clear interrupt.
    614 		 */
    615 		vrpiu_write(sc, PIUINT_REG_W, intrstat & TP_INTR);
    616 		return;
    617 	}
    618 
    619 	page = (intrstat & PIUINT_OVP) ? 1 : 0;
    620 	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
    621 		tpx0 = vrpiu_buf_read(sc, PIUPB(page, 0));
    622 		tpx1 = vrpiu_buf_read(sc, PIUPB(page, 1));
    623 		tpy0 = vrpiu_buf_read(sc, PIUPB(page, 2));
    624 		tpy1 = vrpiu_buf_read(sc, PIUPB(page, 3));
    625 	}
    626 
    627 	if (intrstat & PIUINT_PADDLOSTINTR) {
    628 		page = page ? 0 : 1;
    629 		for (i = 0; i < 4; i++)
    630 			vrpiu_buf_read(sc, PIUPB(page, i));
    631 	}
    632 
    633 	cnt = vrpiu_read(sc, PIUCNT_REG_W);
    634 #ifdef DEBUG
    635 	if (vrpiu_debug)
    636 		vrpiu_dump_cntreg(cnt);
    637 #endif
    638 
    639 	/* clear interrupt status */
    640 	vrpiu_write(sc, PIUINT_REG_W, intrstat & TP_INTR);
    641 
    642 #if 0
    643 	DPRINTF(("vrpiu_intr: OVP=%d", page));
    644 	if (intrstat & PIUINT_PADCMDINTR)
    645 		DPRINTF((" CMD"));
    646 	if (intrstat & PIUINT_PADADPINTR)
    647 		DPRINTF((" A/D"));
    648 	if (intrstat & PIUINT_PADPAGE1INTR)
    649 		DPRINTF((" PAGE1"));
    650 	if (intrstat & PIUINT_PADPAGE0INTR)
    651 		DPRINTF((" PAGE0"));
    652 	if (intrstat & PIUINT_PADDLOSTINTR)
    653 		DPRINTF((" DLOST"));
    654 	if (intrstat & PIUINT_PENCHGINTR)
    655 		DPRINTF((" PENCHG"));
    656 	DPRINTF(("\n"));
    657 #endif
    658 	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
    659 		/*
    660 		 * just ignore scan data if status isn't Touch.
    661 		 */
    662 		if (sc->sc_tpstat == VRPIU_TP_STAT_TOUCH) {
    663 			/* reset tp scan timeout	*/
    664 			callout_reset(&sc->sc_tptimeout, VRPIU_TP_SCAN_TIMEOUT,
    665 			    vrpiu_tp_timeout, sc);
    666 
    667 			if (!((tpx0 & PIUPB_VALID) && (tpx1 & PIUPB_VALID) &&
    668 			    (tpy0 & PIUPB_VALID) && (tpy1 & PIUPB_VALID))) {
    669 				printf("vrpiu: internal error,"
    670 				    " data is not valid!\n");
    671 			} else {
    672 				tpx0 &= sc->sc_pb_paddata_mask;
    673 				tpx1 &= sc->sc_pb_paddata_mask;
    674 				tpy0 &= sc->sc_pb_paddata_mask;
    675 				tpy1 &= sc->sc_pb_paddata_mask;
    676 #define ISVALID(n, c)	((c) - (c)/5 < (n) && (n) < (c) + (c)/5)
    677 				if (ISVALID(tpx0 + tpx1, sc->sc_pb_paddata_max) &&
    678 				    ISVALID(tpy0 + tpy1, sc->sc_pb_paddata_max)) {
    679 #if 0
    680 					DPRINTF(("%04x %04x %04x %04x\n",
    681 					    tpx0, tpx1, tpy0, tpy1));
    682 					DPRINTF(("%3d %3d (%4d %4d)->", tpx0,
    683 					    tpy0, tpx0 + tpx1, tpy0 + tpy1));
    684 #endif
    685 					xraw = tpy1 * sc->sc_pb_paddata_max / (tpy0 + tpy1);
    686 					yraw = tpx1 * sc->sc_pb_paddata_max / (tpx0 + tpx1);
    687 					DPRINTF(("%3d %3d", xraw, yraw));
    688 
    689 					tpcalib_trans(&sc->sc_tpcalib, xraw,
    690 					    yraw, &x, &y);
    691 
    692 					DPRINTF(("->%4d %4d", x, y));
    693 					wsmouse_input(sc->sc_wsmousedev,
    694 					    1, /* button 0 down */
    695 					    x, /* x */
    696 					    y, /* y */
    697 					    0, /* z */
    698 					    WSMOUSE_INPUT_ABSOLUTE_X |
    699 					    WSMOUSE_INPUT_ABSOLUTE_Y);
    700 					DPRINTF(("\n"));
    701 				}
    702 			}
    703 		}
    704 	}
    705 
    706 	if (cnt & PIUCNT_PENSTC) {
    707 		if (sc->sc_tpstat == VRPIU_TP_STAT_RELEASE) {
    708 			/*
    709 			 * pen touch
    710 			 */
    711 			DPRINTF(("PEN TOUCH\n"));
    712 			sc->sc_tpstat = VRPIU_TP_STAT_TOUCH;
    713 			/*
    714 			 * We should not report button down event while
    715 			 * we don't know where it occur.
    716 			 */
    717 
    718 			/* set tp scan timeout	*/
    719 			callout_reset(&sc->sc_tptimeout, VRPIU_TP_SCAN_TIMEOUT,
    720 			    vrpiu_tp_timeout, sc);
    721 		}
    722 	} else {
    723 		vrpiu_tp_up(sc);
    724 	}
    725 
    726 	if (intrstat & PIUINT_PADDLOSTINTR) {
    727 		cnt |= PIUCNT_PIUSEQEN;
    728 		vrpiu_write(sc, PIUCNT_REG_W, cnt);
    729 	}
    730 
    731 	return;
    732 }
    733 
    734 void
    735 vrpiu_tp_up(struct vrpiu_softc *sc)
    736 {
    737 	if (sc->sc_tpstat == VRPIU_TP_STAT_TOUCH) {
    738 		/*
    739 		 * pen release
    740 		 */
    741 		DPRINTF(("RELEASE\n"));
    742 		sc->sc_tpstat = VRPIU_TP_STAT_RELEASE;
    743 
    744 		/* clear tp scan timeout	*/
    745 		callout_stop(&sc->sc_tptimeout);
    746 
    747 		/* button 0 UP */
    748 		wsmouse_input(sc->sc_wsmousedev, 0, 0, 0, 0, 0);
    749 	}
    750 }
    751 
    752 /* touch panel timeout handler */
    753 void
    754 vrpiu_tp_timeout(void *v)
    755 {
    756 	struct vrpiu_softc *sc = (struct vrpiu_softc *)v;
    757 
    758 #ifdef VRPIUDEBUG
    759 	{
    760 		unsigned int cnt = vrpiu_read(sc, PIUCNT_REG_W);
    761 		DPRINTF(("TIMEOUT: stat=%s  reg=%s\n",
    762 		    (sc->sc_tpstat == VRPIU_TP_STAT_TOUCH)?"touch":"release",
    763 		    (cnt & PIUCNT_PENSTC)?"touch":"release"));
    764 	}
    765 #endif
    766 	vrpiu_tp_up(sc);
    767 }
    768 
    769 /*
    770  * PIU interrupt handler.
    771  */
    772 int
    773 vrpiu_intr(void *arg)
    774 {
    775         struct vrpiu_softc *sc = arg;
    776 
    777 	vrpiu_ad_intr(sc);
    778 	vrpiu_tp_intr(sc);
    779 
    780 	return 0;
    781 }
    782 
    783 void
    784 vrpiu_start_powerstate(void *v)
    785 {
    786 	int mask;
    787 	struct vrpiu_softc *sc = (struct vrpiu_softc *)v;
    788 
    789 	vrpiu_ad_enable(sc);
    790 	mask = vrpiu_read(sc, PIUAMSK_REG_W);
    791 	mask &= 0xff8f; /* XXX */
    792 	vrpiu_write(sc, PIUAMSK_REG_W, mask);
    793 	vrpiu_write(sc, PIUASCN_REG_W, PIUACN_ADPSSTART);
    794 	/*
    795 	 * restart next A/D polling
    796 	 */
    797 	callout_reset(&sc->sc_adpoll, hz*vrpiu_ad_poll_interval,
    798 	    vrpiu_start_powerstate, sc);
    799 }
    800 
    801 void
    802 vrpiu_calc_powerstate(struct vrpiu_softc *sc)
    803 {
    804 	extern void vrgiu_diff_io(void);
    805 	vrpiu_ad_disable(sc);
    806 	VPRINTF(("vrpiu:AD: %d, %d, %d\n",
    807 	    sc->sc_battery.value[0],
    808 	    sc->sc_battery.value[1],
    809 	    sc->sc_battery.value[2]));
    810 	sc->sc_battery.nextpoll = hz*vrpiu_ad_poll_interval;
    811 	vrpiu_send_battery_event(sc);
    812 	/*
    813 	 * restart next A/D polling if change polling timming.
    814 	 */
    815 	if (sc->sc_battery.nextpoll != hz*vrpiu_ad_poll_interval)
    816 		callout_reset(&sc->sc_adpoll, sc->sc_battery.nextpoll,
    817 		    vrpiu_start_powerstate, sc);
    818 	if (bootverbose)
    819 		vrgiu_diff_io();
    820 
    821 }
    822 
    823 static void
    824 vrpiu_power(int why, void *arg)
    825 {
    826 	struct vrpiu_softc *sc = arg;
    827 
    828 	switch (why) {
    829 	case PWR_STANDBY:
    830 	case PWR_SUSPEND:
    831 		break;
    832 	case PWR_RESUME:
    833 		callout_reset(&sc->sc_adpoll, hz,
    834 		    vrpiu_start_powerstate, sc);
    835 		break;
    836 	}
    837 }
    838 
    839 static void
    840 vrpiu_send_battery_event(struct vrpiu_softc *sc)
    841 {
    842 #ifdef VRPIU_ADHOC_BATTERY_EVENT
    843 	static int batteryhigh = 0;
    844 	static int batterylow = 0;
    845 	static int critical = 0;
    846 
    847 	if (sc->sc_battery_spec == NULL
    848 	    || sc->sc_battery_spec->main_port == -1)
    849 		return;
    850 
    851 	if (sc->sc_battery.value[sc->sc_battery_spec->main_port]
    852 	    <= sc->sc_battery_spec->dc_critical) {
    853 		batteryhigh = 0;
    854 		config_hook_call(CONFIG_HOOK_PMEVENT,
    855 		    CONFIG_HOOK_PMEVENT_BATTERY,
    856 		    (void *)CONFIG_HOOK_BATT_CRITICAL);
    857 		batterylow = 3;
    858 		if (critical) {
    859 			config_hook_call(CONFIG_HOOK_PMEVENT,
    860 			    CONFIG_HOOK_PMEVENT_SUSPENDREQ,
    861 			    (void *)0);
    862 			critical = 0;
    863 			batterylow = 0;
    864 		}
    865 		critical++;
    866 	} else if (sc->sc_battery.value[sc->sc_battery_spec->main_port]
    867 	    <= sc->sc_battery_spec->dc_20p) {
    868 		batteryhigh = 0;
    869 		if (batterylow == 1)
    870 			config_hook_call(CONFIG_HOOK_PMEVENT,
    871 			    CONFIG_HOOK_PMEVENT_BATTERY,
    872 			    (void *)CONFIG_HOOK_BATT_20P);
    873 		config_hook_call(CONFIG_HOOK_PMEVENT,
    874 		    CONFIG_HOOK_PMEVENT_BATTERY,
    875 		    (void *)CONFIG_HOOK_BATT_LOW);
    876 		batterylow = 2;
    877 	} else if (sc->sc_battery.value[sc->sc_battery_spec->main_port]
    878 	    <= sc->sc_battery_spec->dc_50p) {
    879 		batteryhigh = 0;
    880 		if (batterylow == 0) {
    881 			batterylow = 1;
    882 			config_hook_call(CONFIG_HOOK_PMEVENT,
    883 			    CONFIG_HOOK_PMEVENT_BATTERY,
    884 			    (void *)CONFIG_HOOK_BATT_50P);
    885 		}
    886 	} else if (sc->sc_battery.value[sc->sc_battery_spec->main_port]
    887 	    >= sc->sc_battery_spec->ac_80p) {
    888 		batterylow = 0;
    889 		if (batteryhigh == 0) {
    890 			batteryhigh = 1;
    891 			config_hook_call(CONFIG_HOOK_PMEVENT,
    892 			    CONFIG_HOOK_PMEVENT_BATTERY,
    893 			    (void *)CONFIG_HOOK_BATT_80P);
    894 			config_hook_call(CONFIG_HOOK_PMEVENT,
    895 			    CONFIG_HOOK_PMEVENT_BATTERY,
    896 			    (void *)CONFIG_HOOK_BATT_HIGH);
    897 		}
    898 	}
    899 #else /* VRPIU_ADHOC_BATTERY_EVENT */
    900 	config_hook_call(CONFIG_HOOK_SET,
    901 	    CONFIG_HOOK_BATTERYVAL,
    902 	    (void *)&sc->sc_battery);
    903 #endif /* VRPIU_ADHOC_BATTERY_EVENT */
    904 }
    905 
    906 #ifdef DEBUG
    907 void
    908 vrpiu_dump_cntreg(unsigned int cnt)
    909 {
    910 	printf("%s", (cnt & PIUCNT_PENSTC) ? "Touch" : "Release");
    911 	printf(" state=");
    912 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_CmdScan)
    913 		printf("CmdScan");
    914 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_IntervalNextScan)
    915 		printf("IntervalNextScan");
    916 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_PenDataScan)
    917 		printf("PenDataScan");
    918 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_WaitPenTouch)
    919 		printf("WaitPenTouch");
    920 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_RFU)
    921 		printf("???");
    922 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_ADPortScan)
    923 		printf("ADPortScan");
    924 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Standby)
    925 		printf("Standby");
    926 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Disable)
    927 		printf("Disable");
    928 	if (cnt & PIUCNT_PADATSTOP)
    929 		printf(" AutoStop");
    930 	if (cnt & PIUCNT_PADATSTART)
    931 		printf(" AutoStart");
    932 	if (cnt & PIUCNT_PADSCANSTOP)
    933 		printf(" Stop");
    934 	if (cnt & PIUCNT_PADSCANSTART)
    935 		printf(" Start");
    936 	if (cnt & PIUCNT_PADSCANTYPE)
    937 		printf(" ScanPressure");
    938 	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_ADCONVERTER)
    939 		printf(" A/D");
    940 	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_COORDINATE)
    941 		printf(" Coordinate");
    942 	if (cnt & PIUCNT_PIUSEQEN)
    943 		printf(" SeqEn");
    944 	if ((cnt & PIUCNT_PIUPWR) == 0)
    945 		printf(" PowerOff");
    946 	if ((cnt & PIUCNT_PADRST) == 0)
    947 		printf(" Reset");
    948 	printf("\n");
    949 }
    950 #endif
    951