mse.c revision 31254
177218Sphk/*
277218Sphk * Copyright 1992 by the University of Guelph
377218Sphk *
477218Sphk * Permission to use, copy and modify this
577218Sphk * software and its documentation for any purpose and without
677218Sphk * fee is hereby granted, provided that the above copyright
777218Sphk * notice appear in all copies and that both that copyright
877218Sphk * notice and this permission notice appear in supporting
977218Sphk * documentation.
1077218Sphk * University of Guelph makes no representations about the suitability of
1177218Sphk * this software for any purpose.  It is provided "as is"
1291454Sbrooks * without express or implied warranty.
1391454Sbrooks *
1477218Sphk * $Id: mse.c,v 1.34 1997/09/14 03:19:10 peter Exp $
1577218Sphk */
1677218Sphk/*
1777218Sphk * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and
1877218Sphk * the X386 port, courtesy of
1977218Sphk * Rick Macklem, rick@snowhite.cis.uoguelph.ca
2077218Sphk * Caveats: The driver currently uses spltty(), but doesn't use any
2177218Sphk * generic tty code. It could use splmse() (that only masks off the
2277218Sphk * bus mouse interrupt, but that would require hacking in i386/isa/icu.s.
2377218Sphk * (This may be worth the effort, since the Logitech generates 30/60
2477218Sphk * interrupts/sec continuously while it is open.)
2577218Sphk * NB: The ATI has NOT been tested yet!
2677218Sphk */
2777218Sphk
2877218Sphk/*
2977218Sphk * Modification history:
3077218Sphk * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com)
3177218Sphk *   improved probe based on input from Logitech.
3277218Sphk *
3377218Sphk * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu)
3477218Sphk *   fixes to make it work with Microsoft InPort busmouse
3577218Sphk *
3677218Sphk * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu)
3777218Sphk *   added patches for new "select" interface
3877218Sphk *
3977218Sphk * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu)
4077218Sphk *   changed position of some spl()'s in mseread
4177218Sphk *
4277218Sphk * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu)
4377218Sphk *   limit maximum negative x/y value to -127 to work around XFree problem
4477218Sphk *   that causes spurious button pushes.
4577218Sphk */
4677218Sphk
4777218Sphk#include "mse.h"
4877218Sphk#if NMSE > 0
4977218Sphk#include <sys/param.h>
5077218Sphk#include <sys/systm.h>
5177218Sphk#include <sys/conf.h>
5277218Sphk#include <sys/kernel.h>
5377218Sphk#include <sys/poll.h>
5477218Sphk#include <sys/select.h>
5577218Sphk#include <sys/uio.h>
5677218Sphk#ifdef DEVFS
5777218Sphk#include <sys/devfsext.h>
5877218Sphk#endif /*DEVFS*/
5977218Sphk
6077218Sphk#include <machine/clock.h>
6177218Sphk
6277218Sphk#include <i386/isa/isa_device.h>
6377218Sphk
6477218Sphkstatic int mseprobe(struct isa_device *);
6577218Sphkstatic int mseattach(struct isa_device *);
6677218Sphk
6777218Sphkstruct	isa_driver msedriver = {
6877218Sphk	mseprobe, mseattach, "mse"
6977218Sphk};
7077218Sphk
7177218Sphkstatic	d_open_t	mseopen;
7277218Sphkstatic	d_close_t	mseclose;
7377218Sphkstatic	d_read_t	mseread;
7477218Sphkstatic	d_poll_t	msepoll;
7577218Sphk
7677218Sphk#define CDEV_MAJOR 27
77138593Ssamstatic struct cdevsw mse_cdevsw =
7877218Sphk	{ mseopen,	mseclose,	mseread,	nowrite,	/*27*/
79138593Ssam	  noioc,	nostop,		nullreset,	nodevtotty,/* mse */
80116957Ssam	  msepoll,	nommap,		NULL,	"mse",	NULL,	-1 };
81120178Ssam
82116957Ssam
8377218Sphk/*
8477218Sphk * Software control structure for mouse. The sc_enablemouse(),
8577218Sphk * sc_disablemouse() and sc_getmouse() routines must be called spl'd().
8677218Sphk */
8777218Sphk#define	PROTOBYTES	5
88146873Sjhbstatic struct mse_softc {
8977218Sphk	int	sc_flags;
9077218Sphk	int	sc_mousetype;
9177218Sphk	struct	selinfo sc_selp;
9277218Sphk	u_int	sc_port;
93155931Ssam	void	(*sc_enablemouse) __P((u_int port));
9477218Sphk	void	(*sc_disablemouse) __P((u_int port));
9577218Sphk	void	(*sc_getmouse) __P((u_int port, int *dx, int *dy, int *but));
9677218Sphk	int	sc_deltax;
9777218Sphk	int	sc_deltay;
9877218Sphk	int	sc_obuttons;
9977218Sphk	int	sc_buttons;
10077218Sphk	int	sc_bytesread;
10177218Sphk	u_char	sc_bytes[PROTOBYTES];
102138593Ssam#ifdef DEVFS
103138593Ssam	void 	*devfs_token;
104138593Ssam	void	*n_devfs_token;
105138593Ssam#endif
106138593Ssam} mse_sc[NMSE];
107138593Ssam
108138593Ssam/* Flags */
109138593Ssam#define	MSESC_OPEN	0x1
11077218Sphk#define	MSESC_WANT	0x2
11177218Sphk
11277218Sphk/* and Mouse Types */
11377218Sphk#define	MSE_NONE	0	/* don't move this! */
114151883Sbrooks#define	MSE_LOGITECH	0x1
11577218Sphk#define	MSE_ATIINPORT	0x2
11677218Sphk#define	MSE_LOGI_SIG	0xA5
117121827Sbrooks
11888748Sambrisko#define	MSE_PORTA	0
11988748Sambrisko#define	MSE_PORTB	1
12088748Sambrisko#define	MSE_PORTC	2
12188748Sambrisko#define	MSE_PORTD	3
12277218Sphk
12377218Sphk#define	MSE_UNIT(dev)		(minor(dev) >> 1)
12477218Sphk#define	MSE_NBLOCKIO(dev)	(minor(dev) & 0x1)
125151883Sbrooks
126151883Sbrooks/*
12777218Sphk * Logitech bus mouse definitions
12877218Sphk */
12977218Sphk#define	MSE_SETUP	0x91	/* What does this mean? */
13077218Sphk				/* The definition for the control port */
131138593Ssam				/* is as follows: */
13277218Sphk
13377218Sphk				/* D7 	 =  Mode set flag (1 = active) 	*/
13477218Sphk				/* D6,D5 =  Mode selection (port A) 	*/
13577218Sphk				/* 	    00 = Mode 0 = Basic I/O 	*/
13677218Sphk				/* 	    01 = Mode 1 = Strobed I/O 	*/
13777218Sphk				/* 	    10 = Mode 2 = Bi-dir bus 	*/
13877218Sphk				/* D4	 =  Port A direction (1 = input)*/
13977218Sphk				/* D3	 =  Port C (upper 4 bits) 	*/
14077218Sphk				/*	    direction. (1 = input)	*/
14177218Sphk				/* D2	 =  Mode selection (port B & C) */
14277218Sphk				/*	    0 = Mode 0 = Basic I/O	*/
14377218Sphk				/*	    1 = Mode 1 = Strobed I/O	*/
144138593Ssam				/* D1	 =  Port B direction (1 = input)*/
145138593Ssam				/* D0	 =  Port C (lower 4 bits)	*/
146138593Ssam				/*	    direction. (1 = input)	*/
147138593Ssam
148138593Ssam				/* So 91 means Basic I/O on all 3 ports,*/
149138593Ssam				/* Port A is an input port, B is an 	*/
150138593Ssam				/* output port, C is split with upper	*/
151138593Ssam				/* 4 bits being an output port and lower*/
152138593Ssam				/* 4 bits an input port, and enable the */
153138593Ssam				/* sucker.				*/
154138593Ssam				/* Courtesy Intel 8255 databook. Lars   */
155138593Ssam#define	MSE_HOLD	0x80
156138593Ssam#define	MSE_RXLOW	0x00
157138593Ssam#define	MSE_RXHIGH	0x20
158138593Ssam#define	MSE_RYLOW	0x40
159138593Ssam#define	MSE_RYHIGH	0x60
160138593Ssam#define	MSE_DISINTR	0x10
161138593Ssam#define MSE_INTREN	0x00
162138593Ssam
163165570Ssamstatic int mse_probelogi __P((struct isa_device *idp));
164138593Ssamstatic void mse_disablelogi __P((u_int port));
165138593Ssamstatic void mse_getlogi __P((u_int port, int *dx, int *dy, int *but));
166138593Ssamstatic void mse_enablelogi __P((u_int port));
167138593Ssam
168138593Ssam/*
169165570Ssam * ATI Inport mouse definitions
170165570Ssam */
171165570Ssam#define	MSE_INPORT_RESET	0x80
172165570Ssam#define	MSE_INPORT_STATUS	0x00
173165570Ssam#define	MSE_INPORT_DX		0x01
174165570Ssam#define	MSE_INPORT_DY		0x02
175165570Ssam#define	MSE_INPORT_MODE		0x07
176138593Ssam#define	MSE_INPORT_HOLD		0x20
177138593Ssam#define	MSE_INPORT_INTREN	0x09
178138593Ssam
179138593Ssamstatic int mse_probeati __P((struct isa_device *idp));
18077218Sphkstatic void mse_enableati __P((u_int port));
18177218Sphkstatic void mse_disableati __P((u_int port));
182138593Ssamstatic void mse_getati __P((u_int port, int *dx, int *dy, int *but));
183138593Ssam
184138593Ssam#define	MSEPRI	(PZERO + 3)
185165570Ssam
186138593Ssam/*
187138593Ssam * Table of mouse types.
188116957Ssam * Keep the Logitech last, since I haven't figured out how to probe it
18977218Sphk * properly yet. (Someday I'll have the documentation.)
19077218Sphk */
191138593Ssamstatic struct mse_types {
19277218Sphk	int	m_type;		/* Type of bus mouse */
19377218Sphk	int	(*m_probe) __P((struct isa_device *idp));
19477218Sphk				/* Probe routine to test for it */
19577218Sphk	void	(*m_enable) __P((u_int port));
19691454Sbrooks				/* Start routine */
19777218Sphk	void	(*m_disable) __P((u_int port));
19891454Sbrooks				/* Disable interrupts routine */
19977218Sphk	void	(*m_get) __P((u_int port, int *dx, int *dy, int *but));
20091454Sbrooks				/* and get mouse status */
20177218Sphk} mse_types[] = {
202138593Ssam	{ MSE_ATIINPORT, mse_probeati, mse_enableati, mse_disableati, mse_getati },
203138593Ssam	{ MSE_LOGITECH, mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi },
204138593Ssam	{ 0, },
205138593Ssam};
20677218Sphk
207150708Sruint
20877218Sphkmseprobe(idp)
20977218Sphk	register struct isa_device *idp;
21077218Sphk{
21177218Sphk	register struct mse_softc *sc = &mse_sc[idp->id_unit];
21277218Sphk	register int i;
213138593Ssam
21477218Sphk	/*
21577218Sphk	 * Check for each mouse type in the table.
21677218Sphk	 */
21777218Sphk	i = 0;
21891454Sbrooks	while (mse_types[i].m_type) {
21977218Sphk		if ((*mse_types[i].m_probe)(idp)) {
22091454Sbrooks			sc->sc_mousetype = mse_types[i].m_type;
22177218Sphk			sc->sc_enablemouse = mse_types[i].m_enable;
22291454Sbrooks			sc->sc_disablemouse = mse_types[i].m_disable;
22377218Sphk			sc->sc_getmouse = mse_types[i].m_get;
22491454Sbrooks			return (1);
22577218Sphk		}
22691454Sbrooks		i++;
22777218Sphk	}
22877218Sphk	return (0);
229150708Sru}
23077218Sphk
23177218Sphkint
23277218Sphkmseattach(idp)
23377218Sphk	struct isa_device *idp;
23477218Sphk{
235138593Ssam	int unit = idp->id_unit;
23677218Sphk	struct mse_softc *sc = &mse_sc[unit];
23777218Sphk
23877218Sphk	sc->sc_port = idp->id_iobase;
23977218Sphk#ifdef	DEVFS
24077218Sphk	sc->devfs_token =
24177218Sphk		devfs_add_devswf(&mse_cdevsw, unit << 1, DV_CHR, 0, 0,
24277218Sphk				 0600, "mse%d", unit);
24377218Sphk	sc->n_devfs_token =
24477218Sphk		devfs_add_devswf(&mse_cdevsw, (unit<<1)+1, DV_CHR,0, 0,
24577218Sphk				 0600, "nmse%d", unit);
246138593Ssam#endif
24777218Sphk	return (1);
24877218Sphk}
24977218Sphk
25077218Sphk/*
25177218Sphk * Exclusive open the mouse, initialize it and enable interrupts.
252138593Ssam */
25377218Sphkstatic	int
25477218Sphkmseopen(dev, flags, fmt, p)
25577218Sphk	dev_t dev;
25677218Sphk	int flags;
25791454Sbrooks	int fmt;
25877218Sphk	struct proc *p;
25991454Sbrooks{
26077218Sphk	register struct mse_softc *sc;
26191454Sbrooks	int s;
26277218Sphk
26377218Sphk	if (MSE_UNIT(dev) >= NMSE)
264150708Sru		return (ENXIO);
26577218Sphk	sc = &mse_sc[MSE_UNIT(dev)];
26677218Sphk	if (sc->sc_mousetype == MSE_NONE)
26777218Sphk		return (ENXIO);
26877218Sphk	if (sc->sc_flags & MSESC_OPEN)
26977218Sphk		return (EBUSY);
270138593Ssam	sc->sc_flags |= MSESC_OPEN;
27177218Sphk	sc->sc_obuttons = sc->sc_buttons = 0x7;
27277218Sphk	sc->sc_deltax = sc->sc_deltay = 0;
27377218Sphk	sc->sc_bytesread = PROTOBYTES;
27477218Sphk
27577218Sphk	/*
276139493Ssam	 * Initialize mouse interface and enable interrupts.
277139493Ssam	 */
278139493Ssam	s = spltty();
279139493Ssam	(*sc->sc_enablemouse)(sc->sc_port);
280139493Ssam	splx(s);
281139493Ssam	return (0);
282138593Ssam}
28377218Sphk
28477218Sphk/*
285139493Ssam * mseclose: just turn off mouse innterrupts.
286139493Ssam */
287139493Ssamstatic	int
288139493Ssammseclose(dev, flags, fmt, p)
28977218Sphk	dev_t dev;
29077218Sphk	int flags;
291138593Ssam	int fmt;
29277218Sphk	struct proc *p;
29377218Sphk{
29477218Sphk	struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
29577218Sphk	int s;
296120178Ssam
29777218Sphk	s = spltty();
29891454Sbrooks	(*sc->sc_disablemouse)(sc->sc_port);
29977218Sphk	sc->sc_flags &= ~MSESC_OPEN;
30077218Sphk	splx(s);
30177218Sphk	return(0);
30277218Sphk}
30377218Sphk
30477218Sphk/*
30577218Sphk * mseread: return mouse info using the MSC serial protocol, but without
30677218Sphk * using bytes 4 and 5.
30777218Sphk * (Yes this is cheesy, but it makes the X386 server happy, so...)
30877218Sphk */
30977218Sphkstatic	int
31077218Sphkmseread(dev, uio, ioflag)
311148686Sstefanf	dev_t dev;
312148686Sstefanf	struct uio *uio;
31377218Sphk	int ioflag;
31477218Sphk{
315138593Ssam	register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
31677218Sphk	int xfer, s, error;
31777218Sphk
31877218Sphk	/*
31977218Sphk	 * If there are no protocol bytes to be read, set up a new protocol
320120178Ssam	 * packet.
32177218Sphk	 */
32277218Sphk	s = spltty(); /* XXX Should be its own spl, but where is imlXX() */
32377218Sphk	if (sc->sc_bytesread >= PROTOBYTES) {
32491454Sbrooks		while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
32577218Sphk		       (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
32677218Sphk			if (MSE_NBLOCKIO(dev)) {
32777218Sphk				splx(s);
32891454Sbrooks				return (0);
32977218Sphk			}
33077218Sphk			sc->sc_flags |= MSESC_WANT;
33177218Sphk			if (error = tsleep((caddr_t)sc, MSEPRI | PCATCH,
332151827Sbrooks				"mseread", 0)) {
333151827Sbrooks				splx(s);
33477218Sphk				return (error);
33577218Sphk			}
33677218Sphk		}
33777218Sphk
33877218Sphk		/*
33977218Sphk		 * Generate protocol bytes.
34077218Sphk		 * For some reason X386 expects 5 bytes but never uses
34177218Sphk		 * the fourth or fifth?
34277218Sphk		 */
34377218Sphk		sc->sc_bytes[0] = 0x80 | (sc->sc_buttons & ~0xf8);
34477218Sphk		if (sc->sc_deltax > 127)
34577218Sphk			sc->sc_deltax = 127;
34691454Sbrooks		if (sc->sc_deltax < -127)
34777218Sphk			sc->sc_deltax = -127;
34877218Sphk		sc->sc_deltay = -sc->sc_deltay;	/* Otherwise mousey goes wrong way */
34977218Sphk		if (sc->sc_deltay > 127)
35077218Sphk			sc->sc_deltay = 127;
35177218Sphk		if (sc->sc_deltay < -127)
35277218Sphk			sc->sc_deltay = -127;
353138593Ssam		sc->sc_bytes[1] = sc->sc_deltax;
354127649Ssam		sc->sc_bytes[2] = sc->sc_deltay;
355127649Ssam		sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
356148416Ssam		sc->sc_obuttons = sc->sc_buttons;
357148416Ssam		sc->sc_deltax = sc->sc_deltay = 0;
358127649Ssam		sc->sc_bytesread = 0;
359127649Ssam	}
360138593Ssam	splx(s);
361127649Ssam	xfer = min(uio->uio_resid, PROTOBYTES - sc->sc_bytesread);
362127649Ssam	if (error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio))
363127649Ssam		return (error);
364127649Ssam	sc->sc_bytesread += xfer;
365127649Ssam	return(0);
366127649Ssam}
367127649Ssam
368127649Ssam/*
369127649Ssam * msepoll: check for mouse input to be processed.
370127649Ssam */
371127649Ssamstatic	int
372150708Srumsepoll(dev, events, p)
373127649Ssam	dev_t dev;
374127649Ssam	int events;
375127649Ssam	struct proc *p;
376127649Ssam{
377127649Ssam	register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
378138593Ssam	int s;
379127649Ssam	int revents = 0;
380127649Ssam
381127649Ssam	s = spltty();
382127649Ssam	if (events & (POLLIN | POLLRDNORM))
383127649Ssam		if (sc->sc_bytesread != PROTOBYTES || sc->sc_deltax != 0 ||
384138593Ssam		    sc->sc_deltay != 0 ||
385138593Ssam		    (sc->sc_obuttons ^ sc->sc_buttons) != 0)
386138593Ssam			revents |= events & (POLLIN | POLLRDNORM);
387138593Ssam		else {
388138593Ssam			/*
389138593Ssam			 * Since this is an exclusive open device, any previous
39077218Sphk			 * proc pointer is trash now, so we can just assign it.
391138593Ssam			 */
39277218Sphk			selrecord(p, &sc->sc_selp);
393138593Ssam		}
394138593Ssam
395138593Ssam	splx(s);
396138593Ssam	return (revents);
397138593Ssam}
398138593Ssam
399138593Ssam/*
400150708Sru * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
401138593Ssam */
402138593Ssamvoid
403138593Ssammseintr(unit)
404138593Ssam	int unit;
405138593Ssam{
406138593Ssam	register struct mse_softc *sc = &mse_sc[unit];
407138593Ssam
408138593Ssam#ifdef DEBUG
409138593Ssam	static int mse_intrcnt = 0;
410138593Ssam	if((mse_intrcnt++ % 10000) == 0)
411138593Ssam		printf("mseintr\n");
412138593Ssam#endif /* DEBUG */
413138593Ssam	if ((sc->sc_flags & MSESC_OPEN) == 0)
414138593Ssam		return;
415138593Ssam
416138593Ssam	(*sc->sc_getmouse)(sc->sc_port, &sc->sc_deltax, &sc->sc_deltay, &sc->sc_buttons);
417138593Ssam
418138593Ssam	/*
419138593Ssam	 * If mouse state has changed, wake up anyone wanting to know.
420138593Ssam	 */
421138593Ssam	if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
422138593Ssam	    (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
423138593Ssam		if (sc->sc_flags & MSESC_WANT) {
424138593Ssam			sc->sc_flags &= ~MSESC_WANT;
425138593Ssam			wakeup((caddr_t)sc);
426138593Ssam		}
427138593Ssam		selwakeup(&sc->sc_selp);
428138593Ssam	}
429138593Ssam}
430138593Ssam
431138593Ssam/*
432138593Ssam * Routines for the Logitech mouse.
433138593Ssam */
434138593Ssam/*
435138593Ssam * Test for a Logitech bus mouse and return 1 if it is.
436138593Ssam * (until I know how to use the signature port properly, just disable
437138593Ssam *  interrupts and return 1)
438138593Ssam */
439138593Ssamstatic int
440138593Ssammse_probelogi(idp)
441138593Ssam	register struct isa_device *idp;
442138593Ssam{
443138593Ssam
444138593Ssam	int sig;
445146873Sjhb
446138593Ssam	outb(idp->id_iobase + MSE_PORTD, MSE_SETUP);
447138593Ssam		/* set the signature port */
448138593Ssam	outb(idp->id_iobase + MSE_PORTB, MSE_LOGI_SIG);
449138593Ssam
450138593Ssam	DELAY(30000); /* 30 ms delay */
451146873Sjhb	sig = inb(idp->id_iobase + MSE_PORTB) & 0xFF;
452138593Ssam	if (sig == MSE_LOGI_SIG) {
453138593Ssam		outb(idp->id_iobase + MSE_PORTC, MSE_DISINTR);
454146873Sjhb		return(1);
455138593Ssam	} else {
456138593Ssam		if (bootverbose)
457138593Ssam			printf("mse%d: wrong signature %x\n",idp->id_unit,sig);
458138593Ssam		return(0);
459138593Ssam	}
460138593Ssam}
461138593Ssam
462138593Ssam/*
463138593Ssam * Initialize Logitech mouse and enable interrupts.
464138593Ssam */
465138593Ssamstatic void
466138593Ssammse_enablelogi(port)
467138593Ssam	register u_int port;
468138593Ssam{
469138593Ssam	int dx, dy, but;
470138593Ssam
471138593Ssam	outb(port + MSE_PORTD, MSE_SETUP);
472138593Ssam	mse_getlogi(port, &dx, &dy, &but);
473138593Ssam}
474138593Ssam
475138593Ssam/*
476138593Ssam * Disable interrupts for Logitech mouse.
477138593Ssam */
478138593Ssamstatic void
479138593Ssammse_disablelogi(port)
480138593Ssam	register u_int port;
481138593Ssam{
482138593Ssam
483138593Ssam	outb(port + MSE_PORTC, MSE_DISINTR);
484155702Ssam}
485138593Ssam
486138593Ssam/*
487138593Ssam * Get the current dx, dy and button up/down state.
488138593Ssam */
489138593Ssamstatic void
490138593Ssammse_getlogi(port, dx, dy, but)
491138593Ssam	register u_int port;
492138593Ssam	int *dx;
493138593Ssam	int *dy;
494138593Ssam	int *but;
495138593Ssam{
496138593Ssam	register char x, y;
497138593Ssam
498138593Ssam	outb(port + MSE_PORTC, MSE_HOLD | MSE_RXLOW);
499138593Ssam	x = inb(port + MSE_PORTA);
500138593Ssam	*but = (x >> 5) & 0x7;
501138593Ssam	x &= 0xf;
502138593Ssam	outb(port + MSE_PORTC, MSE_HOLD | MSE_RXHIGH);
503138593Ssam	x |= (inb(port + MSE_PORTA) << 4);
504138593Ssam	outb(port + MSE_PORTC, MSE_HOLD | MSE_RYLOW);
505138593Ssam	y = (inb(port + MSE_PORTA) & 0xf);
506138593Ssam	outb(port + MSE_PORTC, MSE_HOLD | MSE_RYHIGH);
507138593Ssam	y |= (inb(port + MSE_PORTA) << 4);
508138593Ssam	*dx += x;
509138593Ssam	*dy += y;
510138593Ssam	outb(port + MSE_PORTC, MSE_INTREN);
511138593Ssam}
512138593Ssam
513138593Ssam/*
514138593Ssam * Routines for the ATI Inport bus mouse.
515138593Ssam */
516138593Ssam/*
517138593Ssam * Test for a ATI Inport bus mouse and return 1 if it is.
518138593Ssam * (do not enable interrupts)
519138593Ssam */
520138593Ssamstatic int
521138593Ssammse_probeati(idp)
522138593Ssam	register struct isa_device *idp;
523138593Ssam{
524138593Ssam	int i;
525138593Ssam
526138593Ssam	for (i = 0; i < 2; i++)
527138593Ssam		if (inb(idp->id_iobase + MSE_PORTC) == 0xde)
528138593Ssam			return (1);
529138593Ssam	return (0);
530138593Ssam}
531138593Ssam
532138593Ssam/*
533138593Ssam * Initialize ATI Inport mouse and enable interrupts.
534138593Ssam */
535138593Ssamstatic void
536138593Ssammse_enableati(port)
537138593Ssam	register u_int port;
538138593Ssam{
539138593Ssam
540138593Ssam	outb(port + MSE_PORTA, MSE_INPORT_RESET);
541138593Ssam	outb(port + MSE_PORTA, MSE_INPORT_MODE);
542138593Ssam	outb(port + MSE_PORTB, MSE_INPORT_INTREN);
543148621Ssam}
544138593Ssam
545148621Ssam/*
546138593Ssam * Disable interrupts for ATI Inport mouse.
547148621Ssam */
548148621Ssamstatic void
549148621Ssammse_disableati(port)
550148621Ssam	register u_int port;
551148621Ssam{
552138593Ssam
553138593Ssam	outb(port + MSE_PORTA, MSE_INPORT_MODE);
554148621Ssam	outb(port + MSE_PORTB, 0);
555138593Ssam}
556148621Ssam
557138593Ssam/*
558148621Ssam * Get current dx, dy and up/down button state.
559148621Ssam */
560148621Ssamstatic void
561148621Ssammse_getati(port, dx, dy, but)
562148621Ssam	register u_int port;
563138593Ssam	int *dx;
564138593Ssam	int *dy;
565138593Ssam	int *but;
566138593Ssam{
567138593Ssam	register char byte;
568138593Ssam
569138593Ssam	outb(port + MSE_PORTA, MSE_INPORT_MODE);
570138593Ssam	outb(port + MSE_PORTB, MSE_INPORT_HOLD);
571138593Ssam	outb(port + MSE_PORTA, MSE_INPORT_STATUS);
572138593Ssam	*but = ~(inb(port + MSE_PORTB) & 0x7);
573138593Ssam	outb(port + MSE_PORTA, MSE_INPORT_DX);
574138593Ssam	byte = inb(port + MSE_PORTB);
575138593Ssam	*dx += byte;
576138593Ssam	outb(port + MSE_PORTA, MSE_INPORT_DY);
577138593Ssam	byte = inb(port + MSE_PORTB);
578138593Ssam	*dy += byte;
579138593Ssam	outb(port + MSE_PORTA, MSE_INPORT_MODE);
580138593Ssam	outb(port + MSE_PORTB, MSE_INPORT_INTREN);
581138593Ssam}
582138593Ssam
583138593Ssamstatic mse_devsw_installed = 0;
584138593Ssam
585138593Ssamstatic void 	mse_drvinit(void *unused)
586138593Ssam{
587138593Ssam	dev_t dev;
588138593Ssam
589138593Ssam	if( ! mse_devsw_installed ) {
590138593Ssam		dev = makedev(CDEV_MAJOR, 0);
591138593Ssam		cdevsw_add(&dev,&mse_cdevsw, NULL);
592138593Ssam		mse_devsw_installed = 1;
593138593Ssam    	}
594138593Ssam}
595138593Ssam
596138593SsamSYSINIT(msedev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mse_drvinit,NULL)
597138593Ssam
598138593Ssam
599138593Ssam#endif /* NMSE */
600138593Ssam