usb-bus.c 14.9 KB
Newer Older
1 2 3
#include "hw.h"
#include "usb.h"
#include "qdev.h"
4 5
#include "sysemu.h"
#include "monitor.h"
6
#include "trace.h"
7 8

static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
9 10

static char *usb_get_dev_path(DeviceState *dev);
11
static char *usb_get_fw_dev_path(DeviceState *qdev);
12
static int usb_qdev_exit(DeviceState *qdev);
13 14

static struct BusInfo usb_bus_info = {
15 16 17
    .name      = "USB",
    .size      = sizeof(USBBus),
    .print_dev = usb_bus_dev_print,
18
    .get_dev_path = usb_get_dev_path,
19
    .get_fw_dev_path = usb_get_fw_dev_path,
G
Gerd Hoffmann 已提交
20 21 22 23
    .props      = (Property[]) {
        DEFINE_PROP_STRING("port", USBDevice, port_path),
        DEFINE_PROP_END_OF_LIST()
    },
24 25
};
static int next_usb_bus = 0;
B
Blue Swirl 已提交
26
static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
27

G
Gerd Hoffmann 已提交
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
const VMStateDescription vmstate_usb_device = {
    .name = "USBDevice",
    .version_id = 1,
    .minimum_version_id = 1,
    .fields = (VMStateField []) {
        VMSTATE_UINT8(addr, USBDevice),
        VMSTATE_INT32(state, USBDevice),
        VMSTATE_INT32(remote_wakeup, USBDevice),
        VMSTATE_INT32(setup_state, USBDevice),
        VMSTATE_INT32(setup_len, USBDevice),
        VMSTATE_INT32(setup_index, USBDevice),
        VMSTATE_UINT8_ARRAY(setup_buf, USBDevice, 8),
        VMSTATE_END_OF_LIST(),
    }
};

44
void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host)
45
{
46
    qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
47
    bus->ops = ops;
48
    bus->busnr = next_usb_bus++;
G
Gerd Hoffmann 已提交
49
    bus->qbus.allow_hotplug = 1; /* Yes, we can */
B
Blue Swirl 已提交
50 51 52
    QTAILQ_INIT(&bus->free);
    QTAILQ_INIT(&bus->used);
    QTAILQ_INSERT_TAIL(&busses, bus, next);
53 54 55 56 57 58 59
}

USBBus *usb_bus_find(int busnr)
{
    USBBus *bus;

    if (-1 == busnr)
B
Blue Swirl 已提交
60 61
        return QTAILQ_FIRST(&busses);
    QTAILQ_FOREACH(bus, &busses, next) {
62 63 64 65 66 67
        if (bus->busnr == busnr)
            return bus;
    }
    return NULL;
}

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
static int usb_device_init(USBDevice *dev)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->init) {
        return klass->init(dev);
    }
    return 0;
}

static void usb_device_handle_destroy(USBDevice *dev)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->handle_destroy) {
        klass->handle_destroy(dev);
    }
}

int usb_device_handle_packet(USBDevice *dev, USBPacket *p)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->handle_packet) {
        return klass->handle_packet(dev, p);
    }
    return -ENOSYS;
}

void usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->cancel_packet) {
        klass->cancel_packet(dev, p);
    }
}

void usb_device_handle_attach(USBDevice *dev)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->handle_attach) {
        klass->handle_attach(dev);
    }
}

void usb_device_handle_reset(USBDevice *dev)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->handle_reset) {
        klass->handle_reset(dev);
    }
}

int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
                              int value, int index, int length, uint8_t *data)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->handle_control) {
        return klass->handle_control(dev, p, request, value, index, length,
                                         data);
    }
    return -ENOSYS;
}

int usb_device_handle_data(USBDevice *dev, USBPacket *p)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->handle_data) {
        return klass->handle_data(dev, p);
    }
    return -ENOSYS;
}

const char *usb_device_get_product_desc(USBDevice *dev)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    return klass->product_desc;
}

const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    return klass->usb_desc;
}

void usb_device_set_interface(USBDevice *dev, int interface,
                              int alt_old, int alt_new)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->set_interface) {
        klass->set_interface(dev, interface, alt_old, alt_new);
    }
}

159 160
static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
{
161
    USBDevice *dev = USB_DEVICE(qdev);
162 163
    int rc;

164 165
    pstrcpy(dev->product_desc, sizeof(dev->product_desc),
            usb_device_get_product_desc(dev));
G
Gerd Hoffmann 已提交
166
    dev->auto_attach = 1;
167
    QLIST_INIT(&dev->strings);
G
Gerd Hoffmann 已提交
168
    usb_ep_init(dev);
169
    rc = usb_claim_port(dev);
170
    if (rc != 0) {
171
        return rc;
172
    }
173
    rc = usb_device_init(dev);
174
    if (rc != 0) {
175 176
        usb_release_port(dev);
        return rc;
177 178
    }
    if (dev->auto_attach) {
179
        rc = usb_device_attach(dev);
180
        if (rc != 0) {
181 182
            usb_qdev_exit(qdev);
            return rc;
183
        }
184
    }
185
    return 0;
186 187
}

188 189
static int usb_qdev_exit(DeviceState *qdev)
{
190
    USBDevice *dev = USB_DEVICE(qdev);
191

192 193 194
    if (dev->attached) {
        usb_device_detach(dev);
    }
195
    usb_device_handle_destroy(dev);
196 197 198
    if (dev->port) {
        usb_release_port(dev);
    }
199 200 201
    return 0;
}

202
typedef struct LegacyUSBFactory
203
{
204 205 206 207
    const char *name;
    const char *usbdevice_name;
    USBDevice *(*usbdevice_init)(const char *params);
} LegacyUSBFactory;
208

209 210
static GSList *legacy_usb_factory;

211 212
void usb_legacy_register(const char *typename, const char *usbdevice_name,
                         USBDevice *(*usbdevice_init)(const char *params))
213
{
214 215
    if (usbdevice_name) {
        LegacyUSBFactory *f = g_malloc0(sizeof(*f));
216
        f->name = typename;
217 218 219
        f->usbdevice_name = usbdevice_name;
        f->usbdevice_init = usbdevice_init;
        legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
220 221 222
    }
}

223 224 225 226 227 228 229 230 231
void usb_qdev_register(DeviceInfo *info)
{
    info->bus_info = &usb_bus_info;
    info->init     = usb_qdev_init;
    info->unplug   = qdev_simple_unplug_cb;
    info->exit     = usb_qdev_exit;
    qdev_register_subclass(info, TYPE_USB_DEVICE);
}

232
USBDevice *usb_create(USBBus *bus, const char *name)
233 234 235 236 237 238 239 240 241
{
    DeviceState *dev;

#if 1
    /* temporary stopgap until all usb is properly qdev-ified */
    if (!bus) {
        bus = usb_bus_find(-1);
        if (!bus)
            return NULL;
242
        error_report("%s: no bus specified, using \"%s\" for \"%s\"",
243 244 245 246 247
                __FUNCTION__, bus->qbus.name, name);
    }
#endif

    dev = qdev_create(&bus->qbus, name);
248
    return USB_DEVICE(dev);
249
}
250 251 252 253

USBDevice *usb_create_simple(USBBus *bus, const char *name)
{
    USBDevice *dev = usb_create(bus, name);
254 255
    int rc;

P
Paul Brook 已提交
256
    if (!dev) {
257
        error_report("Failed to create USB device '%s'", name);
258 259 260 261
        return NULL;
    }
    rc = qdev_init(&dev->qdev);
    if (rc < 0) {
262
        error_report("Failed to initialize USB device '%s'", name);
263
        return NULL;
P
Paul Brook 已提交
264
    }
265 266 267
    return dev;
}

268 269
static void usb_fill_port(USBPort *port, void *opaque, int index,
                          USBPortOps *ops, int speedmask)
270
{
271 272 273
    port->opaque = opaque;
    port->index = index;
    port->ops = ops;
G
Gerd Hoffmann 已提交
274
    port->speedmask = speedmask;
275
    usb_port_location(port, NULL, index + 1);
276 277 278 279 280 281
}

void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
                       USBPortOps *ops, int speedmask)
{
    usb_fill_port(port, opaque, index, ops, speedmask);
B
Blue Swirl 已提交
282
    QTAILQ_INSERT_TAIL(&bus->free, port, next);
283 284 285
    bus->nfree++;
}

286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
int usb_register_companion(const char *masterbus, USBPort *ports[],
                           uint32_t portcount, uint32_t firstport,
                           void *opaque, USBPortOps *ops, int speedmask)
{
    USBBus *bus;
    int i;

    QTAILQ_FOREACH(bus, &busses, next) {
        if (strcmp(bus->qbus.name, masterbus) == 0) {
            break;
        }
    }

    if (!bus || !bus->ops->register_companion) {
        qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
                      "an USB masterbus");
        if (bus) {
            error_printf_unless_qmp(
                "USB bus '%s' does not allow companion controllers\n",
                masterbus);
        }
        return -1;
    }

    for (i = 0; i < portcount; i++) {
        usb_fill_port(ports[i], opaque, i, ops, speedmask);
    }

    return bus->ops->register_companion(bus, ports, portcount, firstport);
}

317 318 319 320 321 322 323 324 325 326
void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
{
    if (upstream) {
        snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
                 upstream->path, portnr);
    } else {
        snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
    }
}

327 328 329 330 331 332 333 334
void usb_unregister_port(USBBus *bus, USBPort *port)
{
    if (port->dev)
        qdev_free(&port->dev->qdev);
    QTAILQ_REMOVE(&bus->free, port, next);
    bus->nfree--;
}

335
int usb_claim_port(USBDevice *dev)
336 337 338 339
{
    USBBus *bus = usb_bus_from_device(dev);
    USBPort *port;

340 341
    assert(dev->port == NULL);

G
Gerd Hoffmann 已提交
342 343 344 345 346 347 348
    if (dev->port_path) {
        QTAILQ_FOREACH(port, &bus->free, next) {
            if (strcmp(port->path, dev->port_path) == 0) {
                break;
            }
        }
        if (port == NULL) {
349
            error_report("Error: usb port %s (bus %s) not found (in use?)",
350
                         dev->port_path, bus->qbus.name);
351
            return -1;
G
Gerd Hoffmann 已提交
352 353
        }
    } else {
354
        if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
355 356 357 358 359
            /* Create a new hub and chain it on */
            usb_create_simple(bus, "usb-hub");
        }
        if (bus->nfree == 0) {
            error_report("Error: tried to attach usb device %s to a bus "
360
                         "with no free ports", dev->product_desc);
361 362
            return -1;
        }
G
Gerd Hoffmann 已提交
363 364
        port = QTAILQ_FIRST(&bus->free);
    }
365
    trace_usb_port_claim(bus->busnr, port->path);
366

B
Blue Swirl 已提交
367
    QTAILQ_REMOVE(&bus->free, port, next);
368 369
    bus->nfree--;

370 371
    dev->port = port;
    port->dev = dev;
372

B
Blue Swirl 已提交
373
    QTAILQ_INSERT_TAIL(&bus->used, port, next);
374
    bus->nused++;
375
    return 0;
376 377
}

378
void usb_release_port(USBDevice *dev)
379 380
{
    USBBus *bus = usb_bus_from_device(dev);
381
    USBPort *port = dev->port;
382

383 384 385 386 387 388 389 390 391 392 393
    assert(port != NULL);
    trace_usb_port_release(bus->busnr, port->path);

    QTAILQ_REMOVE(&bus->used, port, next);
    bus->nused--;

    dev->port = NULL;
    port->dev = NULL;

    QTAILQ_INSERT_TAIL(&bus->free, port, next);
    bus->nfree++;
394 395
}

396
int usb_device_attach(USBDevice *dev)
397 398
{
    USBBus *bus = usb_bus_from_device(dev);
399
    USBPort *port = dev->port;
400

401 402 403 404 405 406
    assert(port != NULL);
    assert(!dev->attached);
    trace_usb_port_attach(bus->busnr, port->path);

    if (!(port->speedmask & dev->speedmask)) {
        error_report("Warning: speed mismatch trying to attach "
407
                     "usb device %s to bus %s",
408
                     dev->product_desc, bus->qbus.name);
409 410 411
        return -1;
    }

412 413
    dev->attached++;
    usb_attach(port);
414

415 416 417 418 419 420 421
    return 0;
}

int usb_device_detach(USBDevice *dev)
{
    USBBus *bus = usb_bus_from_device(dev);
    USBPort *port = dev->port;
422

423 424 425
    assert(port != NULL);
    assert(dev->attached);
    trace_usb_port_detach(bus->busnr, port->path);
426

427 428
    usb_detach(port);
    dev->attached--;
429 430 431
    return 0;
}

432 433 434 435 436 437 438 439 440 441
int usb_device_delete_addr(int busnr, int addr)
{
    USBBus *bus;
    USBPort *port;
    USBDevice *dev;

    bus = usb_bus_find(busnr);
    if (!bus)
        return -1;

B
Blue Swirl 已提交
442
    QTAILQ_FOREACH(port, &bus->used, next) {
443 444 445 446 447 448 449
        if (port->dev->addr == addr)
            break;
    }
    if (!port)
        return -1;
    dev = port->dev;

450
    qdev_free(&dev->qdev);
451 452 453 454 455 456 457 458 459
    return 0;
}

static const char *usb_speed(unsigned int speed)
{
    static const char *txt[] = {
        [ USB_SPEED_LOW  ] = "1.5",
        [ USB_SPEED_FULL ] = "12",
        [ USB_SPEED_HIGH ] = "480",
460
        [ USB_SPEED_SUPER ] = "5000",
461 462 463 464 465 466 467 468
    };
    if (speed >= ARRAY_SIZE(txt))
        return "?";
    return txt[speed];
}

static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
{
469
    USBDevice *dev = USB_DEVICE(qdev);
470 471
    USBBus *bus = usb_bus_from_device(dev);

472
    monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
473
                   indent, "", bus->busnr, dev->addr,
474
                   dev->port ? dev->port->path : "-",
475
                   usb_speed(dev->speed), dev->product_desc,
476
                   dev->attached ? ", attached" : "");
477 478
}

479 480
static char *usb_get_dev_path(DeviceState *qdev)
{
481
    USBDevice *dev = USB_DEVICE(qdev);
482
    return g_strdup(dev->port->path);
483 484
}

485 486
static char *usb_get_fw_dev_path(DeviceState *qdev)
{
487
    USBDevice *dev = USB_DEVICE(qdev);
488
    char *fw_path, *in;
B
Blue Swirl 已提交
489
    ssize_t pos = 0, fw_len;
490 491
    long nr;

B
Blue Swirl 已提交
492
    fw_len = 32 + strlen(dev->port->path) * 6;
493
    fw_path = g_malloc(fw_len);
494
    in = dev->port->path;
B
Blue Swirl 已提交
495
    while (fw_len - pos > 0) {
496 497 498
        nr = strtol(in, &in, 10);
        if (in[0] == '.') {
            /* some hub between root port and device */
B
Blue Swirl 已提交
499
            pos += snprintf(fw_path + pos, fw_len - pos, "hub@%ld/", nr);
500 501 502
            in++;
        } else {
            /* the device itself */
B
Blue Swirl 已提交
503 504
            pos += snprintf(fw_path + pos, fw_len - pos, "%s@%ld",
                            qdev_fw_name(qdev), nr);
505 506 507 508 509 510
            break;
        }
    }
    return fw_path;
}

511 512 513 514 515 516
void usb_info(Monitor *mon)
{
    USBBus *bus;
    USBDevice *dev;
    USBPort *port;

B
Blue Swirl 已提交
517
    if (QTAILQ_EMPTY(&busses)) {
518 519 520 521
        monitor_printf(mon, "USB support not enabled\n");
        return;
    }

B
Blue Swirl 已提交
522 523
    QTAILQ_FOREACH(bus, &busses, next) {
        QTAILQ_FOREACH(port, &bus->used, next) {
524 525 526
            dev = port->dev;
            if (!dev)
                continue;
527 528
            monitor_printf(mon, "  Device %d.%d, Port %s, Speed %s Mb/s, Product %s\n",
                           bus->busnr, dev->addr, port->path, usb_speed(dev->speed),
529
                           dev->product_desc);
530 531 532 533
        }
    }
}

G
Gerd Hoffmann 已提交
534 535 536 537
/* handle legacy -usbdevice cmd line option */
USBDevice *usbdevice_create(const char *cmdline)
{
    USBBus *bus = usb_bus_find(-1 /* any */);
538 539
    LegacyUSBFactory *f = NULL;
    GSList *i;
540 541
    char driver[32];
    const char *params;
G
Gerd Hoffmann 已提交
542 543 544 545 546 547 548 549 550 551
    int len;

    params = strchr(cmdline,':');
    if (params) {
        params++;
        len = params - cmdline;
        if (len > sizeof(driver))
            len = sizeof(driver);
        pstrcpy(driver, len, cmdline);
    } else {
552
        params = "";
G
Gerd Hoffmann 已提交
553 554 555
        pstrcpy(driver, sizeof(driver), cmdline);
    }

556 557 558 559 560
    for (i = legacy_usb_factory; i; i = i->next) {
        f = i->data;
        if (strcmp(f->usbdevice_name, driver) == 0) {
            break;
        }
G
Gerd Hoffmann 已提交
561
    }
562
    if (i == NULL) {
G
Gerd Hoffmann 已提交
563 564
#if 0
        /* no error because some drivers are not converted (yet) */
565
        error_report("usbdevice %s not found", driver);
G
Gerd Hoffmann 已提交
566 567 568 569
#endif
        return NULL;
    }

570
    if (!f->usbdevice_init) {
T
TeLeMan 已提交
571
        if (*params) {
572
            error_report("usbdevice %s accepts no params", driver);
G
Gerd Hoffmann 已提交
573 574
            return NULL;
        }
575
        return usb_create_simple(bus, f->name);
G
Gerd Hoffmann 已提交
576
    }
577
    return f->usbdevice_init(params);
G
Gerd Hoffmann 已提交
578
}
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593

static TypeInfo usb_device_type_info = {
    .name = TYPE_USB_DEVICE,
    .parent = TYPE_DEVICE,
    .instance_size = sizeof(USBDevice),
    .abstract = true,
    .class_size = sizeof(USBDeviceClass),
};

static void usb_register_devices(void)
{
    type_register_static(&usb_device_type_info);
}

device_init(usb_register_devices);