1 /*	$NetBSD: uhid.c,v 1.46 2001/11/13 06:24:55 lukem Exp $	*/
2 
3 /* Also already merged from NetBSD:
4  *	$NetBSD: uhid.c,v 1.54 2002/09/23 05:51:21 simonb Exp $
5  */
6 
7 #include <sys/cdefs.h>
8 /*-
9  * SPDX-License-Identifier: BSD-2-Clause
10  *
11  * Copyright (c) 1998 The NetBSD Foundation, Inc.
12  * All rights reserved.
13  *
14  * This code is derived from software contributed to The NetBSD Foundation
15  * by Lennart Augustsson (lennart@augustsson.net) at
16  * Carlstedt Research & Technology.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in the
25  *    documentation and/or other materials provided with the distribution.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /*
41  * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
42  */
43 
44 #include "implementation/global_implementation.h"
45 #include "input/usb_rdesc.h"
46 #include "implementation/usbdevs.h"
47 #include "event_hub.h"
48 #include <dev/usb/usb_generic.h>
49 
50 #undef USB_DEBUG_VAR
51 #define	USB_DEBUG_VAR uhid_debug
52 
53 #ifdef LOSCFG_USB_DEBUG
54 static int uhid_debug = 0;
55 #endif
56 
57 #define	UHID_BSIZE	1024		/* bytes, buffer size */
58 #define	UHID_FRAME_NUM 	  50		/* bytes, frame number */
59 
60 #define MOUSE_DATA_LEN 4
61 #define BTN_LEFT_VALUE(v) ((v) & 0x01)
62 #define BTN_RIGHT_VALUE(v) (((v) & 0x02)>>1)
63 #define BTN_MIDDLE_VALUE(v) (((v) & 0x04)>>2)
64 
65 enum {
66 	UHID_INTR_DT_WR,
67 	UHID_INTR_DT_RD,
68 	UHID_CTRL_DT_WR,
69 	UHID_CTRL_DT_RD,
70 	UHID_N_TRANSFER,
71 };
72 
73 struct uhid_softc {
74 	struct usb_fifo_sc sc_fifo;
75 	struct mtx sc_mtx;
76 
77 	struct usb_xfer *sc_xfer[UHID_N_TRANSFER];
78 	struct usb_device *sc_udev;
79 	void   *sc_repdesc_ptr;
80 
81 	uint32_t sc_isize;
82 	uint32_t sc_osize;
83 	uint32_t sc_fsize;
84 
85 	InputDevice *input_dev;
86 
87 	uint16_t sc_repdesc_size;
88 
89 	uint8_t	sc_iface_no;
90 	uint8_t	sc_iface_index;
91 	uint8_t	sc_iid;
92 	uint8_t	sc_oid;
93 	uint8_t	sc_fid;
94 	uint8_t	sc_flags;
95 #define	UHID_FLAG_IMMED        0x01	/* set if read should be immediate */
96 #define	UHID_FLAG_STATIC_DESC  0x04	/* set if report descriptors are
97 					 * static */
98 };
99 
100 static const uint8_t uhid_xb360gp_report_descr[] = {UHID_XB360GP_REPORT_DESCR()};
101 static const uint8_t uhid_graphire_report_descr[] = {UHID_GRAPHIRE_REPORT_DESCR()};
102 static const uint8_t uhid_graphire3_4x5_report_descr[] = {UHID_GRAPHIRE3_4X5_REPORT_DESCR()};
103 
104 /* prototypes */
105 
106 static device_probe_t uhid_probe;
107 static device_attach_t uhid_attach;
108 static device_detach_t uhid_detach;
109 
110 static usb_callback_t uhid_intr_write_callback;
111 static usb_callback_t uhid_intr_read_callback;
112 static usb_callback_t uhid_write_callback;
113 static usb_callback_t uhid_read_callback;
114 
115 static usb_fifo_cmd_t uhid_start_read;
116 static usb_fifo_cmd_t uhid_stop_read;
117 static usb_fifo_cmd_t uhid_start_write;
118 static usb_fifo_cmd_t uhid_stop_write;
119 static usb_fifo_open_t uhid_open;
120 static usb_fifo_close_t uhid_close;
121 static usb_fifo_ioctl_t uhid_ioctl;
122 static usb_fifo_ioctl_t uhid_ioctl_post;
123 
124 static struct usb_fifo_methods uhid_fifo_methods = {
125 	.f_open = &uhid_open,
126 	.f_close = &uhid_close,
127 	.f_ioctl = &uhid_ioctl,
128 	.f_ioctl_post = &uhid_ioctl_post,
129 	.f_start_read = &uhid_start_read,
130 	.f_stop_read = &uhid_stop_read,
131 	.f_start_write = &uhid_start_write,
132 	.f_stop_write = &uhid_stop_write,
133 	.basename[0] = "uhid",
134 };
135 
136 static void
uhid_intr_write_callback(struct usb_xfer *xfer, usb_error_t error)137 uhid_intr_write_callback(struct usb_xfer *xfer, usb_error_t error)
138 {
139 	struct uhid_softc *sc = usbd_xfer_softc(xfer);
140 	struct usb_page_cache *pc;
141 	usb_frlength_t actlen;
142 
143 	switch (USB_GET_STATE(xfer)) {
144 	case USB_ST_TRANSFERRED:
145 	case USB_ST_SETUP:
146 tr_setup:
147 		pc = usbd_xfer_get_frame(xfer, 0);
148 		if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc,
149 		    0, usbd_xfer_max_len(xfer), &actlen, 0)) {
150 			usbd_xfer_set_frame_len(xfer, 0, actlen);
151 			usbd_transfer_submit(xfer);
152 		}
153 		return;
154 
155 	default:			/* Error */
156 		if (error != USB_ERR_CANCELLED) {
157 			/* try to clear stall first */
158 			usbd_xfer_set_stall(xfer);
159 			goto tr_setup;
160 		}
161 		return;
162 	}
163 }
164 
report_event(InputDevice *input_dev, uint32_t type, uint32_t code, int32_t value)165 void report_event(InputDevice *input_dev, uint32_t type, uint32_t code, int32_t value)
166 {
167 	DPRINTF("%s type = %u, code = %u, value = %d\n", input_dev->devName, type, code, value);
168 	if (type == EV_SYN || type == EV_KEY) {
169 		PushOnePackage(input_dev, type, code, value);
170 	} else if (value) {
171 		PushOnePackage(input_dev, type, code, value);
172 	}
173 }
174 
mouse_report_events(InputDevice *input_dev, void *buffer, int len)175 void mouse_report_events(InputDevice *input_dev, void *buffer, int len)
176 {
177 	if (len != MOUSE_DATA_LEN) {
178 		DPRINTF("%s: invalid data len = %d\n", __func__, len);
179 		return;
180 	}
181 
182 	const char *buf = buffer;
183 	report_event(input_dev, EV_KEY, BTN_LEFT, BTN_LEFT_VALUE((unsigned char)buf[0]));
184 	report_event(input_dev, EV_KEY, BTN_RIGHT, BTN_RIGHT_VALUE((unsigned char)buf[0]));
185 	report_event(input_dev, EV_KEY, BTN_MIDDLE, BTN_MIDDLE_VALUE((unsigned char)buf[0]));
186 	report_event(input_dev, EV_REL, REL_X, buf[1]);
187 	report_event(input_dev, EV_REL, REL_Y, buf[2]);
188 	report_event(input_dev, EV_REL, REL_WHEEL, buf[3]);
189 	report_event(input_dev, EV_SYN, SYN_REPORT, 0);
190 }
191 
192 static void
uhid_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)193 uhid_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
194 {
195 	struct uhid_softc *sc = usbd_xfer_softc(xfer);
196 	struct usb_page_cache *pc;
197 	int actlen;
198 
199 	DPRINTF("enter state of xfer is %u!\n", USB_GET_STATE(xfer));
200 
201 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
202 
203 	switch (USB_GET_STATE(xfer)) {
204 	case USB_ST_TRANSFERRED:
205 		pc = usbd_xfer_get_frame(xfer, 0);
206 		if (sc->input_dev && sc->input_dev->devType == INDEV_TYPE_MOUSE) {
207 			mouse_report_events(sc->input_dev, pc->buffer, actlen);
208 		}
209 
210 	case USB_ST_SETUP:
211 		usbd_xfer_set_frame_len(xfer, 0, sc->sc_isize);
212 		usbd_transfer_submit(xfer);
213 		return;
214 
215 	default:
216 		if (error != USB_ERR_CANCELLED) {
217 			usbd_xfer_set_stall(xfer);
218 			usbd_xfer_set_frame_len(xfer, 0, sc->sc_isize);
219 			usbd_transfer_submit(xfer);
220 		}
221 		return;
222 	}
223 }
224 
225 static void
uhid_fill_set_report(struct usb_device_request *req, uint8_t iface_no, uint8_t type, uint8_t id, uint16_t size)226 uhid_fill_set_report(struct usb_device_request *req, uint8_t iface_no,
227     uint8_t type, uint8_t id, uint16_t size)
228 {
229 	req->bmRequestType = UT_WRITE_CLASS_INTERFACE;
230 	req->bRequest = UR_SET_REPORT;
231 	USETW2(req->wValue, type, id);
232 	req->wIndex[0] = iface_no;
233 	req->wIndex[1] = 0;
234 	USETW(req->wLength, size);
235 }
236 
237 static void
uhid_fill_get_report(struct usb_device_request *req, uint8_t iface_no, uint8_t type, uint8_t id, uint16_t size)238 uhid_fill_get_report(struct usb_device_request *req, uint8_t iface_no,
239     uint8_t type, uint8_t id, uint16_t size)
240 {
241 	req->bmRequestType = UT_READ_CLASS_INTERFACE;
242 	req->bRequest = UR_GET_REPORT;
243 	USETW2(req->wValue, type, id);
244 	req->wIndex[0] = iface_no;
245 	req->wIndex[1] = 0;
246 	USETW(req->wLength, size);
247 }
248 
249 static void
uhid_write_callback(struct usb_xfer *xfer, usb_error_t error)250 uhid_write_callback(struct usb_xfer *xfer, usb_error_t error)
251 {
252 	struct uhid_softc *sc = usbd_xfer_softc(xfer);
253 	struct usb_device_request req;
254 	struct usb_page_cache *pc;
255 	uint32_t size = sc->sc_osize;
256 	uint32_t actlen;
257 	uint8_t id;
258 
259 	switch (USB_GET_STATE(xfer)) {
260 	case USB_ST_TRANSFERRED:
261 	case USB_ST_SETUP:
262 		/* try to extract the ID byte */
263 		if (sc->sc_oid) {
264 			pc = usbd_xfer_get_frame(xfer, 0);
265 			if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc,
266 			    0, 1, &actlen, 0)) {
267 				if (actlen != 1) {
268 					goto tr_error;
269 				}
270 				usbd_copy_out(pc, 0, &id, 1);
271 
272 			} else {
273 				return;
274 			}
275 			if (size) {
276 				size--;
277 			}
278 		} else {
279 			id = 0;
280 		}
281 
282 		pc = usbd_xfer_get_frame(xfer, 1);
283 		if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc,
284 		    0, UHID_BSIZE, &actlen, 1)) {
285 			if (actlen != size) {
286 				goto tr_error;
287 			}
288 			uhid_fill_set_report
289 			    (&req, sc->sc_iface_no,
290 			    UHID_OUTPUT_REPORT, id, size);
291 
292 			pc = usbd_xfer_get_frame(xfer, 0);
293 			usbd_copy_in(pc, 0, &req, sizeof(req));
294 
295 			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
296 			usbd_xfer_set_frame_len(xfer, 1, size);
297 			usbd_xfer_set_frames(xfer, size ? 2 : 1);
298 			usbd_transfer_submit(xfer);
299 		}
300 		return;
301 
302 	default:
303 tr_error:
304 		/* bomb out */
305 		usb_fifo_get_data_error(sc->sc_fifo.fp[USB_FIFO_TX]);
306 		return;
307 	}
308 }
309 
310 static void
uhid_read_callback(struct usb_xfer *xfer, usb_error_t error)311 uhid_read_callback(struct usb_xfer *xfer, usb_error_t error)
312 {
313 	struct uhid_softc *sc = usbd_xfer_softc(xfer);
314 	struct usb_device_request req;
315 	struct usb_page_cache *pc;
316 
317 	DPRINTF("enter state of xfer is %u!\n", USB_GET_STATE(xfer));
318 
319 	pc = usbd_xfer_get_frame(xfer, 0);
320 
321 	switch (USB_GET_STATE(xfer)) {
322 	case USB_ST_TRANSFERRED:
323 		usb_fifo_put_data(sc->sc_fifo.fp[USB_FIFO_RX], pc, sizeof(req),
324 		    sc->sc_isize, 1);
325 		return;
326 
327 	case USB_ST_SETUP:
328 
329 		if (usb_fifo_put_bytes_max(sc->sc_fifo.fp[USB_FIFO_RX]) > 0) {
330 			uhid_fill_get_report
331 			    (&req, sc->sc_iface_no, UHID_INPUT_REPORT,
332 			    sc->sc_iid, sc->sc_isize);
333 
334 			usbd_copy_in(pc, 0, &req, sizeof(req));
335 
336 			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
337 			usbd_xfer_set_frame_len(xfer, 1, sc->sc_isize);
338 			usbd_xfer_set_frames(xfer, sc->sc_isize ? 2 : 1);
339 			usbd_transfer_submit(xfer);
340 		}
341 		return;
342 
343 	default:			/* Error */
344 		/* bomb out */
345 		usb_fifo_put_data_error(sc->sc_fifo.fp[USB_FIFO_RX]);
346 		return;
347 	}
348 }
349 
350 static const struct usb_config uhid_config[UHID_N_TRANSFER] = {
351 	[UHID_INTR_DT_WR] = {
352 		.type = UE_INTERRUPT,
353 		.endpoint = UE_ADDR_ANY,
354 		.direction = UE_DIR_OUT,
355 		.flags = {.pipe_bof = 1,.no_pipe_ok = 1, },
356 		.bufsize = UHID_BSIZE,
357 		.callback = &uhid_intr_write_callback,
358 	},
359 
360 	[UHID_INTR_DT_RD] = {
361 		.type = UE_INTERRUPT,
362 		.endpoint = UE_ADDR_ANY,
363 		.direction = UE_DIR_IN,
364 		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
365 		.bufsize = UHID_BSIZE,
366 		.callback = &uhid_intr_read_callback,
367 	},
368 
369 	[UHID_CTRL_DT_WR] = {
370 		.type = UE_CONTROL,
371 		.endpoint = 0x00,	/* Control pipe */
372 		.direction = UE_DIR_ANY,
373 		.bufsize = sizeof(struct usb_device_request) + UHID_BSIZE,
374 		.callback = &uhid_write_callback,
375 		.timeout = 1000,	/* 1 second */
376 	},
377 
378 	[UHID_CTRL_DT_RD] = {
379 		.type = UE_CONTROL,
380 		.endpoint = 0x00,	/* Control pipe */
381 		.direction = UE_DIR_ANY,
382 		.bufsize = sizeof(struct usb_device_request) + UHID_BSIZE,
383 		.callback = &uhid_read_callback,
384 		.timeout = 1000,	/* 1 second */
385 	},
386 };
387 
388 static void
uhid_start_read(struct usb_fifo *fifo)389 uhid_start_read(struct usb_fifo *fifo)
390 {
391 	struct uhid_softc *sc = usb_fifo_softc(fifo);
392 
393 	if (sc->sc_flags & UHID_FLAG_IMMED) {
394 		usbd_transfer_start(sc->sc_xfer[UHID_CTRL_DT_RD]);
395 	} else {
396 		usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_RD]);
397 	}
398 }
399 
400 static void
uhid_stop_read(struct usb_fifo *fifo)401 uhid_stop_read(struct usb_fifo *fifo)
402 {
403 	struct uhid_softc *sc = usb_fifo_softc(fifo);
404 
405 	usbd_transfer_stop(sc->sc_xfer[UHID_CTRL_DT_RD]);
406 	usbd_transfer_stop(sc->sc_xfer[UHID_INTR_DT_RD]);
407 }
408 
409 static void
uhid_start_write(struct usb_fifo *fifo)410 uhid_start_write(struct usb_fifo *fifo)
411 {
412 	struct uhid_softc *sc = usb_fifo_softc(fifo);
413 
414 	if ((sc->sc_flags & UHID_FLAG_IMMED) ||
415 	    sc->sc_xfer[UHID_INTR_DT_WR] == NULL) {
416 		usbd_transfer_start(sc->sc_xfer[UHID_CTRL_DT_WR]);
417 	} else {
418 		usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_WR]);
419 	}
420 }
421 
422 static void
uhid_stop_write(struct usb_fifo *fifo)423 uhid_stop_write(struct usb_fifo *fifo)
424 {
425 	struct uhid_softc *sc = usb_fifo_softc(fifo);
426 
427 	usbd_transfer_stop(sc->sc_xfer[UHID_CTRL_DT_WR]);
428 	usbd_transfer_stop(sc->sc_xfer[UHID_INTR_DT_WR]);
429 }
430 
431 static int
uhid_get_report(struct uhid_softc *sc, uint8_t type, uint8_t id, void *kern_data, void *user_data, uint16_t len)432 uhid_get_report(struct uhid_softc *sc, uint8_t type,
433     uint8_t id, void *kern_data, void *user_data,
434     uint16_t len)
435 {
436 	int err;
437 	uint8_t free_data = 0;
438 
439 	if (kern_data == NULL) {
440 		if (len == 0) {
441 			err = EPERM;
442 			goto done;
443 		}
444 
445 		kern_data = malloc(len);
446 		if (kern_data == NULL) {
447 			err = ENOMEM;
448 			goto done;
449 		}
450 		free_data = 1;
451 	}
452 	err = usbd_req_get_report(sc->sc_udev, NULL, kern_data,
453 	    len, sc->sc_iface_index, type, id);
454 	if (err) {
455 		err = ENXIO;
456 		goto done;
457 	}
458 	if (user_data) {
459 		/* dummy buffer */
460 		err = copyout(kern_data, user_data, len);
461 		if (err) {
462 			goto done;
463 		}
464 	}
465 done:
466 	if (free_data) {
467 		free(kern_data);
468 	}
469 	return (err);
470 }
471 
472 static int
uhid_set_report(struct uhid_softc *sc, uint8_t type, uint8_t id, void *kern_data, const void *user_data, uint16_t len)473 uhid_set_report(struct uhid_softc *sc, uint8_t type,
474     uint8_t id, void *kern_data, const void *user_data,
475     uint16_t len)
476 {
477 	int err;
478 	uint8_t free_data = 0;
479 
480 	if (kern_data == NULL) {
481 		if (len == 0) {
482 			err = EPERM;
483 			goto done;
484 		}
485 
486 		kern_data = malloc(len);
487 		if (kern_data == NULL) {
488 			err = ENOMEM;
489 			goto done;
490 		}
491 		free_data = 1;
492 		err = copyin(user_data, kern_data, len);
493 		if (err) {
494 			goto done;
495 		}
496 	}
497 	err = usbd_req_set_report(sc->sc_udev, NULL, kern_data,
498 	    len, sc->sc_iface_index, type, id);
499 	if (err) {
500 		err = ENXIO;
501 		goto done;
502 	}
503 done:
504 	if (free_data) {
505 		free(kern_data);
506 	}
507 	return (err);
508 }
509 
510 static int
uhid_open(struct usb_fifo *fifo, int fflags)511 uhid_open(struct usb_fifo *fifo, int fflags)
512 {
513 	struct uhid_softc *sc = usb_fifo_softc(fifo);
514 
515 	/*
516 	 * The buffers are one byte larger than maximum so that one
517 	 * can detect too large read/writes and short transfers:
518 	 */
519 	if ((unsigned int)fflags & FREAD) {
520 		/* reset flags */
521 		mtx_lock(&sc->sc_mtx);
522 		sc->sc_flags &= ~UHID_FLAG_IMMED;
523 		mtx_unlock(&sc->sc_mtx);
524 
525 		if (usb_fifo_alloc_buffer(fifo,
526 		    sc->sc_isize + 1, UHID_FRAME_NUM)) {
527 			return (ENOMEM);
528 		}
529 	}
530 	if ((unsigned int)fflags & FWRITE) {
531 		if (usb_fifo_alloc_buffer(fifo,
532 		    sc->sc_osize + 1, UHID_FRAME_NUM)) {
533 			return (ENOMEM);
534 		}
535 	}
536 
537 	return (0);
538 }
539 
540 static void
uhid_close(struct usb_fifo *fifo, int fflags)541 uhid_close(struct usb_fifo *fifo, int fflags)
542 {
543 	if ((unsigned int)fflags & (FREAD | FWRITE)) {
544 		usb_fifo_free_buffer(fifo);
545 	}
546 }
547 
548 static int
uhid_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags)549 uhid_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr,
550     int fflags)
551 {
552 	struct uhid_softc *sc = usb_fifo_softc(fifo);
553 	struct usb_gen_descriptor ugd;
554 	uint32_t size;
555 	int error = 0;
556 	uint8_t id;
557 
558 	switch (cmd) {
559 	case USB_GET_REPORT_DESC:
560 		error = copyin((const void *)addr, &ugd, sizeof(struct usb_gen_descriptor));
561 		if (error != ENOERR) {
562 			break;
563 		}
564 		if (sc->sc_repdesc_size > ugd.ugd_maxlen) {
565 			size = ugd.ugd_maxlen;
566 		} else {
567 			size = sc->sc_repdesc_size;
568 		}
569 		ugd.ugd_actlen = size;
570 		if (ugd.ugd_data == NULL)
571 			break;		/* descriptor length only */
572 		error = copyout(sc->sc_repdesc_ptr, ugd.ugd_data, size);
573 		if (error == ENOERR) {
574 			error = copyout((const void *)&ugd, addr, sizeof(struct usb_gen_descriptor));
575 		}
576 		break;
577 
578 	case USB_SET_IMMED: {
579 		int data;
580 		if (!((unsigned int)fflags & FREAD)) {
581 			error = EPERM;
582 			break;
583 		}
584 		error = copyin((const void *)addr, &data, sizeof(data));
585 		if (error != ENOERR) {
586 			break;
587 		}
588 		if (data) {
589 			/* do a test read */
590 
591 			error = uhid_get_report(sc, UHID_INPUT_REPORT,
592 			    sc->sc_iid, NULL, NULL, sc->sc_isize);
593 			if (error) {
594 				break;
595 			}
596 			mtx_lock(&sc->sc_mtx);
597 			sc->sc_flags |= UHID_FLAG_IMMED;
598 			mtx_unlock(&sc->sc_mtx);
599 		} else {
600 			mtx_lock(&sc->sc_mtx);
601 			sc->sc_flags &= ~UHID_FLAG_IMMED;
602 			mtx_unlock(&sc->sc_mtx);
603 		}
604 		break;
605 	}
606 
607 	case USB_GET_REPORT:
608 		if (!((unsigned int)fflags & FREAD)) {
609 			error = EPERM;
610 			break;
611 		}
612 		error = copyin((const void *)addr, &ugd, sizeof(struct usb_gen_descriptor));
613 		if (error != ENOERR) {
614 			break;
615 		}
616 		switch (ugd.ugd_report_type) {
617 		case UHID_INPUT_REPORT:
618 			size = sc->sc_isize;
619 			id = sc->sc_iid;
620 			break;
621 		case UHID_OUTPUT_REPORT:
622 			size = sc->sc_osize;
623 			id = sc->sc_oid;
624 			break;
625 		case UHID_FEATURE_REPORT:
626 			size = sc->sc_fsize;
627 			id = sc->sc_fid;
628 			break;
629 		default:
630 			return (EINVAL);
631 		}
632 		if (id != 0)
633 			copyin(ugd.ugd_data, &id, 1);
634 		error = uhid_get_report(sc, ugd.ugd_report_type, id,
635 		    NULL, ugd.ugd_data, MIN(ugd.ugd_maxlen, size));
636 		break;
637 
638 	case USB_SET_REPORT:
639 		if (!((unsigned int)fflags & FWRITE)) {
640 			error = EPERM;
641 			break;
642 		}
643 		error = copyin((const void *)addr, &ugd, sizeof(struct usb_gen_descriptor));
644 		if (error != ENOERR) {
645 			break;
646 		}
647 		switch (ugd.ugd_report_type) {
648 		case UHID_INPUT_REPORT:
649 			size = sc->sc_isize;
650 			id = sc->sc_iid;
651 			break;
652 		case UHID_OUTPUT_REPORT:
653 			size = sc->sc_osize;
654 			id = sc->sc_oid;
655 			break;
656 		case UHID_FEATURE_REPORT:
657 			size = sc->sc_fsize;
658 			id = sc->sc_fid;
659 			break;
660 		default:
661 			return (EINVAL);
662 		}
663 		if (id != 0)
664 			copyin(ugd.ugd_data, &id, 1);
665 		error = uhid_set_report(sc, ugd.ugd_report_type, id,
666 		    NULL, ugd.ugd_data, MIN(ugd.ugd_maxlen, size));
667 		break;
668 
669 	case USB_GET_REPORT_ID: {
670 		int data = 0;
671 		error = copyout((const void *)&data, addr, sizeof(data)); /* XXX: we only support reportid 0? */
672 		break;
673 	}
674 
675 	default:
676 		error = ENOIOCTL;
677 		break;
678 	}
679 
680 	return (error);
681 }
682 
683 static int
uhid_ioctl_post(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags)684 uhid_ioctl_post(struct usb_fifo *fifo, u_long cmd, void *addr,
685     int fflags)
686 {
687 	int error;
688 
689 	switch (cmd) {
690 	case USB_GET_DEVICEINFO:
691 		error = ugen_fill_deviceinfo(fifo, addr);
692 		break;
693 
694 	default:
695 		error = EINVAL;
696 		break;
697 	}
698 
699 	return (error);
700 }
701 
702 static const STRUCT_USB_HOST_ID uhid_devs[] = {
703 	/* generic HID class */
704 	{USB_IFACE_CLASS(UICLASS_HID),},
705 	/* the Xbox 360 gamepad doesn't use the HID class */
706 	{USB_IFACE_CLASS(UICLASS_VENDOR),
707 	 USB_IFACE_SUBCLASS(UISUBCLASS_XBOX360_CONTROLLER),
708 	 USB_IFACE_PROTOCOL(UIPROTO_XBOX360_GAMEPAD),},
709 };
710 
711 static int
uhid_probe(device_t dev)712 uhid_probe(device_t dev)
713 {
714 	struct usb_attach_arg *uaa = device_get_ivars(dev);
715 	int error;
716 
717 	DPRINTFN(11, "\n");
718 
719 	if (uaa->usb_mode != USB_MODE_HOST)
720 		return (ENXIO);
721 
722 	error = usbd_lookup_id_by_uaa(uhid_devs, sizeof(uhid_devs), uaa);
723 	if (error)
724 		return (error);
725 
726 	if (usb_test_quirk(uaa, UQ_HID_IGNORE))
727 		return (ENXIO);
728 
729 	return (0);
730 }
731 
732 static int
uhid_attach(device_t dev)733 uhid_attach(device_t dev)
734 {
735 	struct usb_attach_arg *uaa = device_get_ivars(dev);
736 	struct uhid_softc *sc = device_get_softc(dev);
737 	int unit = device_get_unit(dev);
738 	int error = 0;
739 	int32_t ret;
740 
741 	DPRINTFN(10, "sc=%p\n", sc);
742 
743 	device_set_usb_desc(dev);
744 
745 	mtx_init(&sc->sc_mtx, "uhid lock", NULL, MTX_DEF | MTX_RECURSE);
746 
747 	sc->sc_udev = uaa->device;
748 
749 	sc->sc_iface_no = uaa->info.bIfaceNum;
750 	sc->sc_iface_index = uaa->info.bIfaceIndex;
751 
752 	error = usbd_transfer_setup(uaa->device,
753 	    &uaa->info.bIfaceIndex, sc->sc_xfer, uhid_config,
754 	    UHID_N_TRANSFER, sc, &sc->sc_mtx);
755 
756 	if (error) {
757 		DPRINTF("error=%s\n", usbd_errstr(error));
758 		goto detach;
759 	}
760 	if (uaa->info.idVendor == USB_VENDOR_WACOM) {
761 		/* the report descriptor for the Wacom Graphire is broken */
762 
763 		if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE) {
764 			sc->sc_repdesc_size = sizeof(uhid_graphire_report_descr);
765 			sc->sc_repdesc_ptr = __DECONST(void *, &uhid_graphire_report_descr);
766 			sc->sc_flags |= UHID_FLAG_STATIC_DESC;
767 
768 		} else if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE3_4X5) {
769 			static uint8_t reportbuf[] = {2, 2, 2};
770 
771 			/*
772 			 * The Graphire3 needs 0x0202 to be written to
773 			 * feature report ID 2 before it'll start
774 			 * returning digitizer data.
775 			 */
776 			error = usbd_req_set_report(uaa->device, NULL,
777 			    reportbuf, sizeof(reportbuf),
778 			    uaa->info.bIfaceIndex, UHID_FEATURE_REPORT, 2);
779 
780 			if (error) {
781 				DPRINTF("set report failed, error=%s (ignored)\n",
782 				    usbd_errstr(error));
783 			}
784 			sc->sc_repdesc_size = sizeof(uhid_graphire3_4x5_report_descr);
785 			sc->sc_repdesc_ptr = __DECONST(void *, &uhid_graphire3_4x5_report_descr);
786 			sc->sc_flags |= UHID_FLAG_STATIC_DESC;
787 		}
788 	} else if ((uaa->info.bInterfaceClass == UICLASS_VENDOR) &&
789 	    (uaa->info.bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER) &&
790 	    (uaa->info.bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD)) {
791 		static const uint8_t reportbuf[3] = {1, 3, 0};
792 		/*
793 		 * Turn off the four LEDs on the gamepad which
794 		 * are blinking by default:
795 		 */
796 		error = usbd_req_set_report(uaa->device, NULL,
797 		    __DECONST(void *, reportbuf), sizeof(reportbuf),
798 		    uaa->info.bIfaceIndex, UHID_OUTPUT_REPORT, 0);
799 		if (error) {
800 			DPRINTF("set output report failed, error=%s (ignored)\n",
801 			    usbd_errstr(error));
802 		}
803 		/* the Xbox 360 gamepad has no report descriptor */
804 		sc->sc_repdesc_size = sizeof(uhid_xb360gp_report_descr);
805 		sc->sc_repdesc_ptr = __DECONST(void *, &uhid_xb360gp_report_descr);
806 		sc->sc_flags |= UHID_FLAG_STATIC_DESC;
807 	}
808 
809 	if (sc->sc_repdesc_ptr == NULL) {
810 		error = usbd_req_get_hid_desc(uaa->device, NULL,
811 		    &sc->sc_repdesc_ptr, &sc->sc_repdesc_size,
812 		    M_USBDEV, uaa->info.bIfaceIndex);
813 
814 		if (error) {
815 			device_printf(dev, "no report descriptor\n");
816 			goto detach;
817 		}
818 	}
819 
820 	error = usbd_req_set_idle(uaa->device, NULL,
821 	    uaa->info.bIfaceIndex, 0, 0);
822 
823 	if (error) {
824 		DPRINTF("set idle failed, error=%s (ignored)\n",
825 		    usbd_errstr(error));
826 	}
827 
828 	sc->sc_isize = hid_report_size
829 	    (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_input, &sc->sc_iid);
830 
831 	sc->sc_osize = hid_report_size
832 	    (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_output, &sc->sc_oid);
833 
834 	sc->sc_fsize = hid_report_size
835 	    (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_feature, &sc->sc_fid);
836 
837 	if (sc->sc_isize > UHID_BSIZE) {
838 		DPRINTF("input size is too large, "
839 		    "%d bytes (truncating)\n",
840 		    sc->sc_isize);
841 		sc->sc_isize = UHID_BSIZE;
842 	}
843 	if (sc->sc_osize > UHID_BSIZE) {
844 		DPRINTF("output size is too large, "
845 		    "%d bytes (truncating)\n",
846 		    sc->sc_osize);
847 		sc->sc_osize = UHID_BSIZE;
848 	}
849 	if (sc->sc_fsize > UHID_BSIZE) {
850 		DPRINTF("feature size is too large, "
851 		    "%d bytes (truncating)\n",
852 		    sc->sc_fsize);
853 		sc->sc_fsize = UHID_BSIZE;
854 	}
855 
856 	error = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx,
857 	    &uhid_fifo_methods, &sc->sc_fifo,
858 	    unit, -1, uaa->info.bIfaceIndex,
859 	    UID_ROOT, GID_OPERATOR, 0644);
860 	if (error) {
861 		goto detach;
862 	}
863 
864 	sc->input_dev = (InputDevice*)zalloc(sizeof(InputDevice));
865 	if (sc->input_dev) {
866 		if (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE) {
867 			sc->input_dev->devType = INDEV_TYPE_MOUSE;
868 			sc->input_dev->devName = "mouse";
869 		} else {
870 			sc->input_dev->devType = INDEV_TYPE_UNKNOWN;
871 			sc->input_dev->devName = "other";
872 		}
873 
874 		ret = RegisterInputDevice(sc->input_dev);
875 		if (ret != HDF_SUCCESS) {
876 			DPRINTF("%s register failed, ret = %d!\n", sc->input_dev->devName, ret);
877 			free(sc->input_dev);
878 			sc->input_dev = NULL;
879 		} else if (sc->input_dev->devType == INDEV_TYPE_MOUSE) {
880 			DPRINTF("mouse register success!\n");
881 			mtx_lock(&sc->sc_mtx);
882 			sc->sc_flags &= ~UHID_FLAG_IMMED;
883 			usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_RD]);
884 			mtx_unlock(&sc->sc_mtx);
885 		}
886 	}
887 
888 	return (0);			/* success */
889 
890 detach:
891 	uhid_detach(dev);
892 	return (ENOMEM);
893 }
894 
895 static int
uhid_detach(device_t dev)896 uhid_detach(device_t dev)
897 {
898 	struct uhid_softc *sc = device_get_softc(dev);
899 
900 	DPRINTF("enter\n");
901 
902 	if (sc->input_dev) {
903 		if (sc->input_dev->devType == INDEV_TYPE_MOUSE) {
904 			usbd_transfer_stop(sc->sc_xfer[UHID_INTR_DT_RD]);
905 		}
906 
907 		UnregisterInputDevice(sc->input_dev);
908 		free(sc->input_dev);
909 		sc->input_dev = NULL;
910 	}
911 
912 	usb_fifo_detach(&sc->sc_fifo);
913 
914 	usbd_transfer_unsetup(sc->sc_xfer, UHID_N_TRANSFER);
915 
916 	if (sc->sc_repdesc_ptr) {
917 		if (!(sc->sc_flags & UHID_FLAG_STATIC_DESC)) {
918 			free(sc->sc_repdesc_ptr);
919 		}
920 	}
921 	mtx_destroy(&sc->sc_mtx);
922 
923 	return (0);
924 }
925 
926 static devclass_t uhid_devclass;
927 
928 static device_method_t uhid_methods[] = {
929 	DEVMETHOD(device_probe, uhid_probe),
930 	DEVMETHOD(device_attach, uhid_attach),
931 	DEVMETHOD(device_detach, uhid_detach),
932 
933 	DEVMETHOD_END
934 };
935 
936 static driver_t uhid_driver = {
937 	.name = "uhid",
938 	.methods = uhid_methods,
939 	.size = sizeof(struct uhid_softc),
940 };
941 
942 DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, NULL, 0);
943