usb-linux.c 28.4 KB
Newer Older
B
bellard 已提交
1 2 3 4
/*
 * Linux host USB redirector
 *
 * Copyright (c) 2005 Fabrice Bellard
5
 *
6 7 8
 * Copyright (c) 2008 Max Krasnyansky
 *      Support for host device auto connect & disconnect
 *      Magor rewrite to support fully async operation
9
 *
B
bellard 已提交
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
P
pbrook 已提交
28
#include "qemu-common.h"
29
#include "qemu-timer.h"
P
pbrook 已提交
30 31
#include "hw/usb.h"
#include "console.h"
B
bellard 已提交
32 33 34 35 36 37

#if defined(__linux__)
#include <dirent.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>
#include <linux/version.h>
38
#include <signal.h>
B
bellard 已提交
39 40 41 42 43 44 45 46 47 48 49 50

/* We redefine it to avoid version problems */
struct usb_ctrltransfer {
    uint8_t  bRequestType;
    uint8_t  bRequest;
    uint16_t wValue;
    uint16_t wIndex;
    uint16_t wLength;
    uint32_t timeout;
    void *data;
};

B
bellard 已提交
51
typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
52
                        int vendor_id, int product_id,
B
bellard 已提交
53
                        const char *product_name, int speed);
54
static int usb_host_find_device(int *pbus_num, int *paddr,
55
                                char *product_name, int product_name_size,
B
bellard 已提交
56
                                const char *devname);
B
bellard 已提交
57

B
bellard 已提交
58
//#define DEBUG
59 60 61 62 63 64

#ifdef DEBUG
#define dprintf printf
#else
#define dprintf(...)
#endif
B
bellard 已提交
65 66

#define USBDEVFS_PATH "/proc/bus/usb"
67
#define PRODUCT_NAME_SZ 32
68
#define MAX_ENDPOINTS 16
B
bellard 已提交
69

70 71 72 73 74
struct sigaction sigact;

/* endpoint association data */
struct endp_data {
    uint8_t type;
75
    uint8_t halted;
76 77
};

B
bellard 已提交
78 79
typedef struct USBHostDevice {
    USBDevice dev;
80 81 82 83 84
    int       fd;

    uint8_t   descr[1024];
    int       descr_len;
    int       configuration;
85
    int       closing;
86

87
    struct endp_data endp_table[MAX_ENDPOINTS];
88 89 90 91 92 93

    /* Host side address */
    int bus_num;
    int addr;

    struct USBHostDevice *next;
B
bellard 已提交
94 95
} USBHostDevice;

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
static int is_isoc(USBHostDevice *s, int ep)
{
    return s->endp_table[ep - 1].type == USBDEVFS_URB_TYPE_ISO;
}

static int is_halted(USBHostDevice *s, int ep)
{
    return s->endp_table[ep - 1].halted;
}

static void clear_halt(USBHostDevice *s, int ep)
{
    s->endp_table[ep - 1].halted = 0;
}

static void set_halt(USBHostDevice *s, int ep)
{
    s->endp_table[ep - 1].halted = 1;
}

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
static USBHostDevice *hostdev_list;

static void hostdev_link(USBHostDevice *dev)
{
    dev->next = hostdev_list;
    hostdev_list = dev;
}

static void hostdev_unlink(USBHostDevice *dev)
{
    USBHostDevice *pdev = hostdev_list;
    USBHostDevice **prev = &hostdev_list;

    while (pdev) {
	if (pdev == dev) {
            *prev = dev->next;
            return;
        }

        prev = &pdev->next;
        pdev = pdev->next;
    }
}

static USBHostDevice *hostdev_find(int bus_num, int addr)
{
    USBHostDevice *s = hostdev_list;
    while (s) {
        if (s->bus_num == bus_num && s->addr == addr)
            return s;
        s = s->next;
    }
    return NULL;
}

151 152 153 154 155 156 157 158 159
/* 
 * Async URB state.
 * We always allocate one isoc descriptor even for bulk transfers
 * to simplify allocation and casts. 
 */
typedef struct AsyncURB
{
    struct usbdevfs_urb urb;
    struct usbdevfs_iso_packet_desc isocpd;
160

161 162 163
    USBPacket     *packet;
    USBHostDevice *hdev;
} AsyncURB;
164

165
static AsyncURB *async_alloc(void)
166
{
167
    return (AsyncURB *) qemu_mallocz(sizeof(AsyncURB));
168 169
}

170
static void async_free(AsyncURB *aurb)
171
{
172 173
    qemu_free(aurb);
}
174

175 176 177 178 179 180 181
static void async_complete(void *opaque)
{
    USBHostDevice *s = opaque;
    AsyncURB *aurb;

    while (1) {
    	USBPacket *p;
182

183 184 185 186 187
	int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
        if (r < 0) {
            if (errno == EAGAIN)
                return;

188
            if (errno == ENODEV && !s->closing) {
189 190 191 192 193 194 195
                printf("husb: device %d.%d disconnected\n", s->bus_num, s->addr);
	        usb_device_del_addr(0, s->dev.addr);
                return;
            }

            dprintf("husb: async. reap urb failed errno %d\n", errno);
            return;
196
        }
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220

        p = aurb->packet;

	dprintf("husb: async completed. aurb %p status %d alen %d\n", 
                aurb, aurb->urb.status, aurb->urb.actual_length);

	if (p) {
            switch (aurb->urb.status) {
            case 0:
                p->len = aurb->urb.actual_length;
                break;

            case -EPIPE:
                set_halt(s, p->devep);
                /* fall through */
            default:
                p->len = USB_RET_NAK;
                break;
            }

            usb_packet_complete(p);
	}

        async_free(aurb);
221 222 223
    }
}

224
static void async_cancel(USBPacket *unused, void *opaque)
225
{
226 227
    AsyncURB *aurb = opaque;
    USBHostDevice *s = aurb->hdev;
228

229 230 231 232
    dprintf("husb: async cancel. aurb %p\n", aurb);

    /* Mark it as dead (see async_complete above) */
    aurb->packet = NULL;
233

234 235 236
    int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
    if (r < 0) {
        dprintf("husb: async. discard urb failed errno %d\n", errno);
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    }
}

static int usb_host_update_interfaces(USBHostDevice *dev, int configuration)
{
    int dev_descr_len, config_descr_len;
    int interface, nb_interfaces, nb_configurations;
    int ret, i;

    if (configuration == 0) /* address state - ignore */
        return 1;

    i = 0;
    dev_descr_len = dev->descr[0];
    if (dev_descr_len > dev->descr_len)
        goto fail;
    nb_configurations = dev->descr[17];

    i += dev_descr_len;
    while (i < dev->descr_len) {
257
        dprintf("husb: i is %d, descr_len is %d, dl %d, dt %d\n", i, dev->descr_len,
258
               dev->descr[i], dev->descr[i+1]);
259

260 261 262 263 264 265
        if (dev->descr[i+1] != USB_DT_CONFIG) {
            i += dev->descr[i];
            continue;
        }
        config_descr_len = dev->descr[i];

266
	printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration); 
267 268

        if (configuration < 0 || configuration == dev->descr[i + 5])
269 270 271 272 273 274
            break;

        i += config_descr_len;
    }

    if (i >= dev->descr_len) {
275
        printf("husb: update iface failed. no matching configuration\n");
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
        goto fail;
    }
    nb_interfaces = dev->descr[i + 4];

#ifdef USBDEVFS_DISCONNECT
    /* earlier Linux 2.4 do not support that */
    {
        struct usbdevfs_ioctl ctrl;
        for (interface = 0; interface < nb_interfaces; interface++) {
            ctrl.ioctl_code = USBDEVFS_DISCONNECT;
            ctrl.ifno = interface;
            ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
            if (ret < 0 && errno != ENODATA) {
                perror("USBDEVFS_DISCONNECT");
                goto fail;
            }
        }
    }
#endif

    /* XXX: only grab if all interfaces are free */
    for (interface = 0; interface < nb_interfaces; interface++) {
        ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
        if (ret < 0) {
            if (errno == EBUSY) {
301
                printf("husb: update iface. device already grabbed\n");
302
            } else {
303
                perror("husb: failed to claim interface");
304 305 306 307 308 309
            }
        fail:
            return 0;
        }
    }

310
    printf("husb: %d interfaces claimed for configuration %d\n",
311 312 313 314 315
           nb_interfaces, configuration);

    return 1;
}

B
bellard 已提交
316
static void usb_host_handle_reset(USBDevice *dev)
B
bellard 已提交
317 318
{
    USBHostDevice *s = (USBHostDevice *)dev;
319 320 321

    dprintf("husb: reset device %u.%u\n", s->bus_num, s->addr);

B
bellard 已提交
322
    ioctl(s->fd, USBDEVFS_RESET);
323
    usb_host_update_interfaces(s, s->configuration);
324
}
B
bellard 已提交
325

B
bellard 已提交
326 327 328 329
static void usb_host_handle_destroy(USBDevice *dev)
{
    USBHostDevice *s = (USBHostDevice *)dev;

330 331
    s->closing = 1;

332
    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
333

334 335
    hostdev_unlink(s);

336 337
    async_complete(s);

B
bellard 已提交
338 339
    if (s->fd >= 0)
        close(s->fd);
340

B
bellard 已提交
341 342 343
    qemu_free(s);
}

344 345
static int usb_linux_update_endp_table(USBHostDevice *s);

B
bellard 已提交
346 347 348 349 350 351 352 353 354
static int usb_host_handle_control(USBDevice *dev,
                                   int request,
                                   int value,
                                   int index,
                                   int length,
                                   uint8_t *data)
{
    USBHostDevice *s = (USBHostDevice *)dev;
    struct usb_ctrltransfer ct;
355 356
    struct usbdevfs_setinterface si;
    int intf_update_required = 0;
B
bellard 已提交
357 358 359 360 361 362
    int ret;

    if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) {
        /* specific SET_ADDRESS support */
        dev->addr = value;
        return 0;
363 364 365 366 367 368 369 370
    } else if (request == ((USB_RECIP_INTERFACE << 8) |
                           USB_REQ_SET_INTERFACE)) {
        /* set alternate setting for the interface */
        si.interface = index;
        si.altsetting = value;
        ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
        usb_linux_update_endp_table(s);
    } else if (request == (DeviceOutRequest | USB_REQ_SET_CONFIGURATION)) {
371
        dprintf("husb: ctrl set config %d\n", value & 0xff);
372 373 374 375 376
        if (s->configuration != (value & 0xff)) {
            s->configuration = (value & 0xff);
            intf_update_required = 1;
        }
        goto do_request;
B
bellard 已提交
377
    } else {
378
    do_request:
B
bellard 已提交
379 380 381 382 383 384 385 386
        ct.bRequestType = request >> 8;
        ct.bRequest = request;
        ct.wValue = value;
        ct.wIndex = index;
        ct.wLength = length;
        ct.timeout = 50;
        ct.data = data;
        ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
387 388 389

        dprintf("husb: ctrl req 0x%x val 0x%x index %u len %u ret %d\n",
            ct.bRequest, ct.wValue, ct.wIndex, ct.wLength, ret);
390 391 392 393 394 395 396 397
    }

    if (ret < 0) {
        switch(errno) {
        case ETIMEDOUT:
            return USB_RET_NAK;
        default:
            return USB_RET_STALL;
B
bellard 已提交
398
        }
399 400
    } else {
        if (intf_update_required) {
401
            dprintf("husb: updating interfaces\n");
402 403 404 405
            usb_host_update_interfaces(s, value & 0xff);
        }
        return ret;
    }
B
bellard 已提交
406 407
}

P
pbrook 已提交
408
static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
B
bellard 已提交
409
{
410 411 412
    USBHostDevice *s = (USBHostDevice *) dev;
    AsyncURB *aurb;
    struct usbdevfs_urb *urb;
B
bellard 已提交
413 414
    int ret;

415 416 417 418
    aurb = async_alloc();
    if (!aurb) {
        dprintf("husb: async malloc failed\n");
        return USB_RET_NAK;
419
    }
420 421 422 423
    aurb->hdev   = s;
    aurb->packet = p;

    urb = &aurb->urb;
424

P
pbrook 已提交
425
    if (p->pid == USB_TOKEN_IN)
426 427 428 429 430 431 432 433 434
    	urb->endpoint = p->devep | 0x80;
    else
    	urb->endpoint = p->devep;

    if (is_halted(s, p->devep)) {
	ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
        if (ret < 0) {
            dprintf("husb: failed to clear halt. ep 0x%x errno %d\n", 
                   urb->endpoint, errno);
B
bellard 已提交
435 436
            return USB_RET_NAK;
        }
437
        clear_halt(s, p->devep);
438 439
    }

440 441
    urb->buffer        = p->data;
    urb->buffer_length = p->len;
442

443 444 445 446 447 448 449 450 451
    if (is_isoc(s, p->devep)) {
        /* Setup ISOC transfer */
        urb->type     = USBDEVFS_URB_TYPE_ISO;
        urb->flags    = USBDEVFS_URB_ISO_ASAP;
        urb->number_of_packets = 1;
        urb->iso_frame_desc[0].length = p->len;
    } else {
        /* Setup bulk transfer */
        urb->type     = USBDEVFS_URB_TYPE_BULK;
452 453
    }

454
    urb->usercontext = s;
455

456
    ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
457

458
    dprintf("husb: data submit. ep 0x%x len %u aurb %p\n", urb->endpoint, p->len, aurb);
459

460 461 462
    if (ret < 0) {
        dprintf("husb: submit failed. errno %d\n", errno);
        async_free(aurb);
463 464 465 466 467 468 469 470 471

        switch(errno) {
        case ETIMEDOUT:
            return USB_RET_NAK;
        case EPIPE:
        default:
            return USB_RET_STALL;
        }
    }
472 473

    usb_defer_packet(p, async_cancel, aurb);
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
    return USB_RET_ASYNC;
}

/* returns 1 on problem encountered or 0 for success */
static int usb_linux_update_endp_table(USBHostDevice *s)
{
    uint8_t *descriptors;
    uint8_t devep, type, configuration, alt_interface;
    struct usb_ctrltransfer ct;
    int interface, ret, length, i;

    ct.bRequestType = USB_DIR_IN;
    ct.bRequest = USB_REQ_GET_CONFIGURATION;
    ct.wValue = 0;
    ct.wIndex = 0;
    ct.wLength = 1;
    ct.data = &configuration;
    ct.timeout = 50;

    ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
    if (ret < 0) {
        perror("usb_linux_update_endp_table");
        return 1;
    }

    /* in address state */
    if (configuration == 0)
        return 1;

    /* get the desired configuration, interface, and endpoint descriptors
     * from device description */
    descriptors = &s->descr[18];
    length = s->descr_len - 18;
    i = 0;

    if (descriptors[i + 1] != USB_DT_CONFIG ||
        descriptors[i + 5] != configuration) {
511
        dprintf("invalid descriptor data - configuration\n");
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
        return 1;
    }
    i += descriptors[i];

    while (i < length) {
        if (descriptors[i + 1] != USB_DT_INTERFACE ||
            (descriptors[i + 1] == USB_DT_INTERFACE &&
             descriptors[i + 4] == 0)) {
            i += descriptors[i];
            continue;
        }

        interface = descriptors[i + 2];

        ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
        ct.bRequest = USB_REQ_GET_INTERFACE;
        ct.wValue = 0;
        ct.wIndex = interface;
        ct.wLength = 1;
        ct.data = &alt_interface;
        ct.timeout = 50;

        ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
        if (ret < 0) {
            perror("usb_linux_update_endp_table");
            return 1;
        }

        /* the current interface descriptor is the active interface
         * and has endpoints */
        if (descriptors[i + 3] != alt_interface) {
            i += descriptors[i];
            continue;
        }

        /* advance to the endpoints */
        while (i < length && descriptors[i +1] != USB_DT_ENDPOINT)
            i += descriptors[i];

        if (i >= length)
            break;

        while (i < length) {
            if (descriptors[i + 1] != USB_DT_ENDPOINT)
                break;

            devep = descriptors[i + 2];
            switch (descriptors[i + 3] & 0x3) {
            case 0x00:
                type = USBDEVFS_URB_TYPE_CONTROL;
                break;
            case 0x01:
                type = USBDEVFS_URB_TYPE_ISO;
                break;
            case 0x02:
                type = USBDEVFS_URB_TYPE_BULK;
                break;
            case 0x03:
                type = USBDEVFS_URB_TYPE_INTERRUPT;
                break;
            default:
573
                dprintf("usb_host: malformed endpoint type\n");
574 575 576
                type = USBDEVFS_URB_TYPE_BULK;
            }
            s->endp_table[(devep & 0xf) - 1].type = type;
577
            s->endp_table[(devep & 0xf) - 1].halted = 0;
578 579 580 581 582 583 584

            i += descriptors[i];
        }
    }
    return 0;
}

585
static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *prod_name)
B
bellard 已提交
586
{
587 588
    int fd = -1, ret;
    USBHostDevice *dev = NULL;
B
bellard 已提交
589
    struct usbdevfs_connectinfo ci;
B
bellard 已提交
590
    char buf[1024];
591

592 593 594 595
    dev = qemu_mallocz(sizeof(USBHostDevice));
    if (!dev)
        goto fail;

596 597 598
    dev->bus_num = bus_num;
    dev->addr = addr;

599
    printf("husb: open device %d.%d\n", bus_num, addr);
600

601
    snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
B
bellard 已提交
602
             bus_num, addr);
603
    fd = open(buf, O_RDWR | O_NONBLOCK);
B
bellard 已提交
604
    if (fd < 0) {
B
bellard 已提交
605
        perror(buf);
606
        goto fail;
B
bellard 已提交
607 608
    }

609 610 611
    /* read the device description */
    dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
    if (dev->descr_len <= 0) {
612
        perror("husb: reading device data failed");
B
bellard 已提交
613 614
        goto fail;
    }
615

616
#ifdef DEBUG
B
bellard 已提交
617
    {
618 619 620 621 622
        int x;
        printf("=== begin dumping device descriptor data ===\n");
        for (x = 0; x < dev->descr_len; x++)
            printf("%02x ", dev->descr[x]);
        printf("\n=== end dumping device descriptor data ===\n");
B
bellard 已提交
623
    }
B
bellard 已提交
624 625
#endif

626 627 628 629
    dev->fd = fd;
    dev->configuration = 1;

    /* XXX - do something about initial configuration */
630
    if (!usb_host_update_interfaces(dev, -1))
631
        goto fail;
B
bellard 已提交
632 633 634

    ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
    if (ret < 0) {
635
        perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
B
bellard 已提交
636 637 638
        goto fail;
    }

639
    printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
B
bellard 已提交
640

641 642
    ret = usb_linux_update_endp_table(dev);
    if (ret)
B
bellard 已提交
643
        goto fail;
644

B
bellard 已提交
645 646 647 648
    if (ci.slow)
        dev->dev.speed = USB_SPEED_LOW;
    else
        dev->dev.speed = USB_SPEED_HIGH;
B
bellard 已提交
649
    dev->dev.handle_packet = usb_generic_handle_packet;
B
bellard 已提交
650 651 652 653

    dev->dev.handle_reset = usb_host_handle_reset;
    dev->dev.handle_control = usb_host_handle_control;
    dev->dev.handle_data = usb_host_handle_data;
B
bellard 已提交
654
    dev->dev.handle_destroy = usb_host_handle_destroy;
655

656
    if (!prod_name || prod_name[0] == '\0')
657
        snprintf(dev->dev.devname, sizeof(dev->dev.devname),
658
                 "host:%d.%d", bus_num, addr);
659 660
    else
        pstrcpy(dev->dev.devname, sizeof(dev->dev.devname),
661
                prod_name);
662

663 664
    /* USB devio uses 'write' flag to check for async completions */
    qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
665

666 667
    hostdev_link(dev);

668
    return (USBDevice *) dev;
669

670
fail:
671
    if (dev)
672
        qemu_free(dev);
673

674 675
    close(fd);
    return NULL;
B
bellard 已提交
676
}
B
bellard 已提交
677

678 679 680 681 682 683 684 685 686 687 688
USBDevice *usb_host_device_open(const char *devname)
{
    int bus_num, addr;
    char product_name[PRODUCT_NAME_SZ];

    if (usb_host_find_device(&bus_num, &addr,
                             product_name, sizeof(product_name),
                             devname) < 0)
        return NULL;

     if (hostdev_find(bus_num, addr)) {
689
        term_printf("husb: host usb device %d.%d is already open\n", bus_num, addr);
690 691 692 693 694 695
        return NULL;
     }

    return usb_host_device_open_addr(bus_num, addr, product_name);
}
 
B
bellard 已提交
696
static int get_tag_value(char *buf, int buf_size,
697
                         const char *str, const char *tag,
B
bellard 已提交
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
                         const char *stopchars)
{
    const char *p;
    char *q;
    p = strstr(str, tag);
    if (!p)
        return -1;
    p += strlen(tag);
    while (isspace(*p))
        p++;
    q = buf;
    while (*p != '\0' && !strchr(stopchars, *p)) {
        if ((q - buf) < (buf_size - 1))
            *q++ = *p;
        p++;
    }
    *q = '\0';
    return q - buf;
B
bellard 已提交
716 717
}

B
bellard 已提交
718
static int usb_host_scan(void *opaque, USBScanFunc *func)
B
bellard 已提交
719
{
B
bellard 已提交
720 721
    FILE *f;
    char line[1024];
B
bellard 已提交
722
    char buf[1024];
B
bellard 已提交
723 724 725
    int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
    int ret;
    char product_name[512];
726

B
bellard 已提交
727 728
    f = fopen(USBDEVFS_PATH "/devices", "r");
    if (!f) {
729
        term_printf("husb: could not open %s\n", USBDEVFS_PATH "/devices");
B
bellard 已提交
730 731 732 733 734
        return 0;
    }
    device_count = 0;
    bus_num = addr = speed = class_id = product_id = vendor_id = 0;
    ret = 0;
B
bellard 已提交
735
    for(;;) {
B
bellard 已提交
736
        if (fgets(line, sizeof(line), f) == NULL)
B
bellard 已提交
737
            break;
B
bellard 已提交
738 739 740
        if (strlen(line) > 0)
            line[strlen(line) - 1] = '\0';
        if (line[0] == 'T' && line[1] == ':') {
741 742
            if (device_count && (vendor_id || product_id)) {
                /* New device.  Add the previously discovered device.  */
743
                ret = func(opaque, bus_num, addr, class_id, vendor_id,
B
bellard 已提交
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
                           product_id, product_name, speed);
                if (ret)
                    goto the_end;
            }
            if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0)
                goto fail;
            bus_num = atoi(buf);
            if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0)
                goto fail;
            addr = atoi(buf);
            if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0)
                goto fail;
            if (!strcmp(buf, "480"))
                speed = USB_SPEED_HIGH;
            else if (!strcmp(buf, "1.5"))
                speed = USB_SPEED_LOW;
            else
                speed = USB_SPEED_FULL;
            product_name[0] = '\0';
            class_id = 0xff;
            device_count++;
            product_id = 0;
            vendor_id = 0;
        } else if (line[0] == 'P' && line[1] == ':') {
            if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0)
                goto fail;
            vendor_id = strtoul(buf, NULL, 16);
            if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0)
                goto fail;
            product_id = strtoul(buf, NULL, 16);
        } else if (line[0] == 'S' && line[1] == ':') {
            if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0)
                goto fail;
            pstrcpy(product_name, sizeof(product_name), buf);
        } else if (line[0] == 'D' && line[1] == ':') {
            if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0)
                goto fail;
            class_id = strtoul(buf, NULL, 16);
B
bellard 已提交
782
        }
B
bellard 已提交
783 784
    fail: ;
    }
785 786
    if (device_count && (vendor_id || product_id)) {
        /* Add the last device.  */
787
        ret = func(opaque, bus_num, addr, class_id, vendor_id,
B
bellard 已提交
788
                   product_id, product_name, speed);
B
bellard 已提交
789
    }
B
bellard 已提交
790 791 792
 the_end:
    fclose(f);
    return ret;
B
bellard 已提交
793 794
}

795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
struct USBAutoFilter {
    struct USBAutoFilter *next;
    int bus_num;
    int addr;
    int vendor_id;
    int product_id;
};

static QEMUTimer *usb_auto_timer;
static struct USBAutoFilter *usb_auto_filter;

static int usb_host_auto_scan(void *opaque, int bus_num, int addr,
                     int class_id, int vendor_id, int product_id,
                     const char *product_name, int speed)
{
    struct USBAutoFilter *f;
    struct USBDevice *dev;

    /* Ignore hubs */
    if (class_id == 9)
        return 0;

    for (f = usb_auto_filter; f; f = f->next) {
        // printf("Auto match: bus_num %d addr %d vid %d pid %d\n",
	//    bus_num, addr, vendor_id, product_id);

	if (f->bus_num >= 0 && f->bus_num != bus_num)
            continue;

	if (f->addr >= 0 && f->addr != addr)
            continue;

	if (f->vendor_id >= 0 && f->vendor_id != vendor_id)
            continue;

	if (f->product_id >= 0 && f->product_id != product_id)
            continue;

        /* We got a match */

        /* Allredy attached ? */
        if (hostdev_find(bus_num, addr))
            return 0;

839
        dprintf("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862

	dev = usb_host_device_open_addr(bus_num, addr, product_name);
	if (dev)
	    usb_device_add_dev(dev);
    }

    return 0;
}

static void usb_host_auto_timer(void *unused)
{
    usb_host_scan(NULL, usb_host_auto_scan);
    qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000);
}

/*
 * Add autoconnect filter
 * -1 means 'any' (device, vendor, etc)
 */
static void usb_host_auto_add(int bus_num, int addr, int vendor_id, int product_id)
{
    struct USBAutoFilter *f = qemu_mallocz(sizeof(*f));
    if (!f) {
863
        printf("husb: failed to allocate auto filter\n");
864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
	return;
    }

    f->bus_num = bus_num;
    f->addr    = addr;
    f->vendor_id  = vendor_id;
    f->product_id = product_id;

    if (!usb_auto_filter) {
        /*
         * First entry. Init and start the monitor.
         * Right now we're using timer to check for new devices.
         * If this turns out to be too expensive we can move that into a 
         * separate thread.
         */
	usb_auto_timer = qemu_new_timer(rt_clock, usb_host_auto_timer, NULL);
	if (!usb_auto_timer) {
881
            printf("husb: failed to allocate timer\n");
882 883 884 885 886 887 888 889
            qemu_free(f);
            return;
        }

        /* Check for new devices every two seconds */
        qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000);
    }

890
    dprintf("husb: auto filter: bus_num %d addr %d vid %d pid %d\n",
891 892 893 894 895 896
	bus_num, addr, vendor_id, product_id);

    f->next = usb_auto_filter;
    usb_auto_filter = f;
}

B
bellard 已提交
897 898 899 900 901
typedef struct FindDeviceState {
    int vendor_id;
    int product_id;
    int bus_num;
    int addr;
902
    char product_name[PRODUCT_NAME_SZ];
B
bellard 已提交
903 904
} FindDeviceState;

905
static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
B
bellard 已提交
906
                                     int class_id,
907
                                     int vendor_id, int product_id,
B
bellard 已提交
908
                                     const char *product_name, int speed)
B
bellard 已提交
909
{
B
bellard 已提交
910
    FindDeviceState *s = opaque;
911 912 913 914 915
    if ((vendor_id == s->vendor_id &&
        product_id == s->product_id) ||
        (bus_num == s->bus_num &&
        addr == s->addr)) {
        pstrcpy(s->product_name, PRODUCT_NAME_SZ, product_name);
B
bellard 已提交
916 917 918 919 920 921 922
        s->bus_num = bus_num;
        s->addr = addr;
        return 1;
    } else {
        return 0;
    }
}
B
bellard 已提交
923

924 925
/* the syntax is :
   'bus.addr' (decimal numbers) or
B
bellard 已提交
926
   'vendor_id:product_id' (hexa numbers) */
927
static int usb_host_find_device(int *pbus_num, int *paddr,
928
                                char *product_name, int product_name_size,
B
bellard 已提交
929 930 931 932 933 934 935 936 937
                                const char *devname)
{
    const char *p;
    int ret;
    FindDeviceState fs;

    p = strchr(devname, '.');
    if (p) {
        *pbus_num = strtoul(devname, NULL, 0);
938 939 940 941 942 943

        if (*(p + 1) == '*') {
            usb_host_auto_add(*pbus_num, -1, -1, -1);
	    return -1;
	}

B
bellard 已提交
944
        *paddr = strtoul(p + 1, NULL, 0);
945 946 947 948 949
        fs.bus_num = *pbus_num;
        fs.addr = *paddr;
        ret = usb_host_scan(&fs, usb_host_find_device_scan);
        if (ret)
            pstrcpy(product_name, product_name_size, fs.product_name);
B
bellard 已提交
950 951 952 953 954
        return 0;
    }
    p = strchr(devname, ':');
    if (p) {
        fs.vendor_id = strtoul(devname, NULL, 16);
955 956 957 958 959 960

        if (*(p + 1) == '*') {
            usb_host_auto_add(-1, -1, fs.vendor_id, -1);
	    return -1;
	}

B
bellard 已提交
961 962 963 964 965
        fs.product_id = strtoul(p + 1, NULL, 16);
        ret = usb_host_scan(&fs, usb_host_find_device_scan);
        if (ret) {
            *pbus_num = fs.bus_num;
            *paddr = fs.addr;
966
            pstrcpy(product_name, product_name_size, fs.product_name);
B
bellard 已提交
967
            return 0;
B
bellard 已提交
968 969
        }
    }
B
bellard 已提交
970
    return -1;
B
bellard 已提交
971 972
}

B
bellard 已提交
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
/**********************/
/* USB host device info */

struct usb_class_info {
    int class;
    const char *class_name;
};

static const struct usb_class_info usb_class_info[] = {
    { USB_CLASS_AUDIO, "Audio"},
    { USB_CLASS_COMM, "Communication"},
    { USB_CLASS_HID, "HID"},
    { USB_CLASS_HUB, "Hub" },
    { USB_CLASS_PHYSICAL, "Physical" },
    { USB_CLASS_PRINTER, "Printer" },
    { USB_CLASS_MASS_STORAGE, "Storage" },
    { USB_CLASS_CDC_DATA, "Data" },
    { USB_CLASS_APP_SPEC, "Application Specific" },
    { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
    { USB_CLASS_STILL_IMAGE, "Still Image" },
993
    { USB_CLASS_CSCID, "Smart Card" },
B
bellard 已提交
994 995 996 997 998
    { USB_CLASS_CONTENT_SEC, "Content Security" },
    { -1, NULL }
};

static const char *usb_class_str(uint8_t class)
B
bellard 已提交
999
{
B
bellard 已提交
1000 1001 1002 1003
    const struct usb_class_info *p;
    for(p = usb_class_info; p->class != -1; p++) {
        if (p->class == class)
            break;
B
bellard 已提交
1004
    }
B
bellard 已提交
1005 1006 1007
    return p->class_name;
}

1008 1009 1010 1011
static void usb_info_device(int bus_num, int addr, int class_id,
                            int vendor_id, int product_id,
                            const char *product_name,
                            int speed)
B
bellard 已提交
1012 1013 1014 1015
{
    const char *class_str, *speed_str;

    switch(speed) {
1016 1017
    case USB_SPEED_LOW:
        speed_str = "1.5";
B
bellard 已提交
1018
        break;
1019 1020
    case USB_SPEED_FULL:
        speed_str = "12";
B
bellard 已提交
1021
        break;
1022 1023
    case USB_SPEED_HIGH:
        speed_str = "480";
B
bellard 已提交
1024 1025
        break;
    default:
1026
        speed_str = "?";
B
bellard 已提交
1027 1028 1029
        break;
    }

1030
    term_printf("  Device %d.%d, speed %s Mb/s\n",
B
bellard 已提交
1031 1032
                bus_num, addr, speed_str);
    class_str = usb_class_str(class_id);
1033
    if (class_str)
B
bellard 已提交
1034 1035 1036 1037 1038 1039 1040 1041 1042
        term_printf("    %s:", class_str);
    else
        term_printf("    Class %02x:", class_id);
    term_printf(" USB device %04x:%04x", vendor_id, product_id);
    if (product_name[0] != '\0')
        term_printf(", %s", product_name);
    term_printf("\n");
}

1043
static int usb_host_info_device(void *opaque, int bus_num, int addr,
B
bellard 已提交
1044
                                int class_id,
1045
                                int vendor_id, int product_id,
B
bellard 已提交
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
                                const char *product_name,
                                int speed)
{
    usb_info_device(bus_num, addr, class_id, vendor_id, product_id,
                    product_name, speed);
    return 0;
}

void usb_host_info(void)
{
    usb_host_scan(NULL, usb_host_info_device);
B
bellard 已提交
1057 1058 1059 1060
}

#else

B
bellard 已提交
1061 1062 1063 1064 1065
void usb_host_info(void)
{
    term_printf("USB host devices not supported\n");
}

B
bellard 已提交
1066
/* XXX: modify configure to compile the right host driver */
B
bellard 已提交
1067
USBDevice *usb_host_device_open(const char *devname)
B
bellard 已提交
1068 1069 1070 1071 1072
{
    return NULL;
}

#endif