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

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

static char *usb_get_dev_path(DeviceState *dev);
10
static char *usb_get_fw_dev_path(DeviceState *qdev);
11 12

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

G
Gerd Hoffmann 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
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(),
    }
};

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

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

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

static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
{
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
    USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base);
    int rc;

72
    pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc);
73
    dev->info = info;
G
Gerd Hoffmann 已提交
74
    dev->auto_attach = 1;
75
    QLIST_INIT(&dev->strings);
76
    rc = dev->info->init(dev);
G
Gerd Hoffmann 已提交
77
    if (rc == 0 && dev->auto_attach)
78
        rc = usb_device_attach(dev);
79 80 81
    return rc;
}

82 83 84 85
static int usb_qdev_exit(DeviceState *qdev)
{
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);

86 87 88
    if (dev->attached) {
        usb_device_detach(dev);
    }
89 90 91 92 93 94
    if (dev->info->handle_destroy) {
        dev->info->handle_destroy(dev);
    }
    return 0;
}

95 96 97 98
void usb_qdev_register(USBDeviceInfo *info)
{
    info->qdev.bus_info = &usb_bus_info;
    info->qdev.init     = usb_qdev_init;
G
Gerd Hoffmann 已提交
99
    info->qdev.unplug   = qdev_simple_unplug_cb;
100
    info->qdev.exit     = usb_qdev_exit;
101 102 103 104 105 106 107 108 109 110 111
    qdev_register(&info->qdev);
}

void usb_qdev_register_many(USBDeviceInfo *info)
{
    while (info->qdev.name) {
        usb_qdev_register(info);
        info++;
    }
}

112
USBDevice *usb_create(USBBus *bus, const char *name)
113 114 115 116 117 118 119 120 121
{
    DeviceState *dev;

#if 1
    /* temporary stopgap until all usb is properly qdev-ified */
    if (!bus) {
        bus = usb_bus_find(-1);
        if (!bus)
            return NULL;
122
        error_report("%s: no bus specified, using \"%s\" for \"%s\"\n",
123 124 125 126 127 128 129
                __FUNCTION__, bus->qbus.name, name);
    }
#endif

    dev = qdev_create(&bus->qbus, name);
    return DO_UPCAST(USBDevice, qdev, dev);
}
130 131 132 133

USBDevice *usb_create_simple(USBBus *bus, const char *name)
{
    USBDevice *dev = usb_create(bus, name);
P
Paul Brook 已提交
134 135 136
    if (!dev) {
        hw_error("Failed to create USB device '%s'\n", name);
    }
M
Markus Armbruster 已提交
137
    qdev_init_nofail(&dev->qdev);
138 139 140
    return dev;
}

141 142
static void usb_fill_port(USBPort *port, void *opaque, int index,
                          USBPortOps *ops, int speedmask)
143
{
144 145 146
    port->opaque = opaque;
    port->index = index;
    port->ops = ops;
G
Gerd Hoffmann 已提交
147
    port->speedmask = speedmask;
148
    usb_port_location(port, NULL, index + 1);
149 150 151 152 153 154
}

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 已提交
155
    QTAILQ_INSERT_TAIL(&bus->free, port, next);
156 157 158
    bus->nfree++;
}

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
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);
}

190 191 192 193 194 195 196 197 198 199
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);
    }
}

200 201 202 203 204 205 206 207
void usb_unregister_port(USBBus *bus, USBPort *port)
{
    if (port->dev)
        qdev_free(&port->dev->qdev);
    QTAILQ_REMOVE(&bus->free, port, next);
    bus->nfree--;
}

208
static int do_attach(USBDevice *dev)
209 210 211 212 213
{
    USBBus *bus = usb_bus_from_device(dev);
    USBPort *port;

    if (dev->attached) {
214
        error_report("Error: tried to attach usb device %s twice\n",
215
                dev->product_desc);
216
        return -1;
217
    }
218
    if (bus->nfree == 0) {
219
        error_report("Error: tried to attach usb device %s to a bus with no free ports\n",
220
                dev->product_desc);
221
        return -1;
222
    }
G
Gerd Hoffmann 已提交
223 224 225 226 227 228 229
    if (dev->port_path) {
        QTAILQ_FOREACH(port, &bus->free, next) {
            if (strcmp(port->path, dev->port_path) == 0) {
                break;
            }
        }
        if (port == NULL) {
230
            error_report("Error: usb port %s (bus %s) not found\n",
G
Gerd Hoffmann 已提交
231
                    dev->port_path, bus->qbus.name);
232
            return -1;
G
Gerd Hoffmann 已提交
233 234 235 236
        }
    } else {
        port = QTAILQ_FIRST(&bus->free);
    }
237 238 239 240 241
    if (!(port->speedmask & dev->speedmask)) {
        error_report("Warning: speed mismatch trying to attach usb device %s to bus %s\n",
                dev->product_desc, bus->qbus.name);
        return -1;
    }
242

G
Gerd Hoffmann 已提交
243
    dev->attached++;
B
Blue Swirl 已提交
244
    QTAILQ_REMOVE(&bus->free, port, next);
245 246 247 248
    bus->nfree--;

    usb_attach(port, dev);

B
Blue Swirl 已提交
249
    QTAILQ_INSERT_TAIL(&bus->used, port, next);
250
    bus->nused++;
251 252

    return 0;
253 254 255 256 257 258
}

int usb_device_attach(USBDevice *dev)
{
    USBBus *bus = usb_bus_from_device(dev);

G
Gerd Hoffmann 已提交
259 260 261
    if (bus->nfree == 1 && dev->port_path == NULL) {
        /* Create a new hub and chain it on
           (unless a physical port location is specified). */
262
        usb_create_simple(bus, "usb-hub");
263
    }
264
    return do_attach(dev);
265 266
}

267 268 269 270 271 272
int usb_device_detach(USBDevice *dev)
{
    USBBus *bus = usb_bus_from_device(dev);
    USBPort *port;

    if (!dev->attached) {
273
        error_report("Error: tried to detach unattached usb device %s\n",
274
                dev->product_desc);
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
        return -1;
    }
    dev->attached--;

    QTAILQ_FOREACH(port, &bus->used, next) {
        if (port->dev == dev)
            break;
    }
    assert(port != NULL);

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

    usb_attach(port, NULL);

    QTAILQ_INSERT_TAIL(&bus->free, port, next);
    bus->nfree++;
    return 0;
}

295 296 297 298 299 300 301 302 303 304
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 已提交
305
    QTAILQ_FOREACH(port, &bus->used, next) {
306 307 308 309 310 311 312
        if (port->dev->addr == addr)
            break;
    }
    if (!port)
        return -1;
    dev = port->dev;

313
    qdev_free(&dev->qdev);
314 315 316 317 318 319 320 321 322
    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",
323
        [ USB_SPEED_SUPER ] = "5000",
324 325 326 327 328 329 330 331 332 333 334
    };
    if (speed >= ARRAY_SIZE(txt))
        return "?";
    return txt[speed];
}

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

335
    monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
336
                   indent, "", bus->busnr, dev->addr,
337
                   dev->port ? dev->port->path : "-",
338
                   usb_speed(dev->speed), dev->product_desc,
339
                   dev->attached ? ", attached" : "");
340 341
}

342 343 344
static char *usb_get_dev_path(DeviceState *qdev)
{
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
345
    return g_strdup(dev->port->path);
346 347
}

348 349 350 351
static char *usb_get_fw_dev_path(DeviceState *qdev)
{
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
    char *fw_path, *in;
B
Blue Swirl 已提交
352
    ssize_t pos = 0, fw_len;
353 354
    long nr;

B
Blue Swirl 已提交
355
    fw_len = 32 + strlen(dev->port->path) * 6;
356
    fw_path = g_malloc(fw_len);
357
    in = dev->port->path;
B
Blue Swirl 已提交
358
    while (fw_len - pos > 0) {
359 360 361
        nr = strtol(in, &in, 10);
        if (in[0] == '.') {
            /* some hub between root port and device */
B
Blue Swirl 已提交
362
            pos += snprintf(fw_path + pos, fw_len - pos, "hub@%ld/", nr);
363 364 365
            in++;
        } else {
            /* the device itself */
B
Blue Swirl 已提交
366 367
            pos += snprintf(fw_path + pos, fw_len - pos, "%s@%ld",
                            qdev_fw_name(qdev), nr);
368 369 370 371 372 373
            break;
        }
    }
    return fw_path;
}

374 375 376 377 378 379
void usb_info(Monitor *mon)
{
    USBBus *bus;
    USBDevice *dev;
    USBPort *port;

B
Blue Swirl 已提交
380
    if (QTAILQ_EMPTY(&busses)) {
381 382 383 384
        monitor_printf(mon, "USB support not enabled\n");
        return;
    }

B
Blue Swirl 已提交
385 386
    QTAILQ_FOREACH(bus, &busses, next) {
        QTAILQ_FOREACH(port, &bus->used, next) {
387 388 389
            dev = port->dev;
            if (!dev)
                continue;
390 391
            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),
392
                           dev->product_desc);
393 394 395 396
        }
    }
}

G
Gerd Hoffmann 已提交
397 398 399 400 401 402
/* handle legacy -usbdevice cmd line option */
USBDevice *usbdevice_create(const char *cmdline)
{
    USBBus *bus = usb_bus_find(-1 /* any */);
    DeviceInfo *info;
    USBDeviceInfo *usb;
403 404
    char driver[32];
    const char *params;
G
Gerd Hoffmann 已提交
405 406 407 408 409 410 411 412 413 414
    int len;

    params = strchr(cmdline,':');
    if (params) {
        params++;
        len = params - cmdline;
        if (len > sizeof(driver))
            len = sizeof(driver);
        pstrcpy(driver, len, cmdline);
    } else {
415
        params = "";
G
Gerd Hoffmann 已提交
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
        pstrcpy(driver, sizeof(driver), cmdline);
    }

    for (info = device_info_list; info != NULL; info = info->next) {
        if (info->bus_info != &usb_bus_info)
            continue;
        usb = DO_UPCAST(USBDeviceInfo, qdev, info);
        if (usb->usbdevice_name == NULL)
            continue;
        if (strcmp(usb->usbdevice_name, driver) != 0)
            continue;
        break;
    }
    if (info == NULL) {
#if 0
        /* no error because some drivers are not converted (yet) */
432
        error_report("usbdevice %s not found", driver);
G
Gerd Hoffmann 已提交
433 434 435 436 437
#endif
        return NULL;
    }

    if (!usb->usbdevice_init) {
T
TeLeMan 已提交
438
        if (*params) {
439
            error_report("usbdevice %s accepts no params", driver);
G
Gerd Hoffmann 已提交
440 441 442 443 444 445
            return NULL;
        }
        return usb_create_simple(bus, usb->qdev.name);
    }
    return usb->usbdevice_init(params);
}