|
|
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: ! 42: #include "lms.h" ! 43: ! 44: #if NLMS > 0 ! 45: ! 46: #include "param.h" ! 47: #include "kernel.h" ! 48: #include "systm.h" ! 49: #include "buf.h" ! 50: #include "malloc.h" ! 51: #include "ioctl.h" ! 52: #include "tty.h" ! 53: #include "file.h" ! 54: #ifdef NetBSD ! 55: #include "select.h" ! 56: #endif ! 57: #include "proc.h" ! 58: #include "vnode.h" ! 59: ! 60: #include "i386/include/mouse.h" ! 61: #include "i386/include/pio.h" /* Julian's fast IO macros */ ! 62: #include "i386/isa/isa_device.h" ! 63: ! 64: #define DATA 0 /* Offset for data port, read-only */ ! 65: #define SIGN 1 /* Offset for signature port, read-write */ ! 66: #define INTR 2 /* Offset for interrupt port, read-only */ ! 67: #define CNTRL 2 /* Offset for control port, write-only */ ! 68: #define CONFIG 3 /* for configuration port, read-write */ ! 69: ! 70: #define LMSUNIT(dev) (minor(dev) >> 1) ! 71: ! 72: #ifndef min ! 73: #define min(x,y) (x < y ? x : y) ! 74: #endif min ! 75: ! 76: int lmsprobe (struct isa_device *); ! 77: int lmsattach (struct isa_device *); ! 78: ! 79: static int lmsaddr[NLMS]; /* Base I/O port addresses per unit */ ! 80: ! 81: #define MSBSZ 1024 /* Output queue size (pwr of 2 is best) */ ! 82: ! 83: struct ringbuf { ! 84: int count, first, last; ! 85: char queue[MSBSZ]; ! 86: }; ! 87: ! 88: static struct lms_softc { /* Driver status information */ ! 89: struct ringbuf inq; /* Input queue */ ! 90: #ifdef NetBSD ! 91: struct selinfo rsel; ! 92: #else ! 93: pid_t rsel; /* Process selecting for Input */ ! 94: #endif ! 95: unsigned char state; /* Mouse driver state */ ! 96: unsigned char status; /* Mouse button status */ ! 97: unsigned char button; /* Previous mouse button status bits */ ! 98: int x, y; /* accumulated motion in the X,Y axis */ ! 99: } lms_softc[NLMS]; ! 100: ! 101: #define OPEN 1 /* Device is open */ ! 102: #define ASLP 2 /* Waiting for mouse data */ ! 103: ! 104: struct isa_driver lmsdriver = { lmsprobe, lmsattach, "lms" }; ! 105: ! 106: int lmsprobe(struct isa_device *dvp) ! 107: { ! 108: int ioport = dvp->id_iobase; ! 109: int val; ! 110: ! 111: /* Configure and check for port present */ ! 112: ! 113: outb(ioport+CONFIG, 0x91); ! 114: DELAY(10); ! 115: outb(ioport+SIGN, 0x0C); ! 116: DELAY(10); ! 117: val = inb(ioport+SIGN); ! 118: DELAY(10); ! 119: outb(ioport+SIGN, 0x50); ! 120: ! 121: /* Check if something is out there */ ! 122: ! 123: if (val == 0x0C && inb(ioport+SIGN) == 0x50) ! 124: return(4); ! 125: ! 126: /* Not present */ ! 127: ! 128: return(0); ! 129: } ! 130: ! 131: int lmsattach(struct isa_device *dvp) ! 132: { ! 133: int unit = dvp->id_unit; ! 134: int ioport = dvp->id_iobase; ! 135: struct lms_softc *sc = &lms_softc[unit]; ! 136: ! 137: /* Save I/O base address */ ! 138: ! 139: lmsaddr[unit] = ioport; ! 140: ! 141: /* Disable mouse interrupts */ ! 142: ! 143: outb(ioport+CNTRL, 0x10); ! 144: ! 145: /* Setup initial state */ ! 146: ! 147: sc->state = 0; ! 148: ! 149: /* Done */ ! 150: ! 151: return(0); ! 152: } ! 153: ! 154: int lmsopen(dev_t dev, int flag, int fmt, struct proc *p) ! 155: { ! 156: int unit = LMSUNIT(dev); ! 157: struct lms_softc *sc; ! 158: int ioport; ! 159: ! 160: /* Validate unit number */ ! 161: ! 162: if (unit >= NLMS) ! 163: return(ENXIO); ! 164: ! 165: /* Get device data */ ! 166: ! 167: sc = &lms_softc[unit]; ! 168: ioport = lmsaddr[unit]; ! 169: ! 170: /* If device does not exist */ ! 171: ! 172: if (ioport == 0) ! 173: return(ENXIO); ! 174: ! 175: /* Disallow multiple opens */ ! 176: ! 177: if (sc->state & OPEN) ! 178: return(EBUSY); ! 179: ! 180: /* Initialize state */ ! 181: ! 182: sc->state |= OPEN; ! 183: #ifdef NetBSD ! 184: sc->rsel.si_pid = 0; ! 185: sc->rsel.si_coll = 0; ! 186: #else ! 187: sc->rsel = 0; ! 188: #endif ! 189: sc->status = 0; ! 190: sc->button = 0; ! 191: sc->x = 0; ! 192: sc->y = 0; ! 193: ! 194: /* Allocate and initialize a ring buffer */ ! 195: ! 196: sc->inq.count = sc->inq.first = sc->inq.last = 0; ! 197: ! 198: /* Enable Bus Mouse interrupts */ ! 199: ! 200: outb(ioport+CNTRL, 0); ! 201: ! 202: /* Successful open */ ! 203: ! 204: return(0); ! 205: } ! 206: ! 207: int lmsclose(dev_t dev, int flag, int fmt, struct proc *p) ! 208: { ! 209: int unit, ioport; ! 210: struct lms_softc *sc; ! 211: ! 212: /* Get unit and associated info */ ! 213: ! 214: unit = LMSUNIT(dev); ! 215: sc = &lms_softc[unit]; ! 216: ioport = lmsaddr[unit]; ! 217: ! 218: /* Disable further mouse interrupts */ ! 219: ! 220: outb(ioport+CNTRL, 0x10); ! 221: ! 222: /* Complete the close */ ! 223: ! 224: sc->state &= ~OPEN; ! 225: ! 226: /* close is almost always successful */ ! 227: ! 228: return(0); ! 229: } ! 230: ! 231: int lmsread(dev_t dev, struct uio *uio, int flag) ! 232: { ! 233: int s; ! 234: int error = 0; /* keep compiler quiet, even though initialisation ! 235: is unnecessary */ ! 236: unsigned length; ! 237: struct lms_softc *sc; ! 238: unsigned char buffer[100]; ! 239: ! 240: /* Get device information */ ! 241: ! 242: sc = &lms_softc[LMSUNIT(dev)]; ! 243: ! 244: /* Block until mouse activity occured */ ! 245: ! 246: s = spltty(); ! 247: while (sc->inq.count == 0) { ! 248: if (minor(dev) & 0x1) { ! 249: splx(s); ! 250: return(EWOULDBLOCK); ! 251: } ! 252: sc->state |= ASLP; ! 253: error = tsleep((caddr_t)sc, PZERO | PCATCH, "lmsrea", 0); ! 254: if (error != 0) { ! 255: splx(s); ! 256: return(error); ! 257: } ! 258: } ! 259: ! 260: /* Transfer as many chunks as possible */ ! 261: ! 262: while (sc->inq.count > 0 && uio->uio_resid > 0) { ! 263: length = min(sc->inq.count, uio->uio_resid); ! 264: if (length > sizeof(buffer)) ! 265: length = sizeof(buffer); ! 266: ! 267: /* Remove a small chunk from input queue */ ! 268: ! 269: if (sc->inq.first + length >= MSBSZ) { ! 270: bcopy(&sc->inq.queue[sc->inq.first], ! 271: buffer, MSBSZ - sc->inq.first); ! 272: bcopy(sc->inq.queue, &buffer[MSBSZ-sc->inq.first], ! 273: length - (MSBSZ - sc->inq.first)); ! 274: } ! 275: else ! 276: bcopy(&sc->inq.queue[sc->inq.first], buffer, length); ! 277: ! 278: sc->inq.first = (sc->inq.first + length) % MSBSZ; ! 279: sc->inq.count -= length; ! 280: ! 281: /* Copy data to user process */ ! 282: ! 283: error = uiomove(buffer, length, uio); ! 284: if (error) ! 285: break; ! 286: } ! 287: ! 288: sc->x = sc->y = 0; ! 289: ! 290: /* Allow interrupts again */ ! 291: ! 292: splx(s); ! 293: return(error); ! 294: } ! 295: ! 296: int lmsioctl(dev_t dev, caddr_t addr, int cmd, int flag, struct proc *p) ! 297: { ! 298: struct lms_softc *sc; ! 299: struct mouseinfo info; ! 300: int s, error; ! 301: ! 302: /* Get device information */ ! 303: ! 304: sc = &lms_softc[LMSUNIT(dev)]; ! 305: ! 306: /* Perform IOCTL command */ ! 307: ! 308: switch (cmd) { ! 309: ! 310: case MOUSEIOCREAD: ! 311: ! 312: /* Don't modify info while calculating */ ! 313: ! 314: s = spltty(); ! 315: ! 316: /* Build mouse status octet */ ! 317: ! 318: info.status = sc->status; ! 319: if (sc->x || sc->y) ! 320: info.status |= MOVEMENT; ! 321: ! 322: /* Encode X and Y motion as good as we can */ ! 323: ! 324: if (sc->x > 127) ! 325: info.xmotion = 127; ! 326: else if (sc->x < -127) ! 327: info.xmotion = -127; ! 328: else ! 329: info.xmotion = sc->x; ! 330: ! 331: if (sc->y > 127) ! 332: info.ymotion = 127; ! 333: else if (sc->y < -127) ! 334: info.ymotion = -127; ! 335: else ! 336: info.ymotion = sc->y; ! 337: ! 338: /* Reset historical information */ ! 339: ! 340: sc->x = 0; ! 341: sc->y = 0; ! 342: sc->status &= ~BUTCHNGMASK; ! 343: ! 344: /* Allow interrupts and copy result buffer */ ! 345: ! 346: splx(s); ! 347: error = copyout(&info, addr, sizeof(struct mouseinfo)); ! 348: break; ! 349: ! 350: default: ! 351: error = EINVAL; ! 352: break; ! 353: } ! 354: ! 355: /* Return error code */ ! 356: ! 357: return(error); ! 358: } ! 359: ! 360: void lmsintr(unit) ! 361: int unit; ! 362: { ! 363: struct lms_softc *sc = &lms_softc[unit]; ! 364: int ioport = lmsaddr[unit]; ! 365: char hi, lo, dx, dy, buttons, changed; ! 366: ! 367: outb(ioport+CNTRL, 0xAB); ! 368: hi = inb(ioport+DATA) & 15; ! 369: outb(ioport+CNTRL, 0x90); ! 370: lo = inb(ioport+DATA) & 15; ! 371: dx = (hi << 4) | lo; ! 372: dx = (dx == -128) ? -127 : dx; ! 373: ! 374: outb(ioport+CNTRL, 0xF0); ! 375: hi = inb(ioport+DATA); ! 376: outb(ioport+CNTRL, 0xD0); ! 377: lo = inb(ioport+DATA); ! 378: outb(ioport+CNTRL, 0); ! 379: dy = ((hi & 15) << 4) | (lo & 15); ! 380: dy = (dy == -128) ? 127 : -dy; ! 381: ! 382: buttons = (~hi >> 5) & 7; ! 383: changed = buttons ^ sc->button; ! 384: sc->button = buttons; ! 385: sc->status = buttons | (sc->status & ~BUTSTATMASK) | (changed << 3); ! 386: ! 387: /* Update accumulated movements */ ! 388: ! 389: sc->x += dx; ! 390: sc->y += dy; ! 391: ! 392: /* If device in use and a change occurred... */ ! 393: ! 394: if (sc->state & OPEN && (dx || dy || changed)) { ! 395: sc->inq.queue[sc->inq.last++] = 0x80 | (buttons ^ BUTSTATMASK); ! 396: sc->inq.queue[sc->inq.last++ % MSBSZ] = dx; ! 397: sc->inq.queue[sc->inq.last++ % MSBSZ] = dy; ! 398: sc->inq.queue[sc->inq.last++ % MSBSZ] = 0; ! 399: sc->inq.queue[sc->inq.last++ % MSBSZ] = 0; ! 400: sc->inq.last = sc->inq.last % MSBSZ; ! 401: sc->inq.count += 5; ! 402: ! 403: if (sc->state & ASLP) { ! 404: sc->state &= ~ASLP; ! 405: wakeup((caddr_t)sc); ! 406: } ! 407: #ifdef NetBSD ! 408: selwakeup(&sc->rsel); ! 409: #else ! 410: if (sc->rsel) { ! 411: selwakeup(sc->rsel, 0); ! 412: sc->rsel = 0; ! 413: } ! 414: #endif ! 415: } ! 416: } ! 417: ! 418: int lmsselect(dev_t dev, int rw, struct proc *p) ! 419: { ! 420: int s, ret; ! 421: struct lms_softc *sc = &lms_softc[LMSUNIT(dev)]; ! 422: ! 423: /* Silly to select for output */ ! 424: ! 425: if (rw == FWRITE) ! 426: return(0); ! 427: ! 428: /* Return true if a mouse event available */ ! 429: ! 430: s = spltty(); ! 431: if (sc->inq.count) ! 432: ret = 1; ! 433: else { ! 434: #ifdef NetBSD ! 435: selrecord(p, &sc->rsel); ! 436: #else ! 437: sc->rsel = p->p_pid; ! 438: #endif ! 439: ret = 0; ! 440: } ! 441: splx(s); ! 442: ! 443: return(ret); ! 444: } ! 445: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.