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