Annotation of qemu/usb-bsd.c, revision 1.1.1.5

1.1       root        1: /*
                      2:  * BSD host USB redirector
                      3:  *
                      4:  * Copyright (c) 2006 Lonnie Mendez
                      5:  * Portions of code and concepts borrowed from
                      6:  * usb-linux.c and libusb's bsd.c and are copyright their respective owners.
                      7:  *
                      8:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      9:  * of this software and associated documentation files (the "Software"), to deal
                     10:  * in the Software without restriction, including without limitation the rights
                     11:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     12:  * copies of the Software, and to permit persons to whom the Software is
                     13:  * furnished to do so, subject to the following conditions:
                     14:  *
                     15:  * The above copyright notice and this permission notice shall be included in
                     16:  * all copies or substantial portions of the Software.
                     17:  *
                     18:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     19:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     20:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     21:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     22:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     23:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     24:  * THE SOFTWARE.
                     25:  */
                     26: 
                     27: #include "qemu-common.h"
1.1.1.2   root       28: #include "monitor.h"
1.1       root       29: #include "hw/usb.h"
                     30: 
                     31: /* usb.h declares these */
                     32: #undef USB_SPEED_HIGH
                     33: #undef USB_SPEED_FULL
                     34: #undef USB_SPEED_LOW
                     35: 
                     36: #include <sys/ioctl.h>
1.1.1.2   root       37: #ifndef __DragonFly__
1.1       root       38: #include <dev/usb/usb.h>
1.1.1.2   root       39: #else
                     40: #include <bus/usb/usb.h>
                     41: #endif
1.1       root       42: 
                     43: /* This value has maximum potential at 16.
                     44:  * You should also set hw.usb.debug to gain
                     45:  * more detailed view.
                     46:  */
                     47: //#define DEBUG
                     48: #define UGEN_DEBUG_LEVEL 0
                     49: 
                     50: 
                     51: typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
                     52:                         int vendor_id, int product_id,
                     53:                         const char *product_name, int speed);
                     54: static int usb_host_find_device(int *pbus_num, int *paddr,
                     55:                                 const char *devname);
                     56: 
                     57: typedef struct USBHostDevice {
                     58:     USBDevice dev;
                     59:     int ep_fd[USB_MAX_ENDPOINTS];
                     60:     int devfd;
                     61:     char devpath[32];
                     62: } USBHostDevice;
                     63: 
                     64: 
1.1.1.3   root       65: #if 0
1.1       root       66: static int ensure_ep_open(USBHostDevice *dev, int ep, int mode)
                     67: {
                     68:     char buf[32];
                     69:     int fd;
                     70: 
                     71:     /* Get the address for this endpoint */
                     72:     ep = UE_GET_ADDR(ep);
                     73: 
                     74:     if (dev->ep_fd[ep] < 0) {
1.1.1.2   root       75: #if defined(__FreeBSD__) || defined(__DragonFly__)
1.1       root       76:         snprintf(buf, sizeof(buf) - 1, "%s.%d", dev->devpath, ep);
                     77: #else
                     78:         snprintf(buf, sizeof(buf) - 1, "%s.%02d", dev->devpath, ep);
                     79: #endif
                     80:         /* Try to open it O_RDWR first for those devices which have in and out
                     81:          * endpoints with the same address (eg 0x02 and 0x82)
                     82:          */
                     83:         fd = open(buf, O_RDWR);
                     84:         if (fd < 0 && errno == ENXIO)
                     85:             fd = open(buf, mode);
                     86:         if (fd < 0) {
                     87: #ifdef DEBUG
                     88:             printf("ensure_ep_open: failed to open device endpoint %s: %s\n",
                     89:                    buf, strerror(errno));
                     90: #endif
                     91:         }
                     92:         dev->ep_fd[ep] = fd;
                     93:     }
                     94: 
                     95:     return dev->ep_fd[ep];
                     96: }
                     97: 
                     98: static void ensure_eps_closed(USBHostDevice *dev)
                     99: {
                    100:     int epnum = 1;
                    101: 
                    102:     if (!dev)
                    103:         return;
                    104: 
                    105:     while (epnum < USB_MAX_ENDPOINTS) {
                    106:         if (dev->ep_fd[epnum] >= 0) {
                    107:             close(dev->ep_fd[epnum]);
                    108:             dev->ep_fd[epnum] = -1;
                    109:         }
                    110:         epnum++;
                    111:     }
                    112: }
1.1.1.3   root      113: #endif
1.1       root      114: 
                    115: static void usb_host_handle_reset(USBDevice *dev)
                    116: {
                    117: #if 0
                    118:     USBHostDevice *s = (USBHostDevice *)dev;
                    119: #endif
                    120: }
                    121: 
1.1.1.3   root      122: #if 0
1.1       root      123: /* XXX:
                    124:  * -check device states against transfer requests
                    125:  *  and return appropriate response
                    126:  */
                    127: static int usb_host_handle_control(USBDevice *dev,
1.1.1.5 ! root      128:                                    USBPacket *p,
1.1       root      129:                                    int request,
                    130:                                    int value,
                    131:                                    int index,
                    132:                                    int length,
                    133:                                    uint8_t *data)
                    134: {
                    135:     USBHostDevice *s = (USBHostDevice *)dev;
                    136:     struct usb_ctl_request req;
                    137:     struct usb_alt_interface aiface;
                    138:     int ret, timeout = 50;
                    139: 
                    140:     if ((request >> 8) == UT_WRITE_DEVICE &&
                    141:         (request & 0xff) == UR_SET_ADDRESS) {
                    142: 
                    143:         /* specific SET_ADDRESS support */
                    144:         dev->addr = value;
                    145:         return 0;
                    146:     } else if ((request >> 8) == UT_WRITE_DEVICE &&
                    147:                (request & 0xff) == UR_SET_CONFIG) {
                    148: 
                    149:         ensure_eps_closed(s); /* can't do this without all eps closed */
                    150: 
                    151:         ret = ioctl(s->devfd, USB_SET_CONFIG, &value);
                    152:         if (ret < 0) {
                    153: #ifdef DEBUG
                    154:             printf("handle_control: failed to set configuration - %s\n",
                    155:                    strerror(errno));
                    156: #endif
                    157:             return USB_RET_STALL;
                    158:         }
                    159: 
                    160:         return 0;
                    161:     } else if ((request >> 8) == UT_WRITE_INTERFACE &&
                    162:                (request & 0xff) == UR_SET_INTERFACE) {
                    163: 
                    164:         aiface.uai_interface_index = index;
                    165:         aiface.uai_alt_no = value;
                    166: 
                    167:         ensure_eps_closed(s); /* can't do this without all eps closed */
                    168:         ret = ioctl(s->devfd, USB_SET_ALTINTERFACE, &aiface);
                    169:         if (ret < 0) {
                    170: #ifdef DEBUG
                    171:             printf("handle_control: failed to set alternate interface - %s\n",
                    172:                    strerror(errno));
                    173: #endif
                    174:             return USB_RET_STALL;
                    175:         }
                    176: 
                    177:         return 0;
                    178:     } else {
                    179:         req.ucr_request.bmRequestType = request >> 8;
                    180:         req.ucr_request.bRequest = request & 0xff;
                    181:         USETW(req.ucr_request.wValue, value);
                    182:         USETW(req.ucr_request.wIndex, index);
                    183:         USETW(req.ucr_request.wLength, length);
                    184:         req.ucr_data = data;
                    185:         req.ucr_flags = USBD_SHORT_XFER_OK;
                    186: 
                    187:         ret = ioctl(s->devfd, USB_SET_TIMEOUT, &timeout);
                    188: #if defined(__NetBSD__) || defined(__OpenBSD__)
                    189:         if (ret < 0 && errno != EINVAL) {
                    190: #else
                    191:         if (ret < 0) {
                    192: #endif
                    193: #ifdef DEBUG
                    194:             printf("handle_control: setting timeout failed - %s\n",
                    195:                    strerror(errno));
                    196: #endif
                    197:         }
                    198: 
                    199:         ret = ioctl(s->devfd, USB_DO_REQUEST, &req);
                    200:         /* ugen returns EIO for usbd_do_request_ no matter what
                    201:          * happens with the transfer */
                    202:         if (ret < 0) {
                    203: #ifdef DEBUG
                    204:             printf("handle_control: error after request - %s\n",
                    205:                    strerror(errno));
                    206: #endif
                    207:             return USB_RET_NAK; // STALL
                    208:         } else {
                    209:             return req.ucr_actlen;
                    210:         }
                    211:     }
                    212: }
                    213: 
                    214: static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
                    215: {
                    216:     USBHostDevice *s = (USBHostDevice *)dev;
                    217:     int ret, fd, mode;
                    218:     int one = 1, shortpacket = 0, timeout = 50;
                    219:     sigset_t new_mask, old_mask;
                    220:     uint8_t devep = p->devep;
                    221: 
                    222:     /* protect data transfers from SIGALRM signal */
                    223:     sigemptyset(&new_mask);
                    224:     sigaddset(&new_mask, SIGALRM);
                    225:     sigprocmask(SIG_BLOCK, &new_mask, &old_mask);
                    226: 
                    227:     if (p->pid == USB_TOKEN_IN) {
                    228:         devep |= 0x80;
                    229:         mode = O_RDONLY;
                    230:         shortpacket = 1;
                    231:     } else {
                    232:         mode = O_WRONLY;
                    233:     }
                    234: 
                    235:     fd = ensure_ep_open(s, devep, mode);
                    236:     if (fd < 0) {
                    237:         sigprocmask(SIG_SETMASK, &old_mask, NULL);
                    238:         return USB_RET_NODEV;
                    239:     }
                    240: 
                    241:     if (ioctl(fd, USB_SET_TIMEOUT, &timeout) < 0) {
                    242: #ifdef DEBUG
                    243:         printf("handle_data: failed to set timeout - %s\n",
                    244:                strerror(errno));
                    245: #endif
                    246:     }
                    247: 
                    248:     if (shortpacket) {
                    249:         if (ioctl(fd, USB_SET_SHORT_XFER, &one) < 0) {
                    250: #ifdef DEBUG
                    251:             printf("handle_data: failed to set short xfer mode - %s\n",
                    252:                    strerror(errno));
                    253: #endif
                    254:             sigprocmask(SIG_SETMASK, &old_mask, NULL);
                    255:         }
                    256:     }
                    257: 
                    258:     if (p->pid == USB_TOKEN_IN)
                    259:         ret = read(fd, p->data, p->len);
                    260:     else
                    261:         ret = write(fd, p->data, p->len);
                    262: 
                    263:     sigprocmask(SIG_SETMASK, &old_mask, NULL);
                    264: 
                    265:     if (ret < 0) {
                    266: #ifdef DEBUG
                    267:         printf("handle_data: error after %s data - %s\n",
                    268:                pid == USB_TOKEN_IN ? "reading" : "writing", strerror(errno));
                    269: #endif
                    270:         switch(errno) {
                    271:         case ETIMEDOUT:
                    272:         case EINTR:
                    273:             return USB_RET_NAK;
                    274:         default:
                    275:             return USB_RET_STALL;
                    276:         }
                    277:     } else {
                    278:         return ret;
                    279:     }
                    280: }
1.1.1.3   root      281: #endif
1.1       root      282: 
                    283: static void usb_host_handle_destroy(USBDevice *opaque)
                    284: {
                    285:     USBHostDevice *s = (USBHostDevice *)opaque;
                    286:     int i;
                    287: 
                    288:     for (i = 0; i < USB_MAX_ENDPOINTS; i++)
                    289:         if (s->ep_fd[i] >= 0)
                    290:             close(s->ep_fd[i]);
                    291: 
                    292:     if (s->devfd < 0)
                    293:         return;
                    294: 
                    295:     close(s->devfd);
                    296: 
                    297:     qemu_free(s);
                    298: }
                    299: 
1.1.1.3   root      300: static int usb_host_initfn(USBDevice *dev)
                    301: {
                    302:     return 0;
                    303: }
                    304: 
1.1       root      305: USBDevice *usb_host_device_open(const char *devname)
                    306: {
                    307:     struct usb_device_info bus_info, dev_info;
1.1.1.3   root      308:     USBDevice *d = NULL;
1.1.1.4   root      309:     USBHostDevice *dev, *ret = NULL;
1.1       root      310:     char ctlpath[PATH_MAX + 1];
                    311:     char buspath[PATH_MAX + 1];
                    312:     int bfd, dfd, bus, address, i;
                    313:     int ugendebug = UGEN_DEBUG_LEVEL;
                    314: 
1.1.1.4   root      315:     if (usb_host_find_device(&bus, &address, devname) < 0) {
                    316:         goto fail;
                    317:     }
1.1       root      318: 
                    319:     snprintf(buspath, PATH_MAX, "/dev/usb%d", bus);
                    320: 
                    321:     bfd = open(buspath, O_RDWR);
                    322:     if (bfd < 0) {
                    323: #ifdef DEBUG
                    324:         printf("usb_host_device_open: failed to open usb bus - %s\n",
                    325:                strerror(errno));
                    326: #endif
1.1.1.4   root      327:         goto fail;
1.1       root      328:     }
                    329: 
                    330:     bus_info.udi_addr = address;
                    331:     if (ioctl(bfd, USB_DEVICEINFO, &bus_info) < 0) {
                    332: #ifdef DEBUG
                    333:         printf("usb_host_device_open: failed to grab bus information - %s\n",
                    334:                strerror(errno));
                    335: #endif
1.1.1.4   root      336:         goto fail_bfd;
1.1       root      337:     }
                    338: 
1.1.1.3   root      339: #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1.1       root      340:     snprintf(ctlpath, PATH_MAX, "/dev/%s", bus_info.udi_devnames[0]);
                    341: #else
                    342:     snprintf(ctlpath, PATH_MAX, "/dev/%s.00", bus_info.udi_devnames[0]);
                    343: #endif
                    344: 
                    345:     dfd  = open(ctlpath, O_RDWR);
                    346:     if (dfd < 0) {
                    347:         dfd = open(ctlpath, O_RDONLY);
                    348:         if (dfd < 0) {
                    349: #ifdef DEBUG
                    350:             printf("usb_host_device_open: failed to open usb device %s - %s\n",
                    351:                    ctlpath, strerror(errno));
                    352: #endif
                    353:         }
1.1.1.4   root      354:         goto fail_dfd;
1.1       root      355:     }
                    356: 
1.1.1.4   root      357:     if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) {
1.1       root      358: #ifdef DEBUG
1.1.1.4   root      359:         printf("usb_host_device_open: failed to grab device info - %s\n",
                    360:                strerror(errno));
1.1       root      361: #endif
1.1.1.4   root      362:         goto fail_dfd;
                    363:     }
                    364: 
                    365:     d = usb_create(NULL /* FIXME */, "usb-host");
                    366:     dev = DO_UPCAST(USBHostDevice, dev, d);
1.1       root      367: 
1.1.1.4   root      368:     if (dev_info.udi_speed == 1) {
                    369:         dev->dev.speed = USB_SPEED_LOW - 1;
1.1.1.5 ! root      370:         dev->dev.speedmask = USB_SPEED_MASK_LOW;
1.1.1.4   root      371:     } else {
                    372:         dev->dev.speed = USB_SPEED_FULL - 1;
1.1.1.5 ! root      373:         dev->dev.speedmask = USB_SPEED_MASK_FULL;
1.1.1.4   root      374:     }
1.1.1.3   root      375: 
1.1.1.4   root      376:     if (strncmp(dev_info.udi_product, "product", 7) != 0) {
                    377:         pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
                    378:                 dev_info.udi_product);
                    379:     } else {
                    380:         snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
                    381:                  "host:%s", devname);
                    382:     }
1.1       root      383: 
1.1.1.4   root      384:     pstrcpy(dev->devpath, sizeof(dev->devpath), "/dev/");
                    385:     pstrcat(dev->devpath, sizeof(dev->devpath), dev_info.udi_devnames[0]);
1.1       root      386: 
1.1.1.4   root      387:     /* Mark the endpoints as not yet open */
                    388:     for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
                    389:         dev->ep_fd[i] = -1;
1.1       root      390:     }
                    391: 
1.1.1.4   root      392:     ioctl(dfd, USB_SETDEBUG, &ugendebug);
                    393: 
                    394:     ret = (USBDevice *)dev;
                    395: 
                    396: fail_dfd:
                    397:     close(dfd);
                    398: fail_bfd:
                    399:     close(bfd);
1.1       root      400: fail:
1.1.1.4   root      401:     return ret;
1.1       root      402: }
                    403: 
1.1.1.3   root      404: static struct USBDeviceInfo usb_host_dev_info = {
                    405:     .product_desc   = "USB Host Device",
                    406:     .qdev.name      = "usb-host",
                    407:     .qdev.size      = sizeof(USBHostDevice),
                    408:     .init           = usb_host_initfn,
                    409:     .handle_packet  = usb_generic_handle_packet,
                    410:     .handle_reset   = usb_host_handle_reset,
                    411: #if 0
                    412:     .handle_control = usb_host_handle_control,
                    413:     .handle_data    = usb_host_handle_data,
                    414: #endif
                    415:     .handle_destroy = usb_host_handle_destroy,
                    416: };
                    417: 
                    418: static void usb_host_register_devices(void)
                    419: {
                    420:     usb_qdev_register(&usb_host_dev_info);
                    421: }
                    422: device_init(usb_host_register_devices)
                    423: 
1.1       root      424: static int usb_host_scan(void *opaque, USBScanFunc *func)
                    425: {
                    426:     struct usb_device_info bus_info;
                    427:     struct usb_device_info dev_info;
                    428:     uint16_t vendor_id, product_id, class_id, speed;
                    429:     int bfd, dfd, bus, address;
                    430:     char busbuf[20], devbuf[20], product_name[256];
                    431:     int ret = 0;
                    432: 
                    433:     for (bus = 0; bus < 10; bus++) {
                    434: 
                    435:         snprintf(busbuf, sizeof(busbuf) - 1, "/dev/usb%d", bus);
                    436:         bfd = open(busbuf, O_RDWR);
                    437:         if (bfd < 0)
                    438:            continue;
                    439: 
                    440:         for (address = 1; address < 127; address++) {
                    441: 
                    442:             bus_info.udi_addr = address;
                    443:             if (ioctl(bfd, USB_DEVICEINFO, &bus_info) < 0)
                    444:                 continue;
                    445: 
                    446:             /* only list devices that can be used by generic layer */
                    447:             if (strncmp(bus_info.udi_devnames[0], "ugen", 4) != 0)
                    448:                 continue;
                    449: 
1.1.1.3   root      450: #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
1.1       root      451:             snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s", bus_info.udi_devnames[0]);
                    452: #else
                    453:             snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s.00", bus_info.udi_devnames[0]);
                    454: #endif
                    455: 
                    456:             dfd = open(devbuf, O_RDONLY);
                    457:             if (dfd < 0) {
                    458: #ifdef DEBUG
                    459:                 printf("usb_host_scan: couldn't open device %s - %s\n", devbuf,
                    460:                        strerror(errno));
                    461: #endif
                    462:                 continue;
                    463:             }
                    464: 
                    465:             if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0)
                    466:                 printf("usb_host_scan: couldn't get device information for %s - %s\n",
                    467:                        devbuf, strerror(errno));
                    468: 
1.1.1.5 ! root      469:             /* XXX: might need to fixup endianness of word values before copying over */
1.1       root      470: 
                    471:             vendor_id = dev_info.udi_vendorNo;
                    472:             product_id = dev_info.udi_productNo;
                    473:             class_id = dev_info.udi_class;
                    474:             speed = dev_info.udi_speed;
                    475: 
                    476:             if (strncmp(dev_info.udi_product, "product", 7) != 0)
                    477:                 pstrcpy(product_name, sizeof(product_name),
                    478:                         dev_info.udi_product);
                    479:             else
                    480:                 product_name[0] = '\0';
                    481: 
                    482:             ret = func(opaque, bus, address, class_id, vendor_id,
                    483:                        product_id, product_name, speed);
                    484: 
                    485:             close(dfd);
                    486: 
                    487:             if (ret)
                    488:                 goto the_end;
                    489:         }
                    490: 
                    491:         close(bfd);
                    492:     }
                    493: 
                    494: the_end:
                    495:     return ret;
                    496: }
                    497: 
                    498: typedef struct FindDeviceState {
                    499:     int vendor_id;
                    500:     int product_id;
                    501:     int bus_num;
                    502:     int addr;
                    503: } FindDeviceState;
                    504: 
                    505: static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
                    506:                                      int class_id,
                    507:                                      int vendor_id, int product_id,
                    508:                                      const char *product_name, int speed)
                    509: {
                    510:     FindDeviceState *s = opaque;
                    511:     if (vendor_id == s->vendor_id &&
                    512:         product_id == s->product_id) {
                    513:         s->bus_num = bus_num;
                    514:         s->addr = addr;
                    515:         return 1;
                    516:      } else {
                    517:         return 0;
                    518:      }
                    519: }
                    520: 
                    521: 
                    522: /* the syntax is :
                    523:    'bus.addr' (decimal numbers) or
                    524:    'vendor_id:product_id' (hexa numbers) */
                    525: static int usb_host_find_device(int *pbus_num, int *paddr,
                    526:                                 const char *devname)
                    527: {
                    528:     const char *p;
                    529:     int ret;
                    530:     FindDeviceState fs;
                    531: 
                    532:     p = strchr(devname, '.');
                    533:     if (p) {
                    534:         *pbus_num = strtoul(devname, NULL, 0);
                    535:         *paddr = strtoul(p + 1, NULL, 0);
                    536:         return 0;
                    537:     }
                    538:     p = strchr(devname, ':');
                    539:     if (p) {
                    540:         fs.vendor_id = strtoul(devname, NULL, 16);
                    541:         fs.product_id = strtoul(p + 1, NULL, 16);
                    542:         ret = usb_host_scan(&fs, usb_host_find_device_scan);
                    543:         if (ret) {
                    544:             *pbus_num = fs.bus_num;
                    545:             *paddr = fs.addr;
                    546:             return 0;
                    547:         }
                    548:      }
                    549:      return -1;
                    550: }
                    551: 
                    552: /**********************/
                    553: /* USB host device info */
                    554: 
                    555: struct usb_class_info {
                    556:     int class;
                    557:     const char *class_name;
                    558: };
                    559: 
                    560: static const struct usb_class_info usb_class_info[] = {
                    561:     { USB_CLASS_AUDIO, "Audio"},
                    562:     { USB_CLASS_COMM, "Communication"},
                    563:     { USB_CLASS_HID, "HID"},
                    564:     { USB_CLASS_HUB, "Hub" },
                    565:     { USB_CLASS_PHYSICAL, "Physical" },
                    566:     { USB_CLASS_PRINTER, "Printer" },
                    567:     { USB_CLASS_MASS_STORAGE, "Storage" },
                    568:     { USB_CLASS_CDC_DATA, "Data" },
                    569:     { USB_CLASS_APP_SPEC, "Application Specific" },
                    570:     { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
                    571:     { USB_CLASS_STILL_IMAGE, "Still Image" },
                    572:     { USB_CLASS_CSCID, "Smart Card" },
                    573:     { USB_CLASS_CONTENT_SEC, "Content Security" },
                    574:     { -1, NULL }
                    575: };
                    576: 
                    577: static const char *usb_class_str(uint8_t class)
                    578: {
                    579:     const struct usb_class_info *p;
                    580:     for (p = usb_class_info; p->class != -1; p++) {
                    581:         if (p->class == class)
                    582:             break;
                    583:     }
                    584:     return p->class_name;
                    585: }
                    586: 
1.1.1.3   root      587: static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
1.1       root      588:                             int vendor_id, int product_id,
                    589:                             const char *product_name,
                    590:                             int speed)
                    591: {
                    592:     const char *class_str, *speed_str;
                    593: 
                    594:     switch(speed) {
                    595:     case USB_SPEED_LOW:
                    596:         speed_str = "1.5";
                    597:         break;
                    598:     case USB_SPEED_FULL:
                    599:         speed_str = "12";
                    600:         break;
                    601:     case USB_SPEED_HIGH:
                    602:         speed_str = "480";
                    603:         break;
                    604:     default:
                    605:         speed_str = "?";
                    606:         break;
                    607:     }
                    608: 
1.1.1.2   root      609:     monitor_printf(mon, "  Device %d.%d, speed %s Mb/s\n",
                    610:                    bus_num, addr, speed_str);
1.1       root      611:     class_str = usb_class_str(class_id);
                    612:     if (class_str)
1.1.1.2   root      613:         monitor_printf(mon, "    %s:", class_str);
1.1       root      614:     else
1.1.1.2   root      615:         monitor_printf(mon, "    Class %02x:", class_id);
                    616:     monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
1.1       root      617:     if (product_name[0] != '\0')
1.1.1.2   root      618:         monitor_printf(mon, ", %s", product_name);
                    619:     monitor_printf(mon, "\n");
1.1       root      620: }
                    621: 
1.1.1.2   root      622: static int usb_host_info_device(void *opaque,
                    623:                                 int bus_num, int addr,
1.1       root      624:                                 int class_id,
                    625:                                 int vendor_id, int product_id,
                    626:                                 const char *product_name,
                    627:                                 int speed)
                    628: {
1.1.1.3   root      629:     Monitor *mon = opaque;
                    630: 
                    631:     usb_info_device(mon, bus_num, addr, class_id, vendor_id, product_id,
1.1       root      632:                     product_name, speed);
                    633:     return 0;
                    634: }
                    635: 
1.1.1.2   root      636: void usb_host_info(Monitor *mon)
1.1       root      637: {
1.1.1.3   root      638:     usb_host_scan(mon, usb_host_info_device);
1.1       root      639: }
                    640: 
                    641: /* XXX add this */
                    642: int usb_host_device_close(const char *devname)
                    643: {
                    644:     return 0;
                    645: }

unix.superglobalmegacorp.com