mse.c revision 58229
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 *
1450477Speter * $FreeBSD: head/sys/dev/mse/mse.c 58229 2000-03-18 15:13:30Z yokota $
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
472056Swollman#include <sys/param.h>
483745Swollman#include <sys/systm.h>
4912658Sbde#include <sys/conf.h>
502056Swollman#include <sys/kernel.h>
5158229Syokota#include <sys/bus.h>
5229368Speter#include <sys/poll.h>
5331254Sbde#include <sys/select.h>
542056Swollman#include <sys/uio.h>
55637Snate
5658229Syokota#include <machine/bus_pio.h>
5758229Syokota#include <machine/bus.h>
587430Sbde#include <machine/clock.h>
5931603Syokota#include <machine/mouse.h>
6058229Syokota#include <machine/resource.h>
6158229Syokota#include <sys/rman.h>
627430Sbde
6358229Syokota#include <isa/isavar.h>
64637Snate
6531603Syokota/* driver configuration flags (config) */
6631603Syokota#define MSE_CONFIG_ACCEL	0x00f0  /* acceleration factor */
6731603Syokota#define MSE_CONFIG_FLAGS	(MSE_CONFIG_ACCEL)
6831603Syokota
6958229Syokota/*
7058229Syokota * Software control structure for mouse. The sc_enablemouse(),
7158229Syokota * sc_disablemouse() and sc_getmouse() routines must be called spl'd().
7258229Syokota */
7358229Syokotatypedef struct mse_softc {
7458229Syokota	int		sc_flags;
7558229Syokota	int		sc_mousetype;
7658229Syokota	struct selinfo	sc_selp;
7758229Syokota	struct resource	*sc_port;
7858229Syokota	struct resource	*sc_intr;
7958229Syokota	bus_space_tag_t	sc_iot;
8058229Syokota	bus_space_handle_t sc_ioh;
8158229Syokota	void		*sc_ih;
8258229Syokota	void		(*sc_enablemouse) __P((bus_space_tag_t t,
8358229Syokota					       bus_space_handle_t h));
8458229Syokota	void		(*sc_disablemouse) __P((bus_space_tag_t t,
8558229Syokota						bus_space_handle_t h));
8658229Syokota	void		(*sc_getmouse) __P((bus_space_tag_t t,
8758229Syokota					    bus_space_handle_t h,
8858229Syokota					    int *dx, int *dy, int *but));
8958229Syokota	int		sc_deltax;
9058229Syokota	int		sc_deltay;
9158229Syokota	int		sc_obuttons;
9258229Syokota	int		sc_buttons;
9358229Syokota	int		sc_bytesread;
9458229Syokota	u_char		sc_bytes[MOUSE_SYS_PACKETSIZE];
9558229Syokota	struct		callout_handle sc_callout;
9658229Syokota	int		sc_watchdog;
9758229Syokota	dev_t		sc_dev;
9858229Syokota	dev_t		sc_ndev;
9958229Syokota	mousehw_t	hw;
10058229Syokota	mousemode_t	mode;
10158229Syokota	mousestatus_t	status;
10258229Syokota} mse_softc_t;
103637Snate
10458229Syokotastatic	devclass_t	mse_devclass;
10558229Syokota
10658229Syokotastatic	int		mse_probe __P((device_t dev));
10758229Syokotastatic	int		mse_attach __P((device_t dev));
10858229Syokotastatic	int		mse_detach __P((device_t dev));
10958229Syokota
11058229Syokotastatic	device_method_t	mse_methods[] = {
11158229Syokota	DEVMETHOD(device_probe,		mse_probe),
11258229Syokota	DEVMETHOD(device_attach,	mse_attach),
11358229Syokota	DEVMETHOD(device_detach,	mse_detach),
11458229Syokota	{ 0, 0 }
115637Snate};
116637Snate
11758229Syokotastatic	driver_t	mse_driver = {
11858229Syokota	"mse",
11958229Syokota	mse_methods,
12058229Syokota	sizeof(mse_softc_t),
12158229Syokota};
12258229Syokota
12358229SyokotaDRIVER_MODULE(mse, isa, mse_driver, mse_devclass, 0, 0);
12458229Syokota
12558229Syokotastatic struct isa_pnp_id mse_ids[] = {
12658229Syokota	{ 0x000fd041, "Bus mouse" },			/* PNP0F00 */
12758229Syokota	{ 0x020fd041, "InPort mouse" },			/* PNP0F02 */
12858229Syokota	{ 0x0d0fd041, "InPort mouse compatible" },	/* PNP0F0D */
12958229Syokota	{ 0x110fd041, "Bus mouse compatible" },		/* PNP0F11 */
13058229Syokota	{ 0x150fd041, "Logitech bus mouse" },		/* PNP0F15 */
13158229Syokota	{ 0x180fd041, "Logitech bus mouse compatible" },/* PNP0F18 */
13258229Syokota	{ 0 }
13358229Syokota};
13458229Syokota
13512675Sjulianstatic	d_open_t	mseopen;
13612675Sjulianstatic	d_close_t	mseclose;
13712675Sjulianstatic	d_read_t	mseread;
13831603Syokotastatic  d_ioctl_t	mseioctl;
13929368Speterstatic	d_poll_t	msepoll;
14012675Sjulian
14112675Sjulian#define CDEV_MAJOR 27
14247625Sphkstatic struct cdevsw mse_cdevsw = {
14347625Sphk	/* open */	mseopen,
14447625Sphk	/* close */	mseclose,
14547625Sphk	/* read */	mseread,
14647625Sphk	/* write */	nowrite,
14747625Sphk	/* ioctl */	mseioctl,
14847625Sphk	/* poll */	msepoll,
14947625Sphk	/* mmap */	nommap,
15047625Sphk	/* strategy */	nostrategy,
15147625Sphk	/* name */	"mse",
15247625Sphk	/* maj */	CDEV_MAJOR,
15347625Sphk	/* dump */	nodump,
15447625Sphk	/* psize */	nopsize,
15547625Sphk	/* flags */	0,
15647625Sphk	/* bmaj */	-1
15747625Sphk};
15812675Sjulian
15958229Syokotastatic	void		mseintr __P((void *));
16058229Syokotastatic	timeout_t	msetimeout;
16112675Sjulian
162637Snate/* Flags */
163637Snate#define	MSESC_OPEN	0x1
164637Snate#define	MSESC_WANT	0x2
165637Snate
166637Snate/* and Mouse Types */
16720688Sjoerg#define	MSE_NONE	0	/* don't move this! */
168637Snate#define	MSE_LOGITECH	0x1
169637Snate#define	MSE_ATIINPORT	0x2
1704259Sjkh#define	MSE_LOGI_SIG	0xA5
171637Snate
172637Snate#define	MSE_PORTA	0
173637Snate#define	MSE_PORTB	1
174637Snate#define	MSE_PORTC	2
175637Snate#define	MSE_PORTD	3
17658229Syokota#define MSE_IOSIZE	4
177637Snate
178637Snate#define	MSE_UNIT(dev)		(minor(dev) >> 1)
179637Snate#define	MSE_NBLOCKIO(dev)	(minor(dev) & 0x1)
180637Snate
181637Snate/*
182637Snate * Logitech bus mouse definitions
183637Snate */
184637Snate#define	MSE_SETUP	0x91	/* What does this mean? */
1854259Sjkh				/* The definition for the control port */
1864259Sjkh				/* is as follows: */
1878876Srgrimes
1884259Sjkh				/* D7 	 =  Mode set flag (1 = active) 	*/
1898876Srgrimes				/* D6,D5 =  Mode selection (port A) 	*/
1904259Sjkh				/* 	    00 = Mode 0 = Basic I/O 	*/
1914259Sjkh				/* 	    01 = Mode 1 = Strobed I/O 	*/
1924259Sjkh				/* 	    10 = Mode 2 = Bi-dir bus 	*/
1934259Sjkh				/* D4	 =  Port A direction (1 = input)*/
1944259Sjkh				/* D3	 =  Port C (upper 4 bits) 	*/
1954259Sjkh				/*	    direction. (1 = input)	*/
1964259Sjkh				/* D2	 =  Mode selection (port B & C) */
1974259Sjkh				/*	    0 = Mode 0 = Basic I/O	*/
1984259Sjkh				/*	    1 = Mode 1 = Strobed I/O	*/
1994259Sjkh				/* D1	 =  Port B direction (1 = input)*/
2004259Sjkh				/* D0	 =  Port C (lower 4 bits)	*/
2014259Sjkh				/*	    direction. (1 = input)	*/
2028876Srgrimes
2034259Sjkh				/* So 91 means Basic I/O on all 3 ports,*/
2044259Sjkh				/* Port A is an input port, B is an 	*/
2054259Sjkh				/* output port, C is split with upper	*/
2064259Sjkh				/* 4 bits being an output port and lower*/
2074259Sjkh				/* 4 bits an input port, and enable the */
2084259Sjkh				/* sucker.				*/
2094259Sjkh				/* Courtesy Intel 8255 databook. Lars   */
210637Snate#define	MSE_HOLD	0x80
211637Snate#define	MSE_RXLOW	0x00
212637Snate#define	MSE_RXHIGH	0x20
213637Snate#define	MSE_RYLOW	0x40
214637Snate#define	MSE_RYHIGH	0x60
215637Snate#define	MSE_DISINTR	0x10
216637Snate#define MSE_INTREN	0x00
217637Snate
21858229Syokotastatic	int		mse_probelogi __P((device_t dev, mse_softc_t *sc));
21958229Syokotastatic	void		mse_disablelogi __P((bus_space_tag_t t,
22058229Syokota					     bus_space_handle_t h));
22158229Syokotastatic	void		mse_getlogi __P((bus_space_tag_t t,
22258229Syokota					 bus_space_handle_t h,
22358229Syokota					 int *dx, int *dy, int *but));
22458229Syokotastatic	void		mse_enablelogi __P((bus_space_tag_t t,
22558229Syokota					    bus_space_handle_t h));
226637Snate
227637Snate/*
228637Snate * ATI Inport mouse definitions
229637Snate */
230637Snate#define	MSE_INPORT_RESET	0x80
231637Snate#define	MSE_INPORT_STATUS	0x00
232637Snate#define	MSE_INPORT_DX		0x01
233637Snate#define	MSE_INPORT_DY		0x02
234637Snate#define	MSE_INPORT_MODE		0x07
235637Snate#define	MSE_INPORT_HOLD		0x20
236637Snate#define	MSE_INPORT_INTREN	0x09
237637Snate
23858229Syokotastatic	int		mse_probeati __P((device_t dev, mse_softc_t *sc));
23958229Syokotastatic	void		mse_enableati __P((bus_space_tag_t t,
24058229Syokota					   bus_space_handle_t h));
24158229Syokotastatic	void		mse_disableati __P((bus_space_tag_t t,
24258229Syokota					    bus_space_handle_t h));
24358229Syokotastatic	void		mse_getati __P((bus_space_tag_t t,
24458229Syokota					bus_space_handle_t h,
24558229Syokota					int *dx, int *dy, int *but));
246637Snate
247637Snate#define	MSEPRI	(PZERO + 3)
248637Snate
249637Snate/*
250637Snate * Table of mouse types.
251637Snate * Keep the Logitech last, since I haven't figured out how to probe it
252637Snate * properly yet. (Someday I'll have the documentation.)
253637Snate */
25412724Sphkstatic struct mse_types {
255637Snate	int	m_type;		/* Type of bus mouse */
25658229Syokota	int	(*m_probe) __P((device_t dev, mse_softc_t *sc));
25712854Sbde				/* Probe routine to test for it */
25858229Syokota	void	(*m_enable) __P((bus_space_tag_t t, bus_space_handle_t h));
25912854Sbde				/* Start routine */
26058229Syokota	void	(*m_disable) __P((bus_space_tag_t t, bus_space_handle_t h));
26112854Sbde				/* Disable interrupts routine */
26258229Syokota	void	(*m_get) __P((bus_space_tag_t t, bus_space_handle_t h,
26358229Syokota			      int *dx, int *dy, int *but));
26412854Sbde				/* and get mouse status */
26531603Syokota	mousehw_t   m_hw;	/* buttons iftype type model hwid */
26631603Syokota	mousemode_t m_mode;	/* proto rate res accel level size mask */
267637Snate} mse_types[] = {
26831603Syokota	{ MSE_ATIINPORT,
26931603Syokota	  mse_probeati, mse_enableati, mse_disableati, mse_getati,
27031603Syokota	  { 2, MOUSE_IF_INPORT, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, },
27131603Syokota	  { MOUSE_PROTO_INPORT, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE,
27231603Syokota	    { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, },
27331603Syokota	{ MSE_LOGITECH,
27431603Syokota	  mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi,
27531603Syokota	  { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, },
27631603Syokota	  { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE,
27731603Syokota	    { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, },
278637Snate	{ 0, },
279637Snate};
280637Snate
28158229Syokotastatic	int
28258229Syokotamse_probe(dev)
28358229Syokota	device_t dev;
284637Snate{
28558229Syokota	mse_softc_t *sc;
28658229Syokota	int error;
28758229Syokota	int rid;
28858229Syokota	int i;
289637Snate
29058229Syokota	/* check PnP IDs */
29158229Syokota	error = ISA_PNP_PROBE(device_get_parent(dev), dev, mse_ids);
29258229Syokota	if (error == ENXIO)
29358229Syokota		return ENXIO;
29458229Syokota
29558229Syokota	sc = device_get_softc(dev);
29658229Syokota	rid = 0;
29758229Syokota	sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
29858229Syokota					 MSE_IOSIZE, RF_ACTIVE);
29958229Syokota	if (sc->sc_port == NULL)
30058229Syokota		return ENXIO;
30158229Syokota	sc->sc_iot = rman_get_bustag(sc->sc_port);
30258229Syokota	sc->sc_ioh = rman_get_bushandle(sc->sc_port);
30358229Syokota
304637Snate	/*
305637Snate	 * Check for each mouse type in the table.
306637Snate	 */
307637Snate	i = 0;
308637Snate	while (mse_types[i].m_type) {
30958229Syokota		if ((*mse_types[i].m_probe)(dev, sc)) {
310637Snate			sc->sc_mousetype = mse_types[i].m_type;
311637Snate			sc->sc_enablemouse = mse_types[i].m_enable;
312637Snate			sc->sc_disablemouse = mse_types[i].m_disable;
313637Snate			sc->sc_getmouse = mse_types[i].m_get;
31431603Syokota			sc->hw = mse_types[i].m_hw;
31531603Syokota			sc->mode = mse_types[i].m_mode;
31658229Syokota			bus_release_resource(dev, SYS_RES_IOPORT, rid,
31758229Syokota					     sc->sc_port);
31858229Syokota			device_set_desc(dev, "Bus/InPort Mouse");
31958229Syokota			return 0;
320637Snate		}
321637Snate		i++;
322637Snate	}
32358229Syokota	bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
32458229Syokota	return ENXIO;
325637Snate}
326637Snate
32758229Syokotastatic	int
32858229Syokotamse_attach(dev)
32958229Syokota	device_t dev;
330637Snate{
33158229Syokota	mse_softc_t *sc;
33258229Syokota	int flags;
33358229Syokota	int unit;
33458229Syokota	int rid;
335637Snate
33658229Syokota	sc = device_get_softc(dev);
33758229Syokota	unit = device_get_unit(dev);
33858229Syokota
33958229Syokota	rid = 0;
34058229Syokota	sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
34158229Syokota					 MSE_IOSIZE, RF_ACTIVE);
34258229Syokota	if (sc->sc_port == NULL)
34358229Syokota		return ENXIO;
34458229Syokota	sc->sc_intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
34558229Syokota					 RF_ACTIVE);
34658229Syokota	if (sc->sc_intr == NULL) {
34758229Syokota		bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
34858229Syokota		return ENXIO;
34958229Syokota	}
35058229Syokota	sc->sc_iot = rman_get_bustag(sc->sc_port);
35158229Syokota	sc->sc_ioh = rman_get_bushandle(sc->sc_port);
35258229Syokota
35358229Syokota	if (BUS_SETUP_INTR(device_get_parent(dev), dev, sc->sc_intr,
35458229Syokota			   INTR_TYPE_TTY, mseintr, sc, &sc->sc_ih)) {
35558229Syokota		bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
35658229Syokota		bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr);
35758229Syokota		return ENXIO;
35858229Syokota	}
35958229Syokota
36058229Syokota	flags = device_get_flags(dev);
36158229Syokota	sc->mode.accelfactor = (flags & MSE_CONFIG_ACCEL) >> 4;
36258229Syokota	callout_handle_init(&sc->sc_callout);
36358229Syokota
36458229Syokota	sc->sc_dev = make_dev(&mse_cdevsw, unit << 1, 0, 0, 0600,
36558229Syokota			      "mse%d", unit);
36658229Syokota	sc->sc_ndev = make_dev(&mse_cdevsw, (unit<<1)+1, 0, 0, 0600,
36758229Syokota			       "nmse%d", unit);
36858229Syokota
36958229Syokota	return 0;
370637Snate}
371637Snate
37258229Syokotastatic	int
37358229Syokotamse_detach(dev)
37458229Syokota	device_t dev;
37558229Syokota{
37658229Syokota	mse_softc_t *sc;
37758229Syokota	int rid;
37858229Syokota
37958229Syokota	sc = device_get_softc(dev);
38058229Syokota	if (sc->sc_flags & MSESC_OPEN)
38158229Syokota		return EBUSY;
38258229Syokota
38358229Syokota	rid = 0;
38458229Syokota	BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->sc_intr, sc->sc_ih);
38558229Syokota	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr);
38658229Syokota	bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
38758229Syokota
38858229Syokota	destroy_dev(sc->sc_dev);
38958229Syokota	destroy_dev(sc->sc_ndev);
39058229Syokota
39158229Syokota	return 0;
39258229Syokota}
39358229Syokota
394637Snate/*
395637Snate * Exclusive open the mouse, initialize it and enable interrupts.
396637Snate */
39712675Sjulianstatic	int
39810624Sbdemseopen(dev, flags, fmt, p)
399637Snate	dev_t dev;
40010624Sbde	int flags;
40110624Sbde	int fmt;
40210624Sbde	struct proc *p;
403637Snate{
40458229Syokota	mse_softc_t *sc;
405637Snate	int s;
406637Snate
40758229Syokota	sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
40858229Syokota	if (sc == NULL)
409637Snate		return (ENXIO);
41020688Sjoerg	if (sc->sc_mousetype == MSE_NONE)
41120688Sjoerg		return (ENXIO);
412637Snate	if (sc->sc_flags & MSESC_OPEN)
413637Snate		return (EBUSY);
414637Snate	sc->sc_flags |= MSESC_OPEN;
41531603Syokota	sc->sc_obuttons = sc->sc_buttons = MOUSE_MSC_BUTTONS;
416637Snate	sc->sc_deltax = sc->sc_deltay = 0;
41731603Syokota	sc->sc_bytesread = sc->mode.packetsize = MOUSE_MSC_PACKETSIZE;
41858229Syokota	sc->sc_watchdog = FALSE;
41958229Syokota	sc->sc_callout = timeout(msetimeout, dev, hz*2);
42031603Syokota	sc->mode.level = 0;
42131603Syokota	sc->status.flags = 0;
42231603Syokota	sc->status.button = sc->status.obutton = 0;
42331603Syokota	sc->status.dx = sc->status.dy = sc->status.dz = 0;
424637Snate
425637Snate	/*
426637Snate	 * Initialize mouse interface and enable interrupts.
427637Snate	 */
428637Snate	s = spltty();
42958229Syokota	(*sc->sc_enablemouse)(sc->sc_iot, sc->sc_ioh);
430637Snate	splx(s);
431637Snate	return (0);
432637Snate}
433637Snate
434637Snate/*
435637Snate * mseclose: just turn off mouse innterrupts.
436637Snate */
43712675Sjulianstatic	int
43810624Sbdemseclose(dev, flags, fmt, p)
439798Swollman	dev_t dev;
44010624Sbde	int flags;
44110624Sbde	int fmt;
44210624Sbde	struct proc *p;
443637Snate{
44458229Syokota	mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
445637Snate	int s;
446637Snate
44758229Syokota	untimeout(msetimeout, dev, sc->sc_callout);
44858229Syokota	callout_handle_init(&sc->sc_callout);
449637Snate	s = spltty();
45058229Syokota	(*sc->sc_disablemouse)(sc->sc_iot, sc->sc_ioh);
451637Snate	sc->sc_flags &= ~MSESC_OPEN;
452637Snate	splx(s);
453637Snate	return(0);
454637Snate}
455637Snate
4568876Srgrimes/*
457637Snate * mseread: return mouse info using the MSC serial protocol, but without
458637Snate * using bytes 4 and 5.
459637Snate * (Yes this is cheesy, but it makes the X386 server happy, so...)
460637Snate */
46112675Sjulianstatic	int
46210624Sbdemseread(dev, uio, ioflag)
463637Snate	dev_t dev;
464637Snate	struct uio *uio;
46510624Sbde	int ioflag;
466637Snate{
46758229Syokota	mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
468637Snate	int xfer, s, error;
469637Snate
470637Snate	/*
471637Snate	 * If there are no protocol bytes to be read, set up a new protocol
472637Snate	 * packet.
473637Snate	 */
474637Snate	s = spltty(); /* XXX Should be its own spl, but where is imlXX() */
47531603Syokota	if (sc->sc_bytesread >= sc->mode.packetsize) {
476637Snate		while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
477637Snate		       (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
478637Snate			if (MSE_NBLOCKIO(dev)) {
479637Snate				splx(s);
480637Snate				return (0);
481637Snate			}
482637Snate			sc->sc_flags |= MSESC_WANT;
48346571Speter			error = tsleep((caddr_t)sc, MSEPRI | PCATCH,
48446571Speter				"mseread", 0);
48546571Speter			if (error) {
486637Snate				splx(s);
487637Snate				return (error);
488637Snate			}
489637Snate		}
490637Snate
491637Snate		/*
492637Snate		 * Generate protocol bytes.
493637Snate		 * For some reason X386 expects 5 bytes but never uses
494637Snate		 * the fourth or fifth?
495637Snate		 */
49631603Syokota		sc->sc_bytes[0] = sc->mode.syncmask[1]
49731603Syokota		    | (sc->sc_buttons & ~sc->mode.syncmask[0]);
498637Snate		if (sc->sc_deltax > 127)
499637Snate			sc->sc_deltax = 127;
500637Snate		if (sc->sc_deltax < -127)
501637Snate			sc->sc_deltax = -127;
502637Snate		sc->sc_deltay = -sc->sc_deltay;	/* Otherwise mousey goes wrong way */
503637Snate		if (sc->sc_deltay > 127)
504637Snate			sc->sc_deltay = 127;
505637Snate		if (sc->sc_deltay < -127)
506637Snate			sc->sc_deltay = -127;
507637Snate		sc->sc_bytes[1] = sc->sc_deltax;
508637Snate		sc->sc_bytes[2] = sc->sc_deltay;
509637Snate		sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
51031603Syokota		sc->sc_bytes[5] = sc->sc_bytes[6] = 0;
51131603Syokota		sc->sc_bytes[7] = MOUSE_SYS_EXTBUTTONS;
512637Snate		sc->sc_obuttons = sc->sc_buttons;
513637Snate		sc->sc_deltax = sc->sc_deltay = 0;
514637Snate		sc->sc_bytesread = 0;
515637Snate	}
516637Snate	splx(s);
51731603Syokota	xfer = min(uio->uio_resid, sc->mode.packetsize - sc->sc_bytesread);
51846571Speter	error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio);
51946571Speter	if (error)
520637Snate		return (error);
521637Snate	sc->sc_bytesread += xfer;
522637Snate	return(0);
523637Snate}
524637Snate
525637Snate/*
52631603Syokota * mseioctl: process ioctl commands.
52731603Syokota */
52831603Syokotastatic int
52931603Syokotamseioctl(dev, cmd, addr, flag, p)
53031603Syokota	dev_t dev;
53136735Sdfr	u_long cmd;
53231603Syokota	caddr_t addr;
53331603Syokota	int flag;
53431603Syokota	struct proc *p;
53531603Syokota{
53658229Syokota	mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
53731603Syokota	mousestatus_t status;
53831603Syokota	int err = 0;
53931603Syokota	int s;
54031603Syokota
54131603Syokota	switch (cmd) {
54231603Syokota
54331603Syokota	case MOUSE_GETHWINFO:
54431603Syokota		s = spltty();
54531603Syokota		*(mousehw_t *)addr = sc->hw;
54631603Syokota		if (sc->mode.level == 0)
54731603Syokota			((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
54831603Syokota		splx(s);
54931603Syokota		break;
55031603Syokota
55131603Syokota	case MOUSE_GETMODE:
55231603Syokota		s = spltty();
55331603Syokota		*(mousemode_t *)addr = sc->mode;
55431603Syokota		switch (sc->mode.level) {
55531603Syokota		case 0:
55631603Syokota			break;
55731603Syokota		case 1:
55831603Syokota			((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
55931603Syokota	    		((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
56031603Syokota	    		((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
56131603Syokota			break;
56231603Syokota		}
56331603Syokota		splx(s);
56431603Syokota		break;
56531603Syokota
56631603Syokota	case MOUSE_SETMODE:
56731603Syokota		switch (((mousemode_t *)addr)->level) {
56831603Syokota		case 0:
56931603Syokota		case 1:
57031603Syokota			break;
57131603Syokota		default:
57231603Syokota			return (EINVAL);
57331603Syokota		}
57431603Syokota		if (((mousemode_t *)addr)->accelfactor < -1)
57531603Syokota			return (EINVAL);
57631603Syokota		else if (((mousemode_t *)addr)->accelfactor >= 0)
57731603Syokota			sc->mode.accelfactor =
57831603Syokota			    ((mousemode_t *)addr)->accelfactor;
57931603Syokota		sc->mode.level = ((mousemode_t *)addr)->level;
58031603Syokota		switch (sc->mode.level) {
58131603Syokota		case 0:
58231603Syokota			sc->sc_bytesread = sc->mode.packetsize
58331603Syokota			    = MOUSE_MSC_PACKETSIZE;
58431603Syokota			break;
58531603Syokota		case 1:
58631603Syokota			sc->sc_bytesread = sc->mode.packetsize
58731603Syokota			    = MOUSE_SYS_PACKETSIZE;
58831603Syokota			break;
58931603Syokota		}
59031603Syokota		break;
59131603Syokota
59231603Syokota	case MOUSE_GETLEVEL:
59331603Syokota		*(int *)addr = sc->mode.level;
59431603Syokota		break;
59531603Syokota
59631603Syokota	case MOUSE_SETLEVEL:
59731603Syokota		switch (*(int *)addr) {
59831603Syokota		case 0:
59931603Syokota			sc->mode.level = *(int *)addr;
60031603Syokota			sc->sc_bytesread = sc->mode.packetsize
60131603Syokota			    = MOUSE_MSC_PACKETSIZE;
60231603Syokota			break;
60331603Syokota		case 1:
60431603Syokota			sc->mode.level = *(int *)addr;
60531603Syokota			sc->sc_bytesread = sc->mode.packetsize
60631603Syokota			    = MOUSE_SYS_PACKETSIZE;
60731603Syokota			break;
60831603Syokota		default:
60931603Syokota			return (EINVAL);
61031603Syokota		}
61131603Syokota		break;
61231603Syokota
61331603Syokota	case MOUSE_GETSTATUS:
61431603Syokota		s = spltty();
61531603Syokota		status = sc->status;
61631603Syokota		sc->status.flags = 0;
61731603Syokota		sc->status.obutton = sc->status.button;
61831603Syokota		sc->status.button = 0;
61931603Syokota		sc->status.dx = 0;
62031603Syokota		sc->status.dy = 0;
62131603Syokota		sc->status.dz = 0;
62231603Syokota		splx(s);
62331603Syokota		*(mousestatus_t *)addr = status;
62431603Syokota		break;
62531603Syokota
62631603Syokota	case MOUSE_READSTATE:
62731603Syokota	case MOUSE_READDATA:
62831603Syokota		return (ENODEV);
62931603Syokota
63031603Syokota#if (defined(MOUSE_GETVARS))
63131603Syokota	case MOUSE_GETVARS:
63231603Syokota	case MOUSE_SETVARS:
63331603Syokota		return (ENODEV);
63431603Syokota#endif
63531603Syokota
63631603Syokota	default:
63731603Syokota		return (ENOTTY);
63831603Syokota	}
63931603Syokota	return (err);
64031603Syokota}
64131603Syokota
64231603Syokota/*
64329368Speter * msepoll: check for mouse input to be processed.
644637Snate */
64512675Sjulianstatic	int
64629368Spetermsepoll(dev, events, p)
647637Snate	dev_t dev;
64829368Speter	int events;
649637Snate	struct proc *p;
650637Snate{
65158229Syokota	mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
652637Snate	int s;
65329368Speter	int revents = 0;
654637Snate
655637Snate	s = spltty();
65646568Speter	if (events & (POLLIN | POLLRDNORM)) {
65731603Syokota		if (sc->sc_bytesread != sc->mode.packetsize ||
65831603Syokota		    sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
65929368Speter		    (sc->sc_obuttons ^ sc->sc_buttons) != 0)
66029368Speter			revents |= events & (POLLIN | POLLRDNORM);
66129368Speter		else {
66229368Speter			/*
66329368Speter			 * Since this is an exclusive open device, any previous
66429368Speter			 * proc pointer is trash now, so we can just assign it.
66529368Speter			 */
66629368Speter			selrecord(p, &sc->sc_selp);
66729368Speter		}
66846568Speter	}
669637Snate	splx(s);
67029368Speter	return (revents);
671637Snate}
672637Snate
673637Snate/*
67458229Syokota * msetimeout: watchdog timer routine.
67558229Syokota */
67658229Syokotastatic void
67758229Syokotamsetimeout(arg)
67858229Syokota	void *arg;
67958229Syokota{
68058229Syokota	dev_t dev;
68158229Syokota	mse_softc_t *sc;
68258229Syokota
68358229Syokota	dev = (dev_t)arg;
68458229Syokota	sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
68558229Syokota	if (sc->sc_watchdog) {
68658229Syokota		if (bootverbose)
68758229Syokota			printf("mse%d: lost interrupt?\n", MSE_UNIT(dev));
68858229Syokota		mseintr(sc);
68958229Syokota	}
69058229Syokota	sc->sc_watchdog = TRUE;
69158229Syokota	sc->sc_callout = timeout(msetimeout, dev, hz);
69258229Syokota}
69358229Syokota
69458229Syokota/*
695637Snate * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
696637Snate */
69740565Sbdestatic void
69858229Syokotamseintr(arg)
69958229Syokota	void *arg;
700637Snate{
70131603Syokota	/*
70231603Syokota	 * the table to turn MouseSystem button bits (MOUSE_MSC_BUTTON?UP)
70331603Syokota	 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
70431603Syokota	 */
70531603Syokota	static int butmap[8] = {
70631603Syokota		0,
70731603Syokota		MOUSE_BUTTON3DOWN,
70831603Syokota		MOUSE_BUTTON2DOWN,
70931603Syokota		MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
71031603Syokota		MOUSE_BUTTON1DOWN,
71131603Syokota		MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
71231603Syokota		MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
71331603Syokota        	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
71431603Syokota	};
71558229Syokota	mse_softc_t *sc = arg;
71631603Syokota	int dx, dy, but;
71731603Syokota	int sign;
718637Snate
719637Snate#ifdef DEBUG
720637Snate	static int mse_intrcnt = 0;
721637Snate	if((mse_intrcnt++ % 10000) == 0)
722637Snate		printf("mseintr\n");
723637Snate#endif /* DEBUG */
724637Snate	if ((sc->sc_flags & MSESC_OPEN) == 0)
725637Snate		return;
726637Snate
72758229Syokota	(*sc->sc_getmouse)(sc->sc_iot, sc->sc_ioh, &dx, &dy, &but);
72831603Syokota	if (sc->mode.accelfactor > 0) {
72931603Syokota		sign = (dx < 0);
73031603Syokota		dx = dx * dx / sc->mode.accelfactor;
73131603Syokota		if (dx == 0)
73231603Syokota			dx = 1;
73331603Syokota		if (sign)
73431603Syokota			dx = -dx;
73531603Syokota		sign = (dy < 0);
73631603Syokota		dy = dy * dy / sc->mode.accelfactor;
73731603Syokota		if (dy == 0)
73831603Syokota			dy = 1;
73931603Syokota		if (sign)
74031603Syokota			dy = -dy;
74131603Syokota	}
74231603Syokota	sc->sc_deltax += dx;
74331603Syokota	sc->sc_deltay += dy;
74431603Syokota	sc->sc_buttons = but;
745637Snate
74631603Syokota	but = butmap[~but & MOUSE_MSC_BUTTONS];
74731603Syokota	sc->status.dx += dx;
74831603Syokota	sc->status.dy += dy;
74931603Syokota	sc->status.flags |= ((dx || dy) ? MOUSE_POSCHANGED : 0)
75031603Syokota	    | (sc->status.button ^ but);
75131603Syokota	sc->status.button = but;
75231603Syokota
75358229Syokota	sc->sc_watchdog = FALSE;
75458229Syokota
755637Snate	/*
756637Snate	 * If mouse state has changed, wake up anyone wanting to know.
757637Snate	 */
758637Snate	if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
759637Snate	    (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
7608876Srgrimes		if (sc->sc_flags & MSESC_WANT) {
7618876Srgrimes			sc->sc_flags &= ~MSESC_WANT;
7628876Srgrimes			wakeup((caddr_t)sc);
7638876Srgrimes		}
7641549Srgrimes		selwakeup(&sc->sc_selp);
765637Snate	}
766637Snate}
767637Snate
768637Snate/*
769637Snate * Routines for the Logitech mouse.
770637Snate */
771637Snate/*
772637Snate * Test for a Logitech bus mouse and return 1 if it is.
773637Snate * (until I know how to use the signature port properly, just disable
774637Snate *  interrupts and return 1)
775637Snate */
776637Snatestatic int
77758229Syokotamse_probelogi(dev, sc)
77858229Syokota	device_t dev;
77958229Syokota	mse_softc_t *sc;
780637Snate{
781637Snate
7824259Sjkh	int sig;
7834259Sjkh
78458229Syokota	bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTD, MSE_SETUP);
7854259Sjkh		/* set the signature port */
78658229Syokota	bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB, MSE_LOGI_SIG);
7874259Sjkh
7884259Sjkh	DELAY(30000); /* 30 ms delay */
78958229Syokota	sig = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB) & 0xFF;
7904259Sjkh	if (sig == MSE_LOGI_SIG) {
79158229Syokota		bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC,
79258229Syokota				  MSE_DISINTR);
7934259Sjkh		return(1);
7944259Sjkh	} else {
79516074Sjoerg		if (bootverbose)
79658229Syokota			device_printf(dev, "wrong signature %x\n", sig);
7974259Sjkh		return(0);
798637Snate	}
799637Snate}
800637Snate
801637Snate/*
802637Snate * Initialize Logitech mouse and enable interrupts.
803637Snate */
804637Snatestatic void
80558229Syokotamse_enablelogi(tag, handle)
80658229Syokota	bus_space_tag_t tag;
80758229Syokota	bus_space_handle_t handle;
808637Snate{
809637Snate	int dx, dy, but;
810637Snate
81158229Syokota	bus_space_write_1(tag, handle, MSE_PORTD, MSE_SETUP);
81258229Syokota	mse_getlogi(tag, handle, &dx, &dy, &but);
813637Snate}
814637Snate
815637Snate/*
816637Snate * Disable interrupts for Logitech mouse.
817637Snate */
818637Snatestatic void
81958229Syokotamse_disablelogi(tag, handle)
82058229Syokota	bus_space_tag_t tag;
82158229Syokota	bus_space_handle_t handle;
822637Snate{
823637Snate
82458229Syokota	bus_space_write_1(tag, handle, MSE_PORTC, MSE_DISINTR);
825637Snate}
826637Snate
827637Snate/*
828637Snate * Get the current dx, dy and button up/down state.
829637Snate */
830637Snatestatic void
83158229Syokotamse_getlogi(tag, handle, dx, dy, but)
83258229Syokota	bus_space_tag_t tag;
83358229Syokota	bus_space_handle_t handle;
834637Snate	int *dx;
835637Snate	int *dy;
836637Snate	int *but;
837637Snate{
838637Snate	register char x, y;
839637Snate
84058229Syokota	bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXLOW);
84158229Syokota	x = bus_space_read_1(tag, handle, MSE_PORTA);
84231603Syokota	*but = (x >> 5) & MOUSE_MSC_BUTTONS;
843637Snate	x &= 0xf;
84458229Syokota	bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXHIGH);
84558229Syokota	x |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4);
84658229Syokota	bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYLOW);
84758229Syokota	y = (bus_space_read_1(tag, handle, MSE_PORTA) & 0xf);
84858229Syokota	bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYHIGH);
84958229Syokota	y |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4);
85031603Syokota	*dx = x;
85131603Syokota	*dy = y;
85258229Syokota	bus_space_write_1(tag, handle, MSE_PORTC, MSE_INTREN);
853637Snate}
854637Snate
855637Snate/*
856637Snate * Routines for the ATI Inport bus mouse.
857637Snate */
858637Snate/*
859637Snate * Test for a ATI Inport bus mouse and return 1 if it is.
860637Snate * (do not enable interrupts)
861637Snate */
862637Snatestatic int
86358229Syokotamse_probeati(dev, sc)
86458229Syokota	device_t dev;
86558229Syokota	mse_softc_t *sc;
866637Snate{
867637Snate	int i;
868637Snate
869637Snate	for (i = 0; i < 2; i++)
87058229Syokota		if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC) == 0xde)
871637Snate			return (1);
872637Snate	return (0);
873637Snate}
874637Snate
875637Snate/*
876637Snate * Initialize ATI Inport mouse and enable interrupts.
877637Snate */
878637Snatestatic void
87958229Syokotamse_enableati(tag, handle)
88058229Syokota	bus_space_tag_t tag;
88158229Syokota	bus_space_handle_t handle;
882637Snate{
883637Snate
88458229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_RESET);
88558229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE);
88658229Syokota	bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN);
887637Snate}
888637Snate
889637Snate/*
890637Snate * Disable interrupts for ATI Inport mouse.
891637Snate */
892637Snatestatic void
89358229Syokotamse_disableati(tag, handle)
89458229Syokota	bus_space_tag_t tag;
89558229Syokota	bus_space_handle_t handle;
896637Snate{
897637Snate
89858229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE);
89958229Syokota	bus_space_write_1(tag, handle, MSE_PORTB, 0);
900637Snate}
901637Snate
902637Snate/*
903637Snate * Get current dx, dy and up/down button state.
904637Snate */
905637Snatestatic void
90658229Syokotamse_getati(tag, handle, dx, dy, but)
90758229Syokota	bus_space_tag_t tag;
90858229Syokota	bus_space_handle_t handle;
909637Snate	int *dx;
910637Snate	int *dy;
911637Snate	int *but;
912637Snate{
913637Snate	register char byte;
914637Snate
91558229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE);
91658229Syokota	bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_HOLD);
91758229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_STATUS);
91858229Syokota	*but = ~bus_space_read_1(tag, handle, MSE_PORTB) & MOUSE_MSC_BUTTONS;
91958229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DX);
92058229Syokota	byte = bus_space_read_1(tag, handle, MSE_PORTB);
92131603Syokota	*dx = byte;
92258229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DY);
92358229Syokota	byte = bus_space_read_1(tag, handle, MSE_PORTB);
92431603Syokota	*dy = byte;
92558229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE);
92658229Syokota	bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN);
927637Snate}
928