mse.c revision 10624
1637Snate/*
2637Snate * Copyright 1992 by the University of Guelph
3637Snate *
4637Snate * Permission to use, copy and modify this
5637Snate * software and its documentation for any purpose and without
6637Snate * fee is hereby granted, provided that the above copyright
7637Snate * notice appear in all copies and that both that copyright
8637Snate * notice and this permission notice appear in supporting
9637Snate * documentation.
10637Snate * University of Guelph makes no representations about the suitability of
11637Snate * this software for any purpose.  It is provided "as is"
12637Snate * without express or implied warranty.
131817Sdg *
1410624Sbde * $Id: mse.c,v 1.13 1995/07/16 10:12:06 bde Exp $
15637Snate */
16637Snate/*
17637Snate * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and
18637Snate * the X386 port, courtesy of
19637Snate * Rick Macklem, rick@snowhite.cis.uoguelph.ca
20637Snate * Caveats: The driver currently uses spltty(), but doesn't use any
21637Snate * generic tty code. It could use splmse() (that only masks off the
22637Snate * bus mouse interrupt, but that would require hacking in i386/isa/icu.s.
23637Snate * (This may be worth the effort, since the Logitech generates 30/60
24637Snate * interrupts/sec continuously while it is open.)
25637Snate * NB: The ATI has NOT been tested yet!
26637Snate */
27637Snate
28637Snate/*
29637Snate * Modification history:
304259Sjkh * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com)
314259Sjkh *   improved probe based on input from Logitech.
32637Snate *
33637Snate * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu)
34637Snate *   fixes to make it work with Microsoft InPort busmouse
35637Snate *
36637Snate * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu)
37637Snate *   added patches for new "select" interface
38637Snate *
39637Snate * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu)
40637Snate *   changed position of some spl()'s in mseread
41637Snate *
42637Snate * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu)
43637Snate *   limit maximum negative x/y value to -127 to work around XFree problem
44637Snate *   that causes spurious button pushes.
45637Snate */
46637Snate
47637Snate#include "mse.h"
48637Snate#if NMSE > 0
492056Swollman#include <sys/param.h>
503745Swollman#include <sys/systm.h>
512056Swollman#include <sys/proc.h>
522056Swollman#include <sys/user.h>
532056Swollman#include <sys/buf.h>
542056Swollman#include <sys/kernel.h>
552056Swollman#include <sys/ioctl.h>
562056Swollman#include <sys/uio.h>
573816Swollman#include <sys/devconf.h>
58637Snate
597430Sbde#include <machine/clock.h>
607430Sbde
612056Swollman#include <i386/isa/isa_device.h>
622056Swollman#include <i386/isa/icu.h>
63637Snate
64798Swollmanstatic int mseprobe(struct isa_device *);
65798Swollmanstatic int mseattach(struct isa_device *);
66798Swollmanvoid mseintr(int);
67637Snate
68637Snatestruct	isa_driver msedriver = {
69637Snate	mseprobe, mseattach, "mse"
70637Snate};
71637Snate
72637Snate/*
73637Snate * Software control structure for mouse. The sc_enablemouse(),
74637Snate * sc_disablemouse() and sc_getmouse() routines must be called spl'd().
75637Snate */
76637Snate#define	PROTOBYTES	5
77637Snatestruct mse_softc {
78637Snate	int	sc_flags;
79637Snate	int	sc_mousetype;
801549Srgrimes	struct	selinfo sc_selp;
81637Snate	u_int	sc_port;
82637Snate	void	(*sc_enablemouse)();
83637Snate	void	(*sc_disablemouse)();
84637Snate	void	(*sc_getmouse)();
85637Snate	int	sc_deltax;
86637Snate	int	sc_deltay;
87637Snate	int	sc_obuttons;
88637Snate	int	sc_buttons;
89637Snate	int	sc_bytesread;
90637Snate	u_char	sc_bytes[PROTOBYTES];
91637Snate} mse_sc[NMSE];
92637Snate
93637Snate/* Flags */
94637Snate#define	MSESC_OPEN	0x1
95637Snate#define	MSESC_WANT	0x2
96637Snate
97637Snate/* and Mouse Types */
98637Snate#define	MSE_LOGITECH	0x1
99637Snate#define	MSE_ATIINPORT	0x2
1004259Sjkh#define	MSE_LOGI_SIG	0xA5
101637Snate
102637Snate#define	MSE_PORTA	0
103637Snate#define	MSE_PORTB	1
104637Snate#define	MSE_PORTC	2
105637Snate#define	MSE_PORTD	3
106637Snate
107637Snate#define	MSE_UNIT(dev)		(minor(dev) >> 1)
108637Snate#define	MSE_NBLOCKIO(dev)	(minor(dev) & 0x1)
109637Snate
110637Snate/*
111637Snate * Logitech bus mouse definitions
112637Snate */
113637Snate#define	MSE_SETUP	0x91	/* What does this mean? */
1144259Sjkh				/* The definition for the control port */
1154259Sjkh				/* is as follows: */
1168876Srgrimes
1174259Sjkh				/* D7 	 =  Mode set flag (1 = active) 	*/
1188876Srgrimes				/* D6,D5 =  Mode selection (port A) 	*/
1194259Sjkh				/* 	    00 = Mode 0 = Basic I/O 	*/
1204259Sjkh				/* 	    01 = Mode 1 = Strobed I/O 	*/
1214259Sjkh				/* 	    10 = Mode 2 = Bi-dir bus 	*/
1224259Sjkh				/* D4	 =  Port A direction (1 = input)*/
1234259Sjkh				/* D3	 =  Port C (upper 4 bits) 	*/
1244259Sjkh				/*	    direction. (1 = input)	*/
1254259Sjkh				/* D2	 =  Mode selection (port B & C) */
1264259Sjkh				/*	    0 = Mode 0 = Basic I/O	*/
1274259Sjkh				/*	    1 = Mode 1 = Strobed I/O	*/
1284259Sjkh				/* D1	 =  Port B direction (1 = input)*/
1294259Sjkh				/* D0	 =  Port C (lower 4 bits)	*/
1304259Sjkh				/*	    direction. (1 = input)	*/
1318876Srgrimes
1324259Sjkh				/* So 91 means Basic I/O on all 3 ports,*/
1334259Sjkh				/* Port A is an input port, B is an 	*/
1344259Sjkh				/* output port, C is split with upper	*/
1354259Sjkh				/* 4 bits being an output port and lower*/
1364259Sjkh				/* 4 bits an input port, and enable the */
1374259Sjkh				/* sucker.				*/
1384259Sjkh				/* Courtesy Intel 8255 databook. Lars   */
139637Snate#define	MSE_HOLD	0x80
140637Snate#define	MSE_RXLOW	0x00
141637Snate#define	MSE_RXHIGH	0x20
142637Snate#define	MSE_RYLOW	0x40
143637Snate#define	MSE_RYHIGH	0x60
144637Snate#define	MSE_DISINTR	0x10
145637Snate#define MSE_INTREN	0x00
146637Snate
147637Snatestatic int mse_probelogi();
148637Snatestatic void mse_enablelogi(), mse_disablelogi(), mse_getlogi();
149637Snate
150637Snate/*
151637Snate * ATI Inport mouse definitions
152637Snate */
153637Snate#define	MSE_INPORT_RESET	0x80
154637Snate#define	MSE_INPORT_STATUS	0x00
155637Snate#define	MSE_INPORT_DX		0x01
156637Snate#define	MSE_INPORT_DY		0x02
157637Snate#define	MSE_INPORT_MODE		0x07
158637Snate#define	MSE_INPORT_HOLD		0x20
159637Snate#define	MSE_INPORT_INTREN	0x09
160637Snate
161637Snatestatic int mse_probeati();
162637Snatestatic void mse_enableati(), mse_disableati(), mse_getati();
163637Snate
164637Snate#define	MSEPRI	(PZERO + 3)
165637Snate
166637Snate/*
167637Snate * Table of mouse types.
168637Snate * Keep the Logitech last, since I haven't figured out how to probe it
169637Snate * properly yet. (Someday I'll have the documentation.)
170637Snate */
171637Snatestruct mse_types {
172637Snate	int	m_type;		/* Type of bus mouse */
173637Snate	int	(*m_probe)();	/* Probe routine to test for it */
174637Snate	void	(*m_enable)();	/* Start routine */
175637Snate	void	(*m_disable)();	/* Disable interrupts routine */
176637Snate	void	(*m_get)();	/* and get mouse status */
177637Snate} mse_types[] = {
178637Snate	{ MSE_ATIINPORT, mse_probeati, mse_enableati, mse_disableati, mse_getati },
179637Snate	{ MSE_LOGITECH, mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi },
180637Snate	{ 0, },
181637Snate};
182637Snate
1837780Swollmanstatic struct kern_devconf kdc_mse[NMSE] = { {
1847780Swollman	0, 0, 0,		/* filled in by dev_attach */
1857780Swollman	"mse", 0, { MDDT_ISA, 0, "tty" },
1867780Swollman	isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
1877780Swollman	&kdc_isa0,		/* parent */
1887780Swollman	0,			/* parentdata */
1897780Swollman	DC_UNCONFIGURED,	/* state */
1907780Swollman	"ATI or Logitech bus mouse adapter",
1917780Swollman	DC_CLS_MISC		/* class */
1927780Swollman} };
1937780Swollman
1947780Swollmanstatic inline void
1957780Swollmanmse_registerdev(struct isa_device *id)
1967780Swollman{
1977780Swollman	if(id->id_unit)
1987780Swollman		kdc_mse[id->id_unit] = kdc_mse[0];
1997780Swollman	kdc_mse[id->id_unit].kdc_unit = id->id_unit;
2007780Swollman	kdc_mse[id->id_unit].kdc_isa = id;
2017780Swollman	dev_attach(&kdc_mse[id->id_unit]);
2027780Swollman}
2037780Swollman
204798Swollmanint
205637Snatemseprobe(idp)
206637Snate	register struct isa_device *idp;
207637Snate{
208637Snate	register struct mse_softc *sc = &mse_sc[idp->id_unit];
209637Snate	register int i;
210637Snate
2117780Swollman	mse_registerdev(idp);
212637Snate	/*
213637Snate	 * Check for each mouse type in the table.
214637Snate	 */
215637Snate	i = 0;
216637Snate	while (mse_types[i].m_type) {
217637Snate		if ((*mse_types[i].m_probe)(idp)) {
218637Snate			sc->sc_mousetype = mse_types[i].m_type;
219637Snate			sc->sc_enablemouse = mse_types[i].m_enable;
220637Snate			sc->sc_disablemouse = mse_types[i].m_disable;
221637Snate			sc->sc_getmouse = mse_types[i].m_get;
222637Snate			return (1);
223637Snate		}
224637Snate		i++;
225637Snate	}
226637Snate	return (0);
227637Snate}
228637Snate
229798Swollmanint
230637Snatemseattach(idp)
231637Snate	struct isa_device *idp;
232637Snate{
233637Snate	struct mse_softc *sc = &mse_sc[idp->id_unit];
234637Snate
235637Snate	sc->sc_port = idp->id_iobase;
2367780Swollman	kdc_mse[idp->id_unit].kdc_state = DC_IDLE;
237637Snate	return (1);
238637Snate}
239637Snate
240637Snate/*
241637Snate * Exclusive open the mouse, initialize it and enable interrupts.
242637Snate */
243798Swollmanint
24410624Sbdemseopen(dev, flags, fmt, p)
245637Snate	dev_t dev;
24610624Sbde	int flags;
24710624Sbde	int fmt;
24810624Sbde	struct proc *p;
249637Snate{
250637Snate	register struct mse_softc *sc;
251637Snate	int s;
252637Snate
253637Snate	if (MSE_UNIT(dev) >= NMSE)
254637Snate		return (ENXIO);
255637Snate	sc = &mse_sc[MSE_UNIT(dev)];
256637Snate	if (sc->sc_flags & MSESC_OPEN)
257637Snate		return (EBUSY);
258637Snate	sc->sc_flags |= MSESC_OPEN;
2597780Swollman	kdc_mse[MSE_UNIT(dev)].kdc_state = DC_BUSY;
260637Snate	sc->sc_obuttons = sc->sc_buttons = 0x7;
261637Snate	sc->sc_deltax = sc->sc_deltay = 0;
262637Snate	sc->sc_bytesread = PROTOBYTES;
263637Snate
264637Snate	/*
265637Snate	 * Initialize mouse interface and enable interrupts.
266637Snate	 */
267637Snate	s = spltty();
268637Snate	(*sc->sc_enablemouse)(sc->sc_port);
269637Snate	splx(s);
270637Snate	return (0);
271637Snate}
272637Snate
273637Snate/*
274637Snate * mseclose: just turn off mouse innterrupts.
275637Snate */
276798Swollmanint
27710624Sbdemseclose(dev, flags, fmt, p)
278798Swollman	dev_t dev;
27910624Sbde	int flags;
28010624Sbde	int fmt;
28110624Sbde	struct proc *p;
282637Snate{
283637Snate	struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
284637Snate	int s;
285637Snate
286637Snate	s = spltty();
287637Snate	(*sc->sc_disablemouse)(sc->sc_port);
288637Snate	sc->sc_flags &= ~MSESC_OPEN;
2897780Swollman	kdc_mse[MSE_UNIT(dev)].kdc_state = DC_IDLE;
290637Snate	splx(s);
291637Snate	return(0);
292637Snate}
293637Snate
2948876Srgrimes/*
295637Snate * mseread: return mouse info using the MSC serial protocol, but without
296637Snate * using bytes 4 and 5.
297637Snate * (Yes this is cheesy, but it makes the X386 server happy, so...)
298637Snate */
299798Swollmanint
30010624Sbdemseread(dev, uio, ioflag)
301637Snate	dev_t dev;
302637Snate	struct uio *uio;
30310624Sbde	int ioflag;
304637Snate{
305637Snate	register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
306637Snate	int xfer, s, error;
307637Snate
308637Snate	/*
309637Snate	 * If there are no protocol bytes to be read, set up a new protocol
310637Snate	 * packet.
311637Snate	 */
312637Snate	s = spltty(); /* XXX Should be its own spl, but where is imlXX() */
313637Snate	if (sc->sc_bytesread >= PROTOBYTES) {
314637Snate		while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
315637Snate		       (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
316637Snate			if (MSE_NBLOCKIO(dev)) {
317637Snate				splx(s);
318637Snate				return (0);
319637Snate			}
320637Snate			sc->sc_flags |= MSESC_WANT;
321637Snate			if (error = tsleep((caddr_t)sc, MSEPRI | PCATCH,
322637Snate				"mseread", 0)) {
323637Snate				splx(s);
324637Snate				return (error);
325637Snate			}
326637Snate		}
327637Snate
328637Snate		/*
329637Snate		 * Generate protocol bytes.
330637Snate		 * For some reason X386 expects 5 bytes but never uses
331637Snate		 * the fourth or fifth?
332637Snate		 */
333637Snate		sc->sc_bytes[0] = 0x80 | (sc->sc_buttons & ~0xf8);
334637Snate		if (sc->sc_deltax > 127)
335637Snate			sc->sc_deltax = 127;
336637Snate		if (sc->sc_deltax < -127)
337637Snate			sc->sc_deltax = -127;
338637Snate		sc->sc_deltay = -sc->sc_deltay;	/* Otherwise mousey goes wrong way */
339637Snate		if (sc->sc_deltay > 127)
340637Snate			sc->sc_deltay = 127;
341637Snate		if (sc->sc_deltay < -127)
342637Snate			sc->sc_deltay = -127;
343637Snate		sc->sc_bytes[1] = sc->sc_deltax;
344637Snate		sc->sc_bytes[2] = sc->sc_deltay;
345637Snate		sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
346637Snate		sc->sc_obuttons = sc->sc_buttons;
347637Snate		sc->sc_deltax = sc->sc_deltay = 0;
348637Snate		sc->sc_bytesread = 0;
349637Snate	}
350637Snate	splx(s);
3511567Srgrimes	xfer = min(uio->uio_resid, PROTOBYTES - sc->sc_bytesread);
352637Snate	if (error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio))
353637Snate		return (error);
354637Snate	sc->sc_bytesread += xfer;
355637Snate	return(0);
356637Snate}
357637Snate
358637Snate/*
359637Snate * mseselect: check for mouse input to be processed.
360637Snate */
361798Swollmanint
362637Snatemseselect(dev, rw, p)
363637Snate	dev_t dev;
364637Snate	int rw;
365637Snate	struct proc *p;
366637Snate{
367637Snate	register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
368637Snate	int s;
369637Snate
370637Snate	s = spltty();
371637Snate	if (sc->sc_bytesread != PROTOBYTES || sc->sc_deltax != 0 ||
372637Snate	    sc->sc_deltay != 0 || (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
373637Snate		splx(s);
374637Snate		return (1);
375637Snate	}
376637Snate
377637Snate	/*
378637Snate	 * Since this is an exclusive open device, any previous proc.
379637Snate	 * pointer is trash now, so we can just assign it.
380637Snate	 */
3811549Srgrimes	selrecord(p, &sc->sc_selp);
382637Snate	splx(s);
383637Snate	return (0);
384637Snate}
385637Snate
386637Snate/*
387637Snate * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
388637Snate */
389798Swollmanvoid
390637Snatemseintr(unit)
391637Snate	int unit;
392637Snate{
393637Snate	register struct mse_softc *sc = &mse_sc[unit];
394637Snate	pid_t p;
395637Snate
396637Snate#ifdef DEBUG
397637Snate	static int mse_intrcnt = 0;
398637Snate	if((mse_intrcnt++ % 10000) == 0)
399637Snate		printf("mseintr\n");
400637Snate#endif /* DEBUG */
401637Snate	if ((sc->sc_flags & MSESC_OPEN) == 0)
402637Snate		return;
403637Snate
404637Snate	(*sc->sc_getmouse)(sc->sc_port, &sc->sc_deltax, &sc->sc_deltay, &sc->sc_buttons);
405637Snate
406637Snate	/*
407637Snate	 * If mouse state has changed, wake up anyone wanting to know.
408637Snate	 */
409637Snate	if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
410637Snate	    (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
4118876Srgrimes		if (sc->sc_flags & MSESC_WANT) {
4128876Srgrimes			sc->sc_flags &= ~MSESC_WANT;
4138876Srgrimes			wakeup((caddr_t)sc);
4148876Srgrimes		}
4151549Srgrimes		selwakeup(&sc->sc_selp);
416637Snate	}
417637Snate}
418637Snate
419637Snate/*
420637Snate * Routines for the Logitech mouse.
421637Snate */
422637Snate/*
423637Snate * Test for a Logitech bus mouse and return 1 if it is.
424637Snate * (until I know how to use the signature port properly, just disable
425637Snate *  interrupts and return 1)
426637Snate */
427637Snatestatic int
428637Snatemse_probelogi(idp)
429637Snate	register struct isa_device *idp;
430637Snate{
431637Snate
4324259Sjkh	int sig;
4334259Sjkh
4344259Sjkh	outb(idp->id_iobase + MSE_PORTD, MSE_SETUP);
4354259Sjkh		/* set the signature port */
4364259Sjkh	outb(idp->id_iobase + MSE_PORTB, MSE_LOGI_SIG);
4374259Sjkh
4384259Sjkh	DELAY(30000); /* 30 ms delay */
4394259Sjkh	sig = inb(idp->id_iobase + MSE_PORTB) & 0xFF;
4404259Sjkh	if (sig == MSE_LOGI_SIG) {
4414259Sjkh		outb(idp->id_iobase + MSE_PORTC, MSE_DISINTR);
4424259Sjkh		return(1);
4434259Sjkh	} else {
4448876Srgrimes		printf("mse%d: wrong signature %x\n",idp->id_unit,sig);
4454259Sjkh		return(0);
446637Snate	}
447637Snate}
448637Snate
449637Snate/*
450637Snate * Initialize Logitech mouse and enable interrupts.
451637Snate */
452637Snatestatic void
453637Snatemse_enablelogi(port)
454637Snate	register u_int port;
455637Snate{
456637Snate	int dx, dy, but;
457637Snate
458637Snate	outb(port + MSE_PORTD, MSE_SETUP);
459637Snate	mse_getlogi(port, &dx, &dy, &but);
460637Snate}
461637Snate
462637Snate/*
463637Snate * Disable interrupts for Logitech mouse.
464637Snate */
465637Snatestatic void
466637Snatemse_disablelogi(port)
467637Snate	register u_int port;
468637Snate{
469637Snate
470637Snate	outb(port + MSE_PORTC, MSE_DISINTR);
471637Snate}
472637Snate
473637Snate/*
474637Snate * Get the current dx, dy and button up/down state.
475637Snate */
476637Snatestatic void
477637Snatemse_getlogi(port, dx, dy, but)
478637Snate	register u_int port;
479637Snate	int *dx;
480637Snate	int *dy;
481637Snate	int *but;
482637Snate{
483637Snate	register char x, y;
484637Snate
485637Snate	outb(port + MSE_PORTC, MSE_HOLD | MSE_RXLOW);
486637Snate	x = inb(port + MSE_PORTA);
487637Snate	*but = (x >> 5) & 0x7;
488637Snate	x &= 0xf;
489637Snate	outb(port + MSE_PORTC, MSE_HOLD | MSE_RXHIGH);
490637Snate	x |= (inb(port + MSE_PORTA) << 4);
491637Snate	outb(port + MSE_PORTC, MSE_HOLD | MSE_RYLOW);
492637Snate	y = (inb(port + MSE_PORTA) & 0xf);
493637Snate	outb(port + MSE_PORTC, MSE_HOLD | MSE_RYHIGH);
494637Snate	y |= (inb(port + MSE_PORTA) << 4);
495637Snate	*dx += x;
496637Snate	*dy += y;
497637Snate	outb(port + MSE_PORTC, MSE_INTREN);
498637Snate}
499637Snate
500637Snate/*
501637Snate * Routines for the ATI Inport bus mouse.
502637Snate */
503637Snate/*
504637Snate * Test for a ATI Inport bus mouse and return 1 if it is.
505637Snate * (do not enable interrupts)
506637Snate */
507637Snatestatic int
508637Snatemse_probeati(idp)
509637Snate	register struct isa_device *idp;
510637Snate{
511637Snate	int i;
512637Snate
513637Snate	for (i = 0; i < 2; i++)
514637Snate		if (inb(idp->id_iobase + MSE_PORTC) == 0xde)
515637Snate			return (1);
516637Snate	return (0);
517637Snate}
518637Snate
519637Snate/*
520637Snate * Initialize ATI Inport mouse and enable interrupts.
521637Snate */
522637Snatestatic void
523637Snatemse_enableati(port)
524637Snate	register u_int port;
525637Snate{
526637Snate
527637Snate	outb(port + MSE_PORTA, MSE_INPORT_RESET);
528637Snate	outb(port + MSE_PORTA, MSE_INPORT_MODE);
529637Snate	outb(port + MSE_PORTB, MSE_INPORT_INTREN);
530637Snate}
531637Snate
532637Snate/*
533637Snate * Disable interrupts for ATI Inport mouse.
534637Snate */
535637Snatestatic void
536637Snatemse_disableati(port)
537637Snate	register u_int port;
538637Snate{
539637Snate
540637Snate	outb(port + MSE_PORTA, MSE_INPORT_MODE);
541637Snate	outb(port + MSE_PORTB, 0);
542637Snate}
543637Snate
544637Snate/*
545637Snate * Get current dx, dy and up/down button state.
546637Snate */
547637Snatestatic void
548637Snatemse_getati(port, dx, dy, but)
549637Snate	register u_int port;
550637Snate	int *dx;
551637Snate	int *dy;
552637Snate	int *but;
553637Snate{
554637Snate	register char byte;
555637Snate
556637Snate	outb(port + MSE_PORTA, MSE_INPORT_MODE);
557637Snate	outb(port + MSE_PORTB, MSE_INPORT_HOLD);
558637Snate	outb(port + MSE_PORTA, MSE_INPORT_STATUS);
559637Snate	*but = ~(inb(port + MSE_PORTB) & 0x7);
560637Snate	outb(port + MSE_PORTA, MSE_INPORT_DX);
561637Snate	byte = inb(port + MSE_PORTB);
562637Snate	*dx += byte;
563637Snate	outb(port + MSE_PORTA, MSE_INPORT_DY);
564637Snate	byte = inb(port + MSE_PORTB);
565637Snate	*dy += byte;
566637Snate	outb(port + MSE_PORTA, MSE_INPORT_MODE);
567637Snate	outb(port + MSE_PORTB, MSE_INPORT_INTREN);
568637Snate}
569637Snate#endif /* NMSE */
570