xref: /openbmc/qemu/hw/usb/bus.c (revision 7d553f27)
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);
12*7d553f27SGonglei static void usb_qdev_unrealize(DeviceState *qdev, Error **errp);
13f1ae32a1SGerd Hoffmann 
143cb75a7cSPaolo Bonzini static Property usb_props[] = {
153cb75a7cSPaolo Bonzini     DEFINE_PROP_STRING("port", USBDevice, port_path),
1671938a09SGerd Hoffmann     DEFINE_PROP_STRING("serial", USBDevice, serial),
173cb75a7cSPaolo Bonzini     DEFINE_PROP_BIT("full-path", USBDevice, flags,
183cb75a7cSPaolo Bonzini                     USB_DEV_FLAG_FULL_PATH, true),
195319dc7bSGerd Hoffmann     DEFINE_PROP_BIT("msos-desc", USBDevice, flags,
205319dc7bSGerd Hoffmann                     USB_DEV_FLAG_MSOS_DESC_ENABLE, true),
213cb75a7cSPaolo Bonzini     DEFINE_PROP_END_OF_LIST()
223cb75a7cSPaolo Bonzini };
233cb75a7cSPaolo Bonzini 
240d936928SAnthony Liguori static void usb_bus_class_init(ObjectClass *klass, void *data)
250d936928SAnthony Liguori {
260d936928SAnthony Liguori     BusClass *k = BUS_CLASS(klass);
270d936928SAnthony Liguori 
280d936928SAnthony Liguori     k->print_dev = usb_bus_dev_print;
290d936928SAnthony Liguori     k->get_dev_path = usb_get_dev_path;
300d936928SAnthony Liguori     k->get_fw_dev_path = usb_get_fw_dev_path;
310d936928SAnthony Liguori }
320d936928SAnthony Liguori 
330d936928SAnthony Liguori static const TypeInfo usb_bus_info = {
340d936928SAnthony Liguori     .name = TYPE_USB_BUS,
350d936928SAnthony Liguori     .parent = TYPE_BUS,
360d936928SAnthony Liguori     .instance_size = sizeof(USBBus),
370d936928SAnthony Liguori     .class_init = usb_bus_class_init,
38f1ae32a1SGerd Hoffmann };
393cb75a7cSPaolo Bonzini 
40f1ae32a1SGerd Hoffmann static int next_usb_bus = 0;
41f1ae32a1SGerd Hoffmann static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
42f1ae32a1SGerd Hoffmann 
43495d5447SGerd Hoffmann static int usb_device_post_load(void *opaque, int version_id)
44495d5447SGerd Hoffmann {
45495d5447SGerd Hoffmann     USBDevice *dev = opaque;
46495d5447SGerd Hoffmann 
47495d5447SGerd Hoffmann     if (dev->state == USB_STATE_NOTATTACHED) {
48495d5447SGerd Hoffmann         dev->attached = 0;
49495d5447SGerd Hoffmann     } else {
50495d5447SGerd Hoffmann         dev->attached = 1;
51495d5447SGerd Hoffmann     }
529f8e9895SMichael S. Tsirkin     if (dev->setup_index < 0 ||
539f8e9895SMichael S. Tsirkin         dev->setup_len < 0 ||
54719ffe1fSMichael S. Tsirkin         dev->setup_index > dev->setup_len ||
55719ffe1fSMichael S. Tsirkin         dev->setup_len > sizeof(dev->data_buf)) {
56c60174e8SGerd Hoffmann         return -EINVAL;
57c60174e8SGerd Hoffmann     }
58495d5447SGerd Hoffmann     return 0;
59495d5447SGerd Hoffmann }
60495d5447SGerd Hoffmann 
61f1ae32a1SGerd Hoffmann const VMStateDescription vmstate_usb_device = {
62f1ae32a1SGerd Hoffmann     .name = "USBDevice",
63f1ae32a1SGerd Hoffmann     .version_id = 1,
64f1ae32a1SGerd Hoffmann     .minimum_version_id = 1,
65495d5447SGerd Hoffmann     .post_load = usb_device_post_load,
66f1ae32a1SGerd Hoffmann     .fields = (VMStateField[]) {
67f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(addr, USBDevice),
68f1ae32a1SGerd Hoffmann         VMSTATE_INT32(state, USBDevice),
69f1ae32a1SGerd Hoffmann         VMSTATE_INT32(remote_wakeup, USBDevice),
70f1ae32a1SGerd Hoffmann         VMSTATE_INT32(setup_state, USBDevice),
71f1ae32a1SGerd Hoffmann         VMSTATE_INT32(setup_len, USBDevice),
72f1ae32a1SGerd Hoffmann         VMSTATE_INT32(setup_index, USBDevice),
73f1ae32a1SGerd Hoffmann         VMSTATE_UINT8_ARRAY(setup_buf, USBDevice, 8),
74f1ae32a1SGerd Hoffmann         VMSTATE_END_OF_LIST(),
75f1ae32a1SGerd Hoffmann     }
76f1ae32a1SGerd Hoffmann };
77f1ae32a1SGerd Hoffmann 
78c889b3a5SAndreas Färber void usb_bus_new(USBBus *bus, size_t bus_size,
79c889b3a5SAndreas Färber                  USBBusOps *ops, DeviceState *host)
80f1ae32a1SGerd Hoffmann {
81fb17dfe0SAndreas Färber     qbus_create_inplace(bus, bus_size, TYPE_USB_BUS, host, NULL);
82f1ae32a1SGerd Hoffmann     bus->ops = ops;
83f1ae32a1SGerd Hoffmann     bus->busnr = next_usb_bus++;
84f1ae32a1SGerd Hoffmann     bus->qbus.allow_hotplug = 1; /* Yes, we can */
85f1ae32a1SGerd Hoffmann     QTAILQ_INIT(&bus->free);
86f1ae32a1SGerd Hoffmann     QTAILQ_INIT(&bus->used);
87f1ae32a1SGerd Hoffmann     QTAILQ_INSERT_TAIL(&busses, bus, next);
88f1ae32a1SGerd Hoffmann }
89f1ae32a1SGerd Hoffmann 
90e5a9beceSGonglei void usb_bus_release(USBBus *bus)
91e5a9beceSGonglei {
92e5a9beceSGonglei     assert(next_usb_bus > 0);
93e5a9beceSGonglei 
94e5a9beceSGonglei     QTAILQ_REMOVE(&busses, bus, next);
95e5a9beceSGonglei }
96e5a9beceSGonglei 
97f1ae32a1SGerd Hoffmann USBBus *usb_bus_find(int busnr)
98f1ae32a1SGerd Hoffmann {
99f1ae32a1SGerd Hoffmann     USBBus *bus;
100f1ae32a1SGerd Hoffmann 
101f1ae32a1SGerd Hoffmann     if (-1 == busnr)
102f1ae32a1SGerd Hoffmann         return QTAILQ_FIRST(&busses);
103f1ae32a1SGerd Hoffmann     QTAILQ_FOREACH(bus, &busses, next) {
104f1ae32a1SGerd Hoffmann         if (bus->busnr == busnr)
105f1ae32a1SGerd Hoffmann             return bus;
106f1ae32a1SGerd Hoffmann     }
107f1ae32a1SGerd Hoffmann     return NULL;
108f1ae32a1SGerd Hoffmann }
109f1ae32a1SGerd Hoffmann 
110*7d553f27SGonglei static void usb_device_realize(USBDevice *dev, Error **errp)
111f1ae32a1SGerd Hoffmann {
112f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
113*7d553f27SGonglei 
114*7d553f27SGonglei     if (klass->realize) {
115*7d553f27SGonglei         klass->realize(dev, errp);
116*7d553f27SGonglei     } else if (klass->init) {
117*7d553f27SGonglei         klass->init(dev);
118f1ae32a1SGerd Hoffmann     }
119f1ae32a1SGerd Hoffmann }
120f1ae32a1SGerd Hoffmann 
121f1ae32a1SGerd Hoffmann USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
122f1ae32a1SGerd Hoffmann {
123f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
124f1ae32a1SGerd Hoffmann     if (klass->find_device) {
125f1ae32a1SGerd Hoffmann         return klass->find_device(dev, addr);
126f1ae32a1SGerd Hoffmann     }
127f1ae32a1SGerd Hoffmann     return NULL;
128f1ae32a1SGerd Hoffmann }
129f1ae32a1SGerd Hoffmann 
130f1ae32a1SGerd Hoffmann static void usb_device_handle_destroy(USBDevice *dev)
131f1ae32a1SGerd Hoffmann {
132f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
133f1ae32a1SGerd Hoffmann     if (klass->handle_destroy) {
134f1ae32a1SGerd Hoffmann         klass->handle_destroy(dev);
135f1ae32a1SGerd Hoffmann     }
136f1ae32a1SGerd Hoffmann }
137f1ae32a1SGerd Hoffmann 
138f1ae32a1SGerd Hoffmann void usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
139f1ae32a1SGerd Hoffmann {
140f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
141f1ae32a1SGerd Hoffmann     if (klass->cancel_packet) {
142f1ae32a1SGerd Hoffmann         klass->cancel_packet(dev, p);
143f1ae32a1SGerd Hoffmann     }
144f1ae32a1SGerd Hoffmann }
145f1ae32a1SGerd Hoffmann 
146f1ae32a1SGerd Hoffmann void usb_device_handle_attach(USBDevice *dev)
147f1ae32a1SGerd Hoffmann {
148f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
149f1ae32a1SGerd Hoffmann     if (klass->handle_attach) {
150f1ae32a1SGerd Hoffmann         klass->handle_attach(dev);
151f1ae32a1SGerd Hoffmann     }
152f1ae32a1SGerd Hoffmann }
153f1ae32a1SGerd Hoffmann 
154f1ae32a1SGerd Hoffmann void usb_device_handle_reset(USBDevice *dev)
155f1ae32a1SGerd Hoffmann {
156f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
157f1ae32a1SGerd Hoffmann     if (klass->handle_reset) {
158f1ae32a1SGerd Hoffmann         klass->handle_reset(dev);
159f1ae32a1SGerd Hoffmann     }
160f1ae32a1SGerd Hoffmann }
161f1ae32a1SGerd Hoffmann 
1629a77a0f5SHans de Goede void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
163f1ae32a1SGerd Hoffmann                                int value, int index, int length, uint8_t *data)
164f1ae32a1SGerd Hoffmann {
165f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
166f1ae32a1SGerd Hoffmann     if (klass->handle_control) {
1679a77a0f5SHans de Goede         klass->handle_control(dev, p, request, value, index, length, data);
168f1ae32a1SGerd Hoffmann     }
169f1ae32a1SGerd Hoffmann }
170f1ae32a1SGerd Hoffmann 
1719a77a0f5SHans de Goede void usb_device_handle_data(USBDevice *dev, USBPacket *p)
172f1ae32a1SGerd Hoffmann {
173f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
174f1ae32a1SGerd Hoffmann     if (klass->handle_data) {
1759a77a0f5SHans de Goede         klass->handle_data(dev, p);
176f1ae32a1SGerd Hoffmann     }
177f1ae32a1SGerd Hoffmann }
178f1ae32a1SGerd Hoffmann 
179f1ae32a1SGerd Hoffmann const char *usb_device_get_product_desc(USBDevice *dev)
180f1ae32a1SGerd Hoffmann {
181f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
182f1ae32a1SGerd Hoffmann     return klass->product_desc;
183f1ae32a1SGerd Hoffmann }
184f1ae32a1SGerd Hoffmann 
185f1ae32a1SGerd Hoffmann const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
186f1ae32a1SGerd Hoffmann {
187f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
188386ab487SHans de Goede     if (dev->usb_desc) {
189386ab487SHans de Goede         return dev->usb_desc;
190386ab487SHans de Goede     }
191f1ae32a1SGerd Hoffmann     return klass->usb_desc;
192f1ae32a1SGerd Hoffmann }
193f1ae32a1SGerd Hoffmann 
194f1ae32a1SGerd Hoffmann void usb_device_set_interface(USBDevice *dev, int interface,
195f1ae32a1SGerd Hoffmann                               int alt_old, int alt_new)
196f1ae32a1SGerd Hoffmann {
197f1ae32a1SGerd Hoffmann     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
198f1ae32a1SGerd Hoffmann     if (klass->set_interface) {
199f1ae32a1SGerd Hoffmann         klass->set_interface(dev, interface, alt_old, alt_new);
200f1ae32a1SGerd Hoffmann     }
201f1ae32a1SGerd Hoffmann }
202f1ae32a1SGerd Hoffmann 
20336dfe324SHans de Goede void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
20436dfe324SHans de Goede {
20536dfe324SHans de Goede     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
20636dfe324SHans de Goede     if (klass->flush_ep_queue) {
20736dfe324SHans de Goede         klass->flush_ep_queue(dev, ep);
20836dfe324SHans de Goede     }
20936dfe324SHans de Goede }
21036dfe324SHans de Goede 
211f79738b0SHans de Goede void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep)
212f79738b0SHans de Goede {
213f79738b0SHans de Goede     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
214f79738b0SHans de Goede     if (klass->ep_stopped) {
215f79738b0SHans de Goede         klass->ep_stopped(dev, ep);
216f79738b0SHans de Goede     }
217f79738b0SHans de Goede }
218f79738b0SHans de Goede 
2193b444eadSHans de Goede int usb_device_alloc_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps,
2203b444eadSHans de Goede                              int streams)
2213b444eadSHans de Goede {
2223b444eadSHans de Goede     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
2233b444eadSHans de Goede     if (klass->alloc_streams) {
2243b444eadSHans de Goede         return klass->alloc_streams(dev, eps, nr_eps, streams);
2253b444eadSHans de Goede     }
2263b444eadSHans de Goede     return 0;
2273b444eadSHans de Goede }
2283b444eadSHans de Goede 
2293b444eadSHans de Goede void usb_device_free_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps)
2303b444eadSHans de Goede {
2313b444eadSHans de Goede     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
2323b444eadSHans de Goede     if (klass->free_streams) {
2333b444eadSHans de Goede         klass->free_streams(dev, eps, nr_eps);
2343b444eadSHans de Goede     }
2353b444eadSHans de Goede }
2363b444eadSHans de Goede 
237*7d553f27SGonglei static void usb_qdev_realize(DeviceState *qdev, Error **errp)
238f1ae32a1SGerd Hoffmann {
239f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
240*7d553f27SGonglei     Error *local_err = NULL;
241f1ae32a1SGerd Hoffmann 
242f1ae32a1SGerd Hoffmann     pstrcpy(dev->product_desc, sizeof(dev->product_desc),
243f1ae32a1SGerd Hoffmann             usb_device_get_product_desc(dev));
244f1ae32a1SGerd Hoffmann     dev->auto_attach = 1;
245f1ae32a1SGerd Hoffmann     QLIST_INIT(&dev->strings);
246f1ae32a1SGerd Hoffmann     usb_ep_init(dev);
247*7d553f27SGonglei 
248*7d553f27SGonglei     usb_claim_port(dev, &local_err);
249*7d553f27SGonglei     if (local_err) {
250*7d553f27SGonglei         error_propagate(errp, local_err);
251*7d553f27SGonglei         return;
252f1ae32a1SGerd Hoffmann     }
253f1ae32a1SGerd Hoffmann 
254*7d553f27SGonglei     usb_device_realize(dev, &local_err);
255*7d553f27SGonglei     if (local_err) {
256*7d553f27SGonglei         usb_release_port(dev);
257*7d553f27SGonglei         error_propagate(errp, local_err);
258*7d553f27SGonglei         return;
259*7d553f27SGonglei     }
260*7d553f27SGonglei 
261*7d553f27SGonglei     if (dev->auto_attach) {
262*7d553f27SGonglei         usb_device_attach(dev, &local_err);
263*7d553f27SGonglei         if (local_err) {
264*7d553f27SGonglei             usb_qdev_unrealize(qdev, NULL);
265*7d553f27SGonglei             error_propagate(errp, local_err);
266*7d553f27SGonglei             return;
267*7d553f27SGonglei         }
268*7d553f27SGonglei     }
269*7d553f27SGonglei }
270*7d553f27SGonglei 
271*7d553f27SGonglei static void usb_qdev_unrealize(DeviceState *qdev, Error **errp)
272f1ae32a1SGerd Hoffmann {
273f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
274f1ae32a1SGerd Hoffmann 
275f1ae32a1SGerd Hoffmann     if (dev->attached) {
276f1ae32a1SGerd Hoffmann         usb_device_detach(dev);
277f1ae32a1SGerd Hoffmann     }
278f1ae32a1SGerd Hoffmann     usb_device_handle_destroy(dev);
279f1ae32a1SGerd Hoffmann     if (dev->port) {
280f1ae32a1SGerd Hoffmann         usb_release_port(dev);
281f1ae32a1SGerd Hoffmann     }
282f1ae32a1SGerd Hoffmann }
283f1ae32a1SGerd Hoffmann 
284f1ae32a1SGerd Hoffmann typedef struct LegacyUSBFactory
285f1ae32a1SGerd Hoffmann {
286f1ae32a1SGerd Hoffmann     const char *name;
287f1ae32a1SGerd Hoffmann     const char *usbdevice_name;
288f1ae32a1SGerd Hoffmann     USBDevice *(*usbdevice_init)(USBBus *bus, const char *params);
289f1ae32a1SGerd Hoffmann } LegacyUSBFactory;
290f1ae32a1SGerd Hoffmann 
291f1ae32a1SGerd Hoffmann static GSList *legacy_usb_factory;
292f1ae32a1SGerd Hoffmann 
293f1ae32a1SGerd Hoffmann void usb_legacy_register(const char *typename, const char *usbdevice_name,
294f1ae32a1SGerd Hoffmann                          USBDevice *(*usbdevice_init)(USBBus *bus,
295f1ae32a1SGerd Hoffmann                                                       const char *params))
296f1ae32a1SGerd Hoffmann {
297f1ae32a1SGerd Hoffmann     if (usbdevice_name) {
298f1ae32a1SGerd Hoffmann         LegacyUSBFactory *f = g_malloc0(sizeof(*f));
299f1ae32a1SGerd Hoffmann         f->name = typename;
300f1ae32a1SGerd Hoffmann         f->usbdevice_name = usbdevice_name;
301f1ae32a1SGerd Hoffmann         f->usbdevice_init = usbdevice_init;
302f1ae32a1SGerd Hoffmann         legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
303f1ae32a1SGerd Hoffmann     }
304f1ae32a1SGerd Hoffmann }
305f1ae32a1SGerd Hoffmann 
306f1ae32a1SGerd Hoffmann USBDevice *usb_create(USBBus *bus, const char *name)
307f1ae32a1SGerd Hoffmann {
308f1ae32a1SGerd Hoffmann     DeviceState *dev;
309f1ae32a1SGerd Hoffmann 
310f1ae32a1SGerd Hoffmann     dev = qdev_create(&bus->qbus, name);
311f1ae32a1SGerd Hoffmann     return USB_DEVICE(dev);
312f1ae32a1SGerd Hoffmann }
313f1ae32a1SGerd Hoffmann 
314f1ae32a1SGerd Hoffmann USBDevice *usb_create_simple(USBBus *bus, const char *name)
315f1ae32a1SGerd Hoffmann {
316f1ae32a1SGerd Hoffmann     USBDevice *dev = usb_create(bus, name);
317f1ae32a1SGerd Hoffmann     int rc;
318f1ae32a1SGerd Hoffmann 
319f1ae32a1SGerd Hoffmann     if (!dev) {
320f1ae32a1SGerd Hoffmann         error_report("Failed to create USB device '%s'", name);
321f1ae32a1SGerd Hoffmann         return NULL;
322f1ae32a1SGerd Hoffmann     }
323f1ae32a1SGerd Hoffmann     rc = qdev_init(&dev->qdev);
324f1ae32a1SGerd Hoffmann     if (rc < 0) {
325f1ae32a1SGerd Hoffmann         error_report("Failed to initialize USB device '%s'", name);
326f1ae32a1SGerd Hoffmann         return NULL;
327f1ae32a1SGerd Hoffmann     }
328f1ae32a1SGerd Hoffmann     return dev;
329f1ae32a1SGerd Hoffmann }
330f1ae32a1SGerd Hoffmann 
331f1ae32a1SGerd Hoffmann static void usb_fill_port(USBPort *port, void *opaque, int index,
332f1ae32a1SGerd Hoffmann                           USBPortOps *ops, int speedmask)
333f1ae32a1SGerd Hoffmann {
334f1ae32a1SGerd Hoffmann     port->opaque = opaque;
335f1ae32a1SGerd Hoffmann     port->index = index;
336f1ae32a1SGerd Hoffmann     port->ops = ops;
337f1ae32a1SGerd Hoffmann     port->speedmask = speedmask;
338f1ae32a1SGerd Hoffmann     usb_port_location(port, NULL, index + 1);
339f1ae32a1SGerd Hoffmann }
340f1ae32a1SGerd Hoffmann 
341f1ae32a1SGerd Hoffmann void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
342f1ae32a1SGerd Hoffmann                        USBPortOps *ops, int speedmask)
343f1ae32a1SGerd Hoffmann {
344f1ae32a1SGerd Hoffmann     usb_fill_port(port, opaque, index, ops, speedmask);
345f1ae32a1SGerd Hoffmann     QTAILQ_INSERT_TAIL(&bus->free, port, next);
346f1ae32a1SGerd Hoffmann     bus->nfree++;
347f1ae32a1SGerd Hoffmann }
348f1ae32a1SGerd Hoffmann 
349f1ae32a1SGerd Hoffmann int usb_register_companion(const char *masterbus, USBPort *ports[],
350f1ae32a1SGerd Hoffmann                            uint32_t portcount, uint32_t firstport,
351f1ae32a1SGerd Hoffmann                            void *opaque, USBPortOps *ops, int speedmask)
352f1ae32a1SGerd Hoffmann {
353f1ae32a1SGerd Hoffmann     USBBus *bus;
354f1ae32a1SGerd Hoffmann     int i;
355f1ae32a1SGerd Hoffmann 
356f1ae32a1SGerd Hoffmann     QTAILQ_FOREACH(bus, &busses, next) {
357f1ae32a1SGerd Hoffmann         if (strcmp(bus->qbus.name, masterbus) == 0) {
358f1ae32a1SGerd Hoffmann             break;
359f1ae32a1SGerd Hoffmann         }
360f1ae32a1SGerd Hoffmann     }
361f1ae32a1SGerd Hoffmann 
362f1ae32a1SGerd Hoffmann     if (!bus || !bus->ops->register_companion) {
363f1ae32a1SGerd Hoffmann         qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
364f1ae32a1SGerd Hoffmann                       "an USB masterbus");
365f1ae32a1SGerd Hoffmann         if (bus) {
366f1ae32a1SGerd Hoffmann             error_printf_unless_qmp(
367f1ae32a1SGerd Hoffmann                 "USB bus '%s' does not allow companion controllers\n",
368f1ae32a1SGerd Hoffmann                 masterbus);
369f1ae32a1SGerd Hoffmann         }
370f1ae32a1SGerd Hoffmann         return -1;
371f1ae32a1SGerd Hoffmann     }
372f1ae32a1SGerd Hoffmann 
373f1ae32a1SGerd Hoffmann     for (i = 0; i < portcount; i++) {
374f1ae32a1SGerd Hoffmann         usb_fill_port(ports[i], opaque, i, ops, speedmask);
375f1ae32a1SGerd Hoffmann     }
376f1ae32a1SGerd Hoffmann 
377f1ae32a1SGerd Hoffmann     return bus->ops->register_companion(bus, ports, portcount, firstport);
378f1ae32a1SGerd Hoffmann }
379f1ae32a1SGerd Hoffmann 
380f1ae32a1SGerd Hoffmann void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
381f1ae32a1SGerd Hoffmann {
382f1ae32a1SGerd Hoffmann     if (upstream) {
383f1ae32a1SGerd Hoffmann         snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
384f1ae32a1SGerd Hoffmann                  upstream->path, portnr);
385c24e4aacSGerd Hoffmann         downstream->hubcount = upstream->hubcount + 1;
386f1ae32a1SGerd Hoffmann     } else {
387f1ae32a1SGerd Hoffmann         snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
388c24e4aacSGerd Hoffmann         downstream->hubcount = 0;
389f1ae32a1SGerd Hoffmann     }
390f1ae32a1SGerd Hoffmann }
391f1ae32a1SGerd Hoffmann 
392f1ae32a1SGerd Hoffmann void usb_unregister_port(USBBus *bus, USBPort *port)
393f1ae32a1SGerd Hoffmann {
39402a5c4c9SStefan Hajnoczi     if (port->dev) {
39502a5c4c9SStefan Hajnoczi         object_unparent(OBJECT(port->dev));
39602a5c4c9SStefan Hajnoczi     }
397f1ae32a1SGerd Hoffmann     QTAILQ_REMOVE(&bus->free, port, next);
398f1ae32a1SGerd Hoffmann     bus->nfree--;
399f1ae32a1SGerd Hoffmann }
400f1ae32a1SGerd Hoffmann 
401*7d553f27SGonglei void usb_claim_port(USBDevice *dev, Error **errp)
402f1ae32a1SGerd Hoffmann {
403f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
404f1ae32a1SGerd Hoffmann     USBPort *port;
405f1ae32a1SGerd Hoffmann 
406f1ae32a1SGerd Hoffmann     assert(dev->port == NULL);
407f1ae32a1SGerd Hoffmann 
408f1ae32a1SGerd Hoffmann     if (dev->port_path) {
409f1ae32a1SGerd Hoffmann         QTAILQ_FOREACH(port, &bus->free, next) {
410f1ae32a1SGerd Hoffmann             if (strcmp(port->path, dev->port_path) == 0) {
411f1ae32a1SGerd Hoffmann                 break;
412f1ae32a1SGerd Hoffmann             }
413f1ae32a1SGerd Hoffmann         }
414f1ae32a1SGerd Hoffmann         if (port == NULL) {
415*7d553f27SGonglei             error_setg(errp, "Error: usb port %s (bus %s) not found (in use?)",
416f1ae32a1SGerd Hoffmann                        dev->port_path, bus->qbus.name);
417*7d553f27SGonglei             return;
418f1ae32a1SGerd Hoffmann         }
419f1ae32a1SGerd Hoffmann     } else {
420f1ae32a1SGerd Hoffmann         if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
421f1ae32a1SGerd Hoffmann             /* Create a new hub and chain it on */
422f1ae32a1SGerd Hoffmann             usb_create_simple(bus, "usb-hub");
423f1ae32a1SGerd Hoffmann         }
424f1ae32a1SGerd Hoffmann         if (bus->nfree == 0) {
425*7d553f27SGonglei             error_setg(errp, "Error: tried to attach usb device %s to a bus "
426f1ae32a1SGerd Hoffmann                        "with no free ports", dev->product_desc);
427*7d553f27SGonglei             return;
428f1ae32a1SGerd Hoffmann         }
429f1ae32a1SGerd Hoffmann         port = QTAILQ_FIRST(&bus->free);
430f1ae32a1SGerd Hoffmann     }
431f1ae32a1SGerd Hoffmann     trace_usb_port_claim(bus->busnr, port->path);
432f1ae32a1SGerd Hoffmann 
433f1ae32a1SGerd Hoffmann     QTAILQ_REMOVE(&bus->free, port, next);
434f1ae32a1SGerd Hoffmann     bus->nfree--;
435f1ae32a1SGerd Hoffmann 
436f1ae32a1SGerd Hoffmann     dev->port = port;
437f1ae32a1SGerd Hoffmann     port->dev = dev;
438f1ae32a1SGerd Hoffmann 
439f1ae32a1SGerd Hoffmann     QTAILQ_INSERT_TAIL(&bus->used, port, next);
440f1ae32a1SGerd Hoffmann     bus->nused++;
441f1ae32a1SGerd Hoffmann }
442f1ae32a1SGerd Hoffmann 
443f1ae32a1SGerd Hoffmann void usb_release_port(USBDevice *dev)
444f1ae32a1SGerd Hoffmann {
445f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
446f1ae32a1SGerd Hoffmann     USBPort *port = dev->port;
447f1ae32a1SGerd Hoffmann 
448f1ae32a1SGerd Hoffmann     assert(port != NULL);
449f1ae32a1SGerd Hoffmann     trace_usb_port_release(bus->busnr, port->path);
450f1ae32a1SGerd Hoffmann 
451f1ae32a1SGerd Hoffmann     QTAILQ_REMOVE(&bus->used, port, next);
452f1ae32a1SGerd Hoffmann     bus->nused--;
453f1ae32a1SGerd Hoffmann 
454f1ae32a1SGerd Hoffmann     dev->port = NULL;
455f1ae32a1SGerd Hoffmann     port->dev = NULL;
456f1ae32a1SGerd Hoffmann 
457f1ae32a1SGerd Hoffmann     QTAILQ_INSERT_TAIL(&bus->free, port, next);
458f1ae32a1SGerd Hoffmann     bus->nfree++;
459f1ae32a1SGerd Hoffmann }
460f1ae32a1SGerd Hoffmann 
4613b7e759aSGerd Hoffmann static void usb_mask_to_str(char *dest, size_t size,
4623b7e759aSGerd Hoffmann                             unsigned int speedmask)
4633b7e759aSGerd Hoffmann {
4643b7e759aSGerd Hoffmann     static const struct {
4653b7e759aSGerd Hoffmann         unsigned int mask;
4663b7e759aSGerd Hoffmann         const char *name;
4673b7e759aSGerd Hoffmann     } speeds[] = {
4683b7e759aSGerd Hoffmann         { .mask = USB_SPEED_MASK_FULL,  .name = "full"  },
4693b7e759aSGerd Hoffmann         { .mask = USB_SPEED_MASK_HIGH,  .name = "high"  },
4703b7e759aSGerd Hoffmann         { .mask = USB_SPEED_MASK_SUPER, .name = "super" },
4713b7e759aSGerd Hoffmann     };
4723b7e759aSGerd Hoffmann     int i, pos = 0;
4733b7e759aSGerd Hoffmann 
4743b7e759aSGerd Hoffmann     for (i = 0; i < ARRAY_SIZE(speeds); i++) {
4753b7e759aSGerd Hoffmann         if (speeds[i].mask & speedmask) {
4763b7e759aSGerd Hoffmann             pos += snprintf(dest + pos, size - pos, "%s%s",
4773b7e759aSGerd Hoffmann                             pos ? "+" : "",
4783b7e759aSGerd Hoffmann                             speeds[i].name);
4793b7e759aSGerd Hoffmann         }
4803b7e759aSGerd Hoffmann     }
4813b7e759aSGerd Hoffmann }
4823b7e759aSGerd Hoffmann 
483*7d553f27SGonglei void usb_device_attach(USBDevice *dev, Error **errp)
484f1ae32a1SGerd Hoffmann {
485f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
486f1ae32a1SGerd Hoffmann     USBPort *port = dev->port;
4873b7e759aSGerd Hoffmann     char devspeed[32], portspeed[32];
488f1ae32a1SGerd Hoffmann 
489f1ae32a1SGerd Hoffmann     assert(port != NULL);
490f1ae32a1SGerd Hoffmann     assert(!dev->attached);
4913b7e759aSGerd Hoffmann     usb_mask_to_str(devspeed, sizeof(devspeed), dev->speedmask);
4923b7e759aSGerd Hoffmann     usb_mask_to_str(portspeed, sizeof(portspeed), port->speedmask);
4933b7e759aSGerd Hoffmann     trace_usb_port_attach(bus->busnr, port->path,
4943b7e759aSGerd Hoffmann                           devspeed, portspeed);
495f1ae32a1SGerd Hoffmann 
496f1ae32a1SGerd Hoffmann     if (!(port->speedmask & dev->speedmask)) {
497*7d553f27SGonglei         error_setg(errp, "Warning: speed mismatch trying to attach"
4983b7e759aSGerd Hoffmann                    " usb device \"%s\" (%s speed)"
4993b7e759aSGerd Hoffmann                    " to bus \"%s\", port \"%s\" (%s speed)",
5003b7e759aSGerd Hoffmann                    dev->product_desc, devspeed,
5013b7e759aSGerd Hoffmann                    bus->qbus.name, port->path, portspeed);
502*7d553f27SGonglei         return;
503f1ae32a1SGerd Hoffmann     }
504f1ae32a1SGerd Hoffmann 
505f1ae32a1SGerd Hoffmann     dev->attached++;
506f1ae32a1SGerd Hoffmann     usb_attach(port);
507f1ae32a1SGerd Hoffmann }
508f1ae32a1SGerd Hoffmann 
509f1ae32a1SGerd Hoffmann int usb_device_detach(USBDevice *dev)
510f1ae32a1SGerd Hoffmann {
511f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
512f1ae32a1SGerd Hoffmann     USBPort *port = dev->port;
513f1ae32a1SGerd Hoffmann 
514f1ae32a1SGerd Hoffmann     assert(port != NULL);
515f1ae32a1SGerd Hoffmann     assert(dev->attached);
516f1ae32a1SGerd Hoffmann     trace_usb_port_detach(bus->busnr, port->path);
517f1ae32a1SGerd Hoffmann 
518f1ae32a1SGerd Hoffmann     usb_detach(port);
519f1ae32a1SGerd Hoffmann     dev->attached--;
520f1ae32a1SGerd Hoffmann     return 0;
521f1ae32a1SGerd Hoffmann }
522f1ae32a1SGerd Hoffmann 
523f1ae32a1SGerd Hoffmann int usb_device_delete_addr(int busnr, int addr)
524f1ae32a1SGerd Hoffmann {
525f1ae32a1SGerd Hoffmann     USBBus *bus;
526f1ae32a1SGerd Hoffmann     USBPort *port;
527f1ae32a1SGerd Hoffmann     USBDevice *dev;
528f1ae32a1SGerd Hoffmann 
529f1ae32a1SGerd Hoffmann     bus = usb_bus_find(busnr);
530f1ae32a1SGerd Hoffmann     if (!bus)
531f1ae32a1SGerd Hoffmann         return -1;
532f1ae32a1SGerd Hoffmann 
533f1ae32a1SGerd Hoffmann     QTAILQ_FOREACH(port, &bus->used, next) {
534f1ae32a1SGerd Hoffmann         if (port->dev->addr == addr)
535f1ae32a1SGerd Hoffmann             break;
536f1ae32a1SGerd Hoffmann     }
537f1ae32a1SGerd Hoffmann     if (!port)
538f1ae32a1SGerd Hoffmann         return -1;
539f1ae32a1SGerd Hoffmann     dev = port->dev;
540f1ae32a1SGerd Hoffmann 
54102a5c4c9SStefan Hajnoczi     object_unparent(OBJECT(dev));
542f1ae32a1SGerd Hoffmann     return 0;
543f1ae32a1SGerd Hoffmann }
544f1ae32a1SGerd Hoffmann 
545f1ae32a1SGerd Hoffmann static const char *usb_speed(unsigned int speed)
546f1ae32a1SGerd Hoffmann {
547f1ae32a1SGerd Hoffmann     static const char *txt[] = {
548f1ae32a1SGerd Hoffmann         [ USB_SPEED_LOW  ] = "1.5",
549f1ae32a1SGerd Hoffmann         [ USB_SPEED_FULL ] = "12",
550f1ae32a1SGerd Hoffmann         [ USB_SPEED_HIGH ] = "480",
551f1ae32a1SGerd Hoffmann         [ USB_SPEED_SUPER ] = "5000",
552f1ae32a1SGerd Hoffmann     };
553f1ae32a1SGerd Hoffmann     if (speed >= ARRAY_SIZE(txt))
554f1ae32a1SGerd Hoffmann         return "?";
555f1ae32a1SGerd Hoffmann     return txt[speed];
556f1ae32a1SGerd Hoffmann }
557f1ae32a1SGerd Hoffmann 
558f1ae32a1SGerd Hoffmann static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
559f1ae32a1SGerd Hoffmann {
560f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
561f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_from_device(dev);
562f1ae32a1SGerd Hoffmann 
563f1ae32a1SGerd Hoffmann     monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
564f1ae32a1SGerd Hoffmann                    indent, "", bus->busnr, dev->addr,
565f1ae32a1SGerd Hoffmann                    dev->port ? dev->port->path : "-",
566f1ae32a1SGerd Hoffmann                    usb_speed(dev->speed), dev->product_desc,
567f1ae32a1SGerd Hoffmann                    dev->attached ? ", attached" : "");
568f1ae32a1SGerd Hoffmann }
569f1ae32a1SGerd Hoffmann 
570f1ae32a1SGerd Hoffmann static char *usb_get_dev_path(DeviceState *qdev)
571f1ae32a1SGerd Hoffmann {
572f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
573eeb0cf9aSGerd Hoffmann     DeviceState *hcd = qdev->parent_bus->parent;
574eeb0cf9aSGerd Hoffmann     char *id = NULL;
575eeb0cf9aSGerd Hoffmann 
57609e5ab63SAnthony Liguori     if (dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) {
57709e5ab63SAnthony Liguori         id = qdev_get_dev_path(hcd);
578eeb0cf9aSGerd Hoffmann     }
579eeb0cf9aSGerd Hoffmann     if (id) {
580eeb0cf9aSGerd Hoffmann         char *ret = g_strdup_printf("%s/%s", id, dev->port->path);
581eeb0cf9aSGerd Hoffmann         g_free(id);
582eeb0cf9aSGerd Hoffmann         return ret;
583eeb0cf9aSGerd Hoffmann     } else {
584f1ae32a1SGerd Hoffmann         return g_strdup(dev->port->path);
585f1ae32a1SGerd Hoffmann     }
586eeb0cf9aSGerd Hoffmann }
587f1ae32a1SGerd Hoffmann 
588f1ae32a1SGerd Hoffmann static char *usb_get_fw_dev_path(DeviceState *qdev)
589f1ae32a1SGerd Hoffmann {
590f1ae32a1SGerd Hoffmann     USBDevice *dev = USB_DEVICE(qdev);
591f1ae32a1SGerd Hoffmann     char *fw_path, *in;
592f1ae32a1SGerd Hoffmann     ssize_t pos = 0, fw_len;
593f1ae32a1SGerd Hoffmann     long nr;
594f1ae32a1SGerd Hoffmann 
595f1ae32a1SGerd Hoffmann     fw_len = 32 + strlen(dev->port->path) * 6;
596f1ae32a1SGerd Hoffmann     fw_path = g_malloc(fw_len);
597f1ae32a1SGerd Hoffmann     in = dev->port->path;
598f1ae32a1SGerd Hoffmann     while (fw_len - pos > 0) {
599f1ae32a1SGerd Hoffmann         nr = strtol(in, &in, 10);
600f1ae32a1SGerd Hoffmann         if (in[0] == '.') {
601f1ae32a1SGerd Hoffmann             /* some hub between root port and device */
602830cd54fSMarkus Armbruster             pos += snprintf(fw_path + pos, fw_len - pos, "hub@%lx/", nr);
603f1ae32a1SGerd Hoffmann             in++;
604f1ae32a1SGerd Hoffmann         } else {
605f1ae32a1SGerd Hoffmann             /* the device itself */
606830cd54fSMarkus Armbruster             pos += snprintf(fw_path + pos, fw_len - pos, "%s@%lx",
607f1ae32a1SGerd Hoffmann                             qdev_fw_name(qdev), nr);
608f1ae32a1SGerd Hoffmann             break;
609f1ae32a1SGerd Hoffmann         }
610f1ae32a1SGerd Hoffmann     }
611f1ae32a1SGerd Hoffmann     return fw_path;
612f1ae32a1SGerd Hoffmann }
613f1ae32a1SGerd Hoffmann 
61484f2d0eaSWenchao Xia void usb_info(Monitor *mon, const QDict *qdict)
615f1ae32a1SGerd Hoffmann {
616f1ae32a1SGerd Hoffmann     USBBus *bus;
617f1ae32a1SGerd Hoffmann     USBDevice *dev;
618f1ae32a1SGerd Hoffmann     USBPort *port;
619f1ae32a1SGerd Hoffmann 
620f1ae32a1SGerd Hoffmann     if (QTAILQ_EMPTY(&busses)) {
621f1ae32a1SGerd Hoffmann         monitor_printf(mon, "USB support not enabled\n");
622f1ae32a1SGerd Hoffmann         return;
623f1ae32a1SGerd Hoffmann     }
624f1ae32a1SGerd Hoffmann 
625f1ae32a1SGerd Hoffmann     QTAILQ_FOREACH(bus, &busses, next) {
626f1ae32a1SGerd Hoffmann         QTAILQ_FOREACH(port, &bus->used, next) {
627f1ae32a1SGerd Hoffmann             dev = port->dev;
628f1ae32a1SGerd Hoffmann             if (!dev)
629f1ae32a1SGerd Hoffmann                 continue;
630f1ae32a1SGerd Hoffmann             monitor_printf(mon, "  Device %d.%d, Port %s, Speed %s Mb/s, Product %s\n",
631f1ae32a1SGerd Hoffmann                            bus->busnr, dev->addr, port->path, usb_speed(dev->speed),
632f1ae32a1SGerd Hoffmann                            dev->product_desc);
633f1ae32a1SGerd Hoffmann         }
634f1ae32a1SGerd Hoffmann     }
635f1ae32a1SGerd Hoffmann }
636f1ae32a1SGerd Hoffmann 
637f1ae32a1SGerd Hoffmann /* handle legacy -usbdevice cmd line option */
638f1ae32a1SGerd Hoffmann USBDevice *usbdevice_create(const char *cmdline)
639f1ae32a1SGerd Hoffmann {
640f1ae32a1SGerd Hoffmann     USBBus *bus = usb_bus_find(-1 /* any */);
641f1ae32a1SGerd Hoffmann     LegacyUSBFactory *f = NULL;
642f1ae32a1SGerd Hoffmann     GSList *i;
643f1ae32a1SGerd Hoffmann     char driver[32];
644f1ae32a1SGerd Hoffmann     const char *params;
645f1ae32a1SGerd Hoffmann     int len;
646f1ae32a1SGerd Hoffmann 
647f1ae32a1SGerd Hoffmann     params = strchr(cmdline,':');
648f1ae32a1SGerd Hoffmann     if (params) {
649f1ae32a1SGerd Hoffmann         params++;
650f1ae32a1SGerd Hoffmann         len = params - cmdline;
651f1ae32a1SGerd Hoffmann         if (len > sizeof(driver))
652f1ae32a1SGerd Hoffmann             len = sizeof(driver);
653f1ae32a1SGerd Hoffmann         pstrcpy(driver, len, cmdline);
654f1ae32a1SGerd Hoffmann     } else {
655f1ae32a1SGerd Hoffmann         params = "";
656f1ae32a1SGerd Hoffmann         pstrcpy(driver, sizeof(driver), cmdline);
657f1ae32a1SGerd Hoffmann     }
658f1ae32a1SGerd Hoffmann 
659f1ae32a1SGerd Hoffmann     for (i = legacy_usb_factory; i; i = i->next) {
660f1ae32a1SGerd Hoffmann         f = i->data;
661f1ae32a1SGerd Hoffmann         if (strcmp(f->usbdevice_name, driver) == 0) {
662f1ae32a1SGerd Hoffmann             break;
663f1ae32a1SGerd Hoffmann         }
664f1ae32a1SGerd Hoffmann     }
665f1ae32a1SGerd Hoffmann     if (i == NULL) {
666f1ae32a1SGerd Hoffmann #if 0
667f1ae32a1SGerd Hoffmann         /* no error because some drivers are not converted (yet) */
668f1ae32a1SGerd Hoffmann         error_report("usbdevice %s not found", driver);
669f1ae32a1SGerd Hoffmann #endif
670f1ae32a1SGerd Hoffmann         return NULL;
671f1ae32a1SGerd Hoffmann     }
672f1ae32a1SGerd Hoffmann 
673c128d6a6SStefan Hajnoczi     if (!bus) {
674c128d6a6SStefan Hajnoczi         error_report("Error: no usb bus to attach usbdevice %s, "
675c128d6a6SStefan Hajnoczi                      "please try -machine usb=on and check that "
676c128d6a6SStefan Hajnoczi                      "the machine model supports USB", driver);
677c128d6a6SStefan Hajnoczi         return NULL;
678c128d6a6SStefan Hajnoczi     }
679c128d6a6SStefan Hajnoczi 
680f1ae32a1SGerd Hoffmann     if (!f->usbdevice_init) {
681f1ae32a1SGerd Hoffmann         if (*params) {
682f1ae32a1SGerd Hoffmann             error_report("usbdevice %s accepts no params", driver);
683f1ae32a1SGerd Hoffmann             return NULL;
684f1ae32a1SGerd Hoffmann         }
685f1ae32a1SGerd Hoffmann         return usb_create_simple(bus, f->name);
686f1ae32a1SGerd Hoffmann     }
687f1ae32a1SGerd Hoffmann     return f->usbdevice_init(bus, params);
688f1ae32a1SGerd Hoffmann }
689f1ae32a1SGerd Hoffmann 
690f1ae32a1SGerd Hoffmann static void usb_device_class_init(ObjectClass *klass, void *data)
691f1ae32a1SGerd Hoffmann {
692f1ae32a1SGerd Hoffmann     DeviceClass *k = DEVICE_CLASS(klass);
6930d936928SAnthony Liguori     k->bus_type = TYPE_USB_BUS;
694f1ae32a1SGerd Hoffmann     k->unplug   = qdev_simple_unplug_cb;
695*7d553f27SGonglei     k->realize  = usb_qdev_realize;
696*7d553f27SGonglei     k->unrealize = usb_qdev_unrealize;
697bce54474SPaolo Bonzini     k->props    = usb_props;
698f1ae32a1SGerd Hoffmann }
699f1ae32a1SGerd Hoffmann 
7008c43a6f0SAndreas Färber static const TypeInfo usb_device_type_info = {
701f1ae32a1SGerd Hoffmann     .name = TYPE_USB_DEVICE,
702f1ae32a1SGerd Hoffmann     .parent = TYPE_DEVICE,
703f1ae32a1SGerd Hoffmann     .instance_size = sizeof(USBDevice),
704f1ae32a1SGerd Hoffmann     .abstract = true,
705f1ae32a1SGerd Hoffmann     .class_size = sizeof(USBDeviceClass),
706f1ae32a1SGerd Hoffmann     .class_init = usb_device_class_init,
707f1ae32a1SGerd Hoffmann };
708f1ae32a1SGerd Hoffmann 
709f1ae32a1SGerd Hoffmann static void usb_register_types(void)
710f1ae32a1SGerd Hoffmann {
7110d936928SAnthony Liguori     type_register_static(&usb_bus_info);
712f1ae32a1SGerd Hoffmann     type_register_static(&usb_device_type_info);
713f1ae32a1SGerd Hoffmann }
714f1ae32a1SGerd Hoffmann 
715f1ae32a1SGerd Hoffmann type_init(usb_register_types)
716