File:  [DragonFly] / src / sys / dev / usbmisc / ums / ums.c
Revision 1.11: download - view: text, annotated - select for diffs
Thu May 13 23:49:22 2004 UTC (10 years, 3 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:  * $FreeBSD: src/sys/dev/usb/ums.c,v 1.64 2003/11/09 09:17:22 tanimura Exp $
    3:  * $DragonFly: src/sys/dev/usbmisc/ums/ums.c,v 1.11 2004/05/13 23:49:22 dillon Exp $
    4:  */
    5: 
    6: /*
    7:  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    8:  * All rights reserved.
    9:  *
   10:  * This code is derived from software contributed to The NetBSD Foundation
   11:  * by Lennart Augustsson (lennart@augustsson.net) at
   12:  * Carlstedt Research & Technology.
   13:  *
   14:  * Redistribution and use in source and binary forms, with or without
   15:  * modification, are permitted provided that the following conditions
   16:  * are met:
   17:  * 1. Redistributions of source code must retain the above copyright
   18:  *    notice, this list of conditions and the following disclaimer.
   19:  * 2. Redistributions in binary form must reproduce the above copyright
   20:  *    notice, this list of conditions and the following disclaimer in the
   21:  *    documentation and/or other materials provided with the distribution.
   22:  * 3. All advertising materials mentioning features or use of this software
   23:  *    must display the following acknowledgement:
   24:  *        This product includes software developed by the NetBSD
   25:  *        Foundation, Inc. and its contributors.
   26:  * 4. Neither the name of The NetBSD Foundation nor the names of its
   27:  *    contributors may be used to endorse or promote products derived
   28:  *    from this software without specific prior written permission.
   29:  *
   30:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   31:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   32:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   33:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   34:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   35:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   36:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   37:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   38:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   39:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   40:  * POSSIBILITY OF SUCH DAMAGE.
   41:  */
   42: 
   43: /*
   44:  * HID spec: http://www.usb.org/developers/data/devclass/hid1_1.pdf
   45:  */
   46: 
   47: #include <sys/param.h>
   48: #include <sys/systm.h>
   49: #include <sys/kernel.h>
   50: #include <sys/malloc.h>
   51: #include <sys/module.h>
   52: #include <sys/bus.h>
   53: #include <sys/ioccom.h>
   54: #include <sys/conf.h>
   55: #include <sys/tty.h>
   56: #include <sys/file.h>
   57: #if defined(__FreeBSD__) && __FreeBSD_version >= 500014
   58: #include <sys/selinfo.h>
   59: #else
   60: #include <sys/select.h>
   61: #endif
   62: #include <sys/vnode.h>
   63: #include <sys/poll.h>
   64: #include <sys/sysctl.h>
   65: 
   66: #include <bus/usb/usb.h>
   67: #include <bus/usb/usbhid.h>
   68: 
   69: #include <bus/usb/usbdi.h>
   70: #include <bus/usb/usbdi_util.h>
   71: #include <bus/usb/usbdevs.h>
   72: #include <bus/usb/usb_quirks.h>
   73: #include <bus/usb/hid.h>
   74: 
   75: #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
   76: #include <sys/mouse.h>
   77: #else
   78: #include <machine/mouse.h>
   79: #endif
   80: 
   81: #ifdef USB_DEBUG
   82: #define DPRINTF(x)	if (umsdebug) logprintf x
   83: #define DPRINTFN(n,x)	if (umsdebug>(n)) logprintf x
   84: int	umsdebug = 0;
   85: SYSCTL_NODE(_hw_usb, OID_AUTO, ums, CTLFLAG_RW, 0, "USB ums");
   86: SYSCTL_INT(_hw_usb_ums, OID_AUTO, debug, CTLFLAG_RW,
   87: 	   &umsdebug, 0, "ums debug level");
   88: #else
   89: #define DPRINTF(x)
   90: #define DPRINTFN(n,x)
   91: #endif
   92: 
   93: #define UMSUNIT(s)	(minor(s)&0x1f)
   94: 
   95: #define MS_TO_TICKS(ms) ((ms) * hz / 1000)
   96: 
   97: #define QUEUE_BUFSIZE	400	/* MUST be divisible by 5 _and_ 8 */
   98: 
   99: struct ums_softc {
  100: 	device_t sc_dev;		/* base device */
  101: 	usbd_interface_handle sc_iface;	/* interface */
  102: 	usbd_pipe_handle sc_intrpipe;	/* interrupt pipe */
  103: 	int sc_ep_addr;
  104: 
  105: 	u_char *sc_ibuf;
  106: 	u_int8_t sc_iid;
  107: 	int sc_isize;
  108: 	struct hid_location sc_loc_x, sc_loc_y, sc_loc_z;
  109: 	struct hid_location *sc_loc_btn;
  110: 
  111: 	usb_callout_t callout_handle;	/* for spurious button ups */
  112: 
  113: 	int sc_enabled;
  114: 	int sc_disconnected;	/* device is gone */
  115: 
  116: 	int flags;		/* device configuration */
  117: #define UMS_Z		0x01	/* z direction available */
  118: #define UMS_SPUR_BUT_UP	0x02	/* spurious button up events */
  119: 	int nbuttons;
  120: #define MAX_BUTTONS	7	/* chosen because sc_buttons is u_char */
  121: 
  122: 	u_char		qbuf[QUEUE_BUFSIZE];	/* must be divisable by 3&4 */
  123: 	u_char		dummy[100];	/* XXX just for safety and for now */
  124: 	int		qcount, qhead, qtail;
  125: 	mousehw_t	hw;
  126: 	mousemode_t	mode;
  127: 	mousestatus_t	status;
  128: 
  129: 	int		state;
  130: #	  define	UMS_ASLEEP	0x01	/* readFromDevice is waiting */
  131: #	  define	UMS_SELECT	0x02	/* select is waiting */
  132: 	struct selinfo	rsel;		/* process waiting in select */
  133: 
  134: 	dev_t		dev;		/* specfs */
  135: };
  136: 
  137: #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE)
  138: #define MOUSE_FLAGS (HIO_RELATIVE)
  139: 
  140: Static void ums_intr(usbd_xfer_handle xfer,
  141: 			  usbd_private_handle priv, usbd_status status);
  142: 
  143: Static void ums_add_to_queue(struct ums_softc *sc,
  144: 				int dx, int dy, int dz, int buttons);
  145: Static void ums_add_to_queue_timeout(void *priv);
  146: 
  147: Static int  ums_enable(void *);
  148: Static void ums_disable(void *);
  149: 
  150: Static d_open_t  ums_open;
  151: Static d_close_t ums_close;
  152: Static d_read_t  ums_read;
  153: Static d_ioctl_t ums_ioctl;
  154: Static d_poll_t  ums_poll;
  155: 
  156: #define UMS_CDEV_MAJOR	111
  157: 
  158: Static struct cdevsw ums_cdevsw = {
  159: 	/* name */	"ums",
  160: 	/* maj */	UMS_CDEV_MAJOR,
  161: 	/* flags */	0,
  162: 	/* port */	NULL,
  163: 	/* clone */	NULL,
  164: 
  165: 	/* open */	ums_open,
  166: 	/* close */	ums_close,
  167: 	/* read */	ums_read,
  168: 	/* write */	nowrite,
  169: 	/* ioctl */	ums_ioctl,
  170: 	/* poll */	ums_poll,
  171: 	/* mmap */	nommap,
  172: 	/* strategy */	nostrategy,
  173: 	/* dump */	nodump,
  174: 	/* psize */	nopsize
  175: };
  176: 
  177: USB_DECLARE_DRIVER(ums);
  178: 
  179: USB_MATCH(ums)
  180: {
  181: 	USB_MATCH_START(ums, uaa);
  182: 	usb_interface_descriptor_t *id;
  183: 	int size, ret;
  184: 	void *desc;
  185: 	usbd_status err;
  186: 
  187: 	if (!uaa->iface)
  188: 		return (UMATCH_NONE);
  189: 	id = usbd_get_interface_descriptor(uaa->iface);
  190: 	if (!id || id->bInterfaceClass != UICLASS_HID)
  191: 		return (UMATCH_NONE);
  192: 
  193: 	err = usbd_read_report_desc(uaa->iface, &desc, &size, M_TEMP);
  194: 	if (err)
  195: 		return (UMATCH_NONE);
  196: 
  197: 	if (hid_is_collection(desc, size,
  198: 			      HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
  199: 		ret = UMATCH_IFACECLASS;
  200: 	else
  201: 		ret = UMATCH_NONE;
  202: 
  203: 	free(desc, M_TEMP);
  204: 	return (ret);
  205: }
  206: 
  207: USB_ATTACH(ums)
  208: {
  209: 	USB_ATTACH_START(ums, sc, uaa);
  210: 	usbd_interface_handle iface = uaa->iface;
  211: 	usb_interface_descriptor_t *id;
  212: 	usb_endpoint_descriptor_t *ed;
  213: 	int size;
  214: 	void *desc;
  215: 	usbd_status err;
  216: 	char devinfo[1024];
  217: 	u_int32_t flags;
  218: 	int i;
  219: 	struct hid_location loc_btn;
  220: 
  221: 	sc->sc_disconnected = 1;
  222: 	sc->sc_iface = iface;
  223: 	id = usbd_get_interface_descriptor(iface);
  224: 	usbd_devinfo(uaa->device, 0, devinfo);
  225: 	USB_ATTACH_SETUP;
  226: 	printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
  227: 	       devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
  228: 	ed = usbd_interface2endpoint_descriptor(iface, 0);
  229: 	if (!ed) {
  230: 		printf("%s: could not read endpoint descriptor\n",
  231: 		       USBDEVNAME(sc->sc_dev));
  232: 		USB_ATTACH_ERROR_RETURN;
  233: 	}
  234: 
  235: 	DPRINTFN(10,("ums_attach: bLength=%d bDescriptorType=%d "
  236: 		     "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
  237: 		     " bInterval=%d\n",
  238: 		     ed->bLength, ed->bDescriptorType,
  239: 		     UE_GET_ADDR(ed->bEndpointAddress),
  240: 		     UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN ? "in":"out",
  241: 		     UE_GET_XFERTYPE(ed->bmAttributes),
  242: 		     UGETW(ed->wMaxPacketSize), ed->bInterval));
  243: 
  244: 	if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN ||
  245: 	    UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) {
  246: 		printf("%s: unexpected endpoint\n",
  247: 		       USBDEVNAME(sc->sc_dev));
  248: 		USB_ATTACH_ERROR_RETURN;
  249: 	}
  250: 
  251: 	err = usbd_read_report_desc(uaa->iface, &desc, &size, M_TEMP);
  252: 	if (err)
  253: 		USB_ATTACH_ERROR_RETURN;
  254: 
  255: 	if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
  256: 		       hid_input, &sc->sc_loc_x, &flags)) {
  257: 		printf("%s: mouse has no X report\n", USBDEVNAME(sc->sc_dev));
  258: 		USB_ATTACH_ERROR_RETURN;
  259: 	}
  260: 	if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
  261: 		printf("%s: X report 0x%04x not supported\n",
  262: 		       USBDEVNAME(sc->sc_dev), flags);
  263: 		USB_ATTACH_ERROR_RETURN;
  264: 	}
  265: 
  266: 	if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
  267: 		       hid_input, &sc->sc_loc_y, &flags)) {
  268: 		printf("%s: mouse has no Y report\n", USBDEVNAME(sc->sc_dev));
  269: 		USB_ATTACH_ERROR_RETURN;
  270: 	}
  271: 	if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
  272: 		printf("%s: Y report 0x%04x not supported\n",
  273: 		       USBDEVNAME(sc->sc_dev), flags);
  274: 		USB_ATTACH_ERROR_RETURN;
  275: 	}
  276: 
  277: 	/* try to guess the Z activator: first check Z, then WHEEL */
  278: 	if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z),
  279: 		       hid_input, &sc->sc_loc_z, &flags) ||
  280: 	    hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL),
  281: 		       hid_input, &sc->sc_loc_z, &flags)) {
  282: 		if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
  283: 			sc->sc_loc_z.size = 0;	/* Bad Z coord, ignore it */
  284: 		} else {
  285: 			sc->flags |= UMS_Z;
  286: 		}
  287: 	}
  288: 
  289: 	/* figure out the number of buttons */
  290: 	for (i = 1; i <= MAX_BUTTONS; i++)
  291: 		if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
  292: 				hid_input, &loc_btn, 0))
  293: 			break;
  294: 	sc->nbuttons = i - 1;
  295: 	sc->sc_loc_btn = malloc(sizeof(struct hid_location)*sc->nbuttons,
  296: 				M_USBDEV, M_INTWAIT);
  297: 
  298: 	printf("%s: %d buttons%s\n", USBDEVNAME(sc->sc_dev),
  299: 	       sc->nbuttons, sc->flags & UMS_Z? " and Z dir." : "");
  300: 
  301: 	for (i = 1; i <= sc->nbuttons; i++)
  302: 		hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
  303: 				hid_input, &sc->sc_loc_btn[i-1], 0);
  304: 
  305: 	sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid);
  306: 	sc->sc_ibuf = malloc(sc->sc_isize, M_USB, M_INTWAIT);
  307: 	sc->sc_ep_addr = ed->bEndpointAddress;
  308: 	sc->sc_disconnected = 0;
  309: 	free(desc, M_TEMP);
  310: 
  311: #ifdef USB_DEBUG
  312: 	DPRINTF(("ums_attach: sc=%p\n", sc));
  313: 	DPRINTF(("ums_attach: X\t%d/%d\n",
  314: 		 sc->sc_loc_x.pos, sc->sc_loc_x.size));
  315: 	DPRINTF(("ums_attach: Y\t%d/%d\n",
  316: 		 sc->sc_loc_y.pos, sc->sc_loc_y.size));
  317: 	if (sc->flags & UMS_Z)
  318: 		DPRINTF(("ums_attach: Z\t%d/%d\n",
  319: 			 sc->sc_loc_z.pos, sc->sc_loc_z.size));
  320: 	for (i = 1; i <= sc->nbuttons; i++) {
  321: 		DPRINTF(("ums_attach: B%d\t%d/%d\n",
  322: 			 i, sc->sc_loc_btn[i-1].pos,sc->sc_loc_btn[i-1].size));
  323: 	}
  324: 	DPRINTF(("ums_attach: size=%d, id=%d\n", sc->sc_isize, sc->sc_iid));
  325: #endif
  326: 
  327: 	if (sc->nbuttons > MOUSE_MSC_MAXBUTTON)
  328: 		sc->hw.buttons = MOUSE_MSC_MAXBUTTON;
  329: 	else
  330: 		sc->hw.buttons = sc->nbuttons;
  331: 	sc->hw.iftype = MOUSE_IF_USB;
  332: 	sc->hw.type = MOUSE_MOUSE;
  333: 	sc->hw.model = MOUSE_MODEL_GENERIC;
  334: 	sc->hw.hwid = 0;
  335: 	sc->mode.protocol = MOUSE_PROTO_MSC;
  336: 	sc->mode.rate = -1;
  337: 	sc->mode.resolution = MOUSE_RES_UNKNOWN;
  338: 	sc->mode.accelfactor = 0;
  339: 	sc->mode.level = 0;
  340: 	sc->mode.packetsize = MOUSE_MSC_PACKETSIZE;
  341: 	sc->mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
  342: 	sc->mode.syncmask[1] = MOUSE_MSC_SYNC;
  343: 
  344: 	sc->status.flags = 0;
  345: 	sc->status.button = sc->status.obutton = 0;
  346: 	sc->status.dx = sc->status.dy = sc->status.dz = 0;
  347: 
  348: #if !defined(__FreeBSD__) && !defined(__DragonFly__)
  349: 	sc->rsel.si_flags = 0;
  350: 	sc->rsel.si_pid = 0;
  351: #endif
  352: 
  353: 	sc->dev = make_dev(&ums_cdevsw, device_get_unit(self),
  354: 			UID_ROOT, GID_OPERATOR,
  355: 			0644, "ums%d", device_get_unit(self));
  356: 
  357: 	if (usbd_get_quirks(uaa->device)->uq_flags & UQ_SPUR_BUT_UP) {
  358: 		DPRINTF(("%s: Spurious button up events\n",
  359: 			USBDEVNAME(sc->sc_dev)));
  360: 		sc->flags |= UMS_SPUR_BUT_UP;
  361: 	}
  362: 
  363: 	USB_ATTACH_SUCCESS_RETURN;
  364: }
  365: 
  366: 
  367: Static int
  368: ums_detach(device_t self)
  369: {
  370: 	struct ums_softc *sc = device_get_softc(self);
  371: 
  372: 	if (sc->sc_enabled)
  373: 		ums_disable(sc);
  374: 
  375: 	DPRINTF(("%s: disconnected\n", USBDEVNAME(self)));
  376: 
  377: 	free(sc->sc_loc_btn, M_USB);
  378: 	free(sc->sc_ibuf, M_USB);
  379: 
  380: 	/* someone waiting for data */
  381: 	/*
  382: 	 * XXX If we wakeup the process here, the device will be gone by
  383: 	 * the time the process gets a chance to notice. *_close and friends
  384: 	 * should be fixed to handle this case.
  385: 	 * Or we should do a delayed detach for this.
  386: 	 * Does this delay now force tsleep to exit with an error?
  387: 	 */
  388: 	if (sc->state & UMS_ASLEEP) {
  389: 		sc->state &= ~UMS_ASLEEP;
  390: 		wakeup(sc);
  391: 	}
  392: 	if (sc->state & UMS_SELECT) {
  393: 		sc->state &= ~UMS_SELECT;
  394: 		selwakeuppri(&sc->rsel, 0);
  395: 	}
  396: 
  397: 	destroy_dev(sc->dev);
  398: 
  399: 	return 0;
  400: }
  401: 
  402: void
  403: ums_intr(xfer, addr, status)
  404: 	usbd_xfer_handle xfer;
  405: 	usbd_private_handle addr;
  406: 	usbd_status status;
  407: {
  408: 	struct ums_softc *sc = addr;
  409: 	u_char *ibuf;
  410: 	int dx, dy, dz;
  411: 	u_char buttons = 0;
  412: 	int i;
  413: 
  414: #define UMS_BUT(i) ((i) < 3 ? (((i) + 2) % 3) : (i))
  415: 
  416: 	DPRINTFN(5, ("ums_intr: sc=%p status=%d\n", sc, status));
  417: 	DPRINTFN(5, ("ums_intr: data = %02x %02x %02x\n",
  418: 		     sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2]));
  419: 
  420: 	if (status == USBD_CANCELLED)
  421: 		return;
  422: 
  423: 	if (status != USBD_NORMAL_COMPLETION) {
  424: 		DPRINTF(("ums_intr: status=%d\n", status));
  425: 		if (status == USBD_STALLED)
  426: 		    usbd_clear_endpoint_stall_async(sc->sc_intrpipe);
  427: 		return;
  428: 	}
  429: 
  430: 	ibuf = sc->sc_ibuf;
  431: 	if (sc->sc_iid) {
  432: 		if (*ibuf++ != sc->sc_iid)
  433: 			return;
  434: 	}
  435: 
  436: 	dx =  hid_get_data(ibuf, &sc->sc_loc_x);
  437: 	dy = -hid_get_data(ibuf, &sc->sc_loc_y);
  438: 	dz = -hid_get_data(ibuf, &sc->sc_loc_z);
  439: 	for (i = 0; i < sc->nbuttons; i++)
  440: 		if (hid_get_data(ibuf, &sc->sc_loc_btn[i]))
  441: 			buttons |= (1 << UMS_BUT(i));
  442: 
  443: 	if (dx || dy || dz || (sc->flags & UMS_Z)
  444: 	    || buttons != sc->status.button) {
  445: 		DPRINTFN(5, ("ums_intr: x:%d y:%d z:%d buttons:0x%x\n",
  446: 			dx, dy, dz, buttons));
  447: 
  448: 		sc->status.button = buttons;
  449: 		sc->status.dx += dx;
  450: 		sc->status.dy += dy;
  451: 		sc->status.dz += dz;
  452: 
  453: 		/* Discard data in case of full buffer */
  454: 		if (sc->qcount == sizeof(sc->qbuf)) {
  455: 			DPRINTF(("Buffer full, discarded packet"));
  456: 			return;
  457: 		}
  458: 
  459: 		/*
  460: 		 * The Qtronix keyboard has a built in PS/2 port for a mouse.
  461: 		 * The firmware once in a while posts a spurious button up
  462: 		 * event. This event we ignore by doing a timeout for 50 msecs.
  463: 		 * If we receive dx=dy=dz=buttons=0 before we add the event to
  464: 		 * the queue.
  465: 		 * In any other case we delete the timeout event.
  466: 		 */
  467: 		if (sc->flags & UMS_SPUR_BUT_UP &&
  468: 		    dx == 0 && dy == 0 && dz == 0 && buttons == 0) {
  469: 			usb_callout(sc->callout_handle, MS_TO_TICKS(50 /*msecs*/),
  470: 				    ums_add_to_queue_timeout, (void *) sc);
  471: 		} else {
  472: 			usb_uncallout(sc->callout_handle,
  473: 				      ums_add_to_queue_timeout, (void *) sc);
  474: 			ums_add_to_queue(sc, dx, dy, dz, buttons);
  475: 		}
  476: 	}
  477: }
  478: 
  479: Static void
  480: ums_add_to_queue_timeout(void *priv)
  481: {
  482: 	struct ums_softc *sc = priv;
  483: 	int s;
  484: 
  485: 	s = splusb();
  486: 	ums_add_to_queue(sc, 0, 0, 0, 0);
  487: 	splx(s);
  488: }
  489: 
  490: Static void
  491: ums_add_to_queue(struct ums_softc *sc, int dx, int dy, int dz, int buttons)
  492: {
  493: 	/* Discard data in case of full buffer */
  494: 	if (sc->qhead+sc->mode.packetsize > sizeof(sc->qbuf)) {
  495: 		DPRINTF(("Buffer full, discarded packet"));
  496: 		return;
  497: 	}
  498: 
  499: 	if (dx >  254)		dx =  254;
  500: 	if (dx < -256)		dx = -256;
  501: 	if (dy >  254)		dy =  254;
  502: 	if (dy < -256)		dy = -256;
  503: 	if (dz >  126)		dz =  126;
  504: 	if (dz < -128)		dz = -128;
  505: 
  506: 	sc->qbuf[sc->qhead] = sc->mode.syncmask[1];
  507: 	sc->qbuf[sc->qhead] |= ~buttons & MOUSE_MSC_BUTTONS;
  508: 	sc->qbuf[sc->qhead+1] = dx >> 1;
  509: 	sc->qbuf[sc->qhead+2] = dy >> 1;
  510: 	sc->qbuf[sc->qhead+3] = dx - (dx >> 1);
  511: 	sc->qbuf[sc->qhead+4] = dy - (dy >> 1);
  512: 
  513: 	if (sc->mode.level == 1) {
  514: 		sc->qbuf[sc->qhead+5] = dz >> 1;
  515: 		sc->qbuf[sc->qhead+6] = dz - (dz >> 1);
  516: 		sc->qbuf[sc->qhead+7] = ((~buttons >> 3)
  517: 					 & MOUSE_SYS_EXTBUTTONS);
  518: 	}
  519: 
  520: 	sc->qhead += sc->mode.packetsize;
  521: 	sc->qcount += sc->mode.packetsize;
  522: 	/* wrap round at end of buffer */
  523: 	if (sc->qhead >= sizeof(sc->qbuf))
  524: 		sc->qhead = 0;
  525: 
  526: 	/* someone waiting for data */
  527: 	if (sc->state & UMS_ASLEEP) {
  528: 		sc->state &= ~UMS_ASLEEP;
  529: 		wakeup(sc);
  530: 	}
  531: 	if (sc->state & UMS_SELECT) {
  532: 		sc->state &= ~UMS_SELECT;
  533: 		selwakeuppri(&sc->rsel, 0);
  534: 	}
  535: }
  536: Static int
  537: ums_enable(v)
  538: 	void *v;
  539: {
  540: 	struct ums_softc *sc = v;
  541: 
  542: 	usbd_status err;
  543: 
  544: 	if (sc->sc_enabled)
  545: 		return EBUSY;
  546: 
  547: 	sc->sc_enabled = 1;
  548: 	sc->qcount = 0;
  549: 	sc->qhead = sc->qtail = 0;
  550: 	sc->status.flags = 0;
  551: 	sc->status.button = sc->status.obutton = 0;
  552: 	sc->status.dx = sc->status.dy = sc->status.dz = 0;
  553: 
  554: 	callout_handle_init((struct callout_handle *)&sc->callout_handle);
  555: 
  556: 	/* Set up interrupt pipe. */
  557: 	err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr,
  558: 				USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc,
  559: 				sc->sc_ibuf, sc->sc_isize, ums_intr,
  560: 				USBD_DEFAULT_INTERVAL);
  561: 	if (err) {
  562: 		DPRINTF(("ums_enable: usbd_open_pipe_intr failed, error=%d\n",
  563: 			 err));
  564: 		sc->sc_enabled = 0;
  565: 		return (EIO);
  566: 	}
  567: 	return (0);
  568: }
  569: 
  570: Static void
  571: ums_disable(priv)
  572: 	void *priv;
  573: {
  574: 	struct ums_softc *sc = priv;
  575: 
  576: 	usb_uncallout(sc->callout_handle, ums_add_to_queue_timeout, sc);
  577: 
  578: 	/* Disable interrupts. */
  579: 	usbd_abort_pipe(sc->sc_intrpipe);
  580: 	usbd_close_pipe(sc->sc_intrpipe);
  581: 
  582: 	sc->sc_enabled = 0;
  583: 
  584: 	if (sc->qcount != 0)
  585: 		DPRINTF(("Discarded %d bytes in queue\n", sc->qcount));
  586: }
  587: 
  588: Static int
  589: ums_open(dev_t dev, int flag, int fmt, usb_proc_ptr p)
  590: {
  591: 	struct ums_softc *sc;
  592: 
  593: 	USB_GET_SC_OPEN(ums, UMSUNIT(dev), sc);
  594: 
  595: 	return ums_enable(sc);
  596: }
  597: 
  598: Static int
  599: ums_close(dev_t dev, int flag, int fmt, usb_proc_ptr p)
  600: {
  601: 	struct ums_softc *sc;
  602: 
  603: 	USB_GET_SC(ums, UMSUNIT(dev), sc);
  604: 
  605: 	if (!sc)
  606: 		return 0;
  607: 
  608: 	if (sc->sc_enabled)
  609: 		ums_disable(sc);
  610: 
  611: 	return 0;
  612: }
  613: 
  614: Static int
  615: ums_read(dev_t dev, struct uio *uio, int flag)
  616: {
  617: 	struct ums_softc *sc;
  618: 	int s;
  619: 	char buf[sizeof(sc->qbuf)];
  620: 	int l = 0;
  621: 	int error;
  622: 
  623: 	USB_GET_SC(ums, UMSUNIT(dev), sc);
  624: 
  625: 	s = splusb();
  626: 	if (!sc) {
  627: 		splx(s);
  628: 		return EIO;
  629: 	}
  630: 
  631: 	while (sc->qcount == 0 )  {
  632: 		if (flag & IO_NDELAY) {		/* non-blocking I/O */
  633: 			splx(s);
  634: 			return EWOULDBLOCK;
  635: 		}
  636: 
  637: 		sc->state |= UMS_ASLEEP;	/* blocking I/O */
  638: 		error = tsleep(sc, PCATCH, "umsrea", 0);
  639: 		if (error) {
  640: 			splx(s);
  641: 			return error;
  642: 		} else if (!sc->sc_enabled) {
  643: 			splx(s);
  644: 			return EINTR;
  645: 		}
  646: 		/* check whether the device is still there */
  647: 
  648: 		sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
  649: 		if (!sc) {
  650: 			splx(s);
  651: 			return EIO;
  652: 		}
  653: 	}
  654: 
  655: 	/*
  656: 	 * XXX we could optimise the use of splx/splusb somewhat. The writer
  657: 	 * process only extends qcount and qtail. We could copy them and use the copies
  658: 	 * to do the copying out of the queue.
  659: 	 */
  660: 
  661: 	while ((sc->qcount > 0) && (uio->uio_resid > 0)) {
  662: 		l = (sc->qcount < uio->uio_resid? sc->qcount:uio->uio_resid);
  663: 		if (l > sizeof(buf))
  664: 			l = sizeof(buf);
  665: 		if (l > sizeof(sc->qbuf) - sc->qtail)		/* transfer till end of buf */
  666: 			l = sizeof(sc->qbuf) - sc->qtail;
  667: 
  668: 		splx(s);
  669: 		uiomove(&sc->qbuf[sc->qtail], l, uio);
  670: 		s = splusb();
  671: 
  672: 		if ( sc->qcount - l < 0 ) {
  673: 			DPRINTF(("qcount below 0, count=%d l=%d\n", sc->qcount, l));
  674: 			sc->qcount = l;
  675: 		}
  676: 		sc->qcount -= l;	/* remove the bytes from the buffer */
  677: 		sc->qtail = (sc->qtail + l) % sizeof(sc->qbuf);
  678: 	}
  679: 	splx(s);
  680: 
  681: 	return 0;
  682: }
  683: 
  684: Static int
  685: ums_poll(dev_t dev, int events, usb_proc_ptr p)
  686: {
  687: 	struct ums_softc *sc;
  688: 	int revents = 0;
  689: 	int s;
  690: 
  691: 	USB_GET_SC(ums, UMSUNIT(dev), sc);
  692: 
  693: 	if (!sc)
  694: 		return 0;
  695: 
  696: 	s = splusb();
  697: 	if (events & (POLLIN | POLLRDNORM)) {
  698: 		if (sc->qcount) {
  699: 			revents = events & (POLLIN | POLLRDNORM);
  700: 		} else {
  701: 			sc->state |= UMS_SELECT;
  702: 			selrecord(p, &sc->rsel);
  703: 		}
  704: 	}
  705: 	splx(s);
  706: 
  707: 	return revents;
  708: }
  709: 
  710: int
  711: ums_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p)
  712: {
  713: 	struct ums_softc *sc;
  714: 	int error = 0;
  715: 	int s;
  716: 	mousemode_t mode;
  717: 
  718: 	USB_GET_SC(ums, UMSUNIT(dev), sc);
  719: 
  720: 	if (!sc)
  721: 		return EIO;
  722: 
  723: 	switch(cmd) {
  724: 	case MOUSE_GETHWINFO:
  725: 		*(mousehw_t *)addr = sc->hw;
  726: 		break;
  727: 	case MOUSE_GETMODE:
  728: 		*(mousemode_t *)addr = sc->mode;
  729: 		break;
  730: 	case MOUSE_SETMODE:
  731: 		mode = *(mousemode_t *)addr;
  732: 
  733: 		if (mode.level == -1)
  734: 			/* don't change the current setting */
  735: 			;
  736: 		else if ((mode.level < 0) || (mode.level > 1))
  737: 			return (EINVAL);
  738: 
  739: 		s = splusb();
  740: 		sc->mode.level = mode.level;
  741: 
  742: 		if (sc->mode.level == 0) {
  743: 			if (sc->nbuttons > MOUSE_MSC_MAXBUTTON)
  744: 				sc->hw.buttons = MOUSE_MSC_MAXBUTTON;
  745: 			else
  746: 				sc->hw.buttons = sc->nbuttons;
  747: 			sc->mode.protocol = MOUSE_PROTO_MSC;
  748: 			sc->mode.packetsize = MOUSE_MSC_PACKETSIZE;
  749: 			sc->mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
  750: 			sc->mode.syncmask[1] = MOUSE_MSC_SYNC;
  751: 		} else if (sc->mode.level == 1) {
  752: 			if (sc->nbuttons > MOUSE_SYS_MAXBUTTON)
  753: 				sc->hw.buttons = MOUSE_SYS_MAXBUTTON;
  754: 			else
  755: 				sc->hw.buttons = sc->nbuttons;
  756: 			sc->mode.protocol = MOUSE_PROTO_SYSMOUSE;
  757: 			sc->mode.packetsize = MOUSE_SYS_PACKETSIZE;
  758: 			sc->mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
  759: 			sc->mode.syncmask[1] = MOUSE_SYS_SYNC;
  760: 		}
  761: 
  762: 		bzero(sc->qbuf, sizeof(sc->qbuf));
  763: 		sc->qhead = sc->qtail = sc->qcount = 0;
  764: 		splx(s);
  765: 
  766: 		break;
  767: 	case MOUSE_GETLEVEL:
  768: 		*(int *)addr = sc->mode.level;
  769: 		break;
  770: 	case MOUSE_SETLEVEL:
  771: 		if (*(int *)addr < 0 || *(int *)addr > 1)
  772: 			return (EINVAL);
  773: 
  774: 		s = splusb();
  775: 		sc->mode.level = *(int *)addr;
  776: 
  777: 		if (sc->mode.level == 0) {
  778: 			if (sc->nbuttons > MOUSE_MSC_MAXBUTTON)
  779: 				sc->hw.buttons = MOUSE_MSC_MAXBUTTON;
  780: 			else
  781: 				sc->hw.buttons = sc->nbuttons;
  782: 			sc->mode.protocol = MOUSE_PROTO_MSC;
  783: 			sc->mode.packetsize = MOUSE_MSC_PACKETSIZE;
  784: 			sc->mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
  785: 			sc->mode.syncmask[1] = MOUSE_MSC_SYNC;
  786: 		} else if (sc->mode.level == 1) {
  787: 			if (sc->nbuttons > MOUSE_SYS_MAXBUTTON)
  788: 				sc->hw.buttons = MOUSE_SYS_MAXBUTTON;
  789: 			else
  790: 				sc->hw.buttons = sc->nbuttons;
  791: 			sc->mode.protocol = MOUSE_PROTO_SYSMOUSE;
  792: 			sc->mode.packetsize = MOUSE_SYS_PACKETSIZE;
  793: 			sc->mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
  794: 			sc->mode.syncmask[1] = MOUSE_SYS_SYNC;
  795: 		}
  796: 
  797: 		bzero(sc->qbuf, sizeof(sc->qbuf));
  798: 		sc->qhead = sc->qtail = sc->qcount = 0;
  799: 		splx(s);
  800: 
  801: 		break;
  802: 	case MOUSE_GETSTATUS: {
  803: 		mousestatus_t *status = (mousestatus_t *) addr;
  804: 
  805: 		s = splusb();
  806: 		*status = sc->status;
  807: 		sc->status.obutton = sc->status.button;
  808: 		sc->status.button = 0;
  809: 		sc->status.dx = sc->status.dy = sc->status.dz = 0;
  810: 		splx(s);
  811: 
  812: 		if (status->dx || status->dy || status->dz)
  813: 			status->flags |= MOUSE_POSCHANGED;
  814: 		if (status->button != status->obutton)
  815: 			status->flags |= MOUSE_BUTTONSCHANGED;
  816: 		break;
  817: 		}
  818: 	default:
  819: 		error = ENOTTY;
  820: 	}
  821: 
  822: 	return error;
  823: }
  824: 
  825: DRIVER_MODULE(ums, uhub, ums_driver, ums_devclass, usbd_driver_load, 0);