root/dev/usb/uhidev.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. uhidev_match
  2. uhidev_attach
  3. uhidev_maxrepid
  4. uhidevprint
  5. uhidevsubmatch
  6. uhidev_activate
  7. uhidev_detach
  8. uhidev_intr
  9. uhidev_get_report_desc
  10. uhidev_open
  11. uhidev_close
  12. uhidev_set_report
  13. uhidev_set_report_async
  14. uhidev_get_report
  15. uhidev_write

    1 /*      $OpenBSD: uhidev.c,v 1.27 2007/06/14 10:11:16 mbalmer Exp $     */
    2 /*      $NetBSD: uhidev.c,v 1.14 2003/03/11 16:44:00 augustss Exp $     */
    3 
    4 /*
    5  * Copyright (c) 2001 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Lennart Augustsson (lennart@augustsson.net) at
   10  * Carlstedt Research & Technology.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *        This product includes software developed by the NetBSD
   23  *        Foundation, Inc. and its contributors.
   24  * 4. Neither the name of The NetBSD Foundation nor the names of its
   25  *    contributors may be used to endorse or promote products derived
   26  *    from this software without specific prior written permission.
   27  *
   28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   38  * POSSIBILITY OF SUCH DAMAGE.
   39  */
   40 
   41 /*
   42  * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
   43  */
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/kernel.h>
   48 #include <sys/malloc.h>
   49 #include <sys/signalvar.h>
   50 #include <sys/device.h>
   51 #include <sys/ioctl.h>
   52 #include <sys/conf.h>
   53 
   54 #include <dev/usb/usb.h>
   55 #include <dev/usb/usbhid.h>
   56 
   57 #include <dev/usb/usbdevs.h>
   58 #include <dev/usb/usbdi.h>
   59 #include <dev/usb/usbdi_util.h>
   60 #include <dev/usb/hid.h>
   61 #include <dev/usb/usb_quirks.h>
   62 
   63 #include <dev/usb/uhidev.h>
   64 
   65 /* Report descriptor for broken Wacom Graphire */
   66 #include <dev/usb/ugraphire_rdesc.h>
   67 
   68 #ifdef UHIDEV_DEBUG
   69 #define DPRINTF(x)      do { if (uhidevdebug) printf x; } while (0)
   70 #define DPRINTFN(n,x)   do { if (uhidevdebug>(n)) printf x; } while (0)
   71 int     uhidevdebug = 0;
   72 #else
   73 #define DPRINTF(x)
   74 #define DPRINTFN(n,x)
   75 #endif
   76 
   77 void uhidev_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
   78 
   79 int uhidev_maxrepid(void *buf, int len);
   80 int uhidevprint(void *aux, const char *pnp);
   81 int uhidevsubmatch(struct device *parent, void *cf, void *aux);
   82 
   83 int uhidev_match(struct device *, void *, void *); 
   84 void uhidev_attach(struct device *, struct device *, void *); 
   85 int uhidev_detach(struct device *, int); 
   86 int uhidev_activate(struct device *, enum devact); 
   87 
   88 struct cfdriver uhidev_cd = { 
   89         NULL, "uhidev", DV_DULL 
   90 }; 
   91 
   92 const struct cfattach uhidev_ca = { 
   93         sizeof(struct uhidev_softc), 
   94         uhidev_match, 
   95         uhidev_attach, 
   96         uhidev_detach, 
   97         uhidev_activate, 
   98 };
   99 
  100 int
  101 uhidev_match(struct device *parent, void *match, void *aux)
  102 {
  103         struct usb_attach_arg *uaa = aux;
  104         usb_interface_descriptor_t *id;
  105 
  106         if (uaa->iface == NULL)
  107                 return (UMATCH_NONE);
  108         id = usbd_get_interface_descriptor(uaa->iface);
  109         if (id == NULL || id->bInterfaceClass != UICLASS_HID)
  110                 return (UMATCH_NONE);
  111         if (usbd_get_quirks(uaa->device)->uq_flags & UQ_BAD_HID)
  112                 return (UMATCH_NONE);
  113         if (uaa->matchlvl)
  114                 return (uaa->matchlvl);
  115 
  116 #ifdef __macppc__
  117         /*
  118          * Some Apple laptops have USB phantom devices which match
  119          * the ADB devices.  We want to ignore them to avoid
  120          * confusing users, as the real hardware underneath is adb
  121          * and has already attached.
  122          */
  123         if (uaa->vendor == USB_VENDOR_APPLE &&
  124             uaa->product == USB_PRODUCT_APPLE_ADB)
  125                 return (UMATCH_NONE);
  126 #endif
  127 
  128         return (UMATCH_IFACECLASS_GENERIC);
  129 }
  130 
  131 void
  132 uhidev_attach(struct device *parent, struct device *self, void *aux)
  133 {
  134         struct uhidev_softc *sc = (struct uhidev_softc *)self;
  135         struct usb_attach_arg *uaa = aux;
  136         usbd_interface_handle iface = uaa->iface;
  137         usb_interface_descriptor_t *id;
  138         usb_endpoint_descriptor_t *ed;
  139         struct uhidev_attach_arg uha;
  140         struct uhidev *dev;
  141         int size, nrepid, repid, repsz;
  142         int repsizes[256];
  143         int i;
  144         void *desc;
  145         const void *descptr;
  146         usbd_status err;
  147         char *devinfop;
  148 
  149         sc->sc_udev = uaa->device;
  150         sc->sc_iface = iface;
  151         id = usbd_get_interface_descriptor(iface);
  152 
  153         devinfop = usbd_devinfo_alloc(uaa->device, 0);
  154         printf("\n%s: %s, iclass %d/%d\n", sc->sc_dev.dv_xname,
  155                devinfop, id->bInterfaceClass, id->bInterfaceSubClass);
  156         usbd_devinfo_free(devinfop);
  157 
  158         (void)usbd_set_idle(iface, 0, 0);
  159 #if 0
  160 
  161         qflags = usbd_get_quirks(sc->sc_udev)->uq_flags;
  162         if ((qflags & UQ_NO_SET_PROTO) == 0 &&
  163             id->bInterfaceSubClass != UISUBCLASS_BOOT)
  164                 (void)usbd_set_protocol(iface, 1);
  165 #endif
  166 
  167         sc->sc_iep_addr = sc->sc_oep_addr = -1;
  168         for (i = 0; i < id->bNumEndpoints; i++) {
  169                 ed = usbd_interface2endpoint_descriptor(iface, i);
  170                 if (ed == NULL) {
  171                         printf("%s: could not read endpoint descriptor\n",
  172                             sc->sc_dev.dv_xname);
  173                         sc->sc_dying = 1;
  174                         return;
  175                 }
  176 
  177                 DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d "
  178                     "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
  179                     " bInterval=%d\n",
  180                     ed->bLength, ed->bDescriptorType,
  181                     ed->bEndpointAddress & UE_ADDR,
  182                     UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
  183                     ed->bmAttributes & UE_XFERTYPE,
  184                     UGETW(ed->wMaxPacketSize), ed->bInterval));
  185 
  186                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  187                     (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
  188                         sc->sc_iep_addr = ed->bEndpointAddress;
  189                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
  190                     (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
  191                         sc->sc_oep_addr = ed->bEndpointAddress;
  192                 } else {
  193                         printf("%s: unexpected endpoint\n", sc->sc_dev.dv_xname);
  194                         sc->sc_dying = 1;
  195                         return;
  196                 }
  197         }
  198 
  199         /*
  200          * Check that we found an input interrupt endpoint. The output interrupt
  201          * endpoint is optional
  202          */
  203         if (sc->sc_iep_addr == -1) {
  204                 printf("%s: no input interrupt endpoint\n", sc->sc_dev.dv_xname);
  205                 sc->sc_dying = 1;
  206                 return;
  207         }
  208 
  209         /* XXX need to extend this */
  210         descptr = NULL;
  211         if (uaa->vendor == USB_VENDOR_WACOM) {
  212                 static uByte reportbuf[] = {2, 2, 2};
  213 
  214                 /* The report descriptor for the Wacom Graphire is broken. */
  215                 switch (uaa->product) {
  216                 case USB_PRODUCT_WACOM_GRAPHIRE:
  217                         size = sizeof uhid_graphire_report_descr;
  218                         descptr = uhid_graphire_report_descr;
  219                         break;
  220                 case USB_PRODUCT_WACOM_GRAPHIRE3_4X5:
  221                 case USB_PRODUCT_WACOM_GRAPHIRE4_4X5:
  222                         usbd_set_report(uaa->iface, UHID_FEATURE_REPORT, 2,
  223                             &reportbuf, sizeof reportbuf);
  224                         size = sizeof uhid_graphire3_4x5_report_descr;
  225                         descptr = uhid_graphire3_4x5_report_descr;
  226                         break;
  227                 default:
  228                         /* Keep descriptor */
  229                         break;
  230                 }
  231         }
  232 
  233         if (descptr) {
  234                 desc = malloc(size, M_USBDEV, M_NOWAIT);
  235                 if (desc == NULL)
  236                         err = USBD_NOMEM;
  237                 else {
  238                         err = USBD_NORMAL_COMPLETION;
  239                         memcpy(desc, descptr, size);
  240                 }
  241         } else {
  242                 desc = NULL;
  243                 err = usbd_read_report_desc(uaa->iface, &desc, &size, M_USBDEV);
  244         }
  245         if (err) {
  246                 printf("%s: no report descriptor\n", sc->sc_dev.dv_xname);
  247                 sc->sc_dying = 1;
  248                 return;
  249         }
  250 
  251         sc->sc_repdesc = desc;
  252         sc->sc_repdesc_size = size;
  253 
  254         uha.uaa = uaa;
  255         nrepid = uhidev_maxrepid(desc, size);
  256         if (nrepid < 0)
  257                 return;
  258         if (nrepid > 0)
  259                 printf("%s: %d report ids\n", sc->sc_dev.dv_xname, nrepid);
  260         nrepid++;
  261         sc->sc_subdevs = malloc(nrepid * sizeof(struct device *),
  262             M_USBDEV, M_NOWAIT);
  263         if (sc->sc_subdevs == NULL) {
  264                 printf("%s: no memory\n", sc->sc_dev.dv_xname);
  265                 return;
  266         }
  267         bzero(sc->sc_subdevs, nrepid * sizeof(struct device *));
  268         sc->sc_nrepid = nrepid;
  269         sc->sc_isize = 0;
  270 
  271         usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
  272                            &sc->sc_dev);
  273 
  274         for (repid = 0; repid < nrepid; repid++) {
  275                 repsz = hid_report_size(desc, size, hid_input, repid);
  276                 DPRINTF(("uhidev_match: repid=%d, repsz=%d\n", repid, repsz));
  277                 repsizes[repid] = repsz;
  278                 if (repsz > 0) {
  279                         if (repsz > sc->sc_isize)
  280                                 sc->sc_isize = repsz;
  281                 }
  282         }
  283         sc->sc_isize += nrepid != 1;    /* space for report ID */
  284         DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize));
  285 
  286         uha.parent = sc;
  287         for (repid = 0; repid < nrepid; repid++) {
  288                 DPRINTF(("uhidev_match: try repid=%d\n", repid));
  289                 if (hid_report_size(desc, size, hid_input, repid) == 0 &&
  290                     hid_report_size(desc, size, hid_output, repid) == 0 &&
  291                     hid_report_size(desc, size, hid_feature, repid) == 0) {
  292                         ;       /* already NULL in sc->sc_subdevs[repid] */
  293                 } else {
  294                         uha.reportid = repid;
  295                         dev = (struct uhidev *)config_found_sm(self, &uha,
  296                                                    uhidevprint, uhidevsubmatch);
  297                         sc->sc_subdevs[repid] = dev;
  298                         if (dev != NULL) {
  299                                 dev->sc_in_rep_size = repsizes[repid];
  300 #ifdef DIAGNOSTIC
  301                                 DPRINTF(("uhidev_match: repid=%d dev=%p\n",
  302                                          repid, dev));
  303                                 if (dev->sc_intr == NULL) {
  304                                         printf("%s: sc_intr == NULL\n",
  305                                                sc->sc_dev.dv_xname);
  306                                         return;
  307                                 }
  308 #endif
  309                         }
  310                 }
  311         }
  312 }
  313 
  314 int
  315 uhidev_maxrepid(void *buf, int len)
  316 {
  317         struct hid_data *d;
  318         struct hid_item h;
  319         int maxid;
  320 
  321         maxid = -1;
  322         h.report_ID = 0;
  323         for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); )
  324                 if (h.report_ID > maxid)
  325                         maxid = h.report_ID;
  326         hid_end_parse(d);
  327         return (maxid);
  328 }
  329 
  330 int
  331 uhidevprint(void *aux, const char *pnp)
  332 {
  333         struct uhidev_attach_arg *uha = aux;
  334 
  335         if (pnp)
  336                 printf("uhid at %s", pnp);
  337         if (uha->reportid != 0)
  338                 printf(" reportid %d", uha->reportid);
  339         return (UNCONF);
  340 }
  341 
  342 int uhidevsubmatch(struct device *parent, void *match, void *aux)
  343 {
  344         struct uhidev_attach_arg *uha = aux;
  345         struct cfdata *cf = match;
  346 
  347         if (cf->uhidevcf_reportid != UHIDEV_UNK_REPORTID &&
  348             cf->uhidevcf_reportid != uha->reportid)
  349                 return (0);
  350         if (cf->uhidevcf_reportid == uha->reportid)
  351                 uha->matchlvl = UMATCH_VENDOR_PRODUCT;
  352         else
  353                 uha->matchlvl = 0;
  354         return ((*cf->cf_attach->ca_match)(parent, cf, aux));
  355 }
  356 
  357 int
  358 uhidev_activate(struct device *self, enum devact act)
  359 {
  360         struct uhidev_softc *sc = (struct uhidev_softc *)self;
  361         int i, rv = 0;
  362 
  363         switch (act) {
  364         case DVACT_ACTIVATE:
  365                 break;
  366 
  367         case DVACT_DEACTIVATE:
  368                 for (i = 0; i < sc->sc_nrepid; i++)
  369                         if (sc->sc_subdevs[i] != NULL)
  370                                 rv |= config_deactivate(
  371                                         &sc->sc_subdevs[i]->sc_dev);
  372                 sc->sc_dying = 1;
  373                 break;
  374         }
  375         return (rv);
  376 }
  377 
  378 int
  379 uhidev_detach(struct device *self, int flags)
  380 {
  381         struct uhidev_softc *sc = (struct uhidev_softc *)self;
  382         int i, rv;
  383 
  384         DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags));
  385 
  386         sc->sc_dying = 1;
  387         if (sc->sc_ipipe != NULL)
  388                 usbd_abort_pipe(sc->sc_ipipe);
  389 
  390         if (sc->sc_repdesc != NULL)
  391                 free(sc->sc_repdesc, M_USBDEV);
  392 
  393         rv = 0;
  394         for (i = 0; i < sc->sc_nrepid; i++) {
  395                 if (sc->sc_subdevs[i] != NULL) {
  396                         rv |= config_detach(&sc->sc_subdevs[i]->sc_dev, flags);
  397                         sc->sc_subdevs[i] = NULL;
  398                 }
  399         }
  400 
  401         usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
  402                            &sc->sc_dev);
  403 
  404         return (rv);
  405 }
  406 
  407 void
  408 uhidev_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
  409 {
  410         struct uhidev_softc *sc = addr;
  411         struct uhidev *scd;
  412         u_char *p;
  413         u_int rep;
  414         u_int32_t cc;
  415 
  416         usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
  417 
  418 #ifdef UHIDEV_DEBUG
  419         if (uhidevdebug > 5) {
  420                 u_int32_t i;
  421 
  422                 DPRINTF(("uhidev_intr: status=%d cc=%d\n", status, cc));
  423                 DPRINTF(("uhidev_intr: data ="));
  424                 for (i = 0; i < cc; i++)
  425                         DPRINTF((" %02x", sc->sc_ibuf[i]));
  426                 DPRINTF(("\n"));
  427         }
  428 #endif
  429 
  430         if (status == USBD_CANCELLED)
  431                 return;
  432 
  433         if (status != USBD_NORMAL_COMPLETION) {
  434                 DPRINTF(("%s: interrupt status=%d\n", sc->sc_dev.dv_xname,
  435                          status));
  436                 usbd_clear_endpoint_stall_async(sc->sc_ipipe);
  437                 return;
  438         }
  439 
  440         p = sc->sc_ibuf;
  441         if (sc->sc_nrepid != 1)
  442                 rep = *p++, cc--;
  443         else
  444                 rep = 0;
  445         if (rep >= sc->sc_nrepid) {
  446                 printf("uhidev_intr: bad repid %d\n", rep);
  447                 return;
  448         }
  449         scd = sc->sc_subdevs[rep];
  450         DPRINTFN(5,("uhidev_intr: rep=%d, scd=%p state=0x%x\n",
  451                     rep, scd, scd ? scd->sc_state : 0));
  452         if (scd == NULL || !(scd->sc_state & UHIDEV_OPEN))
  453                 return;
  454 #ifdef UHIDEV_DEBUG
  455         if (scd->sc_in_rep_size != cc)
  456                 printf("%s: bad input length %d != %d\n",sc->sc_dev.dv_xname,
  457                        scd->sc_in_rep_size, cc);
  458 #endif
  459         scd->sc_intr(scd, p, cc);
  460 }
  461 
  462 void
  463 uhidev_get_report_desc(struct uhidev_softc *sc, void **desc, int *size)
  464 {
  465         *desc = sc->sc_repdesc;
  466         *size = sc->sc_repdesc_size;
  467 }
  468 
  469 int
  470 uhidev_open(struct uhidev *scd)
  471 {
  472         struct uhidev_softc *sc = scd->sc_parent;
  473         usbd_status err;
  474         int error;
  475 
  476         DPRINTF(("uhidev_open: open pipe, state=%d refcnt=%d\n",
  477                  scd->sc_state, sc->sc_refcnt));
  478 
  479         if (scd->sc_state & UHIDEV_OPEN)
  480                 return (EBUSY);
  481         scd->sc_state |= UHIDEV_OPEN;
  482         if (sc->sc_refcnt++)
  483                 return (0);
  484 
  485         if (sc->sc_isize == 0)
  486                 return (0);
  487 
  488         sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
  489 
  490         /* Set up input interrupt pipe. */
  491         DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize,
  492             sc->sc_iep_addr));
  493                 
  494         err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_iep_addr,
  495                   USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf,
  496                   sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL);
  497         if (err != USBD_NORMAL_COMPLETION) {
  498                 DPRINTF(("uhidopen: usbd_open_pipe_intr failed, "
  499                     "error=%d\n", err));
  500                 error = EIO;
  501                 goto out1;
  502         }
  503 
  504         DPRINTF(("uhidev_open: sc->sc_ipipe=%p\n", sc->sc_ipipe));
  505 
  506         sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
  507         if (sc->sc_ixfer == NULL) {
  508                 DPRINTF(("uhidev_open: couldn't allocate an xfer\n"));
  509                 error = ENOMEM;
  510                 goto out1; // xxxx
  511         }
  512 
  513         /*
  514          * Set up output interrupt pipe if an output interrupt endpoint
  515          * exists.
  516          */
  517         if (sc->sc_oep_addr != -1) {
  518                 DPRINTF(("uhidev_open: oep=0x%02x\n", sc->sc_oep_addr));
  519 
  520                 err = usbd_open_pipe(sc->sc_iface, sc->sc_oep_addr,
  521                     0, &sc->sc_opipe);
  522 
  523                 if (err != USBD_NORMAL_COMPLETION) {
  524                         DPRINTF(("uhidev_open: usbd_open_pipe failed, "
  525                             "error=%d\n", err));
  526                         error = EIO;
  527                         goto out2;
  528                 }
  529                 DPRINTF(("uhidev_open: sc->sc_opipe=%p\n", sc->sc_opipe));
  530 
  531                 sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
  532                 if (sc->sc_oxfer == NULL) {
  533                         DPRINTF(("uhidev_open: couldn't allocate an xfer\n"));
  534                         error = ENOMEM;
  535                         goto out3;
  536                 }
  537 
  538                 sc->sc_owxfer = usbd_alloc_xfer(sc->sc_udev);
  539                 if (sc->sc_owxfer == NULL) {
  540                         DPRINTF(("uhidev_open: couldn't allocate owxfer\n"));
  541                         error = ENOMEM;
  542                         goto out3;
  543                 }
  544         }
  545         
  546         return (0);
  547 
  548 out3:
  549         /* Abort output pipe */
  550         usbd_close_pipe(sc->sc_opipe);
  551 out2:
  552         /* Abort input pipe */
  553         usbd_close_pipe(sc->sc_ipipe);
  554 out1:
  555         DPRINTF(("uhidev_open: failed in someway"));
  556         free(sc->sc_ibuf, M_USBDEV);
  557         scd->sc_state &= ~UHIDEV_OPEN;
  558         sc->sc_refcnt = 0;
  559         sc->sc_ipipe = NULL;
  560         sc->sc_opipe = NULL;
  561         if (sc->sc_oxfer != NULL) {
  562                 usbd_free_xfer(sc->sc_oxfer);
  563                 sc->sc_oxfer = NULL;
  564         }
  565         if (sc->sc_owxfer != NULL) {
  566                 usbd_free_xfer(sc->sc_owxfer);
  567                 sc->sc_owxfer = NULL;
  568         }
  569         return (error);
  570 }
  571 
  572 void
  573 uhidev_close(struct uhidev *scd)
  574 {
  575         struct uhidev_softc *sc = scd->sc_parent;
  576 
  577         if (!(scd->sc_state & UHIDEV_OPEN))
  578                 return;
  579         scd->sc_state &= ~UHIDEV_OPEN;
  580         if (--sc->sc_refcnt)
  581                 return;
  582         DPRINTF(("uhidev_close: close pipe\n"));
  583 
  584         if (sc->sc_oxfer != NULL)
  585                 usbd_free_xfer(sc->sc_oxfer);
  586 
  587         if (sc->sc_owxfer != NULL)
  588                 usbd_free_xfer(sc->sc_owxfer);
  589 
  590         /* Disable interrupts. */
  591         if (sc->sc_opipe != NULL) {
  592                 usbd_abort_pipe(sc->sc_opipe);
  593                 usbd_close_pipe(sc->sc_opipe);
  594                 sc->sc_opipe = NULL;
  595         }
  596 
  597         if (sc->sc_ipipe != NULL) {
  598                 usbd_abort_pipe(sc->sc_ipipe);
  599                 usbd_close_pipe(sc->sc_ipipe);
  600                 sc->sc_ipipe = NULL;
  601         }
  602 
  603         if (sc->sc_ibuf != NULL) {
  604                 free(sc->sc_ibuf, M_USBDEV);
  605                 sc->sc_ibuf = NULL;
  606         }
  607 }
  608 
  609 usbd_status
  610 uhidev_set_report(struct uhidev *scd, int type, void *data, int len)
  611 {
  612         char *buf;
  613         usbd_status retstat;
  614 
  615         if (scd->sc_report_id == 0)
  616                 return usbd_set_report(scd->sc_parent->sc_iface, type,
  617                                        scd->sc_report_id, data, len);
  618 
  619         buf = malloc(len + 1, M_TEMP, M_WAITOK);
  620         buf[0] = scd->sc_report_id;
  621         memcpy(buf+1, data, len);
  622 
  623         retstat = usbd_set_report(scd->sc_parent->sc_iface, type,
  624                                   scd->sc_report_id, data, len + 1);
  625 
  626         free(buf, M_TEMP);
  627 
  628         return retstat;
  629 }
  630 
  631 void
  632 uhidev_set_report_async(struct uhidev *scd, int type, void *data, int len)
  633 {
  634         /* XXX */
  635         char buf[100];
  636         if (scd->sc_report_id) {
  637                 buf[0] = scd->sc_report_id;
  638                 memcpy(buf+1, data, len);
  639                 len++;
  640                 data = buf;
  641         }
  642 
  643         usbd_set_report_async(scd->sc_parent->sc_iface, type,
  644                               scd->sc_report_id, data, len);
  645 }
  646 
  647 usbd_status
  648 uhidev_get_report(struct uhidev *scd, int type, void *data, int len)
  649 {
  650         return usbd_get_report(scd->sc_parent->sc_iface, type,
  651                                scd->sc_report_id, data, len);
  652 }
  653 
  654 usbd_status
  655 uhidev_write(struct uhidev_softc *sc, void *data, int len)
  656 {
  657 
  658         DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len));
  659 
  660         if (sc->sc_opipe == NULL)
  661                 return USBD_INVAL;
  662 
  663 #ifdef UHIDEV_DEBUG
  664         if (uhidevdebug > 50) {
  665 
  666                 u_int32_t i;
  667                 u_int8_t *d = data;
  668 
  669                 DPRINTF(("uhidev_write: data ="));
  670                 for (i = 0; i < len; i++)
  671                         DPRINTF((" %02x", d[i]));
  672                 DPRINTF(("\n"));
  673         }
  674 #endif
  675         return usbd_intr_transfer(sc->sc_owxfer, sc->sc_opipe, 0,
  676             USBD_NO_TIMEOUT, data, &len, "uhidevwi");
  677 }

/* [<][>][^][v][top][bottom][index][help] */