mse.c revision 92765
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 92765 2002-03-20 07:51:46Z alfred $
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>
5371286Swollman#include <sys/selinfo.h>
542056Swollman#include <sys/uio.h>
5566860Sphk#include <sys/mouse.h>
56637Snate
5758229Syokota#include <machine/bus_pio.h>
5858229Syokota#include <machine/bus.h>
597430Sbde#include <machine/clock.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;
8292765Salfred	void		(*sc_enablemouse)(bus_space_tag_t t,
8392765Salfred					       bus_space_handle_t h);
8492765Salfred	void		(*sc_disablemouse)(bus_space_tag_t t,
8592765Salfred						bus_space_handle_t h);
8692765Salfred	void		(*sc_getmouse)(bus_space_tag_t t,
8758229Syokota					    bus_space_handle_t h,
8892765Salfred					    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
10692765Salfredstatic	int		mse_probe(device_t dev);
10792765Salfredstatic	int		mse_attach(device_t dev);
10892765Salfredstatic	int		mse_detach(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};
15712675Sjulian
15892765Salfredstatic	void		mseintr(void *);
15958229Syokotastatic	timeout_t	msetimeout;
16012675Sjulian
161637Snate/* Flags */
162637Snate#define	MSESC_OPEN	0x1
163637Snate#define	MSESC_WANT	0x2
164637Snate
165637Snate/* and Mouse Types */
16620688Sjoerg#define	MSE_NONE	0	/* don't move this! */
167637Snate#define	MSE_LOGITECH	0x1
168637Snate#define	MSE_ATIINPORT	0x2
1694259Sjkh#define	MSE_LOGI_SIG	0xA5
170637Snate
171637Snate#define	MSE_PORTA	0
172637Snate#define	MSE_PORTB	1
173637Snate#define	MSE_PORTC	2
174637Snate#define	MSE_PORTD	3
17558229Syokota#define MSE_IOSIZE	4
176637Snate
177637Snate#define	MSE_UNIT(dev)		(minor(dev) >> 1)
178637Snate#define	MSE_NBLOCKIO(dev)	(minor(dev) & 0x1)
179637Snate
180637Snate/*
181637Snate * Logitech bus mouse definitions
182637Snate */
183637Snate#define	MSE_SETUP	0x91	/* What does this mean? */
1844259Sjkh				/* The definition for the control port */
1854259Sjkh				/* is as follows: */
1868876Srgrimes
1874259Sjkh				/* D7 	 =  Mode set flag (1 = active) 	*/
1888876Srgrimes				/* D6,D5 =  Mode selection (port A) 	*/
1894259Sjkh				/* 	    00 = Mode 0 = Basic I/O 	*/
1904259Sjkh				/* 	    01 = Mode 1 = Strobed I/O 	*/
1914259Sjkh				/* 	    10 = Mode 2 = Bi-dir bus 	*/
1924259Sjkh				/* D4	 =  Port A direction (1 = input)*/
1934259Sjkh				/* D3	 =  Port C (upper 4 bits) 	*/
1944259Sjkh				/*	    direction. (1 = input)	*/
1954259Sjkh				/* D2	 =  Mode selection (port B & C) */
1964259Sjkh				/*	    0 = Mode 0 = Basic I/O	*/
1974259Sjkh				/*	    1 = Mode 1 = Strobed I/O	*/
1984259Sjkh				/* D1	 =  Port B direction (1 = input)*/
1994259Sjkh				/* D0	 =  Port C (lower 4 bits)	*/
2004259Sjkh				/*	    direction. (1 = input)	*/
2018876Srgrimes
2024259Sjkh				/* So 91 means Basic I/O on all 3 ports,*/
2034259Sjkh				/* Port A is an input port, B is an 	*/
2044259Sjkh				/* output port, C is split with upper	*/
2054259Sjkh				/* 4 bits being an output port and lower*/
2064259Sjkh				/* 4 bits an input port, and enable the */
2074259Sjkh				/* sucker.				*/
2084259Sjkh				/* Courtesy Intel 8255 databook. Lars   */
209637Snate#define	MSE_HOLD	0x80
210637Snate#define	MSE_RXLOW	0x00
211637Snate#define	MSE_RXHIGH	0x20
212637Snate#define	MSE_RYLOW	0x40
213637Snate#define	MSE_RYHIGH	0x60
214637Snate#define	MSE_DISINTR	0x10
215637Snate#define MSE_INTREN	0x00
216637Snate
21792765Salfredstatic	int		mse_probelogi(device_t dev, mse_softc_t *sc);
21892765Salfredstatic	void		mse_disablelogi(bus_space_tag_t t,
21992765Salfred					     bus_space_handle_t h);
22092765Salfredstatic	void		mse_getlogi(bus_space_tag_t t,
22158229Syokota					 bus_space_handle_t h,
22292765Salfred					 int *dx, int *dy, int *but);
22392765Salfredstatic	void		mse_enablelogi(bus_space_tag_t t,
22492765Salfred					    bus_space_handle_t h);
225637Snate
226637Snate/*
227637Snate * ATI Inport mouse definitions
228637Snate */
229637Snate#define	MSE_INPORT_RESET	0x80
230637Snate#define	MSE_INPORT_STATUS	0x00
231637Snate#define	MSE_INPORT_DX		0x01
232637Snate#define	MSE_INPORT_DY		0x02
233637Snate#define	MSE_INPORT_MODE		0x07
234637Snate#define	MSE_INPORT_HOLD		0x20
235637Snate#define	MSE_INPORT_INTREN	0x09
236637Snate
23792765Salfredstatic	int		mse_probeati(device_t dev, mse_softc_t *sc);
23892765Salfredstatic	void		mse_enableati(bus_space_tag_t t,
23992765Salfred					   bus_space_handle_t h);
24092765Salfredstatic	void		mse_disableati(bus_space_tag_t t,
24192765Salfred					    bus_space_handle_t h);
24292765Salfredstatic	void		mse_getati(bus_space_tag_t t,
24358229Syokota					bus_space_handle_t h,
24492765Salfred					int *dx, int *dy, int *but);
245637Snate
246637Snate#define	MSEPRI	(PZERO + 3)
247637Snate
248637Snate/*
249637Snate * Table of mouse types.
250637Snate * Keep the Logitech last, since I haven't figured out how to probe it
251637Snate * properly yet. (Someday I'll have the documentation.)
252637Snate */
25312724Sphkstatic struct mse_types {
254637Snate	int	m_type;		/* Type of bus mouse */
25592765Salfred	int	(*m_probe)(device_t dev, mse_softc_t *sc);
25612854Sbde				/* Probe routine to test for it */
25792765Salfred	void	(*m_enable)(bus_space_tag_t t, bus_space_handle_t h);
25812854Sbde				/* Start routine */
25992765Salfred	void	(*m_disable)(bus_space_tag_t t, bus_space_handle_t h);
26012854Sbde				/* Disable interrupts routine */
26192765Salfred	void	(*m_get)(bus_space_tag_t t, bus_space_handle_t h,
26292765Salfred			      int *dx, int *dy, int *but);
26312854Sbde				/* and get mouse status */
26431603Syokota	mousehw_t   m_hw;	/* buttons iftype type model hwid */
26531603Syokota	mousemode_t m_mode;	/* proto rate res accel level size mask */
266637Snate} mse_types[] = {
26731603Syokota	{ MSE_ATIINPORT,
26831603Syokota	  mse_probeati, mse_enableati, mse_disableati, mse_getati,
26931603Syokota	  { 2, MOUSE_IF_INPORT, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, },
27031603Syokota	  { MOUSE_PROTO_INPORT, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE,
27131603Syokota	    { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, },
27231603Syokota	{ MSE_LOGITECH,
27331603Syokota	  mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi,
27431603Syokota	  { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, },
27531603Syokota	  { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE,
27631603Syokota	    { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, },
277637Snate	{ 0, },
278637Snate};
279637Snate
28058229Syokotastatic	int
28158229Syokotamse_probe(dev)
28258229Syokota	device_t dev;
283637Snate{
28458229Syokota	mse_softc_t *sc;
28558229Syokota	int error;
28658229Syokota	int rid;
28758229Syokota	int i;
288637Snate
28958229Syokota	/* check PnP IDs */
29058229Syokota	error = ISA_PNP_PROBE(device_get_parent(dev), dev, mse_ids);
29182618Smsmith	if (error == ENXIO)
29282554Smsmith		return error;
29358229Syokota
29458229Syokota	sc = device_get_softc(dev);
29558229Syokota	rid = 0;
29658229Syokota	sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
29758229Syokota					 MSE_IOSIZE, RF_ACTIVE);
29858229Syokota	if (sc->sc_port == NULL)
29958229Syokota		return ENXIO;
30058229Syokota	sc->sc_iot = rman_get_bustag(sc->sc_port);
30158229Syokota	sc->sc_ioh = rman_get_bushandle(sc->sc_port);
30258229Syokota
303637Snate	/*
304637Snate	 * Check for each mouse type in the table.
305637Snate	 */
306637Snate	i = 0;
307637Snate	while (mse_types[i].m_type) {
30858229Syokota		if ((*mse_types[i].m_probe)(dev, sc)) {
309637Snate			sc->sc_mousetype = mse_types[i].m_type;
310637Snate			sc->sc_enablemouse = mse_types[i].m_enable;
311637Snate			sc->sc_disablemouse = mse_types[i].m_disable;
312637Snate			sc->sc_getmouse = mse_types[i].m_get;
31331603Syokota			sc->hw = mse_types[i].m_hw;
31431603Syokota			sc->mode = mse_types[i].m_mode;
31558229Syokota			bus_release_resource(dev, SYS_RES_IOPORT, rid,
31658229Syokota					     sc->sc_port);
31758229Syokota			device_set_desc(dev, "Bus/InPort Mouse");
31858229Syokota			return 0;
319637Snate		}
320637Snate		i++;
321637Snate	}
32258229Syokota	bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
32358229Syokota	return ENXIO;
324637Snate}
325637Snate
32658229Syokotastatic	int
32758229Syokotamse_attach(dev)
32858229Syokota	device_t dev;
329637Snate{
33058229Syokota	mse_softc_t *sc;
33158229Syokota	int flags;
33258229Syokota	int unit;
33358229Syokota	int rid;
334637Snate
33558229Syokota	sc = device_get_softc(dev);
33658229Syokota	unit = device_get_unit(dev);
33758229Syokota
33858229Syokota	rid = 0;
33958229Syokota	sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
34058229Syokota					 MSE_IOSIZE, RF_ACTIVE);
34158229Syokota	if (sc->sc_port == NULL)
34258229Syokota		return ENXIO;
34358229Syokota	sc->sc_intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
34458229Syokota					 RF_ACTIVE);
34558229Syokota	if (sc->sc_intr == NULL) {
34658229Syokota		bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
34758229Syokota		return ENXIO;
34858229Syokota	}
34958229Syokota	sc->sc_iot = rman_get_bustag(sc->sc_port);
35058229Syokota	sc->sc_ioh = rman_get_bushandle(sc->sc_port);
35158229Syokota
35258229Syokota	if (BUS_SETUP_INTR(device_get_parent(dev), dev, sc->sc_intr,
35358229Syokota			   INTR_TYPE_TTY, mseintr, sc, &sc->sc_ih)) {
35458229Syokota		bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
35558229Syokota		bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr);
35658229Syokota		return ENXIO;
35758229Syokota	}
35858229Syokota
35958229Syokota	flags = device_get_flags(dev);
36058229Syokota	sc->mode.accelfactor = (flags & MSE_CONFIG_ACCEL) >> 4;
36158229Syokota	callout_handle_init(&sc->sc_callout);
36258229Syokota
36358229Syokota	sc->sc_dev = make_dev(&mse_cdevsw, unit << 1, 0, 0, 0600,
36458229Syokota			      "mse%d", unit);
36558229Syokota	sc->sc_ndev = make_dev(&mse_cdevsw, (unit<<1)+1, 0, 0, 0600,
36658229Syokota			       "nmse%d", unit);
36758229Syokota
36858229Syokota	return 0;
369637Snate}
370637Snate
37158229Syokotastatic	int
37258229Syokotamse_detach(dev)
37358229Syokota	device_t dev;
37458229Syokota{
37558229Syokota	mse_softc_t *sc;
37658229Syokota	int rid;
37758229Syokota
37858229Syokota	sc = device_get_softc(dev);
37958229Syokota	if (sc->sc_flags & MSESC_OPEN)
38058229Syokota		return EBUSY;
38158229Syokota
38258229Syokota	rid = 0;
38358229Syokota	BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->sc_intr, sc->sc_ih);
38458229Syokota	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr);
38558229Syokota	bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port);
38658229Syokota
38758229Syokota	destroy_dev(sc->sc_dev);
38858229Syokota	destroy_dev(sc->sc_ndev);
38958229Syokota
39058229Syokota	return 0;
39158229Syokota}
39258229Syokota
393637Snate/*
394637Snate * Exclusive open the mouse, initialize it and enable interrupts.
395637Snate */
39612675Sjulianstatic	int
39783366Sjulianmseopen(dev, flags, fmt, td)
398637Snate	dev_t dev;
39910624Sbde	int flags;
40010624Sbde	int fmt;
40183366Sjulian	struct thread *td;
402637Snate{
40358229Syokota	mse_softc_t *sc;
404637Snate	int s;
405637Snate
40658229Syokota	sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
40758229Syokota	if (sc == NULL)
408637Snate		return (ENXIO);
40920688Sjoerg	if (sc->sc_mousetype == MSE_NONE)
41020688Sjoerg		return (ENXIO);
411637Snate	if (sc->sc_flags & MSESC_OPEN)
412637Snate		return (EBUSY);
413637Snate	sc->sc_flags |= MSESC_OPEN;
41431603Syokota	sc->sc_obuttons = sc->sc_buttons = MOUSE_MSC_BUTTONS;
415637Snate	sc->sc_deltax = sc->sc_deltay = 0;
41631603Syokota	sc->sc_bytesread = sc->mode.packetsize = MOUSE_MSC_PACKETSIZE;
41758229Syokota	sc->sc_watchdog = FALSE;
41858229Syokota	sc->sc_callout = timeout(msetimeout, dev, hz*2);
41931603Syokota	sc->mode.level = 0;
42031603Syokota	sc->status.flags = 0;
42131603Syokota	sc->status.button = sc->status.obutton = 0;
42231603Syokota	sc->status.dx = sc->status.dy = sc->status.dz = 0;
423637Snate
424637Snate	/*
425637Snate	 * Initialize mouse interface and enable interrupts.
426637Snate	 */
427637Snate	s = spltty();
42858229Syokota	(*sc->sc_enablemouse)(sc->sc_iot, sc->sc_ioh);
429637Snate	splx(s);
430637Snate	return (0);
431637Snate}
432637Snate
433637Snate/*
434637Snate * mseclose: just turn off mouse innterrupts.
435637Snate */
43612675Sjulianstatic	int
43783366Sjulianmseclose(dev, flags, fmt, td)
438798Swollman	dev_t dev;
43910624Sbde	int flags;
44010624Sbde	int fmt;
44183366Sjulian	struct thread *td;
442637Snate{
44358229Syokota	mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
444637Snate	int s;
445637Snate
44658229Syokota	untimeout(msetimeout, dev, sc->sc_callout);
44758229Syokota	callout_handle_init(&sc->sc_callout);
448637Snate	s = spltty();
44958229Syokota	(*sc->sc_disablemouse)(sc->sc_iot, sc->sc_ioh);
450637Snate	sc->sc_flags &= ~MSESC_OPEN;
451637Snate	splx(s);
452637Snate	return(0);
453637Snate}
454637Snate
4558876Srgrimes/*
456637Snate * mseread: return mouse info using the MSC serial protocol, but without
457637Snate * using bytes 4 and 5.
458637Snate * (Yes this is cheesy, but it makes the X386 server happy, so...)
459637Snate */
46012675Sjulianstatic	int
46110624Sbdemseread(dev, uio, ioflag)
462637Snate	dev_t dev;
463637Snate	struct uio *uio;
46410624Sbde	int ioflag;
465637Snate{
46658229Syokota	mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
467637Snate	int xfer, s, error;
468637Snate
469637Snate	/*
470637Snate	 * If there are no protocol bytes to be read, set up a new protocol
471637Snate	 * packet.
472637Snate	 */
473637Snate	s = spltty(); /* XXX Should be its own spl, but where is imlXX() */
47431603Syokota	if (sc->sc_bytesread >= sc->mode.packetsize) {
475637Snate		while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
476637Snate		       (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
477637Snate			if (MSE_NBLOCKIO(dev)) {
478637Snate				splx(s);
479637Snate				return (0);
480637Snate			}
481637Snate			sc->sc_flags |= MSESC_WANT;
48246571Speter			error = tsleep((caddr_t)sc, MSEPRI | PCATCH,
48346571Speter				"mseread", 0);
48446571Speter			if (error) {
485637Snate				splx(s);
486637Snate				return (error);
487637Snate			}
488637Snate		}
489637Snate
490637Snate		/*
491637Snate		 * Generate protocol bytes.
492637Snate		 * For some reason X386 expects 5 bytes but never uses
493637Snate		 * the fourth or fifth?
494637Snate		 */
49531603Syokota		sc->sc_bytes[0] = sc->mode.syncmask[1]
49631603Syokota		    | (sc->sc_buttons & ~sc->mode.syncmask[0]);
497637Snate		if (sc->sc_deltax > 127)
498637Snate			sc->sc_deltax = 127;
499637Snate		if (sc->sc_deltax < -127)
500637Snate			sc->sc_deltax = -127;
501637Snate		sc->sc_deltay = -sc->sc_deltay;	/* Otherwise mousey goes wrong way */
502637Snate		if (sc->sc_deltay > 127)
503637Snate			sc->sc_deltay = 127;
504637Snate		if (sc->sc_deltay < -127)
505637Snate			sc->sc_deltay = -127;
506637Snate		sc->sc_bytes[1] = sc->sc_deltax;
507637Snate		sc->sc_bytes[2] = sc->sc_deltay;
508637Snate		sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
50931603Syokota		sc->sc_bytes[5] = sc->sc_bytes[6] = 0;
51031603Syokota		sc->sc_bytes[7] = MOUSE_SYS_EXTBUTTONS;
511637Snate		sc->sc_obuttons = sc->sc_buttons;
512637Snate		sc->sc_deltax = sc->sc_deltay = 0;
513637Snate		sc->sc_bytesread = 0;
514637Snate	}
515637Snate	splx(s);
51631603Syokota	xfer = min(uio->uio_resid, sc->mode.packetsize - sc->sc_bytesread);
51746571Speter	error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio);
51846571Speter	if (error)
519637Snate		return (error);
520637Snate	sc->sc_bytesread += xfer;
521637Snate	return(0);
522637Snate}
523637Snate
524637Snate/*
52531603Syokota * mseioctl: process ioctl commands.
52631603Syokota */
52731603Syokotastatic int
52883366Sjulianmseioctl(dev, cmd, addr, flag, td)
52931603Syokota	dev_t dev;
53036735Sdfr	u_long cmd;
53131603Syokota	caddr_t addr;
53231603Syokota	int flag;
53383366Sjulian	struct thread *td;
53431603Syokota{
53558229Syokota	mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
53631603Syokota	mousestatus_t status;
53731603Syokota	int err = 0;
53831603Syokota	int s;
53931603Syokota
54031603Syokota	switch (cmd) {
54131603Syokota
54231603Syokota	case MOUSE_GETHWINFO:
54331603Syokota		s = spltty();
54431603Syokota		*(mousehw_t *)addr = sc->hw;
54531603Syokota		if (sc->mode.level == 0)
54631603Syokota			((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
54731603Syokota		splx(s);
54831603Syokota		break;
54931603Syokota
55031603Syokota	case MOUSE_GETMODE:
55131603Syokota		s = spltty();
55231603Syokota		*(mousemode_t *)addr = sc->mode;
55331603Syokota		switch (sc->mode.level) {
55431603Syokota		case 0:
55531603Syokota			break;
55631603Syokota		case 1:
55731603Syokota			((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
55831603Syokota	    		((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
55931603Syokota	    		((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
56031603Syokota			break;
56131603Syokota		}
56231603Syokota		splx(s);
56331603Syokota		break;
56431603Syokota
56531603Syokota	case MOUSE_SETMODE:
56631603Syokota		switch (((mousemode_t *)addr)->level) {
56731603Syokota		case 0:
56831603Syokota		case 1:
56931603Syokota			break;
57031603Syokota		default:
57131603Syokota			return (EINVAL);
57231603Syokota		}
57331603Syokota		if (((mousemode_t *)addr)->accelfactor < -1)
57431603Syokota			return (EINVAL);
57531603Syokota		else if (((mousemode_t *)addr)->accelfactor >= 0)
57631603Syokota			sc->mode.accelfactor =
57731603Syokota			    ((mousemode_t *)addr)->accelfactor;
57831603Syokota		sc->mode.level = ((mousemode_t *)addr)->level;
57931603Syokota		switch (sc->mode.level) {
58031603Syokota		case 0:
58131603Syokota			sc->sc_bytesread = sc->mode.packetsize
58231603Syokota			    = MOUSE_MSC_PACKETSIZE;
58331603Syokota			break;
58431603Syokota		case 1:
58531603Syokota			sc->sc_bytesread = sc->mode.packetsize
58631603Syokota			    = MOUSE_SYS_PACKETSIZE;
58731603Syokota			break;
58831603Syokota		}
58931603Syokota		break;
59031603Syokota
59131603Syokota	case MOUSE_GETLEVEL:
59231603Syokota		*(int *)addr = sc->mode.level;
59331603Syokota		break;
59431603Syokota
59531603Syokota	case MOUSE_SETLEVEL:
59631603Syokota		switch (*(int *)addr) {
59731603Syokota		case 0:
59831603Syokota			sc->mode.level = *(int *)addr;
59931603Syokota			sc->sc_bytesread = sc->mode.packetsize
60031603Syokota			    = MOUSE_MSC_PACKETSIZE;
60131603Syokota			break;
60231603Syokota		case 1:
60331603Syokota			sc->mode.level = *(int *)addr;
60431603Syokota			sc->sc_bytesread = sc->mode.packetsize
60531603Syokota			    = MOUSE_SYS_PACKETSIZE;
60631603Syokota			break;
60731603Syokota		default:
60831603Syokota			return (EINVAL);
60931603Syokota		}
61031603Syokota		break;
61131603Syokota
61231603Syokota	case MOUSE_GETSTATUS:
61331603Syokota		s = spltty();
61431603Syokota		status = sc->status;
61531603Syokota		sc->status.flags = 0;
61631603Syokota		sc->status.obutton = sc->status.button;
61731603Syokota		sc->status.button = 0;
61831603Syokota		sc->status.dx = 0;
61931603Syokota		sc->status.dy = 0;
62031603Syokota		sc->status.dz = 0;
62131603Syokota		splx(s);
62231603Syokota		*(mousestatus_t *)addr = status;
62331603Syokota		break;
62431603Syokota
62531603Syokota	case MOUSE_READSTATE:
62631603Syokota	case MOUSE_READDATA:
62731603Syokota		return (ENODEV);
62831603Syokota
62931603Syokota#if (defined(MOUSE_GETVARS))
63031603Syokota	case MOUSE_GETVARS:
63131603Syokota	case MOUSE_SETVARS:
63231603Syokota		return (ENODEV);
63331603Syokota#endif
63431603Syokota
63531603Syokota	default:
63631603Syokota		return (ENOTTY);
63731603Syokota	}
63831603Syokota	return (err);
63931603Syokota}
64031603Syokota
64131603Syokota/*
64229368Speter * msepoll: check for mouse input to be processed.
643637Snate */
64412675Sjulianstatic	int
64583366Sjulianmsepoll(dev, events, td)
646637Snate	dev_t dev;
64729368Speter	int events;
64883366Sjulian	struct thread *td;
649637Snate{
65058229Syokota	mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
651637Snate	int s;
65229368Speter	int revents = 0;
653637Snate
654637Snate	s = spltty();
65546568Speter	if (events & (POLLIN | POLLRDNORM)) {
65631603Syokota		if (sc->sc_bytesread != sc->mode.packetsize ||
65731603Syokota		    sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
65829368Speter		    (sc->sc_obuttons ^ sc->sc_buttons) != 0)
65929368Speter			revents |= events & (POLLIN | POLLRDNORM);
66029368Speter		else {
66129368Speter			/*
66229368Speter			 * Since this is an exclusive open device, any previous
66329368Speter			 * proc pointer is trash now, so we can just assign it.
66429368Speter			 */
66583366Sjulian			selrecord(td, &sc->sc_selp);
66629368Speter		}
66746568Speter	}
668637Snate	splx(s);
66929368Speter	return (revents);
670637Snate}
671637Snate
672637Snate/*
67358229Syokota * msetimeout: watchdog timer routine.
67458229Syokota */
67558229Syokotastatic void
67658229Syokotamsetimeout(arg)
67758229Syokota	void *arg;
67858229Syokota{
67958229Syokota	dev_t dev;
68058229Syokota	mse_softc_t *sc;
68158229Syokota
68258229Syokota	dev = (dev_t)arg;
68358229Syokota	sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev));
68458229Syokota	if (sc->sc_watchdog) {
68558229Syokota		if (bootverbose)
68658229Syokota			printf("mse%d: lost interrupt?\n", MSE_UNIT(dev));
68758229Syokota		mseintr(sc);
68858229Syokota	}
68958229Syokota	sc->sc_watchdog = TRUE;
69058229Syokota	sc->sc_callout = timeout(msetimeout, dev, hz);
69158229Syokota}
69258229Syokota
69358229Syokota/*
694637Snate * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
695637Snate */
69640565Sbdestatic void
69758229Syokotamseintr(arg)
69858229Syokota	void *arg;
699637Snate{
70031603Syokota	/*
70131603Syokota	 * the table to turn MouseSystem button bits (MOUSE_MSC_BUTTON?UP)
70231603Syokota	 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
70331603Syokota	 */
70431603Syokota	static int butmap[8] = {
70531603Syokota		0,
70631603Syokota		MOUSE_BUTTON3DOWN,
70731603Syokota		MOUSE_BUTTON2DOWN,
70831603Syokota		MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
70931603Syokota		MOUSE_BUTTON1DOWN,
71031603Syokota		MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
71131603Syokota		MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
71231603Syokota        	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
71331603Syokota	};
71458229Syokota	mse_softc_t *sc = arg;
71531603Syokota	int dx, dy, but;
71631603Syokota	int sign;
717637Snate
718637Snate#ifdef DEBUG
719637Snate	static int mse_intrcnt = 0;
720637Snate	if((mse_intrcnt++ % 10000) == 0)
721637Snate		printf("mseintr\n");
722637Snate#endif /* DEBUG */
723637Snate	if ((sc->sc_flags & MSESC_OPEN) == 0)
724637Snate		return;
725637Snate
72658229Syokota	(*sc->sc_getmouse)(sc->sc_iot, sc->sc_ioh, &dx, &dy, &but);
72731603Syokota	if (sc->mode.accelfactor > 0) {
72831603Syokota		sign = (dx < 0);
72931603Syokota		dx = dx * dx / sc->mode.accelfactor;
73031603Syokota		if (dx == 0)
73131603Syokota			dx = 1;
73231603Syokota		if (sign)
73331603Syokota			dx = -dx;
73431603Syokota		sign = (dy < 0);
73531603Syokota		dy = dy * dy / sc->mode.accelfactor;
73631603Syokota		if (dy == 0)
73731603Syokota			dy = 1;
73831603Syokota		if (sign)
73931603Syokota			dy = -dy;
74031603Syokota	}
74131603Syokota	sc->sc_deltax += dx;
74231603Syokota	sc->sc_deltay += dy;
74331603Syokota	sc->sc_buttons = but;
744637Snate
74531603Syokota	but = butmap[~but & MOUSE_MSC_BUTTONS];
74631603Syokota	sc->status.dx += dx;
74731603Syokota	sc->status.dy += dy;
74831603Syokota	sc->status.flags |= ((dx || dy) ? MOUSE_POSCHANGED : 0)
74931603Syokota	    | (sc->status.button ^ but);
75031603Syokota	sc->status.button = but;
75131603Syokota
75258229Syokota	sc->sc_watchdog = FALSE;
75358229Syokota
754637Snate	/*
755637Snate	 * If mouse state has changed, wake up anyone wanting to know.
756637Snate	 */
757637Snate	if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
758637Snate	    (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
7598876Srgrimes		if (sc->sc_flags & MSESC_WANT) {
7608876Srgrimes			sc->sc_flags &= ~MSESC_WANT;
7618876Srgrimes			wakeup((caddr_t)sc);
7628876Srgrimes		}
7631549Srgrimes		selwakeup(&sc->sc_selp);
764637Snate	}
765637Snate}
766637Snate
767637Snate/*
768637Snate * Routines for the Logitech mouse.
769637Snate */
770637Snate/*
771637Snate * Test for a Logitech bus mouse and return 1 if it is.
772637Snate * (until I know how to use the signature port properly, just disable
773637Snate *  interrupts and return 1)
774637Snate */
775637Snatestatic int
77658229Syokotamse_probelogi(dev, sc)
77758229Syokota	device_t dev;
77858229Syokota	mse_softc_t *sc;
779637Snate{
780637Snate
7814259Sjkh	int sig;
7824259Sjkh
78358229Syokota	bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTD, MSE_SETUP);
7844259Sjkh		/* set the signature port */
78558229Syokota	bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB, MSE_LOGI_SIG);
7864259Sjkh
7874259Sjkh	DELAY(30000); /* 30 ms delay */
78858229Syokota	sig = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB) & 0xFF;
7894259Sjkh	if (sig == MSE_LOGI_SIG) {
79058229Syokota		bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC,
79158229Syokota				  MSE_DISINTR);
7924259Sjkh		return(1);
7934259Sjkh	} else {
79416074Sjoerg		if (bootverbose)
79558229Syokota			device_printf(dev, "wrong signature %x\n", sig);
7964259Sjkh		return(0);
797637Snate	}
798637Snate}
799637Snate
800637Snate/*
801637Snate * Initialize Logitech mouse and enable interrupts.
802637Snate */
803637Snatestatic void
80458229Syokotamse_enablelogi(tag, handle)
80558229Syokota	bus_space_tag_t tag;
80658229Syokota	bus_space_handle_t handle;
807637Snate{
808637Snate	int dx, dy, but;
809637Snate
81058229Syokota	bus_space_write_1(tag, handle, MSE_PORTD, MSE_SETUP);
81158229Syokota	mse_getlogi(tag, handle, &dx, &dy, &but);
812637Snate}
813637Snate
814637Snate/*
815637Snate * Disable interrupts for Logitech mouse.
816637Snate */
817637Snatestatic void
81858229Syokotamse_disablelogi(tag, handle)
81958229Syokota	bus_space_tag_t tag;
82058229Syokota	bus_space_handle_t handle;
821637Snate{
822637Snate
82358229Syokota	bus_space_write_1(tag, handle, MSE_PORTC, MSE_DISINTR);
824637Snate}
825637Snate
826637Snate/*
827637Snate * Get the current dx, dy and button up/down state.
828637Snate */
829637Snatestatic void
83058229Syokotamse_getlogi(tag, handle, dx, dy, but)
83158229Syokota	bus_space_tag_t tag;
83258229Syokota	bus_space_handle_t handle;
833637Snate	int *dx;
834637Snate	int *dy;
835637Snate	int *but;
836637Snate{
837637Snate	register char x, y;
838637Snate
83958229Syokota	bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXLOW);
84058229Syokota	x = bus_space_read_1(tag, handle, MSE_PORTA);
84131603Syokota	*but = (x >> 5) & MOUSE_MSC_BUTTONS;
842637Snate	x &= 0xf;
84358229Syokota	bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXHIGH);
84458229Syokota	x |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4);
84558229Syokota	bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYLOW);
84658229Syokota	y = (bus_space_read_1(tag, handle, MSE_PORTA) & 0xf);
84758229Syokota	bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYHIGH);
84858229Syokota	y |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4);
84931603Syokota	*dx = x;
85031603Syokota	*dy = y;
85158229Syokota	bus_space_write_1(tag, handle, MSE_PORTC, MSE_INTREN);
852637Snate}
853637Snate
854637Snate/*
855637Snate * Routines for the ATI Inport bus mouse.
856637Snate */
857637Snate/*
858637Snate * Test for a ATI Inport bus mouse and return 1 if it is.
859637Snate * (do not enable interrupts)
860637Snate */
861637Snatestatic int
86258229Syokotamse_probeati(dev, sc)
86358229Syokota	device_t dev;
86458229Syokota	mse_softc_t *sc;
865637Snate{
866637Snate	int i;
867637Snate
868637Snate	for (i = 0; i < 2; i++)
86958229Syokota		if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC) == 0xde)
870637Snate			return (1);
871637Snate	return (0);
872637Snate}
873637Snate
874637Snate/*
875637Snate * Initialize ATI Inport mouse and enable interrupts.
876637Snate */
877637Snatestatic void
87858229Syokotamse_enableati(tag, handle)
87958229Syokota	bus_space_tag_t tag;
88058229Syokota	bus_space_handle_t handle;
881637Snate{
882637Snate
88358229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_RESET);
88458229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE);
88558229Syokota	bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN);
886637Snate}
887637Snate
888637Snate/*
889637Snate * Disable interrupts for ATI Inport mouse.
890637Snate */
891637Snatestatic void
89258229Syokotamse_disableati(tag, handle)
89358229Syokota	bus_space_tag_t tag;
89458229Syokota	bus_space_handle_t handle;
895637Snate{
896637Snate
89758229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE);
89858229Syokota	bus_space_write_1(tag, handle, MSE_PORTB, 0);
899637Snate}
900637Snate
901637Snate/*
902637Snate * Get current dx, dy and up/down button state.
903637Snate */
904637Snatestatic void
90558229Syokotamse_getati(tag, handle, dx, dy, but)
90658229Syokota	bus_space_tag_t tag;
90758229Syokota	bus_space_handle_t handle;
908637Snate	int *dx;
909637Snate	int *dy;
910637Snate	int *but;
911637Snate{
912637Snate	register char byte;
913637Snate
91458229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE);
91558229Syokota	bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_HOLD);
91658229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_STATUS);
91758229Syokota	*but = ~bus_space_read_1(tag, handle, MSE_PORTB) & MOUSE_MSC_BUTTONS;
91858229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DX);
91958229Syokota	byte = bus_space_read_1(tag, handle, MSE_PORTB);
92031603Syokota	*dx = byte;
92158229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DY);
92258229Syokota	byte = bus_space_read_1(tag, handle, MSE_PORTB);
92331603Syokota	*dy = byte;
92458229Syokota	bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE);
92558229Syokota	bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN);
926637Snate}
927