mse.c revision 14873
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 *
1414873Sscrappy * $Id: mse.c,v 1.24 1995/12/15 00:54:25 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>
5112658Sbde#include <sys/conf.h>
522056Swollman#include <sys/proc.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>
5812675Sjulian#ifdef DEVFS
5912675Sjulian#include <sys/devfsext.h>
6012675Sjulian#endif /*DEVFS*/
61637Snate
627430Sbde#include <machine/clock.h>
637430Sbde
642056Swollman#include <i386/isa/isa_device.h>
652056Swollman#include <i386/isa/icu.h>
66637Snate
6712502Sjulian
68798Swollmanstatic int mseprobe(struct isa_device *);
69798Swollmanstatic int mseattach(struct isa_device *);
70637Snate
71637Snatestruct	isa_driver msedriver = {
72637Snate	mseprobe, mseattach, "mse"
73637Snate};
74637Snate
7512675Sjulianstatic	d_open_t	mseopen;
7612675Sjulianstatic	d_close_t	mseclose;
7712675Sjulianstatic	d_read_t	mseread;
7812675Sjulianstatic	d_select_t	mseselect;
7912675Sjulian
8012675Sjulian#define CDEV_MAJOR 27
8112678Sphkstatic struct cdevsw mse_cdevsw =
8212675Sjulian	{ mseopen,	mseclose,	mseread,	nowrite,	/*27*/
8312675Sjulian	  noioc,	nostop,		nullreset,	nodevtotty,/* mse */
8412675Sjulian	  mseselect,	nommap,		NULL,	"mse",	NULL,	-1 };
8512675Sjulian
8612675Sjulian
87637Snate/*
88637Snate * Software control structure for mouse. The sc_enablemouse(),
89637Snate * sc_disablemouse() and sc_getmouse() routines must be called spl'd().
90637Snate */
91637Snate#define	PROTOBYTES	5
9212724Sphkstatic struct mse_softc {
93637Snate	int	sc_flags;
94637Snate	int	sc_mousetype;
951549Srgrimes	struct	selinfo sc_selp;
96637Snate	u_int	sc_port;
9712854Sbde	void	(*sc_enablemouse) __P((u_int port));
9812854Sbde	void	(*sc_disablemouse) __P((u_int port));
9912854Sbde	void	(*sc_getmouse) __P((u_int port, int *dx, int *dy, int *but));
100637Snate	int	sc_deltax;
101637Snate	int	sc_deltay;
102637Snate	int	sc_obuttons;
103637Snate	int	sc_buttons;
104637Snate	int	sc_bytesread;
105637Snate	u_char	sc_bytes[PROTOBYTES];
10612675Sjulian#ifdef DEVFS
10712675Sjulian	void 	*devfs_token;
10812675Sjulian	void	*n_devfs_token;
10912675Sjulian#endif
110637Snate} mse_sc[NMSE];
111637Snate
112637Snate/* Flags */
113637Snate#define	MSESC_OPEN	0x1
114637Snate#define	MSESC_WANT	0x2
115637Snate
116637Snate/* and Mouse Types */
117637Snate#define	MSE_LOGITECH	0x1
118637Snate#define	MSE_ATIINPORT	0x2
1194259Sjkh#define	MSE_LOGI_SIG	0xA5
120637Snate
121637Snate#define	MSE_PORTA	0
122637Snate#define	MSE_PORTB	1
123637Snate#define	MSE_PORTC	2
124637Snate#define	MSE_PORTD	3
125637Snate
126637Snate#define	MSE_UNIT(dev)		(minor(dev) >> 1)
127637Snate#define	MSE_NBLOCKIO(dev)	(minor(dev) & 0x1)
128637Snate
129637Snate/*
130637Snate * Logitech bus mouse definitions
131637Snate */
132637Snate#define	MSE_SETUP	0x91	/* What does this mean? */
1334259Sjkh				/* The definition for the control port */
1344259Sjkh				/* is as follows: */
1358876Srgrimes
1364259Sjkh				/* D7 	 =  Mode set flag (1 = active) 	*/
1378876Srgrimes				/* D6,D5 =  Mode selection (port A) 	*/
1384259Sjkh				/* 	    00 = Mode 0 = Basic I/O 	*/
1394259Sjkh				/* 	    01 = Mode 1 = Strobed I/O 	*/
1404259Sjkh				/* 	    10 = Mode 2 = Bi-dir bus 	*/
1414259Sjkh				/* D4	 =  Port A direction (1 = input)*/
1424259Sjkh				/* D3	 =  Port C (upper 4 bits) 	*/
1434259Sjkh				/*	    direction. (1 = input)	*/
1444259Sjkh				/* D2	 =  Mode selection (port B & C) */
1454259Sjkh				/*	    0 = Mode 0 = Basic I/O	*/
1464259Sjkh				/*	    1 = Mode 1 = Strobed I/O	*/
1474259Sjkh				/* D1	 =  Port B direction (1 = input)*/
1484259Sjkh				/* D0	 =  Port C (lower 4 bits)	*/
1494259Sjkh				/*	    direction. (1 = input)	*/
1508876Srgrimes
1514259Sjkh				/* So 91 means Basic I/O on all 3 ports,*/
1524259Sjkh				/* Port A is an input port, B is an 	*/
1534259Sjkh				/* output port, C is split with upper	*/
1544259Sjkh				/* 4 bits being an output port and lower*/
1554259Sjkh				/* 4 bits an input port, and enable the */
1564259Sjkh				/* sucker.				*/
1574259Sjkh				/* Courtesy Intel 8255 databook. Lars   */
158637Snate#define	MSE_HOLD	0x80
159637Snate#define	MSE_RXLOW	0x00
160637Snate#define	MSE_RXHIGH	0x20
161637Snate#define	MSE_RYLOW	0x40
162637Snate#define	MSE_RYHIGH	0x60
163637Snate#define	MSE_DISINTR	0x10
164637Snate#define MSE_INTREN	0x00
165637Snate
16612854Sbdestatic int mse_probelogi __P((struct isa_device *idp));
16712854Sbdestatic void mse_disablelogi __P((u_int port));
16812854Sbdestatic void mse_getlogi __P((u_int port, int *dx, int *dy, int *but));
16912854Sbdestatic void mse_enablelogi __P((u_int port));
170637Snate
171637Snate/*
172637Snate * ATI Inport mouse definitions
173637Snate */
174637Snate#define	MSE_INPORT_RESET	0x80
175637Snate#define	MSE_INPORT_STATUS	0x00
176637Snate#define	MSE_INPORT_DX		0x01
177637Snate#define	MSE_INPORT_DY		0x02
178637Snate#define	MSE_INPORT_MODE		0x07
179637Snate#define	MSE_INPORT_HOLD		0x20
180637Snate#define	MSE_INPORT_INTREN	0x09
181637Snate
18212854Sbdestatic int mse_probeati __P((struct isa_device *idp));
18312854Sbdestatic void mse_enableati __P((u_int port));
18412854Sbdestatic void mse_disableati __P((u_int port));
18512854Sbdestatic void mse_getati __P((u_int port, int *dx, int *dy, int *but));
186637Snate
187637Snate#define	MSEPRI	(PZERO + 3)
188637Snate
189637Snate/*
190637Snate * Table of mouse types.
191637Snate * Keep the Logitech last, since I haven't figured out how to probe it
192637Snate * properly yet. (Someday I'll have the documentation.)
193637Snate */
19412724Sphkstatic struct mse_types {
195637Snate	int	m_type;		/* Type of bus mouse */
19612854Sbde	int	(*m_probe) __P((struct isa_device *idp));
19712854Sbde				/* Probe routine to test for it */
19812854Sbde	void	(*m_enable) __P((u_int port));
19912854Sbde				/* Start routine */
20012854Sbde	void	(*m_disable) __P((u_int port));
20112854Sbde				/* Disable interrupts routine */
20212854Sbde	void	(*m_get) __P((u_int port, int *dx, int *dy, int *but));
20312854Sbde				/* and get mouse status */
204637Snate} mse_types[] = {
205637Snate	{ MSE_ATIINPORT, mse_probeati, mse_enableati, mse_disableati, mse_getati },
206637Snate	{ MSE_LOGITECH, mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi },
207637Snate	{ 0, },
208637Snate};
209637Snate
2107780Swollmanstatic struct kern_devconf kdc_mse[NMSE] = { {
2117780Swollman	0, 0, 0,		/* filled in by dev_attach */
2127780Swollman	"mse", 0, { MDDT_ISA, 0, "tty" },
2137780Swollman	isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
2147780Swollman	&kdc_isa0,		/* parent */
2157780Swollman	0,			/* parentdata */
2167780Swollman	DC_UNCONFIGURED,	/* state */
2177780Swollman	"ATI or Logitech bus mouse adapter",
2187780Swollman	DC_CLS_MISC		/* class */
2197780Swollman} };
2207780Swollman
2217780Swollmanstatic inline void
2227780Swollmanmse_registerdev(struct isa_device *id)
2237780Swollman{
2247780Swollman	if(id->id_unit)
2257780Swollman		kdc_mse[id->id_unit] = kdc_mse[0];
2267780Swollman	kdc_mse[id->id_unit].kdc_unit = id->id_unit;
2277780Swollman	kdc_mse[id->id_unit].kdc_isa = id;
2287780Swollman	dev_attach(&kdc_mse[id->id_unit]);
2297780Swollman}
2307780Swollman
231798Swollmanint
232637Snatemseprobe(idp)
233637Snate	register struct isa_device *idp;
234637Snate{
235637Snate	register struct mse_softc *sc = &mse_sc[idp->id_unit];
236637Snate	register int i;
237637Snate
2387780Swollman	mse_registerdev(idp);
239637Snate	/*
240637Snate	 * Check for each mouse type in the table.
241637Snate	 */
242637Snate	i = 0;
243637Snate	while (mse_types[i].m_type) {
244637Snate		if ((*mse_types[i].m_probe)(idp)) {
245637Snate			sc->sc_mousetype = mse_types[i].m_type;
246637Snate			sc->sc_enablemouse = mse_types[i].m_enable;
247637Snate			sc->sc_disablemouse = mse_types[i].m_disable;
248637Snate			sc->sc_getmouse = mse_types[i].m_get;
249637Snate			return (1);
250637Snate		}
251637Snate		i++;
252637Snate	}
253637Snate	return (0);
254637Snate}
255637Snate
256798Swollmanint
257637Snatemseattach(idp)
258637Snate	struct isa_device *idp;
259637Snate{
26012675Sjulian	int unit = idp->id_unit;
26112675Sjulian	struct mse_softc *sc = &mse_sc[unit];
262637Snate
263637Snate	sc->sc_port = idp->id_iobase;
26412675Sjulian	kdc_mse[unit].kdc_state = DC_IDLE;
26512675Sjulian#ifdef	DEVFS
26614873Sscrappy	sc->devfs_token =
26714873Sscrappy		devfs_add_devswf(&mse_cdevsw, unit << 1, DV_CHR, 0, 0,
26814873Sscrappy				 0600, "mse%d", unit);
26914873Sscrappy	sc->n_devfs_token =
27014873Sscrappy		devfs_add_devswf(&mse_cdevsw, (unit<<1)+1, DV_CHR,0, 0,
27114873Sscrappy				 0600, "nmse%d", unit);
27212675Sjulian#endif
273637Snate	return (1);
274637Snate}
275637Snate
276637Snate/*
277637Snate * Exclusive open the mouse, initialize it and enable interrupts.
278637Snate */
27912675Sjulianstatic	int
28010624Sbdemseopen(dev, flags, fmt, p)
281637Snate	dev_t dev;
28210624Sbde	int flags;
28310624Sbde	int fmt;
28410624Sbde	struct proc *p;
285637Snate{
286637Snate	register struct mse_softc *sc;
287637Snate	int s;
288637Snate
289637Snate	if (MSE_UNIT(dev) >= NMSE)
290637Snate		return (ENXIO);
291637Snate	sc = &mse_sc[MSE_UNIT(dev)];
292637Snate	if (sc->sc_flags & MSESC_OPEN)
293637Snate		return (EBUSY);
294637Snate	sc->sc_flags |= MSESC_OPEN;
2957780Swollman	kdc_mse[MSE_UNIT(dev)].kdc_state = DC_BUSY;
296637Snate	sc->sc_obuttons = sc->sc_buttons = 0x7;
297637Snate	sc->sc_deltax = sc->sc_deltay = 0;
298637Snate	sc->sc_bytesread = PROTOBYTES;
299637Snate
300637Snate	/*
301637Snate	 * Initialize mouse interface and enable interrupts.
302637Snate	 */
303637Snate	s = spltty();
304637Snate	(*sc->sc_enablemouse)(sc->sc_port);
305637Snate	splx(s);
306637Snate	return (0);
307637Snate}
308637Snate
309637Snate/*
310637Snate * mseclose: just turn off mouse innterrupts.
311637Snate */
31212675Sjulianstatic	int
31310624Sbdemseclose(dev, flags, fmt, p)
314798Swollman	dev_t dev;
31510624Sbde	int flags;
31610624Sbde	int fmt;
31710624Sbde	struct proc *p;
318637Snate{
319637Snate	struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
320637Snate	int s;
321637Snate
322637Snate	s = spltty();
323637Snate	(*sc->sc_disablemouse)(sc->sc_port);
324637Snate	sc->sc_flags &= ~MSESC_OPEN;
3257780Swollman	kdc_mse[MSE_UNIT(dev)].kdc_state = DC_IDLE;
326637Snate	splx(s);
327637Snate	return(0);
328637Snate}
329637Snate
3308876Srgrimes/*
331637Snate * mseread: return mouse info using the MSC serial protocol, but without
332637Snate * using bytes 4 and 5.
333637Snate * (Yes this is cheesy, but it makes the X386 server happy, so...)
334637Snate */
33512675Sjulianstatic	int
33610624Sbdemseread(dev, uio, ioflag)
337637Snate	dev_t dev;
338637Snate	struct uio *uio;
33910624Sbde	int ioflag;
340637Snate{
341637Snate	register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
342637Snate	int xfer, s, error;
343637Snate
344637Snate	/*
345637Snate	 * If there are no protocol bytes to be read, set up a new protocol
346637Snate	 * packet.
347637Snate	 */
348637Snate	s = spltty(); /* XXX Should be its own spl, but where is imlXX() */
349637Snate	if (sc->sc_bytesread >= PROTOBYTES) {
350637Snate		while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
351637Snate		       (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
352637Snate			if (MSE_NBLOCKIO(dev)) {
353637Snate				splx(s);
354637Snate				return (0);
355637Snate			}
356637Snate			sc->sc_flags |= MSESC_WANT;
357637Snate			if (error = tsleep((caddr_t)sc, MSEPRI | PCATCH,
358637Snate				"mseread", 0)) {
359637Snate				splx(s);
360637Snate				return (error);
361637Snate			}
362637Snate		}
363637Snate
364637Snate		/*
365637Snate		 * Generate protocol bytes.
366637Snate		 * For some reason X386 expects 5 bytes but never uses
367637Snate		 * the fourth or fifth?
368637Snate		 */
369637Snate		sc->sc_bytes[0] = 0x80 | (sc->sc_buttons & ~0xf8);
370637Snate		if (sc->sc_deltax > 127)
371637Snate			sc->sc_deltax = 127;
372637Snate		if (sc->sc_deltax < -127)
373637Snate			sc->sc_deltax = -127;
374637Snate		sc->sc_deltay = -sc->sc_deltay;	/* Otherwise mousey goes wrong way */
375637Snate		if (sc->sc_deltay > 127)
376637Snate			sc->sc_deltay = 127;
377637Snate		if (sc->sc_deltay < -127)
378637Snate			sc->sc_deltay = -127;
379637Snate		sc->sc_bytes[1] = sc->sc_deltax;
380637Snate		sc->sc_bytes[2] = sc->sc_deltay;
381637Snate		sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
382637Snate		sc->sc_obuttons = sc->sc_buttons;
383637Snate		sc->sc_deltax = sc->sc_deltay = 0;
384637Snate		sc->sc_bytesread = 0;
385637Snate	}
386637Snate	splx(s);
3871567Srgrimes	xfer = min(uio->uio_resid, PROTOBYTES - sc->sc_bytesread);
388637Snate	if (error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio))
389637Snate		return (error);
390637Snate	sc->sc_bytesread += xfer;
391637Snate	return(0);
392637Snate}
393637Snate
394637Snate/*
395637Snate * mseselect: check for mouse input to be processed.
396637Snate */
39712675Sjulianstatic	int
398637Snatemseselect(dev, rw, p)
399637Snate	dev_t dev;
400637Snate	int rw;
401637Snate	struct proc *p;
402637Snate{
403637Snate	register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
404637Snate	int s;
405637Snate
406637Snate	s = spltty();
407637Snate	if (sc->sc_bytesread != PROTOBYTES || sc->sc_deltax != 0 ||
408637Snate	    sc->sc_deltay != 0 || (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
409637Snate		splx(s);
410637Snate		return (1);
411637Snate	}
412637Snate
413637Snate	/*
414637Snate	 * Since this is an exclusive open device, any previous proc.
415637Snate	 * pointer is trash now, so we can just assign it.
416637Snate	 */
4171549Srgrimes	selrecord(p, &sc->sc_selp);
418637Snate	splx(s);
419637Snate	return (0);
420637Snate}
421637Snate
422637Snate/*
423637Snate * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
424637Snate */
425798Swollmanvoid
426637Snatemseintr(unit)
427637Snate	int unit;
428637Snate{
429637Snate	register struct mse_softc *sc = &mse_sc[unit];
430637Snate
431637Snate#ifdef DEBUG
432637Snate	static int mse_intrcnt = 0;
433637Snate	if((mse_intrcnt++ % 10000) == 0)
434637Snate		printf("mseintr\n");
435637Snate#endif /* DEBUG */
436637Snate	if ((sc->sc_flags & MSESC_OPEN) == 0)
437637Snate		return;
438637Snate
439637Snate	(*sc->sc_getmouse)(sc->sc_port, &sc->sc_deltax, &sc->sc_deltay, &sc->sc_buttons);
440637Snate
441637Snate	/*
442637Snate	 * If mouse state has changed, wake up anyone wanting to know.
443637Snate	 */
444637Snate	if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
445637Snate	    (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
4468876Srgrimes		if (sc->sc_flags & MSESC_WANT) {
4478876Srgrimes			sc->sc_flags &= ~MSESC_WANT;
4488876Srgrimes			wakeup((caddr_t)sc);
4498876Srgrimes		}
4501549Srgrimes		selwakeup(&sc->sc_selp);
451637Snate	}
452637Snate}
453637Snate
454637Snate/*
455637Snate * Routines for the Logitech mouse.
456637Snate */
457637Snate/*
458637Snate * Test for a Logitech bus mouse and return 1 if it is.
459637Snate * (until I know how to use the signature port properly, just disable
460637Snate *  interrupts and return 1)
461637Snate */
462637Snatestatic int
463637Snatemse_probelogi(idp)
464637Snate	register struct isa_device *idp;
465637Snate{
466637Snate
4674259Sjkh	int sig;
4684259Sjkh
4694259Sjkh	outb(idp->id_iobase + MSE_PORTD, MSE_SETUP);
4704259Sjkh		/* set the signature port */
4714259Sjkh	outb(idp->id_iobase + MSE_PORTB, MSE_LOGI_SIG);
4724259Sjkh
4734259Sjkh	DELAY(30000); /* 30 ms delay */
4744259Sjkh	sig = inb(idp->id_iobase + MSE_PORTB) & 0xFF;
4754259Sjkh	if (sig == MSE_LOGI_SIG) {
4764259Sjkh		outb(idp->id_iobase + MSE_PORTC, MSE_DISINTR);
4774259Sjkh		return(1);
4784259Sjkh	} else {
4798876Srgrimes		printf("mse%d: wrong signature %x\n",idp->id_unit,sig);
4804259Sjkh		return(0);
481637Snate	}
482637Snate}
483637Snate
484637Snate/*
485637Snate * Initialize Logitech mouse and enable interrupts.
486637Snate */
487637Snatestatic void
488637Snatemse_enablelogi(port)
489637Snate	register u_int port;
490637Snate{
491637Snate	int dx, dy, but;
492637Snate
493637Snate	outb(port + MSE_PORTD, MSE_SETUP);
494637Snate	mse_getlogi(port, &dx, &dy, &but);
495637Snate}
496637Snate
497637Snate/*
498637Snate * Disable interrupts for Logitech mouse.
499637Snate */
500637Snatestatic void
501637Snatemse_disablelogi(port)
502637Snate	register u_int port;
503637Snate{
504637Snate
505637Snate	outb(port + MSE_PORTC, MSE_DISINTR);
506637Snate}
507637Snate
508637Snate/*
509637Snate * Get the current dx, dy and button up/down state.
510637Snate */
511637Snatestatic void
512637Snatemse_getlogi(port, dx, dy, but)
513637Snate	register u_int port;
514637Snate	int *dx;
515637Snate	int *dy;
516637Snate	int *but;
517637Snate{
518637Snate	register char x, y;
519637Snate
520637Snate	outb(port + MSE_PORTC, MSE_HOLD | MSE_RXLOW);
521637Snate	x = inb(port + MSE_PORTA);
522637Snate	*but = (x >> 5) & 0x7;
523637Snate	x &= 0xf;
524637Snate	outb(port + MSE_PORTC, MSE_HOLD | MSE_RXHIGH);
525637Snate	x |= (inb(port + MSE_PORTA) << 4);
526637Snate	outb(port + MSE_PORTC, MSE_HOLD | MSE_RYLOW);
527637Snate	y = (inb(port + MSE_PORTA) & 0xf);
528637Snate	outb(port + MSE_PORTC, MSE_HOLD | MSE_RYHIGH);
529637Snate	y |= (inb(port + MSE_PORTA) << 4);
530637Snate	*dx += x;
531637Snate	*dy += y;
532637Snate	outb(port + MSE_PORTC, MSE_INTREN);
533637Snate}
534637Snate
535637Snate/*
536637Snate * Routines for the ATI Inport bus mouse.
537637Snate */
538637Snate/*
539637Snate * Test for a ATI Inport bus mouse and return 1 if it is.
540637Snate * (do not enable interrupts)
541637Snate */
542637Snatestatic int
543637Snatemse_probeati(idp)
544637Snate	register struct isa_device *idp;
545637Snate{
546637Snate	int i;
547637Snate
548637Snate	for (i = 0; i < 2; i++)
549637Snate		if (inb(idp->id_iobase + MSE_PORTC) == 0xde)
550637Snate			return (1);
551637Snate	return (0);
552637Snate}
553637Snate
554637Snate/*
555637Snate * Initialize ATI Inport mouse and enable interrupts.
556637Snate */
557637Snatestatic void
558637Snatemse_enableati(port)
559637Snate	register u_int port;
560637Snate{
561637Snate
562637Snate	outb(port + MSE_PORTA, MSE_INPORT_RESET);
563637Snate	outb(port + MSE_PORTA, MSE_INPORT_MODE);
564637Snate	outb(port + MSE_PORTB, MSE_INPORT_INTREN);
565637Snate}
566637Snate
567637Snate/*
568637Snate * Disable interrupts for ATI Inport mouse.
569637Snate */
570637Snatestatic void
571637Snatemse_disableati(port)
572637Snate	register u_int port;
573637Snate{
574637Snate
575637Snate	outb(port + MSE_PORTA, MSE_INPORT_MODE);
576637Snate	outb(port + MSE_PORTB, 0);
577637Snate}
578637Snate
579637Snate/*
580637Snate * Get current dx, dy and up/down button state.
581637Snate */
582637Snatestatic void
583637Snatemse_getati(port, dx, dy, but)
584637Snate	register u_int port;
585637Snate	int *dx;
586637Snate	int *dy;
587637Snate	int *but;
588637Snate{
589637Snate	register char byte;
590637Snate
591637Snate	outb(port + MSE_PORTA, MSE_INPORT_MODE);
592637Snate	outb(port + MSE_PORTB, MSE_INPORT_HOLD);
593637Snate	outb(port + MSE_PORTA, MSE_INPORT_STATUS);
594637Snate	*but = ~(inb(port + MSE_PORTB) & 0x7);
595637Snate	outb(port + MSE_PORTA, MSE_INPORT_DX);
596637Snate	byte = inb(port + MSE_PORTB);
597637Snate	*dx += byte;
598637Snate	outb(port + MSE_PORTA, MSE_INPORT_DY);
599637Snate	byte = inb(port + MSE_PORTB);
600637Snate	*dy += byte;
601637Snate	outb(port + MSE_PORTA, MSE_INPORT_MODE);
602637Snate	outb(port + MSE_PORTB, MSE_INPORT_INTREN);
603637Snate}
60412502Sjulian
60512502Sjulianstatic mse_devsw_installed = 0;
60612502Sjulian
60712517Sjulianstatic void 	mse_drvinit(void *unused)
60812502Sjulian{
60912517Sjulian	dev_t dev;
61012517Sjulian
61112502Sjulian	if( ! mse_devsw_installed ) {
61212675Sjulian		dev = makedev(CDEV_MAJOR, 0);
61312675Sjulian		cdevsw_add(&dev,&mse_cdevsw, NULL);
61412502Sjulian		mse_devsw_installed = 1;
61512517Sjulian    	}
61612502Sjulian}
61712517Sjulian
61812517SjulianSYSINIT(msedev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mse_drvinit,NULL)
61912517Sjulian
62012517Sjulian
621637Snate#endif /* NMSE */
622