Statistics
| Branch: | Revision:

root / hw / usb-hub.c @ 5fafdf24

History | View | Annotate | Download (16.2 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
        /* send the attach message */
183
        usb_send_msg(dev, USB_MSG_ATTACH);
184
    } else {
185
        dev = port->port.dev;
186
        if (dev) {
187
            port->wPortStatus &= ~PORT_STAT_CONNECTION;
188
            port->wPortChange |= PORT_STAT_C_CONNECTION;
189
            if (port->wPortStatus & PORT_STAT_ENABLE) {
190
                port->wPortStatus &= ~PORT_STAT_ENABLE;
191
                port->wPortChange |= PORT_STAT_C_ENABLE;
192
            }
193
            /* send the detach message */
194
            usb_send_msg(dev, USB_MSG_DETACH);
195
            port->port.dev = NULL;
196
        }
197
    }
198
}
199

    
200
static void usb_hub_handle_reset(USBDevice *dev)
201
{
202
    /* XXX: do it */
203
}
204

    
205
static int usb_hub_handle_control(USBDevice *dev, int request, int value,
206
                                  int index, int length, uint8_t *data)
207
{
208
    USBHubState *s = (USBHubState *)dev;
209
    int ret;
210

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

    
255
            /* status change endpoint size based on number
256
             * of ports */
257
            data[22] = (s->nb_ports + 1 + 7) / 8;
258

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

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

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

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

    
434
static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
435
{
436
    USBHubState *s = (USBHubState *)dev;
437
    int ret;
438

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

    
478
static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
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, p);
489
            if (ret != USB_RET_NODEV) {
490
                return ret;
491
            }
492
        }
493
    }
494
    return USB_RET_NODEV;
495
}
496

    
497
static int usb_hub_handle_packet(USBDevice *dev, USBPacket *p)
498
{
499
    USBHubState *s = (USBHubState *)dev;
500

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

    
516
static void usb_hub_handle_destroy(USBDevice *dev)
517
{
518
    USBHubState *s = (USBHubState *)dev;
519

    
520
    qemu_free(s);
521
}
522

    
523
USBDevice *usb_hub_init(int nb_ports)
524
{
525
    USBHubState *s;
526
    USBHubPort *port;
527
    int i;
528

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

    
537
    /* generic USB device init */
538
    s->dev.handle_reset = usb_hub_handle_reset;
539
    s->dev.handle_control = usb_hub_handle_control;
540
    s->dev.handle_data = usb_hub_handle_data;
541
    s->dev.handle_destroy = usb_hub_handle_destroy;
542

    
543
    pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Hub");
544

    
545
    s->nb_ports = nb_ports;
546
    for(i = 0; i < s->nb_ports; i++) {
547
        port = &s->ports[i];
548
        qemu_register_usb_port(&port->port, s, i, usb_hub_attach);
549
        port->wPortStatus = PORT_STAT_POWER;
550
        port->wPortChange = 0;
551
    }
552
    return (USBDevice *)s;
553
}