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