[BACK]Return to uhidev.c CVS log [TXT][DIR] Up to [local] / sys / dev / usb

Annotation of sys/dev/usb/uhidev.c, Revision 1.1.1.1

1.1       nbrk        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: }

CVSweb