bus.c 17.6 KB
Newer Older
G
Gerd Hoffmann 已提交
1 2 3
#include "hw/hw.h"
#include "hw/usb.h"
#include "hw/qdev.h"
4
#include "sysemu/sysemu.h"
5
#include "monitor/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 15
static Property usb_props[] = {
    DEFINE_PROP_STRING("port", USBDevice, port_path),
G
Gerd Hoffmann 已提交
16
    DEFINE_PROP_STRING("serial", USBDevice, serial),
17 18 19 20 21
    DEFINE_PROP_BIT("full-path", USBDevice, flags,
                    USB_DEV_FLAG_FULL_PATH, true),
    DEFINE_PROP_END_OF_LIST()
};

22 23 24 25 26 27 28 29 30 31 32 33 34 35
static void usb_bus_class_init(ObjectClass *klass, void *data)
{
    BusClass *k = BUS_CLASS(klass);

    k->print_dev = usb_bus_dev_print;
    k->get_dev_path = usb_get_dev_path;
    k->get_fw_dev_path = usb_get_fw_dev_path;
}

static const TypeInfo usb_bus_info = {
    .name = TYPE_USB_BUS,
    .parent = TYPE_BUS,
    .instance_size = sizeof(USBBus),
    .class_init = usb_bus_class_init,
36
};
37

38
static int next_usb_bus = 0;
B
Blue Swirl 已提交
39
static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
40

41 42 43 44 45 46 47 48 49
static int usb_device_post_load(void *opaque, int version_id)
{
    USBDevice *dev = opaque;

    if (dev->state == USB_STATE_NOTATTACHED) {
        dev->attached = 0;
    } else {
        dev->attached = 1;
    }
50 51 52 53
    if (dev->setup_index >= sizeof(dev->data_buf) ||
        dev->setup_len >= sizeof(dev->data_buf)) {
        return -EINVAL;
    }
54 55 56
    return 0;
}

G
Gerd Hoffmann 已提交
57 58 59 60
const VMStateDescription vmstate_usb_device = {
    .name = "USBDevice",
    .version_id = 1,
    .minimum_version_id = 1,
61
    .post_load = usb_device_post_load,
G
Gerd Hoffmann 已提交
62 63 64 65 66 67 68 69 70 71 72 73
    .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(),
    }
};

74 75
void usb_bus_new(USBBus *bus, size_t bus_size,
                 USBBusOps *ops, DeviceState *host)
76
{
77
    qbus_create_inplace(bus, bus_size, TYPE_USB_BUS, host, NULL);
78
    bus->ops = ops;
79
    bus->busnr = next_usb_bus++;
G
Gerd Hoffmann 已提交
80
    bus->qbus.allow_hotplug = 1; /* Yes, we can */
B
Blue Swirl 已提交
81 82 83
    QTAILQ_INIT(&bus->free);
    QTAILQ_INIT(&bus->used);
    QTAILQ_INSERT_TAIL(&busses, bus, next);
84 85 86 87 88 89 90
}

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

    if (-1 == busnr)
B
Blue Swirl 已提交
91 92
        return QTAILQ_FIRST(&busses);
    QTAILQ_FOREACH(bus, &busses, next) {
93 94 95 96 97 98
        if (bus->busnr == busnr)
            return bus;
    }
    return NULL;
}

99 100 101 102 103 104 105 106 107
static int usb_device_init(USBDevice *dev)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->init) {
        return klass->init(dev);
    }
    return 0;
}

G
Gerd Hoffmann 已提交
108
USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
109 110
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
G
Gerd Hoffmann 已提交
111 112
    if (klass->find_device) {
        return klass->find_device(dev, addr);
113
    }
G
Gerd Hoffmann 已提交
114
    return NULL;
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
}

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

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);
    }
}

149 150
void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
                               int value, int index, int length, uint8_t *data)
151 152 153
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->handle_control) {
154
        klass->handle_control(dev, p, request, value, index, length, data);
155 156 157
    }
}

158
void usb_device_handle_data(USBDevice *dev, USBPacket *p)
159 160 161
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->handle_data) {
162
        klass->handle_data(dev, p);
163 164 165 166 167 168 169 170 171 172 173 174
    }
}

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);
175 176 177
    if (dev->usb_desc) {
        return dev->usb_desc;
    }
178 179 180 181 182 183 184 185 186 187 188 189
    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);
    }
}

190 191 192 193 194 195 196 197
void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->flush_ep_queue) {
        klass->flush_ep_queue(dev, ep);
    }
}

198 199 200 201 202 203 204 205
void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->ep_stopped) {
        klass->ep_stopped(dev, ep);
    }
}

A
Anthony Liguori 已提交
206
static int usb_qdev_init(DeviceState *qdev)
207
{
208
    USBDevice *dev = USB_DEVICE(qdev);
209 210
    int rc;

211 212
    pstrcpy(dev->product_desc, sizeof(dev->product_desc),
            usb_device_get_product_desc(dev));
G
Gerd Hoffmann 已提交
213
    dev->auto_attach = 1;
214
    QLIST_INIT(&dev->strings);
G
Gerd Hoffmann 已提交
215
    usb_ep_init(dev);
216
    rc = usb_claim_port(dev);
217
    if (rc != 0) {
218
        return rc;
219
    }
220
    rc = usb_device_init(dev);
221
    if (rc != 0) {
222 223
        usb_release_port(dev);
        return rc;
224 225
    }
    if (dev->auto_attach) {
226
        rc = usb_device_attach(dev);
227
        if (rc != 0) {
228 229
            usb_qdev_exit(qdev);
            return rc;
230
        }
231
    }
232
    return 0;
233 234
}

235 236
static int usb_qdev_exit(DeviceState *qdev)
{
237
    USBDevice *dev = USB_DEVICE(qdev);
238

239 240 241
    if (dev->attached) {
        usb_device_detach(dev);
    }
242
    usb_device_handle_destroy(dev);
243 244 245
    if (dev->port) {
        usb_release_port(dev);
    }
246 247 248
    return 0;
}

249
typedef struct LegacyUSBFactory
250
{
251 252
    const char *name;
    const char *usbdevice_name;
253
    USBDevice *(*usbdevice_init)(USBBus *bus, const char *params);
254
} LegacyUSBFactory;
255

256 257
static GSList *legacy_usb_factory;

258
void usb_legacy_register(const char *typename, const char *usbdevice_name,
259 260
                         USBDevice *(*usbdevice_init)(USBBus *bus,
                                                      const char *params))
261
{
262 263
    if (usbdevice_name) {
        LegacyUSBFactory *f = g_malloc0(sizeof(*f));
264
        f->name = typename;
265 266 267
        f->usbdevice_name = usbdevice_name;
        f->usbdevice_init = usbdevice_init;
        legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
268 269 270
    }
}

271
USBDevice *usb_create(USBBus *bus, const char *name)
272 273 274 275
{
    DeviceState *dev;

    dev = qdev_create(&bus->qbus, name);
276
    return USB_DEVICE(dev);
277
}
278 279 280 281

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

P
Paul Brook 已提交
284
    if (!dev) {
285
        error_report("Failed to create USB device '%s'", name);
286 287 288 289
        return NULL;
    }
    rc = qdev_init(&dev->qdev);
    if (rc < 0) {
290
        error_report("Failed to initialize USB device '%s'", name);
291
        return NULL;
P
Paul Brook 已提交
292
    }
293 294 295
    return dev;
}

296 297
static void usb_fill_port(USBPort *port, void *opaque, int index,
                          USBPortOps *ops, int speedmask)
298
{
299 300 301
    port->opaque = opaque;
    port->index = index;
    port->ops = ops;
G
Gerd Hoffmann 已提交
302
    port->speedmask = speedmask;
303
    usb_port_location(port, NULL, index + 1);
304 305 306 307 308 309
}

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 已提交
310
    QTAILQ_INSERT_TAIL(&bus->free, port, next);
311 312 313
    bus->nfree++;
}

314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
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);
}

345 346 347 348 349
void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
{
    if (upstream) {
        snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
                 upstream->path, portnr);
G
Gerd Hoffmann 已提交
350
        downstream->hubcount = upstream->hubcount + 1;
351 352
    } else {
        snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
G
Gerd Hoffmann 已提交
353
        downstream->hubcount = 0;
354 355 356
    }
}

357 358
void usb_unregister_port(USBBus *bus, USBPort *port)
{
359 360 361
    if (port->dev) {
        object_unparent(OBJECT(port->dev));
    }
362 363 364 365
    QTAILQ_REMOVE(&bus->free, port, next);
    bus->nfree--;
}

366
int usb_claim_port(USBDevice *dev)
367 368 369 370
{
    USBBus *bus = usb_bus_from_device(dev);
    USBPort *port;

371 372
    assert(dev->port == NULL);

G
Gerd Hoffmann 已提交
373 374 375 376 377 378 379
    if (dev->port_path) {
        QTAILQ_FOREACH(port, &bus->free, next) {
            if (strcmp(port->path, dev->port_path) == 0) {
                break;
            }
        }
        if (port == NULL) {
380
            error_report("Error: usb port %s (bus %s) not found (in use?)",
381
                         dev->port_path, bus->qbus.name);
382
            return -1;
G
Gerd Hoffmann 已提交
383 384
        }
    } else {
385
        if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
386 387 388 389 390
            /* 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 "
391
                         "with no free ports", dev->product_desc);
392 393
            return -1;
        }
G
Gerd Hoffmann 已提交
394 395
        port = QTAILQ_FIRST(&bus->free);
    }
396
    trace_usb_port_claim(bus->busnr, port->path);
397

B
Blue Swirl 已提交
398
    QTAILQ_REMOVE(&bus->free, port, next);
399 400
    bus->nfree--;

401 402
    dev->port = port;
    port->dev = dev;
403

B
Blue Swirl 已提交
404
    QTAILQ_INSERT_TAIL(&bus->used, port, next);
405
    bus->nused++;
406
    return 0;
407 408
}

409
void usb_release_port(USBDevice *dev)
410 411
{
    USBBus *bus = usb_bus_from_device(dev);
412
    USBPort *port = dev->port;
413

414 415 416 417 418 419 420 421 422 423 424
    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++;
425 426
}

427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
static void usb_mask_to_str(char *dest, size_t size,
                            unsigned int speedmask)
{
    static const struct {
        unsigned int mask;
        const char *name;
    } speeds[] = {
        { .mask = USB_SPEED_MASK_FULL,  .name = "full"  },
        { .mask = USB_SPEED_MASK_HIGH,  .name = "high"  },
        { .mask = USB_SPEED_MASK_SUPER, .name = "super" },
    };
    int i, pos = 0;

    for (i = 0; i < ARRAY_SIZE(speeds); i++) {
        if (speeds[i].mask & speedmask) {
            pos += snprintf(dest + pos, size - pos, "%s%s",
                            pos ? "+" : "",
                            speeds[i].name);
        }
    }
}

449
int usb_device_attach(USBDevice *dev)
450 451
{
    USBBus *bus = usb_bus_from_device(dev);
452
    USBPort *port = dev->port;
453
    char devspeed[32], portspeed[32];
454

455 456
    assert(port != NULL);
    assert(!dev->attached);
457 458 459 460
    usb_mask_to_str(devspeed, sizeof(devspeed), dev->speedmask);
    usb_mask_to_str(portspeed, sizeof(portspeed), port->speedmask);
    trace_usb_port_attach(bus->busnr, port->path,
                          devspeed, portspeed);
461 462

    if (!(port->speedmask & dev->speedmask)) {
463 464 465 466 467
        error_report("Warning: speed mismatch trying to attach"
                     " usb device \"%s\" (%s speed)"
                     " to bus \"%s\", port \"%s\" (%s speed)",
                     dev->product_desc, devspeed,
                     bus->qbus.name, port->path, portspeed);
468 469 470
        return -1;
    }

471 472
    dev->attached++;
    usb_attach(port);
473

474 475 476 477 478 479 480
    return 0;
}

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

482 483 484
    assert(port != NULL);
    assert(dev->attached);
    trace_usb_port_detach(bus->busnr, port->path);
485

486 487
    usb_detach(port);
    dev->attached--;
488 489 490
    return 0;
}

491 492 493 494 495 496 497 498 499 500
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 已提交
501
    QTAILQ_FOREACH(port, &bus->used, next) {
502 503 504 505 506 507 508
        if (port->dev->addr == addr)
            break;
    }
    if (!port)
        return -1;
    dev = port->dev;

509
    object_unparent(OBJECT(dev));
510 511 512 513 514 515 516 517 518
    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",
519
        [ USB_SPEED_SUPER ] = "5000",
520 521 522 523 524 525 526 527
    };
    if (speed >= ARRAY_SIZE(txt))
        return "?";
    return txt[speed];
}

static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
{
528
    USBDevice *dev = USB_DEVICE(qdev);
529 530
    USBBus *bus = usb_bus_from_device(dev);

531
    monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
532
                   indent, "", bus->busnr, dev->addr,
533
                   dev->port ? dev->port->path : "-",
534
                   usb_speed(dev->speed), dev->product_desc,
535
                   dev->attached ? ", attached" : "");
536 537
}

538 539
static char *usb_get_dev_path(DeviceState *qdev)
{
540
    USBDevice *dev = USB_DEVICE(qdev);
G
Gerd Hoffmann 已提交
541 542 543
    DeviceState *hcd = qdev->parent_bus->parent;
    char *id = NULL;

544 545
    if (dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) {
        id = qdev_get_dev_path(hcd);
G
Gerd Hoffmann 已提交
546 547 548 549 550 551 552 553
    }
    if (id) {
        char *ret = g_strdup_printf("%s/%s", id, dev->port->path);
        g_free(id);
        return ret;
    } else {
        return g_strdup(dev->port->path);
    }
554 555
}

556 557
static char *usb_get_fw_dev_path(DeviceState *qdev)
{
558
    USBDevice *dev = USB_DEVICE(qdev);
559
    char *fw_path, *in;
B
Blue Swirl 已提交
560
    ssize_t pos = 0, fw_len;
561 562
    long nr;

B
Blue Swirl 已提交
563
    fw_len = 32 + strlen(dev->port->path) * 6;
564
    fw_path = g_malloc(fw_len);
565
    in = dev->port->path;
B
Blue Swirl 已提交
566
    while (fw_len - pos > 0) {
567 568 569
        nr = strtol(in, &in, 10);
        if (in[0] == '.') {
            /* some hub between root port and device */
B
Blue Swirl 已提交
570
            pos += snprintf(fw_path + pos, fw_len - pos, "hub@%ld/", nr);
571 572 573
            in++;
        } else {
            /* the device itself */
B
Blue Swirl 已提交
574 575
            pos += snprintf(fw_path + pos, fw_len - pos, "%s@%ld",
                            qdev_fw_name(qdev), nr);
576 577 578 579 580 581
            break;
        }
    }
    return fw_path;
}

582
void usb_info(Monitor *mon, const QDict *qdict)
583 584 585 586 587
{
    USBBus *bus;
    USBDevice *dev;
    USBPort *port;

B
Blue Swirl 已提交
588
    if (QTAILQ_EMPTY(&busses)) {
589 590 591 592
        monitor_printf(mon, "USB support not enabled\n");
        return;
    }

B
Blue Swirl 已提交
593 594
    QTAILQ_FOREACH(bus, &busses, next) {
        QTAILQ_FOREACH(port, &bus->used, next) {
595 596 597
            dev = port->dev;
            if (!dev)
                continue;
598 599
            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),
600
                           dev->product_desc);
601 602 603 604
        }
    }
}

G
Gerd Hoffmann 已提交
605 606 607 608
/* handle legacy -usbdevice cmd line option */
USBDevice *usbdevice_create(const char *cmdline)
{
    USBBus *bus = usb_bus_find(-1 /* any */);
609 610
    LegacyUSBFactory *f = NULL;
    GSList *i;
611 612
    char driver[32];
    const char *params;
G
Gerd Hoffmann 已提交
613 614 615 616 617 618 619 620 621 622
    int len;

    params = strchr(cmdline,':');
    if (params) {
        params++;
        len = params - cmdline;
        if (len > sizeof(driver))
            len = sizeof(driver);
        pstrcpy(driver, len, cmdline);
    } else {
623
        params = "";
G
Gerd Hoffmann 已提交
624 625 626
        pstrcpy(driver, sizeof(driver), cmdline);
    }

627 628 629 630 631
    for (i = legacy_usb_factory; i; i = i->next) {
        f = i->data;
        if (strcmp(f->usbdevice_name, driver) == 0) {
            break;
        }
G
Gerd Hoffmann 已提交
632
    }
633
    if (i == NULL) {
G
Gerd Hoffmann 已提交
634 635
#if 0
        /* no error because some drivers are not converted (yet) */
636
        error_report("usbdevice %s not found", driver);
G
Gerd Hoffmann 已提交
637 638 639 640
#endif
        return NULL;
    }

641 642 643 644 645 646 647
    if (!bus) {
        error_report("Error: no usb bus to attach usbdevice %s, "
                     "please try -machine usb=on and check that "
                     "the machine model supports USB", driver);
        return NULL;
    }

648
    if (!f->usbdevice_init) {
T
TeLeMan 已提交
649
        if (*params) {
650
            error_report("usbdevice %s accepts no params", driver);
G
Gerd Hoffmann 已提交
651 652
            return NULL;
        }
653
        return usb_create_simple(bus, f->name);
G
Gerd Hoffmann 已提交
654
    }
655
    return f->usbdevice_init(bus, params);
G
Gerd Hoffmann 已提交
656
}
657

658 659 660
static void usb_device_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *k = DEVICE_CLASS(klass);
661
    k->bus_type = TYPE_USB_BUS;
662 663 664
    k->init     = usb_qdev_init;
    k->unplug   = qdev_simple_unplug_cb;
    k->exit     = usb_qdev_exit;
665
    k->props    = usb_props;
666 667
}

668
static const TypeInfo usb_device_type_info = {
669 670 671 672 673
    .name = TYPE_USB_DEVICE,
    .parent = TYPE_DEVICE,
    .instance_size = sizeof(USBDevice),
    .abstract = true,
    .class_size = sizeof(USBDeviceClass),
674
    .class_init = usb_device_class_init,
675 676
};

A
Andreas Färber 已提交
677
static void usb_register_types(void)
678
{
679
    type_register_static(&usb_bus_info);
680 681 682
    type_register_static(&usb_device_type_info);
}

A
Andreas Färber 已提交
683
type_init(usb_register_types)