The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/usb/input/uhid.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: ef7dff151c6f7bfb6f295728f6aa4186


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.