host-linux.c 53.0 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;
118
    int32_t bootindex;
G
Gerd Hoffmann 已提交
119
    int seen, errcount;
120

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

124 125 126 127 128
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);
129 130
static int usb_host_read_file(char *line, size_t line_size,
                            const char *device_file, const char *device_name);
G
Gerd Hoffmann 已提交
131
static int usb_linux_update_endp_table(USBHostDevice *s);
132

G
Gerd Hoffmann 已提交
133 134 135 136 137 138 139 140
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,
    };
141
    uint8_t type = p->ep->type;
G
Gerd Hoffmann 已提交
142 143 144 145
    assert(type < ARRAY_SIZE(usbfs));
    return usbfs[type];
}

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
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 已提交
165
static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
G
Gerd Hoffmann 已提交
166
{
G
Gerd Hoffmann 已提交
167 168
    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 已提交
169
    assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
G
Gerd Hoffmann 已提交
170
    return eps + ep - 1;
G
Gerd Hoffmann 已提交
171 172
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    while (1) {
309
        USBPacket *p;
310

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

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

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

334 335 336
        /* 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) {
337
            int inflight;
G
Gerd Hoffmann 已提交
338 339 340
            int pid = (aurb->urb.endpoint & USB_DIR_IN) ?
                USB_TOKEN_IN : USB_TOKEN_OUT;
            int ep = aurb->urb.endpoint & 0xf;
341
            if (aurb->urb.status == -EPIPE) {
G
Gerd Hoffmann 已提交
342
                set_halt(s, pid, ep);
343 344
            }
            aurb->iso_frame_idx = 0;
345
            urbs++;
G
Gerd Hoffmann 已提交
346 347
            inflight = change_iso_inflight(s, pid, ep, -1);
            if (inflight == 0 && is_iso_started(s, pid, ep)) {
348 349
                fprintf(stderr, "husb: out of buffers for iso stream\n");
            }
350 351 352 353
            continue;
        }

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

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

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

368 369 370 371
            case -EOVERFLOW:
                p->result = USB_RET_BABBLE;
                break;

372
            default:
H
Hans de Goede 已提交
373
                p->result = USB_RET_IOERROR;
374 375 376
                break;
            }

377
            if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
378
                trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result);
379
                usb_generic_async_ctrl_complete(&s->dev, p);
G
Gerd Hoffmann 已提交
380
            } else if (!aurb->more) {
381
                trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result);
382 383
                usb_packet_complete(&s->dev, p);
            }
384
        }
385 386

        async_free(aurb);
387 388 389
    }
}

390
static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
391
{
392
    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
393
    AsyncURB *aurb;
394

395
    trace_usb_host_req_canceled(s->bus_num, s->addr, p);
396

397 398 399 400
    QLIST_FOREACH(aurb, &s->aurbs, next) {
        if (p != aurb->packet) {
            continue;
        }
401

402
        trace_usb_host_urb_canceled(s->bus_num, s->addr, aurb);
403

404 405 406 407 408 409 410
        /* 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);
        }
411 412 413
    }
}

414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
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 已提交
439 440 441 442
static int usb_host_claim_port(USBHostDevice *s)
{
#ifdef USBDEVFS_CLAIM_PORT
    char *h, hub_name[64], line[1024];
443
    int hub_addr, ret;
G
Gerd Hoffmann 已提交
444 445 446 447 448 449 450

    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) {
451
        s->hub_port = atoi(h+1);
G
Gerd Hoffmann 已提交
452 453 454 455 456
        *h = '\0';
    } else {
        /* no dot in there -> it is the root hub */
        snprintf(hub_name, sizeof(hub_name), "usb%d",
                 s->match.bus_num);
457
        s->hub_port = atoi(s->match.port);
G
Gerd Hoffmann 已提交
458 459 460 461 462 463 464 465 466 467
    }

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

468
    s->hub_fd = usb_host_open_device(s->match.bus_num, hub_addr);
G
Gerd Hoffmann 已提交
469 470 471 472
    if (s->hub_fd < 0) {
        return -1;
    }

473
    ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &s->hub_port);
G
Gerd Hoffmann 已提交
474 475 476 477 478 479
    if (ret < 0) {
        close(s->hub_fd);
        s->hub_fd = -1;
        return -1;
    }

480
    trace_usb_host_claim_port(s->match.bus_num, hub_addr, s->hub_port);
G
Gerd Hoffmann 已提交
481 482 483 484 485 486
    return 0;
#else
    return -1;
#endif
}

487 488 489 490 491 492 493 494 495 496 497 498
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 已提交
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
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;
}

520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
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;
}

536
static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
537
{
538
    const char *op = NULL;
539
    int dev_descr_len, config_descr_len;
540
    int interface, nb_interfaces;
541 542
    int ret, i;

543 544 545 546
    for (i = 0; i < USB_MAX_INTERFACES; i++) {
        dev->dev.altsetting[i] = 0;
    }

547
    if (configuration == 0) { /* address state - ignore */
548 549
        dev->dev.ninterfaces   = 0;
        dev->dev.configuration = 0;
550
        return 1;
551
    }
552

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

555 556
    i = 0;
    dev_descr_len = dev->descr[0];
557
    if (dev_descr_len > dev->descr_len) {
558 559
        fprintf(stderr, "husb: update iface failed. descr too short\n");
        return 0;
560
    }
561 562 563

    i += dev_descr_len;
    while (i < dev->descr_len) {
564 565
        DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
                i, dev->descr_len,
566
               dev->descr[i], dev->descr[i+1]);
567

568 569 570 571 572 573
        if (dev->descr[i+1] != USB_DT_CONFIG) {
            i += dev->descr[i];
            continue;
        }
        config_descr_len = dev->descr[i];

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

576
        if (configuration == dev->descr[i + 5]) {
577
            configuration = dev->descr[i + 5];
578
            break;
579
        }
580 581 582 583 584

        i += config_descr_len;
    }

    if (i >= dev->descr_len) {
585 586
        fprintf(stderr,
                "husb: update iface failed. no matching configuration\n");
587
        return 0;
588 589 590
    }
    nb_interfaces = dev->descr[i + 4];

G
Gerd Hoffmann 已提交
591 592
    if (usb_host_disconnect_ifaces(dev, nb_interfaces) < 0) {
        goto fail;
593 594 595 596
    }

    /* XXX: only grab if all interfaces are free */
    for (interface = 0; interface < nb_interfaces; interface++) {
597
        op = "USBDEVFS_CLAIMINTERFACE";
598 599
        ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
        if (ret < 0) {
600
            goto fail;
601 602 603
        }
    }

G
Gerd Hoffmann 已提交
604 605
    trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
                                    nb_interfaces, configuration);
606

607 608
    dev->dev.ninterfaces   = nb_interfaces;
    dev->dev.configuration = configuration;
609
    return 1;
610 611 612 613 614 615 616

fail:
    if (errno == ENODEV) {
        do_disconnect(dev);
    }
    perror(op);
    return 0;
617 618 619 620 621 622
}

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

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

625
    for (i = 0; i < s->dev.ninterfaces; i++) {
626 627
        ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
        if (ret < 0) {
G
Gerd Hoffmann 已提交
628
            perror("USBDEVFS_RELEASEINTERFACE");
629 630 631
            return 0;
        }
    }
632 633 634
    return 1;
}

B
bellard 已提交
635
static void usb_host_handle_reset(USBDevice *dev)
B
bellard 已提交
636
{
637
    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
638

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

641
    usb_host_do_reset(s);;
642

643
    usb_host_claim_interfaces(s, 0);
G
Gerd Hoffmann 已提交
644
    usb_linux_update_endp_table(s);
645
}
B
bellard 已提交
646

B
bellard 已提交
647 648 649 650
static void usb_host_handle_destroy(USBDevice *dev)
{
    USBHostDevice *s = (USBHostDevice *)dev;

651
    usb_host_release_port(s);
652 653
    usb_host_close(s);
    QTAILQ_REMOVE(&hostdevs, s, next);
654
    qemu_remove_exit_notifier(&s->exit);
B
bellard 已提交
655 656
}

657 658 659
/* 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 已提交
660
static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
661 662
{
    AsyncURB *aurb;
663
    int i, j, len = usb_ep_get_max_packet_size(&s->dev, pid, ep);
664

665
    aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
666
    for (i = 0; i < s->iso_urb_count; i++) {
667 668
        aurb[i].urb.endpoint      = ep;
        aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
669
        aurb[i].urb.buffer        = g_malloc(aurb[i].urb.buffer_length);
670 671 672 673 674
        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 已提交
675
        if (pid == USB_TOKEN_IN) {
676 677 678 679 680
            aurb[i].urb.endpoint |= 0x80;
            /* Mark as fully consumed (idle) */
            aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
        }
    }
G
Gerd Hoffmann 已提交
681
    set_iso_urb(s, pid, ep, aurb);
682 683 684 685

    return aurb;
}

G
Gerd Hoffmann 已提交
686
static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep)
687 688 689 690
{
    AsyncURB *aurb;
    int i, ret, killed = 0, free = 1;

G
Gerd Hoffmann 已提交
691
    aurb = get_iso_urb(s, pid, ep);
692 693 694 695
    if (!aurb) {
        return;
    }

696
    for (i = 0; i < s->iso_urb_count; i++) {
697 698 699 700
        /* in flight? */
        if (aurb[i].iso_frame_idx == -1) {
            ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
            if (ret < 0) {
G
Gerd Hoffmann 已提交
701
                perror("USBDEVFS_DISCARDURB");
702 703 704 705 706 707 708 709 710 711 712 713
                free = 0;
                continue;
            }
            killed++;
        }
    }

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

714
    for (i = 0; i < s->iso_urb_count; i++) {
715
        g_free(aurb[i].urb.buffer);
716 717 718
    }

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

static int urb_status_to_usb_ret(int status)
{
    switch (status) {
    case -EPIPE:
        return USB_RET_STALL;
732 733
    case -EOVERFLOW:
        return USB_RET_BABBLE;
734
    default:
H
Hans de Goede 已提交
735
        return USB_RET_IOERROR;
736 737 738
    }
}

739
static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
740 741
{
    AsyncURB *aurb;
742
    int i, j, ret, max_packet_size, offset, len = 0;
G
Gerd Hoffmann 已提交
743
    uint8_t *buf;
744

745
    max_packet_size = p->ep->max_packet_size;
746 747
    if (max_packet_size == 0)
        return USB_RET_NAK;
748

749
    aurb = get_iso_urb(s, p->pid, p->ep->nr);
750
    if (!aurb) {
751
        aurb = usb_host_alloc_iso(s, p->pid, p->ep->nr);
752 753
    }

754
    i = get_iso_urb_idx(s, p->pid, p->ep->nr);
755 756
    j = aurb[i].iso_frame_idx;
    if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
757 758 759 760 761 762 763 764 765 766 767
        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 已提交
768 769
            } else if (aurb[i].urb.iso_frame_desc[j].actual_length
                       > p->iov.size) {
770
                printf("husb: received iso data is larger then packet\n");
771
                len = USB_RET_BABBLE;
772 773 774
            /* All good copy data over */
            } else {
                len = aurb[i].urb.iso_frame_desc[j].actual_length;
G
Gerd Hoffmann 已提交
775 776 777
                buf  = aurb[i].urb.buffer +
                    j * aurb[i].urb.iso_frame_desc[0].length;
                usb_packet_copy(p, buf, len);
778
            }
779
        } else {
G
Gerd Hoffmann 已提交
780
            len = p->iov.size;
781
            offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->ep->nr);
782 783 784 785 786 787 788 789

            /* 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 已提交
790
            usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
791 792
            aurb[i].urb.iso_frame_desc[j].length = len;
            offset += len;
793
            set_iso_buffer_used(s, p->pid, p->ep->nr, offset);
794 795

            /* Start the stream once we have buffered enough data */
796 797
            if (!is_iso_started(s, p->pid, p->ep->nr) && i == 1 && j == 8) {
                set_iso_started(s, p->pid, p->ep->nr);
798
            }
799 800 801
        }
        aurb[i].iso_frame_idx++;
        if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
802
            i = (i + 1) % s->iso_urb_count;
803
            set_iso_urb_idx(s, p->pid, p->ep->nr, i);
804
        }
805 806
    } else {
        if (in) {
807
            set_iso_started(s, p->pid, p->ep->nr);
808 809 810
        } else {
            DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
        }
811 812
    }

813
    if (is_iso_started(s, p->pid, p->ep->nr)) {
814
        /* (Re)-submit all fully consumed / filled urbs */
815
        for (i = 0; i < s->iso_urb_count; i++) {
816 817 818
            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 已提交
819
                    perror("USBDEVFS_SUBMITURB");
820 821 822 823
                    if (!in || len == 0) {
                        switch(errno) {
                        case ETIMEDOUT:
                            len = USB_RET_NAK;
824
                            break;
825 826 827 828
                        case EPIPE:
                        default:
                            len = USB_RET_STALL;
                        }
829
                    }
830
                    break;
831
                }
832
                aurb[i].iso_frame_idx = -1;
833
                change_iso_inflight(s, p->pid, p->ep->nr, 1);
834 835 836 837 838 839 840
            }
        }
    }

    return len;
}

841
static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
B
bellard 已提交
842
{
843
    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
844
    struct usbdevfs_urb *urb;
845
    AsyncURB *aurb;
G
Gerd Hoffmann 已提交
846
    int ret, rem, prem, v;
G
Gerd Hoffmann 已提交
847
    uint8_t *pbuf;
848
    uint8_t ep;
849

850
    trace_usb_host_req_data(s->bus_num, s->addr, p,
G
Gerd Hoffmann 已提交
851
                            p->pid == USB_TOKEN_IN,
852
                            p->ep->nr, p->iov.size);
G
Gerd Hoffmann 已提交
853

854
    if (!is_valid(s, p->pid, p->ep->nr)) {
855
        trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK);
856 857 858
        return USB_RET_NAK;
    }

859
    if (p->pid == USB_TOKEN_IN) {
860
        ep = p->ep->nr | 0x80;
861
    } else {
862
        ep = p->ep->nr;
863
    }
864

865
    if (is_halted(s, p->pid, p->ep->nr)) {
G
Gerd Hoffmann 已提交
866 867
        unsigned int arg = ep;
        ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
868
        if (ret < 0) {
G
Gerd Hoffmann 已提交
869
            perror("USBDEVFS_CLEAR_HALT");
870
            trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK);
B
bellard 已提交
871 872
            return USB_RET_NAK;
        }
873
        clear_halt(s, p->pid, p->ep->nr);
874 875
    }

876
    if (is_isoc(s, p->pid, p->ep->nr)) {
877 878
        return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
    }
879

G
Gerd Hoffmann 已提交
880 881 882 883
    v = 0;
    prem = p->iov.iov[v].iov_len;
    pbuf = p->iov.iov[v].iov_base;
    rem = p->iov.size;
G
Gerd Hoffmann 已提交
884
    while (rem) {
G
Gerd Hoffmann 已提交
885 886 887 888 889 890 891
        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 已提交
892 893 894 895 896
        aurb = async_alloc(s);
        aurb->packet = p;

        urb = &aurb->urb;
        urb->endpoint      = ep;
G
Gerd Hoffmann 已提交
897
        urb->type          = usb_host_usbfs_type(s, p);
G
Gerd Hoffmann 已提交
898 899
        urb->usercontext   = s;
        urb->buffer        = pbuf;
G
Gerd Hoffmann 已提交
900
        urb->buffer_length = prem;
G
Gerd Hoffmann 已提交
901

G
Gerd Hoffmann 已提交
902
        if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) {
G
Gerd Hoffmann 已提交
903 904 905
            urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
        }
        pbuf += urb->buffer_length;
G
Gerd Hoffmann 已提交
906
        prem -= urb->buffer_length;
G
Gerd Hoffmann 已提交
907
        rem  -= urb->buffer_length;
G
Gerd Hoffmann 已提交
908 909 910
        if (rem) {
            aurb->more         = 1;
        }
911

G
Gerd Hoffmann 已提交
912 913
        trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
                                  urb->buffer_length, aurb->more);
G
Gerd Hoffmann 已提交
914
        ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
915

G
Gerd Hoffmann 已提交
916 917
        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);
918

G
Gerd Hoffmann 已提交
919
        if (ret < 0) {
G
Gerd Hoffmann 已提交
920
            perror("USBDEVFS_SUBMITURB");
G
Gerd Hoffmann 已提交
921
            async_free(aurb);
922

G
Gerd Hoffmann 已提交
923 924
            switch(errno) {
            case ETIMEDOUT:
925 926
                trace_usb_host_req_complete(s->bus_num, s->addr, p,
                                            USB_RET_NAK);
G
Gerd Hoffmann 已提交
927 928 929
                return USB_RET_NAK;
            case EPIPE:
            default:
930 931
                trace_usb_host_req_complete(s->bus_num, s->addr, p,
                                            USB_RET_STALL);
G
Gerd Hoffmann 已提交
932 933
                return USB_RET_STALL;
            }
934 935
        }
    }
936

937 938 939
    return USB_RET_ASYNC;
}

940 941
static int ctrl_error(void)
{
942
    if (errno == ETIMEDOUT) {
943
        return USB_RET_NAK;
944
    } else {
945
        return USB_RET_STALL;
946
    }
947 948 949 950
}

static int usb_host_set_address(USBHostDevice *s, int addr)
{
G
Gerd Hoffmann 已提交
951
    trace_usb_host_set_address(s->bus_num, s->addr, addr);
952 953 954 955 956 957
    s->dev.addr = addr;
    return 0;
}

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

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

962 963
    usb_host_release_interfaces(s);

964 965
again:
    ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
966

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

969 970 971 972 973 974 975 976 977 978 979
    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;
        }
    }

980
    if (ret < 0) {
981
        return ctrl_error();
982
    }
983
    usb_host_claim_interfaces(s, config);
984
    usb_linux_update_endp_table(s);
985 986 987 988 989 990
    return 0;
}

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

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

G
Gerd Hoffmann 已提交
995
    for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
G
Gerd Hoffmann 已提交
996 997 998 999 1000
        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);
1001 1002
        }
    }
1003

1004 1005 1006 1007
    if (iface >= USB_MAX_INTERFACES) {
        return USB_RET_STALL;
    }

1008 1009 1010 1011
    si.interface  = iface;
    si.altsetting = alt;
    ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);

1012 1013 1014 1015 1016 1017
    DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
            iface, alt, ret, errno);

    if (ret < 0) {
        return ctrl_error();
    }
1018 1019

    s->dev.altsetting[iface] = alt;
1020 1021 1022 1023
    usb_linux_update_endp_table(s);
    return 0;
}

1024 1025
static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
               int request, int value, int index, int length, uint8_t *data)
1026
{
1027
    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1028 1029
    struct usbdevfs_urb *urb;
    AsyncURB *aurb;
1030
    int ret;
1031

1032
    /*
1033 1034 1035 1036
     * Process certain standard device requests.
     * These are infrequent and are processed synchronously.
     */

1037
    /* Note request is (bRequestType << 8) | bRequest */
1038
    trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
1039

1040 1041
    switch (request) {
    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
1042
        ret = usb_host_set_address(s, value);
1043
        trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
1044
        return ret;
1045

1046
    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
1047
        ret = usb_host_set_config(s, value & 0xff);
1048
        trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
1049
        return ret;
1050

1051
    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
1052
        ret = usb_host_set_interface(s, index, value);
1053
        trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
1054
        return ret;
1055
    }
1056 1057 1058

    /* The rest are asynchronous */

1059 1060 1061
    if (length > sizeof(dev->data_buf)) {
        fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
                length, sizeof(dev->data_buf));
1062
        return USB_RET_STALL;
J
Jim Paris 已提交
1063 1064
    }

G
Gerd Hoffmann 已提交
1065
    aurb = async_alloc(s);
1066 1067
    aurb->packet = p;

1068
    /*
1069 1070
     * Setup ctrl transfer.
     *
1071
     * s->ctrl is laid out such that data buffer immediately follows
1072
     * 'req' struct which is exactly what usbdevfs expects.
1073
     */
1074 1075 1076
    urb = &aurb->urb;

    urb->type     = USBDEVFS_URB_TYPE_CONTROL;
1077
    urb->endpoint = p->ep->nr;
1078

1079 1080
    urb->buffer        = &dev->setup_buf;
    urb->buffer_length = length + 8;
1081 1082 1083

    urb->usercontext = s;

G
Gerd Hoffmann 已提交
1084 1085
    trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
                              urb->buffer_length, aurb->more);
1086 1087
    ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);

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

    if (ret < 0) {
M
malc 已提交
1091
        DPRINTF("husb: submit failed. errno %d\n", errno);
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
        async_free(aurb);

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

    return USB_RET_ASYNC;
}

1106 1107 1108
static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
    uint8_t configuration, uint8_t interface)
{
1109 1110
    char device_name[64], line[1024];
    int alt_setting;
1111

1112 1113
    sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
            (int)configuration, (int)interface);
1114

1115 1116 1117 1118 1119 1120
    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) {
1121 1122 1123 1124 1125 1126
        /* Assume alt 0 on error */
        return 0;
    }
    return alt_setting;
}

1127 1128 1129 1130
/* returns 1 on problem encountered or 0 for success */
static int usb_linux_update_endp_table(USBHostDevice *s)
{
    uint8_t *descriptors;
1131
    uint8_t devep, type, alt_interface;
1132
    uint16_t raw;
G
Gerd Hoffmann 已提交
1133 1134
    int interface, length, i, ep, pid;
    struct endp_data *epd;
1135

G
Gerd Hoffmann 已提交
1136
    usb_ep_init(&s->dev);
1137

1138
    if (s->dev.configuration == 0) {
1139 1140 1141
        /* not configured yet -- leave all endpoints disabled */
        return 0;
    }
1142

1143 1144 1145 1146 1147 1148 1149
    /* 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) {
1150 1151 1152
        if (descriptors[i + 1] != USB_DT_CONFIG) {
            fprintf(stderr, "invalid descriptor data\n");
            return 1;
1153 1154
        } else if (descriptors[i + 5] != s->dev.configuration) {
            DPRINTF("not requested configuration %d\n", s->dev.configuration);
1155 1156 1157 1158 1159
            i += (descriptors[i + 3] << 8) + descriptors[i + 2];
            continue;
        }
        i += descriptors[i];

1160 1161 1162 1163 1164 1165 1166 1167
        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];
1168
        alt_interface = usb_linux_get_alt_setting(s, s->dev.configuration,
1169
                                                  interface);
1170 1171 1172 1173 1174 1175 1176 1177 1178

        /* 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 */
1179
        while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
1180
            i += descriptors[i];
1181
        }
1182 1183 1184 1185 1186

        if (i >= length)
            break;

        while (i < length) {
1187
            if (descriptors[i + 1] != USB_DT_ENDPOINT) {
1188
                break;
1189
            }
1190 1191

            devep = descriptors[i + 2];
G
Gerd Hoffmann 已提交
1192 1193 1194
            pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
            ep = devep & 0xf;
            if (ep == 0) {
H
Hans de Goede 已提交
1195 1196 1197 1198
                fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
                return 1;
            }

G
Gerd Hoffmann 已提交
1199
            type = descriptors[i + 3] & 0x3;
1200 1201
            raw = descriptors[i + 4] + (descriptors[i + 5] << 8);
            usb_ep_set_max_packet_size(&s->dev, pid, ep, raw);
G
Gerd Hoffmann 已提交
1202 1203 1204
            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 已提交
1205
            usb_ep_set_ifnum(&s->dev, pid, ep, interface);
1206 1207 1208
            if (type == USB_ENDPOINT_XFER_BULK) {
                usb_ep_set_pipeline(&s->dev, pid, ep, true);
            }
G
Gerd Hoffmann 已提交
1209

G
Gerd Hoffmann 已提交
1210 1211
            epd = get_endp(s, pid, ep);
            epd->halted = 0;
1212 1213 1214 1215

            i += descriptors[i];
        }
    }
G
Gerd Hoffmann 已提交
1216 1217 1218
#ifdef DEBUG
    usb_ep_dump(&s->dev);
#endif
1219 1220 1221
    return 0;
}

1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257
/*
 * 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;
}

1258
static int usb_host_open(USBHostDevice *dev, int bus_num,
G
Gerd Hoffmann 已提交
1259 1260
                         int addr, const char *port,
                         const char *prod_name, int speed)
B
bellard 已提交
1261
{
1262
    int fd = -1, ret;
1263

G
Gerd Hoffmann 已提交
1264 1265
    trace_usb_host_open_started(bus_num, addr);

1266
    if (dev->fd != -1) {
1267
        goto fail;
1268
    }
1269

1270
    fd = usb_host_open_device(bus_num, addr);
B
bellard 已提交
1271
    if (fd < 0) {
1272
        goto fail;
B
bellard 已提交
1273
    }
M
malc 已提交
1274
    DPRINTF("husb: opened %s\n", buf);
B
bellard 已提交
1275

1276 1277
    dev->bus_num = bus_num;
    dev->addr = addr;
1278
    strcpy(dev->port, port);
1279
    dev->fd = fd;
1280

1281 1282 1283
    /* read the device description */
    dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
    if (dev->descr_len <= 0) {
1284
        perror("husb: reading device data failed");
B
bellard 已提交
1285 1286
        goto fail;
    }
1287

1288
#ifdef DEBUG
B
bellard 已提交
1289
    {
1290 1291
        int x;
        printf("=== begin dumping device descriptor data ===\n");
1292
        for (x = 0; x < dev->descr_len; x++) {
1293
            printf("%02x ", dev->descr[x]);
1294
        }
1295
        printf("\n=== end dumping device descriptor data ===\n");
B
bellard 已提交
1296
    }
B
bellard 已提交
1297 1298
#endif

1299

1300 1301
    /* start unconfigured -- we'll wait for the guest to set a configuration */
    if (!usb_host_claim_interfaces(dev, 0)) {
1302
        goto fail;
1303
    }
B
bellard 已提交
1304

1305
    ret = usb_linux_update_endp_table(dev);
1306
    if (ret) {
B
bellard 已提交
1307
        goto fail;
1308
    }
1309

1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323
    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;
        }
1324
    }
1325
    dev->dev.speed = speed;
H
Hans de Goede 已提交
1326
    dev->dev.speedmask = (1 << speed);
1327 1328 1329
    if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
        dev->dev.speedmask |= USB_SPEED_MASK_FULL;
    }
1330

G
Gerd Hoffmann 已提交
1331
    trace_usb_host_open_success(bus_num, addr);
B
bellard 已提交
1332

1333
    if (!prod_name || prod_name[0] == '\0') {
1334
        snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
1335
                 "host:%d.%d", bus_num, addr);
1336
    } else {
1337
        pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
1338
                prod_name);
1339
    }
1340

1341 1342 1343 1344 1345
    ret = usb_device_attach(&dev->dev);
    if (ret) {
        goto fail;
    }

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

1349
    return 0;
1350

1351
fail:
G
Gerd Hoffmann 已提交
1352
    trace_usb_host_open_failure(bus_num, addr);
1353 1354 1355
    if (dev->fd != -1) {
        close(dev->fd);
        dev->fd = -1;
1356
    }
1357 1358 1359 1360 1361
    return -1;
}

static int usb_host_close(USBHostDevice *dev)
{
1362 1363
    int i;

G
Gerd Hoffmann 已提交
1364
    if (dev->fd == -1) {
1365
        return -1;
1366
    }
1367

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

1370 1371
    qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
    dev->closing = 1;
G
Gerd Hoffmann 已提交
1372
    for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
G
Gerd Hoffmann 已提交
1373 1374 1375 1376 1377
        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);
1378 1379
        }
    }
1380 1381
    async_complete(dev);
    dev->closing = 0;
G
Gerd Hoffmann 已提交
1382 1383 1384
    if (dev->dev.attached) {
        usb_device_detach(&dev->dev);
    }
1385
    usb_host_do_reset(dev);
1386 1387 1388 1389 1390
    close(dev->fd);
    dev->fd = -1;
    return 0;
}

1391
static void usb_host_exit_notifier(struct Notifier *n, void *data)
1392 1393 1394
{
    USBHostDevice *s = container_of(n, USBHostDevice, exit);

1395
    usb_host_release_port(s);
1396
    if (s->fd != -1) {
1397
        usb_host_do_reset(s);;
1398 1399 1400
    }
}

1401 1402 1403 1404 1405 1406
static int usb_host_initfn(USBDevice *dev)
{
    USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);

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

1409
    QTAILQ_INSERT_TAIL(&hostdevs, s, next);
1410 1411
    s->exit.notify = usb_host_exit_notifier;
    qemu_add_exit_notifier(&s->exit);
1412
    usb_host_auto_check(NULL);
G
Gerd Hoffmann 已提交
1413 1414

    if (s->match.bus_num != 0 && s->match.port != NULL) {
G
Gerd Hoffmann 已提交
1415
        usb_host_claim_port(s);
G
Gerd Hoffmann 已提交
1416
    }
1417
    add_boot_device_path(s->bootindex, &dev->qdev, NULL);
1418
    return 0;
B
bellard 已提交
1419
}
B
bellard 已提交
1420

G
Gerd Hoffmann 已提交
1421 1422 1423 1424 1425
static const VMStateDescription vmstate_usb_host = {
    .name = "usb-host",
    .unmigratable = 1,
};

1426 1427 1428 1429 1430 1431 1432
static Property usb_host_dev_properties[] = {
    DEFINE_PROP_UINT32("hostbus",  USBHostDevice, match.bus_num,    0),
    DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr,       0),
    DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
    DEFINE_PROP_HEX32("vendorid",  USBHostDevice, match.vendor_id,  0),
    DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
    DEFINE_PROP_UINT32("isobufs",  USBHostDevice, iso_urb_count,    4),
1433
    DEFINE_PROP_INT32("bootindex", USBHostDevice, bootindex,        -1),
1434 1435 1436
    DEFINE_PROP_END_OF_LIST(),
};

1437 1438
static void usb_host_class_initfn(ObjectClass *klass, void *data)
{
1439
    DeviceClass *dc = DEVICE_CLASS(klass);
1440 1441 1442 1443 1444 1445 1446 1447 1448
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);

    uc->init           = usb_host_initfn;
    uc->product_desc   = "USB Host Device";
    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;
1449 1450
    dc->vmsd = &vmstate_usb_host;
    dc->props = usb_host_dev_properties;
1451 1452
}

1453 1454 1455 1456 1457
static TypeInfo usb_host_dev_info = {
    .name          = "usb-host",
    .parent        = TYPE_USB_DEVICE,
    .instance_size = sizeof(USBHostDevice),
    .class_init    = usb_host_class_initfn,
1458 1459
};

A
Andreas Färber 已提交
1460
static void usb_host_register_types(void)
1461
{
1462
    type_register_static(&usb_host_dev_info);
1463
    usb_legacy_register("usb-host", "host", usb_host_device_open);
1464
}
A
Andreas Färber 已提交
1465 1466

type_init(usb_host_register_types)
1467

1468
USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
1469
{
1470
    struct USBAutoFilter filter;
1471 1472 1473
    USBDevice *dev;
    char *p;

1474
    dev = usb_create(bus, "usb-host");
1475

1476
    if (strstr(devname, "auto:")) {
1477
        if (parse_filter(devname, &filter) < 0) {
1478
            goto fail;
1479
        }
1480 1481
    } else {
        if ((p = strchr(devname, '.'))) {
1482 1483 1484 1485
            filter.bus_num    = strtoul(devname, NULL, 0);
            filter.addr       = strtoul(p + 1, NULL, 0);
            filter.vendor_id  = 0;
            filter.product_id = 0;
1486
        } else if ((p = strchr(devname, ':'))) {
1487 1488
            filter.bus_num    = 0;
            filter.addr       = 0;
1489
            filter.vendor_id  = strtoul(devname, NULL, 16);
1490
            filter.product_id = strtoul(p + 1, NULL, 16);
1491 1492 1493
        } else {
            goto fail;
        }
1494
    }
1495

1496 1497
    qdev_prop_set_uint32(&dev->qdev, "hostbus",   filter.bus_num);
    qdev_prop_set_uint32(&dev->qdev, "hostaddr",  filter.addr);
1498 1499
    qdev_prop_set_uint32(&dev->qdev, "vendorid",  filter.vendor_id);
    qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
K
Kevin Wolf 已提交
1500
    qdev_init_nofail(&dev->qdev);
1501
    return dev;
1502

1503 1504 1505
fail:
    qdev_free(&dev->qdev);
    return NULL;
1506
}
1507 1508 1509

int usb_host_device_close(const char *devname)
{
1510
#if 0
1511 1512 1513 1514
    char product_name[PRODUCT_NAME_SZ];
    int bus_num, addr;
    USBHostDevice *s;

1515
    if (strstr(devname, "auto:")) {
1516
        return usb_host_auto_del(devname);
1517 1518 1519
    }
    if (usb_host_find_device(&bus_num, &addr, product_name,
                                    sizeof(product_name), devname) < 0) {
1520
        return -1;
1521
    }
1522 1523
    s = hostdev_find(bus_num, addr);
    if (s) {
1524
        usb_device_delete_addr(s->bus_num, s->dev.addr);
1525 1526
        return 0;
    }
1527
#endif
1528 1529 1530

    return -1;
}
1531

1532 1533 1534 1535 1536 1537 1538 1539 1540 1541
/*
 * 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)
 */
1542 1543
static int usb_host_read_file(char *line, size_t line_size,
                              const char *device_file, const char *device_name)
1544 1545 1546 1547 1548
{
    FILE *f;
    int ret = 0;
    char filename[PATH_MAX];

1549
    snprintf(filename, PATH_MAX, "/sys/bus/usb/devices/%s/%s", device_name,
1550
             device_file);
1551 1552
    f = fopen(filename, "r");
    if (f) {
1553
        ret = fgets(line, line_size, f) != NULL;
1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566
        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
 */
1567
static int usb_host_scan(void *opaque, USBScanFunc *func)
1568
{
1569
    DIR *dir = NULL;
1570
    char line[1024];
1571
    int bus_num, addr, speed, class_id, product_id, vendor_id;
1572
    int ret = 0;
1573
    char port[MAX_PORTLEN];
1574 1575 1576
    char product_name[512];
    struct dirent *de;

1577
    dir = opendir("/sys/bus/usb/devices");
1578
    if (!dir) {
1579 1580
        perror("husb: opendir /sys/bus/usb/devices");
        fprintf(stderr, "husb: please make sure sysfs is mounted at /sys\n");
1581 1582 1583 1584 1585
        goto the_end;
    }

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

1590
            if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
1591
                goto the_end;
1592 1593
            }
            if (sscanf(line, "%d", &addr) != 1) {
1594
                goto the_end;
1595
            }
1596
            if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
1597
                                    de->d_name)) {
1598
                goto the_end;
1599 1600
            }
            if (sscanf(line, "%x", &class_id) != 1) {
1601
                goto the_end;
1602
            }
1603

1604 1605
            if (!usb_host_read_file(line, sizeof(line), "idVendor",
                                    de->d_name)) {
1606
                goto the_end;
1607 1608
            }
            if (sscanf(line, "%x", &vendor_id) != 1) {
1609
                goto the_end;
1610
            }
1611
            if (!usb_host_read_file(line, sizeof(line), "idProduct",
1612
                                    de->d_name)) {
1613
                goto the_end;
1614 1615
            }
            if (sscanf(line, "%x", &product_id) != 1) {
1616
                goto the_end;
1617
            }
1618 1619
            if (!usb_host_read_file(line, sizeof(line), "product",
                                    de->d_name)) {
1620 1621
                *product_name = 0;
            } else {
1622
                if (strlen(line) > 0) {
1623
                    line[strlen(line) - 1] = '\0';
1624
                }
1625 1626 1627
                pstrcpy(product_name, sizeof(product_name), line);
            }

1628
            if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
1629
                goto the_end;
1630
            }
1631 1632 1633
            if (!strcmp(line, "5000\n")) {
                speed = USB_SPEED_SUPER;
            } else if (!strcmp(line, "480\n")) {
1634
                speed = USB_SPEED_HIGH;
1635
            } else if (!strcmp(line, "1.5\n")) {
1636
                speed = USB_SPEED_LOW;
1637
            } else {
1638
                speed = USB_SPEED_FULL;
1639
            }
1640

1641
            ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
1642
                       product_id, product_name, speed);
1643
            if (ret) {
1644
                goto the_end;
1645
            }
1646 1647 1648
        }
    }
 the_end:
1649
    if (dir) {
1650
        closedir(dir);
1651
    }
1652 1653 1654
    return ret;
}

1655 1656
static QEMUTimer *usb_auto_timer;

G
Gerd Hoffmann 已提交
1657 1658
static int usb_host_auto_scan(void *opaque, int bus_num,
                              int addr, const char *port,
1659 1660
                              int class_id, int vendor_id, int product_id,
                              const char *product_name, int speed)
1661 1662
{
    struct USBAutoFilter *f;
1663
    struct USBHostDevice *s;
1664 1665 1666 1667 1668

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

1669 1670 1671
    QTAILQ_FOREACH(s, &hostdevs, next) {
        f = &s->match;

1672
        if (f->bus_num > 0 && f->bus_num != bus_num) {
1673
            continue;
1674 1675
        }
        if (f->addr > 0 && f->addr != addr) {
1676
            continue;
1677
        }
G
Gerd Hoffmann 已提交
1678 1679 1680
        if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) {
            continue;
        }
1681

1682
        if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
1683
            continue;
1684
        }
1685

1686
        if (f->product_id > 0 && f->product_id != product_id) {
1687
            continue;
1688
        }
1689
        /* We got a match */
G
Gerd Hoffmann 已提交
1690 1691 1692 1693
        s->seen++;
        if (s->errcount >= 3) {
            return 0;
        }
1694

1695
        /* Already attached ? */
1696
        if (s->fd != -1) {
1697
            return 0;
1698
        }
M
malc 已提交
1699
        DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
1700

G
Gerd Hoffmann 已提交
1701 1702 1703
        if (usb_host_open(s, bus_num, addr, port, product_name, speed) < 0) {
            s->errcount++;
        }
1704
        break;
1705 1706 1707 1708 1709
    }

    return 0;
}

1710
static void usb_host_auto_check(void *unused)
1711
{
1712 1713 1714
    struct USBHostDevice *s;
    int unconnected = 0;

1715
    usb_host_scan(NULL, usb_host_auto_scan);
1716 1717

    QTAILQ_FOREACH(s, &hostdevs, next) {
1718
        if (s->fd == -1) {
1719
            unconnected++;
1720
        }
G
Gerd Hoffmann 已提交
1721 1722 1723 1724
        if (s->seen == 0) {
            s->errcount = 0;
        }
        s->seen = 0;
1725 1726 1727 1728
    }

    if (unconnected == 0) {
        /* nothing to watch */
1729
        if (usb_auto_timer) {
1730
            qemu_del_timer(usb_auto_timer);
G
Gerd Hoffmann 已提交
1731
            trace_usb_host_auto_scan_disabled();
1732
        }
1733 1734 1735 1736
        return;
    }

    if (!usb_auto_timer) {
1737
        usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
1738
        if (!usb_auto_timer) {
1739
            return;
1740
        }
G
Gerd Hoffmann 已提交
1741
        trace_usb_host_auto_scan_enabled();
1742
    }
1743
    qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
1744 1745 1746
}

/*
1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757
 * 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.
1758
 */
1759
static int parse_filter(const char *spec, struct USBAutoFilter *f)
1760
{
1761 1762 1763 1764
    enum { BUS, DEV, VID, PID, DONE };
    const char *p = spec;
    int i;

1765 1766 1767 1768
    f->bus_num    = 0;
    f->addr       = 0;
    f->vendor_id  = 0;
    f->product_id = 0;
1769 1770

    for (i = BUS; i < DONE; i++) {
1771 1772 1773 1774
        p = strpbrk(p, ":.");
        if (!p) {
            break;
        }
1775 1776
        p++;

1777 1778 1779
        if (*p == '*') {
            continue;
        }
1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795
        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 已提交
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815
/**********************/
/* 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" },
1816
    { USB_CLASS_CSCID, "Smart Card" },
B
bellard 已提交
1817 1818 1819 1820 1821
    { USB_CLASS_CONTENT_SEC, "Content Security" },
    { -1, NULL }
};

static const char *usb_class_str(uint8_t class)
B
bellard 已提交
1822
{
B
bellard 已提交
1823 1824
    const struct usb_class_info *p;
    for(p = usb_class_info; p->class != -1; p++) {
1825
        if (p->class == class) {
B
bellard 已提交
1826
            break;
1827
        }
B
bellard 已提交
1828
    }
B
bellard 已提交
1829 1830 1831
    return p->class_name;
}

G
Gerd Hoffmann 已提交
1832 1833
static void usb_info_device(Monitor *mon, int bus_num,
                            int addr, const char *port,
1834
                            int class_id, int vendor_id, int product_id,
1835 1836
                            const char *product_name,
                            int speed)
B
bellard 已提交
1837 1838 1839 1840
{
    const char *class_str, *speed_str;

    switch(speed) {
1841 1842
    case USB_SPEED_LOW:
        speed_str = "1.5";
B
bellard 已提交
1843
        break;
1844 1845
    case USB_SPEED_FULL:
        speed_str = "12";
B
bellard 已提交
1846
        break;
1847 1848
    case USB_SPEED_HIGH:
        speed_str = "480";
B
bellard 已提交
1849
        break;
1850 1851 1852
    case USB_SPEED_SUPER:
        speed_str = "5000";
        break;
B
bellard 已提交
1853
    default:
1854
        speed_str = "?";
B
bellard 已提交
1855 1856 1857
        break;
    }

1858 1859
    monitor_printf(mon, "  Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
                   bus_num, addr, port, speed_str);
B
bellard 已提交
1860
    class_str = usb_class_str(class_id);
1861
    if (class_str) {
A
aliguori 已提交
1862
        monitor_printf(mon, "    %s:", class_str);
1863
    } else {
A
aliguori 已提交
1864
        monitor_printf(mon, "    Class %02x:", class_id);
1865
    }
A
aliguori 已提交
1866
    monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
1867
    if (product_name[0] != '\0') {
A
aliguori 已提交
1868
        monitor_printf(mon, ", %s", product_name);
1869
    }
A
aliguori 已提交
1870
    monitor_printf(mon, "\n");
B
bellard 已提交
1871 1872
}

1873
static int usb_host_info_device(void *opaque, int bus_num, int addr,
G
Gerd Hoffmann 已提交
1874
                                const char *path, int class_id,
1875
                                int vendor_id, int product_id,
B
bellard 已提交
1876 1877 1878
                                const char *product_name,
                                int speed)
{
1879 1880
    Monitor *mon = opaque;

1881
    usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
B
bellard 已提交
1882 1883 1884 1885
                    product_name, speed);
    return 0;
}

A
aliguori 已提交
1886
static void dec2str(int val, char *str, size_t size)
1887
{
1888
    if (val == 0) {
A
aliguori 已提交
1889
        snprintf(str, size, "*");
1890 1891 1892
    } else {
        snprintf(str, size, "%d", val);
    }
1893 1894
}

A
aliguori 已提交
1895
static void hex2str(int val, char *str, size_t size)
1896
{
1897
    if (val == 0) {
A
aliguori 已提交
1898
        snprintf(str, size, "*");
1899
    } else {
1900
        snprintf(str, size, "%04x", val);
1901
    }
1902 1903
}

A
aliguori 已提交
1904
void usb_host_info(Monitor *mon)
B
bellard 已提交
1905
{
1906
    struct USBAutoFilter *f;
1907
    struct USBHostDevice *s;
1908

1909
    usb_host_scan(mon, usb_host_info_device);
1910

1911
    if (QTAILQ_EMPTY(&hostdevs)) {
1912
        return;
1913 1914
    }

1915 1916
    monitor_printf(mon, "  Auto filters:\n");
    QTAILQ_FOREACH(s, &hostdevs, next) {
1917
        char bus[10], addr[10], vid[10], pid[10];
1918
        f = &s->match;
A
aliguori 已提交
1919 1920 1921 1922
        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 已提交
1923 1924
        monitor_printf(mon, "    Bus %s, Addr %s, Port %s, ID %s:%s\n",
                       bus, addr, f->port ? f->port : "*", vid, pid);
1925
    }
B
bellard 已提交
1926
}