Statistics
| Branch: | Revision:

root / hw / usb-bus.c @ f5654039

History | View | Annotate | Download (11.9 kB)

1 806b6024 Gerd Hoffmann
#include "hw.h"
2 806b6024 Gerd Hoffmann
#include "usb.h"
3 806b6024 Gerd Hoffmann
#include "qdev.h"
4 a5d2f727 Gerd Hoffmann
#include "sysemu.h"
5 a5d2f727 Gerd Hoffmann
#include "monitor.h"
6 891fb2cd Gerd Hoffmann
#include "trace.h"
7 a5d2f727 Gerd Hoffmann
8 a5d2f727 Gerd Hoffmann
static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
9 c7a2196a Gerd Hoffmann
10 c7a2196a Gerd Hoffmann
static char *usb_get_dev_path(DeviceState *dev);
11 70d31cb2 Gerd Hoffmann
static char *usb_get_fw_dev_path(DeviceState *qdev);
12 806b6024 Gerd Hoffmann
13 806b6024 Gerd Hoffmann
static struct BusInfo usb_bus_info = {
14 a5d2f727 Gerd Hoffmann
    .name      = "USB",
15 a5d2f727 Gerd Hoffmann
    .size      = sizeof(USBBus),
16 a5d2f727 Gerd Hoffmann
    .print_dev = usb_bus_dev_print,
17 c7a2196a Gerd Hoffmann
    .get_dev_path = usb_get_dev_path,
18 70d31cb2 Gerd Hoffmann
    .get_fw_dev_path = usb_get_fw_dev_path,
19 5f69076b Gerd Hoffmann
    .props      = (Property[]) {
20 5f69076b Gerd Hoffmann
        DEFINE_PROP_STRING("port", USBDevice, port_path),
21 5f69076b Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST()
22 5f69076b Gerd Hoffmann
    },
23 806b6024 Gerd Hoffmann
};
24 806b6024 Gerd Hoffmann
static int next_usb_bus = 0;
25 72cf2d4f Blue Swirl
static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
26 806b6024 Gerd Hoffmann
27 c1ecb40a Gerd Hoffmann
const VMStateDescription vmstate_usb_device = {
28 c1ecb40a Gerd Hoffmann
    .name = "USBDevice",
29 c1ecb40a Gerd Hoffmann
    .version_id = 1,
30 c1ecb40a Gerd Hoffmann
    .minimum_version_id = 1,
31 c1ecb40a Gerd Hoffmann
    .fields = (VMStateField []) {
32 c1ecb40a Gerd Hoffmann
        VMSTATE_UINT8(addr, USBDevice),
33 c1ecb40a Gerd Hoffmann
        VMSTATE_INT32(state, USBDevice),
34 c1ecb40a Gerd Hoffmann
        VMSTATE_INT32(remote_wakeup, USBDevice),
35 c1ecb40a Gerd Hoffmann
        VMSTATE_INT32(setup_state, USBDevice),
36 c1ecb40a Gerd Hoffmann
        VMSTATE_INT32(setup_len, USBDevice),
37 c1ecb40a Gerd Hoffmann
        VMSTATE_INT32(setup_index, USBDevice),
38 c1ecb40a Gerd Hoffmann
        VMSTATE_UINT8_ARRAY(setup_buf, USBDevice, 8),
39 c1ecb40a Gerd Hoffmann
        VMSTATE_END_OF_LIST(),
40 c1ecb40a Gerd Hoffmann
    }
41 c1ecb40a Gerd Hoffmann
};
42 c1ecb40a Gerd Hoffmann
43 07771f6f Gerd Hoffmann
void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host)
44 806b6024 Gerd Hoffmann
{
45 b2317837 Gerd Hoffmann
    qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
46 07771f6f Gerd Hoffmann
    bus->ops = ops;
47 806b6024 Gerd Hoffmann
    bus->busnr = next_usb_bus++;
48 ef816d83 Gerd Hoffmann
    bus->qbus.allow_hotplug = 1; /* Yes, we can */
49 72cf2d4f Blue Swirl
    QTAILQ_INIT(&bus->free);
50 72cf2d4f Blue Swirl
    QTAILQ_INIT(&bus->used);
51 72cf2d4f Blue Swirl
    QTAILQ_INSERT_TAIL(&busses, bus, next);
52 806b6024 Gerd Hoffmann
}
53 806b6024 Gerd Hoffmann
54 806b6024 Gerd Hoffmann
USBBus *usb_bus_find(int busnr)
55 806b6024 Gerd Hoffmann
{
56 806b6024 Gerd Hoffmann
    USBBus *bus;
57 806b6024 Gerd Hoffmann
58 806b6024 Gerd Hoffmann
    if (-1 == busnr)
59 72cf2d4f Blue Swirl
        return QTAILQ_FIRST(&busses);
60 72cf2d4f Blue Swirl
    QTAILQ_FOREACH(bus, &busses, next) {
61 806b6024 Gerd Hoffmann
        if (bus->busnr == busnr)
62 806b6024 Gerd Hoffmann
            return bus;
63 806b6024 Gerd Hoffmann
    }
64 806b6024 Gerd Hoffmann
    return NULL;
65 806b6024 Gerd Hoffmann
}
66 806b6024 Gerd Hoffmann
67 806b6024 Gerd Hoffmann
static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
68 806b6024 Gerd Hoffmann
{
69 806b6024 Gerd Hoffmann
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
70 806b6024 Gerd Hoffmann
    USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base);
71 806b6024 Gerd Hoffmann
    int rc;
72 806b6024 Gerd Hoffmann
73 06384698 Markus Armbruster
    pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc);
74 806b6024 Gerd Hoffmann
    dev->info = info;
75 61e094c0 Gerd Hoffmann
    dev->auto_attach = 1;
76 132a3f55 Gerd Hoffmann
    QLIST_INIT(&dev->strings);
77 891fb2cd Gerd Hoffmann
    rc = usb_claim_port(dev);
78 891fb2cd Gerd Hoffmann
    if (rc == 0) {
79 891fb2cd Gerd Hoffmann
        rc = dev->info->init(dev);
80 891fb2cd Gerd Hoffmann
    }
81 891fb2cd Gerd Hoffmann
    if (rc == 0 && dev->auto_attach) {
82 fa19bf83 Hans de Goede
        rc = usb_device_attach(dev);
83 891fb2cd Gerd Hoffmann
    }
84 806b6024 Gerd Hoffmann
    return rc;
85 806b6024 Gerd Hoffmann
}
86 806b6024 Gerd Hoffmann
87 a8e662b5 Gerd Hoffmann
static int usb_qdev_exit(DeviceState *qdev)
88 a8e662b5 Gerd Hoffmann
{
89 a8e662b5 Gerd Hoffmann
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
90 a8e662b5 Gerd Hoffmann
91 290a5c60 Hans de Goede
    if (dev->attached) {
92 290a5c60 Hans de Goede
        usb_device_detach(dev);
93 290a5c60 Hans de Goede
    }
94 a8e662b5 Gerd Hoffmann
    if (dev->info->handle_destroy) {
95 a8e662b5 Gerd Hoffmann
        dev->info->handle_destroy(dev);
96 a8e662b5 Gerd Hoffmann
    }
97 891fb2cd Gerd Hoffmann
    if (dev->port) {
98 891fb2cd Gerd Hoffmann
        usb_release_port(dev);
99 891fb2cd Gerd Hoffmann
    }
100 a8e662b5 Gerd Hoffmann
    return 0;
101 a8e662b5 Gerd Hoffmann
}
102 a8e662b5 Gerd Hoffmann
103 806b6024 Gerd Hoffmann
void usb_qdev_register(USBDeviceInfo *info)
104 806b6024 Gerd Hoffmann
{
105 806b6024 Gerd Hoffmann
    info->qdev.bus_info = &usb_bus_info;
106 806b6024 Gerd Hoffmann
    info->qdev.init     = usb_qdev_init;
107 ef816d83 Gerd Hoffmann
    info->qdev.unplug   = qdev_simple_unplug_cb;
108 a8e662b5 Gerd Hoffmann
    info->qdev.exit     = usb_qdev_exit;
109 806b6024 Gerd Hoffmann
    qdev_register(&info->qdev);
110 806b6024 Gerd Hoffmann
}
111 806b6024 Gerd Hoffmann
112 806b6024 Gerd Hoffmann
void usb_qdev_register_many(USBDeviceInfo *info)
113 806b6024 Gerd Hoffmann
{
114 806b6024 Gerd Hoffmann
    while (info->qdev.name) {
115 806b6024 Gerd Hoffmann
        usb_qdev_register(info);
116 806b6024 Gerd Hoffmann
        info++;
117 806b6024 Gerd Hoffmann
    }
118 806b6024 Gerd Hoffmann
}
119 806b6024 Gerd Hoffmann
120 a5d2f727 Gerd Hoffmann
USBDevice *usb_create(USBBus *bus, const char *name)
121 806b6024 Gerd Hoffmann
{
122 806b6024 Gerd Hoffmann
    DeviceState *dev;
123 806b6024 Gerd Hoffmann
124 806b6024 Gerd Hoffmann
#if 1
125 806b6024 Gerd Hoffmann
    /* temporary stopgap until all usb is properly qdev-ified */
126 806b6024 Gerd Hoffmann
    if (!bus) {
127 806b6024 Gerd Hoffmann
        bus = usb_bus_find(-1);
128 806b6024 Gerd Hoffmann
        if (!bus)
129 806b6024 Gerd Hoffmann
            return NULL;
130 fa19bf83 Hans de Goede
        error_report("%s: no bus specified, using \"%s\" for \"%s\"\n",
131 806b6024 Gerd Hoffmann
                __FUNCTION__, bus->qbus.name, name);
132 806b6024 Gerd Hoffmann
    }
133 806b6024 Gerd Hoffmann
#endif
134 806b6024 Gerd Hoffmann
135 806b6024 Gerd Hoffmann
    dev = qdev_create(&bus->qbus, name);
136 806b6024 Gerd Hoffmann
    return DO_UPCAST(USBDevice, qdev, dev);
137 806b6024 Gerd Hoffmann
}
138 a5d2f727 Gerd Hoffmann
139 a5d2f727 Gerd Hoffmann
USBDevice *usb_create_simple(USBBus *bus, const char *name)
140 a5d2f727 Gerd Hoffmann
{
141 a5d2f727 Gerd Hoffmann
    USBDevice *dev = usb_create(bus, name);
142 d44168ff Paul Brook
    if (!dev) {
143 d44168ff Paul Brook
        hw_error("Failed to create USB device '%s'\n", name);
144 d44168ff Paul Brook
    }
145 e23a1b33 Markus Armbruster
    qdev_init_nofail(&dev->qdev);
146 a5d2f727 Gerd Hoffmann
    return dev;
147 a5d2f727 Gerd Hoffmann
}
148 a5d2f727 Gerd Hoffmann
149 090ac642 Hans de Goede
static void usb_fill_port(USBPort *port, void *opaque, int index,
150 090ac642 Hans de Goede
                          USBPortOps *ops, int speedmask)
151 a5d2f727 Gerd Hoffmann
{
152 a5d2f727 Gerd Hoffmann
    port->opaque = opaque;
153 a5d2f727 Gerd Hoffmann
    port->index = index;
154 0d86d2be Gerd Hoffmann
    port->ops = ops;
155 843d4e0c Gerd Hoffmann
    port->speedmask = speedmask;
156 3631e6c8 Hans de Goede
    usb_port_location(port, NULL, index + 1);
157 090ac642 Hans de Goede
}
158 090ac642 Hans de Goede
159 090ac642 Hans de Goede
void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
160 090ac642 Hans de Goede
                       USBPortOps *ops, int speedmask)
161 090ac642 Hans de Goede
{
162 090ac642 Hans de Goede
    usb_fill_port(port, opaque, index, ops, speedmask);
163 72cf2d4f Blue Swirl
    QTAILQ_INSERT_TAIL(&bus->free, port, next);
164 a5d2f727 Gerd Hoffmann
    bus->nfree++;
165 a5d2f727 Gerd Hoffmann
}
166 a5d2f727 Gerd Hoffmann
167 ae60fea9 Hans de Goede
int usb_register_companion(const char *masterbus, USBPort *ports[],
168 ae60fea9 Hans de Goede
                           uint32_t portcount, uint32_t firstport,
169 ae60fea9 Hans de Goede
                           void *opaque, USBPortOps *ops, int speedmask)
170 ae60fea9 Hans de Goede
{
171 ae60fea9 Hans de Goede
    USBBus *bus;
172 ae60fea9 Hans de Goede
    int i;
173 ae60fea9 Hans de Goede
174 ae60fea9 Hans de Goede
    QTAILQ_FOREACH(bus, &busses, next) {
175 ae60fea9 Hans de Goede
        if (strcmp(bus->qbus.name, masterbus) == 0) {
176 ae60fea9 Hans de Goede
            break;
177 ae60fea9 Hans de Goede
        }
178 ae60fea9 Hans de Goede
    }
179 ae60fea9 Hans de Goede
180 ae60fea9 Hans de Goede
    if (!bus || !bus->ops->register_companion) {
181 ae60fea9 Hans de Goede
        qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
182 ae60fea9 Hans de Goede
                      "an USB masterbus");
183 ae60fea9 Hans de Goede
        if (bus) {
184 ae60fea9 Hans de Goede
            error_printf_unless_qmp(
185 ae60fea9 Hans de Goede
                "USB bus '%s' does not allow companion controllers\n",
186 ae60fea9 Hans de Goede
                masterbus);
187 ae60fea9 Hans de Goede
        }
188 ae60fea9 Hans de Goede
        return -1;
189 ae60fea9 Hans de Goede
    }
190 ae60fea9 Hans de Goede
191 ae60fea9 Hans de Goede
    for (i = 0; i < portcount; i++) {
192 ae60fea9 Hans de Goede
        usb_fill_port(ports[i], opaque, i, ops, speedmask);
193 ae60fea9 Hans de Goede
    }
194 ae60fea9 Hans de Goede
195 ae60fea9 Hans de Goede
    return bus->ops->register_companion(bus, ports, portcount, firstport);
196 ae60fea9 Hans de Goede
}
197 ae60fea9 Hans de Goede
198 c7a2196a Gerd Hoffmann
void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
199 c7a2196a Gerd Hoffmann
{
200 c7a2196a Gerd Hoffmann
    if (upstream) {
201 c7a2196a Gerd Hoffmann
        snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
202 c7a2196a Gerd Hoffmann
                 upstream->path, portnr);
203 c7a2196a Gerd Hoffmann
    } else {
204 c7a2196a Gerd Hoffmann
        snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
205 c7a2196a Gerd Hoffmann
    }
206 c7a2196a Gerd Hoffmann
}
207 c7a2196a Gerd Hoffmann
208 a8e662b5 Gerd Hoffmann
void usb_unregister_port(USBBus *bus, USBPort *port)
209 a8e662b5 Gerd Hoffmann
{
210 a8e662b5 Gerd Hoffmann
    if (port->dev)
211 a8e662b5 Gerd Hoffmann
        qdev_free(&port->dev->qdev);
212 a8e662b5 Gerd Hoffmann
    QTAILQ_REMOVE(&bus->free, port, next);
213 a8e662b5 Gerd Hoffmann
    bus->nfree--;
214 a8e662b5 Gerd Hoffmann
}
215 a8e662b5 Gerd Hoffmann
216 891fb2cd Gerd Hoffmann
int usb_claim_port(USBDevice *dev)
217 a5d2f727 Gerd Hoffmann
{
218 a5d2f727 Gerd Hoffmann
    USBBus *bus = usb_bus_from_device(dev);
219 a5d2f727 Gerd Hoffmann
    USBPort *port;
220 a5d2f727 Gerd Hoffmann
221 891fb2cd Gerd Hoffmann
    assert(dev->port == NULL);
222 891fb2cd Gerd Hoffmann
223 5f69076b Gerd Hoffmann
    if (dev->port_path) {
224 5f69076b Gerd Hoffmann
        QTAILQ_FOREACH(port, &bus->free, next) {
225 5f69076b Gerd Hoffmann
            if (strcmp(port->path, dev->port_path) == 0) {
226 5f69076b Gerd Hoffmann
                break;
227 5f69076b Gerd Hoffmann
            }
228 5f69076b Gerd Hoffmann
        }
229 5f69076b Gerd Hoffmann
        if (port == NULL) {
230 891fb2cd Gerd Hoffmann
            error_report("Error: usb port %s (bus %s) not found (in use?)\n",
231 891fb2cd Gerd Hoffmann
                         dev->port_path, bus->qbus.name);
232 fa19bf83 Hans de Goede
            return -1;
233 5f69076b Gerd Hoffmann
        }
234 5f69076b Gerd Hoffmann
    } else {
235 891fb2cd Gerd Hoffmann
        if (bus->nfree == 1 && strcmp(dev->qdev.info->name, "usb-hub") != 0) {
236 891fb2cd Gerd Hoffmann
            /* Create a new hub and chain it on */
237 891fb2cd Gerd Hoffmann
            usb_create_simple(bus, "usb-hub");
238 891fb2cd Gerd Hoffmann
        }
239 891fb2cd Gerd Hoffmann
        if (bus->nfree == 0) {
240 891fb2cd Gerd Hoffmann
            error_report("Error: tried to attach usb device %s to a bus "
241 891fb2cd Gerd Hoffmann
                         "with no free ports\n", dev->product_desc);
242 891fb2cd Gerd Hoffmann
            return -1;
243 891fb2cd Gerd Hoffmann
        }
244 5f69076b Gerd Hoffmann
        port = QTAILQ_FIRST(&bus->free);
245 5f69076b Gerd Hoffmann
    }
246 891fb2cd Gerd Hoffmann
    trace_usb_port_claim(bus->busnr, port->path);
247 a5d2f727 Gerd Hoffmann
248 72cf2d4f Blue Swirl
    QTAILQ_REMOVE(&bus->free, port, next);
249 a5d2f727 Gerd Hoffmann
    bus->nfree--;
250 a5d2f727 Gerd Hoffmann
251 891fb2cd Gerd Hoffmann
    dev->port = port;
252 891fb2cd Gerd Hoffmann
    port->dev = dev;
253 a5d2f727 Gerd Hoffmann
254 72cf2d4f Blue Swirl
    QTAILQ_INSERT_TAIL(&bus->used, port, next);
255 a5d2f727 Gerd Hoffmann
    bus->nused++;
256 fa19bf83 Hans de Goede
    return 0;
257 a5d2f727 Gerd Hoffmann
}
258 a5d2f727 Gerd Hoffmann
259 891fb2cd Gerd Hoffmann
void usb_release_port(USBDevice *dev)
260 a5d2f727 Gerd Hoffmann
{
261 a5d2f727 Gerd Hoffmann
    USBBus *bus = usb_bus_from_device(dev);
262 891fb2cd Gerd Hoffmann
    USBPort *port = dev->port;
263 a5d2f727 Gerd Hoffmann
264 891fb2cd Gerd Hoffmann
    assert(port != NULL);
265 891fb2cd Gerd Hoffmann
    trace_usb_port_release(bus->busnr, port->path);
266 891fb2cd Gerd Hoffmann
267 891fb2cd Gerd Hoffmann
    QTAILQ_REMOVE(&bus->used, port, next);
268 891fb2cd Gerd Hoffmann
    bus->nused--;
269 891fb2cd Gerd Hoffmann
270 891fb2cd Gerd Hoffmann
    dev->port = NULL;
271 891fb2cd Gerd Hoffmann
    port->dev = NULL;
272 891fb2cd Gerd Hoffmann
273 891fb2cd Gerd Hoffmann
    QTAILQ_INSERT_TAIL(&bus->free, port, next);
274 891fb2cd Gerd Hoffmann
    bus->nfree++;
275 a5d2f727 Gerd Hoffmann
}
276 a5d2f727 Gerd Hoffmann
277 891fb2cd Gerd Hoffmann
int usb_device_attach(USBDevice *dev)
278 a8e662b5 Gerd Hoffmann
{
279 a8e662b5 Gerd Hoffmann
    USBBus *bus = usb_bus_from_device(dev);
280 891fb2cd Gerd Hoffmann
    USBPort *port = dev->port;
281 a8e662b5 Gerd Hoffmann
282 891fb2cd Gerd Hoffmann
    assert(port != NULL);
283 891fb2cd Gerd Hoffmann
    assert(!dev->attached);
284 891fb2cd Gerd Hoffmann
    trace_usb_port_attach(bus->busnr, port->path);
285 891fb2cd Gerd Hoffmann
286 891fb2cd Gerd Hoffmann
    if (!(port->speedmask & dev->speedmask)) {
287 891fb2cd Gerd Hoffmann
        error_report("Warning: speed mismatch trying to attach "
288 891fb2cd Gerd Hoffmann
                     "usb device %s to bus %s\n",
289 891fb2cd Gerd Hoffmann
                     dev->product_desc, bus->qbus.name);
290 a8e662b5 Gerd Hoffmann
        return -1;
291 a8e662b5 Gerd Hoffmann
    }
292 a8e662b5 Gerd Hoffmann
293 891fb2cd Gerd Hoffmann
    dev->attached++;
294 891fb2cd Gerd Hoffmann
    usb_attach(port);
295 a8e662b5 Gerd Hoffmann
296 891fb2cd Gerd Hoffmann
    return 0;
297 891fb2cd Gerd Hoffmann
}
298 891fb2cd Gerd Hoffmann
299 891fb2cd Gerd Hoffmann
int usb_device_detach(USBDevice *dev)
300 891fb2cd Gerd Hoffmann
{
301 891fb2cd Gerd Hoffmann
    USBBus *bus = usb_bus_from_device(dev);
302 891fb2cd Gerd Hoffmann
    USBPort *port = dev->port;
303 a8e662b5 Gerd Hoffmann
304 891fb2cd Gerd Hoffmann
    assert(port != NULL);
305 891fb2cd Gerd Hoffmann
    assert(dev->attached);
306 891fb2cd Gerd Hoffmann
    trace_usb_port_detach(bus->busnr, port->path);
307 a8e662b5 Gerd Hoffmann
308 891fb2cd Gerd Hoffmann
    usb_detach(port);
309 891fb2cd Gerd Hoffmann
    dev->attached--;
310 a8e662b5 Gerd Hoffmann
    return 0;
311 a8e662b5 Gerd Hoffmann
}
312 a8e662b5 Gerd Hoffmann
313 a5d2f727 Gerd Hoffmann
int usb_device_delete_addr(int busnr, int addr)
314 a5d2f727 Gerd Hoffmann
{
315 a5d2f727 Gerd Hoffmann
    USBBus *bus;
316 a5d2f727 Gerd Hoffmann
    USBPort *port;
317 a5d2f727 Gerd Hoffmann
    USBDevice *dev;
318 a5d2f727 Gerd Hoffmann
319 a5d2f727 Gerd Hoffmann
    bus = usb_bus_find(busnr);
320 a5d2f727 Gerd Hoffmann
    if (!bus)
321 a5d2f727 Gerd Hoffmann
        return -1;
322 a5d2f727 Gerd Hoffmann
323 72cf2d4f Blue Swirl
    QTAILQ_FOREACH(port, &bus->used, next) {
324 a5d2f727 Gerd Hoffmann
        if (port->dev->addr == addr)
325 a5d2f727 Gerd Hoffmann
            break;
326 a5d2f727 Gerd Hoffmann
    }
327 a5d2f727 Gerd Hoffmann
    if (!port)
328 a5d2f727 Gerd Hoffmann
        return -1;
329 a5d2f727 Gerd Hoffmann
    dev = port->dev;
330 a5d2f727 Gerd Hoffmann
331 a8e662b5 Gerd Hoffmann
    qdev_free(&dev->qdev);
332 a5d2f727 Gerd Hoffmann
    return 0;
333 a5d2f727 Gerd Hoffmann
}
334 a5d2f727 Gerd Hoffmann
335 a5d2f727 Gerd Hoffmann
static const char *usb_speed(unsigned int speed)
336 a5d2f727 Gerd Hoffmann
{
337 a5d2f727 Gerd Hoffmann
    static const char *txt[] = {
338 a5d2f727 Gerd Hoffmann
        [ USB_SPEED_LOW  ] = "1.5",
339 a5d2f727 Gerd Hoffmann
        [ USB_SPEED_FULL ] = "12",
340 a5d2f727 Gerd Hoffmann
        [ USB_SPEED_HIGH ] = "480",
341 290d26d2 Hans de Goede
        [ USB_SPEED_SUPER ] = "5000",
342 a5d2f727 Gerd Hoffmann
    };
343 a5d2f727 Gerd Hoffmann
    if (speed >= ARRAY_SIZE(txt))
344 a5d2f727 Gerd Hoffmann
        return "?";
345 a5d2f727 Gerd Hoffmann
    return txt[speed];
346 a5d2f727 Gerd Hoffmann
}
347 a5d2f727 Gerd Hoffmann
348 a5d2f727 Gerd Hoffmann
static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
349 a5d2f727 Gerd Hoffmann
{
350 a5d2f727 Gerd Hoffmann
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
351 a5d2f727 Gerd Hoffmann
    USBBus *bus = usb_bus_from_device(dev);
352 a5d2f727 Gerd Hoffmann
353 c7a2196a Gerd Hoffmann
    monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
354 66a6593a Gerd Hoffmann
                   indent, "", bus->busnr, dev->addr,
355 c7a2196a Gerd Hoffmann
                   dev->port ? dev->port->path : "-",
356 0fe6d12e Markus Armbruster
                   usb_speed(dev->speed), dev->product_desc,
357 66a6593a Gerd Hoffmann
                   dev->attached ? ", attached" : "");
358 a5d2f727 Gerd Hoffmann
}
359 a5d2f727 Gerd Hoffmann
360 c7a2196a Gerd Hoffmann
static char *usb_get_dev_path(DeviceState *qdev)
361 c7a2196a Gerd Hoffmann
{
362 c7a2196a Gerd Hoffmann
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
363 7267c094 Anthony Liguori
    return g_strdup(dev->port->path);
364 c7a2196a Gerd Hoffmann
}
365 c7a2196a Gerd Hoffmann
366 70d31cb2 Gerd Hoffmann
static char *usb_get_fw_dev_path(DeviceState *qdev)
367 70d31cb2 Gerd Hoffmann
{
368 70d31cb2 Gerd Hoffmann
    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
369 70d31cb2 Gerd Hoffmann
    char *fw_path, *in;
370 ea87e95f Blue Swirl
    ssize_t pos = 0, fw_len;
371 70d31cb2 Gerd Hoffmann
    long nr;
372 70d31cb2 Gerd Hoffmann
373 ea87e95f Blue Swirl
    fw_len = 32 + strlen(dev->port->path) * 6;
374 7267c094 Anthony Liguori
    fw_path = g_malloc(fw_len);
375 70d31cb2 Gerd Hoffmann
    in = dev->port->path;
376 ea87e95f Blue Swirl
    while (fw_len - pos > 0) {
377 70d31cb2 Gerd Hoffmann
        nr = strtol(in, &in, 10);
378 70d31cb2 Gerd Hoffmann
        if (in[0] == '.') {
379 70d31cb2 Gerd Hoffmann
            /* some hub between root port and device */
380 ea87e95f Blue Swirl
            pos += snprintf(fw_path + pos, fw_len - pos, "hub@%ld/", nr);
381 70d31cb2 Gerd Hoffmann
            in++;
382 70d31cb2 Gerd Hoffmann
        } else {
383 70d31cb2 Gerd Hoffmann
            /* the device itself */
384 ea87e95f Blue Swirl
            pos += snprintf(fw_path + pos, fw_len - pos, "%s@%ld",
385 ea87e95f Blue Swirl
                            qdev_fw_name(qdev), nr);
386 70d31cb2 Gerd Hoffmann
            break;
387 70d31cb2 Gerd Hoffmann
        }
388 70d31cb2 Gerd Hoffmann
    }
389 70d31cb2 Gerd Hoffmann
    return fw_path;
390 70d31cb2 Gerd Hoffmann
}
391 70d31cb2 Gerd Hoffmann
392 a5d2f727 Gerd Hoffmann
void usb_info(Monitor *mon)
393 a5d2f727 Gerd Hoffmann
{
394 a5d2f727 Gerd Hoffmann
    USBBus *bus;
395 a5d2f727 Gerd Hoffmann
    USBDevice *dev;
396 a5d2f727 Gerd Hoffmann
    USBPort *port;
397 a5d2f727 Gerd Hoffmann
398 72cf2d4f Blue Swirl
    if (QTAILQ_EMPTY(&busses)) {
399 a5d2f727 Gerd Hoffmann
        monitor_printf(mon, "USB support not enabled\n");
400 a5d2f727 Gerd Hoffmann
        return;
401 a5d2f727 Gerd Hoffmann
    }
402 a5d2f727 Gerd Hoffmann
403 72cf2d4f Blue Swirl
    QTAILQ_FOREACH(bus, &busses, next) {
404 72cf2d4f Blue Swirl
        QTAILQ_FOREACH(port, &bus->used, next) {
405 a5d2f727 Gerd Hoffmann
            dev = port->dev;
406 a5d2f727 Gerd Hoffmann
            if (!dev)
407 a5d2f727 Gerd Hoffmann
                continue;
408 c7a2196a Gerd Hoffmann
            monitor_printf(mon, "  Device %d.%d, Port %s, Speed %s Mb/s, Product %s\n",
409 c7a2196a Gerd Hoffmann
                           bus->busnr, dev->addr, port->path, usb_speed(dev->speed),
410 0fe6d12e Markus Armbruster
                           dev->product_desc);
411 a5d2f727 Gerd Hoffmann
        }
412 a5d2f727 Gerd Hoffmann
    }
413 a5d2f727 Gerd Hoffmann
}
414 a5d2f727 Gerd Hoffmann
415 0958b4cc Gerd Hoffmann
/* handle legacy -usbdevice cmd line option */
416 0958b4cc Gerd Hoffmann
USBDevice *usbdevice_create(const char *cmdline)
417 0958b4cc Gerd Hoffmann
{
418 0958b4cc Gerd Hoffmann
    USBBus *bus = usb_bus_find(-1 /* any */);
419 0958b4cc Gerd Hoffmann
    DeviceInfo *info;
420 0958b4cc Gerd Hoffmann
    USBDeviceInfo *usb;
421 702f3e0f Jan Kiszka
    char driver[32];
422 702f3e0f Jan Kiszka
    const char *params;
423 0958b4cc Gerd Hoffmann
    int len;
424 0958b4cc Gerd Hoffmann
425 0958b4cc Gerd Hoffmann
    params = strchr(cmdline,':');
426 0958b4cc Gerd Hoffmann
    if (params) {
427 0958b4cc Gerd Hoffmann
        params++;
428 0958b4cc Gerd Hoffmann
        len = params - cmdline;
429 0958b4cc Gerd Hoffmann
        if (len > sizeof(driver))
430 0958b4cc Gerd Hoffmann
            len = sizeof(driver);
431 0958b4cc Gerd Hoffmann
        pstrcpy(driver, len, cmdline);
432 0958b4cc Gerd Hoffmann
    } else {
433 702f3e0f Jan Kiszka
        params = "";
434 0958b4cc Gerd Hoffmann
        pstrcpy(driver, sizeof(driver), cmdline);
435 0958b4cc Gerd Hoffmann
    }
436 0958b4cc Gerd Hoffmann
437 0958b4cc Gerd Hoffmann
    for (info = device_info_list; info != NULL; info = info->next) {
438 0958b4cc Gerd Hoffmann
        if (info->bus_info != &usb_bus_info)
439 0958b4cc Gerd Hoffmann
            continue;
440 0958b4cc Gerd Hoffmann
        usb = DO_UPCAST(USBDeviceInfo, qdev, info);
441 0958b4cc Gerd Hoffmann
        if (usb->usbdevice_name == NULL)
442 0958b4cc Gerd Hoffmann
            continue;
443 0958b4cc Gerd Hoffmann
        if (strcmp(usb->usbdevice_name, driver) != 0)
444 0958b4cc Gerd Hoffmann
            continue;
445 0958b4cc Gerd Hoffmann
        break;
446 0958b4cc Gerd Hoffmann
    }
447 0958b4cc Gerd Hoffmann
    if (info == NULL) {
448 0958b4cc Gerd Hoffmann
#if 0
449 0958b4cc Gerd Hoffmann
        /* no error because some drivers are not converted (yet) */
450 1ecda02b Markus Armbruster
        error_report("usbdevice %s not found", driver);
451 0958b4cc Gerd Hoffmann
#endif
452 0958b4cc Gerd Hoffmann
        return NULL;
453 0958b4cc Gerd Hoffmann
    }
454 0958b4cc Gerd Hoffmann
455 0958b4cc Gerd Hoffmann
    if (!usb->usbdevice_init) {
456 98f22dc1 TeLeMan
        if (*params) {
457 1ecda02b Markus Armbruster
            error_report("usbdevice %s accepts no params", driver);
458 0958b4cc Gerd Hoffmann
            return NULL;
459 0958b4cc Gerd Hoffmann
        }
460 0958b4cc Gerd Hoffmann
        return usb_create_simple(bus, usb->qdev.name);
461 0958b4cc Gerd Hoffmann
    }
462 0958b4cc Gerd Hoffmann
    return usb->usbdevice_init(params);
463 0958b4cc Gerd Hoffmann
}