Statistics
| Branch: | Revision:

root / hw / usb-hub.c @ 67f36560

History | View | Annotate | Download (16.4 kB)

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