bus.c 19.9 KB
Newer Older
G
Gerd Hoffmann 已提交
1 2 3
#include "hw/hw.h"
#include "hw/usb.h"
#include "hw/qdev.h"
4
#include "qemu/error-report.h"
5
#include "sysemu/sysemu.h"
6
#include "monitor/monitor.h"
7
#include "trace.h"
8 9

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

static char *usb_get_dev_path(DeviceState *dev);
12
static char *usb_get_fw_dev_path(DeviceState *qdev);
13
static void usb_qdev_unrealize(DeviceState *qdev, Error **errp);
14

15 16
static Property usb_props[] = {
    DEFINE_PROP_STRING("port", USBDevice, port_path),
G
Gerd Hoffmann 已提交
17
    DEFINE_PROP_STRING("serial", USBDevice, serial),
18 19
    DEFINE_PROP_BIT("full-path", USBDevice, flags,
                    USB_DEV_FLAG_FULL_PATH, true),
20 21
    DEFINE_PROP_BIT("msos-desc", USBDevice, flags,
                    USB_DEV_FLAG_MSOS_DESC_ENABLE, true),
22 23 24
    DEFINE_PROP_END_OF_LIST()
};

25 26 27
static void usb_bus_class_init(ObjectClass *klass, void *data)
{
    BusClass *k = BUS_CLASS(klass);
28
    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
29 30 31 32

    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;
33
    hc->unplug = qdev_simple_device_unplug_cb;
34 35 36 37 38 39 40
}

static const TypeInfo usb_bus_info = {
    .name = TYPE_USB_BUS,
    .parent = TYPE_BUS,
    .instance_size = sizeof(USBBus),
    .class_init = usb_bus_class_init,
41 42 43 44
    .interfaces = (InterfaceInfo[]) {
        { TYPE_HOTPLUG_HANDLER },
        { }
    }
45
};
46

47
static int next_usb_bus = 0;
B
Blue Swirl 已提交
48
static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
49

50 51 52 53 54 55 56 57 58
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;
    }
59 60
    if (dev->setup_index < 0 ||
        dev->setup_len < 0 ||
61 62
        dev->setup_index > dev->setup_len ||
        dev->setup_len > sizeof(dev->data_buf)) {
63 64
        return -EINVAL;
    }
65 66 67
    return 0;
}

G
Gerd Hoffmann 已提交
68 69 70 71
const VMStateDescription vmstate_usb_device = {
    .name = "USBDevice",
    .version_id = 1,
    .minimum_version_id = 1,
72
    .post_load = usb_device_post_load,
73
    .fields = (VMStateField[]) {
G
Gerd Hoffmann 已提交
74 75 76 77 78 79 80 81 82 83 84
        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(),
    }
};

85 86
void usb_bus_new(USBBus *bus, size_t bus_size,
                 USBBusOps *ops, DeviceState *host)
87
{
88
    qbus_create_inplace(bus, bus_size, TYPE_USB_BUS, host, NULL);
89
    qbus_set_bus_hotplug_handler(BUS(bus), &error_abort);
90
    bus->ops = ops;
91
    bus->busnr = next_usb_bus++;
B
Blue Swirl 已提交
92 93 94
    QTAILQ_INIT(&bus->free);
    QTAILQ_INIT(&bus->used);
    QTAILQ_INSERT_TAIL(&busses, bus, next);
95 96
}

G
Gonglei 已提交
97 98 99 100 101 102 103
void usb_bus_release(USBBus *bus)
{
    assert(next_usb_bus > 0);

    QTAILQ_REMOVE(&busses, bus, next);
}

104 105 106 107 108
USBBus *usb_bus_find(int busnr)
{
    USBBus *bus;

    if (-1 == busnr)
B
Blue Swirl 已提交
109 110
        return QTAILQ_FIRST(&busses);
    QTAILQ_FOREACH(bus, &busses, next) {
111 112 113 114 115 116
        if (bus->busnr == busnr)
            return bus;
    }
    return NULL;
}

117
static void usb_device_realize(USBDevice *dev, Error **errp)
118 119
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
120 121 122

    if (klass->realize) {
        klass->realize(dev, errp);
123 124 125
    }
}

G
Gerd Hoffmann 已提交
126
USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
127 128
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
G
Gerd Hoffmann 已提交
129 130
    if (klass->find_device) {
        return klass->find_device(dev, addr);
131
    }
G
Gerd Hoffmann 已提交
132
    return NULL;
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 159 160 161 162 163 164 165 166
}

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

167 168
void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
                               int value, int index, int length, uint8_t *data)
169 170 171
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->handle_control) {
172
        klass->handle_control(dev, p, request, value, index, length, data);
173 174 175
    }
}

176
void usb_device_handle_data(USBDevice *dev, USBPacket *p)
177 178 179
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->handle_data) {
180
        klass->handle_data(dev, p);
181 182 183 184 185 186 187 188 189 190 191 192
    }
}

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);
193 194 195
    if (dev->usb_desc) {
        return dev->usb_desc;
    }
196 197 198 199 200 201 202 203 204 205 206 207
    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);
    }
}

208 209 210 211 212 213 214 215
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);
    }
}

216 217 218 219 220 221 222 223
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);
    }
}

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
int usb_device_alloc_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps,
                             int streams)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->alloc_streams) {
        return klass->alloc_streams(dev, eps, nr_eps, streams);
    }
    return 0;
}

void usb_device_free_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->free_streams) {
        klass->free_streams(dev, eps, nr_eps);
    }
}

242
static void usb_qdev_realize(DeviceState *qdev, Error **errp)
243
{
244
    USBDevice *dev = USB_DEVICE(qdev);
245
    Error *local_err = NULL;
246

247 248
    pstrcpy(dev->product_desc, sizeof(dev->product_desc),
            usb_device_get_product_desc(dev));
G
Gerd Hoffmann 已提交
249
    dev->auto_attach = 1;
250
    QLIST_INIT(&dev->strings);
G
Gerd Hoffmann 已提交
251
    usb_ep_init(dev);
252 253 254 255 256

    usb_claim_port(dev, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
257
    }
258 259 260

    usb_device_realize(dev, &local_err);
    if (local_err) {
261
        usb_release_port(dev);
262 263
        error_propagate(errp, local_err);
        return;
264
    }
265

266
    if (dev->auto_attach) {
267 268 269 270 271
        usb_device_attach(dev, &local_err);
        if (local_err) {
            usb_qdev_unrealize(qdev, NULL);
            error_propagate(errp, local_err);
            return;
272
        }
273
    }
274 275
}

276
static void usb_qdev_unrealize(DeviceState *qdev, Error **errp)
277
{
278
    USBDevice *dev = USB_DEVICE(qdev);
279

280 281 282
    if (dev->attached) {
        usb_device_detach(dev);
    }
283
    usb_device_handle_destroy(dev);
284 285 286
    if (dev->port) {
        usb_release_port(dev);
    }
287 288
}

289
typedef struct LegacyUSBFactory
290
{
291 292
    const char *name;
    const char *usbdevice_name;
293
    USBDevice *(*usbdevice_init)(USBBus *bus, const char *params);
294
} LegacyUSBFactory;
295

296 297
static GSList *legacy_usb_factory;

298
void usb_legacy_register(const char *typename, const char *usbdevice_name,
299 300
                         USBDevice *(*usbdevice_init)(USBBus *bus,
                                                      const char *params))
301
{
302 303
    if (usbdevice_name) {
        LegacyUSBFactory *f = g_malloc0(sizeof(*f));
304
        f->name = typename;
305 306 307
        f->usbdevice_name = usbdevice_name;
        f->usbdevice_init = usbdevice_init;
        legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
308 309 310
    }
}

311
USBDevice *usb_create(USBBus *bus, const char *name)
312 313 314 315
{
    DeviceState *dev;

    dev = qdev_create(&bus->qbus, name);
316
    return USB_DEVICE(dev);
317
}
318

319 320
static USBDevice *usb_try_create_simple(USBBus *bus, const char *name,
                                        Error **errp)
321
{
322 323
    Error *err = NULL;
    USBDevice *dev;
324

325 326 327 328 329 330 331
    dev = USB_DEVICE(qdev_try_create(&bus->qbus, name));
    if (!dev) {
        error_setg(errp, "Failed to create USB device '%s'", name);
        return NULL;
    }
    object_property_set_bool(OBJECT(dev), true, "realized", &err);
    if (err) {
332 333 334
        error_propagate(errp, err);
        error_prepend(errp, "Failed to initialize USB device '%s': ",
                      name);
335
        object_unparent(OBJECT(dev));
336
        return NULL;
P
Paul Brook 已提交
337
    }
338 339 340
    return dev;
}

341 342
USBDevice *usb_create_simple(USBBus *bus, const char *name)
{
343
    return usb_try_create_simple(bus, name, &error_abort);
344 345
}

346 347
static void usb_fill_port(USBPort *port, void *opaque, int index,
                          USBPortOps *ops, int speedmask)
348
{
349 350 351
    port->opaque = opaque;
    port->index = index;
    port->ops = ops;
G
Gerd Hoffmann 已提交
352
    port->speedmask = speedmask;
353
    usb_port_location(port, NULL, index + 1);
354 355 356 357 358 359
}

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 已提交
360
    QTAILQ_INSERT_TAIL(&bus->free, port, next);
361 362 363
    bus->nfree++;
}

364 365 366 367
void usb_register_companion(const char *masterbus, USBPort *ports[],
                            uint32_t portcount, uint32_t firstport,
                            void *opaque, USBPortOps *ops, int speedmask,
                            Error **errp)
368 369 370 371 372 373 374 375 376 377
{
    USBBus *bus;
    int i;

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

378 379 380 381 382 383 384 385
    if (!bus) {
        error_setg(errp, "USB bus '%s' not found", masterbus);
        return;
    }
    if (!bus->ops->register_companion) {
        error_setg(errp, "Can't use USB bus '%s' as masterbus,"
                   " it doesn't support companion controllers",
                   masterbus);
386
        return;
387 388 389 390 391 392
    }

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

393
    bus->ops->register_companion(bus, ports, portcount, firstport, errp);
394 395
}

396 397 398 399 400
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 已提交
401
        downstream->hubcount = upstream->hubcount + 1;
402 403
    } else {
        snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
G
Gerd Hoffmann 已提交
404
        downstream->hubcount = 0;
405 406 407
    }
}

408 409
void usb_unregister_port(USBBus *bus, USBPort *port)
{
410 411 412
    if (port->dev) {
        object_unparent(OBJECT(port->dev));
    }
413 414 415 416
    QTAILQ_REMOVE(&bus->free, port, next);
    bus->nfree--;
}

417
void usb_claim_port(USBDevice *dev, Error **errp)
418 419 420 421
{
    USBBus *bus = usb_bus_from_device(dev);
    USBPort *port;

422 423
    assert(dev->port == NULL);

G
Gerd Hoffmann 已提交
424 425 426 427 428 429 430
    if (dev->port_path) {
        QTAILQ_FOREACH(port, &bus->free, next) {
            if (strcmp(port->path, dev->port_path) == 0) {
                break;
            }
        }
        if (port == NULL) {
431
            error_setg(errp, "usb port %s (bus %s) not found (in use?)",
432 433
                       dev->port_path, bus->qbus.name);
            return;
G
Gerd Hoffmann 已提交
434 435
        }
    } else {
436
        if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
437
            /* Create a new hub and chain it on */
438
            usb_try_create_simple(bus, "usb-hub", NULL);
439 440
        }
        if (bus->nfree == 0) {
441
            error_setg(errp, "tried to attach usb device %s to a bus "
442 443
                       "with no free ports", dev->product_desc);
            return;
444
        }
G
Gerd Hoffmann 已提交
445 446
        port = QTAILQ_FIRST(&bus->free);
    }
447
    trace_usb_port_claim(bus->busnr, port->path);
448

B
Blue Swirl 已提交
449
    QTAILQ_REMOVE(&bus->free, port, next);
450 451
    bus->nfree--;

452 453
    dev->port = port;
    port->dev = dev;
454

B
Blue Swirl 已提交
455
    QTAILQ_INSERT_TAIL(&bus->used, port, next);
456 457 458
    bus->nused++;
}

459
void usb_release_port(USBDevice *dev)
460 461
{
    USBBus *bus = usb_bus_from_device(dev);
462
    USBPort *port = dev->port;
463

464 465 466 467 468 469 470 471 472 473 474
    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++;
475 476
}

477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
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);
        }
    }
}

499
void usb_check_attach(USBDevice *dev, Error **errp)
500 501
{
    USBBus *bus = usb_bus_from_device(dev);
502
    USBPort *port = dev->port;
503
    char devspeed[32], portspeed[32];
504

505 506
    assert(port != NULL);
    assert(!dev->attached);
507 508 509 510
    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);
511 512

    if (!(port->speedmask & dev->speedmask)) {
513 514 515 516 517 518
        error_setg(errp, "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);
        return;
519
    }
520 521 522 523 524 525 526 527 528 529 530 531
}

void usb_device_attach(USBDevice *dev, Error **errp)
{
    USBPort *port = dev->port;
    Error *local_err = NULL;

    usb_check_attach(dev, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
532

533 534 535 536 537 538 539 540
    dev->attached++;
    usb_attach(port);
}

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

542 543 544
    assert(port != NULL);
    assert(dev->attached);
    trace_usb_port_detach(bus->busnr, port->path);
545

546 547
    usb_detach(port);
    dev->attached--;
548 549 550
    return 0;
}

551 552 553 554 555 556 557 558 559 560
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 已提交
561
    QTAILQ_FOREACH(port, &bus->used, next) {
562 563 564 565 566 567 568
        if (port->dev->addr == addr)
            break;
    }
    if (!port)
        return -1;
    dev = port->dev;

569
    object_unparent(OBJECT(dev));
570 571 572 573 574 575 576 577 578
    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",
579
        [ USB_SPEED_SUPER ] = "5000",
580 581 582 583 584 585 586 587
    };
    if (speed >= ARRAY_SIZE(txt))
        return "?";
    return txt[speed];
}

static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
{
588
    USBDevice *dev = USB_DEVICE(qdev);
589 590
    USBBus *bus = usb_bus_from_device(dev);

591
    monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
592
                   indent, "", bus->busnr, dev->addr,
593
                   dev->port ? dev->port->path : "-",
594
                   usb_speed(dev->speed), dev->product_desc,
595
                   dev->attached ? ", attached" : "");
596 597
}

598 599
static char *usb_get_dev_path(DeviceState *qdev)
{
600
    USBDevice *dev = USB_DEVICE(qdev);
G
Gerd Hoffmann 已提交
601 602 603
    DeviceState *hcd = qdev->parent_bus->parent;
    char *id = NULL;

604 605
    if (dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) {
        id = qdev_get_dev_path(hcd);
G
Gerd Hoffmann 已提交
606 607 608 609 610 611 612 613
    }
    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);
    }
614 615
}

616 617
static char *usb_get_fw_dev_path(DeviceState *qdev)
{
618
    USBDevice *dev = USB_DEVICE(qdev);
619
    char *fw_path, *in;
B
Blue Swirl 已提交
620
    ssize_t pos = 0, fw_len;
621 622
    long nr;

B
Blue Swirl 已提交
623
    fw_len = 32 + strlen(dev->port->path) * 6;
624
    fw_path = g_malloc(fw_len);
625
    in = dev->port->path;
B
Blue Swirl 已提交
626
    while (fw_len - pos > 0) {
627 628 629
        nr = strtol(in, &in, 10);
        if (in[0] == '.') {
            /* some hub between root port and device */
630
            pos += snprintf(fw_path + pos, fw_len - pos, "hub@%lx/", nr);
631 632 633
            in++;
        } else {
            /* the device itself */
634
            pos += snprintf(fw_path + pos, fw_len - pos, "%s@%lx",
B
Blue Swirl 已提交
635
                            qdev_fw_name(qdev), nr);
636 637 638 639 640 641
            break;
        }
    }
    return fw_path;
}

642
void hmp_info_usb(Monitor *mon, const QDict *qdict)
643 644 645 646 647
{
    USBBus *bus;
    USBDevice *dev;
    USBPort *port;

B
Blue Swirl 已提交
648
    if (QTAILQ_EMPTY(&busses)) {
649 650 651 652
        monitor_printf(mon, "USB support not enabled\n");
        return;
    }

B
Blue Swirl 已提交
653 654
    QTAILQ_FOREACH(bus, &busses, next) {
        QTAILQ_FOREACH(port, &bus->used, next) {
655 656 657
            dev = port->dev;
            if (!dev)
                continue;
658 659 660 661 662 663
            monitor_printf(mon, "  Device %d.%d, Port %s, Speed %s Mb/s, "
                           "Product %s%s%s\n",
                           bus->busnr, dev->addr, port->path,
                           usb_speed(dev->speed), dev->product_desc,
                           dev->qdev.id ? ", ID: " : "",
                           dev->qdev.id ?: "");
664 665 666 667
        }
    }
}

G
Gerd Hoffmann 已提交
668 669 670 671
/* handle legacy -usbdevice cmd line option */
USBDevice *usbdevice_create(const char *cmdline)
{
    USBBus *bus = usb_bus_find(-1 /* any */);
672
    LegacyUSBFactory *f = NULL;
673
    Error *err = NULL;
674
    GSList *i;
675 676
    char driver[32];
    const char *params;
G
Gerd Hoffmann 已提交
677
    int len;
678
    USBDevice *dev;
G
Gerd Hoffmann 已提交
679 680 681 682 683 684 685 686 687

    params = strchr(cmdline,':');
    if (params) {
        params++;
        len = params - cmdline;
        if (len > sizeof(driver))
            len = sizeof(driver);
        pstrcpy(driver, len, cmdline);
    } else {
688
        params = "";
G
Gerd Hoffmann 已提交
689 690 691
        pstrcpy(driver, sizeof(driver), cmdline);
    }

692 693 694 695 696
    for (i = legacy_usb_factory; i; i = i->next) {
        f = i->data;
        if (strcmp(f->usbdevice_name, driver) == 0) {
            break;
        }
G
Gerd Hoffmann 已提交
697
    }
698
    if (i == NULL) {
G
Gerd Hoffmann 已提交
699 700
#if 0
        /* no error because some drivers are not converted (yet) */
701
        error_report("usbdevice %s not found", driver);
G
Gerd Hoffmann 已提交
702 703 704 705
#endif
        return NULL;
    }

706 707 708 709 710 711 712
    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;
    }

713 714 715
    if (f->usbdevice_init) {
        dev = f->usbdevice_init(bus, params);
    } else {
T
TeLeMan 已提交
716
        if (*params) {
717
            error_report("usbdevice %s accepts no params", driver);
G
Gerd Hoffmann 已提交
718 719
            return NULL;
        }
720 721 722 723 724
        dev = usb_create(bus, f->name);
    }
    if (!dev) {
        error_report("Failed to create USB device '%s'", f->name);
        return NULL;
G
Gerd Hoffmann 已提交
725
    }
726 727
    object_property_set_bool(OBJECT(dev), true, "realized", &err);
    if (err) {
728 729
        error_reportf_err(err, "Failed to initialize USB device '%s': ",
                          f->name);
730 731 732 733
        object_unparent(OBJECT(dev));
        return NULL;
    }
    return dev;
G
Gerd Hoffmann 已提交
734
}
735

736 737 738
static void usb_device_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *k = DEVICE_CLASS(klass);
739
    k->bus_type = TYPE_USB_BUS;
740 741
    k->realize  = usb_qdev_realize;
    k->unrealize = usb_qdev_unrealize;
742
    k->props    = usb_props;
743 744
}

745
static const TypeInfo usb_device_type_info = {
746 747 748 749 750
    .name = TYPE_USB_DEVICE,
    .parent = TYPE_DEVICE,
    .instance_size = sizeof(USBDevice),
    .abstract = true,
    .class_size = sizeof(USBDeviceClass),
751
    .class_init = usb_device_class_init,
752 753
};

A
Andreas Färber 已提交
754
static void usb_register_types(void)
755
{
756
    type_register_static(&usb_bus_info);
757 758 759
    type_register_static(&usb_device_type_info);
}

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