xref: /openbmc/qemu/hw/usb/bus.c (revision eeb0cf9a)
1f1ae32a1SGerd Hoffmann #include "hw/hw.h"
2f1ae32a1SGerd Hoffmann #include "hw/usb.h"
3f1ae32a1SGerd Hoffmann #include "hw/qdev.h"
4f1ae32a1SGerd Hoffmann #include "sysemu.h"
5f1ae32a1SGerd Hoffmann #include "monitor.h"
6f1ae32a1SGerd Hoffmann #include "trace.h"
7f1ae32a1SGerd Hoffmann 
8f1ae32a1SGerd Hoffmann static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
9f1ae32a1SGerd Hoffmann 
10f1ae32a1SGerd Hoffmann static char *usb_get_dev_path(DeviceState *dev);
11f1ae32a1SGerd Hoffmann static char *usb_get_fw_dev_path(DeviceState *qdev);
12f1ae32a1SGerd Hoffmann static int usb_qdev_exit(DeviceState *qdev);
13f1ae32a1SGerd Hoffmann 
14f1ae32a1SGerd Hoffmann static struct BusInfo usb_bus_info = {
15f1ae32a1SGerd Hoffmann     .name      = "USB",
16f1ae32a1SGerd Hoffmann     .size      = sizeof(USBBus),
17f1ae32a1SGerd Hoffmann     .print_dev = usb_bus_dev_print,
18f1ae32a1SGerd Hoffmann     .get_dev_path = usb_get_dev_path,
19f1ae32a1SGerd Hoffmann     .get_fw_dev_path = usb_get_fw_dev_path,
20f1ae32a1SGerd Hoffmann     .props      = (Property[]) {
21f1ae32a1SGerd Hoffmann         DEFINE_PROP_STRING("port", USBDevice, port_path),
22*eeb0cf9aSGerd Hoffmann         DEFINE_PROP_BIT("full-path", USBDevice, flags,
23*eeb0cf9aSGerd Hoffmann                         USB_DEV_FLAG_FULL_PATH, true),
24f1ae32a1SGerd Hoffmann         DEFINE_PROP_END_OF_LIST()
25f1ae32a1SGerd Hoffmann     },
26f1ae32a1SGerd Hoffmann };
27f1ae32a1SGerd Hoffmann static int next_usb_bus = 0;
28f1ae32a1SGerd Hoffmann static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
29f1ae32a1SGerd Hoffmann 
30f1ae32a1SGerd Hoffmann const VMStateDescription vmstate_usb_device = {
31f1ae32a1SGerd Hoffmann     .name = "USBDevice",
32f1ae32a1SGerd Hoffmann     .version_id = 1,
33f1ae32a1SGerd Hoffmann     .minimum_version_id = 1,
34f1ae32a1SGerd Hoffmann     .fields = (VMStateField []) {
35f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(addr, USBDevice),
36f1ae32a1SGerd Hoffmann         VMSTATE_INT32(state, USBDevice),
37f1ae32a1SGerd Hoffmann         VMSTATE_INT32(remote_wakeup, USBDevice),
38f1ae32a1SGerd Hoffmann         VMSTATE_INT32(setup_state, USBDevice),
39f1ae32a1SGerd Hoffmann         VMSTATE_INT32(setup_len, USBDevice),
40f1ae32a1SGerd Hoffmann         VMSTATE_INT32(setup_index, USBDevice),
41f1ae32a1SGerd Hoffmann         VMSTATE_UINT8_ARRAY(setup_buf, USBDevice, 8),
42f1ae32a1SGerd Hoffmann         VMSTATE_END_OF_LIST(),
43f1ae32a1SGerd Hoffmann     }
44f1ae32a1SGerd Hoffmann };
45f1ae32a1SGerd Hoffmann 
46f1ae32a1SGerd Hoffmann void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host)
47f1ae32a1SGerd Hoffmann {
48f1ae32a1SGerd Hoffmann     qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
49f1ae32a1SGerd Hoffmann     bus->ops = ops;
50f1ae32a1SGerd Hoffmann     bus->busnr = next_usb_bus++;
51f1ae32a1SGerd Hoffmann     bus->qbus.allow_hotplug = 1; /* Yes, we can */
52f1ae32a1SGerd Hoffmann     QTAILQ_INIT(&bus->free);
53f1ae32a1SGerd Hoffmann     QTAILQ_INIT(&bus->used);
54f1ae32a1SGerd Hoffmann     QTAILQ_INSERT_TAIL(&busses, bus, next);
55f1ae32a1SGerd Hoffmann }
56f1ae32a1SGerd Hoffmann 
57f1ae32a1SGerd Hoffmann USBBus *usb_bus_find(int busnr)
58f1ae32a1SGerd Hoffmann {
59f1ae32a1SGerd Hoffmann     USBBus *bus;
60f1ae32a1SGerd Hoffmann 
61f1ae32a1SGerd Hoffmann     if (-1 == busnr)
62f1ae32a1SGerd Hoffmann         return QTAILQ_FIRST(&busses);
63f1ae32a1SGerd Hoffmann     QTAILQ_FOREACH(bus, &busses, next) {
64f1ae32a1SGerd Hoffmann         if (bus->busnr == busnr)
65f1ae32a1SGerd Hoffmann             return bus;
66f1ae32a1SGerd Hoffmann     }
67f1ae32a1SGerd Hoffmann     return NULL;
68f1ae32a1SGerd Hoffmann }
69f1ae32a1SGerd Hoffmann 
70f1ae32a1SGerd Hoffmann static int usb_device_init(USBDevice *dev)
71f1ae32a1SGerd Hoffmann {
72f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
73f1ae32a1SGerd Hoffmann     if (klass->init) {
74f1ae32a1SGerd Hoffmann         return klass->init(dev);
75f1ae32a1SGerd Hoffmann     }
76f1ae32a1SGerd Hoffmann     return 0;
77f1ae32a1SGerd Hoffmann }
78f1ae32a1SGerd Hoffmann 
79f1ae32a1SGerd Hoffmann USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
80f1ae32a1SGerd Hoffmann {
81f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
82f1ae32a1SGerd Hoffmann     if (klass->find_device) {
83f1ae32a1SGerd Hoffmann         return klass->find_device(dev, addr);
84f1ae32a1SGerd Hoffmann     }
85f1ae32a1SGerd Hoffmann     return NULL;
86f1ae32a1SGerd Hoffmann }
87f1ae32a1SGerd Hoffmann 
88f1ae32a1SGerd Hoffmann static void usb_device_handle_destroy(USBDevice *dev)
89f1ae32a1SGerd Hoffmann {
90f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
91f1ae32a1SGerd Hoffmann     if (klass->handle_destroy) {
92f1ae32a1SGerd Hoffmann         klass->handle_destroy(dev);
93f1ae32a1SGerd Hoffmann     }
94f1ae32a1SGerd Hoffmann }
95f1ae32a1SGerd Hoffmann 
96f1ae32a1SGerd Hoffmann void usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
97f1ae32a1SGerd Hoffmann {
98f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
99f1ae32a1SGerd Hoffmann     if (klass->cancel_packet) {
100f1ae32a1SGerd Hoffmann         klass->cancel_packet(dev, p);
101f1ae32a1SGerd Hoffmann     }
102f1ae32a1SGerd Hoffmann }
103f1ae32a1SGerd Hoffmann 
104f1ae32a1SGerd Hoffmann void usb_device_handle_attach(USBDevice *dev)
105f1ae32a1SGerd Hoffmann {
106f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
107f1ae32a1SGerd Hoffmann     if (klass->handle_attach) {
108f1ae32a1SGerd Hoffmann         klass->handle_attach(dev);
109f1ae32a1SGerd Hoffmann     }
110f1ae32a1SGerd Hoffmann }
111f1ae32a1SGerd Hoffmann 
112f1ae32a1SGerd Hoffmann void usb_device_handle_reset(USBDevice *dev)
113f1ae32a1SGerd Hoffmann {
114f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
115f1ae32a1SGerd Hoffmann     if (klass->handle_reset) {
116f1ae32a1SGerd Hoffmann         klass->handle_reset(dev);
117f1ae32a1SGerd Hoffmann     }
118f1ae32a1SGerd Hoffmann }
119f1ae32a1SGerd Hoffmann 
120f1ae32a1SGerd Hoffmann int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
121f1ae32a1SGerd Hoffmann                               int value, int index, int length, uint8_t *data)
122f1ae32a1SGerd Hoffmann {
123f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
124f1ae32a1SGerd Hoffmann     if (klass->handle_control) {
125f1ae32a1SGerd Hoffmann         return klass->handle_control(dev, p, request, value, index, length,
126f1ae32a1SGerd Hoffmann                                          data);
127f1ae32a1SGerd Hoffmann     }
128f1ae32a1SGerd Hoffmann     return -ENOSYS;
129f1ae32a1SGerd Hoffmann }
130f1ae32a1SGerd Hoffmann 
131f1ae32a1SGerd Hoffmann int usb_device_handle_data(USBDevice *dev, USBPacket *p)
132f1ae32a1SGerd Hoffmann {
133f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
134f1ae32a1SGerd Hoffmann     if (klass->handle_data) {
135f1ae32a1SGerd Hoffmann         return klass->handle_data(dev, p);
136f1ae32a1SGerd Hoffmann     }
137f1ae32a1SGerd Hoffmann     return -ENOSYS;
138f1ae32a1SGerd Hoffmann }
139f1ae32a1SGerd Hoffmann 
140f1ae32a1SGerd Hoffmann const char *usb_device_get_product_desc(USBDevice *dev)
141f1ae32a1SGerd Hoffmann {
142f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
143f1ae32a1SGerd Hoffmann     return klass->product_desc;
144f1ae32a1SGerd Hoffmann }
145f1ae32a1SGerd Hoffmann 
146f1ae32a1SGerd Hoffmann const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
147f1ae32a1SGerd Hoffmann {
148f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
149f1ae32a1SGerd Hoffmann     return klass->usb_desc;
150f1ae32a1SGerd Hoffmann }
151f1ae32a1SGerd Hoffmann 
152f1ae32a1SGerd Hoffmann void usb_device_set_interface(USBDevice *dev, int interface,
153f1ae32a1SGerd Hoffmann                               int alt_old, int alt_new)
154f1ae32a1SGerd Hoffmann {
155f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
156f1ae32a1SGerd Hoffmann     if (klass->set_interface) {
157f1ae32a1SGerd Hoffmann         klass->set_interface(dev, interface, alt_old, alt_new);
158f1ae32a1SGerd Hoffmann     }
159f1ae32a1SGerd Hoffmann }
160f1ae32a1SGerd Hoffmann 
161f1ae32a1SGerd Hoffmann static int usb_qdev_init(DeviceState *qdev)
162f1ae32a1SGerd Hoffmann {
163f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
164f1ae32a1SGerd Hoffmann     int rc;
165f1ae32a1SGerd Hoffmann 
166f1ae32a1SGerd Hoffmann     pstrcpy(dev->product_desc, sizeof(dev->product_desc),
167f1ae32a1SGerd Hoffmann             usb_device_get_product_desc(dev));
168f1ae32a1SGerd Hoffmann     dev->auto_attach = 1;
169f1ae32a1SGerd Hoffmann     QLIST_INIT(&dev->strings);
170f1ae32a1SGerd Hoffmann     usb_ep_init(dev);
171f1ae32a1SGerd Hoffmann     rc = usb_claim_port(dev);
172f1ae32a1SGerd Hoffmann     if (rc != 0) {
173f1ae32a1SGerd Hoffmann         return rc;
174f1ae32a1SGerd Hoffmann     }
175f1ae32a1SGerd Hoffmann     rc = usb_device_init(dev);
176f1ae32a1SGerd Hoffmann     if (rc != 0) {
177f1ae32a1SGerd Hoffmann         usb_release_port(dev);
178f1ae32a1SGerd Hoffmann         return rc;
179f1ae32a1SGerd Hoffmann     }
180f1ae32a1SGerd Hoffmann     if (dev->auto_attach) {
181f1ae32a1SGerd Hoffmann         rc = usb_device_attach(dev);
182f1ae32a1SGerd Hoffmann         if (rc != 0) {
183f1ae32a1SGerd Hoffmann             usb_qdev_exit(qdev);
184f1ae32a1SGerd Hoffmann             return rc;
185f1ae32a1SGerd Hoffmann         }
186f1ae32a1SGerd Hoffmann     }
187f1ae32a1SGerd Hoffmann     return 0;
188f1ae32a1SGerd Hoffmann }
189f1ae32a1SGerd Hoffmann 
190f1ae32a1SGerd Hoffmann static int usb_qdev_exit(DeviceState *qdev)
191f1ae32a1SGerd Hoffmann {
192f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
193f1ae32a1SGerd Hoffmann 
194f1ae32a1SGerd Hoffmann     if (dev->attached) {
195f1ae32a1SGerd Hoffmann         usb_device_detach(dev);
196f1ae32a1SGerd Hoffmann     }
197f1ae32a1SGerd Hoffmann     usb_device_handle_destroy(dev);
198f1ae32a1SGerd Hoffmann     if (dev->port) {
199f1ae32a1SGerd Hoffmann         usb_release_port(dev);
200f1ae32a1SGerd Hoffmann     }
201f1ae32a1SGerd Hoffmann     return 0;
202f1ae32a1SGerd Hoffmann }
203f1ae32a1SGerd Hoffmann 
204f1ae32a1SGerd Hoffmann typedef struct LegacyUSBFactory
205f1ae32a1SGerd Hoffmann {
206f1ae32a1SGerd Hoffmann     const char *name;
207f1ae32a1SGerd Hoffmann     const char *usbdevice_name;
208f1ae32a1SGerd Hoffmann     USBDevice *(*usbdevice_init)(USBBus *bus, const char *params);
209f1ae32a1SGerd Hoffmann } LegacyUSBFactory;
210f1ae32a1SGerd Hoffmann 
211f1ae32a1SGerd Hoffmann static GSList *legacy_usb_factory;
212f1ae32a1SGerd Hoffmann 
213f1ae32a1SGerd Hoffmann void usb_legacy_register(const char *typename, const char *usbdevice_name,
214f1ae32a1SGerd Hoffmann                          USBDevice *(*usbdevice_init)(USBBus *bus,
215f1ae32a1SGerd Hoffmann                                                       const char *params))
216f1ae32a1SGerd Hoffmann {
217f1ae32a1SGerd Hoffmann     if (usbdevice_name) {
218f1ae32a1SGerd Hoffmann         LegacyUSBFactory *f = g_malloc0(sizeof(*f));
219f1ae32a1SGerd Hoffmann         f->name = typename;
220f1ae32a1SGerd Hoffmann         f->usbdevice_name = usbdevice_name;
221f1ae32a1SGerd Hoffmann         f->usbdevice_init = usbdevice_init;
222f1ae32a1SGerd Hoffmann         legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
223f1ae32a1SGerd Hoffmann     }
224f1ae32a1SGerd Hoffmann }
225f1ae32a1SGerd Hoffmann 
226f1ae32a1SGerd Hoffmann USBDevice *usb_create(USBBus *bus, const char *name)
227f1ae32a1SGerd Hoffmann {
228f1ae32a1SGerd Hoffmann     DeviceState *dev;
229f1ae32a1SGerd Hoffmann 
230f1ae32a1SGerd Hoffmann     dev = qdev_create(&bus->qbus, name);
231f1ae32a1SGerd Hoffmann     return USB_DEVICE(dev);
232f1ae32a1SGerd Hoffmann }
233f1ae32a1SGerd Hoffmann 
234f1ae32a1SGerd Hoffmann USBDevice *usb_create_simple(USBBus *bus, const char *name)
235f1ae32a1SGerd Hoffmann {
236f1ae32a1SGerd Hoffmann     USBDevice *dev = usb_create(bus, name);
237f1ae32a1SGerd Hoffmann     int rc;
238f1ae32a1SGerd Hoffmann 
239f1ae32a1SGerd Hoffmann     if (!dev) {
240f1ae32a1SGerd Hoffmann         error_report("Failed to create USB device '%s'", name);
241f1ae32a1SGerd Hoffmann         return NULL;
242f1ae32a1SGerd Hoffmann     }
243f1ae32a1SGerd Hoffmann     rc = qdev_init(&dev->qdev);
244f1ae32a1SGerd Hoffmann     if (rc < 0) {
245f1ae32a1SGerd Hoffmann         error_report("Failed to initialize USB device '%s'", name);
246f1ae32a1SGerd Hoffmann         return NULL;
247f1ae32a1SGerd Hoffmann     }
248f1ae32a1SGerd Hoffmann     return dev;
249f1ae32a1SGerd Hoffmann }
250f1ae32a1SGerd Hoffmann 
251f1ae32a1SGerd Hoffmann static void usb_fill_port(USBPort *port, void *opaque, int index,
252f1ae32a1SGerd Hoffmann                           USBPortOps *ops, int speedmask)
253f1ae32a1SGerd Hoffmann {
254f1ae32a1SGerd Hoffmann     port->opaque = opaque;
255f1ae32a1SGerd Hoffmann     port->index = index;
256f1ae32a1SGerd Hoffmann     port->ops = ops;
257f1ae32a1SGerd Hoffmann     port->speedmask = speedmask;
258f1ae32a1SGerd Hoffmann     usb_port_location(port, NULL, index + 1);
259f1ae32a1SGerd Hoffmann }
260f1ae32a1SGerd Hoffmann 
261f1ae32a1SGerd Hoffmann void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
262f1ae32a1SGerd Hoffmann                        USBPortOps *ops, int speedmask)
263f1ae32a1SGerd Hoffmann {
264f1ae32a1SGerd Hoffmann     usb_fill_port(port, opaque, index, ops, speedmask);
265f1ae32a1SGerd Hoffmann     QTAILQ_INSERT_TAIL(&bus->free, port, next);
266f1ae32a1SGerd Hoffmann     bus->nfree++;
267f1ae32a1SGerd Hoffmann }
268f1ae32a1SGerd Hoffmann 
269f1ae32a1SGerd Hoffmann int usb_register_companion(const char *masterbus, USBPort *ports[],
270f1ae32a1SGerd Hoffmann                            uint32_t portcount, uint32_t firstport,
271f1ae32a1SGerd Hoffmann                            void *opaque, USBPortOps *ops, int speedmask)
272f1ae32a1SGerd Hoffmann {
273f1ae32a1SGerd Hoffmann     USBBus *bus;
274f1ae32a1SGerd Hoffmann     int i;
275f1ae32a1SGerd Hoffmann 
276f1ae32a1SGerd Hoffmann     QTAILQ_FOREACH(bus, &busses, next) {
277f1ae32a1SGerd Hoffmann         if (strcmp(bus->qbus.name, masterbus) == 0) {
278f1ae32a1SGerd Hoffmann             break;
279f1ae32a1SGerd Hoffmann         }
280f1ae32a1SGerd Hoffmann     }
281f1ae32a1SGerd Hoffmann 
282f1ae32a1SGerd Hoffmann     if (!bus || !bus->ops->register_companion) {
283f1ae32a1SGerd Hoffmann         qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
284f1ae32a1SGerd Hoffmann                       "an USB masterbus");
285f1ae32a1SGerd Hoffmann         if (bus) {
286f1ae32a1SGerd Hoffmann             error_printf_unless_qmp(
287f1ae32a1SGerd Hoffmann                 "USB bus '%s' does not allow companion controllers\n",
288f1ae32a1SGerd Hoffmann                 masterbus);
289f1ae32a1SGerd Hoffmann         }
290f1ae32a1SGerd Hoffmann         return -1;
291f1ae32a1SGerd Hoffmann     }
292f1ae32a1SGerd Hoffmann 
293f1ae32a1SGerd Hoffmann     for (i = 0; i < portcount; i++) {
294f1ae32a1SGerd Hoffmann         usb_fill_port(ports[i], opaque, i, ops, speedmask);
295f1ae32a1SGerd Hoffmann     }
296f1ae32a1SGerd Hoffmann 
297f1ae32a1SGerd Hoffmann     return bus->ops->register_companion(bus, ports, portcount, firstport);
298f1ae32a1SGerd Hoffmann }
299f1ae32a1SGerd Hoffmann 
300f1ae32a1SGerd Hoffmann void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
301f1ae32a1SGerd Hoffmann {
302f1ae32a1SGerd Hoffmann     if (upstream) {
303f1ae32a1SGerd Hoffmann         snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
304f1ae32a1SGerd Hoffmann                  upstream->path, portnr);
305f1ae32a1SGerd Hoffmann     } else {
306f1ae32a1SGerd Hoffmann         snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
307f1ae32a1SGerd Hoffmann     }
308f1ae32a1SGerd Hoffmann }
309f1ae32a1SGerd Hoffmann 
310f1ae32a1SGerd Hoffmann void usb_unregister_port(USBBus *bus, USBPort *port)
311f1ae32a1SGerd Hoffmann {
312f1ae32a1SGerd Hoffmann     if (port->dev)
313f1ae32a1SGerd Hoffmann         qdev_free(&port->dev->qdev);
314f1ae32a1SGerd Hoffmann     QTAILQ_REMOVE(&bus->free, port, next);
315f1ae32a1SGerd Hoffmann     bus->nfree--;
316f1ae32a1SGerd Hoffmann }
317f1ae32a1SGerd Hoffmann 
318f1ae32a1SGerd Hoffmann int usb_claim_port(USBDevice *dev)
319f1ae32a1SGerd Hoffmann {
320f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
321f1ae32a1SGerd Hoffmann     USBPort *port;
322f1ae32a1SGerd Hoffmann 
323f1ae32a1SGerd Hoffmann     assert(dev->port == NULL);
324f1ae32a1SGerd Hoffmann 
325f1ae32a1SGerd Hoffmann     if (dev->port_path) {
326f1ae32a1SGerd Hoffmann         QTAILQ_FOREACH(port, &bus->free, next) {
327f1ae32a1SGerd Hoffmann             if (strcmp(port->path, dev->port_path) == 0) {
328f1ae32a1SGerd Hoffmann                 break;
329f1ae32a1SGerd Hoffmann             }
330f1ae32a1SGerd Hoffmann         }
331f1ae32a1SGerd Hoffmann         if (port == NULL) {
332f1ae32a1SGerd Hoffmann             error_report("Error: usb port %s (bus %s) not found (in use?)",
333f1ae32a1SGerd Hoffmann                          dev->port_path, bus->qbus.name);
334f1ae32a1SGerd Hoffmann             return -1;
335f1ae32a1SGerd Hoffmann         }
336f1ae32a1SGerd Hoffmann     } else {
337f1ae32a1SGerd Hoffmann         if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
338f1ae32a1SGerd Hoffmann             /* Create a new hub and chain it on */
339f1ae32a1SGerd Hoffmann             usb_create_simple(bus, "usb-hub");
340f1ae32a1SGerd Hoffmann         }
341f1ae32a1SGerd Hoffmann         if (bus->nfree == 0) {
342f1ae32a1SGerd Hoffmann             error_report("Error: tried to attach usb device %s to a bus "
343f1ae32a1SGerd Hoffmann                          "with no free ports", dev->product_desc);
344f1ae32a1SGerd Hoffmann             return -1;
345f1ae32a1SGerd Hoffmann         }
346f1ae32a1SGerd Hoffmann         port = QTAILQ_FIRST(&bus->free);
347f1ae32a1SGerd Hoffmann     }
348f1ae32a1SGerd Hoffmann     trace_usb_port_claim(bus->busnr, port->path);
349f1ae32a1SGerd Hoffmann 
350f1ae32a1SGerd Hoffmann     QTAILQ_REMOVE(&bus->free, port, next);
351f1ae32a1SGerd Hoffmann     bus->nfree--;
352f1ae32a1SGerd Hoffmann 
353f1ae32a1SGerd Hoffmann     dev->port = port;
354f1ae32a1SGerd Hoffmann     port->dev = dev;
355f1ae32a1SGerd Hoffmann 
356f1ae32a1SGerd Hoffmann     QTAILQ_INSERT_TAIL(&bus->used, port, next);
357f1ae32a1SGerd Hoffmann     bus->nused++;
358f1ae32a1SGerd Hoffmann     return 0;
359f1ae32a1SGerd Hoffmann }
360f1ae32a1SGerd Hoffmann 
361f1ae32a1SGerd Hoffmann void usb_release_port(USBDevice *dev)
362f1ae32a1SGerd Hoffmann {
363f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
364f1ae32a1SGerd Hoffmann     USBPort *port = dev->port;
365f1ae32a1SGerd Hoffmann 
366f1ae32a1SGerd Hoffmann     assert(port != NULL);
367f1ae32a1SGerd Hoffmann     trace_usb_port_release(bus->busnr, port->path);
368f1ae32a1SGerd Hoffmann 
369f1ae32a1SGerd Hoffmann     QTAILQ_REMOVE(&bus->used, port, next);
370f1ae32a1SGerd Hoffmann     bus->nused--;
371f1ae32a1SGerd Hoffmann 
372f1ae32a1SGerd Hoffmann     dev->port = NULL;
373f1ae32a1SGerd Hoffmann     port->dev = NULL;
374f1ae32a1SGerd Hoffmann 
375f1ae32a1SGerd Hoffmann     QTAILQ_INSERT_TAIL(&bus->free, port, next);
376f1ae32a1SGerd Hoffmann     bus->nfree++;
377f1ae32a1SGerd Hoffmann }
378f1ae32a1SGerd Hoffmann 
379f1ae32a1SGerd Hoffmann int usb_device_attach(USBDevice *dev)
380f1ae32a1SGerd Hoffmann {
381f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
382f1ae32a1SGerd Hoffmann     USBPort *port = dev->port;
383f1ae32a1SGerd Hoffmann 
384f1ae32a1SGerd Hoffmann     assert(port != NULL);
385f1ae32a1SGerd Hoffmann     assert(!dev->attached);
386f1ae32a1SGerd Hoffmann     trace_usb_port_attach(bus->busnr, port->path);
387f1ae32a1SGerd Hoffmann 
388f1ae32a1SGerd Hoffmann     if (!(port->speedmask & dev->speedmask)) {
389f1ae32a1SGerd Hoffmann         error_report("Warning: speed mismatch trying to attach "
390f1ae32a1SGerd Hoffmann                      "usb device %s to bus %s",
391f1ae32a1SGerd Hoffmann                      dev->product_desc, bus->qbus.name);
392f1ae32a1SGerd Hoffmann         return -1;
393f1ae32a1SGerd Hoffmann     }
394f1ae32a1SGerd Hoffmann 
395f1ae32a1SGerd Hoffmann     dev->attached++;
396f1ae32a1SGerd Hoffmann     usb_attach(port);
397f1ae32a1SGerd Hoffmann 
398f1ae32a1SGerd Hoffmann     return 0;
399f1ae32a1SGerd Hoffmann }
400f1ae32a1SGerd Hoffmann 
401f1ae32a1SGerd Hoffmann int usb_device_detach(USBDevice *dev)
402f1ae32a1SGerd Hoffmann {
403f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
404f1ae32a1SGerd Hoffmann     USBPort *port = dev->port;
405f1ae32a1SGerd Hoffmann 
406f1ae32a1SGerd Hoffmann     assert(port != NULL);
407f1ae32a1SGerd Hoffmann     assert(dev->attached);
408f1ae32a1SGerd Hoffmann     trace_usb_port_detach(bus->busnr, port->path);
409f1ae32a1SGerd Hoffmann 
410f1ae32a1SGerd Hoffmann     usb_detach(port);
411f1ae32a1SGerd Hoffmann     dev->attached--;
412f1ae32a1SGerd Hoffmann     return 0;
413f1ae32a1SGerd Hoffmann }
414f1ae32a1SGerd Hoffmann 
415f1ae32a1SGerd Hoffmann int usb_device_delete_addr(int busnr, int addr)
416f1ae32a1SGerd Hoffmann {
417f1ae32a1SGerd Hoffmann     USBBus *bus;
418f1ae32a1SGerd Hoffmann     USBPort *port;
419f1ae32a1SGerd Hoffmann     USBDevice *dev;
420f1ae32a1SGerd Hoffmann 
421f1ae32a1SGerd Hoffmann     bus = usb_bus_find(busnr);
422f1ae32a1SGerd Hoffmann     if (!bus)
423f1ae32a1SGerd Hoffmann         return -1;
424f1ae32a1SGerd Hoffmann 
425f1ae32a1SGerd Hoffmann     QTAILQ_FOREACH(port, &bus->used, next) {
426f1ae32a1SGerd Hoffmann         if (port->dev->addr == addr)
427f1ae32a1SGerd Hoffmann             break;
428f1ae32a1SGerd Hoffmann     }
429f1ae32a1SGerd Hoffmann     if (!port)
430f1ae32a1SGerd Hoffmann         return -1;
431f1ae32a1SGerd Hoffmann     dev = port->dev;
432f1ae32a1SGerd Hoffmann 
433f1ae32a1SGerd Hoffmann     qdev_free(&dev->qdev);
434f1ae32a1SGerd Hoffmann     return 0;
435f1ae32a1SGerd Hoffmann }
436f1ae32a1SGerd Hoffmann 
437f1ae32a1SGerd Hoffmann static const char *usb_speed(unsigned int speed)
438f1ae32a1SGerd Hoffmann {
439f1ae32a1SGerd Hoffmann     static const char *txt[] = {
440f1ae32a1SGerd Hoffmann         [ USB_SPEED_LOW  ] = "1.5",
441f1ae32a1SGerd Hoffmann         [ USB_SPEED_FULL ] = "12",
442f1ae32a1SGerd Hoffmann         [ USB_SPEED_HIGH ] = "480",
443f1ae32a1SGerd Hoffmann         [ USB_SPEED_SUPER ] = "5000",
444f1ae32a1SGerd Hoffmann     };
445f1ae32a1SGerd Hoffmann     if (speed >= ARRAY_SIZE(txt))
446f1ae32a1SGerd Hoffmann         return "?";
447f1ae32a1SGerd Hoffmann     return txt[speed];
448f1ae32a1SGerd Hoffmann }
449f1ae32a1SGerd Hoffmann 
450f1ae32a1SGerd Hoffmann static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
451f1ae32a1SGerd Hoffmann {
452f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
453f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
454f1ae32a1SGerd Hoffmann 
455f1ae32a1SGerd Hoffmann     monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
456f1ae32a1SGerd Hoffmann                    indent, "", bus->busnr, dev->addr,
457f1ae32a1SGerd Hoffmann                    dev->port ? dev->port->path : "-",
458f1ae32a1SGerd Hoffmann                    usb_speed(dev->speed), dev->product_desc,
459f1ae32a1SGerd Hoffmann                    dev->attached ? ", attached" : "");
460f1ae32a1SGerd Hoffmann }
461f1ae32a1SGerd Hoffmann 
462f1ae32a1SGerd Hoffmann static char *usb_get_dev_path(DeviceState *qdev)
463f1ae32a1SGerd Hoffmann {
464f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
465*eeb0cf9aSGerd Hoffmann     DeviceState *hcd = qdev->parent_bus->parent;
466*eeb0cf9aSGerd Hoffmann     char *id = NULL;
467*eeb0cf9aSGerd Hoffmann 
468*eeb0cf9aSGerd Hoffmann     if ((dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) &&
469*eeb0cf9aSGerd Hoffmann         hcd && hcd->parent_bus && hcd->parent_bus->info->get_dev_path) {
470*eeb0cf9aSGerd Hoffmann         id = hcd->parent_bus->info->get_dev_path(hcd);
471*eeb0cf9aSGerd Hoffmann     }
472*eeb0cf9aSGerd Hoffmann     if (id) {
473*eeb0cf9aSGerd Hoffmann         char *ret = g_strdup_printf("%s/%s", id, dev->port->path);
474*eeb0cf9aSGerd Hoffmann         g_free(id);
475*eeb0cf9aSGerd Hoffmann         return ret;
476*eeb0cf9aSGerd Hoffmann     } else {
477f1ae32a1SGerd Hoffmann         return g_strdup(dev->port->path);
478f1ae32a1SGerd Hoffmann     }
479*eeb0cf9aSGerd Hoffmann }
480f1ae32a1SGerd Hoffmann 
481f1ae32a1SGerd Hoffmann static char *usb_get_fw_dev_path(DeviceState *qdev)
482f1ae32a1SGerd Hoffmann {
483f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
484f1ae32a1SGerd Hoffmann     char *fw_path, *in;
485f1ae32a1SGerd Hoffmann     ssize_t pos = 0, fw_len;
486f1ae32a1SGerd Hoffmann     long nr;
487f1ae32a1SGerd Hoffmann 
488f1ae32a1SGerd Hoffmann     fw_len = 32 + strlen(dev->port->path) * 6;
489f1ae32a1SGerd Hoffmann     fw_path = g_malloc(fw_len);
490f1ae32a1SGerd Hoffmann     in = dev->port->path;
491f1ae32a1SGerd Hoffmann     while (fw_len - pos > 0) {
492f1ae32a1SGerd Hoffmann         nr = strtol(in, &in, 10);
493f1ae32a1SGerd Hoffmann         if (in[0] == '.') {
494f1ae32a1SGerd Hoffmann             /* some hub between root port and device */
495f1ae32a1SGerd Hoffmann             pos += snprintf(fw_path + pos, fw_len - pos, "hub@%ld/", nr);
496f1ae32a1SGerd Hoffmann             in++;
497f1ae32a1SGerd Hoffmann         } else {
498f1ae32a1SGerd Hoffmann             /* the device itself */
499f1ae32a1SGerd Hoffmann             pos += snprintf(fw_path + pos, fw_len - pos, "%s@%ld",
500f1ae32a1SGerd Hoffmann                             qdev_fw_name(qdev), nr);
501f1ae32a1SGerd Hoffmann             break;
502f1ae32a1SGerd Hoffmann         }
503f1ae32a1SGerd Hoffmann     }
504f1ae32a1SGerd Hoffmann     return fw_path;
505f1ae32a1SGerd Hoffmann }
506f1ae32a1SGerd Hoffmann 
507f1ae32a1SGerd Hoffmann void usb_info(Monitor *mon)
508f1ae32a1SGerd Hoffmann {
509f1ae32a1SGerd Hoffmann     USBBus *bus;
510f1ae32a1SGerd Hoffmann     USBDevice *dev;
511f1ae32a1SGerd Hoffmann     USBPort *port;
512f1ae32a1SGerd Hoffmann 
513f1ae32a1SGerd Hoffmann     if (QTAILQ_EMPTY(&busses)) {
514f1ae32a1SGerd Hoffmann         monitor_printf(mon, "USB support not enabled\n");
515f1ae32a1SGerd Hoffmann         return;
516f1ae32a1SGerd Hoffmann     }
517f1ae32a1SGerd Hoffmann 
518f1ae32a1SGerd Hoffmann     QTAILQ_FOREACH(bus, &busses, next) {
519f1ae32a1SGerd Hoffmann         QTAILQ_FOREACH(port, &bus->used, next) {
520f1ae32a1SGerd Hoffmann             dev = port->dev;
521f1ae32a1SGerd Hoffmann             if (!dev)
522f1ae32a1SGerd Hoffmann                 continue;
523f1ae32a1SGerd Hoffmann             monitor_printf(mon, "  Device %d.%d, Port %s, Speed %s Mb/s, Product %s\n",
524f1ae32a1SGerd Hoffmann                            bus->busnr, dev->addr, port->path, usb_speed(dev->speed),
525f1ae32a1SGerd Hoffmann                            dev->product_desc);
526f1ae32a1SGerd Hoffmann         }
527f1ae32a1SGerd Hoffmann     }
528f1ae32a1SGerd Hoffmann }
529f1ae32a1SGerd Hoffmann 
530f1ae32a1SGerd Hoffmann /* handle legacy -usbdevice cmd line option */
531f1ae32a1SGerd Hoffmann USBDevice *usbdevice_create(const char *cmdline)
532f1ae32a1SGerd Hoffmann {
533f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_find(-1 /* any */);
534f1ae32a1SGerd Hoffmann     LegacyUSBFactory *f = NULL;
535f1ae32a1SGerd Hoffmann     GSList *i;
536f1ae32a1SGerd Hoffmann     char driver[32];
537f1ae32a1SGerd Hoffmann     const char *params;
538f1ae32a1SGerd Hoffmann     int len;
539f1ae32a1SGerd Hoffmann 
540f1ae32a1SGerd Hoffmann     params = strchr(cmdline,':');
541f1ae32a1SGerd Hoffmann     if (params) {
542f1ae32a1SGerd Hoffmann         params++;
543f1ae32a1SGerd Hoffmann         len = params - cmdline;
544f1ae32a1SGerd Hoffmann         if (len > sizeof(driver))
545f1ae32a1SGerd Hoffmann             len = sizeof(driver);
546f1ae32a1SGerd Hoffmann         pstrcpy(driver, len, cmdline);
547f1ae32a1SGerd Hoffmann     } else {
548f1ae32a1SGerd Hoffmann         params = "";
549f1ae32a1SGerd Hoffmann         pstrcpy(driver, sizeof(driver), cmdline);
550f1ae32a1SGerd Hoffmann     }
551f1ae32a1SGerd Hoffmann 
552f1ae32a1SGerd Hoffmann     for (i = legacy_usb_factory; i; i = i->next) {
553f1ae32a1SGerd Hoffmann         f = i->data;
554f1ae32a1SGerd Hoffmann         if (strcmp(f->usbdevice_name, driver) == 0) {
555f1ae32a1SGerd Hoffmann             break;
556f1ae32a1SGerd Hoffmann         }
557f1ae32a1SGerd Hoffmann     }
558f1ae32a1SGerd Hoffmann     if (i == NULL) {
559f1ae32a1SGerd Hoffmann #if 0
560f1ae32a1SGerd Hoffmann         /* no error because some drivers are not converted (yet) */
561f1ae32a1SGerd Hoffmann         error_report("usbdevice %s not found", driver);
562f1ae32a1SGerd Hoffmann #endif
563f1ae32a1SGerd Hoffmann         return NULL;
564f1ae32a1SGerd Hoffmann     }
565f1ae32a1SGerd Hoffmann 
566f1ae32a1SGerd Hoffmann     if (!f->usbdevice_init) {
567f1ae32a1SGerd Hoffmann         if (*params) {
568f1ae32a1SGerd Hoffmann             error_report("usbdevice %s accepts no params", driver);
569f1ae32a1SGerd Hoffmann             return NULL;
570f1ae32a1SGerd Hoffmann         }
571f1ae32a1SGerd Hoffmann         return usb_create_simple(bus, f->name);
572f1ae32a1SGerd Hoffmann     }
573f1ae32a1SGerd Hoffmann     return f->usbdevice_init(bus, params);
574f1ae32a1SGerd Hoffmann }
575f1ae32a1SGerd Hoffmann 
576f1ae32a1SGerd Hoffmann static void usb_device_class_init(ObjectClass *klass, void *data)
577f1ae32a1SGerd Hoffmann {
578f1ae32a1SGerd Hoffmann     DeviceClass *k = DEVICE_CLASS(klass);
579f1ae32a1SGerd Hoffmann     k->bus_info = &usb_bus_info;
580f1ae32a1SGerd Hoffmann     k->init     = usb_qdev_init;
581f1ae32a1SGerd Hoffmann     k->unplug   = qdev_simple_unplug_cb;
582f1ae32a1SGerd Hoffmann     k->exit     = usb_qdev_exit;
583f1ae32a1SGerd Hoffmann }
584f1ae32a1SGerd Hoffmann 
585f1ae32a1SGerd Hoffmann static TypeInfo usb_device_type_info = {
586f1ae32a1SGerd Hoffmann     .name = TYPE_USB_DEVICE,
587f1ae32a1SGerd Hoffmann     .parent = TYPE_DEVICE,
588f1ae32a1SGerd Hoffmann     .instance_size = sizeof(USBDevice),
589f1ae32a1SGerd Hoffmann     .abstract = true,
590f1ae32a1SGerd Hoffmann     .class_size = sizeof(USBDeviceClass),
591f1ae32a1SGerd Hoffmann     .class_init = usb_device_class_init,
592f1ae32a1SGerd Hoffmann };
593f1ae32a1SGerd Hoffmann 
594f1ae32a1SGerd Hoffmann static void usb_register_types(void)
595f1ae32a1SGerd Hoffmann {
596f1ae32a1SGerd Hoffmann     type_register_static(&usb_device_type_info);
597f1ae32a1SGerd Hoffmann }
598f1ae32a1SGerd Hoffmann 
599f1ae32a1SGerd Hoffmann type_init(usb_register_types)
600