xref: /openbmc/qemu/hw/usb/bus.c (revision 71938a09)
1f1ae32a1SGerd Hoffmann #include "hw/hw.h"
2f1ae32a1SGerd Hoffmann #include "hw/usb.h"
3f1ae32a1SGerd Hoffmann #include "hw/qdev.h"
49c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
583c9089eSPaolo Bonzini #include "monitor/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 
143cb75a7cSPaolo Bonzini static Property usb_props[] = {
153cb75a7cSPaolo Bonzini     DEFINE_PROP_STRING("port", USBDevice, port_path),
16*71938a09SGerd Hoffmann     DEFINE_PROP_STRING("serial", USBDevice, serial),
173cb75a7cSPaolo Bonzini     DEFINE_PROP_BIT("full-path", USBDevice, flags,
183cb75a7cSPaolo Bonzini                     USB_DEV_FLAG_FULL_PATH, true),
193cb75a7cSPaolo Bonzini     DEFINE_PROP_END_OF_LIST()
203cb75a7cSPaolo Bonzini };
213cb75a7cSPaolo Bonzini 
220d936928SAnthony Liguori static void usb_bus_class_init(ObjectClass *klass, void *data)
230d936928SAnthony Liguori {
240d936928SAnthony Liguori     BusClass *k = BUS_CLASS(klass);
250d936928SAnthony Liguori 
260d936928SAnthony Liguori     k->print_dev = usb_bus_dev_print;
270d936928SAnthony Liguori     k->get_dev_path = usb_get_dev_path;
280d936928SAnthony Liguori     k->get_fw_dev_path = usb_get_fw_dev_path;
290d936928SAnthony Liguori }
300d936928SAnthony Liguori 
310d936928SAnthony Liguori static const TypeInfo usb_bus_info = {
320d936928SAnthony Liguori     .name = TYPE_USB_BUS,
330d936928SAnthony Liguori     .parent = TYPE_BUS,
340d936928SAnthony Liguori     .instance_size = sizeof(USBBus),
350d936928SAnthony Liguori     .class_init = usb_bus_class_init,
36f1ae32a1SGerd Hoffmann };
373cb75a7cSPaolo Bonzini 
38f1ae32a1SGerd Hoffmann static int next_usb_bus = 0;
39f1ae32a1SGerd Hoffmann static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
40f1ae32a1SGerd Hoffmann 
41495d5447SGerd Hoffmann static int usb_device_post_load(void *opaque, int version_id)
42495d5447SGerd Hoffmann {
43495d5447SGerd Hoffmann     USBDevice *dev = opaque;
44495d5447SGerd Hoffmann 
45495d5447SGerd Hoffmann     if (dev->state == USB_STATE_NOTATTACHED) {
46495d5447SGerd Hoffmann         dev->attached = 0;
47495d5447SGerd Hoffmann     } else {
48495d5447SGerd Hoffmann         dev->attached = 1;
49495d5447SGerd Hoffmann     }
50495d5447SGerd Hoffmann     return 0;
51495d5447SGerd Hoffmann }
52495d5447SGerd Hoffmann 
53f1ae32a1SGerd Hoffmann const VMStateDescription vmstate_usb_device = {
54f1ae32a1SGerd Hoffmann     .name = "USBDevice",
55f1ae32a1SGerd Hoffmann     .version_id = 1,
56f1ae32a1SGerd Hoffmann     .minimum_version_id = 1,
57495d5447SGerd Hoffmann     .post_load = usb_device_post_load,
58f1ae32a1SGerd Hoffmann     .fields = (VMStateField []) {
59f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(addr, USBDevice),
60f1ae32a1SGerd Hoffmann         VMSTATE_INT32(state, USBDevice),
61f1ae32a1SGerd Hoffmann         VMSTATE_INT32(remote_wakeup, USBDevice),
62f1ae32a1SGerd Hoffmann         VMSTATE_INT32(setup_state, USBDevice),
63f1ae32a1SGerd Hoffmann         VMSTATE_INT32(setup_len, USBDevice),
64f1ae32a1SGerd Hoffmann         VMSTATE_INT32(setup_index, USBDevice),
65f1ae32a1SGerd Hoffmann         VMSTATE_UINT8_ARRAY(setup_buf, USBDevice, 8),
66f1ae32a1SGerd Hoffmann         VMSTATE_END_OF_LIST(),
67f1ae32a1SGerd Hoffmann     }
68f1ae32a1SGerd Hoffmann };
69f1ae32a1SGerd Hoffmann 
70f1ae32a1SGerd Hoffmann void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host)
71f1ae32a1SGerd Hoffmann {
720d936928SAnthony Liguori     qbus_create_inplace(&bus->qbus, TYPE_USB_BUS, host, NULL);
73f1ae32a1SGerd Hoffmann     bus->ops = ops;
74f1ae32a1SGerd Hoffmann     bus->busnr = next_usb_bus++;
75f1ae32a1SGerd Hoffmann     bus->qbus.allow_hotplug = 1; /* Yes, we can */
76f1ae32a1SGerd Hoffmann     QTAILQ_INIT(&bus->free);
77f1ae32a1SGerd Hoffmann     QTAILQ_INIT(&bus->used);
78f1ae32a1SGerd Hoffmann     QTAILQ_INSERT_TAIL(&busses, bus, next);
79f1ae32a1SGerd Hoffmann }
80f1ae32a1SGerd Hoffmann 
81f1ae32a1SGerd Hoffmann USBBus *usb_bus_find(int busnr)
82f1ae32a1SGerd Hoffmann {
83f1ae32a1SGerd Hoffmann     USBBus *bus;
84f1ae32a1SGerd Hoffmann 
85f1ae32a1SGerd Hoffmann     if (-1 == busnr)
86f1ae32a1SGerd Hoffmann         return QTAILQ_FIRST(&busses);
87f1ae32a1SGerd Hoffmann     QTAILQ_FOREACH(bus, &busses, next) {
88f1ae32a1SGerd Hoffmann         if (bus->busnr == busnr)
89f1ae32a1SGerd Hoffmann             return bus;
90f1ae32a1SGerd Hoffmann     }
91f1ae32a1SGerd Hoffmann     return NULL;
92f1ae32a1SGerd Hoffmann }
93f1ae32a1SGerd Hoffmann 
94f1ae32a1SGerd Hoffmann static int usb_device_init(USBDevice *dev)
95f1ae32a1SGerd Hoffmann {
96f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
97f1ae32a1SGerd Hoffmann     if (klass->init) {
98f1ae32a1SGerd Hoffmann         return klass->init(dev);
99f1ae32a1SGerd Hoffmann     }
100f1ae32a1SGerd Hoffmann     return 0;
101f1ae32a1SGerd Hoffmann }
102f1ae32a1SGerd Hoffmann 
103f1ae32a1SGerd Hoffmann USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
104f1ae32a1SGerd Hoffmann {
105f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
106f1ae32a1SGerd Hoffmann     if (klass->find_device) {
107f1ae32a1SGerd Hoffmann         return klass->find_device(dev, addr);
108f1ae32a1SGerd Hoffmann     }
109f1ae32a1SGerd Hoffmann     return NULL;
110f1ae32a1SGerd Hoffmann }
111f1ae32a1SGerd Hoffmann 
112f1ae32a1SGerd Hoffmann static void usb_device_handle_destroy(USBDevice *dev)
113f1ae32a1SGerd Hoffmann {
114f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
115f1ae32a1SGerd Hoffmann     if (klass->handle_destroy) {
116f1ae32a1SGerd Hoffmann         klass->handle_destroy(dev);
117f1ae32a1SGerd Hoffmann     }
118f1ae32a1SGerd Hoffmann }
119f1ae32a1SGerd Hoffmann 
120f1ae32a1SGerd Hoffmann void usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
121f1ae32a1SGerd Hoffmann {
122f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
123f1ae32a1SGerd Hoffmann     if (klass->cancel_packet) {
124f1ae32a1SGerd Hoffmann         klass->cancel_packet(dev, p);
125f1ae32a1SGerd Hoffmann     }
126f1ae32a1SGerd Hoffmann }
127f1ae32a1SGerd Hoffmann 
128f1ae32a1SGerd Hoffmann void usb_device_handle_attach(USBDevice *dev)
129f1ae32a1SGerd Hoffmann {
130f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
131f1ae32a1SGerd Hoffmann     if (klass->handle_attach) {
132f1ae32a1SGerd Hoffmann         klass->handle_attach(dev);
133f1ae32a1SGerd Hoffmann     }
134f1ae32a1SGerd Hoffmann }
135f1ae32a1SGerd Hoffmann 
136f1ae32a1SGerd Hoffmann void usb_device_handle_reset(USBDevice *dev)
137f1ae32a1SGerd Hoffmann {
138f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
139f1ae32a1SGerd Hoffmann     if (klass->handle_reset) {
140f1ae32a1SGerd Hoffmann         klass->handle_reset(dev);
141f1ae32a1SGerd Hoffmann     }
142f1ae32a1SGerd Hoffmann }
143f1ae32a1SGerd Hoffmann 
1449a77a0f5SHans de Goede void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
145f1ae32a1SGerd Hoffmann                                int value, int index, int length, uint8_t *data)
146f1ae32a1SGerd Hoffmann {
147f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
148f1ae32a1SGerd Hoffmann     if (klass->handle_control) {
1499a77a0f5SHans de Goede         klass->handle_control(dev, p, request, value, index, length, data);
150f1ae32a1SGerd Hoffmann     }
151f1ae32a1SGerd Hoffmann }
152f1ae32a1SGerd Hoffmann 
1539a77a0f5SHans de Goede void usb_device_handle_data(USBDevice *dev, USBPacket *p)
154f1ae32a1SGerd Hoffmann {
155f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
156f1ae32a1SGerd Hoffmann     if (klass->handle_data) {
1579a77a0f5SHans de Goede         klass->handle_data(dev, p);
158f1ae32a1SGerd Hoffmann     }
159f1ae32a1SGerd Hoffmann }
160f1ae32a1SGerd Hoffmann 
161f1ae32a1SGerd Hoffmann const char *usb_device_get_product_desc(USBDevice *dev)
162f1ae32a1SGerd Hoffmann {
163f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
164f1ae32a1SGerd Hoffmann     return klass->product_desc;
165f1ae32a1SGerd Hoffmann }
166f1ae32a1SGerd Hoffmann 
167f1ae32a1SGerd Hoffmann const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
168f1ae32a1SGerd Hoffmann {
169f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
170386ab487SHans de Goede     if (dev->usb_desc) {
171386ab487SHans de Goede         return dev->usb_desc;
172386ab487SHans de Goede     }
173f1ae32a1SGerd Hoffmann     return klass->usb_desc;
174f1ae32a1SGerd Hoffmann }
175f1ae32a1SGerd Hoffmann 
176f1ae32a1SGerd Hoffmann void usb_device_set_interface(USBDevice *dev, int interface,
177f1ae32a1SGerd Hoffmann                               int alt_old, int alt_new)
178f1ae32a1SGerd Hoffmann {
179f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
180f1ae32a1SGerd Hoffmann     if (klass->set_interface) {
181f1ae32a1SGerd Hoffmann         klass->set_interface(dev, interface, alt_old, alt_new);
182f1ae32a1SGerd Hoffmann     }
183f1ae32a1SGerd Hoffmann }
184f1ae32a1SGerd Hoffmann 
18536dfe324SHans de Goede void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
18636dfe324SHans de Goede {
18736dfe324SHans de Goede     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
18836dfe324SHans de Goede     if (klass->flush_ep_queue) {
18936dfe324SHans de Goede         klass->flush_ep_queue(dev, ep);
19036dfe324SHans de Goede     }
19136dfe324SHans de Goede }
19236dfe324SHans de Goede 
193f79738b0SHans de Goede void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep)
194f79738b0SHans de Goede {
195f79738b0SHans de Goede     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
196f79738b0SHans de Goede     if (klass->ep_stopped) {
197f79738b0SHans de Goede         klass->ep_stopped(dev, ep);
198f79738b0SHans de Goede     }
199f79738b0SHans de Goede }
200f79738b0SHans de Goede 
201f1ae32a1SGerd Hoffmann static int usb_qdev_init(DeviceState *qdev)
202f1ae32a1SGerd Hoffmann {
203f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
204f1ae32a1SGerd Hoffmann     int rc;
205f1ae32a1SGerd Hoffmann 
206f1ae32a1SGerd Hoffmann     pstrcpy(dev->product_desc, sizeof(dev->product_desc),
207f1ae32a1SGerd Hoffmann             usb_device_get_product_desc(dev));
208f1ae32a1SGerd Hoffmann     dev->auto_attach = 1;
209f1ae32a1SGerd Hoffmann     QLIST_INIT(&dev->strings);
210f1ae32a1SGerd Hoffmann     usb_ep_init(dev);
211f1ae32a1SGerd Hoffmann     rc = usb_claim_port(dev);
212f1ae32a1SGerd Hoffmann     if (rc != 0) {
213f1ae32a1SGerd Hoffmann         return rc;
214f1ae32a1SGerd Hoffmann     }
215f1ae32a1SGerd Hoffmann     rc = usb_device_init(dev);
216f1ae32a1SGerd Hoffmann     if (rc != 0) {
217f1ae32a1SGerd Hoffmann         usb_release_port(dev);
218f1ae32a1SGerd Hoffmann         return rc;
219f1ae32a1SGerd Hoffmann     }
220f1ae32a1SGerd Hoffmann     if (dev->auto_attach) {
221f1ae32a1SGerd Hoffmann         rc = usb_device_attach(dev);
222f1ae32a1SGerd Hoffmann         if (rc != 0) {
223f1ae32a1SGerd Hoffmann             usb_qdev_exit(qdev);
224f1ae32a1SGerd Hoffmann             return rc;
225f1ae32a1SGerd Hoffmann         }
226f1ae32a1SGerd Hoffmann     }
227f1ae32a1SGerd Hoffmann     return 0;
228f1ae32a1SGerd Hoffmann }
229f1ae32a1SGerd Hoffmann 
230f1ae32a1SGerd Hoffmann static int usb_qdev_exit(DeviceState *qdev)
231f1ae32a1SGerd Hoffmann {
232f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
233f1ae32a1SGerd Hoffmann 
234f1ae32a1SGerd Hoffmann     if (dev->attached) {
235f1ae32a1SGerd Hoffmann         usb_device_detach(dev);
236f1ae32a1SGerd Hoffmann     }
237f1ae32a1SGerd Hoffmann     usb_device_handle_destroy(dev);
238f1ae32a1SGerd Hoffmann     if (dev->port) {
239f1ae32a1SGerd Hoffmann         usb_release_port(dev);
240f1ae32a1SGerd Hoffmann     }
241f1ae32a1SGerd Hoffmann     return 0;
242f1ae32a1SGerd Hoffmann }
243f1ae32a1SGerd Hoffmann 
244f1ae32a1SGerd Hoffmann typedef struct LegacyUSBFactory
245f1ae32a1SGerd Hoffmann {
246f1ae32a1SGerd Hoffmann     const char *name;
247f1ae32a1SGerd Hoffmann     const char *usbdevice_name;
248f1ae32a1SGerd Hoffmann     USBDevice *(*usbdevice_init)(USBBus *bus, const char *params);
249f1ae32a1SGerd Hoffmann } LegacyUSBFactory;
250f1ae32a1SGerd Hoffmann 
251f1ae32a1SGerd Hoffmann static GSList *legacy_usb_factory;
252f1ae32a1SGerd Hoffmann 
253f1ae32a1SGerd Hoffmann void usb_legacy_register(const char *typename, const char *usbdevice_name,
254f1ae32a1SGerd Hoffmann                          USBDevice *(*usbdevice_init)(USBBus *bus,
255f1ae32a1SGerd Hoffmann                                                       const char *params))
256f1ae32a1SGerd Hoffmann {
257f1ae32a1SGerd Hoffmann     if (usbdevice_name) {
258f1ae32a1SGerd Hoffmann         LegacyUSBFactory *f = g_malloc0(sizeof(*f));
259f1ae32a1SGerd Hoffmann         f->name = typename;
260f1ae32a1SGerd Hoffmann         f->usbdevice_name = usbdevice_name;
261f1ae32a1SGerd Hoffmann         f->usbdevice_init = usbdevice_init;
262f1ae32a1SGerd Hoffmann         legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
263f1ae32a1SGerd Hoffmann     }
264f1ae32a1SGerd Hoffmann }
265f1ae32a1SGerd Hoffmann 
266f1ae32a1SGerd Hoffmann USBDevice *usb_create(USBBus *bus, const char *name)
267f1ae32a1SGerd Hoffmann {
268f1ae32a1SGerd Hoffmann     DeviceState *dev;
269f1ae32a1SGerd Hoffmann 
270f1ae32a1SGerd Hoffmann     dev = qdev_create(&bus->qbus, name);
271f1ae32a1SGerd Hoffmann     return USB_DEVICE(dev);
272f1ae32a1SGerd Hoffmann }
273f1ae32a1SGerd Hoffmann 
274f1ae32a1SGerd Hoffmann USBDevice *usb_create_simple(USBBus *bus, const char *name)
275f1ae32a1SGerd Hoffmann {
276f1ae32a1SGerd Hoffmann     USBDevice *dev = usb_create(bus, name);
277f1ae32a1SGerd Hoffmann     int rc;
278f1ae32a1SGerd Hoffmann 
279f1ae32a1SGerd Hoffmann     if (!dev) {
280f1ae32a1SGerd Hoffmann         error_report("Failed to create USB device '%s'", name);
281f1ae32a1SGerd Hoffmann         return NULL;
282f1ae32a1SGerd Hoffmann     }
283f1ae32a1SGerd Hoffmann     rc = qdev_init(&dev->qdev);
284f1ae32a1SGerd Hoffmann     if (rc < 0) {
285f1ae32a1SGerd Hoffmann         error_report("Failed to initialize USB device '%s'", name);
286f1ae32a1SGerd Hoffmann         return NULL;
287f1ae32a1SGerd Hoffmann     }
288f1ae32a1SGerd Hoffmann     return dev;
289f1ae32a1SGerd Hoffmann }
290f1ae32a1SGerd Hoffmann 
291f1ae32a1SGerd Hoffmann static void usb_fill_port(USBPort *port, void *opaque, int index,
292f1ae32a1SGerd Hoffmann                           USBPortOps *ops, int speedmask)
293f1ae32a1SGerd Hoffmann {
294f1ae32a1SGerd Hoffmann     port->opaque = opaque;
295f1ae32a1SGerd Hoffmann     port->index = index;
296f1ae32a1SGerd Hoffmann     port->ops = ops;
297f1ae32a1SGerd Hoffmann     port->speedmask = speedmask;
298f1ae32a1SGerd Hoffmann     usb_port_location(port, NULL, index + 1);
299f1ae32a1SGerd Hoffmann }
300f1ae32a1SGerd Hoffmann 
301f1ae32a1SGerd Hoffmann void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
302f1ae32a1SGerd Hoffmann                        USBPortOps *ops, int speedmask)
303f1ae32a1SGerd Hoffmann {
304f1ae32a1SGerd Hoffmann     usb_fill_port(port, opaque, index, ops, speedmask);
305f1ae32a1SGerd Hoffmann     QTAILQ_INSERT_TAIL(&bus->free, port, next);
306f1ae32a1SGerd Hoffmann     bus->nfree++;
307f1ae32a1SGerd Hoffmann }
308f1ae32a1SGerd Hoffmann 
309f1ae32a1SGerd Hoffmann int usb_register_companion(const char *masterbus, USBPort *ports[],
310f1ae32a1SGerd Hoffmann                            uint32_t portcount, uint32_t firstport,
311f1ae32a1SGerd Hoffmann                            void *opaque, USBPortOps *ops, int speedmask)
312f1ae32a1SGerd Hoffmann {
313f1ae32a1SGerd Hoffmann     USBBus *bus;
314f1ae32a1SGerd Hoffmann     int i;
315f1ae32a1SGerd Hoffmann 
316f1ae32a1SGerd Hoffmann     QTAILQ_FOREACH(bus, &busses, next) {
317f1ae32a1SGerd Hoffmann         if (strcmp(bus->qbus.name, masterbus) == 0) {
318f1ae32a1SGerd Hoffmann             break;
319f1ae32a1SGerd Hoffmann         }
320f1ae32a1SGerd Hoffmann     }
321f1ae32a1SGerd Hoffmann 
322f1ae32a1SGerd Hoffmann     if (!bus || !bus->ops->register_companion) {
323f1ae32a1SGerd Hoffmann         qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
324f1ae32a1SGerd Hoffmann                       "an USB masterbus");
325f1ae32a1SGerd Hoffmann         if (bus) {
326f1ae32a1SGerd Hoffmann             error_printf_unless_qmp(
327f1ae32a1SGerd Hoffmann                 "USB bus '%s' does not allow companion controllers\n",
328f1ae32a1SGerd Hoffmann                 masterbus);
329f1ae32a1SGerd Hoffmann         }
330f1ae32a1SGerd Hoffmann         return -1;
331f1ae32a1SGerd Hoffmann     }
332f1ae32a1SGerd Hoffmann 
333f1ae32a1SGerd Hoffmann     for (i = 0; i < portcount; i++) {
334f1ae32a1SGerd Hoffmann         usb_fill_port(ports[i], opaque, i, ops, speedmask);
335f1ae32a1SGerd Hoffmann     }
336f1ae32a1SGerd Hoffmann 
337f1ae32a1SGerd Hoffmann     return bus->ops->register_companion(bus, ports, portcount, firstport);
338f1ae32a1SGerd Hoffmann }
339f1ae32a1SGerd Hoffmann 
340f1ae32a1SGerd Hoffmann void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
341f1ae32a1SGerd Hoffmann {
342f1ae32a1SGerd Hoffmann     if (upstream) {
343f1ae32a1SGerd Hoffmann         snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
344f1ae32a1SGerd Hoffmann                  upstream->path, portnr);
345c24e4aacSGerd Hoffmann         downstream->hubcount = upstream->hubcount + 1;
346f1ae32a1SGerd Hoffmann     } else {
347f1ae32a1SGerd Hoffmann         snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
348c24e4aacSGerd Hoffmann         downstream->hubcount = 0;
349f1ae32a1SGerd Hoffmann     }
350f1ae32a1SGerd Hoffmann }
351f1ae32a1SGerd Hoffmann 
352f1ae32a1SGerd Hoffmann void usb_unregister_port(USBBus *bus, USBPort *port)
353f1ae32a1SGerd Hoffmann {
354f1ae32a1SGerd Hoffmann     if (port->dev)
355f1ae32a1SGerd Hoffmann         qdev_free(&port->dev->qdev);
356f1ae32a1SGerd Hoffmann     QTAILQ_REMOVE(&bus->free, port, next);
357f1ae32a1SGerd Hoffmann     bus->nfree--;
358f1ae32a1SGerd Hoffmann }
359f1ae32a1SGerd Hoffmann 
360f1ae32a1SGerd Hoffmann int usb_claim_port(USBDevice *dev)
361f1ae32a1SGerd Hoffmann {
362f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
363f1ae32a1SGerd Hoffmann     USBPort *port;
364f1ae32a1SGerd Hoffmann 
365f1ae32a1SGerd Hoffmann     assert(dev->port == NULL);
366f1ae32a1SGerd Hoffmann 
367f1ae32a1SGerd Hoffmann     if (dev->port_path) {
368f1ae32a1SGerd Hoffmann         QTAILQ_FOREACH(port, &bus->free, next) {
369f1ae32a1SGerd Hoffmann             if (strcmp(port->path, dev->port_path) == 0) {
370f1ae32a1SGerd Hoffmann                 break;
371f1ae32a1SGerd Hoffmann             }
372f1ae32a1SGerd Hoffmann         }
373f1ae32a1SGerd Hoffmann         if (port == NULL) {
374f1ae32a1SGerd Hoffmann             error_report("Error: usb port %s (bus %s) not found (in use?)",
375f1ae32a1SGerd Hoffmann                          dev->port_path, bus->qbus.name);
376f1ae32a1SGerd Hoffmann             return -1;
377f1ae32a1SGerd Hoffmann         }
378f1ae32a1SGerd Hoffmann     } else {
379f1ae32a1SGerd Hoffmann         if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
380f1ae32a1SGerd Hoffmann             /* Create a new hub and chain it on */
381f1ae32a1SGerd Hoffmann             usb_create_simple(bus, "usb-hub");
382f1ae32a1SGerd Hoffmann         }
383f1ae32a1SGerd Hoffmann         if (bus->nfree == 0) {
384f1ae32a1SGerd Hoffmann             error_report("Error: tried to attach usb device %s to a bus "
385f1ae32a1SGerd Hoffmann                          "with no free ports", dev->product_desc);
386f1ae32a1SGerd Hoffmann             return -1;
387f1ae32a1SGerd Hoffmann         }
388f1ae32a1SGerd Hoffmann         port = QTAILQ_FIRST(&bus->free);
389f1ae32a1SGerd Hoffmann     }
390f1ae32a1SGerd Hoffmann     trace_usb_port_claim(bus->busnr, port->path);
391f1ae32a1SGerd Hoffmann 
392f1ae32a1SGerd Hoffmann     QTAILQ_REMOVE(&bus->free, port, next);
393f1ae32a1SGerd Hoffmann     bus->nfree--;
394f1ae32a1SGerd Hoffmann 
395f1ae32a1SGerd Hoffmann     dev->port = port;
396f1ae32a1SGerd Hoffmann     port->dev = dev;
397f1ae32a1SGerd Hoffmann 
398f1ae32a1SGerd Hoffmann     QTAILQ_INSERT_TAIL(&bus->used, port, next);
399f1ae32a1SGerd Hoffmann     bus->nused++;
400f1ae32a1SGerd Hoffmann     return 0;
401f1ae32a1SGerd Hoffmann }
402f1ae32a1SGerd Hoffmann 
403f1ae32a1SGerd Hoffmann void usb_release_port(USBDevice *dev)
404f1ae32a1SGerd Hoffmann {
405f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
406f1ae32a1SGerd Hoffmann     USBPort *port = dev->port;
407f1ae32a1SGerd Hoffmann 
408f1ae32a1SGerd Hoffmann     assert(port != NULL);
409f1ae32a1SGerd Hoffmann     trace_usb_port_release(bus->busnr, port->path);
410f1ae32a1SGerd Hoffmann 
411f1ae32a1SGerd Hoffmann     QTAILQ_REMOVE(&bus->used, port, next);
412f1ae32a1SGerd Hoffmann     bus->nused--;
413f1ae32a1SGerd Hoffmann 
414f1ae32a1SGerd Hoffmann     dev->port = NULL;
415f1ae32a1SGerd Hoffmann     port->dev = NULL;
416f1ae32a1SGerd Hoffmann 
417f1ae32a1SGerd Hoffmann     QTAILQ_INSERT_TAIL(&bus->free, port, next);
418f1ae32a1SGerd Hoffmann     bus->nfree++;
419f1ae32a1SGerd Hoffmann }
420f1ae32a1SGerd Hoffmann 
4213b7e759aSGerd Hoffmann static void usb_mask_to_str(char *dest, size_t size,
4223b7e759aSGerd Hoffmann                             unsigned int speedmask)
4233b7e759aSGerd Hoffmann {
4243b7e759aSGerd Hoffmann     static const struct {
4253b7e759aSGerd Hoffmann         unsigned int mask;
4263b7e759aSGerd Hoffmann         const char *name;
4273b7e759aSGerd Hoffmann     } speeds[] = {
4283b7e759aSGerd Hoffmann         { .mask = USB_SPEED_MASK_FULL,  .name = "full"  },
4293b7e759aSGerd Hoffmann         { .mask = USB_SPEED_MASK_HIGH,  .name = "high"  },
4303b7e759aSGerd Hoffmann         { .mask = USB_SPEED_MASK_SUPER, .name = "super" },
4313b7e759aSGerd Hoffmann     };
4323b7e759aSGerd Hoffmann     int i, pos = 0;
4333b7e759aSGerd Hoffmann 
4343b7e759aSGerd Hoffmann     for (i = 0; i < ARRAY_SIZE(speeds); i++) {
4353b7e759aSGerd Hoffmann         if (speeds[i].mask & speedmask) {
4363b7e759aSGerd Hoffmann             pos += snprintf(dest + pos, size - pos, "%s%s",
4373b7e759aSGerd Hoffmann                             pos ? "+" : "",
4383b7e759aSGerd Hoffmann                             speeds[i].name);
4393b7e759aSGerd Hoffmann         }
4403b7e759aSGerd Hoffmann     }
4413b7e759aSGerd Hoffmann }
4423b7e759aSGerd Hoffmann 
443f1ae32a1SGerd Hoffmann int usb_device_attach(USBDevice *dev)
444f1ae32a1SGerd Hoffmann {
445f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
446f1ae32a1SGerd Hoffmann     USBPort *port = dev->port;
4473b7e759aSGerd Hoffmann     char devspeed[32], portspeed[32];
448f1ae32a1SGerd Hoffmann 
449f1ae32a1SGerd Hoffmann     assert(port != NULL);
450f1ae32a1SGerd Hoffmann     assert(!dev->attached);
4513b7e759aSGerd Hoffmann     usb_mask_to_str(devspeed, sizeof(devspeed), dev->speedmask);
4523b7e759aSGerd Hoffmann     usb_mask_to_str(portspeed, sizeof(portspeed), port->speedmask);
4533b7e759aSGerd Hoffmann     trace_usb_port_attach(bus->busnr, port->path,
4543b7e759aSGerd Hoffmann                           devspeed, portspeed);
455f1ae32a1SGerd Hoffmann 
456f1ae32a1SGerd Hoffmann     if (!(port->speedmask & dev->speedmask)) {
457f1ae32a1SGerd Hoffmann         error_report("Warning: speed mismatch trying to attach"
4583b7e759aSGerd Hoffmann                      " usb device \"%s\" (%s speed)"
4593b7e759aSGerd Hoffmann                      " to bus \"%s\", port \"%s\" (%s speed)",
4603b7e759aSGerd Hoffmann                      dev->product_desc, devspeed,
4613b7e759aSGerd Hoffmann                      bus->qbus.name, port->path, portspeed);
462f1ae32a1SGerd Hoffmann         return -1;
463f1ae32a1SGerd Hoffmann     }
464f1ae32a1SGerd Hoffmann 
465f1ae32a1SGerd Hoffmann     dev->attached++;
466f1ae32a1SGerd Hoffmann     usb_attach(port);
467f1ae32a1SGerd Hoffmann 
468f1ae32a1SGerd Hoffmann     return 0;
469f1ae32a1SGerd Hoffmann }
470f1ae32a1SGerd Hoffmann 
471f1ae32a1SGerd Hoffmann int usb_device_detach(USBDevice *dev)
472f1ae32a1SGerd Hoffmann {
473f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
474f1ae32a1SGerd Hoffmann     USBPort *port = dev->port;
475f1ae32a1SGerd Hoffmann 
476f1ae32a1SGerd Hoffmann     assert(port != NULL);
477f1ae32a1SGerd Hoffmann     assert(dev->attached);
478f1ae32a1SGerd Hoffmann     trace_usb_port_detach(bus->busnr, port->path);
479f1ae32a1SGerd Hoffmann 
480f1ae32a1SGerd Hoffmann     usb_detach(port);
481f1ae32a1SGerd Hoffmann     dev->attached--;
482f1ae32a1SGerd Hoffmann     return 0;
483f1ae32a1SGerd Hoffmann }
484f1ae32a1SGerd Hoffmann 
485f1ae32a1SGerd Hoffmann int usb_device_delete_addr(int busnr, int addr)
486f1ae32a1SGerd Hoffmann {
487f1ae32a1SGerd Hoffmann     USBBus *bus;
488f1ae32a1SGerd Hoffmann     USBPort *port;
489f1ae32a1SGerd Hoffmann     USBDevice *dev;
490f1ae32a1SGerd Hoffmann 
491f1ae32a1SGerd Hoffmann     bus = usb_bus_find(busnr);
492f1ae32a1SGerd Hoffmann     if (!bus)
493f1ae32a1SGerd Hoffmann         return -1;
494f1ae32a1SGerd Hoffmann 
495f1ae32a1SGerd Hoffmann     QTAILQ_FOREACH(port, &bus->used, next) {
496f1ae32a1SGerd Hoffmann         if (port->dev->addr == addr)
497f1ae32a1SGerd Hoffmann             break;
498f1ae32a1SGerd Hoffmann     }
499f1ae32a1SGerd Hoffmann     if (!port)
500f1ae32a1SGerd Hoffmann         return -1;
501f1ae32a1SGerd Hoffmann     dev = port->dev;
502f1ae32a1SGerd Hoffmann 
503f1ae32a1SGerd Hoffmann     qdev_free(&dev->qdev);
504f1ae32a1SGerd Hoffmann     return 0;
505f1ae32a1SGerd Hoffmann }
506f1ae32a1SGerd Hoffmann 
507f1ae32a1SGerd Hoffmann static const char *usb_speed(unsigned int speed)
508f1ae32a1SGerd Hoffmann {
509f1ae32a1SGerd Hoffmann     static const char *txt[] = {
510f1ae32a1SGerd Hoffmann         [ USB_SPEED_LOW  ] = "1.5",
511f1ae32a1SGerd Hoffmann         [ USB_SPEED_FULL ] = "12",
512f1ae32a1SGerd Hoffmann         [ USB_SPEED_HIGH ] = "480",
513f1ae32a1SGerd Hoffmann         [ USB_SPEED_SUPER ] = "5000",
514f1ae32a1SGerd Hoffmann     };
515f1ae32a1SGerd Hoffmann     if (speed >= ARRAY_SIZE(txt))
516f1ae32a1SGerd Hoffmann         return "?";
517f1ae32a1SGerd Hoffmann     return txt[speed];
518f1ae32a1SGerd Hoffmann }
519f1ae32a1SGerd Hoffmann 
520f1ae32a1SGerd Hoffmann static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
521f1ae32a1SGerd Hoffmann {
522f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
523f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
524f1ae32a1SGerd Hoffmann 
525f1ae32a1SGerd Hoffmann     monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
526f1ae32a1SGerd Hoffmann                    indent, "", bus->busnr, dev->addr,
527f1ae32a1SGerd Hoffmann                    dev->port ? dev->port->path : "-",
528f1ae32a1SGerd Hoffmann                    usb_speed(dev->speed), dev->product_desc,
529f1ae32a1SGerd Hoffmann                    dev->attached ? ", attached" : "");
530f1ae32a1SGerd Hoffmann }
531f1ae32a1SGerd Hoffmann 
532f1ae32a1SGerd Hoffmann static char *usb_get_dev_path(DeviceState *qdev)
533f1ae32a1SGerd Hoffmann {
534f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
535eeb0cf9aSGerd Hoffmann     DeviceState *hcd = qdev->parent_bus->parent;
536eeb0cf9aSGerd Hoffmann     char *id = NULL;
537eeb0cf9aSGerd Hoffmann 
53809e5ab63SAnthony Liguori     if (dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) {
53909e5ab63SAnthony Liguori         id = qdev_get_dev_path(hcd);
540eeb0cf9aSGerd Hoffmann     }
541eeb0cf9aSGerd Hoffmann     if (id) {
542eeb0cf9aSGerd Hoffmann         char *ret = g_strdup_printf("%s/%s", id, dev->port->path);
543eeb0cf9aSGerd Hoffmann         g_free(id);
544eeb0cf9aSGerd Hoffmann         return ret;
545eeb0cf9aSGerd Hoffmann     } else {
546f1ae32a1SGerd Hoffmann         return g_strdup(dev->port->path);
547f1ae32a1SGerd Hoffmann     }
548eeb0cf9aSGerd Hoffmann }
549f1ae32a1SGerd Hoffmann 
550f1ae32a1SGerd Hoffmann static char *usb_get_fw_dev_path(DeviceState *qdev)
551f1ae32a1SGerd Hoffmann {
552f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
553f1ae32a1SGerd Hoffmann     char *fw_path, *in;
554f1ae32a1SGerd Hoffmann     ssize_t pos = 0, fw_len;
555f1ae32a1SGerd Hoffmann     long nr;
556f1ae32a1SGerd Hoffmann 
557f1ae32a1SGerd Hoffmann     fw_len = 32 + strlen(dev->port->path) * 6;
558f1ae32a1SGerd Hoffmann     fw_path = g_malloc(fw_len);
559f1ae32a1SGerd Hoffmann     in = dev->port->path;
560f1ae32a1SGerd Hoffmann     while (fw_len - pos > 0) {
561f1ae32a1SGerd Hoffmann         nr = strtol(in, &in, 10);
562f1ae32a1SGerd Hoffmann         if (in[0] == '.') {
563f1ae32a1SGerd Hoffmann             /* some hub between root port and device */
564f1ae32a1SGerd Hoffmann             pos += snprintf(fw_path + pos, fw_len - pos, "hub@%ld/", nr);
565f1ae32a1SGerd Hoffmann             in++;
566f1ae32a1SGerd Hoffmann         } else {
567f1ae32a1SGerd Hoffmann             /* the device itself */
568f1ae32a1SGerd Hoffmann             pos += snprintf(fw_path + pos, fw_len - pos, "%s@%ld",
569f1ae32a1SGerd Hoffmann                             qdev_fw_name(qdev), nr);
570f1ae32a1SGerd Hoffmann             break;
571f1ae32a1SGerd Hoffmann         }
572f1ae32a1SGerd Hoffmann     }
573f1ae32a1SGerd Hoffmann     return fw_path;
574f1ae32a1SGerd Hoffmann }
575f1ae32a1SGerd Hoffmann 
57684f2d0eaSWenchao Xia void usb_info(Monitor *mon, const QDict *qdict)
577f1ae32a1SGerd Hoffmann {
578f1ae32a1SGerd Hoffmann     USBBus *bus;
579f1ae32a1SGerd Hoffmann     USBDevice *dev;
580f1ae32a1SGerd Hoffmann     USBPort *port;
581f1ae32a1SGerd Hoffmann 
582f1ae32a1SGerd Hoffmann     if (QTAILQ_EMPTY(&busses)) {
583f1ae32a1SGerd Hoffmann         monitor_printf(mon, "USB support not enabled\n");
584f1ae32a1SGerd Hoffmann         return;
585f1ae32a1SGerd Hoffmann     }
586f1ae32a1SGerd Hoffmann 
587f1ae32a1SGerd Hoffmann     QTAILQ_FOREACH(bus, &busses, next) {
588f1ae32a1SGerd Hoffmann         QTAILQ_FOREACH(port, &bus->used, next) {
589f1ae32a1SGerd Hoffmann             dev = port->dev;
590f1ae32a1SGerd Hoffmann             if (!dev)
591f1ae32a1SGerd Hoffmann                 continue;
592f1ae32a1SGerd Hoffmann             monitor_printf(mon, "  Device %d.%d, Port %s, Speed %s Mb/s, Product %s\n",
593f1ae32a1SGerd Hoffmann                            bus->busnr, dev->addr, port->path, usb_speed(dev->speed),
594f1ae32a1SGerd Hoffmann                            dev->product_desc);
595f1ae32a1SGerd Hoffmann         }
596f1ae32a1SGerd Hoffmann     }
597f1ae32a1SGerd Hoffmann }
598f1ae32a1SGerd Hoffmann 
599f1ae32a1SGerd Hoffmann /* handle legacy -usbdevice cmd line option */
600f1ae32a1SGerd Hoffmann USBDevice *usbdevice_create(const char *cmdline)
601f1ae32a1SGerd Hoffmann {
602f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_find(-1 /* any */);
603f1ae32a1SGerd Hoffmann     LegacyUSBFactory *f = NULL;
604f1ae32a1SGerd Hoffmann     GSList *i;
605f1ae32a1SGerd Hoffmann     char driver[32];
606f1ae32a1SGerd Hoffmann     const char *params;
607f1ae32a1SGerd Hoffmann     int len;
608f1ae32a1SGerd Hoffmann 
609f1ae32a1SGerd Hoffmann     params = strchr(cmdline,':');
610f1ae32a1SGerd Hoffmann     if (params) {
611f1ae32a1SGerd Hoffmann         params++;
612f1ae32a1SGerd Hoffmann         len = params - cmdline;
613f1ae32a1SGerd Hoffmann         if (len > sizeof(driver))
614f1ae32a1SGerd Hoffmann             len = sizeof(driver);
615f1ae32a1SGerd Hoffmann         pstrcpy(driver, len, cmdline);
616f1ae32a1SGerd Hoffmann     } else {
617f1ae32a1SGerd Hoffmann         params = "";
618f1ae32a1SGerd Hoffmann         pstrcpy(driver, sizeof(driver), cmdline);
619f1ae32a1SGerd Hoffmann     }
620f1ae32a1SGerd Hoffmann 
621f1ae32a1SGerd Hoffmann     for (i = legacy_usb_factory; i; i = i->next) {
622f1ae32a1SGerd Hoffmann         f = i->data;
623f1ae32a1SGerd Hoffmann         if (strcmp(f->usbdevice_name, driver) == 0) {
624f1ae32a1SGerd Hoffmann             break;
625f1ae32a1SGerd Hoffmann         }
626f1ae32a1SGerd Hoffmann     }
627f1ae32a1SGerd Hoffmann     if (i == NULL) {
628f1ae32a1SGerd Hoffmann #if 0
629f1ae32a1SGerd Hoffmann         /* no error because some drivers are not converted (yet) */
630f1ae32a1SGerd Hoffmann         error_report("usbdevice %s not found", driver);
631f1ae32a1SGerd Hoffmann #endif
632f1ae32a1SGerd Hoffmann         return NULL;
633f1ae32a1SGerd Hoffmann     }
634f1ae32a1SGerd Hoffmann 
635c128d6a6SStefan Hajnoczi     if (!bus) {
636c128d6a6SStefan Hajnoczi         error_report("Error: no usb bus to attach usbdevice %s, "
637c128d6a6SStefan Hajnoczi                      "please try -machine usb=on and check that "
638c128d6a6SStefan Hajnoczi                      "the machine model supports USB", driver);
639c128d6a6SStefan Hajnoczi         return NULL;
640c128d6a6SStefan Hajnoczi     }
641c128d6a6SStefan Hajnoczi 
642f1ae32a1SGerd Hoffmann     if (!f->usbdevice_init) {
643f1ae32a1SGerd Hoffmann         if (*params) {
644f1ae32a1SGerd Hoffmann             error_report("usbdevice %s accepts no params", driver);
645f1ae32a1SGerd Hoffmann             return NULL;
646f1ae32a1SGerd Hoffmann         }
647f1ae32a1SGerd Hoffmann         return usb_create_simple(bus, f->name);
648f1ae32a1SGerd Hoffmann     }
649f1ae32a1SGerd Hoffmann     return f->usbdevice_init(bus, params);
650f1ae32a1SGerd Hoffmann }
651f1ae32a1SGerd Hoffmann 
652f1ae32a1SGerd Hoffmann static void usb_device_class_init(ObjectClass *klass, void *data)
653f1ae32a1SGerd Hoffmann {
654f1ae32a1SGerd Hoffmann     DeviceClass *k = DEVICE_CLASS(klass);
6550d936928SAnthony Liguori     k->bus_type = TYPE_USB_BUS;
656f1ae32a1SGerd Hoffmann     k->init     = usb_qdev_init;
657f1ae32a1SGerd Hoffmann     k->unplug   = qdev_simple_unplug_cb;
658f1ae32a1SGerd Hoffmann     k->exit     = usb_qdev_exit;
659bce54474SPaolo Bonzini     k->props    = usb_props;
660f1ae32a1SGerd Hoffmann }
661f1ae32a1SGerd Hoffmann 
6628c43a6f0SAndreas Färber static const TypeInfo usb_device_type_info = {
663f1ae32a1SGerd Hoffmann     .name = TYPE_USB_DEVICE,
664f1ae32a1SGerd Hoffmann     .parent = TYPE_DEVICE,
665f1ae32a1SGerd Hoffmann     .instance_size = sizeof(USBDevice),
666f1ae32a1SGerd Hoffmann     .abstract = true,
667f1ae32a1SGerd Hoffmann     .class_size = sizeof(USBDeviceClass),
668f1ae32a1SGerd Hoffmann     .class_init = usb_device_class_init,
669f1ae32a1SGerd Hoffmann };
670f1ae32a1SGerd Hoffmann 
671f1ae32a1SGerd Hoffmann static void usb_register_types(void)
672f1ae32a1SGerd Hoffmann {
6730d936928SAnthony Liguori     type_register_static(&usb_bus_info);
674f1ae32a1SGerd Hoffmann     type_register_static(&usb_device_type_info);
675f1ae32a1SGerd Hoffmann }
676f1ae32a1SGerd Hoffmann 
677f1ae32a1SGerd Hoffmann type_init(usb_register_types)
678