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