qemu/usb-bsd.c
<<
>>
Prefs
   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"
  28#include "monitor.h"
  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>
  37#ifndef __DragonFly__
  38#include <dev/usb/usb.h>
  39#else
  40#include <bus/usb/usb.h>
  41#endif
  42#include <signal.h>
  43
  44/* This value has maximum potential at 16.
  45 * You should also set hw.usb.debug to gain
  46 * more detailed view.
  47 */
  48//#define DEBUG
  49#define UGEN_DEBUG_LEVEL 0
  50
  51
  52typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
  53                        int vendor_id, int product_id,
  54                        const char *product_name, int speed);
  55static int usb_host_find_device(int *pbus_num, int *paddr,
  56                                const char *devname);
  57
  58typedef struct USBHostDevice {
  59    USBDevice dev;
  60    int ep_fd[USB_MAX_ENDPOINTS];
  61    int devfd;
  62    char devpath[32];
  63} USBHostDevice;
  64
  65
  66#if 0
  67static int ensure_ep_open(USBHostDevice *dev, int ep, int mode)
  68{
  69    char buf[32];
  70    int fd;
  71
  72    /* Get the address for this endpoint */
  73    ep = UE_GET_ADDR(ep);
  74
  75    if (dev->ep_fd[ep] < 0) {
  76#if defined(__FreeBSD__) || defined(__DragonFly__)
  77        snprintf(buf, sizeof(buf) - 1, "%s.%d", dev->devpath, ep);
  78#else
  79        snprintf(buf, sizeof(buf) - 1, "%s.%02d", dev->devpath, ep);
  80#endif
  81        /* Try to open it O_RDWR first for those devices which have in and out
  82         * endpoints with the same address (eg 0x02 and 0x82)
  83         */
  84        fd = open(buf, O_RDWR);
  85        if (fd < 0 && errno == ENXIO)
  86            fd = open(buf, mode);
  87        if (fd < 0) {
  88#ifdef DEBUG
  89            printf("ensure_ep_open: failed to open device endpoint %s: %s\n",
  90                   buf, strerror(errno));
  91#endif
  92        }
  93        dev->ep_fd[ep] = fd;
  94    }
  95
  96    return dev->ep_fd[ep];
  97}
  98
  99static void ensure_eps_closed(USBHostDevice *dev)
 100{
 101    int epnum = 1;
 102
 103    if (!dev)
 104        return;
 105
 106    while (epnum < USB_MAX_ENDPOINTS) {
 107        if (dev->ep_fd[epnum] >= 0) {
 108            close(dev->ep_fd[epnum]);
 109            dev->ep_fd[epnum] = -1;
 110        }
 111        epnum++;
 112    }
 113}
 114#endif
 115
 116static void usb_host_handle_reset(USBDevice *dev)
 117{
 118#if 0
 119    USBHostDevice *s = (USBHostDevice *)dev;
 120#endif
 121}
 122
 123#if 0
 124/* XXX:
 125 * -check device states against transfer requests
 126 *  and return appropriate response
 127 */
 128static int usb_host_handle_control(USBDevice *dev,
 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
 214static 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}
 281#endif
 282
 283static 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
 300static int usb_host_initfn(USBDevice *dev)
 301{
 302    return 0;
 303}
 304
 305USBDevice *usb_host_device_open(const char *devname)
 306{
 307    struct usb_device_info bus_info, dev_info;
 308    USBDevice *d = NULL;
 309    USBHostDevice *dev, *ret = NULL;
 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
 315    if (usb_host_find_device(&bus, &address, devname) < 0) {
 316        goto fail;
 317    }
 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
 327        goto fail;
 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
 336        goto fail_bfd;
 337    }
 338
 339#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 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        }
 354        goto fail_dfd;
 355    }
 356
 357    if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) {
 358#ifdef DEBUG
 359        printf("usb_host_device_open: failed to grab device info - %s\n",
 360               strerror(errno));
 361#endif
 362        goto fail_dfd;
 363    }
 364
 365    d = usb_create(NULL /* FIXME */, "usb-host");
 366    dev = DO_UPCAST(USBHostDevice, dev, d);
 367
 368    if (dev_info.udi_speed == 1) {
 369        dev->dev.speed = USB_SPEED_LOW - 1;
 370    } else {
 371        dev->dev.speed = USB_SPEED_FULL - 1;
 372    }
 373
 374    if (strncmp(dev_info.udi_product, "product", 7) != 0) {
 375        pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
 376                dev_info.udi_product);
 377    } else {
 378        snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
 379                 "host:%s", devname);
 380    }
 381
 382    pstrcpy(dev->devpath, sizeof(dev->devpath), "/dev/");
 383    pstrcat(dev->devpath, sizeof(dev->devpath), dev_info.udi_devnames[0]);
 384
 385    /* Mark the endpoints as not yet open */
 386    for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
 387        dev->ep_fd[i] = -1;
 388    }
 389
 390    ioctl(dfd, USB_SETDEBUG, &ugendebug);
 391
 392    ret = (USBDevice *)dev;
 393
 394fail_dfd:
 395    close(dfd);
 396fail_bfd:
 397    close(bfd);
 398fail:
 399    return ret;
 400}
 401
 402static struct USBDeviceInfo usb_host_dev_info = {
 403    .product_desc   = "USB Host Device",
 404    .qdev.name      = "usb-host",
 405    .qdev.size      = sizeof(USBHostDevice),
 406    .init           = usb_host_initfn,
 407    .handle_packet  = usb_generic_handle_packet,
 408    .handle_reset   = usb_host_handle_reset,
 409#if 0
 410    .handle_control = usb_host_handle_control,
 411    .handle_data    = usb_host_handle_data,
 412#endif
 413    .handle_destroy = usb_host_handle_destroy,
 414};
 415
 416static void usb_host_register_devices(void)
 417{
 418    usb_qdev_register(&usb_host_dev_info);
 419}
 420device_init(usb_host_register_devices)
 421
 422static int usb_host_scan(void *opaque, USBScanFunc *func)
 423{
 424    struct usb_device_info bus_info;
 425    struct usb_device_info dev_info;
 426    uint16_t vendor_id, product_id, class_id, speed;
 427    int bfd, dfd, bus, address;
 428    char busbuf[20], devbuf[20], product_name[256];
 429    int ret = 0;
 430
 431    for (bus = 0; bus < 10; bus++) {
 432
 433        snprintf(busbuf, sizeof(busbuf) - 1, "/dev/usb%d", bus);
 434        bfd = open(busbuf, O_RDWR);
 435        if (bfd < 0)
 436            continue;
 437
 438        for (address = 1; address < 127; address++) {
 439
 440            bus_info.udi_addr = address;
 441            if (ioctl(bfd, USB_DEVICEINFO, &bus_info) < 0)
 442                continue;
 443
 444            /* only list devices that can be used by generic layer */
 445            if (strncmp(bus_info.udi_devnames[0], "ugen", 4) != 0)
 446                continue;
 447
 448#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 449            snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s", bus_info.udi_devnames[0]);
 450#else
 451            snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s.00", bus_info.udi_devnames[0]);
 452#endif
 453
 454            dfd = open(devbuf, O_RDONLY);
 455            if (dfd < 0) {
 456#ifdef DEBUG
 457                printf("usb_host_scan: couldn't open device %s - %s\n", devbuf,
 458                       strerror(errno));
 459#endif
 460                continue;
 461            }
 462
 463            if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0)
 464                printf("usb_host_scan: couldn't get device information for %s - %s\n",
 465                       devbuf, strerror(errno));
 466
 467            // XXX: might need to fixup endianess of word values before copying over
 468
 469            vendor_id = dev_info.udi_vendorNo;
 470            product_id = dev_info.udi_productNo;
 471            class_id = dev_info.udi_class;
 472            speed = dev_info.udi_speed;
 473
 474            if (strncmp(dev_info.udi_product, "product", 7) != 0)
 475                pstrcpy(product_name, sizeof(product_name),
 476                        dev_info.udi_product);
 477            else
 478                product_name[0] = '\0';
 479
 480            ret = func(opaque, bus, address, class_id, vendor_id,
 481                       product_id, product_name, speed);
 482
 483            close(dfd);
 484
 485            if (ret)
 486                goto the_end;
 487        }
 488
 489        close(bfd);
 490    }
 491
 492the_end:
 493    return ret;
 494}
 495
 496typedef struct FindDeviceState {
 497    int vendor_id;
 498    int product_id;
 499    int bus_num;
 500    int addr;
 501} FindDeviceState;
 502
 503static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
 504                                     int class_id,
 505                                     int vendor_id, int product_id,
 506                                     const char *product_name, int speed)
 507{
 508    FindDeviceState *s = opaque;
 509    if (vendor_id == s->vendor_id &&
 510        product_id == s->product_id) {
 511        s->bus_num = bus_num;
 512        s->addr = addr;
 513        return 1;
 514     } else {
 515        return 0;
 516     }
 517}
 518
 519
 520/* the syntax is :
 521   'bus.addr' (decimal numbers) or
 522   'vendor_id:product_id' (hexa numbers) */
 523static int usb_host_find_device(int *pbus_num, int *paddr,
 524                                const char *devname)
 525{
 526    const char *p;
 527    int ret;
 528    FindDeviceState fs;
 529
 530    p = strchr(devname, '.');
 531    if (p) {
 532        *pbus_num = strtoul(devname, NULL, 0);
 533        *paddr = strtoul(p + 1, NULL, 0);
 534        return 0;
 535    }
 536    p = strchr(devname, ':');
 537    if (p) {
 538        fs.vendor_id = strtoul(devname, NULL, 16);
 539        fs.product_id = strtoul(p + 1, NULL, 16);
 540        ret = usb_host_scan(&fs, usb_host_find_device_scan);
 541        if (ret) {
 542            *pbus_num = fs.bus_num;
 543            *paddr = fs.addr;
 544            return 0;
 545        }
 546     }
 547     return -1;
 548}
 549
 550/**********************/
 551/* USB host device info */
 552
 553struct usb_class_info {
 554    int class;
 555    const char *class_name;
 556};
 557
 558static const struct usb_class_info usb_class_info[] = {
 559    { USB_CLASS_AUDIO, "Audio"},
 560    { USB_CLASS_COMM, "Communication"},
 561    { USB_CLASS_HID, "HID"},
 562    { USB_CLASS_HUB, "Hub" },
 563    { USB_CLASS_PHYSICAL, "Physical" },
 564    { USB_CLASS_PRINTER, "Printer" },
 565    { USB_CLASS_MASS_STORAGE, "Storage" },
 566    { USB_CLASS_CDC_DATA, "Data" },
 567    { USB_CLASS_APP_SPEC, "Application Specific" },
 568    { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
 569    { USB_CLASS_STILL_IMAGE, "Still Image" },
 570    { USB_CLASS_CSCID, "Smart Card" },
 571    { USB_CLASS_CONTENT_SEC, "Content Security" },
 572    { -1, NULL }
 573};
 574
 575static const char *usb_class_str(uint8_t class)
 576{
 577    const struct usb_class_info *p;
 578    for (p = usb_class_info; p->class != -1; p++) {
 579        if (p->class == class)
 580            break;
 581    }
 582    return p->class_name;
 583}
 584
 585static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
 586                            int vendor_id, int product_id,
 587                            const char *product_name,
 588                            int speed)
 589{
 590    const char *class_str, *speed_str;
 591
 592    switch(speed) {
 593    case USB_SPEED_LOW:
 594        speed_str = "1.5";
 595        break;
 596    case USB_SPEED_FULL:
 597        speed_str = "12";
 598        break;
 599    case USB_SPEED_HIGH:
 600        speed_str = "480";
 601        break;
 602    default:
 603        speed_str = "?";
 604        break;
 605    }
 606
 607    monitor_printf(mon, "  Device %d.%d, speed %s Mb/s\n",
 608                   bus_num, addr, speed_str);
 609    class_str = usb_class_str(class_id);
 610    if (class_str)
 611        monitor_printf(mon, "    %s:", class_str);
 612    else
 613        monitor_printf(mon, "    Class %02x:", class_id);
 614    monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
 615    if (product_name[0] != '\0')
 616        monitor_printf(mon, ", %s", product_name);
 617    monitor_printf(mon, "\n");
 618}
 619
 620static int usb_host_info_device(void *opaque,
 621                                int bus_num, int addr,
 622                                int class_id,
 623                                int vendor_id, int product_id,
 624                                const char *product_name,
 625                                int speed)
 626{
 627    Monitor *mon = opaque;
 628
 629    usb_info_device(mon, bus_num, addr, class_id, vendor_id, product_id,
 630                    product_name, speed);
 631    return 0;
 632}
 633
 634void usb_host_info(Monitor *mon)
 635{
 636    usb_host_scan(mon, usb_host_info_device);
 637}
 638
 639/* XXX add this */
 640int usb_host_device_close(const char *devname)
 641{
 642    return 0;
 643}
 644