Statistics
| Branch: | Revision:

root / hw / usb.c @ 09b26c5e

History | View | Annotate | Download (20.8 kB)

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