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

static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
12 13

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

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

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

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

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

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

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

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

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

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

    QTAILQ_REMOVE(&busses, bus, next);
}

106 107 108 109 110
USBBus *usb_bus_find(int busnr)
{
    USBBus *bus;

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

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

    if (klass->realize) {
        klass->realize(dev, errp);
125 126 127
    }
}

G
Gerd Hoffmann 已提交
128
USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
129 130
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
G
Gerd Hoffmann 已提交
131 132
    if (klass->find_device) {
        return klass->find_device(dev, addr);
133
    }
G
Gerd Hoffmann 已提交
134
    return NULL;
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 167 168
}

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

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

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

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

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

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

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
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);
    }
}

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

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

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

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

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

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

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

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

298 299
static GSList *legacy_usb_factory;

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

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

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

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

327 328 329 330 331 332 333
    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) {
334 335 336
        error_propagate(errp, err);
        error_prepend(errp, "Failed to initialize USB device '%s': ",
                      name);
337
        object_unparent(OBJECT(dev));
338
        return NULL;
P
Paul Brook 已提交
339
    }
340 341 342
    return dev;
}

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

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

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

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

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

380 381 382 383 384 385 386 387
    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);
388
        return;
389 390 391 392 393 394
    }

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

395
    bus->ops->register_companion(bus, ports, portcount, firstport, errp);
396 397
}

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

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

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

424 425
    assert(dev->port == NULL);

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

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

454 455
    dev->port = port;
    port->dev = dev;
456

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

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

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

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

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

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

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

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

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

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

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

548 549
    usb_detach(port);
    dev->attached--;
550 551 552
    return 0;
}

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

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

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

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

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

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

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

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

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

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

B
Blue Swirl 已提交
655 656
    QTAILQ_FOREACH(bus, &busses, next) {
        QTAILQ_FOREACH(port, &bus->used, next) {
657 658 659
            dev = port->dev;
            if (!dev)
                continue;
660 661 662 663 664 665
            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 ?: "");
666 667 668 669
        }
    }
}

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

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

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

708 709 710 711 712 713 714
    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;
    }

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

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

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

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

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