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