usb-linux.c 52.1 KB
Newer Older
B
bellard 已提交
1 2 3 4
/*
 * Linux host USB redirector
 *
 * Copyright (c) 2005 Fabrice Bellard
5
 *
6 7
 * Copyright (c) 2008 Max Krasnyansky
 *      Support for host device auto connect & disconnect
8
 *      Major rewrite to support fully async operation
9
 *
10 11 12 13
 * Copyright 2008 TJ <linux@tjworld.net>
 *      Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
 *      to the legacy /proc/bus/usb USB device discovery and handling
 *
B
bellard 已提交
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 * 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.
 */
32

P
pbrook 已提交
33
#include "qemu-common.h"
34
#include "qemu-timer.h"
A
aliguori 已提交
35
#include "monitor.h"
36
#include "sysemu.h"
G
Gerd Hoffmann 已提交
37
#include "trace.h"
B
bellard 已提交
38 39 40 41

#include <dirent.h>
#include <sys/ioctl.h>

42 43 44
#include <linux/usbdevice_fs.h>
#include <linux/version.h>
#include "hw/usb.h"
B
bellard 已提交
45

46 47 48 49 50 51 52 53 54 55 56
/* 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;
};

G
Gerd Hoffmann 已提交
57
typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port,
58
                        int class_id, int vendor_id, int product_id,
B
bellard 已提交
59
                        const char *product_name, int speed);
60

61
//#define DEBUG
62 63

#ifdef DEBUG
M
malc 已提交
64
#define DPRINTF printf
65
#else
M
malc 已提交
66
#define DPRINTF(...)
67
#endif
B
bellard 已提交
68

69
#define PRODUCT_NAME_SZ 32
70
#define MAX_PORTLEN 16
B
bellard 已提交
71

72
/* endpoint association data */
73 74
#define ISO_FRAME_DESC_PER_URB 32

G
Gerd Hoffmann 已提交
75 76 77
/* devio.c limits single requests to 16k */
#define MAX_USBFS_BUFFER_SIZE 16384

78 79
typedef struct AsyncURB AsyncURB;

80
struct endp_data {
81
    uint8_t halted;
82
    uint8_t iso_started;
83 84
    AsyncURB *iso_urb;
    int iso_urb_idx;
85
    int iso_buffer_used;
86
    int inflight;
87 88
};

89 90 91
struct USBAutoFilter {
    uint32_t bus_num;
    uint32_t addr;
G
Gerd Hoffmann 已提交
92
    char     *port;
93 94 95 96
    uint32_t vendor_id;
    uint32_t product_id;
};

B
bellard 已提交
97 98
typedef struct USBHostDevice {
    USBDevice dev;
99
    int       fd;
G
Gerd Hoffmann 已提交
100
    int       hub_fd;
101
    int       hub_port;
102

103
    uint8_t   descr[8192];
104
    int       descr_len;
105
    int       closing;
106
    uint32_t  iso_urb_count;
107
    Notifier  exit;
108

G
Gerd Hoffmann 已提交
109 110
    struct endp_data ep_in[USB_MAX_ENDPOINTS];
    struct endp_data ep_out[USB_MAX_ENDPOINTS];
G
Gerd Hoffmann 已提交
111
    QLIST_HEAD(, AsyncURB) aurbs;
112 113 114 115

    /* Host side address */
    int bus_num;
    int addr;
116
    char port[MAX_PORTLEN];
117
    struct USBAutoFilter match;
G
Gerd Hoffmann 已提交
118
    int seen, errcount;
119

120
    QTAILQ_ENTRY(USBHostDevice) next;
B
bellard 已提交
121 122
} USBHostDevice;

123 124 125 126 127
static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);

static int usb_host_close(USBHostDevice *dev);
static int parse_filter(const char *spec, struct USBAutoFilter *f);
static void usb_host_auto_check(void *unused);
128 129
static int usb_host_read_file(char *line, size_t line_size,
                            const char *device_file, const char *device_name);
G
Gerd Hoffmann 已提交
130
static int usb_linux_update_endp_table(USBHostDevice *s);
131

G
Gerd Hoffmann 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144
static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p)
{
    static const int usbfs[] = {
        [USB_ENDPOINT_XFER_CONTROL] = USBDEVFS_URB_TYPE_CONTROL,
        [USB_ENDPOINT_XFER_ISOC]    = USBDEVFS_URB_TYPE_ISO,
        [USB_ENDPOINT_XFER_BULK]    = USBDEVFS_URB_TYPE_BULK,
        [USB_ENDPOINT_XFER_INT]     = USBDEVFS_URB_TYPE_INTERRUPT,
    };
    uint8_t type = usb_ep_get_type(&s->dev, p->pid, p->devep);
    assert(type < ARRAY_SIZE(usbfs));
    return usbfs[type];
}

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
static int usb_host_do_reset(USBHostDevice *dev)
{
    struct timeval s, e;
    uint32_t usecs;
    int ret;

    gettimeofday(&s, NULL);
    ret = ioctl(dev->fd, USBDEVFS_RESET);
    gettimeofday(&e, NULL);
    usecs = (e.tv_sec  - s.tv_sec) * 1000000;
    usecs += e.tv_usec - s.tv_usec;
    if (usecs > 1000000) {
        /* more than a second, something is fishy, broken usb device? */
        fprintf(stderr, "husb: device %d:%d reset took %d.%06d seconds\n",
                dev->bus_num, dev->addr, usecs / 1000000, usecs % 1000000);
    }
    return ret;
}

G
Gerd Hoffmann 已提交
164
static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
G
Gerd Hoffmann 已提交
165
{
G
Gerd Hoffmann 已提交
166 167
    struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
    assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
G
Gerd Hoffmann 已提交
168
    assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
G
Gerd Hoffmann 已提交
169
    return eps + ep - 1;
G
Gerd Hoffmann 已提交
170 171
}

G
Gerd Hoffmann 已提交
172
static int is_isoc(USBHostDevice *s, int pid, int ep)
173
{
G
Gerd Hoffmann 已提交
174
    return usb_ep_get_type(&s->dev, pid, ep) == USB_ENDPOINT_XFER_ISOC;
175 176
}

G
Gerd Hoffmann 已提交
177
static int is_valid(USBHostDevice *s, int pid, int ep)
178
{
G
Gerd Hoffmann 已提交
179
    return usb_ep_get_type(&s->dev, pid, ep) != USB_ENDPOINT_XFER_INVALID;
180 181
}

G
Gerd Hoffmann 已提交
182
static int is_halted(USBHostDevice *s, int pid, int ep)
183
{
G
Gerd Hoffmann 已提交
184
    return get_endp(s, pid, ep)->halted;
185 186
}

G
Gerd Hoffmann 已提交
187
static void clear_halt(USBHostDevice *s, int pid, int ep)
188
{
G
Gerd Hoffmann 已提交
189
    trace_usb_host_ep_clear_halt(s->bus_num, s->addr, ep);
G
Gerd Hoffmann 已提交
190
    get_endp(s, pid, ep)->halted = 0;
191 192
}

G
Gerd Hoffmann 已提交
193
static void set_halt(USBHostDevice *s, int pid, int ep)
194
{
G
Gerd Hoffmann 已提交
195 196 197 198
    if (ep != 0) {
        trace_usb_host_ep_set_halt(s->bus_num, s->addr, ep);
        get_endp(s, pid, ep)->halted = 1;
    }
199 200
}

G
Gerd Hoffmann 已提交
201
static int is_iso_started(USBHostDevice *s, int pid, int ep)
202
{
G
Gerd Hoffmann 已提交
203
    return get_endp(s, pid, ep)->iso_started;
204 205
}

G
Gerd Hoffmann 已提交
206
static void clear_iso_started(USBHostDevice *s, int pid, int ep)
207
{
G
Gerd Hoffmann 已提交
208
    trace_usb_host_ep_stop_iso(s->bus_num, s->addr, ep);
G
Gerd Hoffmann 已提交
209
    get_endp(s, pid, ep)->iso_started = 0;
210 211
}

G
Gerd Hoffmann 已提交
212
static void set_iso_started(USBHostDevice *s, int pid, int ep)
213
{
G
Gerd Hoffmann 已提交
214
    struct endp_data *e = get_endp(s, pid, ep);
G
Gerd Hoffmann 已提交
215 216

    trace_usb_host_ep_start_iso(s->bus_num, s->addr, ep);
217 218 219 220 221 222
    if (!e->iso_started) {
        e->iso_started = 1;
        e->inflight = 0;
    }
}

G
Gerd Hoffmann 已提交
223
static int change_iso_inflight(USBHostDevice *s, int pid, int ep, int value)
224
{
G
Gerd Hoffmann 已提交
225
    struct endp_data *e = get_endp(s, pid, ep);
226 227 228

    e->inflight += value;
    return e->inflight;
229 230
}

G
Gerd Hoffmann 已提交
231
static void set_iso_urb(USBHostDevice *s, int pid, int ep, AsyncURB *iso_urb)
232
{
G
Gerd Hoffmann 已提交
233
    get_endp(s, pid, ep)->iso_urb = iso_urb;
234 235
}

G
Gerd Hoffmann 已提交
236
static AsyncURB *get_iso_urb(USBHostDevice *s, int pid, int ep)
237
{
G
Gerd Hoffmann 已提交
238
    return get_endp(s, pid, ep)->iso_urb;
239 240
}

G
Gerd Hoffmann 已提交
241
static void set_iso_urb_idx(USBHostDevice *s, int pid, int ep, int i)
242
{
G
Gerd Hoffmann 已提交
243
    get_endp(s, pid, ep)->iso_urb_idx = i;
244 245
}

G
Gerd Hoffmann 已提交
246
static int get_iso_urb_idx(USBHostDevice *s, int pid, int ep)
247
{
G
Gerd Hoffmann 已提交
248
    return get_endp(s, pid, ep)->iso_urb_idx;
249 250
}

G
Gerd Hoffmann 已提交
251
static void set_iso_buffer_used(USBHostDevice *s, int pid, int ep, int i)
252
{
G
Gerd Hoffmann 已提交
253
    get_endp(s, pid, ep)->iso_buffer_used = i;
254 255
}

G
Gerd Hoffmann 已提交
256
static int get_iso_buffer_used(USBHostDevice *s, int pid, int ep)
257
{
G
Gerd Hoffmann 已提交
258
    return get_endp(s, pid, ep)->iso_buffer_used;
259 260
}

261
/*
262
 * Async URB state.
263
 * We always allocate iso packet descriptors even for bulk transfers
264
 * to simplify allocation and casts.
265
 */
266
struct AsyncURB
267 268
{
    struct usbdevfs_urb urb;
269
    struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
G
Gerd Hoffmann 已提交
270 271
    USBHostDevice *hdev;
    QLIST_ENTRY(AsyncURB) next;
272

273
    /* For regular async urbs */
274
    USBPacket     *packet;
G
Gerd Hoffmann 已提交
275
    int more; /* large transfer, more urbs follow */
276 277 278 279

    /* For buffered iso handling */
    int iso_frame_idx; /* -1 means in flight */
};
280

G
Gerd Hoffmann 已提交
281
static AsyncURB *async_alloc(USBHostDevice *s)
282
{
283
    AsyncURB *aurb = g_malloc0(sizeof(AsyncURB));
G
Gerd Hoffmann 已提交
284 285 286
    aurb->hdev = s;
    QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
    return aurb;
287 288
}

289
static void async_free(AsyncURB *aurb)
290
{
G
Gerd Hoffmann 已提交
291
    QLIST_REMOVE(aurb, next);
292
    g_free(aurb);
293
}
294

295 296 297 298 299 300
static void do_disconnect(USBHostDevice *s)
{
    usb_host_close(s);
    usb_host_auto_check(NULL);
}

301 302 303 304
static void async_complete(void *opaque)
{
    USBHostDevice *s = opaque;
    AsyncURB *aurb;
305
    int urbs = 0;
306 307

    while (1) {
308
        USBPacket *p;
309

310
        int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
311
        if (r < 0) {
312
            if (errno == EAGAIN) {
313 314 315
                if (urbs > 2) {
                    fprintf(stderr, "husb: %d iso urbs finished at once\n", urbs);
                }
316
                return;
317
            }
318 319 320 321 322
            if (errno == ENODEV) {
                if (!s->closing) {
                    trace_usb_host_disconnect(s->bus_num, s->addr);
                    do_disconnect(s);
                }
323 324 325
                return;
            }

G
Gerd Hoffmann 已提交
326
            perror("USBDEVFS_REAPURBNDELAY");
327
            return;
328
        }
329

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

333 334 335
        /* If this is a buffered iso urb mark it as complete and don't do
           anything else (it is handled further in usb_host_handle_iso_data) */
        if (aurb->iso_frame_idx == -1) {
336
            int inflight;
G
Gerd Hoffmann 已提交
337 338 339
            int pid = (aurb->urb.endpoint & USB_DIR_IN) ?
                USB_TOKEN_IN : USB_TOKEN_OUT;
            int ep = aurb->urb.endpoint & 0xf;
340
            if (aurb->urb.status == -EPIPE) {
G
Gerd Hoffmann 已提交
341
                set_halt(s, pid, ep);
342 343
            }
            aurb->iso_frame_idx = 0;
344
            urbs++;
G
Gerd Hoffmann 已提交
345 346
            inflight = change_iso_inflight(s, pid, ep, -1);
            if (inflight == 0 && is_iso_started(s, pid, ep)) {
347 348
                fprintf(stderr, "husb: out of buffers for iso stream\n");
            }
349 350 351 352
            continue;
        }

        p = aurb->packet;
G
Gerd Hoffmann 已提交
353 354
        trace_usb_host_urb_complete(s->bus_num, s->addr, aurb, aurb->urb.status,
                                    aurb->urb.actual_length, aurb->more);
355

356
        if (p) {
357 358
            switch (aurb->urb.status) {
            case 0:
G
Gerd Hoffmann 已提交
359
                p->result += aurb->urb.actual_length;
360 361 362
                break;

            case -EPIPE:
G
Gerd Hoffmann 已提交
363
                set_halt(s, p->pid, p->devep);
G
Gerd Hoffmann 已提交
364
                p->result = USB_RET_STALL;
365
                break;
366

367
            default:
G
Gerd Hoffmann 已提交
368
                p->result = USB_RET_NAK;
369 370 371
                break;
            }

372
            if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
G
Gerd Hoffmann 已提交
373
                trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
374
                usb_generic_async_ctrl_complete(&s->dev, p);
G
Gerd Hoffmann 已提交
375
            } else if (!aurb->more) {
G
Gerd Hoffmann 已提交
376
                trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
377 378
                usb_packet_complete(&s->dev, p);
            }
379
        }
380 381

        async_free(aurb);
382 383 384
    }
}

385
static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
386
{
387
    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
388
    AsyncURB *aurb;
389

390 391 392 393
    QLIST_FOREACH(aurb, &s->aurbs, next) {
        if (p != aurb->packet) {
            continue;
        }
394

395
        DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
396

397 398 399 400 401 402 403
        /* Mark it as dead (see async_complete above) */
        aurb->packet = NULL;

        int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
        if (r < 0) {
            DPRINTF("husb: async. discard urb failed errno %d\n", errno);
        }
404 405 406
    }
}

407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
static int usb_host_open_device(int bus, int addr)
{
    const char *usbfs = NULL;
    char filename[32];
    struct stat st;
    int fd, rc;

    rc = stat("/dev/bus/usb", &st);
    if (rc == 0 && S_ISDIR(st.st_mode)) {
        /* udev-created device nodes available */
        usbfs = "/dev/bus/usb";
    } else {
        /* fallback: usbfs mounted below /proc */
        usbfs = "/proc/bus/usb";
    }

    snprintf(filename, sizeof(filename), "%s/%03d/%03d",
             usbfs, bus, addr);
    fd = open(filename, O_RDWR | O_NONBLOCK);
    if (fd < 0) {
        fprintf(stderr, "husb: open %s: %s\n", filename, strerror(errno));
    }
    return fd;
}

G
Gerd Hoffmann 已提交
432 433 434 435
static int usb_host_claim_port(USBHostDevice *s)
{
#ifdef USBDEVFS_CLAIM_PORT
    char *h, hub_name[64], line[1024];
436
    int hub_addr, ret;
G
Gerd Hoffmann 已提交
437 438 439 440 441 442 443

    snprintf(hub_name, sizeof(hub_name), "%d-%s",
             s->match.bus_num, s->match.port);

    /* try strip off last ".$portnr" to get hub */
    h = strrchr(hub_name, '.');
    if (h != NULL) {
444
        s->hub_port = atoi(h+1);
G
Gerd Hoffmann 已提交
445 446 447 448 449
        *h = '\0';
    } else {
        /* no dot in there -> it is the root hub */
        snprintf(hub_name, sizeof(hub_name), "usb%d",
                 s->match.bus_num);
450
        s->hub_port = atoi(s->match.port);
G
Gerd Hoffmann 已提交
451 452 453 454 455 456 457 458 459 460
    }

    if (!usb_host_read_file(line, sizeof(line), "devnum",
                            hub_name)) {
        return -1;
    }
    if (sscanf(line, "%d", &hub_addr) != 1) {
        return -1;
    }

461
    s->hub_fd = usb_host_open_device(s->match.bus_num, hub_addr);
G
Gerd Hoffmann 已提交
462 463 464 465
    if (s->hub_fd < 0) {
        return -1;
    }

466
    ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &s->hub_port);
G
Gerd Hoffmann 已提交
467 468 469 470 471 472
    if (ret < 0) {
        close(s->hub_fd);
        s->hub_fd = -1;
        return -1;
    }

473
    trace_usb_host_claim_port(s->match.bus_num, hub_addr, s->hub_port);
G
Gerd Hoffmann 已提交
474 475 476 477 478 479
    return 0;
#else
    return -1;
#endif
}

480 481 482 483 484 485 486 487 488 489 490 491
static void usb_host_release_port(USBHostDevice *s)
{
    if (s->hub_fd == -1) {
        return;
    }
#ifdef USBDEVFS_RELEASE_PORT
    ioctl(s->hub_fd, USBDEVFS_RELEASE_PORT, &s->hub_port);
#endif
    close(s->hub_fd);
    s->hub_fd = -1;
}

G
Gerd Hoffmann 已提交
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
{
    /* earlier Linux 2.4 do not support that */
#ifdef USBDEVFS_DISCONNECT
    struct usbdevfs_ioctl ctrl;
    int ret, interface;

    for (interface = 0; interface < nb_interfaces; interface++) {
        ctrl.ioctl_code = USBDEVFS_DISCONNECT;
        ctrl.ifno = interface;
        ctrl.data = 0;
        ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
        if (ret < 0 && errno != ENODATA) {
            perror("USBDEVFS_DISCONNECT");
            return -1;
        }
    }
#endif
    return 0;
}

513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
static int usb_linux_get_num_interfaces(USBHostDevice *s)
{
    char device_name[64], line[1024];
    int num_interfaces = 0;

    sprintf(device_name, "%d-%s", s->bus_num, s->port);
    if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces",
                            device_name)) {
        return -1;
    }
    if (sscanf(line, "%d", &num_interfaces) != 1) {
        return -1;
    }
    return num_interfaces;
}

529
static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
530
{
531
    const char *op = NULL;
532
    int dev_descr_len, config_descr_len;
533
    int interface, nb_interfaces;
534 535
    int ret, i;

536 537 538 539
    for (i = 0; i < USB_MAX_INTERFACES; i++) {
        dev->dev.altsetting[i] = 0;
    }

540
    if (configuration == 0) { /* address state - ignore */
541 542
        dev->dev.ninterfaces   = 0;
        dev->dev.configuration = 0;
543
        return 1;
544
    }
545

M
malc 已提交
546
    DPRINTF("husb: claiming interfaces. config %d\n", configuration);
547

548 549
    i = 0;
    dev_descr_len = dev->descr[0];
550
    if (dev_descr_len > dev->descr_len) {
551 552
        fprintf(stderr, "husb: update iface failed. descr too short\n");
        return 0;
553
    }
554 555 556

    i += dev_descr_len;
    while (i < dev->descr_len) {
557 558
        DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
                i, dev->descr_len,
559
               dev->descr[i], dev->descr[i+1]);
560

561 562 563 564 565 566
        if (dev->descr[i+1] != USB_DT_CONFIG) {
            i += dev->descr[i];
            continue;
        }
        config_descr_len = dev->descr[i];

G
Gerd Hoffmann 已提交
567
        DPRINTF("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
568

569
        if (configuration == dev->descr[i + 5]) {
570
            configuration = dev->descr[i + 5];
571
            break;
572
        }
573 574 575 576 577

        i += config_descr_len;
    }

    if (i >= dev->descr_len) {
578 579
        fprintf(stderr,
                "husb: update iface failed. no matching configuration\n");
580
        return 0;
581 582 583
    }
    nb_interfaces = dev->descr[i + 4];

G
Gerd Hoffmann 已提交
584 585
    if (usb_host_disconnect_ifaces(dev, nb_interfaces) < 0) {
        goto fail;
586 587 588 589
    }

    /* XXX: only grab if all interfaces are free */
    for (interface = 0; interface < nb_interfaces; interface++) {
590
        op = "USBDEVFS_CLAIMINTERFACE";
591 592
        ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
        if (ret < 0) {
593
            goto fail;
594 595 596
        }
    }

G
Gerd Hoffmann 已提交
597 598
    trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
                                    nb_interfaces, configuration);
599

600 601
    dev->dev.ninterfaces   = nb_interfaces;
    dev->dev.configuration = configuration;
602
    return 1;
603 604 605 606 607 608 609

fail:
    if (errno == ENODEV) {
        do_disconnect(dev);
    }
    perror(op);
    return 0;
610 611 612 613 614 615
}

static int usb_host_release_interfaces(USBHostDevice *s)
{
    int ret, i;

G
Gerd Hoffmann 已提交
616
    trace_usb_host_release_interfaces(s->bus_num, s->addr);
617

618
    for (i = 0; i < s->dev.ninterfaces; i++) {
619 620
        ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
        if (ret < 0) {
G
Gerd Hoffmann 已提交
621
            perror("USBDEVFS_RELEASEINTERFACE");
622 623 624
            return 0;
        }
    }
625 626 627
    return 1;
}

B
bellard 已提交
628
static void usb_host_handle_reset(USBDevice *dev)
B
bellard 已提交
629
{
630
    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
631

G
Gerd Hoffmann 已提交
632
    trace_usb_host_reset(s->bus_num, s->addr);
633

634
    usb_host_do_reset(s);;
635

636
    usb_host_claim_interfaces(s, 0);
G
Gerd Hoffmann 已提交
637
    usb_linux_update_endp_table(s);
638
}
B
bellard 已提交
639

B
bellard 已提交
640 641 642 643
static void usb_host_handle_destroy(USBDevice *dev)
{
    USBHostDevice *s = (USBHostDevice *)dev;

644
    usb_host_release_port(s);
645 646
    usb_host_close(s);
    QTAILQ_REMOVE(&hostdevs, s, next);
647
    qemu_remove_exit_notifier(&s->exit);
B
bellard 已提交
648 649
}

650 651 652
/* iso data is special, we need to keep enough urbs in flight to make sure
   that the controller never runs out of them, otherwise the device will
   likely suffer a buffer underrun / overrun. */
G
Gerd Hoffmann 已提交
653
static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
654 655
{
    AsyncURB *aurb;
656
    int i, j, len = usb_ep_get_max_packet_size(&s->dev, pid, ep);
657

658
    aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
659
    for (i = 0; i < s->iso_urb_count; i++) {
660 661
        aurb[i].urb.endpoint      = ep;
        aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
662
        aurb[i].urb.buffer        = g_malloc(aurb[i].urb.buffer_length);
663 664 665 666 667
        aurb[i].urb.type          = USBDEVFS_URB_TYPE_ISO;
        aurb[i].urb.flags         = USBDEVFS_URB_ISO_ASAP;
        aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
        for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
            aurb[i].urb.iso_frame_desc[j].length = len;
G
Gerd Hoffmann 已提交
668
        if (pid == USB_TOKEN_IN) {
669 670 671 672 673
            aurb[i].urb.endpoint |= 0x80;
            /* Mark as fully consumed (idle) */
            aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
        }
    }
G
Gerd Hoffmann 已提交
674
    set_iso_urb(s, pid, ep, aurb);
675 676 677 678

    return aurb;
}

G
Gerd Hoffmann 已提交
679
static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep)
680 681 682 683
{
    AsyncURB *aurb;
    int i, ret, killed = 0, free = 1;

G
Gerd Hoffmann 已提交
684
    aurb = get_iso_urb(s, pid, ep);
685 686 687 688
    if (!aurb) {
        return;
    }

689
    for (i = 0; i < s->iso_urb_count; i++) {
690 691 692 693
        /* in flight? */
        if (aurb[i].iso_frame_idx == -1) {
            ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
            if (ret < 0) {
G
Gerd Hoffmann 已提交
694
                perror("USBDEVFS_DISCARDURB");
695 696 697 698 699 700 701 702 703 704 705 706
                free = 0;
                continue;
            }
            killed++;
        }
    }

    /* Make sure any urbs we've killed are reaped before we free them */
    if (killed) {
        async_complete(s);
    }

707
    for (i = 0; i < s->iso_urb_count; i++) {
708
        g_free(aurb[i].urb.buffer);
709 710 711
    }

    if (free)
712
        g_free(aurb);
713 714
    else
        printf("husb: leaking iso urbs because of discard failure\n");
G
Gerd Hoffmann 已提交
715 716 717
    set_iso_urb(s, pid, ep, NULL);
    set_iso_urb_idx(s, pid, ep, 0);
    clear_iso_started(s, pid, ep);
718 719 720 721 722 723 724 725 726 727 728 729
}

static int urb_status_to_usb_ret(int status)
{
    switch (status) {
    case -EPIPE:
        return USB_RET_STALL;
    default:
        return USB_RET_NAK;
    }
}

730
static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
731 732
{
    AsyncURB *aurb;
733
    int i, j, ret, max_packet_size, offset, len = 0;
G
Gerd Hoffmann 已提交
734
    uint8_t *buf;
735

736
    max_packet_size = usb_ep_get_max_packet_size(&s->dev, p->pid, p->devep);
737 738
    if (max_packet_size == 0)
        return USB_RET_NAK;
739

G
Gerd Hoffmann 已提交
740
    aurb = get_iso_urb(s, p->pid, p->devep);
741
    if (!aurb) {
G
Gerd Hoffmann 已提交
742
        aurb = usb_host_alloc_iso(s, p->pid, p->devep);
743 744
    }

G
Gerd Hoffmann 已提交
745
    i = get_iso_urb_idx(s, p->pid, p->devep);
746 747
    j = aurb[i].iso_frame_idx;
    if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
748 749 750 751 752 753 754 755 756 757 758
        if (in) {
            /* Check urb status  */
            if (aurb[i].urb.status) {
                len = urb_status_to_usb_ret(aurb[i].urb.status);
                /* Move to the next urb */
                aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
            /* Check frame status */
            } else if (aurb[i].urb.iso_frame_desc[j].status) {
                len = urb_status_to_usb_ret(
                                        aurb[i].urb.iso_frame_desc[j].status);
            /* Check the frame fits */
G
Gerd Hoffmann 已提交
759 760
            } else if (aurb[i].urb.iso_frame_desc[j].actual_length
                       > p->iov.size) {
761 762 763 764 765
                printf("husb: received iso data is larger then packet\n");
                len = USB_RET_NAK;
            /* All good copy data over */
            } else {
                len = aurb[i].urb.iso_frame_desc[j].actual_length;
G
Gerd Hoffmann 已提交
766 767 768
                buf  = aurb[i].urb.buffer +
                    j * aurb[i].urb.iso_frame_desc[0].length;
                usb_packet_copy(p, buf, len);
769
            }
770
        } else {
G
Gerd Hoffmann 已提交
771
            len = p->iov.size;
G
Gerd Hoffmann 已提交
772
            offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->devep);
773 774 775 776 777 778 779 780

            /* Check the frame fits */
            if (len > max_packet_size) {
                printf("husb: send iso data is larger then max packet size\n");
                return USB_RET_NAK;
            }

            /* All good copy data over */
G
Gerd Hoffmann 已提交
781
            usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
782 783
            aurb[i].urb.iso_frame_desc[j].length = len;
            offset += len;
G
Gerd Hoffmann 已提交
784
            set_iso_buffer_used(s, p->pid, p->devep, offset);
785 786

            /* Start the stream once we have buffered enough data */
G
Gerd Hoffmann 已提交
787 788
            if (!is_iso_started(s, p->pid, p->devep) && i == 1 && j == 8) {
                set_iso_started(s, p->pid, p->devep);
789
            }
790 791 792
        }
        aurb[i].iso_frame_idx++;
        if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
793
            i = (i + 1) % s->iso_urb_count;
G
Gerd Hoffmann 已提交
794
            set_iso_urb_idx(s, p->pid, p->devep, i);
795
        }
796 797
    } else {
        if (in) {
G
Gerd Hoffmann 已提交
798
            set_iso_started(s, p->pid, p->devep);
799 800 801
        } else {
            DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
        }
802 803
    }

G
Gerd Hoffmann 已提交
804
    if (is_iso_started(s, p->pid, p->devep)) {
805
        /* (Re)-submit all fully consumed / filled urbs */
806
        for (i = 0; i < s->iso_urb_count; i++) {
807 808 809
            if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
                ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
                if (ret < 0) {
G
Gerd Hoffmann 已提交
810
                    perror("USBDEVFS_SUBMITURB");
811 812 813 814
                    if (!in || len == 0) {
                        switch(errno) {
                        case ETIMEDOUT:
                            len = USB_RET_NAK;
815
                            break;
816 817 818 819
                        case EPIPE:
                        default:
                            len = USB_RET_STALL;
                        }
820
                    }
821
                    break;
822
                }
823
                aurb[i].iso_frame_idx = -1;
G
Gerd Hoffmann 已提交
824
                change_iso_inflight(s, p->pid, p->devep, 1);
825 826 827 828 829 830 831
            }
        }
    }

    return len;
}

832
static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
B
bellard 已提交
833
{
834
    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
835
    struct usbdevfs_urb *urb;
836
    AsyncURB *aurb;
G
Gerd Hoffmann 已提交
837
    int ret, rem, prem, v;
G
Gerd Hoffmann 已提交
838
    uint8_t *pbuf;
839
    uint8_t ep;
840

G
Gerd Hoffmann 已提交
841 842 843 844
    trace_usb_host_req_data(s->bus_num, s->addr,
                            p->pid == USB_TOKEN_IN,
                            p->devep, p->iov.size);

G
Gerd Hoffmann 已提交
845
    if (!is_valid(s, p->pid, p->devep)) {
G
Gerd Hoffmann 已提交
846
        trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
847 848 849
        return USB_RET_NAK;
    }

850
    if (p->pid == USB_TOKEN_IN) {
851
        ep = p->devep | 0x80;
852
    } else {
853
        ep = p->devep;
854
    }
855

G
Gerd Hoffmann 已提交
856
    if (is_halted(s, p->pid, p->devep)) {
G
Gerd Hoffmann 已提交
857 858
        unsigned int arg = ep;
        ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
859
        if (ret < 0) {
G
Gerd Hoffmann 已提交
860 861
            perror("USBDEVFS_CLEAR_HALT");
            trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
B
bellard 已提交
862 863
            return USB_RET_NAK;
        }
G
Gerd Hoffmann 已提交
864
        clear_halt(s, p->pid, p->devep);
865 866
    }

G
Gerd Hoffmann 已提交
867
    if (is_isoc(s, p->pid, p->devep)) {
868 869
        return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
    }
870

G
Gerd Hoffmann 已提交
871 872 873 874
    v = 0;
    prem = p->iov.iov[v].iov_len;
    pbuf = p->iov.iov[v].iov_base;
    rem = p->iov.size;
G
Gerd Hoffmann 已提交
875
    while (rem) {
G
Gerd Hoffmann 已提交
876 877 878 879 880 881 882
        if (prem == 0) {
            v++;
            assert(v < p->iov.niov);
            prem = p->iov.iov[v].iov_len;
            pbuf = p->iov.iov[v].iov_base;
            assert(prem <= rem);
        }
G
Gerd Hoffmann 已提交
883 884 885 886 887
        aurb = async_alloc(s);
        aurb->packet = p;

        urb = &aurb->urb;
        urb->endpoint      = ep;
G
Gerd Hoffmann 已提交
888
        urb->type          = usb_host_usbfs_type(s, p);
G
Gerd Hoffmann 已提交
889 890
        urb->usercontext   = s;
        urb->buffer        = pbuf;
G
Gerd Hoffmann 已提交
891
        urb->buffer_length = prem;
G
Gerd Hoffmann 已提交
892

G
Gerd Hoffmann 已提交
893
        if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) {
G
Gerd Hoffmann 已提交
894 895 896
            urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
        }
        pbuf += urb->buffer_length;
G
Gerd Hoffmann 已提交
897
        prem -= urb->buffer_length;
G
Gerd Hoffmann 已提交
898
        rem  -= urb->buffer_length;
G
Gerd Hoffmann 已提交
899 900 901
        if (rem) {
            aurb->more         = 1;
        }
902

G
Gerd Hoffmann 已提交
903 904
        trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
                                  urb->buffer_length, aurb->more);
G
Gerd Hoffmann 已提交
905
        ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
906

G
Gerd Hoffmann 已提交
907 908
        DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
                urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
909

G
Gerd Hoffmann 已提交
910
        if (ret < 0) {
G
Gerd Hoffmann 已提交
911
            perror("USBDEVFS_SUBMITURB");
G
Gerd Hoffmann 已提交
912
            async_free(aurb);
913

G
Gerd Hoffmann 已提交
914 915
            switch(errno) {
            case ETIMEDOUT:
G
Gerd Hoffmann 已提交
916
                trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
G
Gerd Hoffmann 已提交
917 918 919
                return USB_RET_NAK;
            case EPIPE:
            default:
G
Gerd Hoffmann 已提交
920
                trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_STALL);
G
Gerd Hoffmann 已提交
921 922
                return USB_RET_STALL;
            }
923 924
        }
    }
925

926 927 928
    return USB_RET_ASYNC;
}

929 930
static int ctrl_error(void)
{
931
    if (errno == ETIMEDOUT) {
932
        return USB_RET_NAK;
933
    } else {
934
        return USB_RET_STALL;
935
    }
936 937 938 939
}

static int usb_host_set_address(USBHostDevice *s, int addr)
{
G
Gerd Hoffmann 已提交
940
    trace_usb_host_set_address(s->bus_num, s->addr, addr);
941 942 943 944 945 946
    s->dev.addr = addr;
    return 0;
}

static int usb_host_set_config(USBHostDevice *s, int config)
{
947 948
    int ret, first = 1;

G
Gerd Hoffmann 已提交
949 950
    trace_usb_host_set_config(s->bus_num, s->addr, config);

951 952
    usb_host_release_interfaces(s);

953 954
again:
    ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
955

M
malc 已提交
956
    DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
957

958 959 960 961 962 963 964 965 966 967 968
    if (ret < 0 && errno == EBUSY && first) {
        /* happens if usb device is in use by host drivers */
        int count = usb_linux_get_num_interfaces(s);
        if (count > 0) {
            DPRINTF("husb: busy -> disconnecting %d interfaces\n", count);
            usb_host_disconnect_ifaces(s, count);
            first = 0;
            goto again;
        }
    }

969
    if (ret < 0) {
970
        return ctrl_error();
971
    }
972
    usb_host_claim_interfaces(s, config);
973
    usb_linux_update_endp_table(s);
974 975 976 977 978 979
    return 0;
}

static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
{
    struct usbdevfs_setinterface si;
980 981
    int i, ret;

G
Gerd Hoffmann 已提交
982 983
    trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);

G
Gerd Hoffmann 已提交
984
    for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
G
Gerd Hoffmann 已提交
985 986 987 988 989
        if (is_isoc(s, USB_TOKEN_IN, i)) {
            usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
        }
        if (is_isoc(s, USB_TOKEN_OUT, i)) {
            usb_host_stop_n_free_iso(s, USB_TOKEN_OUT, i);
990 991
        }
    }
992

993 994 995 996
    if (iface >= USB_MAX_INTERFACES) {
        return USB_RET_STALL;
    }

997 998 999 1000
    si.interface  = iface;
    si.altsetting = alt;
    ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);

1001 1002 1003 1004 1005 1006
    DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
            iface, alt, ret, errno);

    if (ret < 0) {
        return ctrl_error();
    }
1007 1008

    s->dev.altsetting[iface] = alt;
1009 1010 1011 1012
    usb_linux_update_endp_table(s);
    return 0;
}

1013 1014
static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
               int request, int value, int index, int length, uint8_t *data)
1015
{
1016
    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1017 1018
    struct usbdevfs_urb *urb;
    AsyncURB *aurb;
1019
    int ret;
1020

1021
    /*
1022 1023 1024 1025
     * Process certain standard device requests.
     * These are infrequent and are processed synchronously.
     */

1026
    /* Note request is (bRequestType << 8) | bRequest */
G
Gerd Hoffmann 已提交
1027
    trace_usb_host_req_control(s->bus_num, s->addr, request, value, index);
1028

1029 1030 1031
    switch (request) {
    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
        return usb_host_set_address(s, value);
1032

1033 1034
    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
        return usb_host_set_config(s, value & 0xff);
1035

1036
    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
1037
        return usb_host_set_interface(s, index, value);
1038
    }
1039 1040 1041

    /* The rest are asynchronous */

1042 1043 1044
    if (length > sizeof(dev->data_buf)) {
        fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
                length, sizeof(dev->data_buf));
1045
        return USB_RET_STALL;
J
Jim Paris 已提交
1046 1047
    }

G
Gerd Hoffmann 已提交
1048
    aurb = async_alloc(s);
1049 1050
    aurb->packet = p;

1051
    /*
1052 1053
     * Setup ctrl transfer.
     *
1054
     * s->ctrl is laid out such that data buffer immediately follows
1055
     * 'req' struct which is exactly what usbdevfs expects.
1056
     */
1057 1058 1059 1060 1061
    urb = &aurb->urb;

    urb->type     = USBDEVFS_URB_TYPE_CONTROL;
    urb->endpoint = p->devep;

1062 1063
    urb->buffer        = &dev->setup_buf;
    urb->buffer_length = length + 8;
1064 1065 1066

    urb->usercontext = s;

G
Gerd Hoffmann 已提交
1067 1068
    trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
                              urb->buffer_length, aurb->more);
1069 1070
    ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);

M
malc 已提交
1071
    DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
1072 1073

    if (ret < 0) {
M
malc 已提交
1074
        DPRINTF("husb: submit failed. errno %d\n", errno);
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
        async_free(aurb);

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

    return USB_RET_ASYNC;
}

1089 1090 1091
static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
    uint8_t configuration, uint8_t interface)
{
1092 1093
    char device_name[64], line[1024];
    int alt_setting;
1094

1095 1096
    sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
            (int)configuration, (int)interface);
1097

1098 1099 1100 1101 1102 1103
    if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
                            device_name)) {
        /* Assume alt 0 on error */
        return 0;
    }
    if (sscanf(line, "%d", &alt_setting) != 1) {
1104 1105 1106 1107 1108 1109
        /* Assume alt 0 on error */
        return 0;
    }
    return alt_setting;
}

1110 1111 1112 1113
/* returns 1 on problem encountered or 0 for success */
static int usb_linux_update_endp_table(USBHostDevice *s)
{
    uint8_t *descriptors;
1114
    uint8_t devep, type, alt_interface;
1115
    uint16_t raw;
G
Gerd Hoffmann 已提交
1116 1117
    int interface, length, i, ep, pid;
    struct endp_data *epd;
1118

G
Gerd Hoffmann 已提交
1119
    usb_ep_init(&s->dev);
1120

1121
    if (s->dev.configuration == 0) {
1122 1123 1124
        /* not configured yet -- leave all endpoints disabled */
        return 0;
    }
1125

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

    while (i < length) {
1133 1134 1135
        if (descriptors[i + 1] != USB_DT_CONFIG) {
            fprintf(stderr, "invalid descriptor data\n");
            return 1;
1136 1137
        } else if (descriptors[i + 5] != s->dev.configuration) {
            DPRINTF("not requested configuration %d\n", s->dev.configuration);
1138 1139 1140 1141 1142
            i += (descriptors[i + 3] << 8) + descriptors[i + 2];
            continue;
        }
        i += descriptors[i];

1143 1144 1145 1146 1147 1148 1149 1150
        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];
1151
        alt_interface = usb_linux_get_alt_setting(s, s->dev.configuration,
1152
                                                  interface);
1153 1154 1155 1156 1157 1158 1159 1160 1161

        /* 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 */
1162
        while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
1163
            i += descriptors[i];
1164
        }
1165 1166 1167 1168 1169

        if (i >= length)
            break;

        while (i < length) {
1170
            if (descriptors[i + 1] != USB_DT_ENDPOINT) {
1171
                break;
1172
            }
1173 1174

            devep = descriptors[i + 2];
G
Gerd Hoffmann 已提交
1175 1176 1177
            pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
            ep = devep & 0xf;
            if (ep == 0) {
H
Hans de Goede 已提交
1178 1179 1180 1181
                fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
                return 1;
            }

G
Gerd Hoffmann 已提交
1182
            type = descriptors[i + 3] & 0x3;
1183 1184
            raw = descriptors[i + 4] + (descriptors[i + 5] << 8);
            usb_ep_set_max_packet_size(&s->dev, pid, ep, raw);
G
Gerd Hoffmann 已提交
1185 1186 1187
            assert(usb_ep_get_type(&s->dev, pid, ep) ==
                   USB_ENDPOINT_XFER_INVALID);
            usb_ep_set_type(&s->dev, pid, ep, type);
G
Gerd Hoffmann 已提交
1188
            usb_ep_set_ifnum(&s->dev, pid, ep, interface);
G
Gerd Hoffmann 已提交
1189

G
Gerd Hoffmann 已提交
1190 1191
            epd = get_endp(s, pid, ep);
            epd->halted = 0;
1192 1193 1194 1195

            i += descriptors[i];
        }
    }
G
Gerd Hoffmann 已提交
1196 1197 1198
#ifdef DEBUG
    usb_ep_dump(&s->dev);
#endif
1199 1200 1201
    return 0;
}

1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
/*
 * Check if we can safely redirect a usb2 device to a usb1 virtual controller,
 * this function assumes this is safe, if:
 * 1) There are no isoc endpoints
 * 2) There are no interrupt endpoints with a max_packet_size > 64
 * Note bulk endpoints with a max_packet_size > 64 in theory also are not
 * usb1 compatible, but in practice this seems to work fine.
 */
static int usb_linux_full_speed_compat(USBHostDevice *dev)
{
    int i, packet_size;

    /*
     * usb_linux_update_endp_table only registers info about ep in the current
     * interface altsettings, so we need to parse the descriptors again.
     */
    for (i = 0; (i + 5) < dev->descr_len; i += dev->descr[i]) {
        if (dev->descr[i + 1] == USB_DT_ENDPOINT) {
            switch (dev->descr[i + 3] & 0x3) {
            case 0x00: /* CONTROL */
                break;
            case 0x01: /* ISO */
                return 0;
            case 0x02: /* BULK */
                break;
            case 0x03: /* INTERRUPT */
                packet_size = dev->descr[i + 4] + (dev->descr[i + 5] << 8);
                if (packet_size > 64)
                    return 0;
                break;
            }
        }
    }
    return 1;
}

1238
static int usb_host_open(USBHostDevice *dev, int bus_num,
G
Gerd Hoffmann 已提交
1239 1240
                         int addr, const char *port,
                         const char *prod_name, int speed)
B
bellard 已提交
1241
{
1242
    int fd = -1, ret;
1243

G
Gerd Hoffmann 已提交
1244 1245
    trace_usb_host_open_started(bus_num, addr);

1246
    if (dev->fd != -1) {
1247
        goto fail;
1248
    }
1249

1250
    fd = usb_host_open_device(bus_num, addr);
B
bellard 已提交
1251
    if (fd < 0) {
1252
        goto fail;
B
bellard 已提交
1253
    }
M
malc 已提交
1254
    DPRINTF("husb: opened %s\n", buf);
B
bellard 已提交
1255

1256 1257
    dev->bus_num = bus_num;
    dev->addr = addr;
1258
    strcpy(dev->port, port);
1259
    dev->fd = fd;
1260

1261 1262 1263
    /* read the device description */
    dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
    if (dev->descr_len <= 0) {
1264
        perror("husb: reading device data failed");
B
bellard 已提交
1265 1266
        goto fail;
    }
1267

1268
#ifdef DEBUG
B
bellard 已提交
1269
    {
1270 1271
        int x;
        printf("=== begin dumping device descriptor data ===\n");
1272
        for (x = 0; x < dev->descr_len; x++) {
1273
            printf("%02x ", dev->descr[x]);
1274
        }
1275
        printf("\n=== end dumping device descriptor data ===\n");
B
bellard 已提交
1276
    }
B
bellard 已提交
1277 1278
#endif

1279

1280 1281
    /* start unconfigured -- we'll wait for the guest to set a configuration */
    if (!usb_host_claim_interfaces(dev, 0)) {
1282
        goto fail;
1283
    }
B
bellard 已提交
1284

1285
    ret = usb_linux_update_endp_table(dev);
1286
    if (ret) {
B
bellard 已提交
1287
        goto fail;
1288
    }
1289

1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
    if (speed == -1) {
        struct usbdevfs_connectinfo ci;

        ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
        if (ret < 0) {
            perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
            goto fail;
        }

        if (ci.slow) {
            speed = USB_SPEED_LOW;
        } else {
            speed = USB_SPEED_HIGH;
        }
1304
    }
1305
    dev->dev.speed = speed;
H
Hans de Goede 已提交
1306
    dev->dev.speedmask = (1 << speed);
1307 1308 1309
    if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
        dev->dev.speedmask |= USB_SPEED_MASK_FULL;
    }
1310

G
Gerd Hoffmann 已提交
1311
    trace_usb_host_open_success(bus_num, addr);
B
bellard 已提交
1312

1313
    if (!prod_name || prod_name[0] == '\0') {
1314
        snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
1315
                 "host:%d.%d", bus_num, addr);
1316
    } else {
1317
        pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
1318
                prod_name);
1319
    }
1320

1321 1322 1323 1324 1325
    ret = usb_device_attach(&dev->dev);
    if (ret) {
        goto fail;
    }

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

1329
    return 0;
1330

1331
fail:
G
Gerd Hoffmann 已提交
1332
    trace_usb_host_open_failure(bus_num, addr);
1333 1334 1335
    if (dev->fd != -1) {
        close(dev->fd);
        dev->fd = -1;
1336
    }
1337 1338 1339 1340 1341
    return -1;
}

static int usb_host_close(USBHostDevice *dev)
{
1342 1343
    int i;

G
Gerd Hoffmann 已提交
1344
    if (dev->fd == -1) {
1345
        return -1;
1346
    }
1347

G
Gerd Hoffmann 已提交
1348 1349
    trace_usb_host_close(dev->bus_num, dev->addr);

1350 1351
    qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
    dev->closing = 1;
G
Gerd Hoffmann 已提交
1352
    for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
G
Gerd Hoffmann 已提交
1353 1354 1355 1356 1357
        if (is_isoc(dev, USB_TOKEN_IN, i)) {
            usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
        }
        if (is_isoc(dev, USB_TOKEN_OUT, i)) {
            usb_host_stop_n_free_iso(dev, USB_TOKEN_OUT, i);
1358 1359
        }
    }
1360 1361
    async_complete(dev);
    dev->closing = 0;
G
Gerd Hoffmann 已提交
1362 1363 1364
    if (dev->dev.attached) {
        usb_device_detach(&dev->dev);
    }
1365
    usb_host_do_reset(dev);
1366 1367 1368 1369 1370
    close(dev->fd);
    dev->fd = -1;
    return 0;
}

1371
static void usb_host_exit_notifier(struct Notifier *n, void *data)
1372 1373 1374
{
    USBHostDevice *s = container_of(n, USBHostDevice, exit);

1375
    usb_host_release_port(s);
1376
    if (s->fd != -1) {
1377
        usb_host_do_reset(s);;
1378 1379 1380
    }
}

1381 1382 1383 1384 1385 1386
static int usb_host_initfn(USBDevice *dev)
{
    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);

    dev->auto_attach = 0;
    s->fd = -1;
G
Gerd Hoffmann 已提交
1387 1388
    s->hub_fd = -1;

1389
    QTAILQ_INSERT_TAIL(&hostdevs, s, next);
1390 1391
    s->exit.notify = usb_host_exit_notifier;
    qemu_add_exit_notifier(&s->exit);
1392
    usb_host_auto_check(NULL);
G
Gerd Hoffmann 已提交
1393 1394

    if (s->match.bus_num != 0 && s->match.port != NULL) {
G
Gerd Hoffmann 已提交
1395
        usb_host_claim_port(s);
G
Gerd Hoffmann 已提交
1396
    }
1397
    return 0;
B
bellard 已提交
1398
}
B
bellard 已提交
1399

G
Gerd Hoffmann 已提交
1400 1401 1402 1403 1404
static const VMStateDescription vmstate_usb_host = {
    .name = "usb-host",
    .unmigratable = 1,
};

1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424
static void usb_host_class_initfn(ObjectClass *klass, void *data)
{
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);

    uc->init           = usb_host_initfn;
    uc->product_desc   = "USB Host Device";
    uc->handle_packet  = usb_generic_handle_packet;
    uc->cancel_packet  = usb_host_async_cancel;
    uc->handle_data    = usb_host_handle_data;
    uc->handle_control = usb_host_handle_control;
    uc->handle_reset   = usb_host_handle_reset;
    uc->handle_destroy = usb_host_handle_destroy;
}

static struct DeviceInfo usb_host_dev_info = {
    .name      = "usb-host",
    .size      = sizeof(USBHostDevice),
    .vmsd      = &vmstate_usb_host,
    .class_init= usb_host_class_initfn,
    .props     = (Property[]) {
1425 1426
        DEFINE_PROP_UINT32("hostbus",  USBHostDevice, match.bus_num,    0),
        DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr,       0),
G
Gerd Hoffmann 已提交
1427
        DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
1428 1429
        DEFINE_PROP_HEX32("vendorid",  USBHostDevice, match.vendor_id,  0),
        DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
1430
        DEFINE_PROP_UINT32("isobufs",  USBHostDevice, iso_urb_count,    4),
1431 1432
        DEFINE_PROP_END_OF_LIST(),
    },
1433 1434 1435 1436
};

static void usb_host_register_devices(void)
{
1437
    usb_qdev_register(&usb_host_dev_info, "host", usb_host_device_open);
1438 1439 1440
}
device_init(usb_host_register_devices)

1441 1442
USBDevice *usb_host_device_open(const char *devname)
{
1443
    struct USBAutoFilter filter;
1444 1445 1446
    USBDevice *dev;
    char *p;

1447
    dev = usb_create(NULL /* FIXME */, "usb-host");
1448

1449
    if (strstr(devname, "auto:")) {
1450
        if (parse_filter(devname, &filter) < 0) {
1451
            goto fail;
1452
        }
1453 1454
    } else {
        if ((p = strchr(devname, '.'))) {
1455 1456 1457 1458
            filter.bus_num    = strtoul(devname, NULL, 0);
            filter.addr       = strtoul(p + 1, NULL, 0);
            filter.vendor_id  = 0;
            filter.product_id = 0;
1459
        } else if ((p = strchr(devname, ':'))) {
1460 1461
            filter.bus_num    = 0;
            filter.addr       = 0;
1462
            filter.vendor_id  = strtoul(devname, NULL, 16);
1463
            filter.product_id = strtoul(p + 1, NULL, 16);
1464 1465 1466
        } else {
            goto fail;
        }
1467
    }
1468

1469 1470
    qdev_prop_set_uint32(&dev->qdev, "hostbus",   filter.bus_num);
    qdev_prop_set_uint32(&dev->qdev, "hostaddr",  filter.addr);
1471 1472
    qdev_prop_set_uint32(&dev->qdev, "vendorid",  filter.vendor_id);
    qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
K
Kevin Wolf 已提交
1473
    qdev_init_nofail(&dev->qdev);
1474
    return dev;
1475

1476 1477 1478
fail:
    qdev_free(&dev->qdev);
    return NULL;
1479
}
1480 1481 1482

int usb_host_device_close(const char *devname)
{
1483
#if 0
1484 1485 1486 1487
    char product_name[PRODUCT_NAME_SZ];
    int bus_num, addr;
    USBHostDevice *s;

1488
    if (strstr(devname, "auto:")) {
1489
        return usb_host_auto_del(devname);
1490 1491 1492
    }
    if (usb_host_find_device(&bus_num, &addr, product_name,
                                    sizeof(product_name), devname) < 0) {
1493
        return -1;
1494
    }
1495 1496
    s = hostdev_find(bus_num, addr);
    if (s) {
1497
        usb_device_delete_addr(s->bus_num, s->dev.addr);
1498 1499
        return 0;
    }
1500
#endif
1501 1502 1503

    return -1;
}
1504

1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
/*
 * Read sys file-system device file
 *
 * @line address of buffer to put file contents in
 * @line_size size of line
 * @device_file path to device file (printf format string)
 * @device_name device being opened (inserted into device_file)
 *
 * @return 0 failed, 1 succeeded ('line' contains data)
 */
1515 1516
static int usb_host_read_file(char *line, size_t line_size,
                              const char *device_file, const char *device_name)
1517 1518 1519 1520 1521
{
    FILE *f;
    int ret = 0;
    char filename[PATH_MAX];

1522
    snprintf(filename, PATH_MAX, "/sys/bus/usb/devices/%s/%s", device_name,
1523
             device_file);
1524 1525
    f = fopen(filename, "r");
    if (f) {
1526
        ret = fgets(line, line_size, f) != NULL;
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539
        fclose(f);
    }

    return ret;
}

/*
 * Use /sys/bus/usb/devices/ directory to determine host's USB
 * devices.
 *
 * This code is based on Robert Schiele's original patches posted to
 * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
 */
1540
static int usb_host_scan(void *opaque, USBScanFunc *func)
1541
{
1542
    DIR *dir = NULL;
1543
    char line[1024];
1544
    int bus_num, addr, speed, class_id, product_id, vendor_id;
1545
    int ret = 0;
1546
    char port[MAX_PORTLEN];
1547 1548 1549
    char product_name[512];
    struct dirent *de;

1550
    dir = opendir("/sys/bus/usb/devices");
1551
    if (!dir) {
1552 1553
        perror("husb: opendir /sys/bus/usb/devices");
        fprintf(stderr, "husb: please make sure sysfs is mounted at /sys\n");
1554 1555 1556 1557 1558
        goto the_end;
    }

    while ((de = readdir(dir))) {
        if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
1559 1560
            if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
                continue;
1561
            }
1562

1563
            if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
1564
                goto the_end;
1565 1566
            }
            if (sscanf(line, "%d", &addr) != 1) {
1567
                goto the_end;
1568
            }
1569
            if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
1570
                                    de->d_name)) {
1571
                goto the_end;
1572 1573
            }
            if (sscanf(line, "%x", &class_id) != 1) {
1574
                goto the_end;
1575
            }
1576

1577 1578
            if (!usb_host_read_file(line, sizeof(line), "idVendor",
                                    de->d_name)) {
1579
                goto the_end;
1580 1581
            }
            if (sscanf(line, "%x", &vendor_id) != 1) {
1582
                goto the_end;
1583
            }
1584
            if (!usb_host_read_file(line, sizeof(line), "idProduct",
1585
                                    de->d_name)) {
1586
                goto the_end;
1587 1588
            }
            if (sscanf(line, "%x", &product_id) != 1) {
1589
                goto the_end;
1590
            }
1591 1592
            if (!usb_host_read_file(line, sizeof(line), "product",
                                    de->d_name)) {
1593 1594
                *product_name = 0;
            } else {
1595
                if (strlen(line) > 0) {
1596
                    line[strlen(line) - 1] = '\0';
1597
                }
1598 1599 1600
                pstrcpy(product_name, sizeof(product_name), line);
            }

1601
            if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
1602
                goto the_end;
1603
            }
1604 1605 1606
            if (!strcmp(line, "5000\n")) {
                speed = USB_SPEED_SUPER;
            } else if (!strcmp(line, "480\n")) {
1607
                speed = USB_SPEED_HIGH;
1608
            } else if (!strcmp(line, "1.5\n")) {
1609
                speed = USB_SPEED_LOW;
1610
            } else {
1611
                speed = USB_SPEED_FULL;
1612
            }
1613

1614
            ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
1615
                       product_id, product_name, speed);
1616
            if (ret) {
1617
                goto the_end;
1618
            }
1619 1620 1621
        }
    }
 the_end:
1622
    if (dir) {
1623
        closedir(dir);
1624
    }
1625 1626 1627
    return ret;
}

1628 1629
static QEMUTimer *usb_auto_timer;

G
Gerd Hoffmann 已提交
1630 1631
static int usb_host_auto_scan(void *opaque, int bus_num,
                              int addr, const char *port,
1632 1633
                              int class_id, int vendor_id, int product_id,
                              const char *product_name, int speed)
1634 1635
{
    struct USBAutoFilter *f;
1636
    struct USBHostDevice *s;
1637 1638 1639 1640 1641

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

1642 1643 1644
    QTAILQ_FOREACH(s, &hostdevs, next) {
        f = &s->match;

1645
        if (f->bus_num > 0 && f->bus_num != bus_num) {
1646
            continue;
1647 1648
        }
        if (f->addr > 0 && f->addr != addr) {
1649
            continue;
1650
        }
G
Gerd Hoffmann 已提交
1651 1652 1653
        if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) {
            continue;
        }
1654

1655
        if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
1656
            continue;
1657
        }
1658

1659
        if (f->product_id > 0 && f->product_id != product_id) {
1660
            continue;
1661
        }
1662
        /* We got a match */
G
Gerd Hoffmann 已提交
1663 1664 1665 1666
        s->seen++;
        if (s->errcount >= 3) {
            return 0;
        }
1667

1668
        /* Already attached ? */
1669
        if (s->fd != -1) {
1670
            return 0;
1671
        }
M
malc 已提交
1672
        DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
1673

G
Gerd Hoffmann 已提交
1674 1675 1676
        if (usb_host_open(s, bus_num, addr, port, product_name, speed) < 0) {
            s->errcount++;
        }
1677
        break;
1678 1679 1680 1681 1682
    }

    return 0;
}

1683
static void usb_host_auto_check(void *unused)
1684
{
1685 1686 1687
    struct USBHostDevice *s;
    int unconnected = 0;

1688
    usb_host_scan(NULL, usb_host_auto_scan);
1689 1690

    QTAILQ_FOREACH(s, &hostdevs, next) {
1691
        if (s->fd == -1) {
1692
            unconnected++;
1693
        }
G
Gerd Hoffmann 已提交
1694 1695 1696 1697
        if (s->seen == 0) {
            s->errcount = 0;
        }
        s->seen = 0;
1698 1699 1700 1701
    }

    if (unconnected == 0) {
        /* nothing to watch */
1702
        if (usb_auto_timer) {
1703
            qemu_del_timer(usb_auto_timer);
G
Gerd Hoffmann 已提交
1704
            trace_usb_host_auto_scan_disabled();
1705
        }
1706 1707 1708 1709
        return;
    }

    if (!usb_auto_timer) {
1710
        usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
1711
        if (!usb_auto_timer) {
1712
            return;
1713
        }
G
Gerd Hoffmann 已提交
1714
        trace_usb_host_auto_scan_enabled();
1715
    }
1716
    qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
1717 1718 1719
}

/*
1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730
 * Autoconnect filter
 * Format:
 *    auto:bus:dev[:vid:pid]
 *    auto:bus.dev[:vid:pid]
 *
 *    bus  - bus number    (dec, * means any)
 *    dev  - device number (dec, * means any)
 *    vid  - vendor id     (hex, * means any)
 *    pid  - product id    (hex, * means any)
 *
 *    See 'lsusb' output.
1731
 */
1732
static int parse_filter(const char *spec, struct USBAutoFilter *f)
1733
{
1734 1735 1736 1737
    enum { BUS, DEV, VID, PID, DONE };
    const char *p = spec;
    int i;

1738 1739 1740 1741
    f->bus_num    = 0;
    f->addr       = 0;
    f->vendor_id  = 0;
    f->product_id = 0;
1742 1743

    for (i = BUS; i < DONE; i++) {
1744 1745 1746 1747
        p = strpbrk(p, ":.");
        if (!p) {
            break;
        }
1748 1749
        p++;

1750 1751 1752
        if (*p == '*') {
            continue;
        }
1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768
        switch(i) {
        case BUS: f->bus_num = strtol(p, NULL, 10);    break;
        case DEV: f->addr    = strtol(p, NULL, 10);    break;
        case VID: f->vendor_id  = strtol(p, NULL, 16); break;
        case PID: f->product_id = strtol(p, NULL, 16); break;
        }
    }

    if (i < DEV) {
        fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
        return -1;
    }

    return 0;
}

B
bellard 已提交
1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788
/**********************/
/* 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" },
1789
    { USB_CLASS_CSCID, "Smart Card" },
B
bellard 已提交
1790 1791 1792 1793 1794
    { USB_CLASS_CONTENT_SEC, "Content Security" },
    { -1, NULL }
};

static const char *usb_class_str(uint8_t class)
B
bellard 已提交
1795
{
B
bellard 已提交
1796 1797
    const struct usb_class_info *p;
    for(p = usb_class_info; p->class != -1; p++) {
1798
        if (p->class == class) {
B
bellard 已提交
1799
            break;
1800
        }
B
bellard 已提交
1801
    }
B
bellard 已提交
1802 1803 1804
    return p->class_name;
}

G
Gerd Hoffmann 已提交
1805 1806
static void usb_info_device(Monitor *mon, int bus_num,
                            int addr, const char *port,
1807
                            int class_id, int vendor_id, int product_id,
1808 1809
                            const char *product_name,
                            int speed)
B
bellard 已提交
1810 1811 1812 1813
{
    const char *class_str, *speed_str;

    switch(speed) {
1814 1815
    case USB_SPEED_LOW:
        speed_str = "1.5";
B
bellard 已提交
1816
        break;
1817 1818
    case USB_SPEED_FULL:
        speed_str = "12";
B
bellard 已提交
1819
        break;
1820 1821
    case USB_SPEED_HIGH:
        speed_str = "480";
B
bellard 已提交
1822
        break;
1823 1824 1825
    case USB_SPEED_SUPER:
        speed_str = "5000";
        break;
B
bellard 已提交
1826
    default:
1827
        speed_str = "?";
B
bellard 已提交
1828 1829 1830
        break;
    }

1831 1832
    monitor_printf(mon, "  Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
                   bus_num, addr, port, speed_str);
B
bellard 已提交
1833
    class_str = usb_class_str(class_id);
1834
    if (class_str) {
A
aliguori 已提交
1835
        monitor_printf(mon, "    %s:", class_str);
1836
    } else {
A
aliguori 已提交
1837
        monitor_printf(mon, "    Class %02x:", class_id);
1838
    }
A
aliguori 已提交
1839
    monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
1840
    if (product_name[0] != '\0') {
A
aliguori 已提交
1841
        monitor_printf(mon, ", %s", product_name);
1842
    }
A
aliguori 已提交
1843
    monitor_printf(mon, "\n");
B
bellard 已提交
1844 1845
}

1846
static int usb_host_info_device(void *opaque, int bus_num, int addr,
G
Gerd Hoffmann 已提交
1847
                                const char *path, int class_id,
1848
                                int vendor_id, int product_id,
B
bellard 已提交
1849 1850 1851
                                const char *product_name,
                                int speed)
{
1852 1853
    Monitor *mon = opaque;

1854
    usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
B
bellard 已提交
1855 1856 1857 1858
                    product_name, speed);
    return 0;
}

A
aliguori 已提交
1859
static void dec2str(int val, char *str, size_t size)
1860
{
1861
    if (val == 0) {
A
aliguori 已提交
1862
        snprintf(str, size, "*");
1863 1864 1865
    } else {
        snprintf(str, size, "%d", val);
    }
1866 1867
}

A
aliguori 已提交
1868
static void hex2str(int val, char *str, size_t size)
1869
{
1870
    if (val == 0) {
A
aliguori 已提交
1871
        snprintf(str, size, "*");
1872
    } else {
1873
        snprintf(str, size, "%04x", val);
1874
    }
1875 1876
}

A
aliguori 已提交
1877
void usb_host_info(Monitor *mon)
B
bellard 已提交
1878
{
1879
    struct USBAutoFilter *f;
1880
    struct USBHostDevice *s;
1881

1882
    usb_host_scan(mon, usb_host_info_device);
1883

1884
    if (QTAILQ_EMPTY(&hostdevs)) {
1885
        return;
1886 1887
    }

1888 1889
    monitor_printf(mon, "  Auto filters:\n");
    QTAILQ_FOREACH(s, &hostdevs, next) {
1890
        char bus[10], addr[10], vid[10], pid[10];
1891
        f = &s->match;
A
aliguori 已提交
1892 1893 1894 1895
        dec2str(f->bus_num, bus, sizeof(bus));
        dec2str(f->addr, addr, sizeof(addr));
        hex2str(f->vendor_id, vid, sizeof(vid));
        hex2str(f->product_id, pid, sizeof(pid));
G
Gerd Hoffmann 已提交
1896 1897
        monitor_printf(mon, "    Bus %s, Addr %s, Port %s, ID %s:%s\n",
                       bus, addr, f->port ? f->port : "*", vid, pid);
1898
    }
B
bellard 已提交
1899
}