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