[BACK]Return to ugenhc.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / rump / dev / lib / libugenhc

Annotation of src/sys/rump/dev/lib/libugenhc/ugenhc.c, Revision 1.8.4.1

1.8.4.1 ! rmind       1: /*     $NetBSD: ugenhc.c,v 1.8 2010/02/23 14:05:04 pooka Exp $ */
1.1       pooka       2:
                      3: /*
1.7       pooka       4:  * Copyright (c) 2009, 2010 Antti Kantee.  All Rights Reserved.
1.1       pooka       5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  * 2. Redistributions in binary form must reproduce the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer in the
                     13:  *    documentation and/or other materials provided with the distribution.
                     14:  *
                     15:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
                     16:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     17:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     18:  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     19:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     20:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     21:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     22:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     23:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     24:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     25:  * SUCH DAMAGE.
                     26:  */
                     27:
                     28: /*
                     29:  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
                     30:  * All rights reserved.
                     31:  *
                     32:  * This code is derived from software contributed to The NetBSD Foundation
                     33:  * by Lennart Augustsson (lennart@augustsson.net) at
                     34:  * Carlstedt Research & Technology.
                     35:  *
                     36:  * Redistribution and use in source and binary forms, with or without
                     37:  * modification, are permitted provided that the following conditions
                     38:  * are met:
                     39:  * 1. Redistributions of source code must retain the above copyright
                     40:  *    notice, this list of conditions and the following disclaimer.
                     41:  * 2. Redistributions in binary form must reproduce the above copyright
                     42:  *    notice, this list of conditions and the following disclaimer in the
                     43:  *    documentation and/or other materials provided with the distribution.
                     44:  *
                     45:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     46:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     47:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     48:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     49:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     50:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     51:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     52:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     53:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     54:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     55:  * POSSIBILITY OF SUCH DAMAGE.
                     56:  */
                     57:
                     58: /*
                     59:  * This rump driver attaches ugen as a kernel usb host controller.
                     60:  * It's still somewhat under the hammer ....
                     61:  */
                     62:
                     63: #include <sys/cdefs.h>
1.8.4.1 ! rmind      64: __KERNEL_RCSID(0, "$NetBSD: ugenhc.c,v 1.8 2010/02/23 14:05:04 pooka Exp $");
1.1       pooka      65:
                     66: #include <sys/param.h>
                     67: #include <sys/bus.h>
                     68: #include <sys/conf.h>
                     69: #include <sys/device.h>
                     70: #include <sys/fcntl.h>
                     71: #include <sys/kmem.h>
                     72: #include <sys/kernel.h>
                     73: #include <sys/kthread.h>
                     74:
                     75: #include <dev/usb/usb.h>
                     76: #include <dev/usb/usbdi.h>
                     77: #include <dev/usb/usbhid.h>
                     78: #include <dev/usb/usbdivar.h>
                     79: #include <dev/usb/usb_mem.h>
                     80: #include <dev/usb/usbroothub_subr.h>
                     81:
                     82: #include <rump/rumpuser.h>
                     83:
                     84: #include "rump_private.h"
                     85: #include "rump_dev_private.h"
                     86:
                     87: #define UGEN_NEPTS 16
                     88: #define UGEN_EPT_CTRL 0 /* ugenx.00 is the control endpoint */
                     89:
                     90: struct ugenhc_softc {
                     91:        struct usbd_bus sc_bus;
                     92:        int sc_devnum;
                     93:
                     94:        int sc_ugenfd[UGEN_NEPTS];
                     95:        int sc_fdmodes[UGEN_NEPTS];
                     96:
                     97:        int sc_port_status;
                     98:        int sc_port_change;
                     99:        int sc_addr;
                    100:        int sc_conf;
1.3       pooka     101:
                    102:        struct lwp *sc_rhintr;
                    103:        usbd_xfer_handle sc_intrxfer;
1.1       pooka     104: };
                    105:
                    106: static int     ugenhc_probe(struct device *, struct cfdata *, void *);
                    107: static void    ugenhc_attach(struct device *, struct device *, void *);
                    108:
                    109: CFATTACH_DECL_NEW(ugenhc, sizeof(struct ugenhc_softc),
                    110:        ugenhc_probe, ugenhc_attach, NULL, NULL);
                    111:
                    112: struct rusb_xfer {
                    113:        struct usbd_xfer rusb_xfer;
                    114:        int rusb_status; /* now this is a cheap trick */
                    115: };
                    116: #define RUSB(x) ((struct rusb_xfer *)x)
                    117:
                    118: #define UGENDEV_BASESTR "/dev/ugen"
                    119: #define UGENDEV_BUFSIZE 32
                    120: static void
                    121: makeugendevstr(int devnum, int endpoint, char *buf)
                    122: {
                    123:
                    124:        CTASSERT(UGENDEV_BUFSIZE > sizeof(UGENDEV_BASESTR)+sizeof("0.00")+1);
                    125:        sprintf(buf, "%s%d.%02d", UGENDEV_BASESTR, devnum, endpoint);
                    126: }
                    127:
                    128: /*
                    129:  * Our fictional hubbie.
                    130:  */
                    131:
                    132: static const usb_device_descriptor_t rumphub_udd = {
                    133:        .bLength                = USB_DEVICE_DESCRIPTOR_SIZE,
                    134:        .bDescriptorType        = UDESC_DEVICE,
                    135:        .bDeviceClass           = UDCLASS_HUB,
                    136:        .bDeviceSubClass        = UDSUBCLASS_HUB,
                    137:        .bDeviceProtocol        = UDPROTO_FSHUB,
                    138:        .bMaxPacketSize         = 64,
1.8       pooka     139:        .idVendor               = { 0x75, 0x72 },
                    140:        .idProduct              = { 0x70, 0x6d },
1.1       pooka     141:        .bNumConfigurations     = 1,
                    142: };
                    143:
                    144: static const usb_config_descriptor_t rumphub_ucd = {
                    145:        .bLength                = USB_CONFIG_DESCRIPTOR_SIZE,
                    146:        .bDescriptorType        = UDESC_CONFIG,
                    147:        .wTotalLength           = { USB_CONFIG_DESCRIPTOR_SIZE
                    148:                                  + USB_INTERFACE_DESCRIPTOR_SIZE
                    149:                                  + USB_ENDPOINT_DESCRIPTOR_SIZE },
                    150:        .bNumInterface          = 1,
                    151:        .bmAttributes           = UC_SELF_POWERED | UC_ATTR_MBO,
                    152: };
                    153: /* XXX: spec says UC_ATTR_MBO is reserved and set to one.  required? */
                    154:
                    155: static const usb_interface_descriptor_t rumphub_uid = {
                    156:        .bLength                = USB_INTERFACE_DESCRIPTOR_SIZE,
                    157:        .bDescriptorType        = UDESC_INTERFACE,
                    158:        .bInterfaceNumber       = 0,
                    159:        .bNumEndpoints          = 1,
                    160:        .bInterfaceClass        = UICLASS_HUB,
                    161:        .bInterfaceSubClass     = UISUBCLASS_HUB,
                    162:        .bInterfaceProtocol     = UIPROTO_FSHUB,
                    163: };
                    164:
                    165: static const usb_endpoint_descriptor_t rumphub_epd = {
                    166:        .bLength                = USB_ENDPOINT_DESCRIPTOR_SIZE,
                    167:        .bDescriptorType        = UDESC_ENDPOINT,
                    168:        .bmAttributes           = UE_INTERRUPT,
                    169:        .wMaxPacketSize         = {64, 0},
                    170: };
                    171:
                    172: static const usb_hub_descriptor_t rumphub_hdd = {
                    173:        .bDescLength            = USB_HUB_DESCRIPTOR_SIZE,
                    174:        .bDescriptorType        = UDESC_HUB,
                    175:        .bNbrPorts              = 1,
                    176: };
                    177:
                    178: static usbd_status
                    179: rumpusb_root_ctrl_start(usbd_xfer_handle xfer)
                    180: {
                    181:        usb_device_request_t *req = &xfer->request;
                    182:        struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private;
                    183:        int len, totlen, value, curlen, err;
                    184:        uint8_t *buf = NULL;
                    185:
                    186:        len = totlen = UGETW(req->wLength);
                    187:        if (len)
                    188:                buf = KERNADDR(&xfer->dmabuf, 0);
                    189:        value = UGETW(req->wValue);
                    190:
                    191: #define C(x,y) ((x) | ((y) << 8))
                    192:        switch(C(req->bRequest, req->bmRequestType)) {
                    193:
                    194:        case C(UR_GET_CONFIG, UT_READ_DEVICE):
                    195:                if (len > 0) {
                    196:                        *buf = sc->sc_conf;
                    197:                        totlen = 1;
                    198:                }
                    199:                break;
                    200:
                    201:        case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
                    202:                switch (value >> 8) {
                    203:                case UDESC_DEVICE:
                    204:                        totlen = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
                    205:                        memcpy(buf, &rumphub_udd, totlen);
                    206:                        break;
                    207:
                    208:                case UDESC_CONFIG:
                    209:                        totlen = 0;
                    210:                        curlen = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
                    211:                        memcpy(buf, &rumphub_ucd, curlen);
                    212:                        len -= curlen;
                    213:                        buf += curlen;
                    214:                        totlen += curlen;
                    215:
                    216:                        curlen = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
                    217:                        memcpy(buf, &rumphub_uid, curlen);
                    218:                        len -= curlen;
                    219:                        buf += curlen;
                    220:                        totlen += curlen;
                    221:
                    222:                        curlen = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
                    223:                        memcpy(buf, &rumphub_epd, curlen);
                    224:                        len -= curlen;
                    225:                        buf += curlen;
                    226:                        totlen += curlen;
                    227:                        break;
                    228:
                    229:                case UDESC_STRING:
                    230: #define sd ((usb_string_descriptor_t *)buf)
                    231:                        switch (value & 0xff) {
                    232:                        case 0: /* Language table */
                    233:                                totlen = usb_makelangtbl(sd, len);
                    234:                                break;
                    235:                        case 1: /* Vendor */
                    236:                                totlen = usb_makestrdesc(sd, len, "rod nevada");
                    237:                                break;
                    238:                        case 2: /* Product */
                    239:                                totlen = usb_makestrdesc(sd, len,
                    240:                                    "RUMPUSBHC root hub");
                    241:                                break;
                    242:                        }
                    243: #undef sd
                    244:                        break;
                    245:
                    246:                default:
                    247:                        panic("unhandled read device request");
                    248:                        break;
                    249:                }
                    250:                break;
                    251:
                    252:        case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
                    253:                if (value >= USB_MAX_DEVICES) {
                    254:                        err = USBD_IOERROR;
                    255:                        goto ret;
                    256:                }
                    257:                sc->sc_addr = value;
                    258:                break;
                    259:
                    260:        case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
                    261:                if (value != 0 && value != 1) {
                    262:                        err = USBD_IOERROR;
                    263:                        goto ret;
                    264:                }
                    265:                sc->sc_conf = value;
                    266:                break;
                    267:
                    268:        case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
                    269:                switch (value) {
                    270:                case UHF_PORT_RESET:
                    271:                        sc->sc_port_change |= UPS_C_PORT_RESET;
                    272:                        break;
                    273:                case UHF_PORT_POWER:
                    274:                        break;
                    275:                default:
                    276:                        panic("unhandled");
                    277:                }
                    278:                break;
                    279:
                    280:        case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
                    281:                sc->sc_port_change &= ~value;
                    282:                break;
                    283:
                    284:        case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
                    285:                totlen = min(len, USB_HUB_DESCRIPTOR_SIZE);
                    286:                memcpy(buf, &rumphub_hdd, totlen);
                    287:                break;
                    288:
                    289:        case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
                    290:                /* huh?  other hc's do this */
                    291:                memset(buf, 0, len);
                    292:                totlen = len;
                    293:                break;
                    294:
                    295:        case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
                    296:                {
                    297:                usb_port_status_t ps;
                    298:
                    299:                USETW(ps.wPortStatus, sc->sc_port_status);
                    300:                USETW(ps.wPortChange, sc->sc_port_change);
                    301:                totlen = min(len, sizeof(ps));
                    302:                memcpy(buf, &ps, totlen);
                    303:                break;
                    304:                }
                    305:
                    306:        default:
                    307:                panic("unhandled request");
                    308:                break;
                    309:        }
                    310:        err = USBD_NORMAL_COMPLETION;
                    311:        xfer->actlen = totlen;
                    312:
                    313: ret:
                    314:        xfer->status = err;
                    315:        usb_transfer_complete(xfer);
                    316:        return (USBD_IN_PROGRESS);
                    317: }
                    318:
                    319: static usbd_status
                    320: rumpusb_root_ctrl_transfer(usbd_xfer_handle xfer)
                    321: {
                    322:        usbd_status err;
                    323:
                    324:        err = usb_insert_transfer(xfer);
                    325:        if (err)
                    326:                return (err);
                    327:
                    328:        return (rumpusb_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
                    329: }
                    330:
                    331: static void
                    332: rumpusb_root_ctrl_abort(usbd_xfer_handle xfer)
                    333: {
                    334:
                    335: }
                    336:
                    337: static void
                    338: rumpusb_root_ctrl_close(usbd_pipe_handle pipe)
                    339: {
                    340:
                    341: }
                    342:
                    343: static void
                    344: rumpusb_root_ctrl_cleartoggle(usbd_pipe_handle pipe)
                    345: {
                    346:
                    347: }
                    348:
                    349: static void
                    350: rumpusb_root_ctrl_done(usbd_xfer_handle xfer)
                    351: {
                    352:
                    353: }
                    354:
                    355: static const struct usbd_pipe_methods rumpusb_root_ctrl_methods = {
                    356:        .transfer =     rumpusb_root_ctrl_transfer,
                    357:        .start =        rumpusb_root_ctrl_start,
                    358:        .abort =        rumpusb_root_ctrl_abort,
                    359:        .close =        rumpusb_root_ctrl_close,
                    360:        .cleartoggle =  rumpusb_root_ctrl_cleartoggle,
                    361:        .done =         rumpusb_root_ctrl_done,
                    362: };
                    363:
                    364: static usbd_status
                    365: rumpusb_device_ctrl_start(usbd_xfer_handle xfer)
                    366: {
                    367:        usb_device_request_t *req = &xfer->request;
                    368:        struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private;
                    369:        uint8_t *buf = NULL;
                    370:        int len, totlen;
                    371:        int value;
                    372:        int err = 0;
                    373:        int ru_error, mightfail = 0;
                    374:
                    375:        len = totlen = UGETW(req->wLength);
                    376:        if (len)
                    377:                buf = KERNADDR(&xfer->dmabuf, 0);
                    378:        value = UGETW(req->wValue);
                    379:
                    380: #define C(x,y) ((x) | ((y) << 8))
                    381:        switch(C(req->bRequest, req->bmRequestType)) {
                    382:        case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
                    383:                switch (value>>8) {
                    384:                case UDESC_DEVICE:
                    385:                        {
                    386:                        usb_device_descriptor_t uddesc;
                    387:                        totlen = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
                    388:                        memset(buf, 0, totlen);
                    389:                        if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
1.3       pooka     390:                            USB_GET_DEVICE_DESC, &uddesc, &ru_error) == -1) {
                    391:                                err = EIO;
                    392:                                goto ret;
                    393:                        }
1.1       pooka     394:                        memcpy(buf, &uddesc, totlen);
                    395:                        }
                    396:
                    397:                        break;
                    398:                case UDESC_CONFIG:
                    399:                        {
                    400:                        struct usb_full_desc ufdesc;
1.7       pooka     401:                        ufdesc.ufd_config_index = value & 0xff;
1.1       pooka     402:                        ufdesc.ufd_size = len;
                    403:                        ufdesc.ufd_data = buf;
1.7       pooka     404:                        memset(buf, 0, len);
1.1       pooka     405:                        if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
1.7       pooka     406:                            USB_GET_FULL_DESC, &ufdesc, &ru_error) == -1) {
                    407:                                err = USBD_IOERROR;
                    408:                                goto ret;
                    409:                        }
                    410:                        totlen = ufdesc.ufd_size;
1.1       pooka     411:                        }
                    412:                        break;
                    413:
                    414:                case UDESC_STRING:
                    415:                        {
                    416:                        struct usb_device_info udi;
                    417:
                    418:                        if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
                    419:                            USB_GET_DEVICEINFO, &udi, &ru_error) == -1) {
                    420:                                printf("ugenhc: get dev info failed: %d\n",
                    421:                                    ru_error);
                    422:                                err = USBD_IOERROR;
                    423:                                goto ret;
                    424:                        }
                    425:
                    426:                        switch (value & 0xff) {
                    427: #define sd ((usb_string_descriptor_t *)buf)
                    428:                        case 0: /* language table */
                    429:                                break;
                    430:                        case 1: /* vendor */
                    431:                                totlen = usb_makestrdesc(sd, len,
                    432:                                    udi.udi_vendor);
                    433:                                break;
                    434:                        case 2: /* product */
                    435:                                totlen = usb_makestrdesc(sd, len,
                    436:                                    udi.udi_product);
                    437:                                break;
                    438:                        }
                    439: #undef sd
                    440:                        }
                    441:                        break;
                    442:
                    443:                default:
                    444:                        panic("not handled");
                    445:                }
                    446:                break;
                    447:
                    448:        case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
                    449:                /* ignored, ugen won't let us */
                    450:                break;
                    451:
                    452:        case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
1.7       pooka     453:                if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
                    454:                    USB_SET_CONFIG, &value, &ru_error) == -1) {
                    455:                        printf("ugenhc: set config failed: %d\n",
                    456:                            ru_error);
                    457:                        err = USBD_IOERROR;
                    458:                        goto ret;
                    459:                }
1.1       pooka     460:                break;
                    461:
                    462:        case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
                    463:                {
                    464:                struct usb_alt_interface uai;
                    465:
                    466:                totlen = 0;
                    467:                uai.uai_interface_index = UGETW(req->wIndex);
                    468:                uai.uai_alt_no = value;
                    469:                if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
                    470:                    USB_SET_ALTINTERFACE, &uai, &ru_error) == -1) {
                    471:                        printf("ugenhc: set alt interface failed: %d\n",
                    472:                            ru_error);
                    473:                        err = USBD_IOERROR;
                    474:                        goto ret;
                    475:                }
                    476:                break;
                    477:                }
                    478:
                    479:        /*
                    480:         * This request might fail unknown reasons.  "EIO" doesn't
                    481:         * give much help, and debugging the host ugen would be
                    482:         * necessary.  However, since it doesn't seem to really
                    483:         * affect anything, just let it fail for now.
                    484:         */
                    485:        case C(0x00, UT_WRITE_CLASS_INTERFACE):
                    486:                mightfail = 1;
                    487:                /*FALLTHROUGH*/
                    488:
                    489:        /*
                    490:         * XXX: don't wildcard these yet.  I want to better figure
                    491:         * out what to trap here.  This is kinda silly, though ...
                    492:         */
                    493:
                    494:        case C(0x01, UT_WRITE_VENDOR_DEVICE):
                    495:        case C(0x06, UT_WRITE_VENDOR_DEVICE):
                    496:        case C(0x07, UT_READ_VENDOR_DEVICE):
                    497:        case C(0x09, UT_READ_VENDOR_DEVICE):
                    498:        case C(0xfe, UT_READ_CLASS_INTERFACE):
                    499:        case C(0x01, UT_READ_CLASS_INTERFACE):
                    500:        case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
                    501:        case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
                    502:        case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
                    503:        case C(UR_GET_DESCRIPTOR, UT_READ_INTERFACE):
                    504:        case C(0xff, UT_WRITE_CLASS_INTERFACE):
                    505:        case C(0x20, UT_WRITE_CLASS_INTERFACE):
                    506:        case C(0x22, UT_WRITE_CLASS_INTERFACE):
                    507:        case C(0x0a, UT_WRITE_CLASS_INTERFACE):
                    508:        case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
1.8.4.1 ! rmind     509:        case C(0x00, UT_WRITE_CLASS_DEVICE):
1.2       pooka     510:        case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
1.1       pooka     511:        case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
                    512:        case C(UR_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
                    513:        case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
                    514:                {
                    515:                struct usb_ctl_request ucr;
                    516:
                    517:                memcpy(&ucr.ucr_request, req, sizeof(ucr.ucr_request));
                    518:                ucr.ucr_data = buf;
                    519:                if (rumpuser_ioctl(sc->sc_ugenfd[UGEN_EPT_CTRL],
                    520:                    USB_DO_REQUEST, &ucr, &ru_error) == -1) {
1.2       pooka     521:                        if (!mightfail) {
1.1       pooka     522:                                panic("request failed: %d", ru_error);
1.2       pooka     523:                        } else {
1.1       pooka     524:                                err = ru_error;
1.2       pooka     525:                        }
1.1       pooka     526:                }
                    527:                }
                    528:                break;
                    529:
                    530:        default:
                    531:                panic("unhandled request");
                    532:                break;
                    533:        }
                    534:        xfer->actlen = totlen;
                    535:        err = USBD_NORMAL_COMPLETION;
                    536:
                    537:  ret:
                    538:        xfer->status = err;
                    539:        usb_transfer_complete(xfer);
                    540:        return (USBD_IN_PROGRESS);
                    541: }
                    542:
                    543: static usbd_status
                    544: rumpusb_device_ctrl_transfer(usbd_xfer_handle xfer)
                    545: {
                    546:        usbd_status err;
                    547:
                    548:        err = usb_insert_transfer(xfer);
                    549:        if (err)
                    550:                return (err);
                    551:
                    552:        return (rumpusb_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
                    553: }
                    554:
                    555: static void
                    556: rumpusb_device_ctrl_abort(usbd_xfer_handle xfer)
                    557: {
                    558:
                    559: }
                    560:
                    561: static void
                    562: rumpusb_device_ctrl_close(usbd_pipe_handle pipe)
                    563: {
                    564:
                    565: }
                    566:
                    567: static void
                    568: rumpusb_device_ctrl_cleartoggle(usbd_pipe_handle pipe)
                    569: {
                    570:
                    571: }
                    572:
                    573: static void
                    574: rumpusb_device_ctrl_done(usbd_xfer_handle xfer)
                    575: {
                    576:
                    577: }
                    578:
                    579: static const struct usbd_pipe_methods rumpusb_device_ctrl_methods = {
                    580:        .transfer =     rumpusb_device_ctrl_transfer,
                    581:        .start =        rumpusb_device_ctrl_start,
                    582:        .abort =        rumpusb_device_ctrl_abort,
                    583:        .close =        rumpusb_device_ctrl_close,
                    584:        .cleartoggle =  rumpusb_device_ctrl_cleartoggle,
                    585:        .done =         rumpusb_device_ctrl_done,
                    586: };
                    587:
1.3       pooka     588: static void
                    589: rhscintr(void *arg)
                    590: {
                    591:        char buf[UGENDEV_BUFSIZE];
                    592:        struct ugenhc_softc *sc = arg;
1.1       pooka     593:        usbd_xfer_handle xfer;
1.3       pooka     594:        int fd, error;
                    595:
                    596:        makeugendevstr(sc->sc_devnum, 0, buf);
1.4       pooka     597:
1.3       pooka     598:        for (;;) {
1.4       pooka     599:                /*
                    600:                 * Detect device attach.
                    601:                 */
                    602:
                    603:                for (;;) {
                    604:                        fd = rumpuser_open(buf, O_RDWR, &error);
                    605:                        if (fd != -1)
                    606:                                break;
                    607:                        kpause("ugwait", false, hz/4, NULL);
                    608:                }
                    609:
                    610:                sc->sc_ugenfd[UGEN_EPT_CTRL] = fd;
                    611:                sc->sc_port_status = UPS_CURRENT_CONNECT_STATUS
                    612:                    | UPS_PORT_ENABLED | UPS_PORT_POWER;
1.7       pooka     613:                sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET;
1.4       pooka     614:
                    615:                xfer = sc->sc_intrxfer;
1.7       pooka     616:                memset(xfer->buffer, 0xff, xfer->length);
                    617:                xfer->actlen = xfer->length;
1.4       pooka     618:                xfer->status = USBD_NORMAL_COMPLETION;
1.7       pooka     619:
1.4       pooka     620:                usb_transfer_complete(xfer);
                    621:
1.7       pooka     622:                kpause("ugwait2", false, hz, NULL);
                    623:
1.4       pooka     624:                /*
                    625:                 * Detect device detach.
                    626:                 */
                    627:
                    628:                for (;;) {
                    629:                        fd = rumpuser_open(buf, O_RDWR, &error);
                    630:                        if (fd == -1)
                    631:                                break;
1.7       pooka     632:
1.4       pooka     633:                        rumpuser_close(fd, &error);
                    634:                        kpause("ugwait2", false, hz/4, NULL);
                    635:                }
1.1       pooka     636:
1.4       pooka     637:                sc->sc_port_status = ~(UPS_CURRENT_CONNECT_STATUS
                    638:                    | UPS_PORT_ENABLED | UPS_PORT_POWER);
1.7       pooka     639:                sc->sc_port_change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET;
1.5       pooka     640:
                    641:                rumpuser_close(sc->sc_ugenfd[UGEN_EPT_CTRL], &error);
1.4       pooka     642:                sc->sc_ugenfd[UGEN_EPT_CTRL] = -1;
1.1       pooka     643:
1.4       pooka     644:                xfer = sc->sc_intrxfer;
1.7       pooka     645:                memset(xfer->buffer, 0xff, xfer->length);
                    646:                xfer->actlen = xfer->length;
1.4       pooka     647:                xfer->status = USBD_NORMAL_COMPLETION;
                    648:                usb_transfer_complete(xfer);
1.7       pooka     649:
                    650:                kpause("ugwait3", false, hz, NULL);
1.4       pooka     651:        }
1.1       pooka     652:
1.3       pooka     653:        kthread_exit(0);
1.1       pooka     654: }
                    655:
                    656: static usbd_status
                    657: rumpusb_root_intr_start(usbd_xfer_handle xfer)
                    658: {
1.3       pooka     659:        struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private;
                    660:        int error;
1.1       pooka     661:
1.3       pooka     662:        sc->sc_intrxfer = xfer;
                    663:        if (!sc->sc_rhintr) {
                    664:                error = kthread_create(PRI_NONE, 0, NULL,
                    665:                    rhscintr, sc, &sc->sc_rhintr, "ugenrhi");
                    666:                if (error)
                    667:                        xfer->status = error;
                    668:        }
1.1       pooka     669:
                    670:        return (USBD_IN_PROGRESS);
                    671: }
                    672:
                    673: static usbd_status
                    674: rumpusb_root_intr_transfer(usbd_xfer_handle xfer)
                    675: {
                    676:        usbd_status err;
                    677:
                    678:        err = usb_insert_transfer(xfer);
                    679:        if (err)
                    680:                return (err);
                    681:
                    682:        return (rumpusb_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
                    683: }
                    684:
                    685: static void
                    686: rumpusb_root_intr_abort(usbd_xfer_handle xfer)
                    687: {
                    688:
                    689: }
                    690:
                    691: static void
                    692: rumpusb_root_intr_close(usbd_pipe_handle pipe)
                    693: {
                    694:
                    695: }
                    696:
                    697: static void
                    698: rumpusb_root_intr_cleartoggle(usbd_pipe_handle pipe)
                    699: {
                    700:
                    701: }
                    702:
                    703: static void
                    704: rumpusb_root_intr_done(usbd_xfer_handle xfer)
                    705: {
                    706:
                    707: }
                    708:
                    709: static const struct usbd_pipe_methods rumpusb_root_intr_methods = {
                    710:        .transfer =     rumpusb_root_intr_transfer,
                    711:        .start =        rumpusb_root_intr_start,
                    712:        .abort =        rumpusb_root_intr_abort,
                    713:        .close =        rumpusb_root_intr_close,
                    714:        .cleartoggle =  rumpusb_root_intr_cleartoggle,
                    715:        .done =         rumpusb_root_intr_done,
                    716: };
                    717:
                    718: static usbd_status
                    719: rumpusb_device_bulk_start(usbd_xfer_handle xfer)
                    720: {
                    721:        struct ugenhc_softc *sc = xfer->pipe->device->bus->hci_private;
1.8.4.1 ! rmind     722:        usb_endpoint_descriptor_t *ed = xfer->pipe->endpoint->edesc;
1.1       pooka     723:        ssize_t n;
                    724:        ssize_t done;
                    725:        bool isread;
                    726:        int len, error, endpt;
                    727:        uint8_t *buf;
1.6       pooka     728:        int xfererr = USBD_NORMAL_COMPLETION;
1.8.4.1 ! rmind     729:        int shortval, i;
1.1       pooka     730:
1.8.4.1 ! rmind     731:        ed = xfer->pipe->endpoint->edesc;
        !           732:        endpt = ed->bEndpointAddress;
1.1       pooka     733:        isread = UE_GET_DIR(endpt) == UE_DIR_IN;
                    734:        endpt = UE_GET_ADDR(endpt);
                    735:        KASSERT(endpt < UGEN_NEPTS);
                    736:
                    737:        buf = KERNADDR(&xfer->dmabuf, 0);
                    738:        done = 0;
1.8.4.1 ! rmind     739:        if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) {
        !           740:                for (i = 0, len = 0; i < xfer->nframes; i++)
        !           741:                        len += xfer->frlengths[i];
        !           742:        } else {
        !           743:                KASSERT(xfer->length);
        !           744:                len = xfer->length;
        !           745:        }
        !           746:        shortval = (xfer->flags & USBD_SHORT_XFER_OK) != 0;
1.1       pooka     747:
                    748:        while (RUSB(xfer)->rusb_status == 0) {
                    749:                if (isread) {
                    750:                        rumpuser_ioctl(sc->sc_ugenfd[endpt],
1.8.4.1 ! rmind     751:                            USB_SET_SHORT_XFER, &shortval, &error);
1.1       pooka     752:                        n = rumpuser_read(sc->sc_ugenfd[endpt],
                    753:                            buf+done, len-done, &error);
                    754:                        if (n == -1) {
                    755:                                n = 0;
1.8.4.1 ! rmind     756:                                if (done == 0) {
        !           757:                                        if (error == ETIMEDOUT)
        !           758:                                                continue;
        !           759:                                        xfererr = USBD_IOERROR;
        !           760:                                        goto out;
        !           761:                                }
1.1       pooka     762:                        }
                    763:                        done += n;
                    764:                        if (done == len)
                    765:                                break;
                    766:                } else {
                    767:                        n = rumpuser_write(sc->sc_ugenfd[endpt],
                    768:                            buf, len, &error);
                    769:                        done = n;
                    770:                        if (done == len)
                    771:                                break;
1.6       pooka     772:                        else if (n != -1)
1.1       pooka     773:                                panic("short write");
1.6       pooka     774:
                    775:                        xfererr = USBD_IOERROR;
                    776:                        goto out;
1.1       pooka     777:                }
                    778:
1.8.4.1 ! rmind     779:                if (shortval) {
        !           780:                        /*
        !           781:                         * Holy XXX, bitman.  I get >16byte interrupt
        !           782:                         * transfers from ugen in 16 byte chunks.
        !           783:                         * Don't know how to better fix this for now.
        !           784:                         * Of course this hack will fail e.g. if someone
        !           785:                         * sports other magic values or if the transfer
        !           786:                         * happens to be an integral multiple of 16
        !           787:                         * in size ....
        !           788:                         */
        !           789:                        if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT
        !           790:                            && n == 16) {
        !           791:                                continue;
        !           792:                        } else {
        !           793:                                break;
        !           794:                        }
        !           795:                }
1.1       pooka     796:        }
                    797:
                    798:        if (RUSB(xfer)->rusb_status == 0) {
                    799:                xfer->actlen = done;
                    800:        } else {
1.6       pooka     801:                xfererr = USBD_CANCELLED;
1.1       pooka     802:                RUSB(xfer)->rusb_status = 2;
                    803:        }
                    804:  out:
1.8.4.1 ! rmind     805:        if ((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS)
        !           806:                if (done != len)
        !           807:                        panic("lazy bum");
1.6       pooka     808:        xfer->status = xfererr;
1.1       pooka     809:        usb_transfer_complete(xfer);
                    810:        return (USBD_IN_PROGRESS);
                    811: }
                    812:
                    813: static void
                    814: doxfer_kth(void *arg)
                    815: {
                    816:        usbd_xfer_handle xfer = arg;
                    817:
                    818:        do {
                    819:                rumpusb_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
                    820:        } while (!SIMPLEQ_EMPTY(&xfer->pipe->queue));
                    821:        kthread_exit(0);
                    822: }
                    823:
                    824: static usbd_status
                    825: rumpusb_device_bulk_transfer(usbd_xfer_handle xfer)
                    826: {
                    827:        usbd_status err;
                    828:
                    829:        if (!rump_threads) {
                    830:                /* XXX: lie about supporting async transfers */
                    831:                if ((xfer->flags & USBD_SYNCHRONOUS) == 0) {
                    832:                        printf("non-threaded rump does not support "
                    833:                            "async transfers.\n");
                    834:                        return USBD_IN_PROGRESS;
                    835:                }
                    836:
                    837:                err = usb_insert_transfer(xfer);
                    838:                if (err)
                    839:                        return err;
                    840:
                    841:                return rumpusb_device_bulk_start(
                    842:                    SIMPLEQ_FIRST(&xfer->pipe->queue));
                    843:        } else {
                    844:                /* biglocked */
                    845:                err = usb_insert_transfer(xfer);
                    846:                if (err)
                    847:                        return err;
                    848:                kthread_create(PRI_NONE, 0, NULL, doxfer_kth, xfer, NULL,
                    849:                    "rusbhcxf");
                    850:
                    851:                return USBD_IN_PROGRESS;
                    852:        }
                    853: }
                    854:
                    855: /* wait for transfer to abort.  yea, this is cheesy (from a spray can) */
                    856: static void
                    857: rumpusb_device_bulk_abort(usbd_xfer_handle xfer)
                    858: {
                    859:        struct rusb_xfer *rx = RUSB(xfer);
                    860:
                    861:        rx->rusb_status = 1;
                    862:        while (rx->rusb_status < 2) {
                    863:                kpause("jopo", false, hz/10, NULL);
                    864:        }
                    865: }
                    866:
                    867: static void
                    868: rumpusb_device_bulk_close(usbd_pipe_handle pipe)
                    869: {
1.7       pooka     870:        struct ugenhc_softc *sc = pipe->device->bus->hci_private;
                    871:        int endpt = pipe->endpoint->edesc->bEndpointAddress;
                    872:        usbd_xfer_handle xfer;
                    873:        int error;
1.1       pooka     874:
1.8       pooka     875:        endpt = UE_GET_ADDR(endpt);
                    876:
1.7       pooka     877:        while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL)
                    878:                rumpusb_device_bulk_abort(xfer);
                    879:
                    880:        rumpuser_close(sc->sc_ugenfd[endpt], &error);
                    881:        sc->sc_ugenfd[endpt] = -1;
                    882:        sc->sc_fdmodes[endpt] = -1;
1.1       pooka     883: }
                    884:
                    885: static void
                    886: rumpusb_device_bulk_cleartoggle(usbd_pipe_handle pipe)
                    887: {
                    888:
                    889: }
                    890:
                    891: static void
                    892: rumpusb_device_bulk_done(usbd_xfer_handle xfer)
                    893: {
                    894:
                    895: }
                    896:
                    897: static const struct usbd_pipe_methods rumpusb_device_bulk_methods = {
                    898:        .transfer =     rumpusb_device_bulk_transfer,
                    899:        .start =        rumpusb_device_bulk_start,
                    900:        .abort =        rumpusb_device_bulk_abort,
                    901:        .close =        rumpusb_device_bulk_close,
                    902:        .cleartoggle =  rumpusb_device_bulk_cleartoggle,
                    903:        .done =         rumpusb_device_bulk_done,
                    904: };
                    905:
                    906: static const struct usbd_pipe_methods rumpusb_device_intr_methods = {
                    907:        .transfer =     rumpusb_root_intr_transfer,
                    908:        .start =        rumpusb_root_intr_start,
                    909:        .abort =        rumpusb_root_intr_abort,
                    910:        .close =        rumpusb_root_intr_close,
                    911:        .cleartoggle =  rumpusb_root_intr_cleartoggle,
                    912:        .done =         rumpusb_root_intr_done,
                    913: };
                    914:
                    915: static usbd_status
                    916: ugenhc_open(struct usbd_pipe *pipe)
                    917: {
                    918:        usbd_device_handle dev = pipe->device;
                    919:        struct ugenhc_softc *sc = dev->bus->hci_private;
                    920:        usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
                    921:        u_int8_t addr = dev->address;
                    922:        u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
                    923:        char buf[UGENDEV_BUFSIZE];
                    924:        int endpt, oflags, error;
                    925:        int fd, val;
                    926:
                    927:        if (addr == sc->sc_addr) {
                    928:                switch (xfertype) {
                    929:                case UE_CONTROL:
                    930:                        pipe->methods = &rumpusb_root_ctrl_methods;
                    931:                        break;
                    932:                case UE_INTERRUPT:
                    933:                        pipe->methods = &rumpusb_root_intr_methods;
                    934:                        break;
                    935:                default:
                    936:                        panic("%d not supported", xfertype);
                    937:                        break;
                    938:                }
                    939:        } else {
                    940:                switch (xfertype) {
                    941:                case UE_CONTROL:
                    942:                        pipe->methods = &rumpusb_device_ctrl_methods;
                    943:                        break;
                    944:                case UE_INTERRUPT:
                    945:                case UE_BULK:
1.8.4.1 ! rmind     946:                case UE_ISOCHRONOUS:
1.1       pooka     947:                        pipe->methods = &rumpusb_device_bulk_methods;
                    948:                        endpt = pipe->endpoint->edesc->bEndpointAddress;
                    949:                        if (UE_GET_DIR(endpt) == UE_DIR_IN) {
                    950:                                oflags = O_RDONLY;
                    951:                        } else {
                    952:                                oflags = O_WRONLY;
                    953:                        }
                    954:                        endpt = UE_GET_ADDR(endpt);
                    955:
1.8.4.1 ! rmind     956:                        if (oflags != O_RDONLY && xfertype == UE_ISOCHRONOUS) {
        !           957:                                printf("WARNING: faking isoc write open\n");
        !           958:                                oflags = O_RDONLY;
        !           959:                        }
        !           960:
1.1       pooka     961:                        if (sc->sc_fdmodes[endpt] == oflags
                    962:                            || sc->sc_fdmodes[endpt] == O_RDWR)
                    963:                                break;
                    964:
                    965:                        if (sc->sc_fdmodes[endpt] != -1) {
                    966:                                /* XXX: closing from under someone? */
                    967:                                rumpuser_close(sc->sc_ugenfd[endpt], &error);
                    968:                                oflags = O_RDWR;
                    969:                        }
                    970:
                    971:                        makeugendevstr(sc->sc_devnum, endpt, buf);
                    972:                        fd = rumpuser_open(buf, oflags, &error);
1.8.4.1 ! rmind     973:                        if (fd == -1) {
1.1       pooka     974:                                return USBD_INVAL; /* XXX: no mapping */
1.8.4.1 ! rmind     975:                        }
1.1       pooka     976:                        val = 100;
                    977:                        if (rumpuser_ioctl(fd, USB_SET_TIMEOUT, &val,
                    978:                            &error) == -1)
                    979:                                panic("timeout set failed");
                    980:                        sc->sc_ugenfd[endpt] = fd;
                    981:                        sc->sc_fdmodes[endpt] = oflags;
1.8.4.1 ! rmind     982:
1.1       pooka     983:                        break;
                    984:                default:
                    985:                        panic("%d not supported", xfertype);
                    986:                        break;
                    987:
                    988:                }
                    989:        }
                    990:        return 0;
                    991: }
                    992:
                    993: static void
                    994: ugenhc_softint(void *arg)
                    995: {
                    996:
                    997: }
                    998:
                    999: static void
                   1000: ugenhc_poll(struct usbd_bus *ubus)
                   1001: {
                   1002:
                   1003: }
                   1004:
                   1005: static usbd_status
                   1006: ugenhc_allocm(struct usbd_bus *bus, usb_dma_t *dma, uint32_t size)
                   1007: {
                   1008:        struct ugenhc_softc *sc = bus->hci_private;
                   1009:
                   1010:        return usb_allocmem(&sc->sc_bus, size, 0, dma);
                   1011: }
                   1012:
                   1013: static void
1.8       pooka    1014: ugenhc_freem(struct usbd_bus *bus, usb_dma_t *dma)
1.1       pooka    1015: {
1.8       pooka    1016:        struct ugenhc_softc *sc = bus->hci_private;
1.1       pooka    1017:
1.8       pooka    1018:        usb_freemem(&sc->sc_bus, dma);
1.1       pooka    1019: }
                   1020:
                   1021: static struct usbd_xfer *
                   1022: ugenhc_allocx(struct usbd_bus *bus)
                   1023: {
                   1024:        usbd_xfer_handle xfer;
                   1025:
                   1026:        xfer = kmem_zalloc(sizeof(struct usbd_xfer), KM_SLEEP);
                   1027:        xfer->busy_free = XFER_BUSY;
                   1028:
                   1029:        return xfer;
                   1030: }
                   1031:
                   1032: static void
                   1033: ugenhc_freex(struct usbd_bus *bus, struct usbd_xfer *xfer)
                   1034: {
                   1035:
                   1036:        kmem_free(xfer, sizeof(struct usbd_xfer));
                   1037: }
                   1038:
                   1039: struct ugenhc_pipe {
                   1040:        struct usbd_pipe pipe;
                   1041: };
                   1042:
                   1043: static const struct usbd_bus_methods ugenhc_bus_methods = {
                   1044:        .open_pipe =    ugenhc_open,
                   1045:        .soft_intr =    ugenhc_softint,
                   1046:        .do_poll =      ugenhc_poll,
                   1047:        .allocm =       ugenhc_allocm,
                   1048:        .freem =        ugenhc_freem,
                   1049:        .allocx =       ugenhc_allocx,
                   1050:        .freex =        ugenhc_freex,
                   1051: };
                   1052:
                   1053: static int
                   1054: ugenhc_probe(struct device *parent, struct cfdata *match, void *aux)
                   1055: {
                   1056:        char buf[UGENDEV_BUFSIZE];
1.3       pooka    1057:        int error;
1.1       pooka    1058:
                   1059:        makeugendevstr(match->cf_unit, 0, buf);
1.7       pooka    1060:        if (rumpuser_getfileinfo(buf, NULL, NULL, &error) == -1)
1.1       pooka    1061:                return 0;
                   1062:
                   1063:        return 1;
                   1064: }
                   1065:
                   1066: static void
                   1067: ugenhc_attach(struct device *parent, struct device *self, void *aux)
                   1068: {
                   1069:        struct mainbus_attach_args *maa = aux;
                   1070:        struct ugenhc_softc *sc = device_private(self);
                   1071:
                   1072:        aprint_normal("\n");
                   1073:
                   1074:        memset(sc, 0, sizeof(*sc));
                   1075:        memset(&sc->sc_ugenfd, -1, sizeof(sc->sc_ugenfd));
                   1076:        memset(&sc->sc_fdmodes, -1, sizeof(sc->sc_fdmodes));
                   1077:
                   1078:        sc->sc_bus.usbrev = USBREV_2_0;
                   1079:        sc->sc_bus.methods = &ugenhc_bus_methods;
                   1080:        sc->sc_bus.hci_private = sc;
                   1081:        sc->sc_bus.pipe_size = sizeof(struct ugenhc_pipe);
                   1082:        sc->sc_devnum = maa->maa_unit;
                   1083:
                   1084:        config_found(self, &sc->sc_bus, usbctlprint);
                   1085: }

CVSweb <webmaster@jp.NetBSD.org>