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