ums.c revision 356020
1179065Sjb/*-
2179065Sjb * Copyright (c) 1998 The NetBSD Foundation, Inc.
3319182Sngie * All rights reserved.
4179065Sjb *
5262818Smarcel * This code is derived from software contributed to The NetBSD Foundation
6262818Smarcel * by Lennart Augustsson (lennart@augustsson.net) at
7179065Sjb * Carlstedt Research & Technology.
8179065Sjb *
9179065Sjb * Redistribution and use in source and binary forms, with or without
10179065Sjb * modification, are permitted provided that the following conditions
11262818Smarcel * are met:
12262818Smarcel * 1. Redistributions of source code must retain the above copyright
13316210Sgnn *    notice, this list of conditions and the following disclaimer.
14262818Smarcel * 2. Redistributions in binary form must reproduce the above copyright
15179065Sjb *    notice, this list of conditions and the following disclaimer in the
16179065Sjb *    documentation and/or other materials provided with the distribution.
17253996Savg *
18262818Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/11/sys/dev/usb/input/ums.c 356020 2019-12-22 19:06:45Z kevans $");
33
34/*
35 * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
36 */
37
38#include "opt_evdev.h"
39
40#include <sys/stdint.h>
41#include <sys/stddef.h>
42#include <sys/param.h>
43#include <sys/queue.h>
44#include <sys/types.h>
45#include <sys/systm.h>
46#include <sys/kernel.h>
47#include <sys/bus.h>
48#include <sys/module.h>
49#include <sys/lock.h>
50#include <sys/mutex.h>
51#include <sys/condvar.h>
52#include <sys/sysctl.h>
53#include <sys/sx.h>
54#include <sys/unistd.h>
55#include <sys/callout.h>
56#include <sys/malloc.h>
57#include <sys/priv.h>
58#include <sys/conf.h>
59#include <sys/fcntl.h>
60#include <sys/sbuf.h>
61
62#include <dev/usb/usb.h>
63#include <dev/usb/usbdi.h>
64#include <dev/usb/usbdi_util.h>
65#include <dev/usb/usbhid.h>
66#include "usbdevs.h"
67
68#define	USB_DEBUG_VAR ums_debug
69#include <dev/usb/usb_debug.h>
70
71#include <dev/usb/quirk/usb_quirk.h>
72
73#ifdef EVDEV_SUPPORT
74#include <dev/evdev/input.h>
75#include <dev/evdev/evdev.h>
76#endif
77
78#include <sys/ioccom.h>
79#include <sys/filio.h>
80#include <sys/mouse.h>
81
82#ifdef USB_DEBUG
83static int ums_debug = 0;
84
85static SYSCTL_NODE(_hw_usb, OID_AUTO, ums, CTLFLAG_RW, 0, "USB ums");
86SYSCTL_INT(_hw_usb_ums, OID_AUTO, debug, CTLFLAG_RWTUN,
87    &ums_debug, 0, "Debug level");
88#endif
89
90#define	MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE)
91#define	MOUSE_FLAGS (HIO_RELATIVE)
92
93#define	UMS_BUF_SIZE      8		/* bytes */
94#define	UMS_IFQ_MAXLEN   50		/* units */
95#define	UMS_BUTTON_MAX   31		/* exclusive, must be less than 32 */
96#define	UMS_BUT(i) ((i) < 3 ? (((i) + 2) % 3) : (i))
97#define	UMS_INFO_MAX	  2		/* maximum number of HID sets */
98
99enum {
100	UMS_INTR_DT,
101	UMS_N_TRANSFER,
102};
103
104struct ums_info {
105	struct hid_location sc_loc_w;
106	struct hid_location sc_loc_x;
107	struct hid_location sc_loc_y;
108	struct hid_location sc_loc_z;
109	struct hid_location sc_loc_t;
110	struct hid_location sc_loc_btn[UMS_BUTTON_MAX];
111
112	uint32_t sc_flags;
113#define	UMS_FLAG_X_AXIS     0x0001
114#define	UMS_FLAG_Y_AXIS     0x0002
115#define	UMS_FLAG_Z_AXIS     0x0004
116#define	UMS_FLAG_T_AXIS     0x0008
117#define	UMS_FLAG_SBU        0x0010	/* spurious button up events */
118#define	UMS_FLAG_REVZ	    0x0020	/* Z-axis is reversed */
119#define	UMS_FLAG_W_AXIS     0x0040
120
121	uint8_t	sc_iid_w;
122	uint8_t	sc_iid_x;
123	uint8_t	sc_iid_y;
124	uint8_t	sc_iid_z;
125	uint8_t	sc_iid_t;
126	uint8_t	sc_iid_btn[UMS_BUTTON_MAX];
127	uint8_t	sc_buttons;
128};
129
130struct ums_softc {
131	struct usb_fifo_sc sc_fifo;
132	struct mtx sc_mtx;
133	struct usb_callout sc_callout;
134	struct ums_info sc_info[UMS_INFO_MAX];
135
136	mousehw_t sc_hw;
137	mousemode_t sc_mode;
138	mousestatus_t sc_status;
139
140	struct usb_xfer *sc_xfer[UMS_N_TRANSFER];
141
142	int sc_pollrate;
143	int sc_fflags;
144#ifdef EVDEV_SUPPORT
145	int sc_evflags;
146#define	UMS_EVDEV_OPENED	1
147#endif
148
149	uint8_t	sc_buttons;
150	uint8_t	sc_iid;
151	uint8_t	sc_temp[64];
152
153#ifdef EVDEV_SUPPORT
154	struct evdev_dev *sc_evdev;
155#endif
156};
157
158static void ums_put_queue_timeout(void *__sc);
159
160static usb_callback_t ums_intr_callback;
161
162static device_probe_t ums_probe;
163static device_attach_t ums_attach;
164static device_detach_t ums_detach;
165
166static usb_fifo_cmd_t ums_fifo_start_read;
167static usb_fifo_cmd_t ums_fifo_stop_read;
168static usb_fifo_open_t ums_fifo_open;
169static usb_fifo_close_t ums_fifo_close;
170static usb_fifo_ioctl_t ums_fifo_ioctl;
171
172#ifdef EVDEV_SUPPORT
173static evdev_open_t ums_ev_open;
174static evdev_close_t ums_ev_close;
175static void ums_evdev_push(struct ums_softc *, int32_t, int32_t,
176    int32_t, int32_t, int32_t);
177#endif
178
179static void	ums_start_rx(struct ums_softc *);
180static void	ums_stop_rx(struct ums_softc *);
181static void	ums_put_queue(struct ums_softc *, int32_t, int32_t,
182		    int32_t, int32_t, int32_t);
183static int	ums_sysctl_handler_parseinfo(SYSCTL_HANDLER_ARGS);
184
185static struct usb_fifo_methods ums_fifo_methods = {
186	.f_open = &ums_fifo_open,
187	.f_close = &ums_fifo_close,
188	.f_ioctl = &ums_fifo_ioctl,
189	.f_start_read = &ums_fifo_start_read,
190	.f_stop_read = &ums_fifo_stop_read,
191	.basename[0] = "ums",
192};
193
194#ifdef EVDEV_SUPPORT
195static const struct evdev_methods ums_evdev_methods = {
196	.ev_open = &ums_ev_open,
197	.ev_close = &ums_ev_close,
198};
199#endif
200
201static void
202ums_put_queue_timeout(void *__sc)
203{
204	struct ums_softc *sc = __sc;
205
206	mtx_assert(&sc->sc_mtx, MA_OWNED);
207
208	ums_put_queue(sc, 0, 0, 0, 0, 0);
209#ifdef EVDEV_SUPPORT
210	ums_evdev_push(sc, 0, 0, 0, 0, 0);
211#endif
212}
213
214static void
215ums_intr_callback(struct usb_xfer *xfer, usb_error_t error)
216{
217	struct ums_softc *sc = usbd_xfer_softc(xfer);
218	struct ums_info *info = &sc->sc_info[0];
219	struct usb_page_cache *pc;
220	uint8_t *buf = sc->sc_temp;
221	int32_t buttons = 0;
222	int32_t buttons_found = 0;
223#ifdef EVDEV_SUPPORT
224	int32_t buttons_reported = 0;
225#endif
226	int32_t dw = 0;
227	int32_t dx = 0;
228	int32_t dy = 0;
229	int32_t dz = 0;
230	int32_t dt = 0;
231	uint8_t i;
232	uint8_t id;
233	int len;
234
235	usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
236
237	switch (USB_GET_STATE(xfer)) {
238	case USB_ST_TRANSFERRED:
239		DPRINTFN(6, "sc=%p actlen=%d\n", sc, len);
240
241		if (len > (int)sizeof(sc->sc_temp)) {
242			DPRINTFN(6, "truncating large packet to %zu bytes\n",
243			    sizeof(sc->sc_temp));
244			len = sizeof(sc->sc_temp);
245		}
246		if (len == 0)
247			goto tr_setup;
248
249		pc = usbd_xfer_get_frame(xfer, 0);
250		usbd_copy_out(pc, 0, buf, len);
251
252		DPRINTFN(6, "data = %02x %02x %02x %02x "
253		    "%02x %02x %02x %02x\n",
254		    (len > 0) ? buf[0] : 0, (len > 1) ? buf[1] : 0,
255		    (len > 2) ? buf[2] : 0, (len > 3) ? buf[3] : 0,
256		    (len > 4) ? buf[4] : 0, (len > 5) ? buf[5] : 0,
257		    (len > 6) ? buf[6] : 0, (len > 7) ? buf[7] : 0);
258
259		if (sc->sc_iid) {
260			id = *buf;
261
262			len--;
263			buf++;
264
265		} else {
266			id = 0;
267			if (sc->sc_info[0].sc_flags & UMS_FLAG_SBU) {
268				if ((*buf == 0x14) || (*buf == 0x15)) {
269					goto tr_setup;
270				}
271			}
272		}
273
274	repeat:
275		if ((info->sc_flags & UMS_FLAG_W_AXIS) &&
276		    (id == info->sc_iid_w))
277			dw += hid_get_data(buf, len, &info->sc_loc_w);
278
279		if ((info->sc_flags & UMS_FLAG_X_AXIS) &&
280		    (id == info->sc_iid_x))
281			dx += hid_get_data(buf, len, &info->sc_loc_x);
282
283		if ((info->sc_flags & UMS_FLAG_Y_AXIS) &&
284		    (id == info->sc_iid_y))
285			dy -= hid_get_data(buf, len, &info->sc_loc_y);
286
287		if ((info->sc_flags & UMS_FLAG_Z_AXIS) &&
288		    (id == info->sc_iid_z)) {
289			int32_t temp;
290			temp = hid_get_data(buf, len, &info->sc_loc_z);
291			if (info->sc_flags & UMS_FLAG_REVZ)
292				temp = -temp;
293			dz -= temp;
294		}
295
296		if ((info->sc_flags & UMS_FLAG_T_AXIS) &&
297		    (id == info->sc_iid_t)) {
298			dt += hid_get_data(buf, len, &info->sc_loc_t);
299			/* T-axis is translated into button presses */
300			buttons_found |= (1UL << 5) | (1UL << 6);
301		}
302
303		for (i = 0; i < info->sc_buttons; i++) {
304			uint32_t mask;
305			mask = 1UL << UMS_BUT(i);
306			/* check for correct button ID */
307			if (id != info->sc_iid_btn[i])
308				continue;
309			/* check for button pressed */
310			if (hid_get_data(buf, len, &info->sc_loc_btn[i]))
311				buttons |= mask;
312			/* register button mask */
313			buttons_found |= mask;
314		}
315
316		if (++info != &sc->sc_info[UMS_INFO_MAX])
317			goto repeat;
318
319#ifdef EVDEV_SUPPORT
320		buttons_reported = buttons;
321#endif
322		/* keep old button value(s) for non-detected buttons */
323		buttons |= sc->sc_status.button & ~buttons_found;
324
325		if (dx || dy || dz || dt || dw ||
326		    (buttons != sc->sc_status.button)) {
327
328			DPRINTFN(6, "x:%d y:%d z:%d t:%d w:%d buttons:0x%08x\n",
329			    dx, dy, dz, dt, dw, buttons);
330
331			/* translate T-axis into button presses until further */
332			if (dt > 0) {
333				ums_put_queue(sc, 0, 0, 0, 0, buttons);
334				buttons |= 1UL << 6;
335			} else if (dt < 0) {
336				ums_put_queue(sc, 0, 0, 0, 0, buttons);
337				buttons |= 1UL << 5;
338			}
339
340			sc->sc_status.button = buttons;
341			sc->sc_status.dx += dx;
342			sc->sc_status.dy += dy;
343			sc->sc_status.dz += dz;
344			/*
345			 * sc->sc_status.dt += dt;
346			 * no way to export this yet
347			 */
348
349			/*
350		         * The Qtronix keyboard has a built in PS/2
351		         * port for a mouse.  The firmware once in a
352		         * while posts a spurious button up
353		         * event. This event we ignore by doing a
354		         * timeout for 50 msecs.  If we receive
355		         * dx=dy=dz=buttons=0 before we add the event
356		         * to the queue.  In any other case we delete
357		         * the timeout event.
358		         */
359			if ((sc->sc_info[0].sc_flags & UMS_FLAG_SBU) &&
360			    (dx == 0) && (dy == 0) && (dz == 0) && (dt == 0) &&
361			    (dw == 0) && (buttons == 0)) {
362
363				usb_callout_reset(&sc->sc_callout, hz / 20,
364				    &ums_put_queue_timeout, sc);
365			} else {
366
367				usb_callout_stop(&sc->sc_callout);
368
369				ums_put_queue(sc, dx, dy, dz, dt, buttons);
370#ifdef EVDEV_SUPPORT
371				ums_evdev_push(sc, dx, dy, dz, dt,
372				    buttons_reported);
373#endif
374
375			}
376		}
377	case USB_ST_SETUP:
378tr_setup:
379		/* check if we can put more data into the FIFO */
380		if (usb_fifo_put_bytes_max(sc->sc_fifo.fp[USB_FIFO_RX]) == 0) {
381#ifdef EVDEV_SUPPORT
382			if (sc->sc_evflags == 0)
383				break;
384#else
385			break;
386#endif
387		}
388
389		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
390		usbd_transfer_submit(xfer);
391		break;
392
393	default:			/* Error */
394		if (error != USB_ERR_CANCELLED) {
395			/* try clear stall first */
396			usbd_xfer_set_stall(xfer);
397			goto tr_setup;
398		}
399		break;
400	}
401}
402
403static const struct usb_config ums_config[UMS_N_TRANSFER] = {
404
405	[UMS_INTR_DT] = {
406		.type = UE_INTERRUPT,
407		.endpoint = UE_ADDR_ANY,
408		.direction = UE_DIR_IN,
409		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
410		.bufsize = 0,	/* use wMaxPacketSize */
411		.callback = &ums_intr_callback,
412	},
413};
414
415/* A match on these entries will load ums */
416static const STRUCT_USB_HOST_ID __used ums_devs[] = {
417	{USB_IFACE_CLASS(UICLASS_HID),
418	 USB_IFACE_SUBCLASS(UISUBCLASS_BOOT),
419	 USB_IFACE_PROTOCOL(UIPROTO_MOUSE),},
420};
421
422static int
423ums_probe(device_t dev)
424{
425	struct usb_attach_arg *uaa = device_get_ivars(dev);
426	void *d_ptr;
427	int error;
428	uint16_t d_len;
429
430	DPRINTFN(11, "\n");
431
432	if (uaa->usb_mode != USB_MODE_HOST)
433		return (ENXIO);
434
435	if (uaa->info.bInterfaceClass != UICLASS_HID)
436		return (ENXIO);
437
438	if (usb_test_quirk(uaa, UQ_UMS_IGNORE))
439		return (ENXIO);
440
441	if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
442	    (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE))
443		return (BUS_PROBE_DEFAULT);
444
445	error = usbd_req_get_hid_desc(uaa->device, NULL,
446	    &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex);
447
448	if (error)
449		return (ENXIO);
450
451	if (hid_is_mouse(d_ptr, d_len))
452		error = BUS_PROBE_DEFAULT;
453	else
454		error = ENXIO;
455
456	free(d_ptr, M_TEMP);
457	return (error);
458}
459
460static void
461ums_hid_parse(struct ums_softc *sc, device_t dev, const uint8_t *buf,
462    uint16_t len, uint8_t index)
463{
464	struct ums_info *info = &sc->sc_info[index];
465	uint32_t flags;
466	uint8_t i;
467	uint8_t j;
468
469	if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
470	    hid_input, index, &info->sc_loc_x, &flags, &info->sc_iid_x)) {
471
472		if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
473			info->sc_flags |= UMS_FLAG_X_AXIS;
474		}
475	}
476	if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
477	    hid_input, index, &info->sc_loc_y, &flags, &info->sc_iid_y)) {
478
479		if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
480			info->sc_flags |= UMS_FLAG_Y_AXIS;
481		}
482	}
483	/* Try the wheel first as the Z activator since it's tradition. */
484	if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
485	    HUG_WHEEL), hid_input, index, &info->sc_loc_z, &flags,
486	    &info->sc_iid_z) ||
487	    hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
488	    HUG_TWHEEL), hid_input, index, &info->sc_loc_z, &flags,
489	    &info->sc_iid_z)) {
490		if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
491			info->sc_flags |= UMS_FLAG_Z_AXIS;
492		}
493		/*
494		 * We might have both a wheel and Z direction, if so put
495		 * put the Z on the W coordinate.
496		 */
497		if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
498		    HUG_Z), hid_input, index, &info->sc_loc_w, &flags,
499		    &info->sc_iid_w)) {
500
501			if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
502				info->sc_flags |= UMS_FLAG_W_AXIS;
503			}
504		}
505	} else if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
506	    HUG_Z), hid_input, index, &info->sc_loc_z, &flags,
507	    &info->sc_iid_z)) {
508
509		if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
510			info->sc_flags |= UMS_FLAG_Z_AXIS;
511		}
512	}
513	/*
514	 * The Microsoft Wireless Intellimouse 2.0 reports it's wheel
515	 * using 0x0048, which is HUG_TWHEEL, and seems to expect you
516	 * to know that the byte after the wheel is the tilt axis.
517	 * There are no other HID axis descriptors other than X,Y and
518	 * TWHEEL
519	 */
520	if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
521	    HUG_TWHEEL), hid_input, index, &info->sc_loc_t,
522	    &flags, &info->sc_iid_t)) {
523
524		info->sc_loc_t.pos += 8;
525
526		if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
527			info->sc_flags |= UMS_FLAG_T_AXIS;
528		}
529	} else if (hid_locate(buf, len, HID_USAGE2(HUP_CONSUMER,
530		HUC_AC_PAN), hid_input, index, &info->sc_loc_t,
531		&flags, &info->sc_iid_t)) {
532
533		if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS)
534			info->sc_flags |= UMS_FLAG_T_AXIS;
535	}
536	/* figure out the number of buttons */
537
538	for (i = 0; i < UMS_BUTTON_MAX; i++) {
539		if (!hid_locate(buf, len, HID_USAGE2(HUP_BUTTON, (i + 1)),
540		    hid_input, index, &info->sc_loc_btn[i], NULL,
541		    &info->sc_iid_btn[i])) {
542			break;
543		}
544	}
545
546	/* detect other buttons */
547
548	for (j = 0; (i < UMS_BUTTON_MAX) && (j < 2); i++, j++) {
549		if (!hid_locate(buf, len, HID_USAGE2(HUP_MICROSOFT, (j + 1)),
550		    hid_input, index, &info->sc_loc_btn[i], NULL,
551		    &info->sc_iid_btn[i])) {
552			break;
553		}
554	}
555
556	info->sc_buttons = i;
557
558	if (i > sc->sc_buttons)
559		sc->sc_buttons = i;
560
561	if (info->sc_flags == 0)
562		return;
563
564	/* announce information about the mouse */
565	device_printf(dev, "%d buttons and [%s%s%s%s%s] coordinates ID=%u\n",
566	    (info->sc_buttons),
567	    (info->sc_flags & UMS_FLAG_X_AXIS) ? "X" : "",
568	    (info->sc_flags & UMS_FLAG_Y_AXIS) ? "Y" : "",
569	    (info->sc_flags & UMS_FLAG_Z_AXIS) ? "Z" : "",
570	    (info->sc_flags & UMS_FLAG_T_AXIS) ? "T" : "",
571	    (info->sc_flags & UMS_FLAG_W_AXIS) ? "W" : "",
572	    info->sc_iid_x);
573}
574
575static int
576ums_attach(device_t dev)
577{
578	struct usb_attach_arg *uaa = device_get_ivars(dev);
579	struct ums_softc *sc = device_get_softc(dev);
580	struct ums_info *info;
581	void *d_ptr = NULL;
582	int isize;
583	int err;
584	uint16_t d_len;
585	uint8_t i;
586#ifdef USB_DEBUG
587	uint8_t j;
588#endif
589
590	DPRINTFN(11, "sc=%p\n", sc);
591
592	device_set_usb_desc(dev);
593
594	mtx_init(&sc->sc_mtx, "ums lock", NULL, MTX_DEF | MTX_RECURSE);
595
596	usb_callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0);
597
598	/*
599         * Force the report (non-boot) protocol.
600         *
601         * Mice without boot protocol support may choose not to implement
602         * Set_Protocol at all; Ignore any error.
603         */
604	err = usbd_req_set_protocol(uaa->device, NULL,
605	    uaa->info.bIfaceIndex, 1);
606
607	err = usbd_transfer_setup(uaa->device,
608	    &uaa->info.bIfaceIndex, sc->sc_xfer, ums_config,
609	    UMS_N_TRANSFER, sc, &sc->sc_mtx);
610
611	if (err) {
612		DPRINTF("error=%s\n", usbd_errstr(err));
613		goto detach;
614	}
615
616	/* Get HID descriptor */
617	err = usbd_req_get_hid_desc(uaa->device, NULL, &d_ptr,
618	    &d_len, M_TEMP, uaa->info.bIfaceIndex);
619
620	if (err) {
621		device_printf(dev, "error reading report description\n");
622		goto detach;
623	}
624
625	isize = hid_report_size(d_ptr, d_len, hid_input, &sc->sc_iid);
626
627	/*
628	 * The Microsoft Wireless Notebook Optical Mouse seems to be in worse
629	 * shape than the Wireless Intellimouse 2.0, as its X, Y, wheel, and
630	 * all of its other button positions are all off. It also reports that
631	 * it has two additional buttons and a tilt wheel.
632	 */
633	if (usb_test_quirk(uaa, UQ_MS_BAD_CLASS)) {
634
635		sc->sc_iid = 0;
636
637		info = &sc->sc_info[0];
638		info->sc_flags = (UMS_FLAG_X_AXIS |
639		    UMS_FLAG_Y_AXIS |
640		    UMS_FLAG_Z_AXIS |
641		    UMS_FLAG_SBU);
642		info->sc_buttons = 3;
643		isize = 5;
644		/* 1st byte of descriptor report contains garbage */
645		info->sc_loc_x.pos = 16;
646		info->sc_loc_x.size = 8;
647		info->sc_loc_y.pos = 24;
648		info->sc_loc_y.size = 8;
649		info->sc_loc_z.pos = 32;
650		info->sc_loc_z.size = 8;
651		info->sc_loc_btn[0].pos = 8;
652		info->sc_loc_btn[0].size = 1;
653		info->sc_loc_btn[1].pos = 9;
654		info->sc_loc_btn[1].size = 1;
655		info->sc_loc_btn[2].pos = 10;
656		info->sc_loc_btn[2].size = 1;
657
658		/* Announce device */
659		device_printf(dev, "3 buttons and [XYZ] "
660		    "coordinates ID=0\n");
661
662	} else {
663		/* Search the HID descriptor and announce device */
664		for (i = 0; i < UMS_INFO_MAX; i++) {
665			ums_hid_parse(sc, dev, d_ptr, d_len, i);
666		}
667	}
668
669	if (usb_test_quirk(uaa, UQ_MS_REVZ)) {
670		info = &sc->sc_info[0];
671		/* Some wheels need the Z axis reversed. */
672		info->sc_flags |= UMS_FLAG_REVZ;
673	}
674	if (isize > (int)usbd_xfer_max_framelen(sc->sc_xfer[UMS_INTR_DT])) {
675		DPRINTF("WARNING: report size, %d bytes, is larger "
676		    "than interrupt size, %d bytes!\n", isize,
677		    usbd_xfer_max_framelen(sc->sc_xfer[UMS_INTR_DT]));
678	}
679	free(d_ptr, M_TEMP);
680	d_ptr = NULL;
681
682#ifdef USB_DEBUG
683	for (j = 0; j < UMS_INFO_MAX; j++) {
684		info = &sc->sc_info[j];
685
686		DPRINTF("sc=%p, index=%d\n", sc, j);
687		DPRINTF("X\t%d/%d id=%d\n", info->sc_loc_x.pos,
688		    info->sc_loc_x.size, info->sc_iid_x);
689		DPRINTF("Y\t%d/%d id=%d\n", info->sc_loc_y.pos,
690		    info->sc_loc_y.size, info->sc_iid_y);
691		DPRINTF("Z\t%d/%d id=%d\n", info->sc_loc_z.pos,
692		    info->sc_loc_z.size, info->sc_iid_z);
693		DPRINTF("T\t%d/%d id=%d\n", info->sc_loc_t.pos,
694		    info->sc_loc_t.size, info->sc_iid_t);
695		DPRINTF("W\t%d/%d id=%d\n", info->sc_loc_w.pos,
696		    info->sc_loc_w.size, info->sc_iid_w);
697
698		for (i = 0; i < info->sc_buttons; i++) {
699			DPRINTF("B%d\t%d/%d id=%d\n",
700			    i + 1, info->sc_loc_btn[i].pos,
701			    info->sc_loc_btn[i].size, info->sc_iid_btn[i]);
702		}
703	}
704	DPRINTF("size=%d, id=%d\n", isize, sc->sc_iid);
705#endif
706
707	err = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx,
708	    &ums_fifo_methods, &sc->sc_fifo,
709	    device_get_unit(dev), -1, uaa->info.bIfaceIndex,
710  	    UID_ROOT, GID_OPERATOR, 0644);
711	if (err)
712		goto detach;
713
714#ifdef EVDEV_SUPPORT
715	sc->sc_evdev = evdev_alloc();
716	evdev_set_name(sc->sc_evdev, device_get_desc(dev));
717	evdev_set_phys(sc->sc_evdev, device_get_nameunit(dev));
718	evdev_set_id(sc->sc_evdev, BUS_USB, uaa->info.idVendor,
719	    uaa->info.idProduct, 0);
720	evdev_set_serial(sc->sc_evdev, usb_get_serial(uaa->device));
721	evdev_set_methods(sc->sc_evdev, sc, &ums_evdev_methods);
722	evdev_support_prop(sc->sc_evdev, INPUT_PROP_POINTER);
723	evdev_support_event(sc->sc_evdev, EV_SYN);
724	evdev_support_event(sc->sc_evdev, EV_REL);
725	evdev_support_event(sc->sc_evdev, EV_KEY);
726
727	info = &sc->sc_info[0];
728
729	if (info->sc_flags & UMS_FLAG_X_AXIS)
730		evdev_support_rel(sc->sc_evdev, REL_X);
731
732	if (info->sc_flags & UMS_FLAG_Y_AXIS)
733		evdev_support_rel(sc->sc_evdev, REL_Y);
734
735	if (info->sc_flags & UMS_FLAG_Z_AXIS)
736		evdev_support_rel(sc->sc_evdev, REL_WHEEL);
737
738	if (info->sc_flags & UMS_FLAG_T_AXIS)
739		evdev_support_rel(sc->sc_evdev, REL_HWHEEL);
740
741	for (i = 0; i < info->sc_buttons; i++)
742		evdev_support_key(sc->sc_evdev, BTN_MOUSE + i);
743
744	err = evdev_register_mtx(sc->sc_evdev, &sc->sc_mtx);
745	if (err)
746		goto detach;
747#endif
748
749	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
750	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
751	    OID_AUTO, "parseinfo", CTLTYPE_STRING|CTLFLAG_RD,
752	    sc, 0, ums_sysctl_handler_parseinfo,
753	    "", "Dump of parsed HID report descriptor");
754
755	return (0);
756
757detach:
758	if (d_ptr) {
759		free(d_ptr, M_TEMP);
760	}
761	ums_detach(dev);
762	return (ENOMEM);
763}
764
765static int
766ums_detach(device_t self)
767{
768	struct ums_softc *sc = device_get_softc(self);
769
770	DPRINTF("sc=%p\n", sc);
771
772	usb_fifo_detach(&sc->sc_fifo);
773
774#ifdef EVDEV_SUPPORT
775	evdev_free(sc->sc_evdev);
776#endif
777
778	usbd_transfer_unsetup(sc->sc_xfer, UMS_N_TRANSFER);
779
780	usb_callout_drain(&sc->sc_callout);
781
782	mtx_destroy(&sc->sc_mtx);
783
784	return (0);
785}
786
787static void
788ums_reset(struct ums_softc *sc)
789{
790
791	/* reset all USB mouse parameters */
792
793	if (sc->sc_buttons > MOUSE_MSC_MAXBUTTON)
794		sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON;
795	else
796		sc->sc_hw.buttons = sc->sc_buttons;
797
798	sc->sc_hw.iftype = MOUSE_IF_USB;
799	sc->sc_hw.type = MOUSE_MOUSE;
800	sc->sc_hw.model = MOUSE_MODEL_GENERIC;
801	sc->sc_hw.hwid = 0;
802
803	sc->sc_mode.protocol = MOUSE_PROTO_MSC;
804	sc->sc_mode.rate = -1;
805	sc->sc_mode.resolution = MOUSE_RES_UNKNOWN;
806	sc->sc_mode.accelfactor = 0;
807	sc->sc_mode.level = 0;
808	sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
809	sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
810	sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
811
812	/* reset status */
813
814	sc->sc_status.flags = 0;
815	sc->sc_status.button = 0;
816	sc->sc_status.obutton = 0;
817	sc->sc_status.dx = 0;
818	sc->sc_status.dy = 0;
819	sc->sc_status.dz = 0;
820	/* sc->sc_status.dt = 0; */
821}
822
823static void
824ums_start_rx(struct ums_softc *sc)
825{
826	int rate;
827
828	/* Check if we should override the default polling interval */
829	rate = sc->sc_pollrate;
830	/* Range check rate */
831	if (rate > 1000)
832		rate = 1000;
833	/* Check for set rate */
834	if ((rate > 0) && (sc->sc_xfer[UMS_INTR_DT] != NULL)) {
835		DPRINTF("Setting pollrate = %d\n", rate);
836		/* Stop current transfer, if any */
837		usbd_transfer_stop(sc->sc_xfer[UMS_INTR_DT]);
838		/* Set new interval */
839		usbd_xfer_set_interval(sc->sc_xfer[UMS_INTR_DT], 1000 / rate);
840		/* Only set pollrate once */
841		sc->sc_pollrate = 0;
842	}
843
844	usbd_transfer_start(sc->sc_xfer[UMS_INTR_DT]);
845}
846
847static void
848ums_stop_rx(struct ums_softc *sc)
849{
850	usbd_transfer_stop(sc->sc_xfer[UMS_INTR_DT]);
851	usb_callout_stop(&sc->sc_callout);
852}
853
854static void
855ums_fifo_start_read(struct usb_fifo *fifo)
856{
857	struct ums_softc *sc = usb_fifo_softc(fifo);
858
859	ums_start_rx(sc);
860}
861
862static void
863ums_fifo_stop_read(struct usb_fifo *fifo)
864{
865	struct ums_softc *sc = usb_fifo_softc(fifo);
866
867	ums_stop_rx(sc);
868}
869
870
871#if ((MOUSE_SYS_PACKETSIZE != 8) || \
872     (MOUSE_MSC_PACKETSIZE != 5))
873#error "Software assumptions are not met. Please update code."
874#endif
875
876static void
877ums_put_queue(struct ums_softc *sc, int32_t dx, int32_t dy,
878    int32_t dz, int32_t dt, int32_t buttons)
879{
880	uint8_t buf[8];
881
882	if (1) {
883
884		if (dx > 254)
885			dx = 254;
886		if (dx < -256)
887			dx = -256;
888		if (dy > 254)
889			dy = 254;
890		if (dy < -256)
891			dy = -256;
892		if (dz > 126)
893			dz = 126;
894		if (dz < -128)
895			dz = -128;
896		if (dt > 126)
897			dt = 126;
898		if (dt < -128)
899			dt = -128;
900
901		buf[0] = sc->sc_mode.syncmask[1];
902		buf[0] |= (~buttons) & MOUSE_MSC_BUTTONS;
903		buf[1] = dx >> 1;
904		buf[2] = dy >> 1;
905		buf[3] = dx - (dx >> 1);
906		buf[4] = dy - (dy >> 1);
907
908		if (sc->sc_mode.level == 1) {
909			buf[5] = dz >> 1;
910			buf[6] = dz - (dz >> 1);
911			buf[7] = (((~buttons) >> 3) & MOUSE_SYS_EXTBUTTONS);
912		}
913		usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf,
914		    sc->sc_mode.packetsize, 1);
915	} else {
916		DPRINTF("Buffer full, discarded packet\n");
917	}
918}
919
920#ifdef EVDEV_SUPPORT
921static void
922ums_evdev_push(struct ums_softc *sc, int32_t dx, int32_t dy,
923    int32_t dz, int32_t dt, int32_t buttons)
924{
925	if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) {
926		/* Push evdev event */
927		evdev_push_rel(sc->sc_evdev, REL_X, dx);
928		evdev_push_rel(sc->sc_evdev, REL_Y, -dy);
929		evdev_push_rel(sc->sc_evdev, REL_WHEEL, -dz);
930		evdev_push_rel(sc->sc_evdev, REL_HWHEEL, dt);
931		evdev_push_mouse_btn(sc->sc_evdev,
932		    (buttons & ~MOUSE_STDBUTTONS) |
933		    (buttons & (1 << 2) ? MOUSE_BUTTON1DOWN : 0) |
934		    (buttons & (1 << 1) ? MOUSE_BUTTON2DOWN : 0) |
935		    (buttons & (1 << 0) ? MOUSE_BUTTON3DOWN : 0));
936		evdev_sync(sc->sc_evdev);
937	}
938}
939#endif
940
941static void
942ums_reset_buf(struct ums_softc *sc)
943{
944	/* reset read queue, must be called locked */
945	usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]);
946}
947
948#ifdef EVDEV_SUPPORT
949static int
950ums_ev_open(struct evdev_dev *evdev, void *ev_softc)
951{
952	struct ums_softc *sc = (struct ums_softc *)ev_softc;
953
954	mtx_assert(&sc->sc_mtx, MA_OWNED);
955
956	sc->sc_evflags = UMS_EVDEV_OPENED;
957
958	if (sc->sc_fflags == 0) {
959		ums_reset(sc);
960		ums_start_rx(sc);
961	}
962
963	return (0);
964}
965
966static void
967ums_ev_close(struct evdev_dev *evdev, void *ev_softc)
968{
969	struct ums_softc *sc = (struct ums_softc *)ev_softc;
970
971	mtx_assert(&sc->sc_mtx, MA_OWNED);
972
973	sc->sc_evflags = 0;
974
975	if (sc->sc_fflags == 0)
976		ums_stop_rx(sc);
977}
978#endif
979
980static int
981ums_fifo_open(struct usb_fifo *fifo, int fflags)
982{
983	struct ums_softc *sc = usb_fifo_softc(fifo);
984
985	DPRINTFN(2, "\n");
986
987	/* check for duplicate open, should not happen */
988	if (sc->sc_fflags & fflags)
989		return (EBUSY);
990
991	/* check for first open */
992#ifdef EVDEV_SUPPORT
993	if (sc->sc_fflags == 0 && sc->sc_evflags == 0)
994		ums_reset(sc);
995#else
996	if (sc->sc_fflags == 0)
997		ums_reset(sc);
998#endif
999
1000	if (fflags & FREAD) {
1001		/* allocate RX buffer */
1002		if (usb_fifo_alloc_buffer(fifo,
1003		    UMS_BUF_SIZE, UMS_IFQ_MAXLEN)) {
1004			return (ENOMEM);
1005		}
1006	}
1007
1008	sc->sc_fflags |= fflags & (FREAD | FWRITE);
1009	return (0);
1010}
1011
1012static void
1013ums_fifo_close(struct usb_fifo *fifo, int fflags)
1014{
1015	struct ums_softc *sc = usb_fifo_softc(fifo);
1016
1017	DPRINTFN(2, "\n");
1018
1019	if (fflags & FREAD)
1020		usb_fifo_free_buffer(fifo);
1021
1022	sc->sc_fflags &= ~(fflags & (FREAD | FWRITE));
1023}
1024
1025static int
1026ums_fifo_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags)
1027{
1028	struct ums_softc *sc = usb_fifo_softc(fifo);
1029	mousemode_t mode;
1030	int error = 0;
1031
1032	DPRINTFN(2, "\n");
1033
1034	mtx_lock(&sc->sc_mtx);
1035
1036	switch (cmd) {
1037	case MOUSE_GETHWINFO:
1038		*(mousehw_t *)addr = sc->sc_hw;
1039		break;
1040
1041	case MOUSE_GETMODE:
1042		*(mousemode_t *)addr = sc->sc_mode;
1043		break;
1044
1045	case MOUSE_SETMODE:
1046		mode = *(mousemode_t *)addr;
1047
1048		if (mode.level == -1) {
1049			/* don't change the current setting */
1050		} else if ((mode.level < 0) || (mode.level > 1)) {
1051			error = EINVAL;
1052			break;
1053		} else {
1054			sc->sc_mode.level = mode.level;
1055		}
1056
1057		/* store polling rate */
1058		sc->sc_pollrate = mode.rate;
1059
1060		if (sc->sc_mode.level == 0) {
1061			if (sc->sc_buttons > MOUSE_MSC_MAXBUTTON)
1062				sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON;
1063			else
1064				sc->sc_hw.buttons = sc->sc_buttons;
1065			sc->sc_mode.protocol = MOUSE_PROTO_MSC;
1066			sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
1067			sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
1068			sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
1069		} else if (sc->sc_mode.level == 1) {
1070			if (sc->sc_buttons > MOUSE_SYS_MAXBUTTON)
1071				sc->sc_hw.buttons = MOUSE_SYS_MAXBUTTON;
1072			else
1073				sc->sc_hw.buttons = sc->sc_buttons;
1074			sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
1075			sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
1076			sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
1077			sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC;
1078		}
1079		ums_reset_buf(sc);
1080		break;
1081
1082	case MOUSE_GETLEVEL:
1083		*(int *)addr = sc->sc_mode.level;
1084		break;
1085
1086	case MOUSE_SETLEVEL:
1087		if (*(int *)addr < 0 || *(int *)addr > 1) {
1088			error = EINVAL;
1089			break;
1090		}
1091		sc->sc_mode.level = *(int *)addr;
1092
1093		if (sc->sc_mode.level == 0) {
1094			if (sc->sc_buttons > MOUSE_MSC_MAXBUTTON)
1095				sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON;
1096			else
1097				sc->sc_hw.buttons = sc->sc_buttons;
1098			sc->sc_mode.protocol = MOUSE_PROTO_MSC;
1099			sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
1100			sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
1101			sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
1102		} else if (sc->sc_mode.level == 1) {
1103			if (sc->sc_buttons > MOUSE_SYS_MAXBUTTON)
1104				sc->sc_hw.buttons = MOUSE_SYS_MAXBUTTON;
1105			else
1106				sc->sc_hw.buttons = sc->sc_buttons;
1107			sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
1108			sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
1109			sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
1110			sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC;
1111		}
1112		ums_reset_buf(sc);
1113		break;
1114
1115	case MOUSE_GETSTATUS:{
1116			mousestatus_t *status = (mousestatus_t *)addr;
1117
1118			*status = sc->sc_status;
1119			sc->sc_status.obutton = sc->sc_status.button;
1120			sc->sc_status.button = 0;
1121			sc->sc_status.dx = 0;
1122			sc->sc_status.dy = 0;
1123			sc->sc_status.dz = 0;
1124			/* sc->sc_status.dt = 0; */
1125
1126			if (status->dx || status->dy || status->dz /* || status->dt */ ) {
1127				status->flags |= MOUSE_POSCHANGED;
1128			}
1129			if (status->button != status->obutton) {
1130				status->flags |= MOUSE_BUTTONSCHANGED;
1131			}
1132			break;
1133		}
1134	default:
1135		error = ENOTTY;
1136		break;
1137	}
1138
1139	mtx_unlock(&sc->sc_mtx);
1140	return (error);
1141}
1142
1143static int
1144ums_sysctl_handler_parseinfo(SYSCTL_HANDLER_ARGS)
1145{
1146	struct ums_softc *sc = arg1;
1147	struct ums_info *info;
1148	struct sbuf *sb;
1149	int i, j, err, had_output;
1150
1151	sb = sbuf_new_auto();
1152	for (i = 0, had_output = 0; i < UMS_INFO_MAX; i++) {
1153		info = &sc->sc_info[i];
1154
1155		/* Don't emit empty info */
1156		if ((info->sc_flags &
1157		    (UMS_FLAG_X_AXIS | UMS_FLAG_Y_AXIS | UMS_FLAG_Z_AXIS |
1158		     UMS_FLAG_T_AXIS | UMS_FLAG_W_AXIS)) == 0 &&
1159		    info->sc_buttons == 0)
1160			continue;
1161
1162		if (had_output)
1163			sbuf_printf(sb, "\n");
1164		had_output = 1;
1165		sbuf_printf(sb, "i%d:", i + 1);
1166		if (info->sc_flags & UMS_FLAG_X_AXIS)
1167			sbuf_printf(sb, " X:r%d, p%d, s%d;",
1168			    (int)info->sc_iid_x,
1169			    (int)info->sc_loc_x.pos,
1170			    (int)info->sc_loc_x.size);
1171		if (info->sc_flags & UMS_FLAG_Y_AXIS)
1172			sbuf_printf(sb, " Y:r%d, p%d, s%d;",
1173			    (int)info->sc_iid_y,
1174			    (int)info->sc_loc_y.pos,
1175			    (int)info->sc_loc_y.size);
1176		if (info->sc_flags & UMS_FLAG_Z_AXIS)
1177			sbuf_printf(sb, " Z:r%d, p%d, s%d;",
1178			    (int)info->sc_iid_z,
1179			    (int)info->sc_loc_z.pos,
1180			    (int)info->sc_loc_z.size);
1181		if (info->sc_flags & UMS_FLAG_T_AXIS)
1182			sbuf_printf(sb, " T:r%d, p%d, s%d;",
1183			    (int)info->sc_iid_t,
1184			    (int)info->sc_loc_t.pos,
1185			    (int)info->sc_loc_t.size);
1186		if (info->sc_flags & UMS_FLAG_W_AXIS)
1187			sbuf_printf(sb, " W:r%d, p%d, s%d;",
1188			    (int)info->sc_iid_w,
1189			    (int)info->sc_loc_w.pos,
1190			    (int)info->sc_loc_w.size);
1191
1192		for (j = 0; j < info->sc_buttons; j++) {
1193			sbuf_printf(sb, " B%d:r%d, p%d, s%d;", j + 1,
1194			    (int)info->sc_iid_btn[j],
1195			    (int)info->sc_loc_btn[j].pos,
1196			    (int)info->sc_loc_btn[j].size);
1197		}
1198	}
1199	sbuf_finish(sb);
1200	err = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
1201	sbuf_delete(sb);
1202
1203	return (err);
1204}
1205
1206static devclass_t ums_devclass;
1207
1208static device_method_t ums_methods[] = {
1209	DEVMETHOD(device_probe, ums_probe),
1210	DEVMETHOD(device_attach, ums_attach),
1211	DEVMETHOD(device_detach, ums_detach),
1212
1213	DEVMETHOD_END
1214};
1215
1216static driver_t ums_driver = {
1217	.name = "ums",
1218	.methods = ums_methods,
1219	.size = sizeof(struct ums_softc),
1220};
1221
1222DRIVER_MODULE(ums, uhub, ums_driver, ums_devclass, NULL, 0);
1223MODULE_DEPEND(ums, usb, 1, 1, 1);
1224#ifdef EVDEV_SUPPORT
1225MODULE_DEPEND(ums, evdev, 1, 1, 1);
1226#endif
1227MODULE_VERSION(ums, 1);
1228USB_PNP_HOST_INFO(ums_devs);
1229