|
|
1.1 ! root 1: /*- ! 2: * Copyright (c) 1992, 1993 Erik Forsberg. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms, with or without ! 6: * modification, are permitted provided that the following conditions ! 7: * are met: ! 8: * 1. Redistributions of source code must retain the above copyright ! 9: * notice, this list of conditions and the following disclaimer. ! 10: * ! 11: * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED ! 12: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ! 13: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN ! 14: * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ! 15: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ! 16: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ! 17: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ! 18: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ! 19: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ! 20: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! 21: */ ! 22: ! 23: /* ! 24: * Ported to 386bsd Oct 17, 1992 ! 25: * Sandi Donno, Computer Science, University of Cape Town, South Africa ! 26: * Please send bug reports to [email protected] ! 27: * ! 28: * Thanks are also due to Rick Macklem, [email protected] - ! 29: * although I was only partially successful in getting the alpha release ! 30: * of his "driver for the Logitech and ATI Inport Bus mice for use with ! 31: * 386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless ! 32: * found his code to be an invaluable reference when porting this driver ! 33: * to 386bsd. ! 34: * ! 35: * Further modifications for latest 386BSD+patchkit and port to NetBSD, ! 36: * Andrew Herbert <[email protected]> - 8 June 1993 ! 37: * ! 38: * Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by ! 39: * Andrew Herbert - 12 June 1993 ! 40: * ! 41: * Modified for PS/2 mouse by Charles Hannum <[email protected]> ! 42: * - 13 June 1993 ! 43: */ ! 44: ! 45: #include "pms.h" ! 46: ! 47: #if NPMS > 0 ! 48: ! 49: #include "param.h" ! 50: #include "kernel.h" ! 51: #include "systm.h" ! 52: #include "buf.h" ! 53: #include "malloc.h" ! 54: #include "ioctl.h" ! 55: #include "tty.h" ! 56: #include "file.h" ! 57: #ifdef NetBSD ! 58: #include "select.h" ! 59: #endif ! 60: #include "proc.h" ! 61: #include "vnode.h" ! 62: ! 63: #include "i386/include/mouse.h" ! 64: #include "i386/include/pio.h" /* Julian's fast IO macros */ ! 65: #include "i386/isa/isa_device.h" ! 66: ! 67: #define DATA 0 /* Offset for data port, read-write */ ! 68: #define CNTRL 4 /* Offset for control port, write-only */ ! 69: #define STATUS 4 /* Offset for status port, read-only */ ! 70: ! 71: /* status bits */ ! 72: #define PMS_OUTPUT_ACK 0x02 /* output acknowledge */ ! 73: ! 74: /* controller commands */ ! 75: #define PMS_ENABLE 0xa7 /* enable auxiliary port */ ! 76: #define PMS_DISABLE 0xa8 /* disable auxiliary port */ ! 77: #define PMS_INT_ENABLE 0x47 /* enable controller interrupts */ ! 78: #define PMS_INT_DISABLE 0x65 /* disable controller interrupts */ ! 79: ! 80: /* mouse commands */ ! 81: #define PMS_SET_RES 0xe8 /* set resolution */ ! 82: #define PMS_SET_SCALE 0xe9 /* set scaling factor */ ! 83: #define PMS_SET_STREAM 0xea /* set streaming mode */ ! 84: #define PMS_SET_SAMPLE 0xf3 /* set sampling rate */ ! 85: #define PMS_DEV_ENABLE 0xf4 /* mouse on */ ! 86: #define PMS_DEV_DISABLE 0xf5 /* mouse off */ ! 87: #define PMS_RESET 0xff /* reset */ ! 88: ! 89: #define PMSUNIT(dev) (minor(dev) >> 1) ! 90: ! 91: #ifndef min ! 92: #define min(x,y) (x < y ? x : y) ! 93: #endif min ! 94: ! 95: int pmsprobe (struct isa_device *); ! 96: int pmsattach (struct isa_device *); ! 97: ! 98: static int pmsaddr[NPMS]; /* Base I/O port addresses per unit */ ! 99: ! 100: #define MSBSZ 1024 /* Output queue size (pwr of 2 is best) */ ! 101: ! 102: struct ringbuf { ! 103: int count, first, last; ! 104: char queue[MSBSZ]; ! 105: }; ! 106: ! 107: static struct pms_softc { /* Driver status information */ ! 108: struct ringbuf inq; /* Input queue */ ! 109: #ifdef NetBSD ! 110: struct selinfo rsel; ! 111: #else ! 112: pid_t rsel; /* Process selecting for Input */ ! 113: #endif ! 114: unsigned char state; /* Mouse driver state */ ! 115: unsigned char status; /* Mouse button status */ ! 116: unsigned char button; /* Previous mouse button status bits */ ! 117: int x, y; /* accumulated motion in the X,Y axis */ ! 118: } pms_softc[NPMS]; ! 119: ! 120: #define OPEN 1 /* Device is open */ ! 121: #define ASLP 2 /* Waiting for mouse data */ ! 122: ! 123: struct isa_driver pmsdriver = { pmsprobe, pmsattach, "pms" }; ! 124: ! 125: int pmsprobe(struct isa_device *dvp) ! 126: { ! 127: /* XXX: Needs a real probe routine. */ ! 128: ! 129: return (1); ! 130: } ! 131: ! 132: static inline void pms_write(int ioport, u_char value) ! 133: { ! 134: outb(ioport+CNTRL, 0xd4); ! 135: outb(ioport+DATA, value); ! 136: while (!(inb(ioport+STATUS) & PMS_OUTPUT_ACK)); ! 137: } ! 138: ! 139: static inline void pms_command(int ioport, u_char value) ! 140: { ! 141: outb(ioport+CNTRL, 0x60); ! 142: outb(ioport+DATA, value); ! 143: } ! 144: ! 145: int pmsattach(struct isa_device *dvp) ! 146: { ! 147: int unit = dvp->id_unit; ! 148: int ioport = dvp->id_iobase; ! 149: struct pms_softc *sc = &pms_softc[unit]; ! 150: ! 151: /* Save I/O base address */ ! 152: ! 153: pmsaddr[unit] = ioport; ! 154: ! 155: /* Disable mouse interrupts */ ! 156: ! 157: pms_command(ioport, PMS_DISABLE); ! 158: #if 0 ! 159: pms_command(ioport, PMS_INT_DISABLE); ! 160: #endif ! 161: pms_write(ioport, PMS_DEV_DISABLE); ! 162: ! 163: pms_write(ioport, PMS_SET_RES); ! 164: pms_write(ioport, 0x03); /* 8 counts/mm */ ! 165: pms_write(ioport, PMS_SET_SCALE); ! 166: pms_write(ioport, 0x02); /* 2:1 */ ! 167: pms_write(ioport, PMS_SET_SAMPLE); ! 168: pms_write(ioport, 0x64); /* 100 samples/sec */ ! 169: pms_write(ioport, PMS_SET_STREAM); ! 170: ! 171: /* Setup initial state */ ! 172: ! 173: sc->state = 0; ! 174: ! 175: /* Done */ ! 176: ! 177: return(0); ! 178: } ! 179: ! 180: int pmsopen(dev_t dev, int flag, int fmt, struct proc *p) ! 181: { ! 182: int unit = PMSUNIT(dev); ! 183: struct pms_softc *sc; ! 184: int ioport; ! 185: ! 186: /* Validate unit number */ ! 187: ! 188: if (unit >= NPMS) ! 189: return(ENXIO); ! 190: ! 191: /* Get device data */ ! 192: ! 193: sc = &pms_softc[unit]; ! 194: ioport = pmsaddr[unit]; ! 195: ! 196: /* If device does not exist */ ! 197: ! 198: if (ioport == 0) ! 199: return(ENXIO); ! 200: ! 201: /* Disallow multiple opens */ ! 202: ! 203: if (sc->state & OPEN) ! 204: return(EBUSY); ! 205: ! 206: /* Initialize state */ ! 207: ! 208: sc->state |= OPEN; ! 209: #ifdef NetBSD ! 210: sc->rsel.si_pid = 0; ! 211: sc->rsel.si_coll = 0; ! 212: #else ! 213: sc->rsel = 0; ! 214: #endif ! 215: sc->status = 0; ! 216: sc->button = 0; ! 217: sc->x = 0; ! 218: sc->y = 0; ! 219: ! 220: /* Allocate and initialize a ring buffer */ ! 221: ! 222: sc->inq.count = sc->inq.first = sc->inq.last = 0; ! 223: ! 224: /* Enable Bus Mouse interrupts */ ! 225: ! 226: pms_write(ioport, PMS_DEV_ENABLE); ! 227: #if 0 ! 228: pms_command(ioport, PMS_INT_ENABLE); ! 229: #endif ! 230: pms_command(ioport, PMS_ENABLE); ! 231: ! 232: /* Successful open */ ! 233: ! 234: return(0); ! 235: } ! 236: ! 237: int pmsclose(dev_t dev, int flag, int fmt, struct proc *p) ! 238: { ! 239: int unit, ioport; ! 240: struct pms_softc *sc; ! 241: ! 242: /* Get unit and associated info */ ! 243: ! 244: unit = PMSUNIT(dev); ! 245: sc = &pms_softc[unit]; ! 246: ioport = pmsaddr[unit]; ! 247: ! 248: /* Disable further mouse interrupts */ ! 249: ! 250: pms_command(ioport, PMS_DISABLE); ! 251: #if 0 ! 252: pms_command(ioport, PMS_INT_DISABLE); ! 253: #endif ! 254: pms_write(ioport, PMS_DEV_DISABLE); ! 255: ! 256: /* Complete the close */ ! 257: ! 258: sc->state &= ~OPEN; ! 259: ! 260: /* close is almost always successful */ ! 261: ! 262: return(0); ! 263: } ! 264: ! 265: int pmsread(dev_t dev, struct uio *uio, int flag) ! 266: { ! 267: int s; ! 268: int error = 0; /* keep compiler quiet, even though initialisation ! 269: is unnecessary */ ! 270: unsigned length; ! 271: struct pms_softc *sc; ! 272: unsigned char buffer[100]; ! 273: ! 274: /* Get device information */ ! 275: ! 276: sc = &pms_softc[PMSUNIT(dev)]; ! 277: ! 278: /* Block until mouse activity occured */ ! 279: ! 280: s = spltty(); ! 281: while (sc->inq.count == 0) { ! 282: if (minor(dev) & 0x1) { ! 283: splx(s); ! 284: return(EWOULDBLOCK); ! 285: } ! 286: sc->state |= ASLP; ! 287: error = tsleep((caddr_t)sc, PZERO | PCATCH, "pmsrea", 0); ! 288: if (error != 0) { ! 289: splx(s); ! 290: return(error); ! 291: } ! 292: } ! 293: ! 294: /* Transfer as many chunks as possible */ ! 295: ! 296: while (sc->inq.count > 0 && uio->uio_resid > 0) { ! 297: length = min(sc->inq.count, uio->uio_resid); ! 298: if (length > sizeof(buffer)) ! 299: length = sizeof(buffer); ! 300: ! 301: /* Remove a small chunk from input queue */ ! 302: ! 303: if (sc->inq.first + length >= MSBSZ) { ! 304: bcopy(&sc->inq.queue[sc->inq.first], ! 305: buffer, MSBSZ - sc->inq.first); ! 306: bcopy(sc->inq.queue, &buffer[MSBSZ-sc->inq.first], ! 307: length - (MSBSZ - sc->inq.first)); ! 308: } ! 309: else ! 310: bcopy(&sc->inq.queue[sc->inq.first], buffer, length); ! 311: ! 312: sc->inq.first = (sc->inq.first + length) % MSBSZ; ! 313: sc->inq.count -= length; ! 314: ! 315: /* Copy data to user process */ ! 316: ! 317: error = uiomove(buffer, length, uio); ! 318: if (error) ! 319: break; ! 320: } ! 321: ! 322: sc->x = sc->y = 0; ! 323: ! 324: /* Allow interrupts again */ ! 325: ! 326: splx(s); ! 327: return(error); ! 328: } ! 329: ! 330: int pmsioctl(dev_t dev, caddr_t addr, int cmd, int flag, struct proc *p) ! 331: { ! 332: struct pms_softc *sc; ! 333: struct mouseinfo info; ! 334: int s, error; ! 335: ! 336: /* Get device information */ ! 337: ! 338: sc = &pms_softc[PMSUNIT(dev)]; ! 339: ! 340: /* Perform IOCTL command */ ! 341: ! 342: switch (cmd) { ! 343: ! 344: case MOUSEIOCREAD: ! 345: ! 346: /* Don't modify info while calculating */ ! 347: ! 348: s = spltty(); ! 349: ! 350: /* Build mouse status octet */ ! 351: ! 352: info.status = sc->status; ! 353: if (sc->x || sc->y) ! 354: info.status |= MOVEMENT; ! 355: ! 356: /* Encode X and Y motion as good as we can */ ! 357: ! 358: if (sc->x > 127) ! 359: info.xmotion = 127; ! 360: else if (sc->x < -128) ! 361: info.xmotion = -128; ! 362: else ! 363: info.xmotion = sc->x; ! 364: ! 365: if (sc->y > 127) ! 366: info.ymotion = 127; ! 367: else if (sc->y < -128) ! 368: info.ymotion = -128; ! 369: else ! 370: info.ymotion = sc->y; ! 371: ! 372: /* Reset historical information */ ! 373: ! 374: sc->x = 0; ! 375: sc->y = 0; ! 376: sc->status &= ~BUTCHNGMASK; ! 377: ! 378: /* Allow interrupts and copy result buffer */ ! 379: ! 380: splx(s); ! 381: error = copyout(&info, addr, sizeof(struct mouseinfo)); ! 382: break; ! 383: ! 384: default: ! 385: error = EINVAL; ! 386: break; ! 387: } ! 388: ! 389: /* Return error code */ ! 390: ! 391: return(error); ! 392: } ! 393: ! 394: void pmsintr(unit) ! 395: int unit; ! 396: { ! 397: struct pms_softc *sc = &pms_softc[unit]; ! 398: int ioport = pmsaddr[unit]; ! 399: static int state = 0; ! 400: static char buttons, dx, dy; ! 401: char changed; ! 402: ! 403: switch (state) { ! 404: ! 405: case 0: ! 406: buttons = inb(ioport + DATA); ! 407: if (!(buttons & 0xc0)) ! 408: ++state; ! 409: buttons = ~(((buttons&1) << 2) | (buttons&2)); ! 410: break; ! 411: ! 412: case 1: ! 413: dx = inb(ioport + DATA) << 2; ! 414: dx >>= 2; ! 415: ++state; ! 416: break; ! 417: ! 418: case 2: ! 419: dy = inb(ioport + DATA) << 2; ! 420: dy >>= 2; ! 421: state = 0; ! 422: ! 423: dy = -dy; ! 424: ! 425: changed = buttons ^ sc->button; ! 426: sc->button = buttons; ! 427: sc->status = buttons | (sc->status & ~BUTSTATMASK) | (changed << 3); ! 428: ! 429: /* Update accumulated movements */ ! 430: ! 431: sc->x += dx; ! 432: sc->y += dy; ! 433: ! 434: /* If device in use and a change occurred... */ ! 435: ! 436: if (sc->state & OPEN && (dx || dy || changed)) { ! 437: sc->inq.queue[sc->inq.last++] = 0x40 | ! 438: (buttons ^ BUTSTATMASK); ! 439: sc->inq.queue[sc->inq.last++ % MSBSZ] = dx; ! 440: sc->inq.queue[sc->inq.last++ % MSBSZ] = dy; ! 441: sc->inq.queue[sc->inq.last++ % MSBSZ] = 0; ! 442: sc->inq.queue[sc->inq.last++ % MSBSZ] = 0; ! 443: sc->inq.last = sc->inq.last % MSBSZ; ! 444: sc->inq.count += 5; ! 445: ! 446: if (sc->state & ASLP) { ! 447: sc->state &= ~ASLP; ! 448: wakeup((caddr_t)sc); ! 449: } ! 450: #ifdef NetBSD ! 451: selwakeup(&sc->rsel); ! 452: #else ! 453: if (sc->rsel) { ! 454: selwakeup(sc->rsel, 0); ! 455: sc->rsel = 0; ! 456: } ! 457: #endif ! 458: } ! 459: ! 460: break; ! 461: } ! 462: } ! 463: ! 464: int pmsselect(dev_t dev, int rw, struct proc *p) ! 465: { ! 466: int s, ret; ! 467: struct pms_softc *sc = &pms_softc[PMSUNIT(dev)]; ! 468: ! 469: /* Silly to select for output */ ! 470: ! 471: if (rw == FWRITE) ! 472: return(0); ! 473: ! 474: /* Return true if a mouse event available */ ! 475: ! 476: s = spltty(); ! 477: if (sc->inq.count) ! 478: ret = 1; ! 479: else { ! 480: #ifdef NetBSD ! 481: selrecord(p, &sc->rsel); ! 482: #else ! 483: sc->rsel = p->p_pid; ! 484: #endif ! 485: ret = 0; ! 486: } ! 487: splx(s); ! 488: ! 489: return(ret); ! 490: } ! 491: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.