Annotation of Net2/arch/i386/isa/lms.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.