]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/input/uhid.c
hid: Import usbhid - USB transport backend for HID subsystem.
[FreeBSD/FreeBSD.git] / sys / dev / usb / input / uhid.c
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 <sys/stdint.h>
47 #include <sys/stddef.h>
48 #include <sys/param.h>
49 #include <sys/queue.h>
50 #include <sys/types.h>
51 #include <sys/systm.h>
52 #include <sys/kernel.h>
53 #include <sys/bus.h>
54 #include <sys/module.h>
55 #include <sys/lock.h>
56 #include <sys/mutex.h>
57 #include <sys/condvar.h>
58 #include <sys/sysctl.h>
59 #include <sys/sx.h>
60 #include <sys/unistd.h>
61 #include <sys/callout.h>
62 #include <sys/malloc.h>
63 #include <sys/priv.h>
64 #include <sys/conf.h>
65 #include <sys/fcntl.h>
66
67 #include <dev/hid/hid.h>
68
69 #include "usbdevs.h"
70 #include <dev/usb/usb.h>
71 #include <dev/usb/usbdi.h>
72 #include <dev/usb/usbdi_util.h>
73 #include <dev/usb/usbhid.h>
74 #include <dev/usb/usb_ioctl.h>
75 #include <dev/usb/usb_generic.h>
76
77 #define USB_DEBUG_VAR uhid_debug
78 #include <dev/usb/usb_debug.h>
79
80 #include <dev/usb/input/usb_rdesc.h>
81 #include <dev/usb/quirk/usb_quirk.h>
82
83 #ifdef USB_DEBUG
84 static int uhid_debug = 0;
85
86 static SYSCTL_NODE(_hw_usb, OID_AUTO, uhid, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
87     "USB uhid");
88 SYSCTL_INT(_hw_usb_uhid, OID_AUTO, debug, CTLFLAG_RWTUN,
89     &uhid_debug, 0, "Debug level");
90 #endif
91
92 #define UHID_BSIZE      1024            /* bytes, buffer size */
93 #define UHID_FRAME_NUM    50            /* bytes, frame number */
94
95 enum {
96         UHID_INTR_DT_WR,
97         UHID_INTR_DT_RD,
98         UHID_CTRL_DT_WR,
99         UHID_CTRL_DT_RD,
100         UHID_N_TRANSFER,
101 };
102
103 struct uhid_softc {
104         struct usb_fifo_sc sc_fifo;
105         struct mtx sc_mtx;
106
107         struct usb_xfer *sc_xfer[UHID_N_TRANSFER];
108         struct usb_device *sc_udev;
109         void   *sc_repdesc_ptr;
110
111         uint32_t sc_isize;
112         uint32_t sc_osize;
113         uint32_t sc_fsize;
114
115         uint16_t sc_repdesc_size;
116
117         uint8_t sc_iface_no;
118         uint8_t sc_iface_index;
119         uint8_t sc_iid;
120         uint8_t sc_oid;
121         uint8_t sc_fid;
122         uint8_t sc_flags;
123 #define UHID_FLAG_IMMED        0x01     /* set if read should be immediate */
124 #define UHID_FLAG_STATIC_DESC  0x04     /* set if report descriptors are
125                                          * static */
126 };
127
128 static const uint8_t uhid_xb360gp_report_descr[] = {UHID_XB360GP_REPORT_DESCR()};
129 static const uint8_t uhid_graphire_report_descr[] = {UHID_GRAPHIRE_REPORT_DESCR()};
130 static const uint8_t uhid_graphire3_4x5_report_descr[] = {UHID_GRAPHIRE3_4X5_REPORT_DESCR()};
131
132 /* prototypes */
133
134 static device_probe_t uhid_probe;
135 static device_attach_t uhid_attach;
136 static device_detach_t uhid_detach;
137
138 static usb_callback_t uhid_intr_write_callback;
139 static usb_callback_t uhid_intr_read_callback;
140 static usb_callback_t uhid_write_callback;
141 static usb_callback_t uhid_read_callback;
142
143 static usb_fifo_cmd_t uhid_start_read;
144 static usb_fifo_cmd_t uhid_stop_read;
145 static usb_fifo_cmd_t uhid_start_write;
146 static usb_fifo_cmd_t uhid_stop_write;
147 static usb_fifo_open_t uhid_open;
148 static usb_fifo_close_t uhid_close;
149 static usb_fifo_ioctl_t uhid_ioctl;
150 static usb_fifo_ioctl_t uhid_ioctl_post;
151
152 static struct usb_fifo_methods uhid_fifo_methods = {
153         .f_open = &uhid_open,
154         .f_close = &uhid_close,
155         .f_ioctl = &uhid_ioctl,
156         .f_ioctl_post = &uhid_ioctl_post,
157         .f_start_read = &uhid_start_read,
158         .f_stop_read = &uhid_stop_read,
159         .f_start_write = &uhid_start_write,
160         .f_stop_write = &uhid_stop_write,
161         .basename[0] = "uhid",
162 };
163
164 static void
165 uhid_intr_write_callback(struct usb_xfer *xfer, usb_error_t error)
166 {
167         struct uhid_softc *sc = usbd_xfer_softc(xfer);
168         struct usb_page_cache *pc;
169         int actlen;
170
171         switch (USB_GET_STATE(xfer)) {
172         case USB_ST_TRANSFERRED:
173         case USB_ST_SETUP:
174 tr_setup:
175                 pc = usbd_xfer_get_frame(xfer, 0);
176                 if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc,
177                     0, usbd_xfer_max_len(xfer), &actlen, 0)) {
178                         usbd_xfer_set_frame_len(xfer, 0, actlen);
179                         usbd_transfer_submit(xfer);
180                 }
181                 return;
182
183         default:                        /* Error */
184                 if (error != USB_ERR_CANCELLED) {
185                         /* try to clear stall first */
186                         usbd_xfer_set_stall(xfer);
187                         goto tr_setup;
188                 }
189                 return;
190         }
191 }
192
193 static void
194 uhid_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
195 {
196         struct uhid_softc *sc = usbd_xfer_softc(xfer);
197         struct usb_page_cache *pc;
198         int actlen;
199
200         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
201
202         switch (USB_GET_STATE(xfer)) {
203         case USB_ST_TRANSFERRED:
204                 DPRINTF("transferred!\n");
205
206                 pc = usbd_xfer_get_frame(xfer, 0);
207
208                 /* 
209                  * If the ID byte is non zero we allow descriptors
210                  * having multiple sizes:
211                  */
212                 if ((actlen >= (int)sc->sc_isize) ||
213                     ((actlen > 0) && (sc->sc_iid != 0))) {
214                         /* limit report length to the maximum */
215                         if (actlen > (int)sc->sc_isize)
216                                 actlen = sc->sc_isize;
217                         usb_fifo_put_data(sc->sc_fifo.fp[USB_FIFO_RX], pc,
218                             0, actlen, 1);
219                 } else {
220                         /* ignore it */
221                         DPRINTF("ignored transfer, %d bytes\n", actlen);
222                 }
223
224         case USB_ST_SETUP:
225 re_submit:
226                 if (usb_fifo_put_bytes_max(
227                     sc->sc_fifo.fp[USB_FIFO_RX]) != 0) {
228                         usbd_xfer_set_frame_len(xfer, 0, sc->sc_isize);
229                         usbd_transfer_submit(xfer);
230                 }
231                 return;
232
233         default:                        /* Error */
234                 if (error != USB_ERR_CANCELLED) {
235                         /* try to clear stall first */
236                         usbd_xfer_set_stall(xfer);
237                         goto re_submit;
238                 }
239                 return;
240         }
241 }
242
243 static void
244 uhid_fill_set_report(struct usb_device_request *req, uint8_t iface_no,
245     uint8_t type, uint8_t id, uint16_t size)
246 {
247         req->bmRequestType = UT_WRITE_CLASS_INTERFACE;
248         req->bRequest = UR_SET_REPORT;
249         USETW2(req->wValue, type, id);
250         req->wIndex[0] = iface_no;
251         req->wIndex[1] = 0;
252         USETW(req->wLength, size);
253 }
254
255 static void
256 uhid_fill_get_report(struct usb_device_request *req, uint8_t iface_no,
257     uint8_t type, uint8_t id, uint16_t size)
258 {
259         req->bmRequestType = UT_READ_CLASS_INTERFACE;
260         req->bRequest = UR_GET_REPORT;
261         USETW2(req->wValue, type, id);
262         req->wIndex[0] = iface_no;
263         req->wIndex[1] = 0;
264         USETW(req->wLength, size);
265 }
266
267 static void
268 uhid_write_callback(struct usb_xfer *xfer, usb_error_t error)
269 {
270         struct uhid_softc *sc = usbd_xfer_softc(xfer);
271         struct usb_device_request req;
272         struct usb_page_cache *pc;
273         uint32_t size = sc->sc_osize;
274         uint32_t actlen;
275         uint8_t id;
276
277         switch (USB_GET_STATE(xfer)) {
278         case USB_ST_TRANSFERRED:
279         case USB_ST_SETUP:
280                 /* try to extract the ID byte */
281                 if (sc->sc_oid) {
282                         pc = usbd_xfer_get_frame(xfer, 0);
283                         if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc,
284                             0, 1, &actlen, 0)) {
285                                 if (actlen != 1) {
286                                         goto tr_error;
287                                 }
288                                 usbd_copy_out(pc, 0, &id, 1);
289
290                         } else {
291                                 return;
292                         }
293                         if (size) {
294                                 size--;
295                         }
296                 } else {
297                         id = 0;
298                 }
299
300                 pc = usbd_xfer_get_frame(xfer, 1);
301                 if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc,
302                     0, UHID_BSIZE, &actlen, 1)) {
303                         if (actlen != size) {
304                                 goto tr_error;
305                         }
306                         uhid_fill_set_report
307                             (&req, sc->sc_iface_no,
308                             UHID_OUTPUT_REPORT, id, size);
309
310                         pc = usbd_xfer_get_frame(xfer, 0);
311                         usbd_copy_in(pc, 0, &req, sizeof(req));
312
313                         usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
314                         usbd_xfer_set_frame_len(xfer, 1, size);
315                         usbd_xfer_set_frames(xfer, size ? 2 : 1);
316                         usbd_transfer_submit(xfer);
317                 }
318                 return;
319
320         default:
321 tr_error:
322                 /* bomb out */
323                 usb_fifo_get_data_error(sc->sc_fifo.fp[USB_FIFO_TX]);
324                 return;
325         }
326 }
327
328 static void
329 uhid_read_callback(struct usb_xfer *xfer, usb_error_t error)
330 {
331         struct uhid_softc *sc = usbd_xfer_softc(xfer);
332         struct usb_device_request req;
333         struct usb_page_cache *pc;
334
335         pc = usbd_xfer_get_frame(xfer, 0);
336
337         switch (USB_GET_STATE(xfer)) {
338         case USB_ST_TRANSFERRED:
339                 usb_fifo_put_data(sc->sc_fifo.fp[USB_FIFO_RX], pc, sizeof(req),
340                     sc->sc_isize, 1);
341                 return;
342
343         case USB_ST_SETUP:
344
345                 if (usb_fifo_put_bytes_max(sc->sc_fifo.fp[USB_FIFO_RX]) > 0) {
346                         uhid_fill_get_report
347                             (&req, sc->sc_iface_no, UHID_INPUT_REPORT,
348                             sc->sc_iid, sc->sc_isize);
349
350                         usbd_copy_in(pc, 0, &req, sizeof(req));
351
352                         usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
353                         usbd_xfer_set_frame_len(xfer, 1, sc->sc_isize);
354                         usbd_xfer_set_frames(xfer, sc->sc_isize ? 2 : 1);
355                         usbd_transfer_submit(xfer);
356                 }
357                 return;
358
359         default:                        /* Error */
360                 /* bomb out */
361                 usb_fifo_put_data_error(sc->sc_fifo.fp[USB_FIFO_RX]);
362                 return;
363         }
364 }
365
366 static const struct usb_config uhid_config[UHID_N_TRANSFER] = {
367         [UHID_INTR_DT_WR] = {
368                 .type = UE_INTERRUPT,
369                 .endpoint = UE_ADDR_ANY,
370                 .direction = UE_DIR_OUT,
371                 .flags = {.pipe_bof = 1,.no_pipe_ok = 1, },
372                 .bufsize = UHID_BSIZE,
373                 .callback = &uhid_intr_write_callback,
374         },
375
376         [UHID_INTR_DT_RD] = {
377                 .type = UE_INTERRUPT,
378                 .endpoint = UE_ADDR_ANY,
379                 .direction = UE_DIR_IN,
380                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
381                 .bufsize = UHID_BSIZE,
382                 .callback = &uhid_intr_read_callback,
383         },
384
385         [UHID_CTRL_DT_WR] = {
386                 .type = UE_CONTROL,
387                 .endpoint = 0x00,       /* Control pipe */
388                 .direction = UE_DIR_ANY,
389                 .bufsize = sizeof(struct usb_device_request) + UHID_BSIZE,
390                 .callback = &uhid_write_callback,
391                 .timeout = 1000,        /* 1 second */
392         },
393
394         [UHID_CTRL_DT_RD] = {
395                 .type = UE_CONTROL,
396                 .endpoint = 0x00,       /* Control pipe */
397                 .direction = UE_DIR_ANY,
398                 .bufsize = sizeof(struct usb_device_request) + UHID_BSIZE,
399                 .callback = &uhid_read_callback,
400                 .timeout = 1000,        /* 1 second */
401         },
402 };
403
404 static void
405 uhid_start_read(struct usb_fifo *fifo)
406 {
407         struct uhid_softc *sc = usb_fifo_softc(fifo);
408
409         if (sc->sc_flags & UHID_FLAG_IMMED) {
410                 usbd_transfer_start(sc->sc_xfer[UHID_CTRL_DT_RD]);
411         } else {
412                 usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_RD]);
413         }
414 }
415
416 static void
417 uhid_stop_read(struct usb_fifo *fifo)
418 {
419         struct uhid_softc *sc = usb_fifo_softc(fifo);
420
421         usbd_transfer_stop(sc->sc_xfer[UHID_CTRL_DT_RD]);
422         usbd_transfer_stop(sc->sc_xfer[UHID_INTR_DT_RD]);
423 }
424
425 static void
426 uhid_start_write(struct usb_fifo *fifo)
427 {
428         struct uhid_softc *sc = usb_fifo_softc(fifo);
429
430         if ((sc->sc_flags & UHID_FLAG_IMMED) ||
431             sc->sc_xfer[UHID_INTR_DT_WR] == NULL) {
432                 usbd_transfer_start(sc->sc_xfer[UHID_CTRL_DT_WR]);
433         } else {
434                 usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_WR]);
435         }
436 }
437
438 static void
439 uhid_stop_write(struct usb_fifo *fifo)
440 {
441         struct uhid_softc *sc = usb_fifo_softc(fifo);
442
443         usbd_transfer_stop(sc->sc_xfer[UHID_CTRL_DT_WR]);
444         usbd_transfer_stop(sc->sc_xfer[UHID_INTR_DT_WR]);
445 }
446
447 static int
448 uhid_get_report(struct uhid_softc *sc, uint8_t type,
449     uint8_t id, void *kern_data, void *user_data,
450     uint16_t len)
451 {
452         int err;
453         uint8_t free_data = 0;
454
455         if (kern_data == NULL) {
456                 kern_data = malloc(len, M_USBDEV, M_WAITOK);
457                 free_data = 1;
458         }
459         err = usbd_req_get_report(sc->sc_udev, NULL, kern_data,
460             len, sc->sc_iface_index, type, id);
461         if (err) {
462                 err = ENXIO;
463                 goto done;
464         }
465         if (user_data) {
466                 /* dummy buffer */
467                 err = copyout(kern_data, user_data, len);
468                 if (err) {
469                         goto done;
470                 }
471         }
472 done:
473         if (free_data) {
474                 free(kern_data, M_USBDEV);
475         }
476         return (err);
477 }
478
479 static int
480 uhid_set_report(struct uhid_softc *sc, uint8_t type,
481     uint8_t id, void *kern_data, void *user_data,
482     uint16_t len)
483 {
484         int err;
485         uint8_t free_data = 0;
486
487         if (kern_data == NULL) {
488                 kern_data = malloc(len, M_USBDEV, M_WAITOK);
489                 free_data = 1;
490                 err = copyin(user_data, kern_data, len);
491                 if (err) {
492                         goto done;
493                 }
494         }
495         err = usbd_req_set_report(sc->sc_udev, NULL, kern_data,
496             len, sc->sc_iface_index, type, id);
497         if (err) {
498                 err = ENXIO;
499                 goto done;
500         }
501 done:
502         if (free_data) {
503                 free(kern_data, M_USBDEV);
504         }
505         return (err);
506 }
507
508 static int
509 uhid_open(struct usb_fifo *fifo, int fflags)
510 {
511         struct uhid_softc *sc = usb_fifo_softc(fifo);
512
513         /*
514          * The buffers are one byte larger than maximum so that one
515          * can detect too large read/writes and short transfers:
516          */
517         if (fflags & FREAD) {
518                 /* reset flags */
519                 mtx_lock(&sc->sc_mtx);
520                 sc->sc_flags &= ~UHID_FLAG_IMMED;
521                 mtx_unlock(&sc->sc_mtx);
522
523                 if (usb_fifo_alloc_buffer(fifo,
524                     sc->sc_isize + 1, UHID_FRAME_NUM)) {
525                         return (ENOMEM);
526                 }
527         }
528         if (fflags & FWRITE) {
529                 if (usb_fifo_alloc_buffer(fifo,
530                     sc->sc_osize + 1, UHID_FRAME_NUM)) {
531                         return (ENOMEM);
532                 }
533         }
534         return (0);
535 }
536
537 static void
538 uhid_close(struct usb_fifo *fifo, int fflags)
539 {
540         if (fflags & (FREAD | FWRITE)) {
541                 usb_fifo_free_buffer(fifo);
542         }
543 }
544
545 static int
546 uhid_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr,
547     int fflags)
548 {
549         struct uhid_softc *sc = usb_fifo_softc(fifo);
550         struct usb_gen_descriptor *ugd;
551         uint32_t size;
552         int error = 0;
553         uint8_t id;
554
555         switch (cmd) {
556         case USB_GET_REPORT_DESC:
557                 ugd = addr;
558                 if (sc->sc_repdesc_size > ugd->ugd_maxlen) {
559                         size = ugd->ugd_maxlen;
560                 } else {
561                         size = sc->sc_repdesc_size;
562                 }
563                 ugd->ugd_actlen = size;
564                 if (ugd->ugd_data == NULL)
565                         break;          /* descriptor length only */
566                 error = copyout(sc->sc_repdesc_ptr, ugd->ugd_data, size);
567                 break;
568
569         case USB_SET_IMMED:
570                 if (!(fflags & FREAD)) {
571                         error = EPERM;
572                         break;
573                 }
574                 if (*(int *)addr) {
575                         /* do a test read */
576
577                         error = uhid_get_report(sc, UHID_INPUT_REPORT,
578                             sc->sc_iid, NULL, NULL, sc->sc_isize);
579                         if (error) {
580                                 break;
581                         }
582                         mtx_lock(&sc->sc_mtx);
583                         sc->sc_flags |= UHID_FLAG_IMMED;
584                         mtx_unlock(&sc->sc_mtx);
585                 } else {
586                         mtx_lock(&sc->sc_mtx);
587                         sc->sc_flags &= ~UHID_FLAG_IMMED;
588                         mtx_unlock(&sc->sc_mtx);
589                 }
590                 break;
591
592         case USB_GET_REPORT:
593                 if (!(fflags & FREAD)) {
594                         error = EPERM;
595                         break;
596                 }
597                 ugd = addr;
598                 switch (ugd->ugd_report_type) {
599                 case UHID_INPUT_REPORT:
600                         size = sc->sc_isize;
601                         id = sc->sc_iid;
602                         break;
603                 case UHID_OUTPUT_REPORT:
604                         size = sc->sc_osize;
605                         id = sc->sc_oid;
606                         break;
607                 case UHID_FEATURE_REPORT:
608                         size = sc->sc_fsize;
609                         id = sc->sc_fid;
610                         break;
611                 default:
612                         return (EINVAL);
613                 }
614                 if (id != 0)
615                         copyin(ugd->ugd_data, &id, 1);
616                 error = uhid_get_report(sc, ugd->ugd_report_type, id,
617                     NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size));
618                 break;
619
620         case USB_SET_REPORT:
621                 if (!(fflags & FWRITE)) {
622                         error = EPERM;
623                         break;
624                 }
625                 ugd = addr;
626                 switch (ugd->ugd_report_type) {
627                 case UHID_INPUT_REPORT:
628                         size = sc->sc_isize;
629                         id = sc->sc_iid;
630                         break;
631                 case UHID_OUTPUT_REPORT:
632                         size = sc->sc_osize;
633                         id = sc->sc_oid;
634                         break;
635                 case UHID_FEATURE_REPORT:
636                         size = sc->sc_fsize;
637                         id = sc->sc_fid;
638                         break;
639                 default:
640                         return (EINVAL);
641                 }
642                 if (id != 0)
643                         copyin(ugd->ugd_data, &id, 1);
644                 error = uhid_set_report(sc, ugd->ugd_report_type, id,
645                     NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size));
646                 break;
647
648         case USB_GET_REPORT_ID:
649                 *(int *)addr = 0;       /* XXX: we only support reportid 0? */
650                 break;
651
652         default:
653                 error = ENOIOCTL;
654                 break;
655         }
656         return (error);
657 }
658
659 static int
660 uhid_ioctl_post(struct usb_fifo *fifo, u_long cmd, void *addr,
661     int fflags)
662 {
663         int error;
664
665         switch (cmd) {
666         case USB_GET_DEVICEINFO:
667                 error = ugen_fill_deviceinfo(fifo, addr);
668                 break;
669
670         default:
671                 error = EINVAL;
672                 break;
673         }
674         return (error);
675 }
676
677 static const STRUCT_USB_HOST_ID uhid_devs[] = {
678         /* generic HID class */
679         {USB_IFACE_CLASS(UICLASS_HID),},
680         /* the Xbox 360 gamepad doesn't use the HID class */
681         {USB_IFACE_CLASS(UICLASS_VENDOR),
682          USB_IFACE_SUBCLASS(UISUBCLASS_XBOX360_CONTROLLER),
683          USB_IFACE_PROTOCOL(UIPROTO_XBOX360_GAMEPAD),},
684 };
685
686 static int
687 uhid_probe(device_t dev)
688 {
689         struct usb_attach_arg *uaa = device_get_ivars(dev);
690         int error;
691         void *buf;
692         uint16_t len;
693
694         DPRINTFN(11, "\n");
695
696         if (uaa->usb_mode != USB_MODE_HOST)
697                 return (ENXIO);
698
699         error = usbd_lookup_id_by_uaa(uhid_devs, sizeof(uhid_devs), uaa);
700         if (error)
701                 return (error);
702
703         if (usb_test_quirk(uaa, UQ_HID_IGNORE))
704                 return (ENXIO);
705
706         /*
707          * Don't attach to mouse and keyboard devices, hence then no
708          * "nomatch" event is generated and then ums and ukbd won't
709          * attach properly when loaded.
710          */
711         if ((uaa->info.bInterfaceClass == UICLASS_HID) &&
712             (uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
713             (((uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD) &&
714               !usb_test_quirk(uaa, UQ_KBD_IGNORE)) ||
715              ((uaa->info.bInterfaceProtocol == UIPROTO_MOUSE) &&
716               !usb_test_quirk(uaa, UQ_UMS_IGNORE))))
717                 return (ENXIO);
718
719         /* Check for mandatory multitouch usages to give wmt(4) a chance */
720         if (!usb_test_quirk(uaa, UQ_WMT_IGNORE)) {
721                 error = usbd_req_get_hid_desc(uaa->device, NULL,
722                     &buf, &len, M_USBDEV, uaa->info.bIfaceIndex);
723                 /* Let HID decscriptor-less devices to be handled at attach */
724                 if (!error) {
725                         if (hid_locate(buf, len,
726                             HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACT_MAX),
727                             hid_feature, 0, NULL, NULL, NULL) &&
728                             hid_locate(buf, len,
729                             HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTID),
730                             hid_input, 0, NULL, NULL, NULL)) {
731                                 free(buf, M_USBDEV);
732                                 return (ENXIO);
733                         }
734                         free(buf, M_USBDEV);
735                 }
736         }
737
738         return (BUS_PROBE_GENERIC);
739 }
740
741 static int
742 uhid_attach(device_t dev)
743 {
744         struct usb_attach_arg *uaa = device_get_ivars(dev);
745         struct uhid_softc *sc = device_get_softc(dev);
746         int unit = device_get_unit(dev);
747         int error = 0;
748
749         DPRINTFN(10, "sc=%p\n", sc);
750
751         device_set_usb_desc(dev);
752
753         mtx_init(&sc->sc_mtx, "uhid lock", NULL, MTX_DEF | MTX_RECURSE);
754
755         sc->sc_udev = uaa->device;
756
757         sc->sc_iface_no = uaa->info.bIfaceNum;
758         sc->sc_iface_index = uaa->info.bIfaceIndex;
759
760         error = usbd_transfer_setup(uaa->device,
761             &uaa->info.bIfaceIndex, sc->sc_xfer, uhid_config,
762             UHID_N_TRANSFER, sc, &sc->sc_mtx);
763
764         if (error) {
765                 DPRINTF("error=%s\n", usbd_errstr(error));
766                 goto detach;
767         }
768         if (uaa->info.idVendor == USB_VENDOR_WACOM) {
769                 /* the report descriptor for the Wacom Graphire is broken */
770
771                 if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE) {
772                         sc->sc_repdesc_size = sizeof(uhid_graphire_report_descr);
773                         sc->sc_repdesc_ptr = __DECONST(void *, &uhid_graphire_report_descr);
774                         sc->sc_flags |= UHID_FLAG_STATIC_DESC;
775
776                 } else if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE3_4X5) {
777                         static uint8_t reportbuf[] = {2, 2, 2};
778
779                         /*
780                          * The Graphire3 needs 0x0202 to be written to
781                          * feature report ID 2 before it'll start
782                          * returning digitizer data.
783                          */
784                         error = usbd_req_set_report(uaa->device, NULL,
785                             reportbuf, sizeof(reportbuf),
786                             uaa->info.bIfaceIndex, UHID_FEATURE_REPORT, 2);
787
788                         if (error) {
789                                 DPRINTF("set report failed, error=%s (ignored)\n",
790                                     usbd_errstr(error));
791                         }
792                         sc->sc_repdesc_size = sizeof(uhid_graphire3_4x5_report_descr);
793                         sc->sc_repdesc_ptr = __DECONST(void *, &uhid_graphire3_4x5_report_descr);
794                         sc->sc_flags |= UHID_FLAG_STATIC_DESC;
795                 }
796         } else if ((uaa->info.bInterfaceClass == UICLASS_VENDOR) &&
797             (uaa->info.bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER) &&
798             (uaa->info.bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD)) {
799                 static const uint8_t reportbuf[3] = {1, 3, 0};
800                 /*
801                  * Turn off the four LEDs on the gamepad which
802                  * are blinking by default:
803                  */
804                 error = usbd_req_set_report(uaa->device, NULL,
805                     __DECONST(void *, reportbuf), sizeof(reportbuf),
806                     uaa->info.bIfaceIndex, UHID_OUTPUT_REPORT, 0);
807                 if (error) {
808                         DPRINTF("set output report failed, error=%s (ignored)\n",
809                             usbd_errstr(error));
810                 }
811                 /* the Xbox 360 gamepad has no report descriptor */
812                 sc->sc_repdesc_size = sizeof(uhid_xb360gp_report_descr);
813                 sc->sc_repdesc_ptr = __DECONST(void *, &uhid_xb360gp_report_descr);
814                 sc->sc_flags |= UHID_FLAG_STATIC_DESC;
815         }
816         if (sc->sc_repdesc_ptr == NULL) {
817                 error = usbd_req_get_hid_desc(uaa->device, NULL,
818                     &sc->sc_repdesc_ptr, &sc->sc_repdesc_size,
819                     M_USBDEV, uaa->info.bIfaceIndex);
820
821                 if (error) {
822                         device_printf(dev, "no report descriptor\n");
823                         goto detach;
824                 }
825         }
826         error = usbd_req_set_idle(uaa->device, NULL,
827             uaa->info.bIfaceIndex, 0, 0);
828
829         if (error) {
830                 DPRINTF("set idle failed, error=%s (ignored)\n",
831                     usbd_errstr(error));
832         }
833         sc->sc_isize = hid_report_size_max
834             (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_input, &sc->sc_iid);
835
836         sc->sc_osize = hid_report_size_max
837             (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_output, &sc->sc_oid);
838
839         sc->sc_fsize = hid_report_size_max
840             (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_feature, &sc->sc_fid);
841
842         if (sc->sc_isize > UHID_BSIZE) {
843                 DPRINTF("input size is too large, "
844                     "%d bytes (truncating)\n",
845                     sc->sc_isize);
846                 sc->sc_isize = UHID_BSIZE;
847         }
848         if (sc->sc_osize > UHID_BSIZE) {
849                 DPRINTF("output size is too large, "
850                     "%d bytes (truncating)\n",
851                     sc->sc_osize);
852                 sc->sc_osize = UHID_BSIZE;
853         }
854         if (sc->sc_fsize > UHID_BSIZE) {
855                 DPRINTF("feature size is too large, "
856                     "%d bytes (truncating)\n",
857                     sc->sc_fsize);
858                 sc->sc_fsize = UHID_BSIZE;
859         }
860
861         error = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx,
862             &uhid_fifo_methods, &sc->sc_fifo,
863             unit, -1, uaa->info.bIfaceIndex,
864             UID_ROOT, GID_OPERATOR, 0644);
865         if (error) {
866                 goto detach;
867         }
868         return (0);                     /* success */
869
870 detach:
871         uhid_detach(dev);
872         return (ENOMEM);
873 }
874
875 static int
876 uhid_detach(device_t dev)
877 {
878         struct uhid_softc *sc = device_get_softc(dev);
879
880         usb_fifo_detach(&sc->sc_fifo);
881
882         usbd_transfer_unsetup(sc->sc_xfer, UHID_N_TRANSFER);
883
884         if (sc->sc_repdesc_ptr) {
885                 if (!(sc->sc_flags & UHID_FLAG_STATIC_DESC)) {
886                         free(sc->sc_repdesc_ptr, M_USBDEV);
887                 }
888         }
889         mtx_destroy(&sc->sc_mtx);
890
891         return (0);
892 }
893
894 static devclass_t uhid_devclass;
895
896 static device_method_t uhid_methods[] = {
897         DEVMETHOD(device_probe, uhid_probe),
898         DEVMETHOD(device_attach, uhid_attach),
899         DEVMETHOD(device_detach, uhid_detach),
900
901         DEVMETHOD_END
902 };
903
904 static driver_t uhid_driver = {
905         .name = "uhid",
906         .methods = uhid_methods,
907         .size = sizeof(struct uhid_softc),
908 };
909
910 DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, NULL, 0);
911 MODULE_DEPEND(uhid, usb, 1, 1, 1);
912 MODULE_DEPEND(uhid, hid, 1, 1, 1);
913 MODULE_VERSION(uhid, 1);
914 #ifndef USBHID_ENABLED
915 USB_PNP_HOST_INFO(uhid_devs);
916 #endif