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_snes.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 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright 2013, Michael Terrell <vashisnotatree@gmail.com>
    5  * Copyright 2018, Johannes Lundberg <johalun0@gmail.com>
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  * $FreeBSD$
   30  */
   31 
   32 #include <sys/param.h>
   33 #include <sys/module.h>
   34 #include <sys/kernel.h>
   35 #include <sys/systm.h>
   36 
   37 #include <sys/conf.h>
   38 #include <sys/bus.h>
   39 #include <sys/lock.h>
   40 #include <sys/mutex.h>
   41 #include <sys/syslog.h>
   42 #include <sys/fcntl.h>
   43 
   44 #include <dev/usb/usb.h>
   45 #include <dev/usb/usbdi.h>
   46 #include <dev/usb/usbdi_util.h>
   47 
   48 #include <dev/usb/usbhid.h>
   49 #include <dev/usb/usb_ioctl.h>
   50 
   51 #include "usb_rdesc.h"
   52 
   53 #define UHID_SNES_IFQ_MAX_LEN 8
   54 
   55 #define UREQ_GET_PORT_STATUS 0x01
   56 #define UREQ_SOFT_RESET      0x02
   57 
   58 #define UP      0x7f00
   59 #define DOWN    0x7fff
   60 #define LEFT    0x00ff
   61 #define RIGHT   0xff7f
   62 #define X       0x1f
   63 #define Y       0x8f
   64 #define A       0x2f
   65 #define B       0x4f
   66 #define SELECT  0x10
   67 #define START   0x20
   68 #define LEFT_T  0x01
   69 #define RIGHT_T 0x02
   70 
   71 static const uint8_t uhid_snes_report_descr[] = { UHID_SNES_REPORT_DESCR() };
   72 #define SNES_DEV(v,p,i) { USB_VPI(v,p,i) }
   73 
   74 static const STRUCT_USB_HOST_ID snes_devs[] = {
   75         SNES_DEV(0x0810, 0xe501, 0), /* GeeekPi K-0161 */
   76         SNES_DEV(0x0079, 0x0011, 0)  /* Dragonrise */
   77 };
   78 
   79 enum {
   80         UHID_SNES_INTR_DT_RD,
   81         UHID_SNES_STATUS_DT_RD,
   82         UHID_SNES_N_TRANSFER
   83 };
   84 
   85 struct uhid_snes_softc {
   86         device_t sc_dev;
   87         struct usb_device *sc_usb_device;
   88         struct mtx sc_mutex;
   89         struct usb_callout sc_watchdog;
   90         uint8_t sc_iface_num;
   91         struct usb_xfer *sc_transfer[UHID_SNES_N_TRANSFER];
   92         struct usb_fifo_sc sc_fifo;
   93         struct usb_fifo_sc sc_fifo_no_reset;
   94         int sc_fflags;
   95         struct usb_fifo *sc_fifo_open[2];
   96         uint8_t sc_zero_length_packets;
   97         uint8_t sc_iid;
   98         uint8_t sc_oid;
   99         uint8_t sc_fid;
  100         uint8_t sc_iface_index;
  101 
  102         uint32_t sc_isize;
  103         uint32_t sc_osize;
  104         uint32_t sc_fsize;
  105 
  106         void *sc_repdesc_ptr;
  107 
  108         uint16_t sc_repdesc_size;
  109 
  110         struct usb_device *sc_udev;
  111 #define UHID_FLAG_IMMED        0x01     /* set if read should be immediate */
  112 
  113 };
  114 
  115 static device_probe_t uhid_snes_probe;
  116 static device_attach_t uhid_snes_attach;
  117 static device_detach_t uhid_snes_detach;
  118 
  119 static usb_fifo_open_t uhid_snes_open;
  120 static usb_fifo_close_t uhid_snes_close;
  121 static usb_fifo_ioctl_t uhid_snes_ioctl;
  122 static usb_fifo_cmd_t uhid_snes_start_read;
  123 static usb_fifo_cmd_t uhid_snes_stop_read;
  124 
  125 static void uhid_snes_reset(struct uhid_snes_softc *);
  126 static void uhid_snes_watchdog(void *);
  127 
  128 static usb_callback_t uhid_snes_read_callback;
  129 static usb_callback_t uhid_snes_status_callback;
  130 
  131 static struct usb_fifo_methods uhid_snes_fifo_methods = {
  132         .f_open = &uhid_snes_open,
  133         .f_close = &uhid_snes_close,
  134         .f_ioctl = &uhid_snes_ioctl,
  135         .f_start_read = &uhid_snes_start_read,
  136         .f_stop_read = &uhid_snes_stop_read,
  137         .basename[0] = "uhid_snes"
  138 };
  139 
  140 static const struct usb_config uhid_snes_config[UHID_SNES_N_TRANSFER] = {
  141         [UHID_SNES_INTR_DT_RD] = {
  142                 .callback = &uhid_snes_read_callback,
  143                 .bufsize = sizeof(struct usb_device_request) +1,
  144                 .flags = {.short_xfer_ok = 1, .short_frames_ok = 1,
  145                           .pipe_bof =1, .proxy_buffer =1},
  146                 .type = UE_INTERRUPT,
  147                 .endpoint = 0x81,
  148                 .direction = UE_DIR_IN
  149         },
  150         [UHID_SNES_STATUS_DT_RD] = {
  151                 .callback = &uhid_snes_status_callback,
  152                 .bufsize = sizeof(struct usb_device_request) + 1,
  153                 .timeout = 1000,
  154                 .type = UE_CONTROL,
  155                 .endpoint = 0x00,
  156                 .direction = UE_DIR_ANY
  157         }
  158 };
  159 
  160 static int
  161 uhid_get_report(struct uhid_snes_softc *sc, uint8_t type,
  162     uint8_t id, void *kern_data, void *user_data, uint16_t len)
  163 {
  164         int err;
  165         uint8_t free_data = 0;
  166 
  167         if (kern_data == NULL) {
  168                 kern_data = malloc(len, M_USBDEV, M_WAITOK);
  169                 free_data = 1;
  170         }
  171         err = usbd_req_get_report(sc->sc_udev, NULL, kern_data,
  172             len, sc->sc_iface_index, type, id);
  173         if (err) {
  174                 err = ENXIO;
  175                 goto done;
  176         }
  177         if (user_data) {
  178                 /* dummy buffer */
  179                 err = copyout(kern_data, user_data, len);
  180                 if (err) {
  181                         goto done;
  182                 }
  183         }
  184 done:
  185         if (free_data) {
  186                 free(kern_data, M_USBDEV);
  187         }
  188         return (err);
  189 }
  190 
  191 static int
  192 uhid_set_report(struct uhid_snes_softc *sc, uint8_t type,
  193     uint8_t id, void *kern_data, void *user_data, uint16_t len)
  194 {
  195         int err;
  196         uint8_t free_data = 0;
  197 
  198         if (kern_data == NULL) {
  199                 kern_data = malloc(len, M_USBDEV, M_WAITOK);
  200                 free_data = 1;
  201                 err = copyin(user_data, kern_data, len);
  202                 if (err) {
  203                         goto done;
  204                 }
  205         }
  206         err = usbd_req_set_report(sc->sc_udev, NULL, kern_data,
  207             len, sc->sc_iface_index, type, id);
  208         if (err) {
  209                 err = ENXIO;
  210                 goto done;
  211         }
  212 done:
  213         if (free_data) {
  214                 free(kern_data, M_USBDEV);
  215         }
  216         return (err);
  217 }
  218 
  219 static int
  220 uhid_snes_open(struct usb_fifo *fifo, int fflags)
  221 {
  222         struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
  223         int error;
  224 
  225         if (sc->sc_fflags & fflags) {
  226                 uhid_snes_reset(sc);
  227                 return (EBUSY);
  228         }
  229 
  230         mtx_lock(&sc->sc_mutex);
  231         usbd_xfer_set_stall(sc->sc_transfer[UHID_SNES_INTR_DT_RD]);
  232         mtx_unlock(&sc->sc_mutex);
  233 
  234         error = usb_fifo_alloc_buffer(fifo,
  235             usbd_xfer_max_len(sc->sc_transfer[UHID_SNES_INTR_DT_RD]),
  236             UHID_SNES_IFQ_MAX_LEN);
  237         if (error)
  238                 return (ENOMEM);
  239 
  240         sc->sc_fifo_open[USB_FIFO_RX] = fifo;
  241 
  242         return (0);
  243 }
  244 
  245 static void
  246 uhid_snes_reset(struct uhid_snes_softc *sc)
  247 {
  248         struct usb_device_request req;
  249         int error;
  250 
  251         req.bRequest = UREQ_SOFT_RESET;
  252         USETW(req.wValue, 0);
  253         USETW(req.wIndex, sc->sc_iface_num);
  254         USETW(req.wLength, 0);
  255 
  256         mtx_lock(&sc->sc_mutex);
  257 
  258         error = usbd_do_request_flags(sc->sc_usb_device, &sc->sc_mutex,
  259             &req, NULL, 0, NULL, 2 * USB_MS_HZ);
  260 
  261         if (error) {
  262                 usbd_do_request_flags(sc->sc_usb_device, &sc->sc_mutex,
  263                     &req, NULL, 0, NULL, 2 * USB_MS_HZ);
  264         }
  265 
  266         mtx_unlock(&sc->sc_mutex);
  267 }
  268 
  269 static void
  270 uhid_snes_close(struct usb_fifo *fifo, int fflags)
  271 {
  272         struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
  273 
  274         sc->sc_fflags &= ~(fflags & FREAD);
  275         usb_fifo_free_buffer(fifo);
  276 }
  277 
  278 static int
  279 uhid_snes_ioctl(struct usb_fifo *fifo, u_long cmd, void *data, int fflags)
  280 {
  281         struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
  282         struct usb_gen_descriptor *ugd;
  283 #ifdef COMPAT_FREEBSD32
  284         struct usb_gen_descriptor local_ugd;
  285         struct usb_gen_descriptor32 *ugd32 = NULL;
  286 #endif
  287         uint32_t size;
  288         int error = 0;
  289         uint8_t id;
  290 
  291         ugd = data;
  292 #ifdef COMPAT_FREEBSD32
  293         switch (cmd) {
  294         case USB_GET_REPORT_DESC32:
  295         case USB_GET_REPORT32:
  296         case USB_SET_REPORT32:
  297                 ugd32 = data;
  298                 ugd = &local_ugd;
  299                 usb_gen_descriptor_from32(ugd, ugd32);
  300                 cmd = _IOC_NEWTYPE(cmd, struct usb_gen_descriptor);
  301                 break;
  302         }
  303 #endif
  304 
  305         switch (cmd) {
  306         case USB_GET_REPORT_DESC:
  307                 if (sc->sc_repdesc_size > ugd->ugd_maxlen) {
  308                         size = ugd->ugd_maxlen;
  309                 } else {
  310                         size = sc->sc_repdesc_size;
  311                 }
  312 
  313                 ugd->ugd_actlen = size;
  314                 if (ugd->ugd_data == NULL)
  315                         break; /* descriptor length only*/
  316                 error = copyout(sc->sc_repdesc_ptr, ugd->ugd_data, size);
  317                 break;
  318 
  319         case USB_SET_IMMED:
  320                 if (!(fflags & FREAD)) {
  321                         error = EPERM;
  322                         break;
  323                 }
  324 
  325                 if (*(int *)data) {
  326                         /* do a test read */
  327                         error = uhid_get_report(sc, UHID_INPUT_REPORT,
  328                             sc->sc_iid, NULL, NULL, sc->sc_isize);
  329                         if (error) {
  330                                 break;
  331                         }
  332                         mtx_lock(&sc->sc_mutex);
  333                         sc->sc_fflags |= UHID_FLAG_IMMED;
  334                         mtx_unlock(&sc->sc_mutex);
  335                 } else {
  336                         mtx_lock(&sc->sc_mutex);
  337                         sc->sc_fflags &= ~UHID_FLAG_IMMED;
  338                         mtx_unlock(&sc->sc_mutex);
  339                 }
  340                 break;
  341 
  342         case USB_GET_REPORT:
  343                 if (!(fflags & FREAD)) {
  344                         error = EPERM;
  345                         break;
  346                 }
  347                 switch (ugd->ugd_report_type) {
  348                 case UHID_INPUT_REPORT:
  349                         size = sc->sc_isize;
  350                         id = sc->sc_iid;
  351                         break;
  352                 case UHID_OUTPUT_REPORT:
  353                         size = sc->sc_osize;
  354                         id = sc->sc_oid;
  355                         break;
  356                 case UHID_FEATURE_REPORT:
  357                         size = sc->sc_fsize;
  358                         id = sc->sc_fid;
  359                         break;
  360                 default:
  361                         return (EINVAL);
  362                 }
  363                 if (id != 0)
  364                         copyin(ugd->ugd_data, &id, 1);
  365                 error = uhid_get_report(sc, ugd->ugd_report_type, id,
  366                     NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size));
  367                 break;
  368 
  369         case USB_SET_REPORT:
  370                 if (!(fflags & FWRITE)) {
  371                         error = EPERM;
  372                         break;
  373                 }
  374                 switch (ugd->ugd_report_type) {
  375                 case UHID_INPUT_REPORT:
  376                         size = sc->sc_isize;
  377                         id = sc->sc_iid;
  378                         break;
  379                 case UHID_OUTPUT_REPORT:
  380                         size = sc->sc_osize;
  381                         id = sc->sc_oid;
  382                         break;
  383                 case UHID_FEATURE_REPORT:
  384                         size = sc->sc_fsize;
  385                         id = sc->sc_fid;
  386                         break;
  387                 default:
  388                         return (EINVAL);
  389                 }
  390                 if (id != 0)
  391                         copyin(ugd->ugd_data, &id, 1);
  392                 error = uhid_set_report(sc, ugd->ugd_report_type, id,
  393                     NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size));
  394                 break;
  395 
  396         case USB_GET_REPORT_ID:
  397                 /* XXX: we only support reportid 0? */
  398                 *(int *)data = 0;
  399                 break;
  400 
  401         default:
  402                 error = EINVAL;
  403                 break;
  404         }
  405 
  406 #ifdef COMPAT_FREEBSD32
  407         if (ugd32 != NULL)
  408                 update_usb_gen_descriptor32(ugd32, ugd);
  409 #endif
  410         return (error);
  411 }
  412 
  413 static void
  414 uhid_snes_watchdog(void *arg)
  415 {
  416         struct uhid_snes_softc *sc = arg;
  417 
  418         mtx_assert(&sc->sc_mutex, MA_OWNED);
  419 
  420         if (sc->sc_fflags == 0)
  421                 usbd_transfer_start(sc->sc_transfer[UHID_SNES_STATUS_DT_RD]);
  422 
  423         usb_callout_reset(&sc->sc_watchdog, hz, &uhid_snes_watchdog, sc);
  424 }
  425 
  426 static void
  427 uhid_snes_start_read(struct usb_fifo *fifo)
  428 {
  429         struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
  430 
  431         usbd_transfer_start(sc->sc_transfer[UHID_SNES_INTR_DT_RD]);
  432 }
  433 
  434 static void
  435 uhid_snes_stop_read(struct usb_fifo *fifo)
  436 {
  437         struct uhid_snes_softc *sc = usb_fifo_softc(fifo);
  438 
  439         usbd_transfer_stop(sc->sc_transfer[UHID_SNES_INTR_DT_RD]);
  440 }
  441 
  442 static void
  443 uhid_snes_read_callback(struct usb_xfer *transfer, usb_error_t error)
  444 {
  445         struct uhid_snes_softc *sc = usbd_xfer_softc(transfer);
  446         struct usb_fifo *fifo = sc->sc_fifo_open[USB_FIFO_RX];
  447         struct usb_page_cache *pc;
  448         int actual, max;
  449 
  450         usbd_xfer_status(transfer, &actual, NULL, NULL, NULL);
  451         if (fifo == NULL)
  452                 return;
  453 
  454         switch (USB_GET_STATE(transfer)) {
  455         case USB_ST_TRANSFERRED:
  456                 if (actual == 0) {
  457                         if (sc->sc_zero_length_packets == 4)
  458                                 /* Throttle transfers. */
  459                                 usbd_xfer_set_interval(transfer, 500);
  460                         else
  461                                 sc->sc_zero_length_packets++;
  462 
  463                 } else {
  464                         /* disable throttling. */
  465                         usbd_xfer_set_interval(transfer, 0);
  466                         sc->sc_zero_length_packets = 0;
  467                 }
  468                 pc = usbd_xfer_get_frame(transfer, 0);
  469                 usb_fifo_put_data(fifo, pc, 0, actual, 1);
  470                 /* Fall through */
  471         setup:
  472         case USB_ST_SETUP:
  473                 if (usb_fifo_put_bytes_max(fifo) != 0) {
  474                         max = usbd_xfer_max_len(transfer);
  475                         usbd_xfer_set_frame_len(transfer, 0, max);
  476                         usbd_transfer_submit(transfer);
  477                 }
  478                 break;
  479 
  480         default:
  481                 /*disable throttling. */
  482                 usbd_xfer_set_interval(transfer, 0);
  483                 sc->sc_zero_length_packets = 0;
  484 
  485                 if (error != USB_ERR_CANCELLED) {
  486                         /* Issue a clear-stall request. */
  487                         usbd_xfer_set_stall(transfer);
  488                         goto setup;
  489                 }
  490                 break;
  491         }
  492 }
  493 
  494 static void
  495 uhid_snes_status_callback(struct usb_xfer *transfer, usb_error_t error)
  496 {
  497         struct uhid_snes_softc *sc = usbd_xfer_softc(transfer);
  498         struct usb_device_request req;
  499         struct usb_page_cache *pc;
  500 
  501         switch (USB_GET_STATE(transfer)) {
  502         case USB_ST_SETUP:
  503                 req.bmRequestType = UT_READ_CLASS_INTERFACE;
  504                 req.bRequest = UREQ_GET_PORT_STATUS;
  505                 USETW(req.wValue, 0);
  506                 req.wIndex[0] = sc->sc_iface_num;
  507                 req.wIndex[1] = 0;
  508                 USETW(req.wLength, 1);
  509 
  510                 pc = usbd_xfer_get_frame(transfer, 0);
  511                 usbd_copy_in(pc, 0, &req, sizeof(req));
  512                 usbd_xfer_set_frame_len(transfer, 0, sizeof(req));
  513                 usbd_xfer_set_frame_len(transfer, 1, 1);
  514                 usbd_xfer_set_frames(transfer, 2);
  515                 usbd_transfer_submit(transfer);
  516                 break;
  517 
  518         default:
  519                 break;
  520         }
  521 
  522 }
  523 
  524 static int
  525 uhid_snes_probe(device_t dev)
  526 {
  527         struct usb_attach_arg *uaa = device_get_ivars(dev);
  528 
  529         if (uaa->usb_mode != USB_MODE_HOST)
  530                 return (ENXIO);
  531 
  532         return (usbd_lookup_id_by_uaa(snes_devs, sizeof(snes_devs), uaa));
  533 }
  534 
  535 static int
  536 uhid_snes_attach(device_t dev)
  537 {
  538         struct usb_attach_arg *uaa = device_get_ivars(dev);
  539         struct uhid_snes_softc *sc = device_get_softc(dev);
  540         struct usb_interface_descriptor *idesc;
  541         struct usb_config_descriptor *cdesc;
  542         uint8_t alt_index, iface_index = uaa->info.bIfaceIndex;
  543         int error,unit = device_get_unit(dev);
  544 
  545         sc->sc_dev = dev;
  546         sc->sc_usb_device = uaa->device;
  547         device_set_usb_desc(dev);
  548         mtx_init(&sc->sc_mutex, "uhid_snes", NULL, MTX_DEF | MTX_RECURSE);
  549         usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mutex, 0);
  550 
  551         idesc = usbd_get_interface_descriptor(uaa->iface);
  552         alt_index = -1;
  553         for(;;) {
  554                 if (idesc == NULL)
  555                         break;
  556 
  557                 if ((idesc->bDescriptorType == UDESC_INTERFACE) &&
  558                      (idesc->bLength >= sizeof(*idesc))) {
  559                         if (idesc->bInterfaceNumber != uaa->info.bIfaceNum) {
  560                                 break;
  561                         } else {
  562                                 alt_index++;
  563                                 if (idesc->bInterfaceClass == UICLASS_HID)
  564                                         goto found;
  565                         }
  566                 }
  567 
  568                 cdesc = usbd_get_config_descriptor(uaa->device);
  569                 idesc = (void *)usb_desc_foreach(cdesc, (void *)idesc);
  570                 goto found;
  571         }
  572         goto detach;
  573 
  574 found:
  575         if (alt_index) {
  576                 error = usbd_set_alt_interface_index(uaa->device, iface_index, alt_index);
  577                 if (error)
  578                         goto detach;
  579         }
  580 
  581         sc->sc_iface_num = idesc->bInterfaceNumber;
  582 
  583         error = usbd_transfer_setup(uaa->device, &iface_index,
  584             sc->sc_transfer, uhid_snes_config, UHID_SNES_N_TRANSFER, sc,
  585             &sc->sc_mutex);
  586 
  587         if (error)
  588                 goto detach;
  589 
  590         error = usb_fifo_attach(uaa->device, sc, &sc->sc_mutex,
  591             &uhid_snes_fifo_methods, &sc->sc_fifo, unit, -1,
  592             iface_index, UID_ROOT, GID_OPERATOR, 0644);
  593         sc->sc_repdesc_size = sizeof(uhid_snes_report_descr);
  594         sc->sc_repdesc_ptr = __DECONST(void*, &uhid_snes_report_descr);
  595 
  596         if (error)
  597                 goto detach;
  598 
  599         mtx_lock(&sc->sc_mutex);
  600         uhid_snes_watchdog(sc);
  601         mtx_unlock(&sc->sc_mutex);
  602         return (0);
  603 
  604 detach:
  605         uhid_snes_detach(dev);
  606         return (ENOMEM);
  607 }
  608 
  609 static int
  610 uhid_snes_detach(device_t dev)
  611 {
  612         struct uhid_snes_softc *sc = device_get_softc(dev);
  613 
  614         usb_fifo_detach(&sc->sc_fifo);
  615         usb_fifo_detach(&sc->sc_fifo_no_reset);
  616 
  617         mtx_lock(&sc->sc_mutex);
  618         usb_callout_stop(&sc->sc_watchdog);
  619         mtx_unlock(&sc->sc_mutex);
  620 
  621         usbd_transfer_unsetup(sc->sc_transfer, UHID_SNES_N_TRANSFER);
  622         usb_callout_drain(&sc->sc_watchdog);
  623         mtx_destroy(&sc->sc_mutex);
  624 
  625         return (0);
  626 }
  627 
  628 static device_method_t uhid_snes_methods[] = {
  629         DEVMETHOD(device_probe, uhid_snes_probe),
  630         DEVMETHOD(device_attach, uhid_snes_attach),
  631         DEVMETHOD(device_detach, uhid_snes_detach),
  632         DEVMETHOD_END
  633 };
  634 
  635 static driver_t uhid_snes_driver = {
  636         "uhid_snes",
  637         uhid_snes_methods,
  638         sizeof(struct uhid_snes_softc)
  639 };
  640 
  641 DRIVER_MODULE(uhid_snes, uhub, uhid_snes_driver, NULL, NULL);
  642 MODULE_DEPEND(uhid_snes, usb, 1, 1, 1);
  643 USB_PNP_HOST_INFO(snes_devs);

Cache object: 6a602802bedbdc7f50a33c9210c1392b


[ 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.