Statistics
| Branch: | Revision:

root / hw / usb-bus.c @ c65adf9b

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