Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (16.4 kB)

1
/*
2
 * QEMU USB HUB emulation
3
 *
4
 * Copyright (c) 2005 Fabrice Bellard
5
 * 
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "vl.h"
25

    
26
//#define DEBUG
27

    
28
#define MAX_PORTS 8
29

    
30
typedef struct USBHubPort {
31
    USBPort port;
32
    uint16_t wPortStatus;
33
    uint16_t wPortChange;
34
} USBHubPort;
35

    
36
typedef struct USBHubState {
37
    USBDevice dev;
38
    int nb_ports;
39
    USBHubPort ports[MAX_PORTS];
40
} USBHubState;
41

    
42
#define ClearHubFeature                (0x2000 | USB_REQ_CLEAR_FEATURE)
43
#define ClearPortFeature        (0x2300 | USB_REQ_CLEAR_FEATURE)
44
#define GetHubDescriptor        (0xa000 | USB_REQ_GET_DESCRIPTOR)
45
#define GetHubStatus                (0xa000 | USB_REQ_GET_STATUS)
46
#define GetPortStatus                (0xa300 | USB_REQ_GET_STATUS)
47
#define SetHubFeature                (0x2000 | USB_REQ_SET_FEATURE)
48
#define SetPortFeature                (0x2300 | USB_REQ_SET_FEATURE)
49

    
50
#define PORT_STAT_CONNECTION        0x0001
51
#define PORT_STAT_ENABLE        0x0002
52
#define PORT_STAT_SUSPEND        0x0004
53
#define PORT_STAT_OVERCURRENT        0x0008
54
#define PORT_STAT_RESET                0x0010
55
#define PORT_STAT_POWER                0x0100
56
#define PORT_STAT_LOW_SPEED        0x0200
57
#define PORT_STAT_HIGH_SPEED    0x0400
58
#define PORT_STAT_TEST          0x0800
59
#define PORT_STAT_INDICATOR     0x1000
60

    
61
#define PORT_STAT_C_CONNECTION        0x0001
62
#define PORT_STAT_C_ENABLE        0x0002
63
#define PORT_STAT_C_SUSPEND        0x0004
64
#define PORT_STAT_C_OVERCURRENT        0x0008
65
#define PORT_STAT_C_RESET        0x0010
66

    
67
#define PORT_CONNECTION                0
68
#define PORT_ENABLE                1
69
#define PORT_SUSPEND                2
70
#define PORT_OVERCURRENT        3
71
#define PORT_RESET                4
72
#define PORT_POWER                8
73
#define PORT_LOWSPEED                9
74
#define PORT_HIGHSPEED                10
75
#define PORT_C_CONNECTION        16
76
#define PORT_C_ENABLE                17
77
#define PORT_C_SUSPEND                18
78
#define PORT_C_OVERCURRENT        19
79
#define PORT_C_RESET                20
80
#define PORT_TEST               21
81
#define PORT_INDICATOR          22
82

    
83
/* same as Linux kernel root hubs */
84

    
85
static const uint8_t qemu_hub_dev_descriptor[] = {
86
        0x12,       /*  u8 bLength; */
87
        0x01,       /*  u8 bDescriptorType; Device */
88
        0x10, 0x01, /*  u16 bcdUSB; v1.1 */
89

    
90
        0x09,            /*  u8  bDeviceClass; HUB_CLASSCODE */
91
        0x00,            /*  u8  bDeviceSubClass; */
92
        0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
93
        0x08,       /*  u8  bMaxPacketSize0; 8 Bytes */
94

    
95
        0x00, 0x00, /*  u16 idVendor; */
96
         0x00, 0x00, /*  u16 idProduct; */
97
        0x01, 0x01, /*  u16 bcdDevice */
98

    
99
        0x03,       /*  u8  iManufacturer; */
100
        0x02,       /*  u8  iProduct; */
101
        0x01,       /*  u8  iSerialNumber; */
102
        0x01        /*  u8  bNumConfigurations; */
103
};
104

    
105
/* XXX: patch interrupt size */
106
static const uint8_t qemu_hub_config_descriptor[] = {
107

    
108
        /* one configuration */
109
        0x09,       /*  u8  bLength; */
110
        0x02,       /*  u8  bDescriptorType; Configuration */
111
        0x19, 0x00, /*  u16 wTotalLength; */
112
        0x01,       /*  u8  bNumInterfaces; (1) */
113
        0x01,       /*  u8  bConfigurationValue; */
114
        0x00,       /*  u8  iConfiguration; */
115
        0xc0,       /*  u8  bmAttributes; 
116
                                 Bit 7: must be set,
117
                                     6: Self-powered,
118
                                     5: Remote wakeup,
119
                                     4..0: resvd */
120
        0x00,       /*  u8  MaxPower; */
121
      
122
        /* USB 1.1:
123
         * USB 2.0, single TT organization (mandatory):
124
         *        one interface, protocol 0
125
         *
126
         * USB 2.0, multiple TT organization (optional):
127
         *        two interfaces, protocols 1 (like single TT)
128
         *        and 2 (multiple TT mode) ... config is
129
         *        sometimes settable
130
         *        NOT IMPLEMENTED
131
         */
132

    
133
        /* one interface */
134
        0x09,       /*  u8  if_bLength; */
135
        0x04,       /*  u8  if_bDescriptorType; Interface */
136
        0x00,       /*  u8  if_bInterfaceNumber; */
137
        0x00,       /*  u8  if_bAlternateSetting; */
138
        0x01,       /*  u8  if_bNumEndpoints; */
139
        0x09,       /*  u8  if_bInterfaceClass; HUB_CLASSCODE */
140
        0x00,       /*  u8  if_bInterfaceSubClass; */
141
        0x00,       /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
142
        0x00,       /*  u8  if_iInterface; */
143
     
144
        /* one endpoint (status change endpoint) */
145
        0x07,       /*  u8  ep_bLength; */
146
        0x05,       /*  u8  ep_bDescriptorType; Endpoint */
147
        0x81,       /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
148
         0x03,       /*  u8  ep_bmAttributes; Interrupt */
149
         0x02, 0x00, /*  u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
150
        0xff        /*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
151
};
152

    
153
static const uint8_t qemu_hub_hub_descriptor[] =
154
{
155
        0x00,                        /*  u8  bLength; patched in later */
156
        0x29,                        /*  u8  bDescriptorType; Hub-descriptor */
157
        0x00,                        /*  u8  bNbrPorts; (patched later) */
158
        0x0a,                        /* u16  wHubCharacteristics; */
159
        0x00,                        /*   (per-port OC, no power switching) */
160
        0x01,                        /*  u8  bPwrOn2pwrGood; 2ms */
161
        0x00                        /*  u8  bHubContrCurrent; 0 mA */
162

    
163
        /* DeviceRemovable and PortPwrCtrlMask patched in later */
164
};
165

    
166
static void usb_hub_attach(USBPort *port1, USBDevice *dev)
167
{
168
    USBHubState *s = port1->opaque;
169
    USBHubPort *port = &s->ports[port1->index];
170
    
171
    if (dev) {
172
        if (port->port.dev)
173
            usb_attach(port1, NULL);
174
        
175
        port->wPortStatus |= PORT_STAT_CONNECTION;
176
        port->wPortChange |= PORT_STAT_C_CONNECTION;
177
        if (dev->speed == USB_SPEED_LOW)
178
            port->wPortStatus |= PORT_STAT_LOW_SPEED;
179
        else
180
            port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
181
        port->port.dev = dev;
182
    } else {
183
        dev = port->port.dev;
184
        if (dev) {
185
            port->wPortStatus &= ~PORT_STAT_CONNECTION;
186
            port->wPortChange |= PORT_STAT_C_CONNECTION;
187
            if (port->wPortStatus & PORT_STAT_ENABLE) {
188
                port->wPortStatus &= ~PORT_STAT_ENABLE;
189
                port->wPortChange |= PORT_STAT_C_ENABLE;
190
            }
191
            port->port.dev = NULL;
192
        }
193
    }
194
}
195

    
196
static void usb_hub_handle_reset(USBDevice *dev)
197
{
198
    /* XXX: do it */
199
}
200

    
201
static int usb_hub_handle_control(USBDevice *dev, int request, int value,
202
                                  int index, int length, uint8_t *data)
203
{
204
    USBHubState *s = (USBHubState *)dev;
205
    int ret;
206

    
207
    switch(request) {
208
    case DeviceRequest | USB_REQ_GET_STATUS:
209
        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
210
            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
211
        data[1] = 0x00;
212
        ret = 2;
213
        break;
214
    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
215
        if (value == USB_DEVICE_REMOTE_WAKEUP) {
216
            dev->remote_wakeup = 0;
217
        } else {
218
            goto fail;
219
        }
220
        ret = 0;
221
        break;
222
    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
223
        if (value == 0 && index != 0x81) { /* clear ep halt */
224
            goto fail;
225
        }
226
        ret = 0;
227
        break;
228
    case DeviceOutRequest | USB_REQ_SET_FEATURE:
229
        if (value == USB_DEVICE_REMOTE_WAKEUP) {
230
            dev->remote_wakeup = 1;
231
        } else {
232
            goto fail;
233
        }
234
        ret = 0;
235
        break;
236
    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
237
        dev->addr = value;
238
        ret = 0;
239
        break;
240
    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
241
        switch(value >> 8) {
242
        case USB_DT_DEVICE:
243
            memcpy(data, qemu_hub_dev_descriptor, 
244
                   sizeof(qemu_hub_dev_descriptor));
245
            ret = sizeof(qemu_hub_dev_descriptor);
246
            break;
247
        case USB_DT_CONFIG:
248
            memcpy(data, qemu_hub_config_descriptor, 
249
                   sizeof(qemu_hub_config_descriptor));
250

    
251
            /* status change endpoint size based on number
252
             * of ports */
253
            data[22] = (s->nb_ports + 1 + 7) / 8;
254

    
255
            ret = sizeof(qemu_hub_config_descriptor);
256
            break;
257
        case USB_DT_STRING:
258
            switch(value & 0xff) {
259
            case 0:
260
                /* language ids */
261
                data[0] = 4;
262
                data[1] = 3;
263
                data[2] = 0x09;
264
                data[3] = 0x04;
265
                ret = 4;
266
                break;
267
            case 1:
268
                /* serial number */
269
                ret = set_usb_string(data, "314159");
270
                break;
271
            case 2:
272
                /* product description */
273
                ret = set_usb_string(data, "QEMU USB Hub");
274
                break;
275
            case 3:
276
                /* vendor description */
277
                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
278
                break;
279
            default:
280
                goto fail;
281
            }
282
            break;
283
        default:
284
            goto fail;
285
        }
286
        break;
287
    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
288
        data[0] = 1;
289
        ret = 1;
290
        break;
291
    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
292
        ret = 0;
293
        break;
294
    case DeviceRequest | USB_REQ_GET_INTERFACE:
295
        data[0] = 0;
296
        ret = 1;
297
        break;
298
    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
299
        ret = 0;
300
        break;
301
        /* usb specific requests */
302
    case GetHubStatus:
303
        data[0] = 0;
304
        data[1] = 0;
305
        data[2] = 0;
306
        data[3] = 0;
307
        ret = 4;
308
        break;
309
    case GetPortStatus:
310
        {
311
            unsigned int n = index - 1;
312
            USBHubPort *port;
313
            if (n >= s->nb_ports)
314
                goto fail;
315
            port = &s->ports[n];
316
            data[0] = port->wPortStatus;
317
            data[1] = port->wPortStatus >> 8;
318
            data[2] = port->wPortChange;
319
            data[3] = port->wPortChange >> 8;
320
            ret = 4;
321
        }
322
        break;
323
    case SetHubFeature:
324
    case ClearHubFeature:
325
        if (value == 0 || value == 1) {
326
        } else {
327
            goto fail;
328
        }
329
        ret = 0;
330
        break;
331
    case SetPortFeature:
332
        {
333
            unsigned int n = index - 1;
334
            USBHubPort *port;
335
            USBDevice *dev;
336
            if (n >= s->nb_ports)
337
                goto fail;
338
            port = &s->ports[n];
339
            dev = port->port.dev;
340
            switch(value) {
341
            case PORT_SUSPEND:
342
                port->wPortStatus |= PORT_STAT_SUSPEND;
343
                break;
344
            case PORT_RESET:
345
                if (dev) {
346
                    dev->handle_packet(dev, 
347
                                       USB_MSG_RESET, 0, 0, NULL, 0);
348
                    port->wPortChange |= PORT_STAT_C_RESET;
349
                    /* set enable bit */
350
                    port->wPortStatus |= PORT_STAT_ENABLE;
351
                }
352
                break;
353
            case PORT_POWER:
354
                break;
355
            default:
356
                goto fail;
357
            }
358
            ret = 0;
359
        }
360
        break;
361
    case ClearPortFeature:
362
        {
363
            unsigned int n = index - 1;
364
            USBHubPort *port;
365
            USBDevice *dev;
366
            if (n >= s->nb_ports)
367
                goto fail;
368
            port = &s->ports[n];
369
            dev = port->port.dev;
370
            switch(value) {
371
            case PORT_ENABLE:
372
                port->wPortStatus &= ~PORT_STAT_ENABLE;
373
                break;
374
            case PORT_C_ENABLE:
375
                port->wPortChange &= ~PORT_STAT_C_ENABLE;
376
                break;
377
            case PORT_SUSPEND:
378
                port->wPortStatus &= ~PORT_STAT_SUSPEND;
379
                break;
380
            case PORT_C_SUSPEND:
381
                port->wPortChange &= ~PORT_STAT_C_SUSPEND;
382
                break;
383
            case PORT_C_CONNECTION:
384
                port->wPortChange &= ~PORT_STAT_C_CONNECTION;
385
                break;
386
            case PORT_C_OVERCURRENT:
387
                port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
388
                break;
389
            case PORT_C_RESET:
390
                port->wPortChange &= ~PORT_STAT_C_RESET;
391
                break;
392
            default:
393
                goto fail;
394
            }
395
            ret = 0;
396
        }
397
        break;
398
    case GetHubDescriptor:
399
        {
400
            unsigned int n, limit, var_hub_size = 0;
401
            memcpy(data, qemu_hub_hub_descriptor, 
402
                   sizeof(qemu_hub_hub_descriptor));
403
            data[2] = s->nb_ports;
404

    
405
            /* fill DeviceRemovable bits */
406
            limit = ((s->nb_ports + 1 + 7) / 8) + 7;
407
            for (n = 7; n < limit; n++) {
408
                data[n] = 0x00;
409
                var_hub_size++;
410
            }
411

    
412
            /* fill PortPwrCtrlMask bits */
413
            limit = limit + ((s->nb_ports + 7) / 8);
414
            for (;n < limit; n++) {
415
                data[n] = 0xff;
416
                var_hub_size++;
417
            }
418

    
419
            ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
420
            data[0] = ret;
421
            break;
422
        }
423
    default:
424
    fail:
425
        ret = USB_RET_STALL;
426
        break;
427
    }
428
    return ret;
429
}
430

    
431
static int usb_hub_handle_data(USBDevice *dev, int pid, 
432
                               uint8_t devep, uint8_t *data, int len)
433
{
434
    USBHubState *s = (USBHubState *)dev;
435
    int ret;
436

    
437
    switch(pid) {
438
    case USB_TOKEN_IN:
439
        if (devep == 1) {
440
            USBHubPort *port;
441
            unsigned int status;
442
            int i, n;
443
            n = (s->nb_ports + 1 + 7) / 8;
444
            if (len == 1) { /* FreeBSD workaround */
445
                n = 1;
446
            } else if (n > len) {
447
                return USB_RET_BABBLE;
448
            }
449
            status = 0;
450
            for(i = 0; i < s->nb_ports; i++) {
451
                port = &s->ports[i];
452
                if (port->wPortChange)
453
                    status |= (1 << (i + 1));
454
            }
455
            if (status != 0) {
456
                for(i = 0; i < n; i++) {
457
                    data[i] = status >> (8 * i);
458
                }
459
                ret = n;
460
            } else {
461
                ret = USB_RET_NAK; /* usb11 11.13.1 */
462
            }
463
        } else {
464
            goto fail;
465
        }
466
        break;
467
    case USB_TOKEN_OUT:
468
    default:
469
    fail:
470
        ret = USB_RET_STALL;
471
        break;
472
    }
473
    return ret;
474
}
475

    
476
static int usb_hub_broadcast_packet(USBHubState *s, int pid, 
477
                                    uint8_t devaddr, uint8_t devep,
478
                                    uint8_t *data, int len)
479
{
480
    USBHubPort *port;
481
    USBDevice *dev;
482
    int i, ret;
483

    
484
    for(i = 0; i < s->nb_ports; i++) {
485
        port = &s->ports[i];
486
        dev = port->port.dev;
487
        if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
488
            ret = dev->handle_packet(dev, pid, 
489
                                     devaddr, devep,
490
                                     data, len);
491
            if (ret != USB_RET_NODEV) {
492
                return ret;
493
            }
494
        }
495
    }
496
    return USB_RET_NODEV;
497
}
498

    
499
static int usb_hub_handle_packet(USBDevice *dev, int pid, 
500
                                 uint8_t devaddr, uint8_t devep,
501
                                 uint8_t *data, int len)
502
{
503
    USBHubState *s = (USBHubState *)dev;
504

    
505
#if defined(DEBUG) && 0
506
    printf("usb_hub: pid=0x%x\n", pid);
507
#endif
508
    if (dev->state == USB_STATE_DEFAULT &&
509
        dev->addr != 0 &&
510
        devaddr != dev->addr &&
511
        (pid == USB_TOKEN_SETUP || 
512
         pid == USB_TOKEN_OUT || 
513
         pid == USB_TOKEN_IN)) {
514
        /* broadcast the packet to the devices */
515
        return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len);
516
    }
517
    return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len);
518
}
519

    
520
USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports)
521
{
522
    USBHubState *s;
523
    USBHubPort *port;
524
    int i;
525

    
526
    if (nb_ports > MAX_PORTS)
527
        return NULL;
528
    s = qemu_mallocz(sizeof(USBHubState));
529
    if (!s)
530
        return NULL;
531
    s->dev.speed = USB_SPEED_FULL;
532
    s->dev.handle_packet = usb_hub_handle_packet;
533

    
534
    /* generic USB device init */
535
    s->dev.handle_reset = usb_hub_handle_reset;
536
    s->dev.handle_control = usb_hub_handle_control;
537
    s->dev.handle_data = usb_hub_handle_data;
538

    
539
    s->nb_ports = nb_ports;
540
    for(i = 0; i < s->nb_ports; i++) {
541
        port = &s->ports[i];
542
        port->wPortStatus = PORT_STAT_POWER;
543
        port->wPortChange = 0;
544
        port->port.attach = usb_hub_attach;
545
        port->port.opaque = s;
546
        port->port.index = i;
547
        usb_ports[i] = &port->port;
548
    }
549
    return (USBDevice *)s;
550
}