home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
usenet
/
altsrcs
/
2
/
2648
/
lmouse.c
next >
Wrap
C/C++ Source or Header
|
1991-01-31
|
13KB
|
438 lines
/* 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 */