qemu

Форк
0
/
dev-hub.c 
704 строки · 20.6 Кб
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

25
#include "qemu/osdep.h"
26
#include "qapi/error.h"
27
#include "qemu/timer.h"
28
#include "trace.h"
29
#include "hw/qdev-properties.h"
30
#include "hw/usb.h"
31
#include "migration/vmstate.h"
32
#include "desc.h"
33
#include "qemu/error-report.h"
34
#include "qemu/module.h"
35
#include "qom/object.h"
36

37
#define MAX_PORTS 8
38

39
typedef struct USBHubPort {
40
    USBPort port;
41
    uint16_t wPortStatus;
42
    uint16_t wPortChange;
43
} USBHubPort;
44

45
struct USBHubState {
46
    USBDevice dev;
47
    USBEndpoint *intr;
48
    uint32_t num_ports;
49
    bool port_power;
50
    QEMUTimer *port_timer;
51
    USBHubPort ports[MAX_PORTS];
52
};
53

54
#define TYPE_USB_HUB "usb-hub"
55
OBJECT_DECLARE_SIMPLE_TYPE(USBHubState, USB_HUB)
56

57
#define ClearHubFeature         (0x2000 | USB_REQ_CLEAR_FEATURE)
58
#define ClearPortFeature        (0x2300 | USB_REQ_CLEAR_FEATURE)
59
#define GetHubDescriptor        (0xa000 | USB_REQ_GET_DESCRIPTOR)
60
#define GetHubStatus            (0xa000 | USB_REQ_GET_STATUS)
61
#define GetPortStatus           (0xa300 | USB_REQ_GET_STATUS)
62
#define SetHubFeature           (0x2000 | USB_REQ_SET_FEATURE)
63
#define SetPortFeature          (0x2300 | USB_REQ_SET_FEATURE)
64

65
#define PORT_STAT_CONNECTION    0x0001
66
#define PORT_STAT_ENABLE        0x0002
67
#define PORT_STAT_SUSPEND       0x0004
68
#define PORT_STAT_OVERCURRENT   0x0008
69
#define PORT_STAT_RESET         0x0010
70
#define PORT_STAT_POWER         0x0100
71
#define PORT_STAT_LOW_SPEED     0x0200
72
#define PORT_STAT_HIGH_SPEED    0x0400
73
#define PORT_STAT_TEST          0x0800
74
#define PORT_STAT_INDICATOR     0x1000
75

76
#define PORT_STAT_C_CONNECTION  0x0001
77
#define PORT_STAT_C_ENABLE      0x0002
78
#define PORT_STAT_C_SUSPEND     0x0004
79
#define PORT_STAT_C_OVERCURRENT 0x0008
80
#define PORT_STAT_C_RESET       0x0010
81

82
#define PORT_CONNECTION         0
83
#define PORT_ENABLE             1
84
#define PORT_SUSPEND            2
85
#define PORT_OVERCURRENT        3
86
#define PORT_RESET              4
87
#define PORT_POWER              8
88
#define PORT_LOWSPEED           9
89
#define PORT_HIGHSPEED          10
90
#define PORT_C_CONNECTION       16
91
#define PORT_C_ENABLE           17
92
#define PORT_C_SUSPEND          18
93
#define PORT_C_OVERCURRENT      19
94
#define PORT_C_RESET            20
95
#define PORT_TEST               21
96
#define PORT_INDICATOR          22
97

98
/* same as Linux kernel root hubs */
99

100
enum {
101
    STR_MANUFACTURER = 1,
102
    STR_PRODUCT,
103
    STR_SERIALNUMBER,
104
};
105

106
static const USBDescStrings desc_strings = {
107
    [STR_MANUFACTURER] = "QEMU",
108
    [STR_PRODUCT]      = "QEMU USB Hub",
109
    [STR_SERIALNUMBER] = "314159",
110
};
111

112
static const USBDescIface desc_iface_hub = {
113
    .bInterfaceNumber              = 0,
114
    .bNumEndpoints                 = 1,
115
    .bInterfaceClass               = USB_CLASS_HUB,
116
    .eps = (USBDescEndpoint[]) {
117
        {
118
            .bEndpointAddress      = USB_DIR_IN | 0x01,
119
            .bmAttributes          = USB_ENDPOINT_XFER_INT,
120
            .wMaxPacketSize        = 1 + DIV_ROUND_UP(MAX_PORTS, 8),
121
            .bInterval             = 0xff,
122
        },
123
    }
124
};
125

126
static const USBDescDevice desc_device_hub = {
127
    .bcdUSB                        = 0x0110,
128
    .bDeviceClass                  = USB_CLASS_HUB,
129
    .bMaxPacketSize0               = 8,
130
    .bNumConfigurations            = 1,
131
    .confs = (USBDescConfig[]) {
132
        {
133
            .bNumInterfaces        = 1,
134
            .bConfigurationValue   = 1,
135
            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER |
136
                                     USB_CFG_ATT_WAKEUP,
137
            .nif = 1,
138
            .ifs = &desc_iface_hub,
139
        },
140
    },
141
};
142

143
static const USBDesc desc_hub = {
144
    .id = {
145
        .idVendor          = 0x0409,
146
        .idProduct         = 0x55aa,
147
        .bcdDevice         = 0x0101,
148
        .iManufacturer     = STR_MANUFACTURER,
149
        .iProduct          = STR_PRODUCT,
150
        .iSerialNumber     = STR_SERIALNUMBER,
151
    },
152
    .full = &desc_device_hub,
153
    .str  = desc_strings,
154
};
155

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

166
        /* DeviceRemovable and PortPwrCtrlMask patched in later */
167
};
168

169
static bool usb_hub_port_change(USBHubPort *port, uint16_t status)
170
{
171
    bool notify = false;
172

173
    if (status & 0x1f) {
174
        port->wPortChange |= status;
175
        notify = true;
176
    }
177
    return notify;
178
}
179

180
static bool usb_hub_port_set(USBHubPort *port, uint16_t status)
181
{
182
    if (port->wPortStatus & status) {
183
        return false;
184
    }
185
    port->wPortStatus |= status;
186
    return usb_hub_port_change(port, status);
187
}
188

189
static bool usb_hub_port_clear(USBHubPort *port, uint16_t status)
190
{
191
    if (!(port->wPortStatus & status)) {
192
        return false;
193
    }
194
    port->wPortStatus &= ~status;
195
    return usb_hub_port_change(port, status);
196
}
197

198
static bool usb_hub_port_update(USBHubPort *port)
199
{
200
    bool notify = false;
201

202
    if (port->port.dev && port->port.dev->attached) {
203
        notify = usb_hub_port_set(port, PORT_STAT_CONNECTION);
204
        if (port->port.dev->speed == USB_SPEED_LOW) {
205
            usb_hub_port_set(port, PORT_STAT_LOW_SPEED);
206
        } else {
207
            usb_hub_port_clear(port, PORT_STAT_LOW_SPEED);
208
        }
209
    }
210
    return notify;
211
}
212

213
static void usb_hub_port_update_timer(void *opaque)
214
{
215
    USBHubState *s = opaque;
216
    bool notify = false;
217
    int i;
218

219
    for (i = 0; i < s->num_ports; i++) {
220
        notify |= usb_hub_port_update(&s->ports[i]);
221
    }
222
    if (notify) {
223
        usb_wakeup(s->intr, 0);
224
    }
225
}
226

227
static void usb_hub_attach(USBPort *port1)
228
{
229
    USBHubState *s = port1->opaque;
230
    USBHubPort *port = &s->ports[port1->index];
231

232
    trace_usb_hub_attach(s->dev.addr, port1->index + 1);
233
    usb_hub_port_update(port);
234
    usb_wakeup(s->intr, 0);
235
}
236

237
static void usb_hub_detach(USBPort *port1)
238
{
239
    USBHubState *s = port1->opaque;
240
    USBHubPort *port = &s->ports[port1->index];
241

242
    trace_usb_hub_detach(s->dev.addr, port1->index + 1);
243
    usb_wakeup(s->intr, 0);
244

245
    /* Let upstream know the device on this port is gone */
246
    s->dev.port->ops->child_detach(s->dev.port, port1->dev);
247

248
    usb_hub_port_clear(port, PORT_STAT_CONNECTION);
249
    usb_hub_port_clear(port, PORT_STAT_ENABLE);
250
    usb_hub_port_clear(port, PORT_STAT_SUSPEND);
251
    usb_wakeup(s->intr, 0);
252
}
253

254
static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
255
{
256
    USBHubState *s = port1->opaque;
257

258
    /* Pass along upstream */
259
    s->dev.port->ops->child_detach(s->dev.port, child);
260
}
261

262
static void usb_hub_wakeup(USBPort *port1)
263
{
264
    USBHubState *s = port1->opaque;
265
    USBHubPort *port = &s->ports[port1->index];
266

267
    if (usb_hub_port_clear(port, PORT_STAT_SUSPEND)) {
268
        usb_wakeup(s->intr, 0);
269
    }
270
}
271

272
static void usb_hub_complete(USBPort *port, USBPacket *packet)
273
{
274
    USBHubState *s = port->opaque;
275

276
    /*
277
     * Just pass it along upstream for now.
278
     *
279
     * If we ever implement usb 2.0 split transactions this will
280
     * become a little more complicated ...
281
     *
282
     * Can't use usb_packet_complete() here because packet->owner is
283
     * cleared already, go call the ->complete() callback directly
284
     * instead.
285
     */
286
    s->dev.port->ops->complete(s->dev.port, packet);
287
}
288

289
static USBDevice *usb_hub_find_device(USBDevice *dev, uint8_t addr)
290
{
291
    USBHubState *s = USB_HUB(dev);
292
    USBHubPort *port;
293
    USBDevice *downstream;
294
    int i;
295

296
    for (i = 0; i < s->num_ports; i++) {
297
        port = &s->ports[i];
298
        if (!(port->wPortStatus & PORT_STAT_ENABLE)) {
299
            continue;
300
        }
301
        downstream = usb_find_device(&port->port, addr);
302
        if (downstream != NULL) {
303
            return downstream;
304
        }
305
    }
306
    return NULL;
307
}
308

309
static void usb_hub_handle_reset(USBDevice *dev)
310
{
311
    USBHubState *s = USB_HUB(dev);
312
    USBHubPort *port;
313
    int i;
314

315
    trace_usb_hub_reset(s->dev.addr);
316
    for (i = 0; i < s->num_ports; i++) {
317
        port = s->ports + i;
318
        port->wPortStatus = 0;
319
        port->wPortChange = 0;
320
        usb_hub_port_set(port, PORT_STAT_POWER);
321
        usb_hub_port_update(port);
322
    }
323
}
324

325
static const char *feature_name(int feature)
326
{
327
    static const char *name[] = {
328
        [PORT_CONNECTION]    = "connection",
329
        [PORT_ENABLE]        = "enable",
330
        [PORT_SUSPEND]       = "suspend",
331
        [PORT_OVERCURRENT]   = "overcurrent",
332
        [PORT_RESET]         = "reset",
333
        [PORT_POWER]         = "power",
334
        [PORT_LOWSPEED]      = "lowspeed",
335
        [PORT_HIGHSPEED]     = "highspeed",
336
        [PORT_C_CONNECTION]  = "change-connection",
337
        [PORT_C_ENABLE]      = "change-enable",
338
        [PORT_C_SUSPEND]     = "change-suspend",
339
        [PORT_C_OVERCURRENT] = "change-overcurrent",
340
        [PORT_C_RESET]       = "change-reset",
341
        [PORT_TEST]          = "test",
342
        [PORT_INDICATOR]     = "indicator",
343
    };
344
    if (feature < 0 || feature >= ARRAY_SIZE(name)) {
345
        return "?";
346
    }
347
    return name[feature] ?: "?";
348
}
349

350
static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
351
               int request, int value, int index, int length, uint8_t *data)
352
{
353
    USBHubState *s = (USBHubState *)dev;
354
    int ret;
355

356
    trace_usb_hub_control(s->dev.addr, request, value, index, length);
357

358
    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
359
    if (ret >= 0) {
360
        return;
361
    }
362

363
    switch(request) {
364
    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
365
        if (value == 0 && index != 0x81) { /* clear ep halt */
366
            goto fail;
367
        }
368
        break;
369
        /* usb specific requests */
370
    case GetHubStatus:
371
        data[0] = 0;
372
        data[1] = 0;
373
        data[2] = 0;
374
        data[3] = 0;
375
        p->actual_length = 4;
376
        break;
377
    case GetPortStatus:
378
        {
379
            unsigned int n = index - 1;
380
            USBHubPort *port;
381
            if (n >= s->num_ports) {
382
                goto fail;
383
            }
384
            port = &s->ports[n];
385
            trace_usb_hub_get_port_status(s->dev.addr, index,
386
                                          port->wPortStatus,
387
                                          port->wPortChange);
388
            data[0] = port->wPortStatus;
389
            data[1] = port->wPortStatus >> 8;
390
            data[2] = port->wPortChange;
391
            data[3] = port->wPortChange >> 8;
392
            p->actual_length = 4;
393
        }
394
        break;
395
    case SetHubFeature:
396
    case ClearHubFeature:
397
        if (value != 0 && value != 1) {
398
            goto fail;
399
        }
400
        break;
401
    case SetPortFeature:
402
        {
403
            unsigned int n = index - 1;
404
            USBHubPort *port;
405
            USBDevice *pdev;
406

407
            trace_usb_hub_set_port_feature(s->dev.addr, index,
408
                                           feature_name(value));
409

410
            if (n >= s->num_ports) {
411
                goto fail;
412
            }
413
            port = &s->ports[n];
414
            pdev = port->port.dev;
415
            switch(value) {
416
            case PORT_SUSPEND:
417
                port->wPortStatus |= PORT_STAT_SUSPEND;
418
                break;
419
            case PORT_RESET:
420
                usb_hub_port_set(port, PORT_STAT_RESET);
421
                usb_hub_port_clear(port, PORT_STAT_RESET);
422
                if (pdev && pdev->attached) {
423
                    usb_device_reset(pdev);
424
                    usb_hub_port_set(port, PORT_STAT_ENABLE);
425
                }
426
                usb_wakeup(s->intr, 0);
427
                break;
428
            case PORT_POWER:
429
                if (s->port_power) {
430
                    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
431
                    usb_hub_port_set(port, PORT_STAT_POWER);
432
                    timer_mod(s->port_timer, now + 5000000); /* 5 ms */
433
                }
434
                break;
435
            default:
436
                goto fail;
437
            }
438
        }
439
        break;
440
    case ClearPortFeature:
441
        {
442
            unsigned int n = index - 1;
443
            USBHubPort *port;
444

445
            trace_usb_hub_clear_port_feature(s->dev.addr, index,
446
                                             feature_name(value));
447

448
            if (n >= s->num_ports) {
449
                goto fail;
450
            }
451
            port = &s->ports[n];
452
            switch(value) {
453
            case PORT_ENABLE:
454
                port->wPortStatus &= ~PORT_STAT_ENABLE;
455
                break;
456
            case PORT_C_ENABLE:
457
                port->wPortChange &= ~PORT_STAT_C_ENABLE;
458
                break;
459
            case PORT_SUSPEND:
460
                usb_hub_port_clear(port, PORT_STAT_SUSPEND);
461
                break;
462
            case PORT_C_SUSPEND:
463
                port->wPortChange &= ~PORT_STAT_C_SUSPEND;
464
                break;
465
            case PORT_C_CONNECTION:
466
                port->wPortChange &= ~PORT_STAT_C_CONNECTION;
467
                break;
468
            case PORT_C_OVERCURRENT:
469
                port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
470
                break;
471
            case PORT_C_RESET:
472
                port->wPortChange &= ~PORT_STAT_C_RESET;
473
                break;
474
            case PORT_POWER:
475
                if (s->port_power) {
476
                    usb_hub_port_clear(port, PORT_STAT_POWER);
477
                    usb_hub_port_clear(port, PORT_STAT_CONNECTION);
478
                    usb_hub_port_clear(port, PORT_STAT_ENABLE);
479
                    usb_hub_port_clear(port, PORT_STAT_SUSPEND);
480
                    port->wPortChange = 0;
481
                }
482
            default:
483
                goto fail;
484
            }
485
        }
486
        break;
487
    case GetHubDescriptor:
488
        {
489
            unsigned int n, limit, var_hub_size = 0;
490
            memcpy(data, qemu_hub_hub_descriptor,
491
                   sizeof(qemu_hub_hub_descriptor));
492
            data[2] = s->num_ports;
493

494
            if (s->port_power) {
495
                data[3] &= ~0x03;
496
                data[3] |= 0x01;
497
            }
498

499
            /* fill DeviceRemovable bits */
500
            limit = DIV_ROUND_UP(s->num_ports + 1, 8) + 7;
501
            for (n = 7; n < limit; n++) {
502
                data[n] = 0x00;
503
                var_hub_size++;
504
            }
505

506
            /* fill PortPwrCtrlMask bits */
507
            limit = limit + DIV_ROUND_UP(s->num_ports, 8);
508
            for (;n < limit; n++) {
509
                data[n] = 0xff;
510
                var_hub_size++;
511
            }
512

513
            p->actual_length = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
514
            data[0] = p->actual_length;
515
            break;
516
        }
517
    default:
518
    fail:
519
        p->status = USB_RET_STALL;
520
        break;
521
    }
522
}
523

524
static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
525
{
526
    USBHubState *s = (USBHubState *)dev;
527

528
    switch(p->pid) {
529
    case USB_TOKEN_IN:
530
        if (p->ep->nr == 1) {
531
            USBHubPort *port;
532
            unsigned int status;
533
            uint8_t buf[4];
534
            int i, n;
535
            n = DIV_ROUND_UP(s->num_ports + 1, 8);
536
            if (p->iov.size == 1) { /* FreeBSD workaround */
537
                n = 1;
538
            } else if (n > p->iov.size) {
539
                p->status = USB_RET_BABBLE;
540
                return;
541
            }
542
            status = 0;
543
            for (i = 0; i < s->num_ports; i++) {
544
                port = &s->ports[i];
545
                if (port->wPortChange)
546
                    status |= (1 << (i + 1));
547
            }
548
            if (status != 0) {
549
                trace_usb_hub_status_report(s->dev.addr, status);
550
                for(i = 0; i < n; i++) {
551
                    buf[i] = status >> (8 * i);
552
                }
553
                usb_packet_copy(p, buf, n);
554
            } else {
555
                p->status = USB_RET_NAK; /* usb11 11.13.1 */
556
            }
557
        } else {
558
            goto fail;
559
        }
560
        break;
561
    case USB_TOKEN_OUT:
562
    default:
563
    fail:
564
        p->status = USB_RET_STALL;
565
        break;
566
    }
567
}
568

569
static void usb_hub_unrealize(USBDevice *dev)
570
{
571
    USBHubState *s = (USBHubState *)dev;
572
    int i;
573

574
    for (i = 0; i < s->num_ports; i++) {
575
        usb_unregister_port(usb_bus_from_device(dev),
576
                            &s->ports[i].port);
577
    }
578

579
    timer_free(s->port_timer);
580
}
581

582
static USBPortOps usb_hub_port_ops = {
583
    .attach = usb_hub_attach,
584
    .detach = usb_hub_detach,
585
    .child_detach = usb_hub_child_detach,
586
    .wakeup = usb_hub_wakeup,
587
    .complete = usb_hub_complete,
588
};
589

590
static void usb_hub_realize(USBDevice *dev, Error **errp)
591
{
592
    USBHubState *s = USB_HUB(dev);
593
    USBHubPort *port;
594
    int i;
595

596
    if (s->num_ports < 1 || s->num_ports > MAX_PORTS) {
597
        error_setg(errp, "num_ports (%d) out of range (1..%d)",
598
                   s->num_ports, MAX_PORTS);
599
        return;
600
    }
601

602
    if (dev->port->hubcount == 5) {
603
        error_setg(errp, "usb hub chain too deep");
604
        return;
605
    }
606

607
    usb_desc_create_serial(dev);
608
    usb_desc_init(dev);
609
    s->port_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
610
                                 usb_hub_port_update_timer, s);
611
    s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
612
    for (i = 0; i < s->num_ports; i++) {
613
        port = &s->ports[i];
614
        usb_register_port(usb_bus_from_device(dev),
615
                          &port->port, s, i, &usb_hub_port_ops,
616
                          USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
617
        usb_port_location(&port->port, dev->port, i+1);
618
    }
619
    usb_hub_handle_reset(dev);
620
}
621

622
static const VMStateDescription vmstate_usb_hub_port = {
623
    .name = "usb-hub-port",
624
    .version_id = 1,
625
    .minimum_version_id = 1,
626
    .fields = (const VMStateField[]) {
627
        VMSTATE_UINT16(wPortStatus, USBHubPort),
628
        VMSTATE_UINT16(wPortChange, USBHubPort),
629
        VMSTATE_END_OF_LIST()
630
    }
631
};
632

633
static bool usb_hub_port_timer_needed(void *opaque)
634
{
635
    USBHubState *s = opaque;
636

637
    return s->port_power;
638
}
639

640
static const VMStateDescription vmstate_usb_hub_port_timer = {
641
    .name = "usb-hub/port-timer",
642
    .version_id = 1,
643
    .minimum_version_id = 1,
644
    .needed = usb_hub_port_timer_needed,
645
    .fields = (const VMStateField[]) {
646
        VMSTATE_TIMER_PTR(port_timer, USBHubState),
647
        VMSTATE_END_OF_LIST()
648
    },
649
};
650

651
static const VMStateDescription vmstate_usb_hub = {
652
    .name = "usb-hub",
653
    .version_id = 1,
654
    .minimum_version_id = 1,
655
    .fields = (const VMStateField[]) {
656
        VMSTATE_USB_DEVICE(dev, USBHubState),
657
        VMSTATE_STRUCT_ARRAY(ports, USBHubState, MAX_PORTS, 0,
658
                             vmstate_usb_hub_port, USBHubPort),
659
        VMSTATE_END_OF_LIST()
660
    },
661
    .subsections = (const VMStateDescription * const []) {
662
        &vmstate_usb_hub_port_timer,
663
        NULL
664
    }
665
};
666

667
static Property usb_hub_properties[] = {
668
    DEFINE_PROP_UINT32("ports", USBHubState, num_ports, 8),
669
    DEFINE_PROP_BOOL("port-power", USBHubState, port_power, false),
670
    DEFINE_PROP_END_OF_LIST(),
671
};
672

673
static void usb_hub_class_initfn(ObjectClass *klass, void *data)
674
{
675
    DeviceClass *dc = DEVICE_CLASS(klass);
676
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
677

678
    uc->realize        = usb_hub_realize;
679
    uc->product_desc   = "QEMU USB Hub";
680
    uc->usb_desc       = &desc_hub;
681
    uc->find_device    = usb_hub_find_device;
682
    uc->handle_reset   = usb_hub_handle_reset;
683
    uc->handle_control = usb_hub_handle_control;
684
    uc->handle_data    = usb_hub_handle_data;
685
    uc->unrealize      = usb_hub_unrealize;
686
    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
687
    dc->fw_name = "hub";
688
    dc->vmsd = &vmstate_usb_hub;
689
    device_class_set_props(dc, usb_hub_properties);
690
}
691

692
static const TypeInfo hub_info = {
693
    .name          = TYPE_USB_HUB,
694
    .parent        = TYPE_USB_DEVICE,
695
    .instance_size = sizeof(USBHubState),
696
    .class_init    = usb_hub_class_initfn,
697
};
698

699
static void usb_hub_register_types(void)
700
{
701
    type_register_static(&hub_info);
702
}
703

704
type_init(usb_hub_register_types)
705

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.