]> Git Repo - qemu.git/blob - hw/usb-bus.c
hw/pl061.c: Support GPIOAMSEL register
[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->ops = ops;
147     port->speedmask = speedmask;
148     usb_port_location(port, NULL, index + 1);
149 }
150
151 void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
152                        USBPortOps *ops, int speedmask)
153 {
154     usb_fill_port(port, opaque, index, ops, speedmask);
155     QTAILQ_INSERT_TAIL(&bus->free, port, next);
156     bus->nfree++;
157 }
158
159 int usb_register_companion(const char *masterbus, USBPort *ports[],
160                            uint32_t portcount, uint32_t firstport,
161                            void *opaque, USBPortOps *ops, int speedmask)
162 {
163     USBBus *bus;
164     int i;
165
166     QTAILQ_FOREACH(bus, &busses, next) {
167         if (strcmp(bus->qbus.name, masterbus) == 0) {
168             break;
169         }
170     }
171
172     if (!bus || !bus->ops->register_companion) {
173         qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
174                       "an USB masterbus");
175         if (bus) {
176             error_printf_unless_qmp(
177                 "USB bus '%s' does not allow companion controllers\n",
178                 masterbus);
179         }
180         return -1;
181     }
182
183     for (i = 0; i < portcount; i++) {
184         usb_fill_port(ports[i], opaque, i, ops, speedmask);
185     }
186
187     return bus->ops->register_companion(bus, ports, portcount, firstport);
188 }
189
190 void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
191 {
192     if (upstream) {
193         snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
194                  upstream->path, portnr);
195     } else {
196         snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
197     }
198 }
199
200 void usb_unregister_port(USBBus *bus, USBPort *port)
201 {
202     if (port->dev)
203         qdev_free(&port->dev->qdev);
204     QTAILQ_REMOVE(&bus->free, port, next);
205     bus->nfree--;
206 }
207
208 static int do_attach(USBDevice *dev)
209 {
210     USBBus *bus = usb_bus_from_device(dev);
211     USBPort *port;
212
213     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     }
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\n",
231                     dev->port_path, bus->qbus.name);
232             return -1;
233         }
234     } else {
235         port = QTAILQ_FIRST(&bus->free);
236     }
237     if (!(port->speedmask & dev->speedmask)) {
238         error_report("Warning: speed mismatch trying to attach usb device %s to bus %s\n",
239                 dev->product_desc, bus->qbus.name);
240         return -1;
241     }
242
243     dev->attached++;
244     QTAILQ_REMOVE(&bus->free, port, next);
245     bus->nfree--;
246
247     usb_attach(port, dev);
248
249     QTAILQ_INSERT_TAIL(&bus->used, port, next);
250     bus->nused++;
251
252     return 0;
253 }
254
255 int usb_device_attach(USBDevice *dev)
256 {
257     USBBus *bus = usb_bus_from_device(dev);
258
259     if (bus->nfree == 1 && dev->port_path == NULL) {
260         /* Create a new hub and chain it on
261            (unless a physical port location is specified). */
262         usb_create_simple(bus, "usb-hub");
263     }
264     return do_attach(dev);
265 }
266
267 int usb_device_detach(USBDevice *dev)
268 {
269     USBBus *bus = usb_bus_from_device(dev);
270     USBPort *port;
271
272     if (!dev->attached) {
273         error_report("Error: tried to detach unattached usb device %s\n",
274                 dev->product_desc);
275         return -1;
276     }
277     dev->attached--;
278
279     QTAILQ_FOREACH(port, &bus->used, next) {
280         if (port->dev == dev)
281             break;
282     }
283     assert(port != NULL);
284
285     QTAILQ_REMOVE(&bus->used, port, next);
286     bus->nused--;
287
288     usb_attach(port, NULL);
289
290     QTAILQ_INSERT_TAIL(&bus->free, port, next);
291     bus->nfree++;
292     return 0;
293 }
294
295 int usb_device_delete_addr(int busnr, int addr)
296 {
297     USBBus *bus;
298     USBPort *port;
299     USBDevice *dev;
300
301     bus = usb_bus_find(busnr);
302     if (!bus)
303         return -1;
304
305     QTAILQ_FOREACH(port, &bus->used, next) {
306         if (port->dev->addr == addr)
307             break;
308     }
309     if (!port)
310         return -1;
311     dev = port->dev;
312
313     qdev_free(&dev->qdev);
314     return 0;
315 }
316
317 static const char *usb_speed(unsigned int speed)
318 {
319     static const char *txt[] = {
320         [ USB_SPEED_LOW  ] = "1.5",
321         [ USB_SPEED_FULL ] = "12",
322         [ USB_SPEED_HIGH ] = "480",
323         [ USB_SPEED_SUPER ] = "5000",
324     };
325     if (speed >= ARRAY_SIZE(txt))
326         return "?";
327     return txt[speed];
328 }
329
330 static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
331 {
332     USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
333     USBBus *bus = usb_bus_from_device(dev);
334
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 static char *usb_get_dev_path(DeviceState *qdev)
343 {
344     USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
345     return qemu_strdup(dev->port->path);
346 }
347
348 static char *usb_get_fw_dev_path(DeviceState *qdev)
349 {
350     USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
351     char *fw_path, *in;
352     ssize_t pos = 0, fw_len;
353     long nr;
354
355     fw_len = 32 + strlen(dev->port->path) * 6;
356     fw_path = qemu_malloc(fw_len);
357     in = dev->port->path;
358     while (fw_len - pos > 0) {
359         nr = strtol(in, &in, 10);
360         if (in[0] == '.') {
361             /* some hub between root port and device */
362             pos += snprintf(fw_path + pos, fw_len - pos, "hub@%ld/", nr);
363             in++;
364         } else {
365             /* the device itself */
366             pos += snprintf(fw_path + pos, fw_len - pos, "%s@%ld",
367                             qdev_fw_name(qdev), nr);
368             break;
369         }
370     }
371     return fw_path;
372 }
373
374 void usb_info(Monitor *mon)
375 {
376     USBBus *bus;
377     USBDevice *dev;
378     USBPort *port;
379
380     if (QTAILQ_EMPTY(&busses)) {
381         monitor_printf(mon, "USB support not enabled\n");
382         return;
383     }
384
385     QTAILQ_FOREACH(bus, &busses, next) {
386         QTAILQ_FOREACH(port, &bus->used, next) {
387             dev = port->dev;
388             if (!dev)
389                 continue;
390             monitor_printf(mon, "  Device %d.%d, Port %s, Speed %s Mb/s, Product %s\n",
391                            bus->busnr, dev->addr, port->path, usb_speed(dev->speed),
392                            dev->product_desc);
393         }
394     }
395 }
396
397 /* handle legacy -usbdevice cmd line option */
398 USBDevice *usbdevice_create(const char *cmdline)
399 {
400     USBBus *bus = usb_bus_find(-1 /* any */);
401     DeviceInfo *info;
402     USBDeviceInfo *usb;
403     char driver[32];
404     const char *params;
405     int len;
406
407     params = strchr(cmdline,':');
408     if (params) {
409         params++;
410         len = params - cmdline;
411         if (len > sizeof(driver))
412             len = sizeof(driver);
413         pstrcpy(driver, len, cmdline);
414     } else {
415         params = "";
416         pstrcpy(driver, sizeof(driver), cmdline);
417     }
418
419     for (info = device_info_list; info != NULL; info = info->next) {
420         if (info->bus_info != &usb_bus_info)
421             continue;
422         usb = DO_UPCAST(USBDeviceInfo, qdev, info);
423         if (usb->usbdevice_name == NULL)
424             continue;
425         if (strcmp(usb->usbdevice_name, driver) != 0)
426             continue;
427         break;
428     }
429     if (info == NULL) {
430 #if 0
431         /* no error because some drivers are not converted (yet) */
432         error_report("usbdevice %s not found", driver);
433 #endif
434         return NULL;
435     }
436
437     if (!usb->usbdevice_init) {
438         if (*params) {
439             error_report("usbdevice %s accepts no params", driver);
440             return NULL;
441         }
442         return usb_create_simple(bus, usb->qdev.name);
443     }
444     return usb->usbdevice_init(params);
445 }
This page took 0.048674 seconds and 4 git commands to generate.