~ubuntu-branches/ubuntu/edgy/qemu/edgy

« back to all changes in this revision

Viewing changes to hw/usb-hub.c

  • Committer: Bazaar Package Importer
  • Author(s): Rodrigo Parra Novo
  • Date: 2006-08-04 22:50:15 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20060804225015-g0tvbozshau6e1oo
Tags: 0.8.2-0ubuntu1
* Merged with Debian unstable
* New Upstream release
* Dropped debian/patches/12_signal_powerpc_support.patch (broken for qemu
  0.8.2)
* Redid debian/patches/21_net_sockopt.patch
* Redid debian/patches/35_syscall_sockaddr.patch
* Redid debian/patches/42_arm_tls.patch
* Dropped debian/patches/50_missing_keycodes.patch (applied upstream)
* Redid debian/patches/61_safe_64bit_int.patch
* Dropped debian/patches/63_sparc_build.patch (applied upstream)
* Added new patch 65_no-linux_types_h.patch (unnecessary kernel header
  breaking compilation of linux-user/syscall.c)
* Added new patch 66_no-linux_compiler_h.patch (unnecessary kernel header
  breaking compilation of linux-usb.c)

Show diffs side-by-side

added added

removed removed

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