Statistics
| Branch: | Revision:

root / hw / usb-hub.c @ 0fe5ea89

History | View | Annotate | Download (16.2 kB)

1 72899afc bellard
/*
2 72899afc bellard
 * QEMU USB HUB emulation
3 72899afc bellard
 *
4 72899afc bellard
 * Copyright (c) 2005 Fabrice Bellard
5 5fafdf24 ths
 *
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 5fafdf24 ths
        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 3b46e624 ths
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 3b46e624 ths
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 3b46e624 ths
171 72899afc bellard
    if (dev) {
172 72899afc bellard
        if (port->port.dev)
173 72899afc bellard
            usb_attach(port1, NULL);
174 3b46e624 ths
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 0d92ed30 pbrook
        /* send the attach message */
183 4d611c9a pbrook
        usb_send_msg(dev, USB_MSG_ATTACH);
184 72899afc bellard
    } else {
185 72899afc bellard
        dev = port->port.dev;
186 72899afc bellard
        if (dev) {
187 72899afc bellard
            port->wPortStatus &= ~PORT_STAT_CONNECTION;
188 72899afc bellard
            port->wPortChange |= PORT_STAT_C_CONNECTION;
189 72899afc bellard
            if (port->wPortStatus & PORT_STAT_ENABLE) {
190 72899afc bellard
                port->wPortStatus &= ~PORT_STAT_ENABLE;
191 72899afc bellard
                port->wPortChange |= PORT_STAT_C_ENABLE;
192 72899afc bellard
            }
193 0d92ed30 pbrook
            /* send the detach message */
194 4d611c9a pbrook
            usb_send_msg(dev, USB_MSG_DETACH);
195 72899afc bellard
            port->port.dev = NULL;
196 72899afc bellard
        }
197 72899afc bellard
    }
198 72899afc bellard
}
199 72899afc bellard
200 059809e4 bellard
static void usb_hub_handle_reset(USBDevice *dev)
201 72899afc bellard
{
202 72899afc bellard
    /* XXX: do it */
203 72899afc bellard
}
204 72899afc bellard
205 72899afc bellard
static int usb_hub_handle_control(USBDevice *dev, int request, int value,
206 72899afc bellard
                                  int index, int length, uint8_t *data)
207 72899afc bellard
{
208 72899afc bellard
    USBHubState *s = (USBHubState *)dev;
209 72899afc bellard
    int ret;
210 72899afc bellard
211 72899afc bellard
    switch(request) {
212 72899afc bellard
    case DeviceRequest | USB_REQ_GET_STATUS:
213 72899afc bellard
        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
214 72899afc bellard
            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
215 72899afc bellard
        data[1] = 0x00;
216 72899afc bellard
        ret = 2;
217 72899afc bellard
        break;
218 72899afc bellard
    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
219 72899afc bellard
        if (value == USB_DEVICE_REMOTE_WAKEUP) {
220 72899afc bellard
            dev->remote_wakeup = 0;
221 72899afc bellard
        } else {
222 72899afc bellard
            goto fail;
223 72899afc bellard
        }
224 72899afc bellard
        ret = 0;
225 72899afc bellard
        break;
226 985d1742 bellard
    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
227 985d1742 bellard
        if (value == 0 && index != 0x81) { /* clear ep halt */
228 985d1742 bellard
            goto fail;
229 985d1742 bellard
        }
230 985d1742 bellard
        ret = 0;
231 985d1742 bellard
        break;
232 72899afc bellard
    case DeviceOutRequest | USB_REQ_SET_FEATURE:
233 72899afc bellard
        if (value == USB_DEVICE_REMOTE_WAKEUP) {
234 72899afc bellard
            dev->remote_wakeup = 1;
235 72899afc bellard
        } else {
236 72899afc bellard
            goto fail;
237 72899afc bellard
        }
238 72899afc bellard
        ret = 0;
239 72899afc bellard
        break;
240 72899afc bellard
    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
241 72899afc bellard
        dev->addr = value;
242 72899afc bellard
        ret = 0;
243 72899afc bellard
        break;
244 72899afc bellard
    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
245 72899afc bellard
        switch(value >> 8) {
246 72899afc bellard
        case USB_DT_DEVICE:
247 5fafdf24 ths
            memcpy(data, qemu_hub_dev_descriptor,
248 72899afc bellard
                   sizeof(qemu_hub_dev_descriptor));
249 72899afc bellard
            ret = sizeof(qemu_hub_dev_descriptor);
250 72899afc bellard
            break;
251 72899afc bellard
        case USB_DT_CONFIG:
252 5fafdf24 ths
            memcpy(data, qemu_hub_config_descriptor,
253 72899afc bellard
                   sizeof(qemu_hub_config_descriptor));
254 985d1742 bellard
255 985d1742 bellard
            /* status change endpoint size based on number
256 985d1742 bellard
             * of ports */
257 985d1742 bellard
            data[22] = (s->nb_ports + 1 + 7) / 8;
258 985d1742 bellard
259 72899afc bellard
            ret = sizeof(qemu_hub_config_descriptor);
260 72899afc bellard
            break;
261 72899afc bellard
        case USB_DT_STRING:
262 72899afc bellard
            switch(value & 0xff) {
263 72899afc bellard
            case 0:
264 72899afc bellard
                /* language ids */
265 72899afc bellard
                data[0] = 4;
266 72899afc bellard
                data[1] = 3;
267 72899afc bellard
                data[2] = 0x09;
268 72899afc bellard
                data[3] = 0x04;
269 72899afc bellard
                ret = 4;
270 72899afc bellard
                break;
271 72899afc bellard
            case 1:
272 72899afc bellard
                /* serial number */
273 72899afc bellard
                ret = set_usb_string(data, "314159");
274 72899afc bellard
                break;
275 72899afc bellard
            case 2:
276 72899afc bellard
                /* product description */
277 72899afc bellard
                ret = set_usb_string(data, "QEMU USB Hub");
278 72899afc bellard
                break;
279 72899afc bellard
            case 3:
280 72899afc bellard
                /* vendor description */
281 72899afc bellard
                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
282 72899afc bellard
                break;
283 72899afc bellard
            default:
284 72899afc bellard
                goto fail;
285 72899afc bellard
            }
286 72899afc bellard
            break;
287 72899afc bellard
        default:
288 72899afc bellard
            goto fail;
289 72899afc bellard
        }
290 72899afc bellard
        break;
291 72899afc bellard
    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
292 72899afc bellard
        data[0] = 1;
293 72899afc bellard
        ret = 1;
294 72899afc bellard
        break;
295 72899afc bellard
    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
296 72899afc bellard
        ret = 0;
297 72899afc bellard
        break;
298 72899afc bellard
    case DeviceRequest | USB_REQ_GET_INTERFACE:
299 72899afc bellard
        data[0] = 0;
300 72899afc bellard
        ret = 1;
301 72899afc bellard
        break;
302 72899afc bellard
    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
303 72899afc bellard
        ret = 0;
304 72899afc bellard
        break;
305 72899afc bellard
        /* usb specific requests */
306 72899afc bellard
    case GetHubStatus:
307 72899afc bellard
        data[0] = 0;
308 72899afc bellard
        data[1] = 0;
309 72899afc bellard
        data[2] = 0;
310 72899afc bellard
        data[3] = 0;
311 72899afc bellard
        ret = 4;
312 72899afc bellard
        break;
313 72899afc bellard
    case GetPortStatus:
314 72899afc bellard
        {
315 72899afc bellard
            unsigned int n = index - 1;
316 72899afc bellard
            USBHubPort *port;
317 72899afc bellard
            if (n >= s->nb_ports)
318 72899afc bellard
                goto fail;
319 72899afc bellard
            port = &s->ports[n];
320 72899afc bellard
            data[0] = port->wPortStatus;
321 72899afc bellard
            data[1] = port->wPortStatus >> 8;
322 72899afc bellard
            data[2] = port->wPortChange;
323 72899afc bellard
            data[3] = port->wPortChange >> 8;
324 72899afc bellard
            ret = 4;
325 72899afc bellard
        }
326 72899afc bellard
        break;
327 72899afc bellard
    case SetHubFeature:
328 72899afc bellard
    case ClearHubFeature:
329 72899afc bellard
        if (value == 0 || value == 1) {
330 72899afc bellard
        } else {
331 72899afc bellard
            goto fail;
332 72899afc bellard
        }
333 72899afc bellard
        ret = 0;
334 72899afc bellard
        break;
335 72899afc bellard
    case SetPortFeature:
336 72899afc bellard
        {
337 72899afc bellard
            unsigned int n = index - 1;
338 72899afc bellard
            USBHubPort *port;
339 72899afc bellard
            USBDevice *dev;
340 72899afc bellard
            if (n >= s->nb_ports)
341 72899afc bellard
                goto fail;
342 72899afc bellard
            port = &s->ports[n];
343 72899afc bellard
            dev = port->port.dev;
344 72899afc bellard
            switch(value) {
345 72899afc bellard
            case PORT_SUSPEND:
346 72899afc bellard
                port->wPortStatus |= PORT_STAT_SUSPEND;
347 72899afc bellard
                break;
348 72899afc bellard
            case PORT_RESET:
349 72899afc bellard
                if (dev) {
350 4d611c9a pbrook
                    usb_send_msg(dev, USB_MSG_RESET);
351 72899afc bellard
                    port->wPortChange |= PORT_STAT_C_RESET;
352 72899afc bellard
                    /* set enable bit */
353 72899afc bellard
                    port->wPortStatus |= PORT_STAT_ENABLE;
354 72899afc bellard
                }
355 72899afc bellard
                break;
356 72899afc bellard
            case PORT_POWER:
357 72899afc bellard
                break;
358 72899afc bellard
            default:
359 72899afc bellard
                goto fail;
360 72899afc bellard
            }
361 72899afc bellard
            ret = 0;
362 72899afc bellard
        }
363 72899afc bellard
        break;
364 72899afc bellard
    case ClearPortFeature:
365 72899afc bellard
        {
366 72899afc bellard
            unsigned int n = index - 1;
367 72899afc bellard
            USBHubPort *port;
368 72899afc bellard
            USBDevice *dev;
369 72899afc bellard
            if (n >= s->nb_ports)
370 72899afc bellard
                goto fail;
371 72899afc bellard
            port = &s->ports[n];
372 72899afc bellard
            dev = port->port.dev;
373 72899afc bellard
            switch(value) {
374 72899afc bellard
            case PORT_ENABLE:
375 72899afc bellard
                port->wPortStatus &= ~PORT_STAT_ENABLE;
376 72899afc bellard
                break;
377 72899afc bellard
            case PORT_C_ENABLE:
378 72899afc bellard
                port->wPortChange &= ~PORT_STAT_C_ENABLE;
379 72899afc bellard
                break;
380 72899afc bellard
            case PORT_SUSPEND:
381 72899afc bellard
                port->wPortStatus &= ~PORT_STAT_SUSPEND;
382 72899afc bellard
                break;
383 72899afc bellard
            case PORT_C_SUSPEND:
384 72899afc bellard
                port->wPortChange &= ~PORT_STAT_C_SUSPEND;
385 72899afc bellard
                break;
386 72899afc bellard
            case PORT_C_CONNECTION:
387 72899afc bellard
                port->wPortChange &= ~PORT_STAT_C_CONNECTION;
388 72899afc bellard
                break;
389 72899afc bellard
            case PORT_C_OVERCURRENT:
390 72899afc bellard
                port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
391 72899afc bellard
                break;
392 72899afc bellard
            case PORT_C_RESET:
393 72899afc bellard
                port->wPortChange &= ~PORT_STAT_C_RESET;
394 72899afc bellard
                break;
395 72899afc bellard
            default:
396 72899afc bellard
                goto fail;
397 72899afc bellard
            }
398 72899afc bellard
            ret = 0;
399 72899afc bellard
        }
400 72899afc bellard
        break;
401 72899afc bellard
    case GetHubDescriptor:
402 985d1742 bellard
        {
403 985d1742 bellard
            unsigned int n, limit, var_hub_size = 0;
404 5fafdf24 ths
            memcpy(data, qemu_hub_hub_descriptor,
405 985d1742 bellard
                   sizeof(qemu_hub_hub_descriptor));
406 985d1742 bellard
            data[2] = s->nb_ports;
407 985d1742 bellard
408 985d1742 bellard
            /* fill DeviceRemovable bits */
409 985d1742 bellard
            limit = ((s->nb_ports + 1 + 7) / 8) + 7;
410 985d1742 bellard
            for (n = 7; n < limit; n++) {
411 985d1742 bellard
                data[n] = 0x00;
412 985d1742 bellard
                var_hub_size++;
413 985d1742 bellard
            }
414 985d1742 bellard
415 985d1742 bellard
            /* fill PortPwrCtrlMask bits */
416 985d1742 bellard
            limit = limit + ((s->nb_ports + 7) / 8);
417 985d1742 bellard
            for (;n < limit; n++) {
418 985d1742 bellard
                data[n] = 0xff;
419 985d1742 bellard
                var_hub_size++;
420 985d1742 bellard
            }
421 985d1742 bellard
422 985d1742 bellard
            ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
423 67f36560 bellard
            data[0] = ret;
424 985d1742 bellard
            break;
425 985d1742 bellard
        }
426 72899afc bellard
    default:
427 72899afc bellard
    fail:
428 72899afc bellard
        ret = USB_RET_STALL;
429 72899afc bellard
        break;
430 72899afc bellard
    }
431 72899afc bellard
    return ret;
432 72899afc bellard
}
433 72899afc bellard
434 4d611c9a pbrook
static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
435 72899afc bellard
{
436 72899afc bellard
    USBHubState *s = (USBHubState *)dev;
437 72899afc bellard
    int ret;
438 72899afc bellard
439 4d611c9a pbrook
    switch(p->pid) {
440 72899afc bellard
    case USB_TOKEN_IN:
441 4d611c9a pbrook
        if (p->devep == 1) {
442 72899afc bellard
            USBHubPort *port;
443 72899afc bellard
            unsigned int status;
444 72899afc bellard
            int i, n;
445 72899afc bellard
            n = (s->nb_ports + 1 + 7) / 8;
446 4d611c9a pbrook
            if (p->len == 1) { /* FreeBSD workaround */
447 985d1742 bellard
                n = 1;
448 4d611c9a pbrook
            } else if (n > p->len) {
449 72899afc bellard
                return USB_RET_BABBLE;
450 985d1742 bellard
            }
451 72899afc bellard
            status = 0;
452 72899afc bellard
            for(i = 0; i < s->nb_ports; i++) {
453 72899afc bellard
                port = &s->ports[i];
454 72899afc bellard
                if (port->wPortChange)
455 72899afc bellard
                    status |= (1 << (i + 1));
456 72899afc bellard
            }
457 72899afc bellard
            if (status != 0) {
458 72899afc bellard
                for(i = 0; i < n; i++) {
459 4d611c9a pbrook
                    p->data[i] = status >> (8 * i);
460 72899afc bellard
                }
461 72899afc bellard
                ret = n;
462 72899afc bellard
            } else {
463 985d1742 bellard
                ret = USB_RET_NAK; /* usb11 11.13.1 */
464 72899afc bellard
            }
465 72899afc bellard
        } else {
466 72899afc bellard
            goto fail;
467 72899afc bellard
        }
468 72899afc bellard
        break;
469 72899afc bellard
    case USB_TOKEN_OUT:
470 72899afc bellard
    default:
471 72899afc bellard
    fail:
472 72899afc bellard
        ret = USB_RET_STALL;
473 72899afc bellard
        break;
474 72899afc bellard
    }
475 72899afc bellard
    return ret;
476 72899afc bellard
}
477 72899afc bellard
478 4d611c9a pbrook
static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
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 4d611c9a pbrook
            ret = dev->handle_packet(dev, p);
489 72899afc bellard
            if (ret != USB_RET_NODEV) {
490 72899afc bellard
                return ret;
491 72899afc bellard
            }
492 72899afc bellard
        }
493 72899afc bellard
    }
494 72899afc bellard
    return USB_RET_NODEV;
495 72899afc bellard
}
496 72899afc bellard
497 4d611c9a pbrook
static int usb_hub_handle_packet(USBDevice *dev, USBPacket *p)
498 72899afc bellard
{
499 72899afc bellard
    USBHubState *s = (USBHubState *)dev;
500 72899afc bellard
501 72899afc bellard
#if defined(DEBUG) && 0
502 72899afc bellard
    printf("usb_hub: pid=0x%x\n", pid);
503 72899afc bellard
#endif
504 72899afc bellard
    if (dev->state == USB_STATE_DEFAULT &&
505 72899afc bellard
        dev->addr != 0 &&
506 4d611c9a pbrook
        p->devaddr != dev->addr &&
507 5fafdf24 ths
        (p->pid == USB_TOKEN_SETUP ||
508 5fafdf24 ths
         p->pid == USB_TOKEN_OUT ||
509 4d611c9a pbrook
         p->pid == USB_TOKEN_IN)) {
510 72899afc bellard
        /* broadcast the packet to the devices */
511 4d611c9a pbrook
        return usb_hub_broadcast_packet(s, p);
512 72899afc bellard
    }
513 4d611c9a pbrook
    return usb_generic_handle_packet(dev, p);
514 72899afc bellard
}
515 72899afc bellard
516 059809e4 bellard
static void usb_hub_handle_destroy(USBDevice *dev)
517 059809e4 bellard
{
518 059809e4 bellard
    USBHubState *s = (USBHubState *)dev;
519 059809e4 bellard
520 059809e4 bellard
    qemu_free(s);
521 059809e4 bellard
}
522 059809e4 bellard
523 0d92ed30 pbrook
USBDevice *usb_hub_init(int nb_ports)
524 72899afc bellard
{
525 72899afc bellard
    USBHubState *s;
526 72899afc bellard
    USBHubPort *port;
527 72899afc bellard
    int i;
528 72899afc bellard
529 72899afc bellard
    if (nb_ports > MAX_PORTS)
530 72899afc bellard
        return NULL;
531 72899afc bellard
    s = qemu_mallocz(sizeof(USBHubState));
532 72899afc bellard
    if (!s)
533 72899afc bellard
        return NULL;
534 72899afc bellard
    s->dev.speed = USB_SPEED_FULL;
535 72899afc bellard
    s->dev.handle_packet = usb_hub_handle_packet;
536 72899afc bellard
537 72899afc bellard
    /* generic USB device init */
538 72899afc bellard
    s->dev.handle_reset = usb_hub_handle_reset;
539 72899afc bellard
    s->dev.handle_control = usb_hub_handle_control;
540 72899afc bellard
    s->dev.handle_data = usb_hub_handle_data;
541 059809e4 bellard
    s->dev.handle_destroy = usb_hub_handle_destroy;
542 72899afc bellard
543 1f6e24e7 bellard
    pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Hub");
544 1f6e24e7 bellard
545 72899afc bellard
    s->nb_ports = nb_ports;
546 72899afc bellard
    for(i = 0; i < s->nb_ports; i++) {
547 72899afc bellard
        port = &s->ports[i];
548 0d92ed30 pbrook
        qemu_register_usb_port(&port->port, s, i, usb_hub_attach);
549 72899afc bellard
        port->wPortStatus = PORT_STAT_POWER;
550 72899afc bellard
        port->wPortChange = 0;
551 72899afc bellard
    }
552 72899afc bellard
    return (USBDevice *)s;
553 72899afc bellard
}