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