Introduce strtosz_suffix()
[qemu/agraf.git] / hw / usb-bus.c
blob8b4583c1e63635fce8e41d69785b58c01670ef61
1 #include "hw.h"
2 #include "usb.h"
3 #include "qdev.h"
4 #include "sysemu.h"
5 #include "monitor.h"
7 static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
8 static char *usbbus_get_fw_dev_path(DeviceState *dev);
10 static struct BusInfo usb_bus_info = {
11 .name = "USB",
12 .size = sizeof(USBBus),
13 .print_dev = usb_bus_dev_print,
14 .get_fw_dev_path = usbbus_get_fw_dev_path,
16 static int next_usb_bus = 0;
17 static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
19 void usb_bus_new(USBBus *bus, DeviceState *host)
21 qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
22 bus->busnr = next_usb_bus++;
23 bus->qbus.allow_hotplug = 1; /* Yes, we can */
24 QTAILQ_INIT(&bus->free);
25 QTAILQ_INIT(&bus->used);
26 QTAILQ_INSERT_TAIL(&busses, bus, next);
29 USBBus *usb_bus_find(int busnr)
31 USBBus *bus;
33 if (-1 == busnr)
34 return QTAILQ_FIRST(&busses);
35 QTAILQ_FOREACH(bus, &busses, next) {
36 if (bus->busnr == busnr)
37 return bus;
39 return NULL;
42 static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
44 USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
45 USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base);
46 int rc;
48 pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc);
49 dev->info = info;
50 dev->auto_attach = 1;
51 rc = dev->info->init(dev);
52 if (rc == 0 && dev->auto_attach)
53 usb_device_attach(dev);
54 return rc;
57 static int usb_qdev_exit(DeviceState *qdev)
59 USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
61 usb_device_detach(dev);
62 if (dev->info->handle_destroy) {
63 dev->info->handle_destroy(dev);
65 return 0;
68 void usb_qdev_register(USBDeviceInfo *info)
70 info->qdev.bus_info = &usb_bus_info;
71 info->qdev.init = usb_qdev_init;
72 info->qdev.unplug = qdev_simple_unplug_cb;
73 info->qdev.exit = usb_qdev_exit;
74 qdev_register(&info->qdev);
77 void usb_qdev_register_many(USBDeviceInfo *info)
79 while (info->qdev.name) {
80 usb_qdev_register(info);
81 info++;
85 USBDevice *usb_create(USBBus *bus, const char *name)
87 DeviceState *dev;
89 #if 1
90 /* temporary stopgap until all usb is properly qdev-ified */
91 if (!bus) {
92 bus = usb_bus_find(-1);
93 if (!bus)
94 return NULL;
95 fprintf(stderr, "%s: no bus specified, using \"%s\" for \"%s\"\n",
96 __FUNCTION__, bus->qbus.name, name);
98 #endif
100 dev = qdev_create(&bus->qbus, name);
101 return DO_UPCAST(USBDevice, qdev, dev);
104 USBDevice *usb_create_simple(USBBus *bus, const char *name)
106 USBDevice *dev = usb_create(bus, name);
107 if (!dev) {
108 hw_error("Failed to create USB device '%s'\n", name);
110 qdev_init_nofail(&dev->qdev);
111 return dev;
114 void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
115 USBDevice *pdev, usb_attachfn attach)
117 port->opaque = opaque;
118 port->index = index;
119 port->attach = attach;
120 port->pdev = pdev;
121 QTAILQ_INSERT_TAIL(&bus->free, port, next);
122 bus->nfree++;
125 void usb_unregister_port(USBBus *bus, USBPort *port)
127 if (port->dev)
128 qdev_free(&port->dev->qdev);
129 QTAILQ_REMOVE(&bus->free, port, next);
130 bus->nfree--;
133 static void do_attach(USBDevice *dev)
135 USBBus *bus = usb_bus_from_device(dev);
136 USBPort *port;
138 if (dev->attached) {
139 fprintf(stderr, "Warning: tried to attach usb device %s twice\n",
140 dev->product_desc);
141 return;
143 dev->attached++;
145 port = QTAILQ_FIRST(&bus->free);
146 QTAILQ_REMOVE(&bus->free, port, next);
147 bus->nfree--;
149 usb_attach(port, dev);
151 QTAILQ_INSERT_TAIL(&bus->used, port, next);
152 bus->nused++;
155 int usb_device_attach(USBDevice *dev)
157 USBBus *bus = usb_bus_from_device(dev);
159 if (bus->nfree == 1) {
160 /* Create a new hub and chain it on. */
161 usb_create_simple(bus, "usb-hub");
163 do_attach(dev);
164 return 0;
167 int usb_device_detach(USBDevice *dev)
169 USBBus *bus = usb_bus_from_device(dev);
170 USBPort *port;
172 if (!dev->attached) {
173 fprintf(stderr, "Warning: tried to detach unattached usb device %s\n",
174 dev->product_desc);
175 return -1;
177 dev->attached--;
179 QTAILQ_FOREACH(port, &bus->used, next) {
180 if (port->dev == dev)
181 break;
183 assert(port != NULL);
185 QTAILQ_REMOVE(&bus->used, port, next);
186 bus->nused--;
188 usb_attach(port, NULL);
190 QTAILQ_INSERT_TAIL(&bus->free, port, next);
191 bus->nfree++;
192 return 0;
195 int usb_device_delete_addr(int busnr, int addr)
197 USBBus *bus;
198 USBPort *port;
199 USBDevice *dev;
201 bus = usb_bus_find(busnr);
202 if (!bus)
203 return -1;
205 QTAILQ_FOREACH(port, &bus->used, next) {
206 if (port->dev->addr == addr)
207 break;
209 if (!port)
210 return -1;
211 dev = port->dev;
213 qdev_free(&dev->qdev);
214 return 0;
217 static const char *usb_speed(unsigned int speed)
219 static const char *txt[] = {
220 [ USB_SPEED_LOW ] = "1.5",
221 [ USB_SPEED_FULL ] = "12",
222 [ USB_SPEED_HIGH ] = "480",
224 if (speed >= ARRAY_SIZE(txt))
225 return "?";
226 return txt[speed];
229 static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
231 USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
232 USBBus *bus = usb_bus_from_device(dev);
234 monitor_printf(mon, "%*saddr %d.%d, speed %s, name %s%s\n",
235 indent, "", bus->busnr, dev->addr,
236 usb_speed(dev->speed), dev->product_desc,
237 dev->attached ? ", attached" : "");
240 void usb_info(Monitor *mon)
242 USBBus *bus;
243 USBDevice *dev;
244 USBPort *port;
246 if (QTAILQ_EMPTY(&busses)) {
247 monitor_printf(mon, "USB support not enabled\n");
248 return;
251 QTAILQ_FOREACH(bus, &busses, next) {
252 QTAILQ_FOREACH(port, &bus->used, next) {
253 dev = port->dev;
254 if (!dev)
255 continue;
256 monitor_printf(mon, " Device %d.%d, Speed %s Mb/s, Product %s\n",
257 bus->busnr, dev->addr, usb_speed(dev->speed),
258 dev->product_desc);
263 /* handle legacy -usbdevice cmd line option */
264 USBDevice *usbdevice_create(const char *cmdline)
266 USBBus *bus = usb_bus_find(-1 /* any */);
267 DeviceInfo *info;
268 USBDeviceInfo *usb;
269 char driver[32];
270 const char *params;
271 int len;
273 params = strchr(cmdline,':');
274 if (params) {
275 params++;
276 len = params - cmdline;
277 if (len > sizeof(driver))
278 len = sizeof(driver);
279 pstrcpy(driver, len, cmdline);
280 } else {
281 params = "";
282 pstrcpy(driver, sizeof(driver), cmdline);
285 for (info = device_info_list; info != NULL; info = info->next) {
286 if (info->bus_info != &usb_bus_info)
287 continue;
288 usb = DO_UPCAST(USBDeviceInfo, qdev, info);
289 if (usb->usbdevice_name == NULL)
290 continue;
291 if (strcmp(usb->usbdevice_name, driver) != 0)
292 continue;
293 break;
295 if (info == NULL) {
296 #if 0
297 /* no error because some drivers are not converted (yet) */
298 error_report("usbdevice %s not found", driver);
299 #endif
300 return NULL;
303 if (!usb->usbdevice_init) {
304 if (*params) {
305 error_report("usbdevice %s accepts no params", driver);
306 return NULL;
308 return usb_create_simple(bus, usb->qdev.name);
310 return usb->usbdevice_init(params);
313 static int usbbus_get_fw_dev_path_helper(USBDevice *d, USBBus *bus, char *p,
314 int len)
316 int l = 0;
317 USBPort *port;
319 QTAILQ_FOREACH(port, &bus->used, next) {
320 if (port->dev == d) {
321 if (port->pdev) {
322 l = usbbus_get_fw_dev_path_helper(port->pdev, bus, p, len);
324 l += snprintf(p + l, len - l, "%s@%x/", qdev_fw_name(&d->qdev),
325 port->index);
326 break;
330 return l;
333 static char *usbbus_get_fw_dev_path(DeviceState *dev)
335 USBDevice *d = (USBDevice*)dev;
336 USBBus *bus = usb_bus_from_device(d);
337 char path[100];
338 int l;
340 assert(d->attached != 0);
342 l = usbbus_get_fw_dev_path_helper(d, bus, path, sizeof(path));
344 if (l == 0) {
345 abort();
348 path[l-1] = '\0';
350 return strdup(path);