bus.c 17.4 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 50 51 52
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;
    }
    return 0;
}

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

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

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

    if (-1 == busnr)
B
Blue Swirl 已提交
87 88
        return QTAILQ_FIRST(&busses);
    QTAILQ_FOREACH(bus, &busses, next) {
89 90 91 92 93 94
        if (bus->busnr == busnr)
            return bus;
    }
    return NULL;
}

95 96 97 98 99 100 101 102 103
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 已提交
104
USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
105 106
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
G
Gerd Hoffmann 已提交
107 108
    if (klass->find_device) {
        return klass->find_device(dev, addr);
109
    }
G
Gerd Hoffmann 已提交
110
    return NULL;
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
}

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

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

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

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);
171 172 173
    if (dev->usb_desc) {
        return dev->usb_desc;
    }
174 175 176 177 178 179 180 181 182 183 184 185
    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);
    }
}

186 187 188 189 190 191 192 193
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);
    }
}

194 195 196 197 198 199 200 201
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 已提交
202
static int usb_qdev_init(DeviceState *qdev)
203
{
204
    USBDevice *dev = USB_DEVICE(qdev);
205 206
    int rc;

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

231 232
static int usb_qdev_exit(DeviceState *qdev)
{
233
    USBDevice *dev = USB_DEVICE(qdev);
234

235 236 237
    if (dev->attached) {
        usb_device_detach(dev);
    }
238
    usb_device_handle_destroy(dev);
239 240 241
    if (dev->port) {
        usb_release_port(dev);
    }
242 243 244
    return 0;
}

245
typedef struct LegacyUSBFactory
246
{
247 248
    const char *name;
    const char *usbdevice_name;
249
    USBDevice *(*usbdevice_init)(USBBus *bus, const char *params);
250
} LegacyUSBFactory;
251

252 253
static GSList *legacy_usb_factory;

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

267
USBDevice *usb_create(USBBus *bus, const char *name)
268 269 270 271
{
    DeviceState *dev;

    dev = qdev_create(&bus->qbus, name);
272
    return USB_DEVICE(dev);
273
}
274 275 276 277

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

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

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

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 已提交
306
    QTAILQ_INSERT_TAIL(&bus->free, port, next);
307 308 309
    bus->nfree++;
}

310 311 312 313 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
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);
}

341 342 343 344 345
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 已提交
346
        downstream->hubcount = upstream->hubcount + 1;
347 348
    } else {
        snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
G
Gerd Hoffmann 已提交
349
        downstream->hubcount = 0;
350 351 352
    }
}

353 354 355 356 357 358 359 360
void usb_unregister_port(USBBus *bus, USBPort *port)
{
    if (port->dev)
        qdev_free(&port->dev->qdev);
    QTAILQ_REMOVE(&bus->free, port, next);
    bus->nfree--;
}

361
int usb_claim_port(USBDevice *dev)
362 363 364 365
{
    USBBus *bus = usb_bus_from_device(dev);
    USBPort *port;

366 367
    assert(dev->port == NULL);

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

B
Blue Swirl 已提交
393
    QTAILQ_REMOVE(&bus->free, port, next);
394 395
    bus->nfree--;

396 397
    dev->port = port;
    port->dev = dev;
398

B
Blue Swirl 已提交
399
    QTAILQ_INSERT_TAIL(&bus->used, port, next);
400
    bus->nused++;
401
    return 0;
402 403
}

404
void usb_release_port(USBDevice *dev)
405 406
{
    USBBus *bus = usb_bus_from_device(dev);
407
    USBPort *port = dev->port;
408

409 410 411 412 413 414 415 416 417 418 419
    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++;
420 421
}

422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
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);
        }
    }
}

444
int usb_device_attach(USBDevice *dev)
445 446
{
    USBBus *bus = usb_bus_from_device(dev);
447
    USBPort *port = dev->port;
448
    char devspeed[32], portspeed[32];
449

450 451
    assert(port != NULL);
    assert(!dev->attached);
452 453 454 455
    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);
456 457

    if (!(port->speedmask & dev->speedmask)) {
458 459 460 461 462
        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);
463 464 465
        return -1;
    }

466 467
    dev->attached++;
    usb_attach(port);
468

469 470 471 472 473 474 475
    return 0;
}

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

477 478 479
    assert(port != NULL);
    assert(dev->attached);
    trace_usb_port_detach(bus->busnr, port->path);
480

481 482
    usb_detach(port);
    dev->attached--;
483 484 485
    return 0;
}

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

504
    qdev_free(&dev->qdev);
505 506 507 508 509 510 511 512 513
    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",
514
        [ USB_SPEED_SUPER ] = "5000",
515 516 517 518 519 520 521 522
    };
    if (speed >= ARRAY_SIZE(txt))
        return "?";
    return txt[speed];
}

static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
{
523
    USBDevice *dev = USB_DEVICE(qdev);
524 525
    USBBus *bus = usb_bus_from_device(dev);

526
    monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
527
                   indent, "", bus->busnr, dev->addr,
528
                   dev->port ? dev->port->path : "-",
529
                   usb_speed(dev->speed), dev->product_desc,
530
                   dev->attached ? ", attached" : "");
531 532
}

533 534
static char *usb_get_dev_path(DeviceState *qdev)
{
535
    USBDevice *dev = USB_DEVICE(qdev);
G
Gerd Hoffmann 已提交
536 537 538
    DeviceState *hcd = qdev->parent_bus->parent;
    char *id = NULL;

539 540
    if (dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) {
        id = qdev_get_dev_path(hcd);
G
Gerd Hoffmann 已提交
541 542 543 544 545 546 547 548
    }
    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);
    }
549 550
}

551 552
static char *usb_get_fw_dev_path(DeviceState *qdev)
{
553
    USBDevice *dev = USB_DEVICE(qdev);
554
    char *fw_path, *in;
B
Blue Swirl 已提交
555
    ssize_t pos = 0, fw_len;
556 557
    long nr;

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

577
void usb_info(Monitor *mon, const QDict *qdict)
578 579 580 581 582
{
    USBBus *bus;
    USBDevice *dev;
    USBPort *port;

B
Blue Swirl 已提交
583
    if (QTAILQ_EMPTY(&busses)) {
584 585 586 587
        monitor_printf(mon, "USB support not enabled\n");
        return;
    }

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

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

    params = strchr(cmdline,':');
    if (params) {
        params++;
        len = params - cmdline;
        if (len > sizeof(driver))
            len = sizeof(driver);
        pstrcpy(driver, len, cmdline);
    } else {
618
        params = "";
G
Gerd Hoffmann 已提交
619 620 621
        pstrcpy(driver, sizeof(driver), cmdline);
    }

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

636 637 638 639 640 641 642
    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;
    }

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

653 654 655
static void usb_device_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *k = DEVICE_CLASS(klass);
656
    k->bus_type = TYPE_USB_BUS;
657 658 659
    k->init     = usb_qdev_init;
    k->unplug   = qdev_simple_unplug_cb;
    k->exit     = usb_qdev_exit;
660
    k->props    = usb_props;
661 662
}

663
static const TypeInfo usb_device_type_info = {
664 665 666 667 668
    .name = TYPE_USB_DEVICE,
    .parent = TYPE_DEVICE,
    .instance_size = sizeof(USBDevice),
    .abstract = true,
    .class_size = sizeof(USBDeviceClass),
669
    .class_init = usb_device_class_init,
670 671
};

A
Andreas Färber 已提交
672
static void usb_register_types(void)
673
{
674
    type_register_static(&usb_bus_info);
675 676 677
    type_register_static(&usb_device_type_info);
}

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