File:  [DragonFly] / src / sys / dev / misc / mse / mse.c
Revision 1.8: download - view: text, annotated - select for diffs
Thu May 13 23:49:16 2004 UTC (10 years, 2 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).

d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device.  It was never
used for that purpose.

d_clone will be more fully implemented as work continues.  We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads.  This is something we will be needing later
on.

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