Annotation of Net2/arch/i386/isa/pms.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:  *  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

unix.superglobalmegacorp.com

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