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 typedef struct USBHubState USBHubState; 54 55 #define TYPE_USB_HUB "usb-hub" 56 DECLARE_INSTANCE_CHECKER(USBHubState, USB_HUB, 57 TYPE_USB_HUB) 58 59 #define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) 60 #define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) 61 #define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) 62 #define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) 63 #define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) 64 #define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) 65 #define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) 66 67 #define PORT_STAT_CONNECTION 0x0001 68 #define PORT_STAT_ENABLE 0x0002 69 #define PORT_STAT_SUSPEND 0x0004 70 #define PORT_STAT_OVERCURRENT 0x0008 71 #define PORT_STAT_RESET 0x0010 72 #define PORT_STAT_POWER 0x0100 73 #define PORT_STAT_LOW_SPEED 0x0200 74 #define PORT_STAT_HIGH_SPEED 0x0400 75 #define PORT_STAT_TEST 0x0800 76 #define PORT_STAT_INDICATOR 0x1000 77 78 #define PORT_STAT_C_CONNECTION 0x0001 79 #define PORT_STAT_C_ENABLE 0x0002 80 #define PORT_STAT_C_SUSPEND 0x0004 81 #define PORT_STAT_C_OVERCURRENT 0x0008 82 #define PORT_STAT_C_RESET 0x0010 83 84 #define PORT_CONNECTION 0 85 #define PORT_ENABLE 1 86 #define PORT_SUSPEND 2 87 #define PORT_OVERCURRENT 3 88 #define PORT_RESET 4 89 #define PORT_POWER 8 90 #define PORT_LOWSPEED 9 91 #define PORT_HIGHSPEED 10 92 #define PORT_C_CONNECTION 16 93 #define PORT_C_ENABLE 17 94 #define PORT_C_SUSPEND 18 95 #define PORT_C_OVERCURRENT 19 96 #define PORT_C_RESET 20 97 #define PORT_TEST 21 98 #define PORT_INDICATOR 22 99 100 /* same as Linux kernel root hubs */ 101 102 enum { 103 STR_MANUFACTURER = 1, 104 STR_PRODUCT, 105 STR_SERIALNUMBER, 106 }; 107 108 static const USBDescStrings desc_strings = { 109 [STR_MANUFACTURER] = "QEMU", 110 [STR_PRODUCT] = "QEMU USB Hub", 111 [STR_SERIALNUMBER] = "314159", 112 }; 113 114 static const USBDescIface desc_iface_hub = { 115 .bInterfaceNumber = 0, 116 .bNumEndpoints = 1, 117 .bInterfaceClass = USB_CLASS_HUB, 118 .eps = (USBDescEndpoint[]) { 119 { 120 .bEndpointAddress = USB_DIR_IN | 0x01, 121 .bmAttributes = USB_ENDPOINT_XFER_INT, 122 .wMaxPacketSize = 1 + DIV_ROUND_UP(MAX_PORTS, 8), 123 .bInterval = 0xff, 124 }, 125 } 126 }; 127 128 static const USBDescDevice desc_device_hub = { 129 .bcdUSB = 0x0110, 130 .bDeviceClass = USB_CLASS_HUB, 131 .bMaxPacketSize0 = 8, 132 .bNumConfigurations = 1, 133 .confs = (USBDescConfig[]) { 134 { 135 .bNumInterfaces = 1, 136 .bConfigurationValue = 1, 137 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER | 138 USB_CFG_ATT_WAKEUP, 139 .nif = 1, 140 .ifs = &desc_iface_hub, 141 }, 142 }, 143 }; 144 145 static const USBDesc desc_hub = { 146 .id = { 147 .idVendor = 0x0409, 148 .idProduct = 0x55aa, 149 .bcdDevice = 0x0101, 150 .iManufacturer = STR_MANUFACTURER, 151 .iProduct = STR_PRODUCT, 152 .iSerialNumber = STR_SERIALNUMBER, 153 }, 154 .full = &desc_device_hub, 155 .str = desc_strings, 156 }; 157 158 static const uint8_t qemu_hub_hub_descriptor[] = 159 { 160 0x00, /* u8 bLength; patched in later */ 161 0x29, /* u8 bDescriptorType; Hub-descriptor */ 162 0x00, /* u8 bNbrPorts; (patched later) */ 163 0x0a, /* u16 wHubCharacteristics; */ 164 0x00, /* (per-port OC, no power switching) */ 165 0x01, /* u8 bPwrOn2pwrGood; 2ms */ 166 0x00 /* u8 bHubContrCurrent; 0 mA */ 167 168 /* DeviceRemovable and PortPwrCtrlMask patched in later */ 169 }; 170 171 static bool usb_hub_port_change(USBHubPort *port, uint16_t status) 172 { 173 bool notify = false; 174 175 if (status & 0x1f) { 176 port->wPortChange |= status; 177 notify = true; 178 } 179 return notify; 180 } 181 182 static bool usb_hub_port_set(USBHubPort *port, uint16_t status) 183 { 184 if (port->wPortStatus & status) { 185 return false; 186 } 187 port->wPortStatus |= status; 188 return usb_hub_port_change(port, status); 189 } 190 191 static bool usb_hub_port_clear(USBHubPort *port, uint16_t status) 192 { 193 if (!(port->wPortStatus & status)) { 194 return false; 195 } 196 port->wPortStatus &= ~status; 197 return usb_hub_port_change(port, status); 198 } 199 200 static bool usb_hub_port_update(USBHubPort *port) 201 { 202 bool notify = false; 203 204 if (port->port.dev && port->port.dev->attached) { 205 notify = usb_hub_port_set(port, PORT_STAT_CONNECTION); 206 if (port->port.dev->speed == USB_SPEED_LOW) { 207 usb_hub_port_set(port, PORT_STAT_LOW_SPEED); 208 } else { 209 usb_hub_port_clear(port, PORT_STAT_LOW_SPEED); 210 } 211 } 212 return notify; 213 } 214 215 static void usb_hub_port_update_timer(void *opaque) 216 { 217 USBHubState *s = opaque; 218 bool notify = false; 219 int i; 220 221 for (i = 0; i < s->num_ports; i++) { 222 notify |= usb_hub_port_update(&s->ports[i]); 223 } 224 if (notify) { 225 usb_wakeup(s->intr, 0); 226 } 227 } 228 229 static void usb_hub_attach(USBPort *port1) 230 { 231 USBHubState *s = port1->opaque; 232 USBHubPort *port = &s->ports[port1->index]; 233 234 trace_usb_hub_attach(s->dev.addr, port1->index + 1); 235 usb_hub_port_update(port); 236 usb_wakeup(s->intr, 0); 237 } 238 239 static void usb_hub_detach(USBPort *port1) 240 { 241 USBHubState *s = port1->opaque; 242 USBHubPort *port = &s->ports[port1->index]; 243 244 trace_usb_hub_detach(s->dev.addr, port1->index + 1); 245 usb_wakeup(s->intr, 0); 246 247 /* Let upstream know the device on this port is gone */ 248 s->dev.port->ops->child_detach(s->dev.port, port1->dev); 249 250 usb_hub_port_clear(port, PORT_STAT_CONNECTION); 251 usb_hub_port_clear(port, PORT_STAT_ENABLE); 252 usb_hub_port_clear(port, PORT_STAT_SUSPEND); 253 usb_wakeup(s->intr, 0); 254 } 255 256 static void usb_hub_child_detach(USBPort *port1, USBDevice *child) 257 { 258 USBHubState *s = port1->opaque; 259 260 /* Pass along upstream */ 261 s->dev.port->ops->child_detach(s->dev.port, child); 262 } 263 264 static void usb_hub_wakeup(USBPort *port1) 265 { 266 USBHubState *s = port1->opaque; 267 USBHubPort *port = &s->ports[port1->index]; 268 269 if (usb_hub_port_clear(port, PORT_STAT_SUSPEND)) { 270 usb_wakeup(s->intr, 0); 271 } 272 } 273 274 static void usb_hub_complete(USBPort *port, USBPacket *packet) 275 { 276 USBHubState *s = port->opaque; 277 278 /* 279 * Just pass it along upstream for now. 280 * 281 * If we ever implement usb 2.0 split transactions this will 282 * become a little more complicated ... 283 * 284 * Can't use usb_packet_complete() here because packet->owner is 285 * cleared already, go call the ->complete() callback directly 286 * instead. 287 */ 288 s->dev.port->ops->complete(s->dev.port, packet); 289 } 290 291 static USBDevice *usb_hub_find_device(USBDevice *dev, uint8_t addr) 292 { 293 USBHubState *s = USB_HUB(dev); 294 USBHubPort *port; 295 USBDevice *downstream; 296 int i; 297 298 for (i = 0; i < s->num_ports; i++) { 299 port = &s->ports[i]; 300 if (!(port->wPortStatus & PORT_STAT_ENABLE)) { 301 continue; 302 } 303 downstream = usb_find_device(&port->port, addr); 304 if (downstream != NULL) { 305 return downstream; 306 } 307 } 308 return NULL; 309 } 310 311 static void usb_hub_handle_reset(USBDevice *dev) 312 { 313 USBHubState *s = USB_HUB(dev); 314 USBHubPort *port; 315 int i; 316 317 trace_usb_hub_reset(s->dev.addr); 318 for (i = 0; i < s->num_ports; i++) { 319 port = s->ports + i; 320 port->wPortStatus = 0; 321 port->wPortChange = 0; 322 usb_hub_port_set(port, PORT_STAT_POWER); 323 usb_hub_port_update(port); 324 } 325 } 326 327 static const char *feature_name(int feature) 328 { 329 static const char *name[] = { 330 [PORT_CONNECTION] = "connection", 331 [PORT_ENABLE] = "enable", 332 [PORT_SUSPEND] = "suspend", 333 [PORT_OVERCURRENT] = "overcurrent", 334 [PORT_RESET] = "reset", 335 [PORT_POWER] = "power", 336 [PORT_LOWSPEED] = "lowspeed", 337 [PORT_HIGHSPEED] = "highspeed", 338 [PORT_C_CONNECTION] = "change-connection", 339 [PORT_C_ENABLE] = "change-enable", 340 [PORT_C_SUSPEND] = "change-suspend", 341 [PORT_C_OVERCURRENT] = "change-overcurrent", 342 [PORT_C_RESET] = "change-reset", 343 [PORT_TEST] = "test", 344 [PORT_INDICATOR] = "indicator", 345 }; 346 if (feature < 0 || feature >= ARRAY_SIZE(name)) { 347 return "?"; 348 } 349 return name[feature] ?: "?"; 350 } 351 352 static void usb_hub_handle_control(USBDevice *dev, USBPacket *p, 353 int request, int value, int index, int length, uint8_t *data) 354 { 355 USBHubState *s = (USBHubState *)dev; 356 int ret; 357 358 trace_usb_hub_control(s->dev.addr, request, value, index, length); 359 360 ret = usb_desc_handle_control(dev, p, request, value, index, length, data); 361 if (ret >= 0) { 362 return; 363 } 364 365 switch(request) { 366 case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: 367 if (value == 0 && index != 0x81) { /* clear ep halt */ 368 goto fail; 369 } 370 break; 371 /* usb specific requests */ 372 case GetHubStatus: 373 data[0] = 0; 374 data[1] = 0; 375 data[2] = 0; 376 data[3] = 0; 377 p->actual_length = 4; 378 break; 379 case GetPortStatus: 380 { 381 unsigned int n = index - 1; 382 USBHubPort *port; 383 if (n >= s->num_ports) { 384 goto fail; 385 } 386 port = &s->ports[n]; 387 trace_usb_hub_get_port_status(s->dev.addr, index, 388 port->wPortStatus, 389 port->wPortChange); 390 data[0] = port->wPortStatus; 391 data[1] = port->wPortStatus >> 8; 392 data[2] = port->wPortChange; 393 data[3] = port->wPortChange >> 8; 394 p->actual_length = 4; 395 } 396 break; 397 case SetHubFeature: 398 case ClearHubFeature: 399 if (value != 0 && value != 1) { 400 goto fail; 401 } 402 break; 403 case SetPortFeature: 404 { 405 unsigned int n = index - 1; 406 USBHubPort *port; 407 USBDevice *dev; 408 409 trace_usb_hub_set_port_feature(s->dev.addr, index, 410 feature_name(value)); 411 412 if (n >= s->num_ports) { 413 goto fail; 414 } 415 port = &s->ports[n]; 416 dev = port->port.dev; 417 switch(value) { 418 case PORT_SUSPEND: 419 port->wPortStatus |= PORT_STAT_SUSPEND; 420 break; 421 case PORT_RESET: 422 usb_hub_port_set(port, PORT_STAT_RESET); 423 usb_hub_port_clear(port, PORT_STAT_RESET); 424 if (dev && dev->attached) { 425 usb_device_reset(dev); 426 usb_hub_port_set(port, PORT_STAT_ENABLE); 427 } 428 usb_wakeup(s->intr, 0); 429 break; 430 case PORT_POWER: 431 if (s->port_power) { 432 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 433 usb_hub_port_set(port, PORT_STAT_POWER); 434 timer_mod(s->port_timer, now + 5000000); /* 5 ms */ 435 } 436 break; 437 default: 438 goto fail; 439 } 440 } 441 break; 442 case ClearPortFeature: 443 { 444 unsigned int n = index - 1; 445 USBHubPort *port; 446 447 trace_usb_hub_clear_port_feature(s->dev.addr, index, 448 feature_name(value)); 449 450 if (n >= s->num_ports) { 451 goto fail; 452 } 453 port = &s->ports[n]; 454 switch(value) { 455 case PORT_ENABLE: 456 port->wPortStatus &= ~PORT_STAT_ENABLE; 457 break; 458 case PORT_C_ENABLE: 459 port->wPortChange &= ~PORT_STAT_C_ENABLE; 460 break; 461 case PORT_SUSPEND: 462 usb_hub_port_clear(port, PORT_STAT_SUSPEND); 463 break; 464 case PORT_C_SUSPEND: 465 port->wPortChange &= ~PORT_STAT_C_SUSPEND; 466 break; 467 case PORT_C_CONNECTION: 468 port->wPortChange &= ~PORT_STAT_C_CONNECTION; 469 break; 470 case PORT_C_OVERCURRENT: 471 port->wPortChange &= ~PORT_STAT_C_OVERCURRENT; 472 break; 473 case PORT_C_RESET: 474 port->wPortChange &= ~PORT_STAT_C_RESET; 475 break; 476 case PORT_POWER: 477 if (s->port_power) { 478 usb_hub_port_clear(port, PORT_STAT_POWER); 479 usb_hub_port_clear(port, PORT_STAT_CONNECTION); 480 usb_hub_port_clear(port, PORT_STAT_ENABLE); 481 usb_hub_port_clear(port, PORT_STAT_SUSPEND); 482 port->wPortChange = 0; 483 } 484 default: 485 goto fail; 486 } 487 } 488 break; 489 case GetHubDescriptor: 490 { 491 unsigned int n, limit, var_hub_size = 0; 492 memcpy(data, qemu_hub_hub_descriptor, 493 sizeof(qemu_hub_hub_descriptor)); 494 data[2] = s->num_ports; 495 496 if (s->port_power) { 497 data[3] &= ~0x03; 498 data[3] |= 0x01; 499 } 500 501 /* fill DeviceRemovable bits */ 502 limit = DIV_ROUND_UP(s->num_ports + 1, 8) + 7; 503 for (n = 7; n < limit; n++) { 504 data[n] = 0x00; 505 var_hub_size++; 506 } 507 508 /* fill PortPwrCtrlMask bits */ 509 limit = limit + DIV_ROUND_UP(s->num_ports, 8); 510 for (;n < limit; n++) { 511 data[n] = 0xff; 512 var_hub_size++; 513 } 514 515 p->actual_length = sizeof(qemu_hub_hub_descriptor) + var_hub_size; 516 data[0] = p->actual_length; 517 break; 518 } 519 default: 520 fail: 521 p->status = USB_RET_STALL; 522 break; 523 } 524 } 525 526 static void usb_hub_handle_data(USBDevice *dev, USBPacket *p) 527 { 528 USBHubState *s = (USBHubState *)dev; 529 530 switch(p->pid) { 531 case USB_TOKEN_IN: 532 if (p->ep->nr == 1) { 533 USBHubPort *port; 534 unsigned int status; 535 uint8_t buf[4]; 536 int i, n; 537 n = DIV_ROUND_UP(s->num_ports + 1, 8); 538 if (p->iov.size == 1) { /* FreeBSD workaround */ 539 n = 1; 540 } else if (n > p->iov.size) { 541 p->status = USB_RET_BABBLE; 542 return; 543 } 544 status = 0; 545 for (i = 0; i < s->num_ports; i++) { 546 port = &s->ports[i]; 547 if (port->wPortChange) 548 status |= (1 << (i + 1)); 549 } 550 if (status != 0) { 551 trace_usb_hub_status_report(s->dev.addr, status); 552 for(i = 0; i < n; i++) { 553 buf[i] = status >> (8 * i); 554 } 555 usb_packet_copy(p, buf, n); 556 } else { 557 p->status = USB_RET_NAK; /* usb11 11.13.1 */ 558 } 559 } else { 560 goto fail; 561 } 562 break; 563 case USB_TOKEN_OUT: 564 default: 565 fail: 566 p->status = USB_RET_STALL; 567 break; 568 } 569 } 570 571 static void usb_hub_unrealize(USBDevice *dev) 572 { 573 USBHubState *s = (USBHubState *)dev; 574 int i; 575 576 for (i = 0; i < s->num_ports; i++) { 577 usb_unregister_port(usb_bus_from_device(dev), 578 &s->ports[i].port); 579 } 580 581 timer_del(s->port_timer); 582 timer_free(s->port_timer); 583 } 584 585 static USBPortOps usb_hub_port_ops = { 586 .attach = usb_hub_attach, 587 .detach = usb_hub_detach, 588 .child_detach = usb_hub_child_detach, 589 .wakeup = usb_hub_wakeup, 590 .complete = usb_hub_complete, 591 }; 592 593 static void usb_hub_realize(USBDevice *dev, Error **errp) 594 { 595 USBHubState *s = USB_HUB(dev); 596 USBHubPort *port; 597 int i; 598 599 if (s->num_ports < 1 || s->num_ports > MAX_PORTS) { 600 error_setg(errp, "num_ports (%d) out of range (1..%d)", 601 s->num_ports, MAX_PORTS); 602 return; 603 } 604 605 if (dev->port->hubcount == 5) { 606 error_setg(errp, "usb hub chain too deep"); 607 return; 608 } 609 610 usb_desc_create_serial(dev); 611 usb_desc_init(dev); 612 s->port_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 613 usb_hub_port_update_timer, s); 614 s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); 615 for (i = 0; i < s->num_ports; i++) { 616 port = &s->ports[i]; 617 usb_register_port(usb_bus_from_device(dev), 618 &port->port, s, i, &usb_hub_port_ops, 619 USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); 620 usb_port_location(&port->port, dev->port, i+1); 621 } 622 usb_hub_handle_reset(dev); 623 } 624 625 static const VMStateDescription vmstate_usb_hub_port = { 626 .name = "usb-hub-port", 627 .version_id = 1, 628 .minimum_version_id = 1, 629 .fields = (VMStateField[]) { 630 VMSTATE_UINT16(wPortStatus, USBHubPort), 631 VMSTATE_UINT16(wPortChange, USBHubPort), 632 VMSTATE_END_OF_LIST() 633 } 634 }; 635 636 static bool usb_hub_port_timer_needed(void *opaque) 637 { 638 USBHubState *s = opaque; 639 640 return s->port_power; 641 } 642 643 static const VMStateDescription vmstate_usb_hub_port_timer = { 644 .name = "usb-hub/port-timer", 645 .version_id = 1, 646 .minimum_version_id = 1, 647 .needed = usb_hub_port_timer_needed, 648 .fields = (VMStateField[]) { 649 VMSTATE_TIMER_PTR(port_timer, USBHubState), 650 VMSTATE_END_OF_LIST() 651 }, 652 }; 653 654 static const VMStateDescription vmstate_usb_hub = { 655 .name = "usb-hub", 656 .version_id = 1, 657 .minimum_version_id = 1, 658 .fields = (VMStateField[]) { 659 VMSTATE_USB_DEVICE(dev, USBHubState), 660 VMSTATE_STRUCT_ARRAY(ports, USBHubState, MAX_PORTS, 0, 661 vmstate_usb_hub_port, USBHubPort), 662 VMSTATE_END_OF_LIST() 663 }, 664 .subsections = (const VMStateDescription * []) { 665 &vmstate_usb_hub_port_timer, 666 NULL 667 } 668 }; 669 670 static Property usb_hub_properties[] = { 671 DEFINE_PROP_UINT32("ports", USBHubState, num_ports, 8), 672 DEFINE_PROP_BOOL("port-power", USBHubState, port_power, false), 673 DEFINE_PROP_END_OF_LIST(), 674 }; 675 676 static void usb_hub_class_initfn(ObjectClass *klass, void *data) 677 { 678 DeviceClass *dc = DEVICE_CLASS(klass); 679 USBDeviceClass *uc = USB_DEVICE_CLASS(klass); 680 681 uc->realize = usb_hub_realize; 682 uc->product_desc = "QEMU USB Hub"; 683 uc->usb_desc = &desc_hub; 684 uc->find_device = usb_hub_find_device; 685 uc->handle_reset = usb_hub_handle_reset; 686 uc->handle_control = usb_hub_handle_control; 687 uc->handle_data = usb_hub_handle_data; 688 uc->unrealize = usb_hub_unrealize; 689 set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); 690 dc->fw_name = "hub"; 691 dc->vmsd = &vmstate_usb_hub; 692 device_class_set_props(dc, usb_hub_properties); 693 } 694 695 static const TypeInfo hub_info = { 696 .name = TYPE_USB_HUB, 697 .parent = TYPE_USB_DEVICE, 698 .instance_size = sizeof(USBHubState), 699 .class_init = usb_hub_class_initfn, 700 }; 701 702 static void usb_hub_register_types(void) 703 { 704 type_register_static(&hub_info); 705 } 706 707 type_init(usb_hub_register_types) 708