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