home *** CD-ROM | disk | FTP | other *** search
- /* lmouse.c - Logitech Bus Mouse Device Driver for SysV/386 R3.2
- **
- ** Copyright (C) 1989,1991 by Mark W. Snitily
- **
- ** Permission to use, copy, modify, and distribute this software and its
- ** documentation for any purpose and without fee is hereby granted, provided
- ** that the above copyright notice appear in all copies and that both that
- ** copyright notice and this permission notice appear in supporting
- ** documentation. This software is provided "as is" without express or
- ** implied warranty.
- **
- ** 29-May-89 MWS Initial code completed and debugged
- ** 31-Jan-91 MWS Copyright notice added for general distribution
- **
- */
-
- #define VPIX
-
- #include "sys/param.h"
- #include "sys/types.h"
- #include "sys/sysmacros.h"
- #include "sys/dir.h"
- #include "sys/signal.h"
- #include "sys/user.h"
- #include "sys/errno.h"
-
- /* Definitions for Logitech Mouse */
-
- /* Base I/O addresses of mouse registers */
- #define DATA_REG 0x23c /* Data register (read only) */
- #define SIGNATURE_REG 0x23d /* Signature register (read/write) */
- #define INTERRUPT_REG 0x23e /* Interrupt register (read only) */
- #define CONTROL_REG 0x23e /* Control register (write only) */
- #define CONFIG_REG 0x23f /* Configuration register (read/write) */
-
- /* Definitions of bits in interrupt register. */
- #define IRQ5 0x01
- #define IRQ4 0x02
- #define IRQ3 0x04
- #define IRQ2 0x08
-
- /* Definitions of bits in control register. */
- #define DINT 0x10 /* Disable Interrupts */
- #define SHL 0x20 /* Select Hi/Lo (0/1) nibble */
- #define SXY 0x40 /* Select X/Y (0/1) counter */
- #define HC 0x80 /* Hold Counters (latch counters on 0->1 edge) */
-
- /* Magic number needed for configuration register. */
- #define CONFIG_BYTE 0x91
-
- #define BUT3STAT 0x01
- #define BUT2STAT 0x02
- #define BUT1STAT 0x04
-
- #define BUT3CHNG 0x08
- #define BUT2CHNG 0x10
- #define BUT1CHNG 0x20
- #define MOVEMENT 0x40
-
- #define BUTSTATMASK 0x07
- #define BUTCHNGMASK 0x38
-
- struct mouseinfo
- { unsigned char status;
- char xmotion, ymotion;
- };
-
- /* Ioctl definitions */
- #define MOUSEIOC ('M'<<8)
- #define MOUSEIOCREAD (MOUSEIOC|60)
-
- #ifdef VPIX
- #define VPC_MOUSE_READ MOUSEIOCREAD
- #endif /* VPIX */
-
- #ifdef VPIX
- #include "sys/immu.h"
- #include "sys/region.h"
- #include "sys/proc.h"
- #include "sys/tss.h"
- #include "sys/v86.h"
- #endif /* VPIX */
-
- static char mousepresent;
- static char mouseinuse;
- static char mousemode;
- static char last_buttons;
- static char mousestatus;
- static int xmotion, ymotion;
- #ifdef VPIX
- static struct proc *ectproc;
- static char rupted;
- #endif /* VPIX */
-
- #define UPPERLIM 127
- #define LOWERLIM -128
- #define ONEBYTE(x) ((x)>UPPERLIM ? UPPERLIM : (x)<LOWERLIM ? LOWERLIM : (x))
-
- /*---------------------------------------------------------------------------*/
- void logminit()
- {
- unsigned char id1, id2, toggles, irq;
- int i;
-
- /* Assume no mouse in system. */
- mouseinuse = mousepresent = 0;
-
- /* Initialize configuration register with the required magic number. */
- outb(CONFIG_REG, CONFIG_BYTE);
-
- /* See if we can store into the signature register. If not return. */
- outb(SIGNATURE_REG, 0xA5);
- for (i=0; i<1000; i++); /* busy loop */
- id1 = inb(SIGNATURE_REG);
- if (id1 != 0xA5) {
- printf("logminit: SIGNATURE_REG = 0x%x (should equal 0xA5)\n", id1);
- printf("Logitech Bus Mouse not loaded.\n");
- return;
- }
-
- /* See which bits toggle in the interrupt register. */
- outb(CONTROL_REG, 0); /* Make sure interrupts are enabled. */
- id1 = inb(INTERRUPT_REG);
- #ifdef DEBUG
- printf("logminit: Initial value of interrupt reg = 0x%x\n", id1);
- #endif /* DEBUG */
- toggles = 0;
- for (i=0; i<10000; i++) {
- id2 = inb(INTERRUPT_REG);
- toggles |= id1 ^ id2;
- id1 = id2;
- }
- outb(CONTROL_REG, DINT); /* Disable interrupts just to be safe. */
-
- /* Based upon which bit(s) toggled, determine which IRQ is being used.
- If nothing toggled, then something is wrong so don't set the
- mousepresent flag. */
- if (toggles & IRQ5) irq = 5;
- else if (toggles & IRQ2) irq = 2;
- else if (toggles & IRQ3) irq = 3;
- else if (toggles & IRQ4) irq = 4;
- else {
- printf("logminit: IRQ line did not respond (INTERRUPT_REG = 0x%x)\n",
- toggles);
- printf("Logitech Bus Mouse not loaded.\n");
- return;
- }
- printf("Logitech Bus Mouse loaded with IRQ%d\n", irq);
-
- /* Set control register. Set HC to 1: A rising edge of HC transfers
- the content of the counters into latches and resets the counters;
- Disable interrupts; (also selects low nibble of the X counter.) */
- outb(CONTROL_REG, HC | DINT);
-
- mousepresent = 1;
-
- } /* logminit */
-
- /*---------------------------------------------------------------------------*/
- void logmopen(dev, flag)
- int dev, flag;
- {
- #ifdef DEBUG
- printf("logmopen: dev = 0x%x, flag = 0x%x\n", dev, flag);
- #endif /* DEBUG */
-
- /* Insist on minor device 0 */
- if (minor(dev)) { u.u_error = ENXIO; return; }
-
- /* Make sure there is a mouse. */
- if (!mousepresent) { u.u_error = ENXIO; return; }
-
- /* Enforce exclusive use. */
- if (mouseinuse) { u.u_error = EBUSY; return; }
-
- xmotion = ymotion = 0;
- mousestatus = last_buttons = 0;
-
- #ifdef VPIX
- ectproc = u.u_procp;
- rupted = 0;
- #endif /* VPIX */
-
- mouseinuse = 1;
-
- /* Set HC to 0 and enable interrupts. */
- outb(CONTROL_REG, 0);
-
- } /* logmopen */
-
- /*---------------------------------------------------------------------------*/
- void logmclose(dev)
- int dev;
- {
- #ifdef DEBUG
- printf("logmclose\n");
- #endif /* DEBUG */
-
- /* Insist on minor device 0 */
- if (minor(dev)) { u.u_error = ENXIO; return; }
-
- /* Make sure there is a mouse. */
- if (!mousepresent) { u.u_error = ENXIO; return; }
-
- /* Make sure mouse has been opened. */
- if (!mouseinuse) { u.u_error = EACCES; return; }
-
- /* Reset the mouse to make sure it does not interrupt. */
- outb(CONTROL_REG, DINT);
- mouseinuse = 0;
-
- } /* logmclose */
-
- /*---------------------------------------------------------------------------*/
- void logmioctl(dev, cmd, arg, flag)
- int dev, cmd, flag;
- caddr_t arg;
- {
- struct mouseinfo info;
- register int intmask;
-
- #ifdef DEBUG
- unsigned char ir;
-
- printf("logmioctl\n");
- #endif /* DEBUG */
-
- /* Insist on minor device 0 */
- if (minor(dev)) { u.u_error = ENXIO; return; }
-
- /* Make sure there is a mouse. */
- if (!mousepresent) { u.u_error = ENXIO; return; }
-
- /* Make sure mouse has been opened. */
- if (!mouseinuse) { u.u_error = EACCES; return; }
-
- switch (cmd) {
- #ifdef DEBUG
- case 0:
- printf("logmioctl: outb(CONTROL_REG, 0 )\n");
- outb(CONTROL_REG, 0 );
- break;
- case 1:
- printf("logmioctl: outb(CONTROL_REG, DINT)\n");
- outb(CONTROL_REG, DINT);
- break;
- case 2:
- printf("logmioctl: outb(CONTROL_REG, SHL )\n");
- outb(CONTROL_REG, SHL );
- break;
- case 3:
- printf("logmioctl: outb(CONTROL_REG, SHL | DINT)\n");
- outb(CONTROL_REG, SHL | DINT);
- break;
- case 4:
- printf("logmioctl: outb(CONTROL_REG, SXY )\n");
- outb(CONTROL_REG, SXY );
- break;
- case 5:
- printf("logmioctl: outb(CONTROL_REG, SXY | DINT)\n");
- outb(CONTROL_REG, SXY | DINT);
- break;
- case 6:
- printf("logmioctl: outb(CONTROL_REG, SXY | SHL )\n");
- outb(CONTROL_REG, SXY | SHL );
- break;
- case 7:
- printf("logmioctl: outb(CONTROL_REG, SXY | SHL | DINT)\n");
- outb(CONTROL_REG, SXY | SHL | DINT);
- break;
- case 8:
- printf("logmioctl: outb(CONTROL_REG, HC )\n");
- outb(CONTROL_REG, HC );
- break;
- case 9:
- printf("logmioctl: outb(CONTROL_REG, HC | DINT)\n");
- outb(CONTROL_REG, HC | DINT);
- break;
- case 10:
- printf("logmioctl: outb(CONTROL_REG, HC | SHL )\n");
- outb(CONTROL_REG, HC | SHL );
- break;
- case 11:
- printf("logmioctl: outb(CONTROL_REG, HC | SHL | DINT)\n");
- outb(CONTROL_REG, HC | SHL | DINT);
- break;
- case 12:
- printf("logmioctl: outb(CONTROL_REG, HC | SXY )\n");
- outb(CONTROL_REG, HC | SXY );
- break;
- case 13:
- printf("logmioctl: outb(CONTROL_REG, HC | SXY | DINT)\n");
- outb(CONTROL_REG, HC | SXY | DINT);
- break;
- case 14:
- printf("logmioctl: outb(CONTROL_REG, HC | SXY | SHL )\n");
- outb(CONTROL_REG, HC | SXY | SHL );
- break;
- case 15:
- printf("logmioctl: outb(CONTROL_REG, HC | SXY | SHL | DINT)\n");
- outb(CONTROL_REG, HC | SXY | SHL | DINT);
- break;
-
- case 20:
- ir = inb(DATA_REG);
- printf("logmioctl: inb(DATA_REG) = 0x%x\n", ir);
- break;
- case 21:
- ir = inb(SIGNATURE_REG);
- printf("logmioctl: inb(SIGNATURE_REG) = 0x%x\n", ir);
- break;
- case 22:
- ir = inb(INTERRUPT_REG);
- printf("logmioctl: inb(INTERRUPT_REG) = 0x%x\n", ir);
- break;
- case 23:
- ir = inb(CONFIG_REG);
- printf("logmioctl: inb(CONFIG_REG) = 0x%x\n", ir);
- break;
- case 24:
- outb(CONFIG_REG, CONFIG_BYTE);
- printf("logmioctl: outb(CONFIG_REG, CONFIG_BYTE)\n");
- break;
- #endif /* DEBUG */
-
- default:
- /* Return error "Invalid argument". */
- u.u_error = EINVAL;
- #ifdef DEBUG
- printf("logmioctl: unknown cmd = 0x%x\n", cmd);
- #endif /* DEBUG */
- break;
-
- case MOUSEIOCREAD:
- /* Prevent mouse interrupts during update. */
- intmask = splhi();
-
- /* Read and reset the accumulated interrupt info. */
-
- /* This emulates the microsoft bus mouse status return. */
- info.status = mousestatus;
- if (xmotion || ymotion) info.status |= MOVEMENT;
-
- info.xmotion = ONEBYTE(xmotion);
- info.ymotion = ONEBYTE(ymotion);
- xmotion = ymotion = 0;
- mousestatus &= ~BUTCHNGMASK; /* clear "button changed" bits */
- #ifdef VPIX
- rupted = 0;
- #endif /* VPIX */
-
- /* Resume mouse interrupts. */
- splx(intmask);
-
- if (copyout(&info, arg, sizeof info)) u.u_error = EFAULT;
- break;
- } /* switch */
- } /* logmioctl */
-
- /*---------------------------------------------------------------------------*/
- void logmintr(ivect)
- int ivect;
- {
- unsigned char lo, hi, buttons, changed_buttons;
- int dx, dy;
-
- /* Ignore if mouse is not present. */
- if (!mousepresent) return;
-
- /* Print error on console if mouse has not been opened. */
- if (!mouseinuse) {
- #ifdef DEBUG
- printf("logmintr: Unsolicited INT %d\n", ivect);
- #endif /* DEBUG */
- outb(CONTROL_REG, DINT); /* disable interrupts */
- return;
- }
-
- /* Read low X nibble. */
- outb(CONTROL_REG, HC);
- lo = inb(DATA_REG) & 0x0F;
-
- /* Read high X nibble. */
- outb(CONTROL_REG, HC | SHL);
- hi = inb(DATA_REG) & 0x0F;
-
- /* Combine high and low X nibbles. */
- dx = (char) ((hi << 4) | lo); /* force dx to be signed */
-
- /* Read low Y nibble. */
- outb(CONTROL_REG, HC | SXY);
- lo = inb(DATA_REG) & 0x0F;
-
- /* Read high Y nibble. */
- outb(CONTROL_REG, HC | SXY | SHL);
- hi = inb(DATA_REG);
-
- /* Extract and invert the button bits.
- After inverting, a set bit means the button was pressed down. */
- buttons = (~hi >> 5) & 0x07;
- changed_buttons = buttons ^ last_buttons;
- last_buttons = buttons;
-
- /* Combine high and low X nibbles. */
- dy = (char) (((hi & 0x0F) << 4) | lo); /* force dy to be signed */
-
- /* This code emulates the Microsoft bus mouse status (except for the MOTION
- bit which is set in the ioctl routine). State changes are or'ed over
- any number of interrupts, but the buttons bits are always set to the
- current state. (The state changes are cleared when read in the ioctl
- routine.) */
- mousestatus = buttons | (mousestatus & ~BUTSTATMASK)
- | (changed_buttons << 3);
-
- /* Reset HC to 0. */
- outb(CONTROL_REG, 0);
-
- /* If nothing has changed, nothing needs to be done, so return. */
- if (!(dx || dy || changed_buttons)) return;
-
- /* Update global variables with info just read. */
- xmotion += dx;
- ymotion += dy;
- #ifdef DEBUG
- printf("logmintr: dx = %d, dy = %d, buttons = %d\n", dx, dy, buttons);
- #endif /* DEBUG */
-
- #ifdef VPIX
- /* Send a pseudorupt if this is an ECT and the mouse has been read since
- the last pseudorupt. */
- if (ectproc && ectproc->p_v86 && !rupted) {
- v86setint(ectproc->p_v86, V86VI_MOUSE);
- rupted = 1;
- }
- #endif /* VPIX */
-
- } /* logmintr */
-