Commit 72899afc5d2a33576094a80d1eba797e293c975a
1 parent
56bebe70
separate file for usb hub device
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1848 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
519 additions
and
498 deletions
Makefile.target
@@ -302,7 +302,7 @@ SOUND_HW += fmopl.o adlib.o | @@ -302,7 +302,7 @@ SOUND_HW += fmopl.o adlib.o | ||
302 | endif | 302 | endif |
303 | 303 | ||
304 | # USB layer | 304 | # USB layer |
305 | -VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o | 305 | +VL_OBJS+= usb.o usb-hub.o usb-uhci.o usb-linux.o usb-hid.o |
306 | 306 | ||
307 | # PCI network cards | 307 | # PCI network cards |
308 | VL_OBJS+= ne2000.o rtl8139.o | 308 | VL_OBJS+= ne2000.o rtl8139.o |
hw/usb-hub.c
0 → 100644
1 | +/* | ||
2 | + * QEMU USB HUB emulation | ||
3 | + * | ||
4 | + * Copyright (c) 2005 Fabrice Bellard | ||
5 | + * | ||
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | + * of this software and associated documentation files (the "Software"), to deal | ||
8 | + * in the Software without restriction, including without limitation the rights | ||
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | + * copies of the Software, and to permit persons to whom the Software is | ||
11 | + * furnished to do so, subject to the following conditions: | ||
12 | + * | ||
13 | + * The above copyright notice and this permission notice shall be included in | ||
14 | + * all copies or substantial portions of the Software. | ||
15 | + * | ||
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | + * THE SOFTWARE. | ||
23 | + */ | ||
24 | +#include "vl.h" | ||
25 | + | ||
26 | +//#define DEBUG | ||
27 | + | ||
28 | +#define MAX_PORTS 8 | ||
29 | + | ||
30 | +typedef struct USBHubPort { | ||
31 | + USBPort port; | ||
32 | + uint16_t wPortStatus; | ||
33 | + uint16_t wPortChange; | ||
34 | +} USBHubPort; | ||
35 | + | ||
36 | +typedef struct USBHubState { | ||
37 | + USBDevice dev; | ||
38 | + int nb_ports; | ||
39 | + USBHubPort ports[MAX_PORTS]; | ||
40 | +} USBHubState; | ||
41 | + | ||
42 | +#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) | ||
43 | +#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) | ||
44 | +#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) | ||
45 | +#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) | ||
46 | +#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) | ||
47 | +#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) | ||
48 | +#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) | ||
49 | + | ||
50 | +#define PORT_STAT_CONNECTION 0x0001 | ||
51 | +#define PORT_STAT_ENABLE 0x0002 | ||
52 | +#define PORT_STAT_SUSPEND 0x0004 | ||
53 | +#define PORT_STAT_OVERCURRENT 0x0008 | ||
54 | +#define PORT_STAT_RESET 0x0010 | ||
55 | +#define PORT_STAT_POWER 0x0100 | ||
56 | +#define PORT_STAT_LOW_SPEED 0x0200 | ||
57 | +#define PORT_STAT_HIGH_SPEED 0x0400 | ||
58 | +#define PORT_STAT_TEST 0x0800 | ||
59 | +#define PORT_STAT_INDICATOR 0x1000 | ||
60 | + | ||
61 | +#define PORT_STAT_C_CONNECTION 0x0001 | ||
62 | +#define PORT_STAT_C_ENABLE 0x0002 | ||
63 | +#define PORT_STAT_C_SUSPEND 0x0004 | ||
64 | +#define PORT_STAT_C_OVERCURRENT 0x0008 | ||
65 | +#define PORT_STAT_C_RESET 0x0010 | ||
66 | + | ||
67 | +#define PORT_CONNECTION 0 | ||
68 | +#define PORT_ENABLE 1 | ||
69 | +#define PORT_SUSPEND 2 | ||
70 | +#define PORT_OVERCURRENT 3 | ||
71 | +#define PORT_RESET 4 | ||
72 | +#define PORT_POWER 8 | ||
73 | +#define PORT_LOWSPEED 9 | ||
74 | +#define PORT_HIGHSPEED 10 | ||
75 | +#define PORT_C_CONNECTION 16 | ||
76 | +#define PORT_C_ENABLE 17 | ||
77 | +#define PORT_C_SUSPEND 18 | ||
78 | +#define PORT_C_OVERCURRENT 19 | ||
79 | +#define PORT_C_RESET 20 | ||
80 | +#define PORT_TEST 21 | ||
81 | +#define PORT_INDICATOR 22 | ||
82 | + | ||
83 | +/* same as Linux kernel root hubs */ | ||
84 | + | ||
85 | +static const uint8_t qemu_hub_dev_descriptor[] = { | ||
86 | + 0x12, /* u8 bLength; */ | ||
87 | + 0x01, /* u8 bDescriptorType; Device */ | ||
88 | + 0x10, 0x01, /* u16 bcdUSB; v1.1 */ | ||
89 | + | ||
90 | + 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */ | ||
91 | + 0x00, /* u8 bDeviceSubClass; */ | ||
92 | + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ | ||
93 | + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ | ||
94 | + | ||
95 | + 0x00, 0x00, /* u16 idVendor; */ | ||
96 | + 0x00, 0x00, /* u16 idProduct; */ | ||
97 | + 0x01, 0x01, /* u16 bcdDevice */ | ||
98 | + | ||
99 | + 0x03, /* u8 iManufacturer; */ | ||
100 | + 0x02, /* u8 iProduct; */ | ||
101 | + 0x01, /* u8 iSerialNumber; */ | ||
102 | + 0x01 /* u8 bNumConfigurations; */ | ||
103 | +}; | ||
104 | + | ||
105 | +/* XXX: patch interrupt size */ | ||
106 | +static const uint8_t qemu_hub_config_descriptor[] = { | ||
107 | + | ||
108 | + /* one configuration */ | ||
109 | + 0x09, /* u8 bLength; */ | ||
110 | + 0x02, /* u8 bDescriptorType; Configuration */ | ||
111 | + 0x19, 0x00, /* u16 wTotalLength; */ | ||
112 | + 0x01, /* u8 bNumInterfaces; (1) */ | ||
113 | + 0x01, /* u8 bConfigurationValue; */ | ||
114 | + 0x00, /* u8 iConfiguration; */ | ||
115 | + 0xc0, /* u8 bmAttributes; | ||
116 | + Bit 7: must be set, | ||
117 | + 6: Self-powered, | ||
118 | + 5: Remote wakeup, | ||
119 | + 4..0: resvd */ | ||
120 | + 0x00, /* u8 MaxPower; */ | ||
121 | + | ||
122 | + /* USB 1.1: | ||
123 | + * USB 2.0, single TT organization (mandatory): | ||
124 | + * one interface, protocol 0 | ||
125 | + * | ||
126 | + * USB 2.0, multiple TT organization (optional): | ||
127 | + * two interfaces, protocols 1 (like single TT) | ||
128 | + * and 2 (multiple TT mode) ... config is | ||
129 | + * sometimes settable | ||
130 | + * NOT IMPLEMENTED | ||
131 | + */ | ||
132 | + | ||
133 | + /* one interface */ | ||
134 | + 0x09, /* u8 if_bLength; */ | ||
135 | + 0x04, /* u8 if_bDescriptorType; Interface */ | ||
136 | + 0x00, /* u8 if_bInterfaceNumber; */ | ||
137 | + 0x00, /* u8 if_bAlternateSetting; */ | ||
138 | + 0x01, /* u8 if_bNumEndpoints; */ | ||
139 | + 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */ | ||
140 | + 0x00, /* u8 if_bInterfaceSubClass; */ | ||
141 | + 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ | ||
142 | + 0x00, /* u8 if_iInterface; */ | ||
143 | + | ||
144 | + /* one endpoint (status change endpoint) */ | ||
145 | + 0x07, /* u8 ep_bLength; */ | ||
146 | + 0x05, /* u8 ep_bDescriptorType; Endpoint */ | ||
147 | + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ | ||
148 | + 0x03, /* u8 ep_bmAttributes; Interrupt */ | ||
149 | + 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ | ||
150 | + 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ | ||
151 | +}; | ||
152 | + | ||
153 | +static const uint8_t qemu_hub_hub_descriptor[] = | ||
154 | +{ | ||
155 | + 0x09, /* u8 bLength; */ | ||
156 | + 0x29, /* u8 bDescriptorType; Hub-descriptor */ | ||
157 | + 0x00, /* u8 bNbrPorts; (patched later) */ | ||
158 | + 0x0a, /* u16 wHubCharacteristics; */ | ||
159 | + 0x00, /* (per-port OC, no power switching) */ | ||
160 | + 0x01, /* u8 bPwrOn2pwrGood; 2ms */ | ||
161 | + 0x00, /* u8 bHubContrCurrent; 0 mA */ | ||
162 | + 0x00, /* u8 DeviceRemovable; *** 7 Ports max *** */ | ||
163 | + 0xff /* u8 PortPwrCtrlMask; *** 7 ports max *** */ | ||
164 | +}; | ||
165 | + | ||
166 | +static void usb_hub_attach(USBPort *port1, USBDevice *dev) | ||
167 | +{ | ||
168 | + USBHubState *s = port1->opaque; | ||
169 | + USBHubPort *port = &s->ports[port1->index]; | ||
170 | + | ||
171 | + if (dev) { | ||
172 | + if (port->port.dev) | ||
173 | + usb_attach(port1, NULL); | ||
174 | + | ||
175 | + port->wPortStatus |= PORT_STAT_CONNECTION; | ||
176 | + port->wPortChange |= PORT_STAT_C_CONNECTION; | ||
177 | + if (dev->speed == USB_SPEED_LOW) | ||
178 | + port->wPortStatus |= PORT_STAT_LOW_SPEED; | ||
179 | + else | ||
180 | + port->wPortStatus &= ~PORT_STAT_LOW_SPEED; | ||
181 | + port->port.dev = dev; | ||
182 | + } else { | ||
183 | + dev = port->port.dev; | ||
184 | + if (dev) { | ||
185 | + port->wPortStatus &= ~PORT_STAT_CONNECTION; | ||
186 | + port->wPortChange |= PORT_STAT_C_CONNECTION; | ||
187 | + if (port->wPortStatus & PORT_STAT_ENABLE) { | ||
188 | + port->wPortStatus &= ~PORT_STAT_ENABLE; | ||
189 | + port->wPortChange |= PORT_STAT_C_ENABLE; | ||
190 | + } | ||
191 | + port->port.dev = NULL; | ||
192 | + } | ||
193 | + } | ||
194 | +} | ||
195 | + | ||
196 | +static void usb_hub_handle_reset(USBDevice *dev) | ||
197 | +{ | ||
198 | + /* XXX: do it */ | ||
199 | +} | ||
200 | + | ||
201 | +static int usb_hub_handle_control(USBDevice *dev, int request, int value, | ||
202 | + int index, int length, uint8_t *data) | ||
203 | +{ | ||
204 | + USBHubState *s = (USBHubState *)dev; | ||
205 | + int ret; | ||
206 | + | ||
207 | + switch(request) { | ||
208 | + case DeviceRequest | USB_REQ_GET_STATUS: | ||
209 | + data[0] = (1 << USB_DEVICE_SELF_POWERED) | | ||
210 | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); | ||
211 | + data[1] = 0x00; | ||
212 | + ret = 2; | ||
213 | + break; | ||
214 | + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: | ||
215 | + if (value == USB_DEVICE_REMOTE_WAKEUP) { | ||
216 | + dev->remote_wakeup = 0; | ||
217 | + } else { | ||
218 | + goto fail; | ||
219 | + } | ||
220 | + ret = 0; | ||
221 | + break; | ||
222 | + case DeviceOutRequest | USB_REQ_SET_FEATURE: | ||
223 | + if (value == USB_DEVICE_REMOTE_WAKEUP) { | ||
224 | + dev->remote_wakeup = 1; | ||
225 | + } else { | ||
226 | + goto fail; | ||
227 | + } | ||
228 | + ret = 0; | ||
229 | + break; | ||
230 | + case DeviceOutRequest | USB_REQ_SET_ADDRESS: | ||
231 | + dev->addr = value; | ||
232 | + ret = 0; | ||
233 | + break; | ||
234 | + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: | ||
235 | + switch(value >> 8) { | ||
236 | + case USB_DT_DEVICE: | ||
237 | + memcpy(data, qemu_hub_dev_descriptor, | ||
238 | + sizeof(qemu_hub_dev_descriptor)); | ||
239 | + ret = sizeof(qemu_hub_dev_descriptor); | ||
240 | + break; | ||
241 | + case USB_DT_CONFIG: | ||
242 | + memcpy(data, qemu_hub_config_descriptor, | ||
243 | + sizeof(qemu_hub_config_descriptor)); | ||
244 | + ret = sizeof(qemu_hub_config_descriptor); | ||
245 | + break; | ||
246 | + case USB_DT_STRING: | ||
247 | + switch(value & 0xff) { | ||
248 | + case 0: | ||
249 | + /* language ids */ | ||
250 | + data[0] = 4; | ||
251 | + data[1] = 3; | ||
252 | + data[2] = 0x09; | ||
253 | + data[3] = 0x04; | ||
254 | + ret = 4; | ||
255 | + break; | ||
256 | + case 1: | ||
257 | + /* serial number */ | ||
258 | + ret = set_usb_string(data, "314159"); | ||
259 | + break; | ||
260 | + case 2: | ||
261 | + /* product description */ | ||
262 | + ret = set_usb_string(data, "QEMU USB Hub"); | ||
263 | + break; | ||
264 | + case 3: | ||
265 | + /* vendor description */ | ||
266 | + ret = set_usb_string(data, "QEMU " QEMU_VERSION); | ||
267 | + break; | ||
268 | + default: | ||
269 | + goto fail; | ||
270 | + } | ||
271 | + break; | ||
272 | + default: | ||
273 | + goto fail; | ||
274 | + } | ||
275 | + break; | ||
276 | + case DeviceRequest | USB_REQ_GET_CONFIGURATION: | ||
277 | + data[0] = 1; | ||
278 | + ret = 1; | ||
279 | + break; | ||
280 | + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: | ||
281 | + ret = 0; | ||
282 | + break; | ||
283 | + case DeviceRequest | USB_REQ_GET_INTERFACE: | ||
284 | + data[0] = 0; | ||
285 | + ret = 1; | ||
286 | + break; | ||
287 | + case DeviceOutRequest | USB_REQ_SET_INTERFACE: | ||
288 | + ret = 0; | ||
289 | + break; | ||
290 | + /* usb specific requests */ | ||
291 | + case GetHubStatus: | ||
292 | + data[0] = 0; | ||
293 | + data[1] = 0; | ||
294 | + data[2] = 0; | ||
295 | + data[3] = 0; | ||
296 | + ret = 4; | ||
297 | + break; | ||
298 | + case GetPortStatus: | ||
299 | + { | ||
300 | + unsigned int n = index - 1; | ||
301 | + USBHubPort *port; | ||
302 | + if (n >= s->nb_ports) | ||
303 | + goto fail; | ||
304 | + port = &s->ports[n]; | ||
305 | + data[0] = port->wPortStatus; | ||
306 | + data[1] = port->wPortStatus >> 8; | ||
307 | + data[2] = port->wPortChange; | ||
308 | + data[3] = port->wPortChange >> 8; | ||
309 | + ret = 4; | ||
310 | + } | ||
311 | + break; | ||
312 | + case SetHubFeature: | ||
313 | + case ClearHubFeature: | ||
314 | + if (value == 0 || value == 1) { | ||
315 | + } else { | ||
316 | + goto fail; | ||
317 | + } | ||
318 | + ret = 0; | ||
319 | + break; | ||
320 | + case SetPortFeature: | ||
321 | + { | ||
322 | + unsigned int n = index - 1; | ||
323 | + USBHubPort *port; | ||
324 | + USBDevice *dev; | ||
325 | + if (n >= s->nb_ports) | ||
326 | + goto fail; | ||
327 | + port = &s->ports[n]; | ||
328 | + dev = port->port.dev; | ||
329 | + switch(value) { | ||
330 | + case PORT_SUSPEND: | ||
331 | + port->wPortStatus |= PORT_STAT_SUSPEND; | ||
332 | + break; | ||
333 | + case PORT_RESET: | ||
334 | + if (dev) { | ||
335 | + dev->handle_packet(dev, | ||
336 | + USB_MSG_RESET, 0, 0, NULL, 0); | ||
337 | + port->wPortChange |= PORT_STAT_C_RESET; | ||
338 | + /* set enable bit */ | ||
339 | + port->wPortChange |= PORT_STAT_C_ENABLE; | ||
340 | + port->wPortStatus |= PORT_STAT_ENABLE; | ||
341 | + } | ||
342 | + break; | ||
343 | + case PORT_POWER: | ||
344 | + break; | ||
345 | + default: | ||
346 | + goto fail; | ||
347 | + } | ||
348 | + ret = 0; | ||
349 | + } | ||
350 | + break; | ||
351 | + case ClearPortFeature: | ||
352 | + { | ||
353 | + unsigned int n = index - 1; | ||
354 | + USBHubPort *port; | ||
355 | + USBDevice *dev; | ||
356 | + if (n >= s->nb_ports) | ||
357 | + goto fail; | ||
358 | + port = &s->ports[n]; | ||
359 | + dev = port->port.dev; | ||
360 | + switch(value) { | ||
361 | + case PORT_ENABLE: | ||
362 | + port->wPortStatus &= ~PORT_STAT_ENABLE; | ||
363 | + break; | ||
364 | + case PORT_C_ENABLE: | ||
365 | + port->wPortChange &= ~PORT_STAT_C_ENABLE; | ||
366 | + break; | ||
367 | + case PORT_SUSPEND: | ||
368 | + port->wPortStatus &= ~PORT_STAT_SUSPEND; | ||
369 | + break; | ||
370 | + case PORT_C_SUSPEND: | ||
371 | + port->wPortChange &= ~PORT_STAT_C_SUSPEND; | ||
372 | + break; | ||
373 | + case PORT_C_CONNECTION: | ||
374 | + port->wPortChange &= ~PORT_STAT_C_CONNECTION; | ||
375 | + break; | ||
376 | + case PORT_C_OVERCURRENT: | ||
377 | + port->wPortChange &= ~PORT_STAT_C_OVERCURRENT; | ||
378 | + break; | ||
379 | + case PORT_C_RESET: | ||
380 | + port->wPortChange &= ~PORT_STAT_C_RESET; | ||
381 | + break; | ||
382 | + default: | ||
383 | + goto fail; | ||
384 | + } | ||
385 | + ret = 0; | ||
386 | + } | ||
387 | + break; | ||
388 | + case GetHubDescriptor: | ||
389 | + memcpy(data, qemu_hub_hub_descriptor, | ||
390 | + sizeof(qemu_hub_hub_descriptor)); | ||
391 | + data[2] = s->nb_ports; | ||
392 | + ret = sizeof(qemu_hub_hub_descriptor); | ||
393 | + break; | ||
394 | + default: | ||
395 | + fail: | ||
396 | + ret = USB_RET_STALL; | ||
397 | + break; | ||
398 | + } | ||
399 | + return ret; | ||
400 | +} | ||
401 | + | ||
402 | +static int usb_hub_handle_data(USBDevice *dev, int pid, | ||
403 | + uint8_t devep, uint8_t *data, int len) | ||
404 | +{ | ||
405 | + USBHubState *s = (USBHubState *)dev; | ||
406 | + int ret; | ||
407 | + | ||
408 | + switch(pid) { | ||
409 | + case USB_TOKEN_IN: | ||
410 | + if (devep == 1) { | ||
411 | + USBHubPort *port; | ||
412 | + unsigned int status; | ||
413 | + int i, n; | ||
414 | + n = (s->nb_ports + 1 + 7) / 8; | ||
415 | + if (n > len) | ||
416 | + return USB_RET_BABBLE; | ||
417 | + status = 0; | ||
418 | + for(i = 0; i < s->nb_ports; i++) { | ||
419 | + port = &s->ports[i]; | ||
420 | + if (port->wPortChange) | ||
421 | + status |= (1 << (i + 1)); | ||
422 | + } | ||
423 | + if (status != 0) { | ||
424 | + for(i = 0; i < n; i++) { | ||
425 | + data[i] = status >> (8 * i); | ||
426 | + } | ||
427 | + ret = n; | ||
428 | + } else { | ||
429 | + ret = 0; | ||
430 | + } | ||
431 | + } else { | ||
432 | + goto fail; | ||
433 | + } | ||
434 | + break; | ||
435 | + case USB_TOKEN_OUT: | ||
436 | + default: | ||
437 | + fail: | ||
438 | + ret = USB_RET_STALL; | ||
439 | + break; | ||
440 | + } | ||
441 | + return ret; | ||
442 | +} | ||
443 | + | ||
444 | +static int usb_hub_broadcast_packet(USBHubState *s, int pid, | ||
445 | + uint8_t devaddr, uint8_t devep, | ||
446 | + uint8_t *data, int len) | ||
447 | +{ | ||
448 | + USBHubPort *port; | ||
449 | + USBDevice *dev; | ||
450 | + int i, ret; | ||
451 | + | ||
452 | + for(i = 0; i < s->nb_ports; i++) { | ||
453 | + port = &s->ports[i]; | ||
454 | + dev = port->port.dev; | ||
455 | + if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { | ||
456 | + ret = dev->handle_packet(dev, pid, | ||
457 | + devaddr, devep, | ||
458 | + data, len); | ||
459 | + if (ret != USB_RET_NODEV) { | ||
460 | + return ret; | ||
461 | + } | ||
462 | + } | ||
463 | + } | ||
464 | + return USB_RET_NODEV; | ||
465 | +} | ||
466 | + | ||
467 | +static int usb_hub_handle_packet(USBDevice *dev, int pid, | ||
468 | + uint8_t devaddr, uint8_t devep, | ||
469 | + uint8_t *data, int len) | ||
470 | +{ | ||
471 | + USBHubState *s = (USBHubState *)dev; | ||
472 | + | ||
473 | +#if defined(DEBUG) && 0 | ||
474 | + printf("usb_hub: pid=0x%x\n", pid); | ||
475 | +#endif | ||
476 | + if (dev->state == USB_STATE_DEFAULT && | ||
477 | + dev->addr != 0 && | ||
478 | + devaddr != dev->addr && | ||
479 | + (pid == USB_TOKEN_SETUP || | ||
480 | + pid == USB_TOKEN_OUT || | ||
481 | + pid == USB_TOKEN_IN)) { | ||
482 | + /* broadcast the packet to the devices */ | ||
483 | + return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len); | ||
484 | + } | ||
485 | + return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); | ||
486 | +} | ||
487 | + | ||
488 | +USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) | ||
489 | +{ | ||
490 | + USBHubState *s; | ||
491 | + USBHubPort *port; | ||
492 | + int i; | ||
493 | + | ||
494 | + if (nb_ports > MAX_PORTS) | ||
495 | + return NULL; | ||
496 | + s = qemu_mallocz(sizeof(USBHubState)); | ||
497 | + if (!s) | ||
498 | + return NULL; | ||
499 | + s->dev.speed = USB_SPEED_FULL; | ||
500 | + s->dev.handle_packet = usb_hub_handle_packet; | ||
501 | + | ||
502 | + /* generic USB device init */ | ||
503 | + s->dev.handle_reset = usb_hub_handle_reset; | ||
504 | + s->dev.handle_control = usb_hub_handle_control; | ||
505 | + s->dev.handle_data = usb_hub_handle_data; | ||
506 | + | ||
507 | + s->nb_ports = nb_ports; | ||
508 | + for(i = 0; i < s->nb_ports; i++) { | ||
509 | + port = &s->ports[i]; | ||
510 | + port->wPortStatus = PORT_STAT_POWER; | ||
511 | + port->wPortChange = 0; | ||
512 | + port->port.attach = usb_hub_attach; | ||
513 | + port->port.opaque = s; | ||
514 | + port->port.index = i; | ||
515 | + usb_ports[i] = &port->port; | ||
516 | + } | ||
517 | + return (USBDevice *)s; | ||
518 | +} |
hw/usb.c
@@ -191,500 +191,3 @@ int set_usb_string(uint8_t *buf, const char *str) | @@ -191,500 +191,3 @@ int set_usb_string(uint8_t *buf, const char *str) | ||
191 | } | 191 | } |
192 | return q - buf; | 192 | return q - buf; |
193 | } | 193 | } |
194 | - | ||
195 | -/**********************/ | ||
196 | -/* USB hub emulation */ | ||
197 | - | ||
198 | -//#define DEBUG | ||
199 | - | ||
200 | -#define MAX_PORTS 8 | ||
201 | - | ||
202 | -typedef struct USBHubPort { | ||
203 | - USBPort port; | ||
204 | - uint16_t wPortStatus; | ||
205 | - uint16_t wPortChange; | ||
206 | -} USBHubPort; | ||
207 | - | ||
208 | -typedef struct USBHubState { | ||
209 | - USBDevice dev; | ||
210 | - int nb_ports; | ||
211 | - USBHubPort ports[MAX_PORTS]; | ||
212 | -} USBHubState; | ||
213 | - | ||
214 | -#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) | ||
215 | -#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) | ||
216 | -#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) | ||
217 | -#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) | ||
218 | -#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) | ||
219 | -#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) | ||
220 | -#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) | ||
221 | - | ||
222 | -#define PORT_STAT_CONNECTION 0x0001 | ||
223 | -#define PORT_STAT_ENABLE 0x0002 | ||
224 | -#define PORT_STAT_SUSPEND 0x0004 | ||
225 | -#define PORT_STAT_OVERCURRENT 0x0008 | ||
226 | -#define PORT_STAT_RESET 0x0010 | ||
227 | -#define PORT_STAT_POWER 0x0100 | ||
228 | -#define PORT_STAT_LOW_SPEED 0x0200 | ||
229 | -#define PORT_STAT_HIGH_SPEED 0x0400 | ||
230 | -#define PORT_STAT_TEST 0x0800 | ||
231 | -#define PORT_STAT_INDICATOR 0x1000 | ||
232 | - | ||
233 | -#define PORT_STAT_C_CONNECTION 0x0001 | ||
234 | -#define PORT_STAT_C_ENABLE 0x0002 | ||
235 | -#define PORT_STAT_C_SUSPEND 0x0004 | ||
236 | -#define PORT_STAT_C_OVERCURRENT 0x0008 | ||
237 | -#define PORT_STAT_C_RESET 0x0010 | ||
238 | - | ||
239 | -#define PORT_CONNECTION 0 | ||
240 | -#define PORT_ENABLE 1 | ||
241 | -#define PORT_SUSPEND 2 | ||
242 | -#define PORT_OVERCURRENT 3 | ||
243 | -#define PORT_RESET 4 | ||
244 | -#define PORT_POWER 8 | ||
245 | -#define PORT_LOWSPEED 9 | ||
246 | -#define PORT_HIGHSPEED 10 | ||
247 | -#define PORT_C_CONNECTION 16 | ||
248 | -#define PORT_C_ENABLE 17 | ||
249 | -#define PORT_C_SUSPEND 18 | ||
250 | -#define PORT_C_OVERCURRENT 19 | ||
251 | -#define PORT_C_RESET 20 | ||
252 | -#define PORT_TEST 21 | ||
253 | -#define PORT_INDICATOR 22 | ||
254 | - | ||
255 | -/* same as Linux kernel root hubs */ | ||
256 | - | ||
257 | -static const uint8_t qemu_hub_dev_descriptor[] = { | ||
258 | - 0x12, /* u8 bLength; */ | ||
259 | - 0x01, /* u8 bDescriptorType; Device */ | ||
260 | - 0x10, 0x01, /* u16 bcdUSB; v1.1 */ | ||
261 | - | ||
262 | - 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */ | ||
263 | - 0x00, /* u8 bDeviceSubClass; */ | ||
264 | - 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ | ||
265 | - 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ | ||
266 | - | ||
267 | - 0x00, 0x00, /* u16 idVendor; */ | ||
268 | - 0x00, 0x00, /* u16 idProduct; */ | ||
269 | - 0x01, 0x01, /* u16 bcdDevice */ | ||
270 | - | ||
271 | - 0x03, /* u8 iManufacturer; */ | ||
272 | - 0x02, /* u8 iProduct; */ | ||
273 | - 0x01, /* u8 iSerialNumber; */ | ||
274 | - 0x01 /* u8 bNumConfigurations; */ | ||
275 | -}; | ||
276 | - | ||
277 | -/* XXX: patch interrupt size */ | ||
278 | -static const uint8_t qemu_hub_config_descriptor[] = { | ||
279 | - | ||
280 | - /* one configuration */ | ||
281 | - 0x09, /* u8 bLength; */ | ||
282 | - 0x02, /* u8 bDescriptorType; Configuration */ | ||
283 | - 0x19, 0x00, /* u16 wTotalLength; */ | ||
284 | - 0x01, /* u8 bNumInterfaces; (1) */ | ||
285 | - 0x01, /* u8 bConfigurationValue; */ | ||
286 | - 0x00, /* u8 iConfiguration; */ | ||
287 | - 0xc0, /* u8 bmAttributes; | ||
288 | - Bit 7: must be set, | ||
289 | - 6: Self-powered, | ||
290 | - 5: Remote wakeup, | ||
291 | - 4..0: resvd */ | ||
292 | - 0x00, /* u8 MaxPower; */ | ||
293 | - | ||
294 | - /* USB 1.1: | ||
295 | - * USB 2.0, single TT organization (mandatory): | ||
296 | - * one interface, protocol 0 | ||
297 | - * | ||
298 | - * USB 2.0, multiple TT organization (optional): | ||
299 | - * two interfaces, protocols 1 (like single TT) | ||
300 | - * and 2 (multiple TT mode) ... config is | ||
301 | - * sometimes settable | ||
302 | - * NOT IMPLEMENTED | ||
303 | - */ | ||
304 | - | ||
305 | - /* one interface */ | ||
306 | - 0x09, /* u8 if_bLength; */ | ||
307 | - 0x04, /* u8 if_bDescriptorType; Interface */ | ||
308 | - 0x00, /* u8 if_bInterfaceNumber; */ | ||
309 | - 0x00, /* u8 if_bAlternateSetting; */ | ||
310 | - 0x01, /* u8 if_bNumEndpoints; */ | ||
311 | - 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */ | ||
312 | - 0x00, /* u8 if_bInterfaceSubClass; */ | ||
313 | - 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ | ||
314 | - 0x00, /* u8 if_iInterface; */ | ||
315 | - | ||
316 | - /* one endpoint (status change endpoint) */ | ||
317 | - 0x07, /* u8 ep_bLength; */ | ||
318 | - 0x05, /* u8 ep_bDescriptorType; Endpoint */ | ||
319 | - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ | ||
320 | - 0x03, /* u8 ep_bmAttributes; Interrupt */ | ||
321 | - 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ | ||
322 | - 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ | ||
323 | -}; | ||
324 | - | ||
325 | -static const uint8_t qemu_hub_hub_descriptor[] = | ||
326 | -{ | ||
327 | - 0x09, /* u8 bLength; */ | ||
328 | - 0x29, /* u8 bDescriptorType; Hub-descriptor */ | ||
329 | - 0x00, /* u8 bNbrPorts; (patched later) */ | ||
330 | - 0x0a, /* u16 wHubCharacteristics; */ | ||
331 | - 0x00, /* (per-port OC, no power switching) */ | ||
332 | - 0x01, /* u8 bPwrOn2pwrGood; 2ms */ | ||
333 | - 0x00, /* u8 bHubContrCurrent; 0 mA */ | ||
334 | - 0x00, /* u8 DeviceRemovable; *** 7 Ports max *** */ | ||
335 | - 0xff /* u8 PortPwrCtrlMask; *** 7 ports max *** */ | ||
336 | -}; | ||
337 | - | ||
338 | -static void usb_hub_attach(USBPort *port1, USBDevice *dev) | ||
339 | -{ | ||
340 | - USBHubState *s = port1->opaque; | ||
341 | - USBHubPort *port = &s->ports[port1->index]; | ||
342 | - | ||
343 | - if (dev) { | ||
344 | - if (port->port.dev) | ||
345 | - usb_attach(port1, NULL); | ||
346 | - | ||
347 | - port->wPortStatus |= PORT_STAT_CONNECTION; | ||
348 | - port->wPortChange |= PORT_STAT_C_CONNECTION; | ||
349 | - if (dev->speed == USB_SPEED_LOW) | ||
350 | - port->wPortStatus |= PORT_STAT_LOW_SPEED; | ||
351 | - else | ||
352 | - port->wPortStatus &= ~PORT_STAT_LOW_SPEED; | ||
353 | - port->port.dev = dev; | ||
354 | - } else { | ||
355 | - dev = port->port.dev; | ||
356 | - if (dev) { | ||
357 | - port->wPortStatus &= ~PORT_STAT_CONNECTION; | ||
358 | - port->wPortChange |= PORT_STAT_C_CONNECTION; | ||
359 | - if (port->wPortStatus & PORT_STAT_ENABLE) { | ||
360 | - port->wPortStatus &= ~PORT_STAT_ENABLE; | ||
361 | - port->wPortChange |= PORT_STAT_C_ENABLE; | ||
362 | - } | ||
363 | - port->port.dev = NULL; | ||
364 | - } | ||
365 | - } | ||
366 | -} | ||
367 | - | ||
368 | -static void usb_hub_handle_reset(USBDevice *dev) | ||
369 | -{ | ||
370 | - /* XXX: do it */ | ||
371 | -} | ||
372 | - | ||
373 | -static int usb_hub_handle_control(USBDevice *dev, int request, int value, | ||
374 | - int index, int length, uint8_t *data) | ||
375 | -{ | ||
376 | - USBHubState *s = (USBHubState *)dev; | ||
377 | - int ret; | ||
378 | - | ||
379 | - switch(request) { | ||
380 | - case DeviceRequest | USB_REQ_GET_STATUS: | ||
381 | - data[0] = (1 << USB_DEVICE_SELF_POWERED) | | ||
382 | - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); | ||
383 | - data[1] = 0x00; | ||
384 | - ret = 2; | ||
385 | - break; | ||
386 | - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: | ||
387 | - if (value == USB_DEVICE_REMOTE_WAKEUP) { | ||
388 | - dev->remote_wakeup = 0; | ||
389 | - } else { | ||
390 | - goto fail; | ||
391 | - } | ||
392 | - ret = 0; | ||
393 | - break; | ||
394 | - case DeviceOutRequest | USB_REQ_SET_FEATURE: | ||
395 | - if (value == USB_DEVICE_REMOTE_WAKEUP) { | ||
396 | - dev->remote_wakeup = 1; | ||
397 | - } else { | ||
398 | - goto fail; | ||
399 | - } | ||
400 | - ret = 0; | ||
401 | - break; | ||
402 | - case DeviceOutRequest | USB_REQ_SET_ADDRESS: | ||
403 | - dev->addr = value; | ||
404 | - ret = 0; | ||
405 | - break; | ||
406 | - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: | ||
407 | - switch(value >> 8) { | ||
408 | - case USB_DT_DEVICE: | ||
409 | - memcpy(data, qemu_hub_dev_descriptor, | ||
410 | - sizeof(qemu_hub_dev_descriptor)); | ||
411 | - ret = sizeof(qemu_hub_dev_descriptor); | ||
412 | - break; | ||
413 | - case USB_DT_CONFIG: | ||
414 | - memcpy(data, qemu_hub_config_descriptor, | ||
415 | - sizeof(qemu_hub_config_descriptor)); | ||
416 | - ret = sizeof(qemu_hub_config_descriptor); | ||
417 | - break; | ||
418 | - case USB_DT_STRING: | ||
419 | - switch(value & 0xff) { | ||
420 | - case 0: | ||
421 | - /* language ids */ | ||
422 | - data[0] = 4; | ||
423 | - data[1] = 3; | ||
424 | - data[2] = 0x09; | ||
425 | - data[3] = 0x04; | ||
426 | - ret = 4; | ||
427 | - break; | ||
428 | - case 1: | ||
429 | - /* serial number */ | ||
430 | - ret = set_usb_string(data, "314159"); | ||
431 | - break; | ||
432 | - case 2: | ||
433 | - /* product description */ | ||
434 | - ret = set_usb_string(data, "QEMU USB Hub"); | ||
435 | - break; | ||
436 | - case 3: | ||
437 | - /* vendor description */ | ||
438 | - ret = set_usb_string(data, "QEMU " QEMU_VERSION); | ||
439 | - break; | ||
440 | - default: | ||
441 | - goto fail; | ||
442 | - } | ||
443 | - break; | ||
444 | - default: | ||
445 | - goto fail; | ||
446 | - } | ||
447 | - break; | ||
448 | - case DeviceRequest | USB_REQ_GET_CONFIGURATION: | ||
449 | - data[0] = 1; | ||
450 | - ret = 1; | ||
451 | - break; | ||
452 | - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: | ||
453 | - ret = 0; | ||
454 | - break; | ||
455 | - case DeviceRequest | USB_REQ_GET_INTERFACE: | ||
456 | - data[0] = 0; | ||
457 | - ret = 1; | ||
458 | - break; | ||
459 | - case DeviceOutRequest | USB_REQ_SET_INTERFACE: | ||
460 | - ret = 0; | ||
461 | - break; | ||
462 | - /* usb specific requests */ | ||
463 | - case GetHubStatus: | ||
464 | - data[0] = 0; | ||
465 | - data[1] = 0; | ||
466 | - data[2] = 0; | ||
467 | - data[3] = 0; | ||
468 | - ret = 4; | ||
469 | - break; | ||
470 | - case GetPortStatus: | ||
471 | - { | ||
472 | - unsigned int n = index - 1; | ||
473 | - USBHubPort *port; | ||
474 | - if (n >= s->nb_ports) | ||
475 | - goto fail; | ||
476 | - port = &s->ports[n]; | ||
477 | - data[0] = port->wPortStatus; | ||
478 | - data[1] = port->wPortStatus >> 8; | ||
479 | - data[2] = port->wPortChange; | ||
480 | - data[3] = port->wPortChange >> 8; | ||
481 | - ret = 4; | ||
482 | - } | ||
483 | - break; | ||
484 | - case SetHubFeature: | ||
485 | - case ClearHubFeature: | ||
486 | - if (value == 0 || value == 1) { | ||
487 | - } else { | ||
488 | - goto fail; | ||
489 | - } | ||
490 | - ret = 0; | ||
491 | - break; | ||
492 | - case SetPortFeature: | ||
493 | - { | ||
494 | - unsigned int n = index - 1; | ||
495 | - USBHubPort *port; | ||
496 | - USBDevice *dev; | ||
497 | - if (n >= s->nb_ports) | ||
498 | - goto fail; | ||
499 | - port = &s->ports[n]; | ||
500 | - dev = port->port.dev; | ||
501 | - switch(value) { | ||
502 | - case PORT_SUSPEND: | ||
503 | - port->wPortStatus |= PORT_STAT_SUSPEND; | ||
504 | - break; | ||
505 | - case PORT_RESET: | ||
506 | - if (dev) { | ||
507 | - dev->handle_packet(dev, | ||
508 | - USB_MSG_RESET, 0, 0, NULL, 0); | ||
509 | - port->wPortChange |= PORT_STAT_C_RESET; | ||
510 | - /* set enable bit */ | ||
511 | - port->wPortChange |= PORT_STAT_C_ENABLE; | ||
512 | - port->wPortStatus |= PORT_STAT_ENABLE; | ||
513 | - } | ||
514 | - break; | ||
515 | - case PORT_POWER: | ||
516 | - break; | ||
517 | - default: | ||
518 | - goto fail; | ||
519 | - } | ||
520 | - ret = 0; | ||
521 | - } | ||
522 | - break; | ||
523 | - case ClearPortFeature: | ||
524 | - { | ||
525 | - unsigned int n = index - 1; | ||
526 | - USBHubPort *port; | ||
527 | - USBDevice *dev; | ||
528 | - if (n >= s->nb_ports) | ||
529 | - goto fail; | ||
530 | - port = &s->ports[n]; | ||
531 | - dev = port->port.dev; | ||
532 | - switch(value) { | ||
533 | - case PORT_ENABLE: | ||
534 | - port->wPortStatus &= ~PORT_STAT_ENABLE; | ||
535 | - break; | ||
536 | - case PORT_C_ENABLE: | ||
537 | - port->wPortChange &= ~PORT_STAT_C_ENABLE; | ||
538 | - break; | ||
539 | - case PORT_SUSPEND: | ||
540 | - port->wPortStatus &= ~PORT_STAT_SUSPEND; | ||
541 | - break; | ||
542 | - case PORT_C_SUSPEND: | ||
543 | - port->wPortChange &= ~PORT_STAT_C_SUSPEND; | ||
544 | - break; | ||
545 | - case PORT_C_CONNECTION: | ||
546 | - port->wPortChange &= ~PORT_STAT_C_CONNECTION; | ||
547 | - break; | ||
548 | - case PORT_C_OVERCURRENT: | ||
549 | - port->wPortChange &= ~PORT_STAT_C_OVERCURRENT; | ||
550 | - break; | ||
551 | - case PORT_C_RESET: | ||
552 | - port->wPortChange &= ~PORT_STAT_C_RESET; | ||
553 | - break; | ||
554 | - default: | ||
555 | - goto fail; | ||
556 | - } | ||
557 | - ret = 0; | ||
558 | - } | ||
559 | - break; | ||
560 | - case GetHubDescriptor: | ||
561 | - memcpy(data, qemu_hub_hub_descriptor, | ||
562 | - sizeof(qemu_hub_hub_descriptor)); | ||
563 | - data[2] = s->nb_ports; | ||
564 | - ret = sizeof(qemu_hub_hub_descriptor); | ||
565 | - break; | ||
566 | - default: | ||
567 | - fail: | ||
568 | - ret = USB_RET_STALL; | ||
569 | - break; | ||
570 | - } | ||
571 | - return ret; | ||
572 | -} | ||
573 | - | ||
574 | -static int usb_hub_handle_data(USBDevice *dev, int pid, | ||
575 | - uint8_t devep, uint8_t *data, int len) | ||
576 | -{ | ||
577 | - USBHubState *s = (USBHubState *)dev; | ||
578 | - int ret; | ||
579 | - | ||
580 | - switch(pid) { | ||
581 | - case USB_TOKEN_IN: | ||
582 | - if (devep == 1) { | ||
583 | - USBHubPort *port; | ||
584 | - unsigned int status; | ||
585 | - int i, n; | ||
586 | - n = (s->nb_ports + 1 + 7) / 8; | ||
587 | - if (n > len) | ||
588 | - return USB_RET_BABBLE; | ||
589 | - status = 0; | ||
590 | - for(i = 0; i < s->nb_ports; i++) { | ||
591 | - port = &s->ports[i]; | ||
592 | - if (port->wPortChange) | ||
593 | - status |= (1 << (i + 1)); | ||
594 | - } | ||
595 | - if (status != 0) { | ||
596 | - for(i = 0; i < n; i++) { | ||
597 | - data[i] = status >> (8 * i); | ||
598 | - } | ||
599 | - ret = n; | ||
600 | - } else { | ||
601 | - ret = 0; | ||
602 | - } | ||
603 | - } else { | ||
604 | - goto fail; | ||
605 | - } | ||
606 | - break; | ||
607 | - case USB_TOKEN_OUT: | ||
608 | - default: | ||
609 | - fail: | ||
610 | - ret = USB_RET_STALL; | ||
611 | - break; | ||
612 | - } | ||
613 | - return ret; | ||
614 | -} | ||
615 | - | ||
616 | -static int usb_hub_broadcast_packet(USBHubState *s, int pid, | ||
617 | - uint8_t devaddr, uint8_t devep, | ||
618 | - uint8_t *data, int len) | ||
619 | -{ | ||
620 | - USBHubPort *port; | ||
621 | - USBDevice *dev; | ||
622 | - int i, ret; | ||
623 | - | ||
624 | - for(i = 0; i < s->nb_ports; i++) { | ||
625 | - port = &s->ports[i]; | ||
626 | - dev = port->port.dev; | ||
627 | - if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { | ||
628 | - ret = dev->handle_packet(dev, pid, | ||
629 | - devaddr, devep, | ||
630 | - data, len); | ||
631 | - if (ret != USB_RET_NODEV) { | ||
632 | - return ret; | ||
633 | - } | ||
634 | - } | ||
635 | - } | ||
636 | - return USB_RET_NODEV; | ||
637 | -} | ||
638 | - | ||
639 | -static int usb_hub_handle_packet(USBDevice *dev, int pid, | ||
640 | - uint8_t devaddr, uint8_t devep, | ||
641 | - uint8_t *data, int len) | ||
642 | -{ | ||
643 | - USBHubState *s = (USBHubState *)dev; | ||
644 | - | ||
645 | -#if defined(DEBUG) && 0 | ||
646 | - printf("usb_hub: pid=0x%x\n", pid); | ||
647 | -#endif | ||
648 | - if (dev->state == USB_STATE_DEFAULT && | ||
649 | - dev->addr != 0 && | ||
650 | - devaddr != dev->addr && | ||
651 | - (pid == USB_TOKEN_SETUP || | ||
652 | - pid == USB_TOKEN_OUT || | ||
653 | - pid == USB_TOKEN_IN)) { | ||
654 | - /* broadcast the packet to the devices */ | ||
655 | - return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len); | ||
656 | - } | ||
657 | - return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); | ||
658 | -} | ||
659 | - | ||
660 | -USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) | ||
661 | -{ | ||
662 | - USBHubState *s; | ||
663 | - USBHubPort *port; | ||
664 | - int i; | ||
665 | - | ||
666 | - if (nb_ports > MAX_PORTS) | ||
667 | - return NULL; | ||
668 | - s = qemu_mallocz(sizeof(USBHubState)); | ||
669 | - if (!s) | ||
670 | - return NULL; | ||
671 | - s->dev.speed = USB_SPEED_FULL; | ||
672 | - s->dev.handle_packet = usb_hub_handle_packet; | ||
673 | - | ||
674 | - /* generic USB device init */ | ||
675 | - s->dev.handle_reset = usb_hub_handle_reset; | ||
676 | - s->dev.handle_control = usb_hub_handle_control; | ||
677 | - s->dev.handle_data = usb_hub_handle_data; | ||
678 | - | ||
679 | - s->nb_ports = nb_ports; | ||
680 | - for(i = 0; i < s->nb_ports; i++) { | ||
681 | - port = &s->ports[i]; | ||
682 | - port->wPortStatus = PORT_STAT_POWER; | ||
683 | - port->wPortChange = 0; | ||
684 | - port->port.attach = usb_hub_attach; | ||
685 | - port->port.opaque = s; | ||
686 | - port->port.index = i; | ||
687 | - usb_ports[i] = &port->port; | ||
688 | - } | ||
689 | - return (USBDevice *)s; | ||
690 | -} |