Home | History | Annotate | Line # | Download | only in vr
vrpiu.c revision 1.5
      1 /*	$NetBSD: vrpiu.c,v 1.5 2000/06/13 05:59:55 matt Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1999 Shin Takemura All rights reserved.
      5  * Copyright (c) 1999 PocketBSD Project. All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  *
     28  */
     29 
     30 #include <sys/param.h>
     31 #include <sys/systm.h>
     32 #include <sys/device.h>
     33 #include <sys/kernel.h>
     34 
     35 #include <dev/wscons/wsconsio.h>
     36 #include <dev/wscons/wsmousevar.h>
     37 
     38 #include <machine/bus.h>
     39 #include <machine/platid.h>
     40 #include <machine/platid_mask.h>
     41 
     42 #include <hpcmips/dev/tpcalibvar.h>
     43 #include <hpcmips/vr/vripvar.h>
     44 #include <hpcmips/vr/cmureg.h>
     45 #include <hpcmips/vr/vrpiuvar.h>
     46 #include <hpcmips/vr/vrpiureg.h>
     47 
     48 /*
     49  * contant and macro definitions
     50  */
     51 #define VRPIUDEBUG
     52 #ifdef VRPIUDEBUG
     53 int	vrpiu_debug = 0;
     54 #define	DPRINTF(arg) if (vrpiu_debug) printf arg;
     55 #else
     56 #define	DPRINTF(arg)
     57 #endif
     58 
     59 /*
     60  * data types
     61  */
     62 /* struct vrpiu_softc is defined in vrpiuvar.h */
     63 
     64 /*
     65  * function prototypes
     66  */
     67 static int	vrpiumatch __P((struct device *, struct cfdata *, void *));
     68 static void	vrpiuattach __P((struct device *, struct device *, void *));
     69 
     70 static void	vrpiu_write __P((struct vrpiu_softc *, int, unsigned short));
     71 static u_short	vrpiu_read __P((struct vrpiu_softc *, int));
     72 
     73 static int	vrpiu_intr __P((void *));
     74 #ifdef DEBUG
     75 static void	vrpiu_dump_cntreg __P((unsigned int cmd));
     76 #endif
     77 
     78 static int	vrpiu_enable __P((void *));
     79 static int	vrpiu_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
     80 static void	vrpiu_disable __P((void *));
     81 
     82 /* mra is defined in mra.c */
     83 int mra_Y_AX1_BX2_C __P((int *y, int ys, int *x1, int x1s, int *x2, int x2s,
     84 			 int n, int scale, int *a, int *b, int *c));
     85 
     86 /*
     87  * static or global variables
     88  */
     89 struct cfattach vrpiu_ca = {
     90 	sizeof(struct vrpiu_softc), vrpiumatch, vrpiuattach
     91 };
     92 
     93 const struct wsmouse_accessops vrpiu_accessops = {
     94 	vrpiu_enable,
     95 	vrpiu_ioctl,
     96 	vrpiu_disable,
     97 };
     98 
     99 /*
    100  * function definitions
    101  */
    102 static inline void
    103 vrpiu_write(sc, port, val)
    104 	struct vrpiu_softc *sc;
    105 	int port;
    106 	unsigned short val;
    107 {
    108 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
    109 }
    110 
    111 static inline u_short
    112 vrpiu_read(sc, port)
    113 	struct vrpiu_softc *sc;
    114 	int port;
    115 {
    116 	return bus_space_read_2(sc->sc_iot, sc->sc_ioh, port);
    117 }
    118 
    119 static int
    120 vrpiumatch(parent, cf, aux)
    121 	struct device *parent;
    122 	struct cfdata *cf;
    123 	void *aux;
    124 {
    125 	return 1;
    126 }
    127 
    128 static void
    129 vrpiuattach(parent, self, aux)
    130 	struct device *parent;
    131 	struct device *self;
    132 	void *aux;
    133 {
    134 	struct vrpiu_softc *sc = (struct vrpiu_softc *)self;
    135 	struct vrip_attach_args *va = aux;
    136 	struct wsmousedev_attach_args wsmaa;
    137 
    138 	bus_space_tag_t iot = va->va_iot;
    139 	bus_space_handle_t ioh;
    140 
    141 	if (bus_space_map(iot, va->va_addr, 1, 0, &ioh)) {
    142 		printf(": can't map bus space\n");
    143 		return;
    144 	}
    145 
    146 	sc->sc_iot = iot;
    147 	sc->sc_ioh = ioh;
    148 	sc->sc_vrip = va->va_vc;
    149 
    150 	/*
    151 	 * disable device until vrpiu_enable called
    152 	 */
    153 	sc->sc_stat = VRPIU_STAT_DISABLE;
    154 
    155 	tpcalib_init(&sc->sc_tpcalib);
    156 #if 1
    157 	/*
    158 	 * XXX, calibrate parameters
    159 	 */
    160 	{
    161 		int i;
    162 		static const struct {
    163 			platid_mask_t *mask;
    164 			struct wsmouse_calibcoords coords;
    165 		} calibrations[] = {
    166 			{ &platid_mask_MACH_NEC_MCR_700A,
    167 				{ 0, 0, 799, 599,
    168 				  4,
    169 				{ { 115,  80,   0,   0 },
    170 				  { 115, 966,   0, 599 },
    171 				  { 912,  80, 799,   0 },
    172 				  { 912, 966, 799, 599 } } } },
    173 
    174 			{ NULL,		/* samples got on my MC-R500 */
    175 				{ 0, 0, 639, 239,
    176 				5,
    177 				{ { 502, 486, 320, 120 },
    178 				  {  55, 109,   0,   0 },
    179 				  {  54, 913,   0, 239 },
    180 				  { 973, 924, 639, 239 },
    181 				  { 975, 123, 639,   0 } } } },
    182 		};
    183 		for (i = 0; ; i++) {
    184 			if (calibrations[i].mask == NULL
    185 			    || platid_match(&platid, calibrations[i].mask))
    186 				break;
    187 		}
    188 		tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
    189 			      (caddr_t)&calibrations[i].coords, 0, 0);
    190 	}
    191 #endif
    192 
    193 	/* install interrupt handler and enable interrupt */
    194 	if (!(sc->sc_handler =
    195 	      vrip_intr_establish(va->va_vc, va->va_intr, IPL_TTY,
    196 				  vrpiu_intr, sc))) {
    197 		printf (": can't map interrupt line.\n");
    198 		return;
    199 	}
    200 
    201 	/* mask level2 interrupt, stop scan sequencer and mask clock to piu */
    202 	vrpiu_disable(sc);
    203 
    204 	printf("\n");
    205 
    206 	wsmaa.accessops = &vrpiu_accessops;
    207 	wsmaa.accesscookie = sc;
    208 
    209 	/*
    210 	 * attach the wsmouse
    211 	 */
    212 	sc->sc_wsmousedev = config_found(self, &wsmaa, wsmousedevprint);
    213 }
    214 
    215 int
    216 vrpiu_enable(v)
    217 	void *v;
    218 {
    219 	struct vrpiu_softc *sc = v;
    220 	int s;
    221 	unsigned int cnt;
    222 
    223 	DPRINTF(("%s(%d): vrpiu_enable()\n", __FILE__, __LINE__));
    224 	if (sc->sc_stat != VRPIU_STAT_DISABLE)
    225 		return EBUSY;
    226 
    227 	/* supply clock to PIU */
    228 	__vrcmu_supply(CMUMSKPIU, 1);
    229 
    230 	/* Scan interval 0x7FF is maximum value */
    231 	vrpiu_write(sc, PIUSIVL_REG_W, 0x7FF);
    232 
    233 	s = spltty();
    234 
    235 	/* clear interrupt status */
    236 	vrpiu_write(sc, PIUINT_REG_W, PIUINT_ALLINTR);
    237 
    238 	/* Disable -> Standby */
    239 	cnt = PIUCNT_PIUPWR |
    240 		PIUCNT_PIUMODE_COORDINATE |
    241 		PIUCNT_PADATSTART | PIUCNT_PADATSTOP;
    242 	vrpiu_write(sc, PIUCNT_REG_W, cnt);
    243 
    244 	/* save pen status, touch or release */
    245 	cnt = vrpiu_read(sc, PIUCNT_REG_W);
    246 
    247 	/* Level2 interrupt register setting */
    248 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 1);
    249 
    250 	/*
    251 	 * Enable scan sequencer operation
    252 	 * Standby -> WaitPenTouch
    253 	 */
    254 	cnt |= PIUCNT_PIUSEQEN;
    255 	vrpiu_write(sc, PIUCNT_REG_W, cnt);
    256 
    257 	/* transit status DISABLE -> TOUCH or RELEASE */
    258 	sc->sc_stat = (cnt & PIUCNT_PENSTC) ?
    259 		VRPIU_STAT_TOUCH : VRPIU_STAT_RELEASE;
    260 
    261 	splx(s);
    262 
    263 	return 0;
    264 }
    265 
    266 void
    267 vrpiu_disable(v)
    268 	void *v;
    269 {
    270 	struct vrpiu_softc *sc = v;
    271 
    272 	DPRINTF(("%s(%d): vrpiu_disable()\n", __FILE__, __LINE__));
    273 
    274 	/* Set level2 interrupt register to mask interrupts */
    275 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 0);
    276 
    277 	sc->sc_stat = VRPIU_STAT_DISABLE;
    278 
    279 	/* Disable scan sequencer operation and power off */
    280 	vrpiu_write(sc, PIUCNT_REG_W, 0);
    281 
    282 	/* mask clock to PIU */
    283 	__vrcmu_supply(CMUMSKPIU, 1);
    284 }
    285 
    286 int
    287 vrpiu_ioctl(v, cmd, data, flag, p)
    288 	void *v;
    289 	u_long cmd;
    290 	caddr_t data;
    291 	int flag;
    292 	struct proc *p;
    293 {
    294 	struct vrpiu_softc *sc = v;
    295 
    296 	DPRINTF(("%s(%d): vrpiu_ioctl(%08lx)\n", __FILE__, __LINE__, cmd));
    297 
    298 	switch (cmd) {
    299 	case WSMOUSEIO_GTYPE:
    300 		*(u_int *)data = WSMOUSE_TYPE_TPANEL;
    301 		break;
    302 
    303 	case WSMOUSEIO_SRES:
    304 		printf("%s(%d): WSMOUSRIO_SRES is not supported",
    305 		       __FILE__, __LINE__);
    306 		break;
    307 
    308 	case WSMOUSEIO_SCALIBCOORDS:
    309 	case WSMOUSEIO_GCALIBCOORDS:
    310                 return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, p);
    311 
    312 	default:
    313 		return (-1);
    314 	}
    315 	return (0);
    316 }
    317 
    318 /*
    319  * PIU interrupt handler.
    320  */
    321 int
    322 vrpiu_intr(arg)
    323 	void *arg;
    324 {
    325         struct vrpiu_softc *sc = arg;
    326 	unsigned int cnt, i;
    327 	unsigned int intrstat, page;
    328 	int tpx0, tpx1, tpy0, tpy1;
    329 	int x, y, xraw, yraw;
    330 
    331 	intrstat = vrpiu_read(sc, PIUINT_REG_W);
    332 
    333 	if (sc->sc_stat == VRPIU_STAT_DISABLE) {
    334 		/*
    335 		 * the device isn't enabled. just clear interrupt.
    336 		 */
    337 		vrpiu_write(sc, PIUINT_REG_W, intrstat);
    338 		return (0);
    339 	}
    340 
    341 	page = (intrstat & PIUINT_OVP) ? 1 : 0;
    342 	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
    343 		tpx0 = vrpiu_read(sc, PIUPB(page, 0));
    344 		tpx1 = vrpiu_read(sc, PIUPB(page, 1));
    345 		tpy0 = vrpiu_read(sc, PIUPB(page, 2));
    346 		tpy1 = vrpiu_read(sc, PIUPB(page, 3));
    347 	}
    348 
    349 	if (intrstat & PIUINT_PADDLOSTINTR) {
    350 		page = page ? 0 : 1;
    351 		for (i = 0; i < 4; i++)
    352 			vrpiu_read(sc, PIUPB(page, i));
    353 	}
    354 
    355 	cnt = vrpiu_read(sc, PIUCNT_REG_W);
    356 #ifdef DEBUG
    357 	if (vrpiu_debug)
    358 		vrpiu_dump_cntreg(cnt);
    359 #endif
    360 
    361 	/* clear interrupt status */
    362 	vrpiu_write(sc, PIUINT_REG_W, intrstat);
    363 
    364 #if 0
    365 	DPRINTF(("vrpiu_intr: OVP=%d", page));
    366 	if (intrstat & PIUINT_PADCMDINTR)
    367 		DPRINTF((" CMD"));
    368 	if (intrstat & PIUINT_PADADPINTR)
    369 		DPRINTF((" A/D"));
    370 	if (intrstat & PIUINT_PADPAGE1INTR)
    371 		DPRINTF((" PAGE1"));
    372 	if (intrstat & PIUINT_PADPAGE0INTR)
    373 		DPRINTF((" PAGE0"));
    374 	if (intrstat & PIUINT_PADDLOSTINTR)
    375 		DPRINTF((" DLOST"));
    376 	if (intrstat & PIUINT_PENCHGINTR)
    377 		DPRINTF((" PENCHG"));
    378 	DPRINTF(("\n"));
    379 #endif
    380 	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
    381 		if (!((tpx0 & PIUPB_VALID) && (tpx1 & PIUPB_VALID) &&
    382 		      (tpy0 & PIUPB_VALID) && (tpy1 & PIUPB_VALID))) {
    383 			printf("vrpiu: internal error, data is not valid!\n");
    384 		} else {
    385 			tpx0 &= PIUPB_PADDATA_MASK;
    386 			tpx1 &= PIUPB_PADDATA_MASK;
    387 			tpy0 &= PIUPB_PADDATA_MASK;
    388 			tpy1 &= PIUPB_PADDATA_MASK;
    389 #define ISVALID(n, c, m)	((c) - (m) < (n) && (n) < (c) + (m))
    390 			if (ISVALID(tpx0 + tpx1, 1024, 200) &&
    391 			    ISVALID(tpx0 + tpx1, 1024, 200)) {
    392 #if 0
    393 				DPRINTF(("%04x %04x %04x %04x\n",
    394 					 tpx0, tpx1, tpy0, tpy1));
    395 				DPRINTF(("%3d %3d (%4d %4d)->", tpx0, tpy0,
    396 					 tpx0 + tpx1, tpy0 + tpy1));
    397 #endif
    398 				xraw = tpy1 * 1024 / (tpy0 + tpy1);
    399 				yraw = tpx1 * 1024 / (tpx0 + tpx1);
    400 				DPRINTF(("%3d %3d", xraw, yraw));
    401 
    402 				tpcalib_trans(&sc->sc_tpcalib,
    403 					      xraw, yraw, &x, &y);
    404 
    405 				DPRINTF(("->%4d %4d", x, y));
    406 				wsmouse_input(sc->sc_wsmousedev,
    407 					      (cnt & PIUCNT_PENSTC) ? 1 : 0,
    408 					      x, /* x */
    409 					      y, /* y */
    410 					      0, /* z */
    411 					      WSMOUSE_INPUT_ABSOLUTE_X |
    412 					      WSMOUSE_INPUT_ABSOLUTE_Y);
    413 				DPRINTF(("\n"));
    414 			}
    415 		}
    416 	}
    417 
    418 	if (cnt & PIUCNT_PENSTC) {
    419 		if (sc->sc_stat == VRPIU_STAT_RELEASE) {
    420 			/*
    421 			 * pen touch
    422 			 */
    423 			DPRINTF(("PEN TOUCH\n"));
    424 			sc->sc_stat = VRPIU_STAT_TOUCH;
    425 			/*
    426 			 * We should not report button down event while
    427 			 * we don't know where it occur.
    428 			 */
    429 		}
    430 	} else {
    431 		if (sc->sc_stat == VRPIU_STAT_TOUCH) {
    432 			/*
    433 			 * pen release
    434 			 */
    435 			DPRINTF(("RELEASE\n"));
    436 			sc->sc_stat = VRPIU_STAT_RELEASE;
    437 			/* button 0 UP */
    438 			wsmouse_input(sc->sc_wsmousedev,
    439 				      0,
    440 				      0, 0, 0, 0);
    441 		}
    442 	}
    443 
    444 	if (intrstat & PIUINT_PADDLOSTINTR) {
    445 		cnt |= PIUCNT_PIUSEQEN;
    446 		vrpiu_write(sc, PIUCNT_REG_W, cnt);
    447 	}
    448 
    449 	return 0;
    450 }
    451 
    452 #ifdef DEBUG
    453 void
    454 vrpiu_dump_cntreg(cnt)
    455 	unsigned int cnt;
    456 {
    457 	printf("%s", (cnt & PIUCNT_PENSTC) ? "Touch" : "Release");
    458 	printf(" state=");
    459 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_CmdScan)
    460 		printf("CmdScan");
    461 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_IntervalNextScan)
    462 		printf("IntervalNextScan");
    463 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_PenDataScan)
    464 		printf("PenDataScan");
    465 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_WaitPenTouch)
    466 		printf("WaitPenTouch");
    467 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_RFU)
    468 		printf("???");
    469 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_ADPortScan)
    470 		printf("ADPortScan");
    471 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Standby)
    472 		printf("Standby");
    473 	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Disable)
    474 		printf("Disable");
    475 	if (cnt & PIUCNT_PADATSTOP)
    476 		printf(" AutoStop");
    477 	if (cnt & PIUCNT_PADATSTART)
    478 		printf(" AutoStart");
    479 	if (cnt & PIUCNT_PADSCANSTOP)
    480 		printf(" Stop");
    481 	if (cnt & PIUCNT_PADSCANSTART)
    482 		printf(" Start");
    483 	if (cnt & PIUCNT_PADSCANTYPE)
    484 		printf(" ScanPressure");
    485 	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_ADCONVERTER)
    486 		printf(" A/D");
    487 	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_COORDINATE)
    488 		printf(" Coordinate");
    489 	if (cnt & PIUCNT_PIUSEQEN)
    490 		printf(" SeqEn");
    491 	if ((cnt & PIUCNT_PIUPWR) == 0)
    492 		printf(" PowerOff");
    493 	if ((cnt & PIUCNT_PADRST) == 0)
    494 		printf(" Reset");
    495 	printf("\n");
    496 }
    497 #endif
    498