Statistics
| Branch: | Revision:

root / hw / usb-bus.c @ 71cf9e62

History | View | Annotate | Download (11.9 kB)

1
#include "hw.h"
2
#include "usb.h"
3
#include "qdev.h"
4
#include "sysemu.h"
5
#include "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

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

    
27
const VMStateDescription vmstate_usb_device = {
28
    .name = "USBDevice",
29
    .version_id = 1,
30
    .minimum_version_id = 1,
31
    .fields = (VMStateField []) {
32
        VMSTATE_UINT8(addr, USBDevice),
33
        VMSTATE_INT32(state, USBDevice),
34
        VMSTATE_INT32(remote_wakeup, USBDevice),
35
        VMSTATE_INT32(setup_state, USBDevice),
36
        VMSTATE_INT32(setup_len, USBDevice),
37
        VMSTATE_INT32(setup_index, USBDevice),
38
        VMSTATE_UINT8_ARRAY(setup_buf, USBDevice, 8),
39
        VMSTATE_END_OF_LIST(),
40
    }
41
};
42

    
43
void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host)
44
{
45
    qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
46
    bus->ops = ops;
47
    bus->busnr = next_usb_bus++;
48
    bus->qbus.allow_hotplug = 1; /* Yes, we can */
49
    QTAILQ_INIT(&bus->free);
50
    QTAILQ_INIT(&bus->used);
51
    QTAILQ_INSERT_TAIL(&busses, bus, next);
52
}
53

    
54
USBBus *usb_bus_find(int busnr)
55
{
56
    USBBus *bus;
57

    
58
    if (-1 == busnr)
59
        return QTAILQ_FIRST(&busses);
60
    QTAILQ_FOREACH(bus, &busses, next) {
61
        if (bus->busnr == busnr)
62
            return bus;
63
    }
64
    return NULL;
65
}
66

    
67
static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
68
{
69
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
70
    USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base);
71
    int rc;
72

    
73
    pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc);
74
    dev->info = info;
75
    dev->auto_attach = 1;
76
    QLIST_INIT(&dev->strings);
77
    rc = usb_claim_port(dev);
78
    if (rc == 0) {
79
        rc = dev->info->init(dev);
80
    }
81
    if (rc == 0 && dev->auto_attach) {
82
        rc = usb_device_attach(dev);
83
    }
84
    return rc;
85
}
86

    
87
static int usb_qdev_exit(DeviceState *qdev)
88
{
89
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
90

    
91
    if (dev->attached) {
92
        usb_device_detach(dev);
93
    }
94
    if (dev->info->handle_destroy) {
95
        dev->info->handle_destroy(dev);
96
    }
97
    if (dev->port) {
98
        usb_release_port(dev);
99
    }
100
    return 0;
101
}
102

    
103
void usb_qdev_register(USBDeviceInfo *info)
104
{
105
    info->qdev.bus_info = &usb_bus_info;
106
    info->qdev.init     = usb_qdev_init;
107
    info->qdev.unplug   = qdev_simple_unplug_cb;
108
    info->qdev.exit     = usb_qdev_exit;
109
    qdev_register(&info->qdev);
110
}
111

    
112
void usb_qdev_register_many(USBDeviceInfo *info)
113
{
114
    while (info->qdev.name) {
115
        usb_qdev_register(info);
116
        info++;
117
    }
118
}
119

    
120
USBDevice *usb_create(USBBus *bus, const char *name)
121
{
122
    DeviceState *dev;
123

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

    
135
    dev = qdev_create(&bus->qbus, name);
136
    return DO_UPCAST(USBDevice, qdev, dev);
137
}
138

    
139
USBDevice *usb_create_simple(USBBus *bus, const char *name)
140
{
141
    USBDevice *dev = usb_create(bus, name);
142
    if (!dev) {
143
        hw_error("Failed to create USB device '%s'\n", name);
144
    }
145
    qdev_init_nofail(&dev->qdev);
146
    return dev;
147
}
148

    
149
static void usb_fill_port(USBPort *port, void *opaque, int index,
150
                          USBPortOps *ops, int speedmask)
151
{
152
    port->opaque = opaque;
153
    port->index = index;
154
    port->ops = ops;
155
    port->speedmask = speedmask;
156
    usb_port_location(port, NULL, index + 1);
157
}
158

    
159
void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
160
                       USBPortOps *ops, int speedmask)
161
{
162
    usb_fill_port(port, opaque, index, ops, speedmask);
163
    QTAILQ_INSERT_TAIL(&bus->free, port, next);
164
    bus->nfree++;
165
}
166

    
167
int usb_register_companion(const char *masterbus, USBPort *ports[],
168
                           uint32_t portcount, uint32_t firstport,
169
                           void *opaque, USBPortOps *ops, int speedmask)
170
{
171
    USBBus *bus;
172
    int i;
173

    
174
    QTAILQ_FOREACH(bus, &busses, next) {
175
        if (strcmp(bus->qbus.name, masterbus) == 0) {
176
            break;
177
        }
178
    }
179

    
180
    if (!bus || !bus->ops->register_companion) {
181
        qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
182
                      "an USB masterbus");
183
        if (bus) {
184
            error_printf_unless_qmp(
185
                "USB bus '%s' does not allow companion controllers\n",
186
                masterbus);
187
        }
188
        return -1;
189
    }
190

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

    
195
    return bus->ops->register_companion(bus, ports, portcount, firstport);
196
}
197

    
198
void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
199
{
200
    if (upstream) {
201
        snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
202
                 upstream->path, portnr);
203
    } else {
204
        snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
205
    }
206
}
207

    
208
void usb_unregister_port(USBBus *bus, USBPort *port)
209
{
210
    if (port->dev)
211
        qdev_free(&port->dev->qdev);
212
    QTAILQ_REMOVE(&bus->free, port, next);
213
    bus->nfree--;
214
}
215

    
216
int usb_claim_port(USBDevice *dev)
217
{
218
    USBBus *bus = usb_bus_from_device(dev);
219
    USBPort *port;
220

    
221
    assert(dev->port == NULL);
222

    
223
    if (dev->port_path) {
224
        QTAILQ_FOREACH(port, &bus->free, next) {
225
            if (strcmp(port->path, dev->port_path) == 0) {
226
                break;
227
            }
228
        }
229
        if (port == NULL) {
230
            error_report("Error: usb port %s (bus %s) not found (in use?)\n",
231
                         dev->port_path, bus->qbus.name);
232
            return -1;
233
        }
234
    } else {
235
        if (bus->nfree == 1 && strcmp(dev->qdev.info->name, "usb-hub") != 0) {
236
            /* Create a new hub and chain it on */
237
            usb_create_simple(bus, "usb-hub");
238
        }
239
        if (bus->nfree == 0) {
240
            error_report("Error: tried to attach usb device %s to a bus "
241
                         "with no free ports\n", dev->product_desc);
242
            return -1;
243
        }
244
        port = QTAILQ_FIRST(&bus->free);
245
    }
246
    trace_usb_port_claim(bus->busnr, port->path);
247

    
248
    QTAILQ_REMOVE(&bus->free, port, next);
249
    bus->nfree--;
250

    
251
    dev->port = port;
252
    port->dev = dev;
253

    
254
    QTAILQ_INSERT_TAIL(&bus->used, port, next);
255
    bus->nused++;
256
    return 0;
257
}
258

    
259
void usb_release_port(USBDevice *dev)
260
{
261
    USBBus *bus = usb_bus_from_device(dev);
262
    USBPort *port = dev->port;
263

    
264
    assert(port != NULL);
265
    trace_usb_port_release(bus->busnr, port->path);
266

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

    
270
    dev->port = NULL;
271
    port->dev = NULL;
272

    
273
    QTAILQ_INSERT_TAIL(&bus->free, port, next);
274
    bus->nfree++;
275
}
276

    
277
int usb_device_attach(USBDevice *dev)
278
{
279
    USBBus *bus = usb_bus_from_device(dev);
280
    USBPort *port = dev->port;
281

    
282
    assert(port != NULL);
283
    assert(!dev->attached);
284
    trace_usb_port_attach(bus->busnr, port->path);
285

    
286
    if (!(port->speedmask & dev->speedmask)) {
287
        error_report("Warning: speed mismatch trying to attach "
288
                     "usb device %s to bus %s\n",
289
                     dev->product_desc, bus->qbus.name);
290
        return -1;
291
    }
292

    
293
    dev->attached++;
294
    usb_attach(port);
295

    
296
    return 0;
297
}
298

    
299
int usb_device_detach(USBDevice *dev)
300
{
301
    USBBus *bus = usb_bus_from_device(dev);
302
    USBPort *port = dev->port;
303

    
304
    assert(port != NULL);
305
    assert(dev->attached);
306
    trace_usb_port_detach(bus->busnr, port->path);
307

    
308
    usb_detach(port);
309
    dev->attached--;
310
    return 0;
311
}
312

    
313
int usb_device_delete_addr(int busnr, int addr)
314
{
315
    USBBus *bus;
316
    USBPort *port;
317
    USBDevice *dev;
318

    
319
    bus = usb_bus_find(busnr);
320
    if (!bus)
321
        return -1;
322

    
323
    QTAILQ_FOREACH(port, &bus->used, next) {
324
        if (port->dev->addr == addr)
325
            break;
326
    }
327
    if (!port)
328
        return -1;
329
    dev = port->dev;
330

    
331
    qdev_free(&dev->qdev);
332
    return 0;
333
}
334

    
335
static const char *usb_speed(unsigned int speed)
336
{
337
    static const char *txt[] = {
338
        [ USB_SPEED_LOW  ] = "1.5",
339
        [ USB_SPEED_FULL ] = "12",
340
        [ USB_SPEED_HIGH ] = "480",
341
        [ USB_SPEED_SUPER ] = "5000",
342
    };
343
    if (speed >= ARRAY_SIZE(txt))
344
        return "?";
345
    return txt[speed];
346
}
347

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

    
353
    monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
354
                   indent, "", bus->busnr, dev->addr,
355
                   dev->port ? dev->port->path : "-",
356
                   usb_speed(dev->speed), dev->product_desc,
357
                   dev->attached ? ", attached" : "");
358
}
359

    
360
static char *usb_get_dev_path(DeviceState *qdev)
361
{
362
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
363
    return g_strdup(dev->port->path);
364
}
365

    
366
static char *usb_get_fw_dev_path(DeviceState *qdev)
367
{
368
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
369
    char *fw_path, *in;
370
    ssize_t pos = 0, fw_len;
371
    long nr;
372

    
373
    fw_len = 32 + strlen(dev->port->path) * 6;
374
    fw_path = g_malloc(fw_len);
375
    in = dev->port->path;
376
    while (fw_len - pos > 0) {
377
        nr = strtol(in, &in, 10);
378
        if (in[0] == '.') {
379
            /* some hub between root port and device */
380
            pos += snprintf(fw_path + pos, fw_len - pos, "hub@%ld/", nr);
381
            in++;
382
        } else {
383
            /* the device itself */
384
            pos += snprintf(fw_path + pos, fw_len - pos, "%s@%ld",
385
                            qdev_fw_name(qdev), nr);
386
            break;
387
        }
388
    }
389
    return fw_path;
390
}
391

    
392
void usb_info(Monitor *mon)
393
{
394
    USBBus *bus;
395
    USBDevice *dev;
396
    USBPort *port;
397

    
398
    if (QTAILQ_EMPTY(&busses)) {
399
        monitor_printf(mon, "USB support not enabled\n");
400
        return;
401
    }
402

    
403
    QTAILQ_FOREACH(bus, &busses, next) {
404
        QTAILQ_FOREACH(port, &bus->used, next) {
405
            dev = port->dev;
406
            if (!dev)
407
                continue;
408
            monitor_printf(mon, "  Device %d.%d, Port %s, Speed %s Mb/s, Product %s\n",
409
                           bus->busnr, dev->addr, port->path, usb_speed(dev->speed),
410
                           dev->product_desc);
411
        }
412
    }
413
}
414

    
415
/* handle legacy -usbdevice cmd line option */
416
USBDevice *usbdevice_create(const char *cmdline)
417
{
418
    USBBus *bus = usb_bus_find(-1 /* any */);
419
    DeviceInfo *info;
420
    USBDeviceInfo *usb;
421
    char driver[32];
422
    const char *params;
423
    int len;
424

    
425
    params = strchr(cmdline,':');
426
    if (params) {
427
        params++;
428
        len = params - cmdline;
429
        if (len > sizeof(driver))
430
            len = sizeof(driver);
431
        pstrcpy(driver, len, cmdline);
432
    } else {
433
        params = "";
434
        pstrcpy(driver, sizeof(driver), cmdline);
435
    }
436

    
437
    for (info = device_info_list; info != NULL; info = info->next) {
438
        if (info->bus_info != &usb_bus_info)
439
            continue;
440
        usb = DO_UPCAST(USBDeviceInfo, qdev, info);
441
        if (usb->usbdevice_name == NULL)
442
            continue;
443
        if (strcmp(usb->usbdevice_name, driver) != 0)
444
            continue;
445
        break;
446
    }
447
    if (info == NULL) {
448
#if 0
449
        /* no error because some drivers are not converted (yet) */
450
        error_report("usbdevice %s not found", driver);
451
#endif
452
        return NULL;
453
    }
454

    
455
    if (!usb->usbdevice_init) {
456
        if (*params) {
457
            error_report("usbdevice %s accepts no params", driver);
458
            return NULL;
459
        }
460
        return usb_create_simple(bus, usb->qdev.name);
461
    }
462
    return usb->usbdevice_init(params);
463
}