vrpiu.c revision 1.1
1/* $NetBSD: vrpiu.c,v 1.1 1999/12/28 03:15:18 takemura 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 40#include <hpcmips/vr/vripvar.h> 41#include <hpcmips/vr/cmureg.h> 42#include <hpcmips/vr/vrpiuvar.h> 43#include <hpcmips/vr/vrpiureg.h> 44 45/* 46 * contant and macro definitions 47 */ 48#define VRPIUDEBUG 49#ifdef VRPIUDEBUG 50int vrpiu_debug = 0; 51#define DPRINTF(arg) if (vrpiu_debug) printf arg; 52#else 53#define DPRINTF(arg) 54#endif 55 56#define SCALE (1024*1024) 57 58/* 59 * data types 60 */ 61/* struct vrpiu_softc is defined in vrpiuvar.h */ 62 63/* 64 * function prototypes 65 */ 66static int vrpiumatch __P((struct device *, struct cfdata *, void *)); 67static void vrpiuattach __P((struct device *, struct device *, void *)); 68 69static void vrpiu_write __P((struct vrpiu_softc *, int, unsigned short)); 70static u_short vrpiu_read __P((struct vrpiu_softc *, int)); 71 72static int vrpiu_intr __P((void *)); 73static void vrpiu_reset_param __P((struct vrpiu_softc *sc)); 74static void vrpiu_timeout __P((void *)); 75#ifdef DEBUG 76static void vrpiu_dump_cntreg __P((unsigned int cmd)); 77#endif 78 79static int vrpiu_enable __P((void *)); 80static int vrpiu_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); 81static void vrpiu_disable __P((void *)); 82 83/* mra is defined in mra.c */ 84int mra_Y_AX1_BX2_C __P((int *y, int ys, int *x1, int x1s, int *x2, int x2s, 85 int n, int scale, int *a, int *b, int *c)); 86 87/* 88 * static or global variables 89 */ 90struct cfattach vrpiu_ca = { 91 sizeof(struct vrpiu_softc), vrpiumatch, vrpiuattach 92}; 93 94const struct wsmouse_accessops vrpiu_accessops = { 95 vrpiu_enable, 96 vrpiu_ioctl, 97 vrpiu_disable, 98}; 99 100/* 101 * function definitions 102 */ 103static inline void 104vrpiu_write(sc, port, val) 105 struct vrpiu_softc *sc; 106 int port; 107 unsigned short val; 108{ 109 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val); 110} 111 112static inline u_short 113vrpiu_read(sc, port) 114 struct vrpiu_softc *sc; 115 int port; 116{ 117 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, port); 118} 119 120static int 121vrpiumatch(parent, cf, aux) 122 struct device *parent; 123 struct cfdata *cf; 124 void *aux; 125{ 126 return 1; 127} 128 129static void 130vrpiuattach(parent, self, aux) 131 struct device *parent; 132 struct device *self; 133 void *aux; 134{ 135 struct vrpiu_softc *sc = (struct vrpiu_softc *)self; 136 struct vrip_attach_args *va = aux; 137 struct wsmousedev_attach_args wsmaa; 138 139 bus_space_tag_t iot = va->va_iot; 140 bus_space_handle_t ioh; 141 142 if (bus_space_map(iot, va->va_addr, 1, 0, &ioh)) { 143 printf(": can't map bus space\n"); 144 return; 145 } 146 147 sc->sc_iot = iot; 148 sc->sc_ioh = ioh; 149 sc->sc_vrip = va->va_vc; 150 151 /* 152 * disable device until vrpiu_enable called 153 */ 154 sc->sc_stat = VRPIU_STAT_DISABLE; 155 156 vrpiu_reset_param(sc); 157#if 1 158 /* 159 * XXX, calibrate parameters 160 */ 161 { 162 static struct sample { 163 int xraw, yraw, x, y; 164 } D[] = { 165 /* samples got on my MC-R500 */ 166 { 502, 486, 320, 120 }, 167 { 55, 109, 0, 0 }, 168 { 54, 913, 0, 239 }, 169 { 973, 924, 639, 239 }, 170 { 975, 123, 639, 0 }, 171 }; 172 int s = sizeof(*D); 173 int n = sizeof(D)/s; 174 175 sc->sc_prmxs = 640; 176 sc->sc_prmys = 240; 177 178 if (mra_Y_AX1_BX2_C(&D->x, s, &D->xraw, s, &D->yraw, s, n, 179 SCALE, &sc->sc_prmax, &sc->sc_prmbx, 180 &sc->sc_prmcx) || 181 mra_Y_AX1_BX2_C(&D->y, s, &D->xraw, s, &D->yraw, s, n, 182 SCALE, &sc->sc_prmay, 183 &sc->sc_prmby, &sc->sc_prmcy)) { 184 printf(": MRA error"); 185 vrpiu_reset_param(sc); 186 } else { 187 DPRINTF(("Ax=%d Bx=%d Cx=%d\n", 188 sc->sc_prmax, sc->sc_prmbx, sc->sc_prmcx)); 189 DPRINTF(("Ay=%d By=%d Cy=%d\n", 190 sc->sc_prmay, sc->sc_prmby, sc->sc_prmcy)); 191 } 192 } 193#endif 194 195 /* install interrupt handler and enable interrupt */ 196 if (!(sc->sc_handler = 197 vrip_intr_establish(va->va_vc, va->va_intr, IPL_TTY, 198 vrpiu_intr, sc))) { 199 printf (": can't map interrupt line.\n"); 200 return; 201 } 202 203 /* mask level2 interrupt, stop scan sequencer and mask clock to piu */ 204 vrpiu_disable(sc); 205 206 printf("\n"); 207 208 wsmaa.accessops = &vrpiu_accessops; 209 wsmaa.accesscookie = sc; 210 211 /* 212 * attach the wsmouse 213 */ 214 sc->sc_wsmousedev = config_found(self, &wsmaa, wsmousedevprint); 215} 216 217int 218vrpiu_enable(v) 219 void *v; 220{ 221 struct vrpiu_softc *sc = v; 222 int s; 223 unsigned int cnt; 224 225 DPRINTF(("%s(%d): vrpiu_enable()\n", __FILE__, __LINE__)); 226 if (sc->sc_stat != VRPIU_STAT_DISABLE) 227 return EBUSY; 228 229 /* supply clock to PIU */ 230 __vrcmu_supply(CMUMSKPIU, 1); 231 232 /* Scan interval 0x7FF is maximum value */ 233 vrpiu_write(sc, PIUSIVL_REG_W, 0x7FF); 234 235 s = spltty(); 236 237 /* clear interrupt status */ 238 vrpiu_write(sc, PIUINT_REG_W, PIUINT_ALLINTR); 239 240 /* Disable -> Standby */ 241 cnt = PIUCNT_PIUPWR | 242 PIUCNT_PIUMODE_COORDINATE | 243 PIUCNT_PADATSTART | PIUCNT_PADATSTOP; 244 vrpiu_write(sc, PIUCNT_REG_W, cnt); 245 246 /* save pen status, touch or release */ 247 cnt = vrpiu_read(sc, PIUCNT_REG_W); 248 249 /* Level2 interrupt register setting */ 250 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 1); 251 252 /* 253 * Enable scan sequencer operation 254 * Standby -> WaitPenTouch 255 */ 256 cnt |= PIUCNT_PIUSEQEN; 257 vrpiu_write(sc, PIUCNT_REG_W, cnt); 258 259 /* transit status DISABLE -> TOUCH or RELEASE */ 260 sc->sc_stat = (cnt & PIUCNT_PENSTC) ? 261 VRPIU_STAT_TOUCH : VRPIU_STAT_RELEASE; 262 263 sc->sc_timeout = 1; 264 265 splx(s); 266 267 return 0; 268} 269 270void 271vrpiu_disable(v) 272 void *v; 273{ 274 struct vrpiu_softc *sc = v; 275 int s; 276 277 DPRINTF(("%s(%d): vrpiu_disable()\n", __FILE__, __LINE__)); 278 279 /* Set level2 interrupt register to mask interrupts */ 280 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 0); 281 282 sc->sc_stat = VRPIU_STAT_DISABLE; 283 284 /* Disable scan sequencer operation and power off */ 285 vrpiu_write(sc, PIUCNT_REG_W, 0); 286 287 /* mask clock to PIU */ 288 __vrcmu_supply(CMUMSKPIU, 1); 289 290 s = spltty(); 291 if (!sc->sc_timeout) { 292 untimeout(vrpiu_timeout, sc); 293 } 294 splx(s); 295} 296 297int 298vrpiu_ioctl(v, cmd, data, flag, p) 299 void *v; 300 u_long cmd; 301 caddr_t data; 302 int flag; 303 struct proc *p; 304{ 305 struct vrpiu_softc *sc = v; 306 307 DPRINTF(("%s(%d): vrpiu_ioctl(%08lx)\n", __FILE__, __LINE__, cmd)); 308 309 switch (cmd) { 310 case WSMOUSEIO_GTYPE: 311 *(u_int *)data = WSMOUSE_TYPE_PS2; 312 break; 313 314 case WSMOUSEIO_SRES: 315 printf("%s(%d): WSMOUSRIO_SRES is not supported", 316 __FILE__, __LINE__); 317 break; 318 319 default: 320 return (-1); 321 } 322 return (0); 323} 324 325/* 326 * PIU interrupt handler. 327 */ 328int 329vrpiu_intr(arg) 330 void *arg; 331{ 332 struct vrpiu_softc *sc = arg; 333 unsigned int cnt, i; 334 unsigned int intrstat, page; 335 int tpx0, tpx1, tpy0, tpy1; 336 int x, y, xraw, yraw; 337 338 intrstat = vrpiu_read(sc, PIUINT_REG_W); 339 340 if (sc->sc_stat == VRPIU_STAT_DISABLE) { 341 /* 342 * the device isn't enabled. just clear interrupt. 343 */ 344 vrpiu_write(sc, PIUINT_REG_W, intrstat); 345 return (0); 346 } 347 348 page = (intrstat & PIUINT_OVP) ? 1 : 0; 349 if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) { 350 tpx0 = vrpiu_read(sc, PIUPB(page, 0)); 351 tpx1 = vrpiu_read(sc, PIUPB(page, 1)); 352 tpy0 = vrpiu_read(sc, PIUPB(page, 2)); 353 tpy1 = vrpiu_read(sc, PIUPB(page, 3)); 354 } 355 356 if (intrstat & PIUINT_PADDLOSTINTR) { 357 page = page ? 0 : 1; 358 for (i = 0; i < 4; i++) 359 vrpiu_read(sc, PIUPB(page, i)); 360 } 361 362 cnt = vrpiu_read(sc, PIUCNT_REG_W); 363#ifdef DEBUG 364 if (vrpiu_debug) 365 vrpiu_dump_cntreg(cnt); 366#endif 367 368 /* clear interrupt status */ 369 vrpiu_write(sc, PIUINT_REG_W, intrstat); 370 371#if 0 372 DPRINTF(("vrpiu_intr: OVP=%d", page)); 373 if (intrstat & PIUINT_PADCMDINTR) 374 DPRINTF((" CMD")); 375 if (intrstat & PIUINT_PADADPINTR) 376 DPRINTF((" A/D")); 377 if (intrstat & PIUINT_PADPAGE1INTR) 378 DPRINTF((" PAGE1")); 379 if (intrstat & PIUINT_PADPAGE0INTR) 380 DPRINTF((" PAGE0")); 381 if (intrstat & PIUINT_PADDLOSTINTR) 382 DPRINTF((" DLOST")); 383 if (intrstat & PIUINT_PENCHGINTR) 384 DPRINTF((" PENCHG")); 385 DPRINTF(("\n")); 386#endif 387 if (cnt & PIUCNT_PENSTC) { 388 if (sc->sc_stat == VRPIU_STAT_RELEASE) { 389 /* 390 * pen touch 391 */ 392 DPRINTF(("PEN TOUCH\n")); 393 sc->sc_stat = VRPIU_STAT_TOUCH; 394 if (sc->sc_timeout) { 395 sc->sc_timeout = 0; 396 sc->sc_releasecount = 0; 397 timeout(vrpiu_timeout, sc, hz/3); 398 } 399 } 400 } else { 401 if (sc->sc_stat == VRPIU_STAT_TOUCH || 402 sc->sc_stat == VRPIU_STAT_DRAG) { 403 /* 404 * pen release 405 */ 406 DPRINTF(("RELEASE\n")); 407 sc->sc_stat = VRPIU_STAT_RELEASE; 408 if (!sc->sc_timeout) { 409 if (++sc->sc_releasecount == 2) { 410 untimeout(vrpiu_timeout, sc); 411 sc->sc_timeout = 1; 412 DPRINTF(("TAP!\n")); 413 /* button 0 DOWN */ 414 wsmouse_input(sc->sc_wsmousedev, 415 (1 << 0), 416 0, 0, 0); 417 /* button 0 UP */ 418 wsmouse_input(sc->sc_wsmousedev, 419 0, 0, 0, 0); 420 } 421 } 422 } 423 } 424 425 if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) { 426 if (!((tpx0 & PIUPB_VALID) && (tpx1 & PIUPB_VALID) && 427 (tpy0 & PIUPB_VALID) && (tpy1 & PIUPB_VALID))) { 428 printf("vrpiu: internal error, data is not valid!\n"); 429 } else { 430 tpx0 &= PIUPB_PADDATA_MASK; 431 tpx1 &= PIUPB_PADDATA_MASK; 432 tpy0 &= PIUPB_PADDATA_MASK; 433 tpy1 &= PIUPB_PADDATA_MASK; 434#define ISVALID(n, c, m) ((c) - (m) < (n) && (n) < (c) + (m)) 435 if (ISVALID(tpx0 + tpx1, 1024, 200) && 436 ISVALID(tpx0 + tpx1, 1024, 200)) { 437#if 0 438 DPRINTF(("%04x %04x %04x %04x\n", 439 tpx0, tpx1, tpy0, tpy1)); 440 DPRINTF(("%3d %3d (%4d %4d)->", tpx0, tpy0, 441 tpx0 + tpx1, tpy0 + tpy1); 442#endif 443 xraw = tpy1 * 1024 / (tpy0 + tpy1); 444 yraw = tpx1 * 1024 / (tpx0 + tpx1); 445 DPRINTF(("%3d %3d", xraw, yraw)); 446 447 x = (sc->sc_prmax*xraw + sc->sc_prmbx*yraw) / 448 SCALE + sc->sc_prmcx; 449 y = (sc->sc_prmay*xraw + sc->sc_prmby*yraw) / 450 SCALE + sc->sc_prmcy; 451 if (x < 0) x = 0; 452 if (y < 0) y = 0; 453 if (sc->sc_prmxs <= x) 454 x = sc->sc_prmxs - 1; 455 if (sc->sc_prmys <= y) 456 y = sc->sc_prmys - 1; 457 DPRINTF(("->%4d %4d", x, y)); 458 if (sc->sc_stat == VRPIU_STAT_TOUCH) { 459 sc->sc_stat = VRPIU_STAT_DRAG; 460 sc->sc_x = x; 461 sc->sc_y = y; 462 } else 463 if (sc->sc_stat == VRPIU_STAT_DRAG) { 464 DPRINTF((" delta %d %d", 465 x - sc->sc_x, y - sc->sc_y)); 466 wsmouse_input(sc->sc_wsmousedev, 467 0, /* all buttons up */ 468 x - sc->sc_x, /* dx */ 469 y - sc->sc_y, /* dy */ 470 0); /* dz */ 471 sc->sc_x = x; 472 sc->sc_y = y; 473 } 474 DPRINTF(("\n")); 475 } 476 } 477 } 478 479 if (intrstat & PIUINT_PADDLOSTINTR) { 480 cnt |= PIUCNT_PIUSEQEN; 481 vrpiu_write(sc, PIUCNT_REG_W, cnt); 482 } 483 484 return 0; 485} 486 487void 488vrpiu_reset_param(sc) 489 struct vrpiu_softc *sc; 490{ 491 sc->sc_prmax = SCALE; 492 sc->sc_prmbx = 0; 493 sc->sc_prmcx = 0; 494 sc->sc_prmxs = PIUPB_PADDATA_MAX; 495 sc->sc_prmay = 0; 496 sc->sc_prmby = SCALE; 497 sc->sc_prmcy = 0; 498 sc->sc_prmys = PIUPB_PADDATA_MAX; 499} 500 501void 502vrpiu_timeout(arg) 503 void *arg; 504{ 505 struct vrpiu_softc *sc = arg; 506 sc->sc_timeout = 1; 507} 508 509#ifdef DEBUG 510void 511vrpiu_dump_cntreg(cnt) 512 unsigned int cnt; 513{ 514 printf("%s", (cnt & PIUCNT_PENSTC) ? "Touch" : "Release"); 515 printf(" state="); 516 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_CmdScan) 517 printf("CmdScan"); 518 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_IntervalNextScan) 519 printf("IntervalNextScan"); 520 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_PenDataScan) 521 printf("PenDataScan"); 522 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_WaitPenTouch) 523 printf("WaitPenTouch"); 524 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_RFU) 525 printf("???"); 526 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_ADPortScan) 527 printf("ADPortScan"); 528 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Standby) 529 printf("Standby"); 530 if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Disable) 531 printf("Disable"); 532 if (cnt & PIUCNT_PADATSTOP) 533 printf(" AutoStop"); 534 if (cnt & PIUCNT_PADATSTART) 535 printf(" AutoStart"); 536 if (cnt & PIUCNT_PADSCANSTOP) 537 printf(" Stop"); 538 if (cnt & PIUCNT_PADSCANSTART) 539 printf(" Start"); 540 if (cnt & PIUCNT_PADSCANTYPE) 541 printf(" ScanPressure"); 542 if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_ADCONVERTER) 543 printf(" A/D"); 544 if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_COORDINATE) 545 printf(" Coordinate"); 546 if (cnt & PIUCNT_PIUSEQEN) 547 printf(" SeqEn"); 548 if ((cnt & PIUCNT_PIUPWR) == 0) 549 printf(" PowerOff"); 550 if ((cnt & PIUCNT_PADRST) == 0) 551 printf(" Reset"); 552 printf("\n"); 553} 554#endif 555