mse.c revision 32726
1/*
2 * Copyright 1992 by the University of Guelph
3 *
4 * Permission to use, copy and modify this
5 * software and its documentation for any purpose and without
6 * fee is hereby granted, provided that the above copyright
7 * notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting
9 * documentation.
10 * University of Guelph makes no representations about the suitability of
11 * this software for any purpose.  It is provided "as is"
12 * without express or implied warranty.
13 *
14 * $Id: mse.c,v 1.36 1997/12/07 08:09:16 yokota Exp $
15 */
16/*
17 * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and
18 * the X386 port, courtesy of
19 * Rick Macklem, rick@snowhite.cis.uoguelph.ca
20 * Caveats: The driver currently uses spltty(), but doesn't use any
21 * generic tty code. It could use splmse() (that only masks off the
22 * bus mouse interrupt, but that would require hacking in i386/isa/icu.s.
23 * (This may be worth the effort, since the Logitech generates 30/60
24 * interrupts/sec continuously while it is open.)
25 * NB: The ATI has NOT been tested yet!
26 */
27
28/*
29 * Modification history:
30 * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com)
31 *   improved probe based on input from Logitech.
32 *
33 * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu)
34 *   fixes to make it work with Microsoft InPort busmouse
35 *
36 * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu)
37 *   added patches for new "select" interface
38 *
39 * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu)
40 *   changed position of some spl()'s in mseread
41 *
42 * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu)
43 *   limit maximum negative x/y value to -127 to work around XFree problem
44 *   that causes spurious button pushes.
45 */
46
47#include "mse.h"
48#if NMSE > 0
49#include "opt_devfs.h"
50
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/conf.h>
54#include <sys/kernel.h>
55#include <sys/poll.h>
56#include <sys/select.h>
57#include <sys/uio.h>
58#ifdef DEVFS
59#include <sys/devfsext.h>
60#endif /*DEVFS*/
61
62#include <machine/clock.h>
63#include <machine/mouse.h>
64
65#include <i386/isa/isa_device.h>
66
67/* driver configuration flags (config) */
68#define MSE_CONFIG_ACCEL	0x00f0  /* acceleration factor */
69#define MSE_CONFIG_FLAGS	(MSE_CONFIG_ACCEL)
70
71static int mseprobe(struct isa_device *);
72static int mseattach(struct isa_device *);
73
74struct	isa_driver msedriver = {
75	mseprobe, mseattach, "mse"
76};
77
78static	d_open_t	mseopen;
79static	d_close_t	mseclose;
80static	d_read_t	mseread;
81static  d_ioctl_t	mseioctl;
82static	d_poll_t	msepoll;
83
84#define CDEV_MAJOR 27
85static struct cdevsw mse_cdevsw =
86	{ mseopen,	mseclose,	mseread,	nowrite,	/*27*/
87	  mseioctl,	nostop,		nullreset,	nodevtotty,/* mse */
88	  msepoll,	nommap,		NULL,	"mse",	NULL,	-1 };
89
90
91/*
92 * Software control structure for mouse. The sc_enablemouse(),
93 * sc_disablemouse() and sc_getmouse() routines must be called spl'd().
94 */
95static struct mse_softc {
96	int	sc_flags;
97	int	sc_mousetype;
98	struct	selinfo sc_selp;
99	u_int	sc_port;
100	void	(*sc_enablemouse) __P((u_int port));
101	void	(*sc_disablemouse) __P((u_int port));
102	void	(*sc_getmouse) __P((u_int port, int *dx, int *dy, int *but));
103	int	sc_deltax;
104	int	sc_deltay;
105	int	sc_obuttons;
106	int	sc_buttons;
107	int	sc_bytesread;
108	u_char	sc_bytes[MOUSE_SYS_PACKETSIZE];
109	mousehw_t	hw;
110	mousemode_t	mode;
111	mousestatus_t	status;
112#ifdef DEVFS
113	void 	*devfs_token;
114	void	*n_devfs_token;
115#endif
116} mse_sc[NMSE];
117
118/* Flags */
119#define	MSESC_OPEN	0x1
120#define	MSESC_WANT	0x2
121
122/* and Mouse Types */
123#define	MSE_NONE	0	/* don't move this! */
124#define	MSE_LOGITECH	0x1
125#define	MSE_ATIINPORT	0x2
126#define	MSE_LOGI_SIG	0xA5
127
128#define	MSE_PORTA	0
129#define	MSE_PORTB	1
130#define	MSE_PORTC	2
131#define	MSE_PORTD	3
132
133#define	MSE_UNIT(dev)		(minor(dev) >> 1)
134#define	MSE_NBLOCKIO(dev)	(minor(dev) & 0x1)
135
136/*
137 * Logitech bus mouse definitions
138 */
139#define	MSE_SETUP	0x91	/* What does this mean? */
140				/* The definition for the control port */
141				/* is as follows: */
142
143				/* D7 	 =  Mode set flag (1 = active) 	*/
144				/* D6,D5 =  Mode selection (port A) 	*/
145				/* 	    00 = Mode 0 = Basic I/O 	*/
146				/* 	    01 = Mode 1 = Strobed I/O 	*/
147				/* 	    10 = Mode 2 = Bi-dir bus 	*/
148				/* D4	 =  Port A direction (1 = input)*/
149				/* D3	 =  Port C (upper 4 bits) 	*/
150				/*	    direction. (1 = input)	*/
151				/* D2	 =  Mode selection (port B & C) */
152				/*	    0 = Mode 0 = Basic I/O	*/
153				/*	    1 = Mode 1 = Strobed I/O	*/
154				/* D1	 =  Port B direction (1 = input)*/
155				/* D0	 =  Port C (lower 4 bits)	*/
156				/*	    direction. (1 = input)	*/
157
158				/* So 91 means Basic I/O on all 3 ports,*/
159				/* Port A is an input port, B is an 	*/
160				/* output port, C is split with upper	*/
161				/* 4 bits being an output port and lower*/
162				/* 4 bits an input port, and enable the */
163				/* sucker.				*/
164				/* Courtesy Intel 8255 databook. Lars   */
165#define	MSE_HOLD	0x80
166#define	MSE_RXLOW	0x00
167#define	MSE_RXHIGH	0x20
168#define	MSE_RYLOW	0x40
169#define	MSE_RYHIGH	0x60
170#define	MSE_DISINTR	0x10
171#define MSE_INTREN	0x00
172
173static int mse_probelogi __P((struct isa_device *idp));
174static void mse_disablelogi __P((u_int port));
175static void mse_getlogi __P((u_int port, int *dx, int *dy, int *but));
176static void mse_enablelogi __P((u_int port));
177
178/*
179 * ATI Inport mouse definitions
180 */
181#define	MSE_INPORT_RESET	0x80
182#define	MSE_INPORT_STATUS	0x00
183#define	MSE_INPORT_DX		0x01
184#define	MSE_INPORT_DY		0x02
185#define	MSE_INPORT_MODE		0x07
186#define	MSE_INPORT_HOLD		0x20
187#define	MSE_INPORT_INTREN	0x09
188
189static int mse_probeati __P((struct isa_device *idp));
190static void mse_enableati __P((u_int port));
191static void mse_disableati __P((u_int port));
192static void mse_getati __P((u_int port, int *dx, int *dy, int *but));
193
194#define	MSEPRI	(PZERO + 3)
195
196/*
197 * Table of mouse types.
198 * Keep the Logitech last, since I haven't figured out how to probe it
199 * properly yet. (Someday I'll have the documentation.)
200 */
201static struct mse_types {
202	int	m_type;		/* Type of bus mouse */
203	int	(*m_probe) __P((struct isa_device *idp));
204				/* Probe routine to test for it */
205	void	(*m_enable) __P((u_int port));
206				/* Start routine */
207	void	(*m_disable) __P((u_int port));
208				/* Disable interrupts routine */
209	void	(*m_get) __P((u_int port, int *dx, int *dy, int *but));
210				/* and get mouse status */
211	mousehw_t   m_hw;	/* buttons iftype type model hwid */
212	mousemode_t m_mode;	/* proto rate res accel level size mask */
213} mse_types[] = {
214	{ MSE_ATIINPORT,
215	  mse_probeati, mse_enableati, mse_disableati, mse_getati,
216	  { 2, MOUSE_IF_INPORT, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, },
217	  { MOUSE_PROTO_INPORT, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE,
218	    { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, },
219	{ MSE_LOGITECH,
220	  mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi,
221	  { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, },
222	  { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE,
223	    { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, },
224	{ 0, },
225};
226
227int
228mseprobe(idp)
229	register struct isa_device *idp;
230{
231	register struct mse_softc *sc = &mse_sc[idp->id_unit];
232	register int i;
233
234	/*
235	 * Check for each mouse type in the table.
236	 */
237	i = 0;
238	while (mse_types[i].m_type) {
239		if ((*mse_types[i].m_probe)(idp)) {
240			sc->sc_mousetype = mse_types[i].m_type;
241			sc->sc_enablemouse = mse_types[i].m_enable;
242			sc->sc_disablemouse = mse_types[i].m_disable;
243			sc->sc_getmouse = mse_types[i].m_get;
244			sc->hw = mse_types[i].m_hw;
245			sc->mode = mse_types[i].m_mode;
246			return (1);
247		}
248		i++;
249	}
250	return (0);
251}
252
253int
254mseattach(idp)
255	struct isa_device *idp;
256{
257	int unit = idp->id_unit;
258	struct mse_softc *sc = &mse_sc[unit];
259
260	sc->sc_port = idp->id_iobase;
261	sc->mode.accelfactor = (idp->id_flags & MSE_CONFIG_ACCEL) >> 4;
262#ifdef	DEVFS
263	sc->devfs_token =
264		devfs_add_devswf(&mse_cdevsw, unit << 1, DV_CHR, 0, 0,
265				 0600, "mse%d", unit);
266	sc->n_devfs_token =
267		devfs_add_devswf(&mse_cdevsw, (unit<<1)+1, DV_CHR,0, 0,
268				 0600, "nmse%d", unit);
269#endif
270	return (1);
271}
272
273/*
274 * Exclusive open the mouse, initialize it and enable interrupts.
275 */
276static	int
277mseopen(dev, flags, fmt, p)
278	dev_t dev;
279	int flags;
280	int fmt;
281	struct proc *p;
282{
283	register struct mse_softc *sc;
284	int s;
285
286	if (MSE_UNIT(dev) >= NMSE)
287		return (ENXIO);
288	sc = &mse_sc[MSE_UNIT(dev)];
289	if (sc->sc_mousetype == MSE_NONE)
290		return (ENXIO);
291	if (sc->sc_flags & MSESC_OPEN)
292		return (EBUSY);
293	sc->sc_flags |= MSESC_OPEN;
294	sc->sc_obuttons = sc->sc_buttons = MOUSE_MSC_BUTTONS;
295	sc->sc_deltax = sc->sc_deltay = 0;
296	sc->sc_bytesread = sc->mode.packetsize = MOUSE_MSC_PACKETSIZE;
297	sc->mode.level = 0;
298	sc->status.flags = 0;
299	sc->status.button = sc->status.obutton = 0;
300	sc->status.dx = sc->status.dy = sc->status.dz = 0;
301
302	/*
303	 * Initialize mouse interface and enable interrupts.
304	 */
305	s = spltty();
306	(*sc->sc_enablemouse)(sc->sc_port);
307	splx(s);
308	return (0);
309}
310
311/*
312 * mseclose: just turn off mouse innterrupts.
313 */
314static	int
315mseclose(dev, flags, fmt, p)
316	dev_t dev;
317	int flags;
318	int fmt;
319	struct proc *p;
320{
321	struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
322	int s;
323
324	s = spltty();
325	(*sc->sc_disablemouse)(sc->sc_port);
326	sc->sc_flags &= ~MSESC_OPEN;
327	splx(s);
328	return(0);
329}
330
331/*
332 * mseread: return mouse info using the MSC serial protocol, but without
333 * using bytes 4 and 5.
334 * (Yes this is cheesy, but it makes the X386 server happy, so...)
335 */
336static	int
337mseread(dev, uio, ioflag)
338	dev_t dev;
339	struct uio *uio;
340	int ioflag;
341{
342	register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
343	int xfer, s, error;
344
345	/*
346	 * If there are no protocol bytes to be read, set up a new protocol
347	 * packet.
348	 */
349	s = spltty(); /* XXX Should be its own spl, but where is imlXX() */
350	if (sc->sc_bytesread >= sc->mode.packetsize) {
351		while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
352		       (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
353			if (MSE_NBLOCKIO(dev)) {
354				splx(s);
355				return (0);
356			}
357			sc->sc_flags |= MSESC_WANT;
358			if (error = tsleep((caddr_t)sc, MSEPRI | PCATCH,
359				"mseread", 0)) {
360				splx(s);
361				return (error);
362			}
363		}
364
365		/*
366		 * Generate protocol bytes.
367		 * For some reason X386 expects 5 bytes but never uses
368		 * the fourth or fifth?
369		 */
370		sc->sc_bytes[0] = sc->mode.syncmask[1]
371		    | (sc->sc_buttons & ~sc->mode.syncmask[0]);
372		if (sc->sc_deltax > 127)
373			sc->sc_deltax = 127;
374		if (sc->sc_deltax < -127)
375			sc->sc_deltax = -127;
376		sc->sc_deltay = -sc->sc_deltay;	/* Otherwise mousey goes wrong way */
377		if (sc->sc_deltay > 127)
378			sc->sc_deltay = 127;
379		if (sc->sc_deltay < -127)
380			sc->sc_deltay = -127;
381		sc->sc_bytes[1] = sc->sc_deltax;
382		sc->sc_bytes[2] = sc->sc_deltay;
383		sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
384		sc->sc_bytes[5] = sc->sc_bytes[6] = 0;
385		sc->sc_bytes[7] = MOUSE_SYS_EXTBUTTONS;
386		sc->sc_obuttons = sc->sc_buttons;
387		sc->sc_deltax = sc->sc_deltay = 0;
388		sc->sc_bytesread = 0;
389	}
390	splx(s);
391	xfer = min(uio->uio_resid, sc->mode.packetsize - sc->sc_bytesread);
392	if (error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio))
393		return (error);
394	sc->sc_bytesread += xfer;
395	return(0);
396}
397
398/*
399 * mseioctl: process ioctl commands.
400 */
401static int
402mseioctl(dev, cmd, addr, flag, p)
403	dev_t dev;
404	int cmd;
405	caddr_t addr;
406	int flag;
407	struct proc *p;
408{
409	register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
410	mousestatus_t status;
411	int err = 0;
412	int s;
413
414	switch (cmd) {
415
416	case MOUSE_GETHWINFO:
417		s = spltty();
418		*(mousehw_t *)addr = sc->hw;
419		if (sc->mode.level == 0)
420			((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
421		splx(s);
422		break;
423
424	case MOUSE_GETMODE:
425		s = spltty();
426		*(mousemode_t *)addr = sc->mode;
427		switch (sc->mode.level) {
428		case 0:
429			break;
430		case 1:
431			((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
432	    		((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
433	    		((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
434			break;
435		}
436		splx(s);
437		break;
438
439	case MOUSE_SETMODE:
440		switch (((mousemode_t *)addr)->level) {
441		case 0:
442		case 1:
443			break;
444		default:
445			return (EINVAL);
446		}
447		if (((mousemode_t *)addr)->accelfactor < -1)
448			return (EINVAL);
449		else if (((mousemode_t *)addr)->accelfactor >= 0)
450			sc->mode.accelfactor =
451			    ((mousemode_t *)addr)->accelfactor;
452		sc->mode.level = ((mousemode_t *)addr)->level;
453		switch (sc->mode.level) {
454		case 0:
455			sc->sc_bytesread = sc->mode.packetsize
456			    = MOUSE_MSC_PACKETSIZE;
457			break;
458		case 1:
459			sc->sc_bytesread = sc->mode.packetsize
460			    = MOUSE_SYS_PACKETSIZE;
461			break;
462		}
463		break;
464
465	case MOUSE_GETLEVEL:
466		*(int *)addr = sc->mode.level;
467		break;
468
469	case MOUSE_SETLEVEL:
470		switch (*(int *)addr) {
471		case 0:
472			sc->mode.level = *(int *)addr;
473			sc->sc_bytesread = sc->mode.packetsize
474			    = MOUSE_MSC_PACKETSIZE;
475			break;
476		case 1:
477			sc->mode.level = *(int *)addr;
478			sc->sc_bytesread = sc->mode.packetsize
479			    = MOUSE_SYS_PACKETSIZE;
480			break;
481		default:
482			return (EINVAL);
483		}
484		break;
485
486	case MOUSE_GETSTATUS:
487		s = spltty();
488		status = sc->status;
489		sc->status.flags = 0;
490		sc->status.obutton = sc->status.button;
491		sc->status.button = 0;
492		sc->status.dx = 0;
493		sc->status.dy = 0;
494		sc->status.dz = 0;
495		splx(s);
496		*(mousestatus_t *)addr = status;
497		break;
498
499	case MOUSE_READSTATE:
500	case MOUSE_READDATA:
501		return (ENODEV);
502
503#if (defined(MOUSE_GETVARS))
504	case MOUSE_GETVARS:
505	case MOUSE_SETVARS:
506		return (ENODEV);
507#endif
508
509	default:
510		return (ENOTTY);
511	}
512	return (err);
513}
514
515/*
516 * msepoll: check for mouse input to be processed.
517 */
518static	int
519msepoll(dev, events, p)
520	dev_t dev;
521	int events;
522	struct proc *p;
523{
524	register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
525	int s;
526	int revents = 0;
527
528	s = spltty();
529	if (events & (POLLIN | POLLRDNORM))
530		if (sc->sc_bytesread != sc->mode.packetsize ||
531		    sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
532		    (sc->sc_obuttons ^ sc->sc_buttons) != 0)
533			revents |= events & (POLLIN | POLLRDNORM);
534		else {
535			/*
536			 * Since this is an exclusive open device, any previous
537			 * proc pointer is trash now, so we can just assign it.
538			 */
539			selrecord(p, &sc->sc_selp);
540		}
541
542	splx(s);
543	return (revents);
544}
545
546/*
547 * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
548 */
549void
550mseintr(unit)
551	int unit;
552{
553	/*
554	 * the table to turn MouseSystem button bits (MOUSE_MSC_BUTTON?UP)
555	 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
556	 */
557	static int butmap[8] = {
558		0,
559		MOUSE_BUTTON3DOWN,
560		MOUSE_BUTTON2DOWN,
561		MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
562		MOUSE_BUTTON1DOWN,
563		MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
564		MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
565        	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
566	};
567	register struct mse_softc *sc = &mse_sc[unit];
568	int dx, dy, but;
569	int sign;
570
571#ifdef DEBUG
572	static int mse_intrcnt = 0;
573	if((mse_intrcnt++ % 10000) == 0)
574		printf("mseintr\n");
575#endif /* DEBUG */
576	if ((sc->sc_flags & MSESC_OPEN) == 0)
577		return;
578
579	(*sc->sc_getmouse)(sc->sc_port, &dx, &dy, &but);
580	if (sc->mode.accelfactor > 0) {
581		sign = (dx < 0);
582		dx = dx * dx / sc->mode.accelfactor;
583		if (dx == 0)
584			dx = 1;
585		if (sign)
586			dx = -dx;
587		sign = (dy < 0);
588		dy = dy * dy / sc->mode.accelfactor;
589		if (dy == 0)
590			dy = 1;
591		if (sign)
592			dy = -dy;
593	}
594	sc->sc_deltax += dx;
595	sc->sc_deltay += dy;
596	sc->sc_buttons = but;
597
598	but = butmap[~but & MOUSE_MSC_BUTTONS];
599	sc->status.dx += dx;
600	sc->status.dy += dy;
601	sc->status.flags |= ((dx || dy) ? MOUSE_POSCHANGED : 0)
602	    | (sc->status.button ^ but);
603	sc->status.button = but;
604
605	/*
606	 * If mouse state has changed, wake up anyone wanting to know.
607	 */
608	if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
609	    (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
610		if (sc->sc_flags & MSESC_WANT) {
611			sc->sc_flags &= ~MSESC_WANT;
612			wakeup((caddr_t)sc);
613		}
614		selwakeup(&sc->sc_selp);
615	}
616}
617
618/*
619 * Routines for the Logitech mouse.
620 */
621/*
622 * Test for a Logitech bus mouse and return 1 if it is.
623 * (until I know how to use the signature port properly, just disable
624 *  interrupts and return 1)
625 */
626static int
627mse_probelogi(idp)
628	register struct isa_device *idp;
629{
630
631	int sig;
632
633	outb(idp->id_iobase + MSE_PORTD, MSE_SETUP);
634		/* set the signature port */
635	outb(idp->id_iobase + MSE_PORTB, MSE_LOGI_SIG);
636
637	DELAY(30000); /* 30 ms delay */
638	sig = inb(idp->id_iobase + MSE_PORTB) & 0xFF;
639	if (sig == MSE_LOGI_SIG) {
640		outb(idp->id_iobase + MSE_PORTC, MSE_DISINTR);
641		return(1);
642	} else {
643		if (bootverbose)
644			printf("mse%d: wrong signature %x\n",idp->id_unit,sig);
645		return(0);
646	}
647}
648
649/*
650 * Initialize Logitech mouse and enable interrupts.
651 */
652static void
653mse_enablelogi(port)
654	register u_int port;
655{
656	int dx, dy, but;
657
658	outb(port + MSE_PORTD, MSE_SETUP);
659	mse_getlogi(port, &dx, &dy, &but);
660}
661
662/*
663 * Disable interrupts for Logitech mouse.
664 */
665static void
666mse_disablelogi(port)
667	register u_int port;
668{
669
670	outb(port + MSE_PORTC, MSE_DISINTR);
671}
672
673/*
674 * Get the current dx, dy and button up/down state.
675 */
676static void
677mse_getlogi(port, dx, dy, but)
678	register u_int port;
679	int *dx;
680	int *dy;
681	int *but;
682{
683	register char x, y;
684
685	outb(port + MSE_PORTC, MSE_HOLD | MSE_RXLOW);
686	x = inb(port + MSE_PORTA);
687	*but = (x >> 5) & MOUSE_MSC_BUTTONS;
688	x &= 0xf;
689	outb(port + MSE_PORTC, MSE_HOLD | MSE_RXHIGH);
690	x |= (inb(port + MSE_PORTA) << 4);
691	outb(port + MSE_PORTC, MSE_HOLD | MSE_RYLOW);
692	y = (inb(port + MSE_PORTA) & 0xf);
693	outb(port + MSE_PORTC, MSE_HOLD | MSE_RYHIGH);
694	y |= (inb(port + MSE_PORTA) << 4);
695	*dx = x;
696	*dy = y;
697	outb(port + MSE_PORTC, MSE_INTREN);
698}
699
700/*
701 * Routines for the ATI Inport bus mouse.
702 */
703/*
704 * Test for a ATI Inport bus mouse and return 1 if it is.
705 * (do not enable interrupts)
706 */
707static int
708mse_probeati(idp)
709	register struct isa_device *idp;
710{
711	int i;
712
713	for (i = 0; i < 2; i++)
714		if (inb(idp->id_iobase + MSE_PORTC) == 0xde)
715			return (1);
716	return (0);
717}
718
719/*
720 * Initialize ATI Inport mouse and enable interrupts.
721 */
722static void
723mse_enableati(port)
724	register u_int port;
725{
726
727	outb(port + MSE_PORTA, MSE_INPORT_RESET);
728	outb(port + MSE_PORTA, MSE_INPORT_MODE);
729	outb(port + MSE_PORTB, MSE_INPORT_INTREN);
730}
731
732/*
733 * Disable interrupts for ATI Inport mouse.
734 */
735static void
736mse_disableati(port)
737	register u_int port;
738{
739
740	outb(port + MSE_PORTA, MSE_INPORT_MODE);
741	outb(port + MSE_PORTB, 0);
742}
743
744/*
745 * Get current dx, dy and up/down button state.
746 */
747static void
748mse_getati(port, dx, dy, but)
749	register u_int port;
750	int *dx;
751	int *dy;
752	int *but;
753{
754	register char byte;
755
756	outb(port + MSE_PORTA, MSE_INPORT_MODE);
757	outb(port + MSE_PORTB, MSE_INPORT_HOLD);
758	outb(port + MSE_PORTA, MSE_INPORT_STATUS);
759	*but = ~inb(port + MSE_PORTB) & MOUSE_MSC_BUTTONS;
760	outb(port + MSE_PORTA, MSE_INPORT_DX);
761	byte = inb(port + MSE_PORTB);
762	*dx = byte;
763	outb(port + MSE_PORTA, MSE_INPORT_DY);
764	byte = inb(port + MSE_PORTB);
765	*dy = byte;
766	outb(port + MSE_PORTA, MSE_INPORT_MODE);
767	outb(port + MSE_PORTB, MSE_INPORT_INTREN);
768}
769
770static mse_devsw_installed = 0;
771
772static void 	mse_drvinit(void *unused)
773{
774	dev_t dev;
775
776	if( ! mse_devsw_installed ) {
777		dev = makedev(CDEV_MAJOR, 0);
778		cdevsw_add(&dev,&mse_cdevsw, NULL);
779		mse_devsw_installed = 1;
780    	}
781}
782
783SYSINIT(msedev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mse_drvinit,NULL)
784
785
786#endif /* NMSE */
787