Statistics
| Branch: | Revision:

root / hw / usb-hub.c @ 556cd098

History | View | Annotate | Download (16.5 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 "qemu-common.h"
25
#include "usb.h"
26

    
27
//#define DEBUG
28

    
29
#define MAX_PORTS 8
30

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

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

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

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

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

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

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

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

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

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

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

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

    
109
        /* one configuration */
110
        0x09,       /*  u8  bLength; */
111
        0x02,       /*  u8  bDescriptorType; Configuration */
112
        0x19, 0x00, /*  u16 wTotalLength; */
113
        0x01,       /*  u8  bNumInterfaces; (1) */
114
        0x01,       /*  u8  bConfigurationValue; */
115
        0x00,       /*  u8  iConfiguration; */
116
        0xc0,       /*  u8  bmAttributes;
117
                                 Bit 7: must be set,
118
                                     6: Self-powered,
119
                                     5: Remote wakeup,
120
                                     4..0: resvd */
121
        0x00,       /*  u8  MaxPower; */
122

    
123
        /* USB 1.1:
124
         * USB 2.0, single TT organization (mandatory):
125
         *        one interface, protocol 0
126
         *
127
         * USB 2.0, multiple TT organization (optional):
128
         *        two interfaces, protocols 1 (like single TT)
129
         *        and 2 (multiple TT mode) ... config is
130
         *        sometimes settable
131
         *        NOT IMPLEMENTED
132
         */
133

    
134
        /* one interface */
135
        0x09,       /*  u8  if_bLength; */
136
        0x04,       /*  u8  if_bDescriptorType; Interface */
137
        0x00,       /*  u8  if_bInterfaceNumber; */
138
        0x00,       /*  u8  if_bAlternateSetting; */
139
        0x01,       /*  u8  if_bNumEndpoints; */
140
        0x09,       /*  u8  if_bInterfaceClass; HUB_CLASSCODE */
141
        0x00,       /*  u8  if_bInterfaceSubClass; */
142
        0x00,       /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
143
        0x00,       /*  u8  if_iInterface; */
144

    
145
        /* one endpoint (status change endpoint) */
146
        0x07,       /*  u8  ep_bLength; */
147
        0x05,       /*  u8  ep_bDescriptorType; Endpoint */
148
        0x81,       /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
149
         0x03,       /*  u8  ep_bmAttributes; Interrupt */
150
         0x02, 0x00, /*  u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
151
        0xff        /*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
152
};
153

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

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

    
167
static void usb_hub_attach(USBPort *port1, USBDevice *dev)
168
{
169
    USBHubState *s = port1->opaque;
170
    USBHubPort *port = &s->ports[port1->index];
171

    
172
    if (dev) {
173
        if (port->port.dev)
174
            usb_attach(port1, NULL);
175

    
176
        port->wPortStatus |= PORT_STAT_CONNECTION;
177
        port->wPortChange |= PORT_STAT_C_CONNECTION;
178
        if (dev->speed == USB_SPEED_LOW)
179
            port->wPortStatus |= PORT_STAT_LOW_SPEED;
180
        else
181
            port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
182
        port->port.dev = dev;
183
        /* send the attach message */
184
        usb_send_msg(dev, USB_MSG_ATTACH);
185
    } else {
186
        dev = port->port.dev;
187
        if (dev) {
188
            port->wPortStatus &= ~PORT_STAT_CONNECTION;
189
            port->wPortChange |= PORT_STAT_C_CONNECTION;
190
            if (port->wPortStatus & PORT_STAT_ENABLE) {
191
                port->wPortStatus &= ~PORT_STAT_ENABLE;
192
                port->wPortChange |= PORT_STAT_C_ENABLE;
193
            }
194
            /* send the detach message */
195
            usb_send_msg(dev, USB_MSG_DETACH);
196
            port->port.dev = NULL;
197
        }
198
    }
199
}
200

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

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

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

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

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

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

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

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

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

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

    
479
static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
480
{
481
    USBHubPort *port;
482
    USBDevice *dev;
483
    int i, ret;
484

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

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

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

    
517
static void usb_hub_handle_destroy(USBDevice *dev)
518
{
519
    USBHubState *s = (USBHubState *)dev;
520
    int i;
521

    
522
    for (i = 0; i < s->nb_ports; i++) {
523
        usb_unregister_port(usb_bus_from_device(dev),
524
                            &s->ports[i].port);
525
    }
526
}
527

    
528
static int usb_hub_initfn(USBDevice *dev)
529
{
530
    USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
531
    USBHubPort *port;
532
    int i;
533

    
534
    s->dev.speed  = USB_SPEED_FULL,
535
    s->nb_ports = MAX_PORTS; /* FIXME: make configurable */
536
    for (i = 0; i < s->nb_ports; i++) {
537
        port = &s->ports[i];
538
        usb_register_port(usb_bus_from_device(dev),
539
                          &port->port, s, i, usb_hub_attach);
540
        port->wPortStatus = PORT_STAT_POWER;
541
        port->wPortChange = 0;
542
    }
543
    return 0;
544
}
545

    
546
static struct USBDeviceInfo hub_info = {
547
    .product_desc   = "QEMU USB Hub",
548
    .qdev.name      = "usb-hub",
549
    .qdev.size      = sizeof(USBHubState),
550
    .init           = usb_hub_initfn,
551
    .handle_packet  = usb_hub_handle_packet,
552
    .handle_reset   = usb_hub_handle_reset,
553
    .handle_control = usb_hub_handle_control,
554
    .handle_data    = usb_hub_handle_data,
555
    .handle_destroy = usb_hub_handle_destroy,
556
};
557

    
558
static void usb_hub_register_devices(void)
559
{
560
    usb_qdev_register(&hub_info);
561
}
562
device_init(usb_hub_register_devices)