* Copyright 1992 by the University of Guelph
* Permission to use, copy and modify 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
* University of Guelph makes no representations about the suitability of
* this software for any purpose. It is provided "as is"
* without express or implied warranty.
* Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and
* the X386 port, courtesy of
* Rick Macklem, rick@snowhite.cis.uoguelph.ca
* Caveats: The driver currently uses spltty(), but doesn't use any
* generic tty code. It could use splmse() (that only masks off the
* bus mouse interrupt, but that would require hacking in i386/isa/icu.s.
* (This may be worth the effort, since the Logitech generates 30/60
* interrupts/sec continuously while it is open.)
* NB: The ATI has NOT been tested yet!
* Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu)
* fixes to make it work with Microsoft InPort busmouse
* Jan, 1993 -- E. Stark (stark@cs.sunysb.edu)
* added patches for new "select" interface
* May 4, 1993 -- E. Stark (stark@cs.sunysb.edu)
* changed position of some spl()'s in mseread
* October 8, 1993 -- E. Stark (stark@cs.sunysb.edu)
* limit maximum negative x/y value to -127 to work around XFree problem
* that causes spurious button pushes.
#include "i386/isa/isa_device.h"
#include "i386/isa/icu.h"
int mseprobe(), mseattach(), mseintr();
struct isa_driver msedriver
= {
mseprobe
, mseattach
, "mse"
* Software control structure for mouse. The sc_enablemouse(),
* sc_disablemouse() and sc_getmouse() routines must be called spl'd().
void (*sc_enablemouse
)();
void (*sc_disablemouse
)();
u_char sc_bytes
[PROTOBYTES
];
#define MSE_ATIINPORT 0x2
#define MSE_UNIT(dev) (minor(dev) >> 1)
#define MSE_NBLOCKIO(dev) (minor(dev) & 0x1)
* Logitech bus mouse definitions
#define MSE_SETUP 0x91 /* What does this mean? */
static int mse_probelogi();
static void mse_enablelogi(), mse_disablelogi(), mse_getlogi();
* ATI Inport mouse definitions
#define MSE_INPORT_RESET 0x80
#define MSE_INPORT_STATUS 0x00
#define MSE_INPORT_DX 0x01
#define MSE_INPORT_DY 0x02
#define MSE_INPORT_MODE 0x07
#define MSE_INPORT_HOLD 0x20
#define MSE_INPORT_INTREN 0x09
static int mse_probeati();
static void mse_enableati(), mse_disableati(), mse_getati();
#define MSEPRI (PZERO + 3)
* Keep the Logitech last, since I haven't figured out how to probe it
* properly yet. (Someday I'll have the documentation.)
int m_type
; /* Type of bus mouse */
int (*m_probe
)(); /* Probe routine to test for it */
void (*m_enable
)(); /* Start routine */
void (*m_disable
)(); /* Disable interrupts routine */
void (*m_get
)(); /* and get mouse status */
{ MSE_ATIINPORT
, mse_probeati
, mse_enableati
, mse_disableati
, mse_getati
},
{ MSE_LOGITECH
, mse_probelogi
, mse_enablelogi
, mse_disablelogi
, mse_getlogi
},
register struct isa_device
*idp
;
register struct mse_softc
*sc
= &mse_sc
[idp
->id_unit
];
* Check for each mouse type in the table.
while (mse_types
[i
].m_type
) {
if ((*mse_types
[i
].m_probe
)(idp
)) {
sc
->sc_mousetype
= mse_types
[i
].m_type
;
sc
->sc_enablemouse
= mse_types
[i
].m_enable
;
sc
->sc_disablemouse
= mse_types
[i
].m_disable
;
sc
->sc_getmouse
= mse_types
[i
].m_get
;
struct mse_softc
*sc
= &mse_sc
[idp
->id_unit
];
sc
->sc_port
= idp
->id_iobase
;
* Exclusive open the mouse, initialize it and enable interrupts.
register struct mse_softc
*sc
;
if (MSE_UNIT(dev
) >= NMSE
)
sc
= &mse_sc
[MSE_UNIT(dev
)];
if (sc
->sc_flags
& MSESC_OPEN
)
sc
->sc_flags
|= MSESC_OPEN
;
sc
->sc_obuttons
= sc
->sc_buttons
= 0x7;
sc
->sc_deltax
= sc
->sc_deltay
= 0;
sc
->sc_bytesread
= PROTOBYTES
;
* Initialize mouse interface and enable interrupts.
(*sc
->sc_enablemouse
)(sc
->sc_port
);
* mseclose: just turn off mouse innterrupts.
struct mse_softc
*sc
= &mse_sc
[MSE_UNIT(dev
)];
(*sc
->sc_disablemouse
)(sc
->sc_port
);
sc
->sc_flags
&= ~MSESC_OPEN
;
* mseread: return mouse info using the MSC serial protocol, but without
* (Yes this is cheesy, but it makes the X386 server happy, so...)
register struct mse_softc
*sc
= &mse_sc
[MSE_UNIT(dev
)];
* If there are no protocol bytes to be read, set up a new protocol
s
= spltty(); /* XXX Should be its own spl, but where is imlXX() */
if (sc
->sc_bytesread
>= PROTOBYTES
) {
while (sc
->sc_deltax
== 0 && sc
->sc_deltay
== 0 &&
(sc
->sc_obuttons
^ sc
->sc_buttons
) == 0) {
sc
->sc_flags
|= MSESC_WANT
;
if (error
= tsleep((caddr_t
)sc
, MSEPRI
| PCATCH
,
* Generate protocol bytes.
* For some reason X386 expects 5 bytes but never uses
sc
->sc_bytes
[0] = 0x80 | (sc
->sc_buttons
& ~0xf8);
if (sc
->sc_deltax
< -127)
sc
->sc_deltay
= -sc
->sc_deltay
; /* Otherwise mousey goes wrong way */
if (sc
->sc_deltay
< -127)
sc
->sc_bytes
[1] = sc
->sc_deltax
;
sc
->sc_bytes
[2] = sc
->sc_deltay
;
sc
->sc_bytes
[3] = sc
->sc_bytes
[4] = 0;
sc
->sc_obuttons
= sc
->sc_buttons
;
sc
->sc_deltax
= sc
->sc_deltay
= 0;
xfer
= MIN(uio
->uio_resid
, PROTOBYTES
- sc
->sc_bytesread
);
if (error
= uiomove(&sc
->sc_bytes
[sc
->sc_bytesread
], xfer
, uio
))
sc
->sc_bytesread
+= xfer
;
* mseselect: check for mouse input to be processed.
register struct mse_softc
*sc
= &mse_sc
[MSE_UNIT(dev
)];
if (sc
->sc_bytesread
!= PROTOBYTES
|| sc
->sc_deltax
!= 0 ||
sc
->sc_deltay
!= 0 || (sc
->sc_obuttons
^ sc
->sc_buttons
) != 0) {
* Since this is an exclusive open device, any previous proc.
* pointer is trash now, so we can just assign it.
* mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
register struct mse_softc
*sc
= &mse_sc
[unit
];
static int mse_intrcnt
= 0;
if((mse_intrcnt
++ % 10000) == 0)
if ((sc
->sc_flags
& MSESC_OPEN
) == 0)
(*sc
->sc_getmouse
)(sc
->sc_port
, &sc
->sc_deltax
, &sc
->sc_deltay
, &sc
->sc_buttons
);
* If mouse state has changed, wake up anyone wanting to know.
if (sc
->sc_deltax
!= 0 || sc
->sc_deltay
!= 0 ||
(sc
->sc_obuttons
^ sc
->sc_buttons
) != 0) {
if (sc
->sc_flags
& MSESC_WANT
) {
sc
->sc_flags
&= ~MSESC_WANT
;
* Routines for the Logitech mouse.
* Test for a Logitech bus mouse and return 1 if it is.
* (until I know how to use the signature port properly, just disable
* interrupts and return 1)
register struct isa_device
*idp
;
outb(idp
->id_iobase
+ MSE_PORTB
, 0x55);
if (inb(idp
->id_iobase
+ MSE_PORTB
) == 0x55) {
outb(idp
->id_iobase
+ MSE_PORTB
, 0xaa);
if (inb(idp
->id_iobase
+ MSE_PORTB
) == 0xaa)
* Initialize Logitech mouse and enable interrupts.
outb(port
+ MSE_PORTD
, MSE_SETUP
);
mse_getlogi(port
, &dx
, &dy
, &but
);
* Disable interrupts for Logitech mouse.
outb(port
+ MSE_PORTC
, MSE_DISINTR
);
* Get the current dx, dy and button up/down state.
mse_getlogi(port
, dx
, dy
, but
)
outb(port
+ MSE_PORTC
, MSE_HOLD
| MSE_RXLOW
);
x
= inb(port
+ MSE_PORTA
);
outb(port
+ MSE_PORTC
, MSE_HOLD
| MSE_RXHIGH
);
x
|= (inb(port
+ MSE_PORTA
) << 4);
outb(port
+ MSE_PORTC
, MSE_HOLD
| MSE_RYLOW
);
y
= (inb(port
+ MSE_PORTA
) & 0xf);
outb(port
+ MSE_PORTC
, MSE_HOLD
| MSE_RYHIGH
);
y
|= (inb(port
+ MSE_PORTA
) << 4);
outb(port
+ MSE_PORTC
, MSE_INTREN
);
* Routines for the ATI Inport bus mouse.
* Test for a ATI Inport bus mouse and return 1 if it is.
* (do not enable interrupts)
register struct isa_device
*idp
;
if (inb(idp
->id_iobase
+ MSE_PORTC
) == 0xde)
* Initialize ATI Inport mouse and enable interrupts.
outb(port
+ MSE_PORTA
, MSE_INPORT_RESET
);
outb(port
+ MSE_PORTA
, MSE_INPORT_MODE
);
outb(port
+ MSE_PORTB
, MSE_INPORT_INTREN
);
* Disable interrupts for ATI Inport mouse.
outb(port
+ MSE_PORTA
, MSE_INPORT_MODE
);
outb(port
+ MSE_PORTB
, 0);
* Get current dx, dy and up/down button state.
mse_getati(port
, dx
, dy
, but
)
outb(port
+ MSE_PORTA
, MSE_INPORT_MODE
);
outb(port
+ MSE_PORTB
, MSE_INPORT_HOLD
);
outb(port
+ MSE_PORTA
, MSE_INPORT_STATUS
);
*but
= ~(inb(port
+ MSE_PORTB
) & 0x7);
outb(port
+ MSE_PORTA
, MSE_INPORT_DX
);
byte
= inb(port
+ MSE_PORTB
);
outb(port
+ MSE_PORTA
, MSE_INPORT_DY
);
byte
= inb(port
+ MSE_PORTB
);
outb(port
+ MSE_PORTA
, MSE_INPORT_MODE
);
outb(port
+ MSE_PORTB
, MSE_INPORT_INTREN
);