Home | History | Annotate | Line # | Download | only in usb
ums.c revision 1.22.4.1
      1  1.22.4.1   thorpej /*	$NetBSD: ums.c,v 1.22.4.1 1999/06/21 01:19:28 thorpej Exp $	*/
      2       1.1  augustss 
      3       1.1  augustss /*
      4       1.1  augustss  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5       1.1  augustss  * All rights reserved.
      6       1.1  augustss  *
      7      1.11  augustss  * This code is derived from software contributed to The NetBSD Foundation
      8      1.11  augustss  * by Lennart Augustsson (augustss (at) carlstedt.se) at
      9      1.11  augustss  * Carlstedt Research & Technology.
     10       1.1  augustss  *
     11       1.1  augustss  * Redistribution and use in source and binary forms, with or without
     12       1.1  augustss  * modification, are permitted provided that the following conditions
     13       1.1  augustss  * are met:
     14       1.1  augustss  * 1. Redistributions of source code must retain the above copyright
     15       1.1  augustss  *    notice, this list of conditions and the following disclaimer.
     16       1.1  augustss  * 2. Redistributions in binary form must reproduce the above copyright
     17       1.1  augustss  *    notice, this list of conditions and the following disclaimer in the
     18       1.1  augustss  *    documentation and/or other materials provided with the distribution.
     19       1.1  augustss  * 3. All advertising materials mentioning features or use of this software
     20       1.1  augustss  *    must display the following acknowledgement:
     21       1.1  augustss  *        This product includes software developed by the NetBSD
     22       1.1  augustss  *        Foundation, Inc. and its contributors.
     23       1.1  augustss  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24       1.1  augustss  *    contributors may be used to endorse or promote products derived
     25       1.1  augustss  *    from this software without specific prior written permission.
     26       1.1  augustss  *
     27       1.1  augustss  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28       1.1  augustss  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29       1.1  augustss  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30       1.1  augustss  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31       1.1  augustss  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32       1.1  augustss  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33       1.1  augustss  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34       1.1  augustss  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35       1.1  augustss  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36       1.1  augustss  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37       1.1  augustss  * POSSIBILITY OF SUCH DAMAGE.
     38      1.20  augustss  */
     39      1.20  augustss 
     40      1.20  augustss /*
     41      1.20  augustss  * HID spec: http://www.usb.org/developers/data/usbhid10.pdf
     42       1.1  augustss  */
     43       1.1  augustss 
     44       1.1  augustss #include <sys/param.h>
     45       1.1  augustss #include <sys/systm.h>
     46       1.1  augustss #include <sys/kernel.h>
     47       1.1  augustss #include <sys/malloc.h>
     48      1.16  augustss #if defined(__NetBSD__)
     49       1.1  augustss #include <sys/device.h>
     50       1.1  augustss #include <sys/ioctl.h>
     51      1.16  augustss #elif defined(__FreeBSD__)
     52      1.16  augustss #include <sys/module.h>
     53      1.16  augustss #include <sys/bus.h>
     54      1.16  augustss #include <sys/ioccom.h>
     55      1.16  augustss #include <sys/conf.h>
     56      1.16  augustss #endif
     57       1.1  augustss #include <sys/tty.h>
     58       1.1  augustss #include <sys/file.h>
     59       1.1  augustss #include <sys/select.h>
     60       1.1  augustss #include <sys/proc.h>
     61       1.1  augustss #include <sys/vnode.h>
     62       1.1  augustss #include <sys/poll.h>
     63       1.1  augustss 
     64       1.1  augustss #include <dev/usb/usb.h>
     65       1.1  augustss #include <dev/usb/usbhid.h>
     66       1.1  augustss 
     67       1.1  augustss #include <dev/usb/usbdi.h>
     68       1.1  augustss #include <dev/usb/usbdi_util.h>
     69       1.1  augustss #include <dev/usb/usbdevs.h>
     70       1.1  augustss #include <dev/usb/usb_quirks.h>
     71       1.1  augustss #include <dev/usb/hid.h>
     72       1.1  augustss 
     73      1.16  augustss #if defined(__NetBSD__)
     74       1.3  augustss #include <dev/wscons/wsconsio.h>
     75       1.3  augustss #include <dev/wscons/wsmousevar.h>
     76      1.16  augustss #elif defined(__FreeBSD__)
     77      1.16  augustss #include <machine/mouse.h>
     78      1.16  augustss #endif
     79       1.3  augustss 
     80       1.1  augustss #ifdef USB_DEBUG
     81       1.1  augustss #define DPRINTF(x)	if (umsdebug) printf x
     82       1.1  augustss #define DPRINTFN(n,x)	if (umsdebug>(n)) printf x
     83       1.1  augustss int	umsdebug = 0;
     84       1.1  augustss #else
     85       1.1  augustss #define DPRINTF(x)
     86       1.1  augustss #define DPRINTFN(n,x)
     87       1.1  augustss #endif
     88       1.1  augustss 
     89      1.16  augustss #define UMSUNIT(s)	(minor(s)&0x1f)
     90      1.16  augustss 
     91      1.16  augustss #define PS2LBUTMASK	x01
     92      1.16  augustss #define PS2RBUTMASK	x02
     93      1.16  augustss #define PS2MBUTMASK	x04
     94       1.1  augustss #define PS2BUTMASK 0x0f
     95       1.1  augustss 
     96      1.16  augustss #define QUEUE_BUFSIZE	240	/* MUST be divisible by 3 _and_ 4 */
     97      1.16  augustss 
     98       1.1  augustss struct ums_softc {
     99      1.16  augustss 	bdevice sc_dev;			/* base device */
    100       1.1  augustss 	usbd_interface_handle sc_iface;	/* interface */
    101       1.1  augustss 	usbd_pipe_handle sc_intrpipe;	/* interrupt pipe */
    102       1.1  augustss 	int sc_ep_addr;
    103       1.1  augustss 
    104       1.1  augustss 	u_char *sc_ibuf;
    105       1.1  augustss 	u_int8_t sc_iid;
    106       1.1  augustss 	int sc_isize;
    107      1.16  augustss 	struct hid_location sc_loc_x, sc_loc_y, sc_loc_z;
    108      1.16  augustss 	struct hid_location *sc_loc_btn;
    109       1.1  augustss 
    110      1.16  augustss 	int sc_enabled;
    111       1.1  augustss 	int sc_disconnected;	/* device is gone */
    112       1.3  augustss 
    113      1.16  augustss 	int flags;		/* device configuration */
    114      1.16  augustss #define UMS_Z		0x01	/* z direction available */
    115      1.16  augustss 	int nbuttons;
    116      1.21  augustss #define MAX_BUTTONS	7	/* chosen because sc_buttons is u_char */
    117      1.16  augustss 
    118      1.16  augustss #if defined(__NetBSD__)
    119      1.16  augustss 	u_char sc_buttons;	/* mouse button status */
    120       1.3  augustss 	struct device *sc_wsmousedev;
    121      1.16  augustss #elif defined(__FreeBSD__)
    122      1.16  augustss 	u_char		qbuf[QUEUE_BUFSIZE];
    123      1.21  augustss 	u_char		dummy[100];	/* XXX just for safety and for now */
    124      1.16  augustss 	int		qcount, qhead, qtail;
    125      1.16  augustss 	mousehw_t	hw;
    126      1.16  augustss 	mousemode_t	mode;
    127      1.16  augustss 	mousestatus_t	status;
    128      1.16  augustss 
    129      1.16  augustss 	int		state;
    130      1.16  augustss #	  define	UMS_ASLEEP	0x01	/* readFromDevice is waiting */
    131      1.16  augustss #	  define	UMS_SELECT	0x02	/* select is waiting */
    132      1.16  augustss 	struct selinfo	rsel;		/* process waiting in select */
    133      1.16  augustss #endif
    134       1.1  augustss };
    135       1.1  augustss 
    136       1.2  augustss #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE)
    137       1.2  augustss #define MOUSE_FLAGS (HIO_RELATIVE)
    138       1.2  augustss 
    139       1.1  augustss void ums_intr __P((usbd_request_handle, usbd_private_handle, usbd_status));
    140       1.1  augustss void ums_disco __P((void *));
    141       1.1  augustss 
    142      1.16  augustss static int	ums_enable __P((void *));
    143      1.16  augustss static void	ums_disable __P((void *));
    144      1.16  augustss 
    145      1.16  augustss #if defined(__NetBSD__)
    146      1.16  augustss static int	ums_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
    147       1.3  augustss 
    148       1.3  augustss const struct wsmouse_accessops ums_accessops = {
    149       1.3  augustss 	ums_enable,
    150       1.3  augustss 	ums_ioctl,
    151       1.3  augustss 	ums_disable,
    152       1.3  augustss };
    153       1.3  augustss 
    154      1.16  augustss #elif defined(__FreeBSD__)
    155      1.16  augustss static d_open_t ums_open;
    156      1.16  augustss static d_close_t ums_close;
    157      1.16  augustss static d_read_t ums_read;
    158      1.16  augustss static d_ioctl_t ums_ioctl;
    159      1.16  augustss static d_poll_t ums_poll;
    160      1.16  augustss 
    161      1.19  augustss #define UMS_CDEV_MAJOR	111
    162      1.16  augustss 
    163      1.16  augustss static struct  cdevsw ums_cdevsw = {
    164      1.16  augustss 	ums_open,	ums_close,	ums_read,	nowrite,
    165      1.16  augustss 	ums_ioctl,	nostop,		nullreset,	nodevtotty,
    166      1.16  augustss 	ums_poll,	nommap,
    167      1.19  augustss 	NULL,		"ums",		NULL,		-1
    168      1.16  augustss };
    169      1.16  augustss #endif
    170       1.1  augustss 
    171      1.16  augustss USB_DECLARE_DRIVER(ums);
    172       1.1  augustss 
    173      1.16  augustss USB_MATCH(ums)
    174       1.1  augustss {
    175      1.16  augustss 	USB_MATCH_START(ums, uaa);
    176       1.1  augustss 	usb_interface_descriptor_t *id;
    177       1.1  augustss 	int size, ret;
    178       1.1  augustss 	void *desc;
    179       1.1  augustss 	usbd_status r;
    180       1.1  augustss 
    181       1.1  augustss 	if (!uaa->iface)
    182       1.1  augustss 		return (UMATCH_NONE);
    183       1.1  augustss 	id = usbd_get_interface_descriptor(uaa->iface);
    184      1.14  augustss 	if (!id || id->bInterfaceClass != UCLASS_HID)
    185       1.1  augustss 		return (UMATCH_NONE);
    186       1.1  augustss 
    187       1.1  augustss 	r = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_TEMP);
    188       1.1  augustss 	if (r != USBD_NORMAL_COMPLETION)
    189       1.1  augustss 		return (UMATCH_NONE);
    190       1.1  augustss 
    191       1.1  augustss 	if (hid_is_collection(desc, size,
    192       1.1  augustss 			      HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
    193       1.1  augustss 		ret = UMATCH_IFACECLASS;
    194       1.1  augustss 	else
    195       1.1  augustss 		ret = UMATCH_NONE;
    196       1.1  augustss 
    197       1.1  augustss 	free(desc, M_TEMP);
    198       1.1  augustss 	return (ret);
    199       1.1  augustss }
    200       1.1  augustss 
    201      1.16  augustss USB_ATTACH(ums)
    202       1.1  augustss {
    203      1.16  augustss 	USB_ATTACH_START(ums, sc, uaa);
    204       1.1  augustss 	usbd_interface_handle iface = uaa->iface;
    205       1.1  augustss 	usb_interface_descriptor_t *id;
    206       1.1  augustss 	usb_endpoint_descriptor_t *ed;
    207      1.19  augustss #if defined(__NetBSD__)
    208       1.3  augustss 	struct wsmousedev_attach_args a;
    209      1.19  augustss #endif
    210       1.1  augustss 	int size;
    211       1.1  augustss 	void *desc;
    212       1.1  augustss 	usbd_status r;
    213       1.1  augustss 	char devinfo[1024];
    214       1.2  augustss 	u_int32_t flags;
    215      1.16  augustss 	int i;
    216      1.16  augustss 	struct hid_location loc_btn;
    217       1.1  augustss 
    218       1.1  augustss 	sc->sc_disconnected = 1;
    219       1.1  augustss 	sc->sc_iface = iface;
    220       1.1  augustss 	id = usbd_get_interface_descriptor(iface);
    221       1.1  augustss 	usbd_devinfo(uaa->device, 0, devinfo);
    222      1.16  augustss 	USB_ATTACH_SETUP;
    223      1.16  augustss 	printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
    224      1.12  augustss 	       devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
    225       1.1  augustss 	ed = usbd_interface2endpoint_descriptor(iface, 0);
    226       1.1  augustss 	if (!ed) {
    227       1.1  augustss 		printf("%s: could not read endpoint descriptor\n",
    228      1.16  augustss 		       USBDEVNAME(sc->sc_dev));
    229      1.16  augustss 		USB_ATTACH_ERROR_RETURN;
    230       1.1  augustss 	}
    231       1.1  augustss 
    232      1.15  augustss 	DPRINTFN(10,("ums_attach: bLength=%d bDescriptorType=%d "
    233      1.15  augustss 		     "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
    234      1.15  augustss 		     " bInterval=%d\n",
    235      1.15  augustss 		     ed->bLength, ed->bDescriptorType,
    236      1.15  augustss 		     ed->bEndpointAddress & UE_ADDR,
    237      1.15  augustss 		     ed->bEndpointAddress & UE_IN ? "in" : "out",
    238      1.15  augustss 		     ed->bmAttributes & UE_XFERTYPE,
    239      1.15  augustss 		     UGETW(ed->wMaxPacketSize), ed->bInterval));
    240       1.1  augustss 
    241       1.1  augustss 	if ((ed->bEndpointAddress & UE_IN) != UE_IN ||
    242       1.1  augustss 	    (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
    243       1.1  augustss 		printf("%s: unexpected endpoint\n",
    244      1.16  augustss 		       USBDEVNAME(sc->sc_dev));
    245      1.16  augustss 		USB_ATTACH_ERROR_RETURN;
    246       1.1  augustss 	}
    247       1.1  augustss 
    248       1.1  augustss 	r = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_TEMP);
    249       1.1  augustss 	if (r != USBD_NORMAL_COMPLETION)
    250      1.16  augustss 		USB_ATTACH_ERROR_RETURN;
    251      1.16  augustss 
    252       1.2  augustss 	if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
    253       1.2  augustss 		       hid_input, &sc->sc_loc_x, &flags)) {
    254      1.16  augustss 		printf("%s: mouse has no X report\n", USBDEVNAME(sc->sc_dev));
    255      1.16  augustss 		USB_ATTACH_ERROR_RETURN;
    256      1.16  augustss 	}
    257      1.16  augustss 	if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
    258      1.16  augustss 		printf("%s: X report 0x%04x not supported\n",
    259      1.16  augustss 		       USBDEVNAME(sc->sc_dev), flags);
    260      1.16  augustss 		USB_ATTACH_ERROR_RETURN;
    261       1.1  augustss 	}
    262      1.10  augustss 
    263       1.2  augustss 	if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
    264       1.2  augustss 		       hid_input, &sc->sc_loc_y, &flags)) {
    265      1.16  augustss 		printf("%s: mouse has no Y report\n", USBDEVNAME(sc->sc_dev));
    266      1.16  augustss 		USB_ATTACH_ERROR_RETURN;
    267      1.16  augustss 	}
    268      1.16  augustss 	if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
    269      1.16  augustss 		printf("%s: Y report 0x%04x not supported\n",
    270      1.16  augustss 		       USBDEVNAME(sc->sc_dev), flags);
    271      1.16  augustss 		USB_ATTACH_ERROR_RETURN;
    272       1.1  augustss 	}
    273      1.10  augustss 
    274      1.22  augustss 	/* Try to guess the Z activator: first check Z, then WHEEL. */
    275       1.6  augustss 	if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z),
    276       1.6  augustss 		       hid_input, &sc->sc_loc_z, &flags) ||
    277       1.6  augustss 	    hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL),
    278       1.6  augustss 		       hid_input, &sc->sc_loc_z, &flags)) {
    279      1.16  augustss 		if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
    280      1.16  augustss 			sc->sc_loc_z.size = 0;	/* Bad Z coord, ignore it */
    281      1.16  augustss 		} else {
    282      1.16  augustss 			sc->flags |= UMS_Z;
    283      1.16  augustss 		}
    284       1.6  augustss 	}
    285       1.6  augustss 
    286      1.21  augustss 	/* figure out the number of buttons */
    287      1.21  augustss 	for (i = 1; i <= MAX_BUTTONS; i++)
    288      1.16  augustss 		if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
    289      1.16  augustss 				hid_input, &loc_btn, 0))
    290      1.16  augustss 			break;
    291      1.16  augustss 	sc->nbuttons = i - 1;
    292      1.16  augustss 	sc->sc_loc_btn = malloc(sizeof(struct hid_location)*sc->nbuttons,
    293      1.16  augustss 				M_USBDEV, M_NOWAIT);
    294      1.22  augustss 	if (!sc->sc_loc_btn) {
    295      1.22  augustss 		printf("%s: no memory\n", USBDEVNAME(sc->sc_dev));
    296      1.16  augustss 		USB_ATTACH_ERROR_RETURN;
    297      1.22  augustss 	}
    298      1.16  augustss 
    299      1.16  augustss 	printf("%s: %d buttons%s\n", USBDEVNAME(sc->sc_dev),
    300      1.22  augustss 	       sc->nbuttons, sc->flags & UMS_Z ? " and Z dir." : "");
    301      1.16  augustss 
    302      1.16  augustss 	for (i = 1; i <= sc->nbuttons; i++)
    303      1.16  augustss 		hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
    304      1.16  augustss 				hid_input, &sc->sc_loc_btn[i-1], 0);
    305       1.1  augustss 
    306       1.1  augustss 	sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid);
    307       1.1  augustss 	sc->sc_ibuf = malloc(sc->sc_isize, M_USB, M_NOWAIT);
    308      1.16  augustss 	if (!sc->sc_ibuf) {
    309      1.22  augustss 		printf("%s: no memory\n", USBDEVNAME(sc->sc_dev));
    310      1.16  augustss 		free(sc->sc_loc_btn, M_USB);
    311      1.16  augustss 		USB_ATTACH_ERROR_RETURN;
    312      1.16  augustss 	}
    313       1.1  augustss 
    314       1.1  augustss 	sc->sc_ep_addr = ed->bEndpointAddress;
    315       1.1  augustss 	sc->sc_disconnected = 0;
    316       1.1  augustss 	free(desc, M_TEMP);
    317       1.3  augustss 
    318      1.16  augustss #ifdef USB_DEBUG
    319      1.16  augustss 	DPRINTF(("ums_attach: sc=%p\n", sc));
    320      1.16  augustss 	DPRINTF(("ums_attach: X\t%d/%d\n",
    321      1.16  augustss 		 sc->sc_loc_x.pos, sc->sc_loc_x.size));
    322      1.16  augustss 	DPRINTF(("ums_attach: Y\t%d/%d\n",
    323      1.16  augustss 		 sc->sc_loc_x.pos, sc->sc_loc_x.size));
    324      1.16  augustss 	if (sc->flags & UMS_Z)
    325      1.16  augustss 		DPRINTF(("ums_attach: Z\t%d/%d\n",
    326      1.16  augustss 			 sc->sc_loc_z.pos, sc->sc_loc_z.size));
    327      1.16  augustss 	for (i = 1; i <= sc->nbuttons; i++) {
    328      1.16  augustss 		DPRINTF(("ums_attach: B%d\t%d/%d\n",
    329      1.16  augustss 			 i, sc->sc_loc_btn[i-1].pos,sc->sc_loc_btn[i-1].size));
    330      1.16  augustss 	}
    331      1.16  augustss 	DPRINTF(("ums_attach: size=%d, id=%d\n", sc->sc_isize, sc->sc_iid));
    332      1.16  augustss #endif
    333      1.16  augustss 
    334      1.16  augustss #if defined(__NetBSD__)
    335       1.3  augustss 	a.accessops = &ums_accessops;
    336       1.3  augustss 	a.accesscookie = sc;
    337       1.3  augustss 
    338       1.3  augustss 	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
    339      1.16  augustss #elif defined(__FreeBSD__)
    340      1.16  augustss 	sc->hw.buttons = 2;		/* XXX hw&mode values are bogus */
    341      1.16  augustss 	sc->hw.iftype = MOUSE_IF_PS2;
    342      1.16  augustss 	sc->hw.type = MOUSE_MOUSE;
    343      1.16  augustss 	if (sc->flags & UMS_Z)
    344      1.16  augustss 		sc->hw.model = MOUSE_MODEL_INTELLI;
    345      1.16  augustss 	else
    346      1.16  augustss 		sc->hw.model = MOUSE_MODEL_GENERIC;
    347      1.16  augustss 	sc->hw.hwid = 0;
    348      1.16  augustss 	sc->mode.protocol = MOUSE_PROTO_PS2;
    349      1.16  augustss 	sc->mode.rate = -1;
    350      1.16  augustss 	sc->mode.resolution = MOUSE_RES_DEFAULT;
    351      1.16  augustss 	sc->mode.accelfactor = 1;
    352      1.16  augustss 	sc->mode.level = 0;
    353      1.16  augustss 	if (sc->flags & UMS_Z) {
    354      1.16  augustss 		sc->mode.packetsize = MOUSE_INTELLI_PACKETSIZE;
    355      1.16  augustss 		sc->mode.syncmask[0] = 0xc8;
    356      1.16  augustss 	} else {
    357      1.16  augustss 		sc->mode.packetsize = MOUSE_PS2_PACKETSIZE;
    358      1.16  augustss 		sc->mode.syncmask[0] = 0xc0;
    359      1.16  augustss 	}
    360      1.16  augustss 	sc->mode.syncmask[1] = 0;
    361      1.16  augustss 
    362      1.16  augustss 	sc->status.flags = 0;
    363      1.16  augustss 	sc->status.button = sc->status.obutton = 0;
    364      1.16  augustss 	sc->status.dx = sc->status.dy = sc->status.dz = 0;
    365      1.16  augustss 
    366      1.16  augustss 	sc->rsel.si_flags = 0;
    367      1.16  augustss 	sc->rsel.si_pid = 0;
    368      1.16  augustss #endif
    369      1.16  augustss 
    370      1.16  augustss 	USB_ATTACH_SUCCESS_RETURN;
    371      1.16  augustss }
    372      1.16  augustss 
    373      1.16  augustss 
    374      1.16  augustss #if defined(__FreeBSD__)
    375      1.16  augustss static int
    376      1.16  augustss ums_detach(device_t self)
    377      1.16  augustss {
    378      1.16  augustss 	struct ums_softc *sc = device_get_softc(self);
    379      1.16  augustss 	char *devinfo = (char *) device_get_desc(self);
    380      1.16  augustss 
    381      1.16  augustss 	if (devinfo) {
    382      1.16  augustss 		device_set_desc(self, NULL);
    383      1.16  augustss 		free(devinfo, M_USB);
    384      1.16  augustss 	}
    385      1.16  augustss 	free(sc->sc_loc_btn, M_USB);
    386      1.16  augustss 	free(sc->sc_ibuf, M_USB);
    387      1.16  augustss 
    388      1.16  augustss 	return 0;
    389       1.1  augustss }
    390      1.16  augustss #endif
    391       1.1  augustss 
    392       1.1  augustss void
    393       1.1  augustss ums_disco(p)
    394       1.1  augustss 	void *p;
    395       1.1  augustss {
    396       1.1  augustss 	struct ums_softc *sc = p;
    397       1.8  augustss 
    398       1.8  augustss 	DPRINTF(("ums_disco: sc=%p\n", sc));
    399       1.8  augustss 	usbd_abort_pipe(sc->sc_intrpipe);
    400       1.1  augustss 	sc->sc_disconnected = 1;
    401       1.1  augustss }
    402       1.1  augustss 
    403       1.1  augustss void
    404       1.1  augustss ums_intr(reqh, addr, status)
    405       1.1  augustss 	usbd_request_handle reqh;
    406       1.1  augustss 	usbd_private_handle addr;
    407       1.1  augustss 	usbd_status status;
    408       1.1  augustss {
    409       1.1  augustss 	struct ums_softc *sc = addr;
    410       1.1  augustss 	u_char *ibuf;
    411       1.6  augustss 	int dx, dy, dz;
    412      1.16  augustss 	u_char buttons = 0;
    413      1.16  augustss 	int i;
    414  1.22.4.1   thorpej 	int s;
    415      1.21  augustss 
    416      1.16  augustss #if defined(__NetBSD__)
    417      1.16  augustss #define UMS_BUT(i) ((i) == 1 || (i) == 2 ? 3 - (i) : i)
    418      1.16  augustss #elif defined(__FreeBSD__)
    419      1.16  augustss #define UMS_BUT(i) (i)
    420      1.16  augustss #endif
    421       1.1  augustss 
    422       1.1  augustss 	DPRINTFN(5, ("ums_intr: sc=%p status=%d\n", sc, status));
    423       1.1  augustss 	DPRINTFN(5, ("ums_intr: data = %02x %02x %02x\n",
    424       1.1  augustss 		     sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2]));
    425       1.1  augustss 
    426       1.1  augustss 	if (status == USBD_CANCELLED)
    427       1.1  augustss 		return;
    428       1.1  augustss 
    429       1.1  augustss 	if (status != USBD_NORMAL_COMPLETION) {
    430       1.1  augustss 		DPRINTF(("ums_intr: status=%d\n", status));
    431       1.7  augustss 		usbd_clear_endpoint_stall_async(sc->sc_intrpipe);
    432       1.1  augustss 		return;
    433       1.1  augustss 	}
    434       1.1  augustss 
    435       1.1  augustss 	ibuf = sc->sc_ibuf;
    436       1.1  augustss 	if (sc->sc_iid) {
    437       1.1  augustss 		if (*ibuf++ != sc->sc_iid)
    438       1.1  augustss 			return;
    439       1.1  augustss 	}
    440       1.1  augustss 	dx =  hid_get_data(ibuf, &sc->sc_loc_x);
    441       1.1  augustss 	dy = -hid_get_data(ibuf, &sc->sc_loc_y);
    442       1.6  augustss 	dz =  hid_get_data(ibuf, &sc->sc_loc_z);
    443      1.16  augustss 	for (i = 0; i < sc->nbuttons; i++)
    444      1.16  augustss 		if (hid_get_data(ibuf, &sc->sc_loc_btn[i]))
    445      1.16  augustss 			buttons |= (1 << UMS_BUT(i));
    446       1.4  augustss 
    447      1.16  augustss #if defined(__NetBSD__)
    448      1.22  augustss 	if (dx || dy || dz || buttons != sc->sc_buttons) {
    449      1.16  augustss 		DPRINTFN(10, ("ums_intr: x:%d y:%d z:%d buttons:0x%x\n",
    450      1.16  augustss 			dx, dy, dz, buttons));
    451       1.4  augustss 		sc->sc_buttons = buttons;
    452  1.22.4.1   thorpej 		if (sc->sc_wsmousedev) {
    453  1.22.4.1   thorpej 			s = spltty();
    454       1.6  augustss 			wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, dz);
    455  1.22.4.1   thorpej 			splx(s);
    456  1.22.4.1   thorpej 		}
    457      1.16  augustss #elif defined(__FreeBSD__)
    458      1.22  augustss 	if (dx || dy || dz || buttons != sc->status.button) {
    459      1.16  augustss 		DPRINTFN(10, ("ums_intr: x:%d y:%d z:%d buttons:0x%x\n",
    460      1.16  augustss 			dx, dy, dz, buttons));
    461      1.16  augustss 
    462      1.16  augustss 		sc->status.button = buttons;
    463      1.16  augustss 		sc->status.dx += dx;
    464      1.16  augustss 		sc->status.dy += dy;
    465      1.16  augustss 		sc->status.dz += dz;
    466      1.16  augustss 
    467      1.16  augustss 		/* Discard data in case of full buffer */
    468      1.16  augustss 		if (sc->qcount == sizeof(sc->qbuf)) {
    469      1.16  augustss 			DPRINTF(("Buffer full, discarded packet"));
    470      1.16  augustss 			return;
    471      1.16  augustss 		}
    472      1.16  augustss 
    473      1.16  augustss 		sc->qbuf[sc->qhead] = MOUSE_PS2_SYNC;
    474      1.16  augustss 		if (dx < 0)
    475      1.16  augustss 			sc->qbuf[sc->qhead] |= MOUSE_PS2_XNEG;
    476      1.16  augustss 		if (dx > 255 || dx < -255)
    477      1.16  augustss 			sc->qbuf[sc->qhead] |= MOUSE_PS2_XOVERFLOW;
    478      1.16  augustss 		if (dy < 0)
    479      1.16  augustss 			sc->qbuf[sc->qhead] |= MOUSE_PS2_YNEG;
    480      1.16  augustss 		if (dy > 255 || dy < -255)
    481      1.16  augustss 			sc->qbuf[sc->qhead] |= MOUSE_PS2_YOVERFLOW;
    482      1.16  augustss 		sc->qbuf[sc->qhead++] |= buttons;
    483      1.16  augustss 		sc->qbuf[sc->qhead++] = dx;
    484      1.16  augustss 		sc->qbuf[sc->qhead++] = dy;
    485      1.16  augustss 		sc->qcount += 3;
    486      1.16  augustss 		if (sc->flags & UMS_Z) {
    487      1.16  augustss 			sc->qbuf[sc->qhead++] = dz;
    488      1.16  augustss 			sc->qcount++;
    489      1.16  augustss 		}
    490      1.16  augustss #ifdef USB_DEBUG
    491      1.16  augustss 		if (sc->qhead > sizeof(sc->qbuf))
    492      1.16  augustss 			DPRINTF(("Buffer overrun! %d %d\n",
    493      1.16  augustss 				 sc->qhead, sizeof(sc->qbuf)));
    494      1.16  augustss #endif
    495      1.16  augustss 		/* wrap round at end of buffer */
    496      1.16  augustss 		if (sc->qhead >= sizeof(sc->qbuf))
    497      1.16  augustss 			sc->qhead = 0;
    498      1.16  augustss 
    499      1.16  augustss 		/* someone waiting for data */
    500      1.16  augustss 		if (sc->state & UMS_ASLEEP)
    501      1.16  augustss 			wakeup(sc);
    502      1.16  augustss 		/* wake up any pending selects */
    503      1.16  augustss 		selwakeup(&sc->rsel);
    504      1.16  augustss 		sc->state &= ~UMS_SELECT;
    505      1.16  augustss #endif
    506       1.1  augustss 	}
    507       1.1  augustss }
    508       1.3  augustss 
    509      1.16  augustss 
    510      1.16  augustss static int
    511       1.3  augustss ums_enable(v)
    512       1.3  augustss 	void *v;
    513       1.3  augustss {
    514       1.3  augustss 	struct ums_softc *sc = v;
    515      1.16  augustss 
    516       1.3  augustss 	usbd_status r;
    517       1.3  augustss 
    518       1.3  augustss 	if (sc->sc_enabled)
    519       1.3  augustss 		return EBUSY;
    520       1.3  augustss 
    521       1.3  augustss 	sc->sc_enabled = 1;
    522      1.16  augustss #if defined(__NetBSD__)
    523       1.4  augustss 	sc->sc_buttons = 0;
    524      1.16  augustss #elif defined(__FreeBSD__)
    525      1.16  augustss 	sc->qcount = 0;
    526      1.16  augustss 	sc->qhead = sc->qtail = 0;
    527      1.16  augustss #ifdef USB_DEBUG
    528      1.16  augustss 	if (sizeof(sc->qbuf) % 4 || sizeof(sc->qbuf) % 3) {
    529      1.16  augustss 		DPRINTF(("Buffer size not divisible by 3 or 4\n"));
    530      1.16  augustss 		return ENXIO;
    531      1.16  augustss 	}
    532      1.16  augustss #endif
    533      1.16  augustss 	sc->status.flags = 0;
    534      1.16  augustss 	sc->status.button = sc->status.obutton = 0;
    535      1.16  augustss 	sc->status.dx = sc->status.dy = sc->status.dz = 0;
    536      1.16  augustss #endif
    537       1.3  augustss 
    538       1.3  augustss 	/* Set up interrupt pipe. */
    539       1.3  augustss 	r = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr,
    540       1.3  augustss 				USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc,
    541       1.3  augustss 				sc->sc_ibuf, sc->sc_isize, ums_intr);
    542       1.3  augustss 	if (r != USBD_NORMAL_COMPLETION) {
    543       1.3  augustss 		DPRINTF(("ums_enable: usbd_open_pipe_intr failed, error=%d\n",
    544       1.3  augustss 			 r));
    545       1.3  augustss 		sc->sc_enabled = 0;
    546       1.3  augustss 		return (EIO);
    547       1.3  augustss 	}
    548       1.3  augustss 	usbd_set_disco(sc->sc_intrpipe, ums_disco, sc);
    549       1.3  augustss 	return (0);
    550       1.3  augustss }
    551       1.3  augustss 
    552      1.16  augustss static void
    553       1.3  augustss ums_disable(v)
    554       1.3  augustss 	void *v;
    555       1.3  augustss {
    556       1.3  augustss 	struct ums_softc *sc = v;
    557       1.3  augustss 
    558       1.3  augustss 	/* Disable interrupts. */
    559       1.3  augustss 	usbd_abort_pipe(sc->sc_intrpipe);
    560       1.3  augustss 	usbd_close_pipe(sc->sc_intrpipe);
    561       1.3  augustss 
    562       1.3  augustss 	sc->sc_enabled = 0;
    563      1.16  augustss 
    564      1.16  augustss #if defined(USBVERBOSE) && defined(__FreeBSD__)
    565      1.16  augustss 	if (sc->qcount != 0)
    566      1.16  augustss 		DPRINTF(("Discarded %d bytes in queue\n", sc->qcount));
    567      1.16  augustss #endif
    568       1.3  augustss }
    569       1.3  augustss 
    570      1.16  augustss #if defined(__NetBSD__)
    571      1.16  augustss static int
    572       1.3  augustss ums_ioctl(v, cmd, data, flag, p)
    573       1.3  augustss 	void *v;
    574       1.3  augustss 	u_long cmd;
    575       1.3  augustss 	caddr_t data;
    576       1.3  augustss 	int flag;
    577       1.3  augustss 	struct proc *p;
    578      1.16  augustss 
    579       1.3  augustss {
    580       1.3  augustss 	switch (cmd) {
    581       1.3  augustss 	case WSMOUSEIO_GTYPE:
    582      1.17  augustss 		*(u_int *)data = WSMOUSE_TYPE_USB;
    583       1.3  augustss 		return (0);
    584       1.3  augustss 	}
    585      1.16  augustss 
    586       1.3  augustss 	return (-1);
    587       1.3  augustss }
    588      1.16  augustss 
    589      1.16  augustss #elif defined(__FreeBSD__)
    590      1.16  augustss static int
    591      1.16  augustss ums_open(dev_t dev, int flag, int fmt, struct proc *p)
    592      1.16  augustss {
    593      1.16  augustss 	struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
    594      1.16  augustss 
    595      1.16  augustss 	if (!sc) {
    596      1.16  augustss 		DPRINTF(("sc not found at open"));
    597      1.16  augustss 		return EINVAL;
    598      1.16  augustss 	}
    599      1.16  augustss 
    600      1.16  augustss 	return ums_enable(sc);
    601      1.16  augustss }
    602      1.16  augustss 
    603      1.16  augustss static int
    604      1.16  augustss ums_close(dev_t dev, int flag, int fmt, struct proc *p)
    605      1.16  augustss {
    606      1.16  augustss 	struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
    607      1.16  augustss 
    608      1.16  augustss 	if (!sc) {
    609      1.16  augustss 		DPRINTF(("sc not found at close"));
    610      1.16  augustss 		return EINVAL;
    611      1.16  augustss 	}
    612      1.16  augustss 
    613      1.16  augustss 	if (sc->sc_enabled)
    614      1.16  augustss 		ums_disable(sc);
    615      1.16  augustss 	return 0;
    616      1.16  augustss }
    617      1.16  augustss 
    618      1.16  augustss static int
    619      1.16  augustss ums_read(dev_t dev, struct uio *uio, int flag)
    620      1.16  augustss {
    621      1.16  augustss 	struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
    622      1.16  augustss 	int s;
    623      1.16  augustss 	char buf[sizeof(sc->qbuf)];
    624      1.16  augustss 	int l = 0;
    625      1.16  augustss 	int error;
    626      1.16  augustss 
    627      1.16  augustss 	if (!sc || !sc->sc_enabled) {
    628      1.16  augustss 		DPRINTF(("sc not found at read"));
    629      1.16  augustss 		return EINVAL;
    630      1.16  augustss 	}
    631      1.16  augustss 
    632      1.16  augustss 	s = splusb();
    633      1.16  augustss 	while (sc->qcount == 0 )  {
    634      1.16  augustss 		/* NWH XXX non blocking I/O ??
    635      1.16  augustss 		if (non blocking I/O ) {
    636      1.16  augustss 			splx(s);
    637      1.16  augustss 			return EWOULDBLOCK;
    638      1.16  augustss 		} else {
    639      1.16  augustss 		*/
    640      1.16  augustss 		sc->state |= UMS_ASLEEP;
    641      1.16  augustss 		error = tsleep(sc, PZERO | PCATCH, "umsrea", 0);
    642      1.16  augustss 		sc->state &= ~UMS_ASLEEP;
    643      1.16  augustss 		if (error) {
    644      1.16  augustss 			splx(s);
    645      1.16  augustss 			return error;
    646      1.16  augustss 		}
    647      1.16  augustss 	}
    648      1.16  augustss 
    649      1.16  augustss 	while ((sc->qcount > 0) && (uio->uio_resid > 0)) {
    650      1.16  augustss 		l = (sc->qcount < uio->uio_resid? sc->qcount:uio->uio_resid);
    651      1.16  augustss 		if (l > sizeof(buf))
    652      1.16  augustss 			l = sizeof(buf);
    653      1.16  augustss 		if (l > sizeof(sc->qbuf) - sc->qtail)		/* transfer till end of buf */
    654      1.16  augustss 			l = sizeof(sc->qbuf) - sc->qtail;
    655      1.16  augustss 
    656      1.16  augustss 		splx(s);
    657      1.16  augustss 		uiomove(&sc->qbuf[sc->qtail], l, uio);
    658      1.16  augustss 		s = splusb();
    659      1.16  augustss 
    660      1.16  augustss 		if ( sc->qcount - l < 0 ) {
    661      1.16  augustss 			DPRINTF(("qcount below 0, count=%d l=%d\n", sc->qcount, l));
    662      1.16  augustss 			sc->qcount = l;
    663      1.16  augustss 		}
    664      1.16  augustss 		sc->qcount -= l;	/* remove the bytes from the buffer */
    665      1.16  augustss 		sc->qtail = (sc->qtail + l) % sizeof(sc->qbuf);
    666      1.16  augustss 	}
    667      1.16  augustss 	splx(s);
    668      1.16  augustss 
    669      1.16  augustss 	return 0;
    670      1.16  augustss }
    671      1.16  augustss 
    672      1.16  augustss static int
    673      1.16  augustss ums_poll(dev_t dev, int events, struct proc *p)
    674      1.16  augustss {
    675      1.16  augustss 	struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
    676      1.16  augustss 	int revents = 0;
    677      1.16  augustss 	int s;
    678      1.16  augustss 
    679      1.16  augustss 	if (!sc) {
    680      1.16  augustss 		DPRINTF(("sc not found at poll"));
    681      1.16  augustss 		return 0;	/* just to make sure */
    682      1.16  augustss 	}
    683      1.16  augustss 
    684      1.16  augustss 	s = splusb();
    685      1.16  augustss 	if (events & (POLLIN | POLLRDNORM))
    686      1.16  augustss 		if (sc->qcount) {
    687      1.16  augustss 			revents = events & (POLLIN | POLLRDNORM);
    688      1.16  augustss 		} else {
    689      1.16  augustss 			sc->state |= UMS_SELECT;
    690      1.16  augustss 			selrecord(p, &sc->rsel);
    691      1.16  augustss 		}
    692      1.16  augustss 	splx(s);
    693      1.16  augustss 
    694      1.16  augustss 	return revents;
    695      1.16  augustss }
    696      1.22  augustss 
    697      1.16  augustss int
    698      1.16  augustss ums_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
    699      1.16  augustss {
    700      1.16  augustss 	struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
    701      1.16  augustss 	int error = 0;
    702      1.16  augustss 	int s;
    703      1.16  augustss 
    704      1.16  augustss 	if (!sc) {
    705      1.16  augustss 		DPRINTF(("sc not found at ioctl"));
    706      1.21  augustss 		return (ENOENT);
    707      1.16  augustss 	}
    708      1.16  augustss 
    709      1.16  augustss 	switch(cmd) {
    710      1.16  augustss 	case MOUSE_GETHWINFO:
    711      1.16  augustss 		*(mousehw_t *)addr = sc->hw;
    712      1.16  augustss 		break;
    713      1.16  augustss 	case MOUSE_GETMODE:
    714      1.16  augustss 		*(mousemode_t *)addr = sc->mode;
    715      1.16  augustss 		break;
    716      1.16  augustss 	case MOUSE_GETLEVEL:
    717      1.16  augustss 		*(int *)addr = sc->mode.level;
    718      1.16  augustss 		break;
    719      1.16  augustss 	case MOUSE_GETSTATUS: {
    720      1.16  augustss 		mousestatus_t *status = (mousestatus_t *) addr;
    721      1.16  augustss 
    722      1.16  augustss 		s = splusb();
    723      1.16  augustss 		*status = sc->status;
    724      1.16  augustss 		sc->status.obutton = sc->status.button;
    725      1.16  augustss 		sc->status.button = 0;
    726      1.16  augustss 		sc->status.dx = sc->status.dy = sc->status.dz = 0;
    727      1.16  augustss 		splx(s);
    728      1.16  augustss 
    729      1.16  augustss 		if (status->dx || status->dy || status->dz)
    730      1.16  augustss 			status->flags |= MOUSE_POSCHANGED;
    731      1.16  augustss 		if (status->button != status->obutton)
    732      1.16  augustss 			status->flags |= MOUSE_BUTTONSCHANGED;
    733      1.16  augustss 		break;
    734      1.16  augustss 		}
    735      1.16  augustss 	default:
    736      1.16  augustss 		error = ENOTTY;
    737      1.16  augustss 	}
    738      1.16  augustss 
    739      1.16  augustss 	return error;
    740      1.16  augustss }
    741      1.16  augustss #endif
    742      1.16  augustss 
    743      1.16  augustss #if defined(__FreeBSD__)
    744      1.16  augustss CDEV_DRIVER_MODULE(ums, usb, ums_driver, ums_devclass,
    745      1.19  augustss 			UMS_CDEV_MAJOR, ums_cdevsw, usbd_driver_load, 0);
    746      1.16  augustss #endif
    747