|
|
1.1 ! root 1: /* ! 2: * QEMU USB 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: void usb_attach(USBPort *port, USBDevice *dev) ! 27: { ! 28: port->attach(port, dev); ! 29: } ! 30: ! 31: /**********************/ ! 32: /* generic USB device helpers (you are not forced to use them when ! 33: writing your USB device driver, but they help handling the ! 34: protocol) ! 35: */ ! 36: ! 37: #define SETUP_STATE_IDLE 0 ! 38: #define SETUP_STATE_DATA 1 ! 39: #define SETUP_STATE_ACK 2 ! 40: ! 41: int usb_generic_handle_packet(USBDevice *s, int pid, ! 42: uint8_t devaddr, uint8_t devep, ! 43: uint8_t *data, int len) ! 44: { ! 45: int l, ret = 0; ! 46: ! 47: switch(pid) { ! 48: case USB_MSG_ATTACH: ! 49: s->state = USB_STATE_ATTACHED; ! 50: break; ! 51: case USB_MSG_DETACH: ! 52: s->state = USB_STATE_NOTATTACHED; ! 53: break; ! 54: case USB_MSG_RESET: ! 55: s->remote_wakeup = 0; ! 56: s->addr = 0; ! 57: s->state = USB_STATE_DEFAULT; ! 58: s->handle_reset(s); ! 59: break; ! 60: case USB_TOKEN_SETUP: ! 61: if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) ! 62: return USB_RET_NODEV; ! 63: if (len != 8) ! 64: goto fail; ! 65: memcpy(s->setup_buf, data, 8); ! 66: s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; ! 67: s->setup_index = 0; ! 68: if (s->setup_buf[0] & USB_DIR_IN) { ! 69: ret = s->handle_control(s, ! 70: (s->setup_buf[0] << 8) | s->setup_buf[1], ! 71: (s->setup_buf[3] << 8) | s->setup_buf[2], ! 72: (s->setup_buf[5] << 8) | s->setup_buf[4], ! 73: s->setup_len, ! 74: s->data_buf); ! 75: if (ret < 0) ! 76: return ret; ! 77: if (ret < s->setup_len) ! 78: s->setup_len = ret; ! 79: s->setup_state = SETUP_STATE_DATA; ! 80: } else { ! 81: if (s->setup_len == 0) ! 82: s->setup_state = SETUP_STATE_ACK; ! 83: else ! 84: s->setup_state = SETUP_STATE_DATA; ! 85: } ! 86: break; ! 87: case USB_TOKEN_IN: ! 88: if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) ! 89: return USB_RET_NODEV; ! 90: switch(devep) { ! 91: case 0: ! 92: switch(s->setup_state) { ! 93: case SETUP_STATE_ACK: ! 94: s->setup_state = SETUP_STATE_IDLE; ! 95: if (!(s->setup_buf[0] & USB_DIR_IN)) { ! 96: ret = s->handle_control(s, ! 97: (s->setup_buf[0] << 8) | s->setup_buf[1], ! 98: (s->setup_buf[3] << 8) | s->setup_buf[2], ! 99: (s->setup_buf[5] << 8) | s->setup_buf[4], ! 100: s->setup_len, ! 101: s->data_buf); ! 102: if (ret > 0) ! 103: ret = 0; ! 104: } else { ! 105: goto fail; ! 106: } ! 107: break; ! 108: case SETUP_STATE_DATA: ! 109: if (s->setup_buf[0] & USB_DIR_IN) { ! 110: l = s->setup_len - s->setup_index; ! 111: if (l > len) ! 112: l = len; ! 113: memcpy(data, s->data_buf + s->setup_index, l); ! 114: s->setup_index += l; ! 115: if (s->setup_index >= s->setup_len) ! 116: s->setup_state = SETUP_STATE_ACK; ! 117: ret = l; ! 118: } else { ! 119: s->setup_state = SETUP_STATE_IDLE; ! 120: goto fail; ! 121: } ! 122: break; ! 123: default: ! 124: goto fail; ! 125: } ! 126: break; ! 127: default: ! 128: ret = s->handle_data(s, pid, devep, data, len); ! 129: break; ! 130: } ! 131: break; ! 132: case USB_TOKEN_OUT: ! 133: if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) ! 134: return USB_RET_NODEV; ! 135: switch(devep) { ! 136: case 0: ! 137: switch(s->setup_state) { ! 138: case SETUP_STATE_ACK: ! 139: s->setup_state = SETUP_STATE_IDLE; ! 140: if (s->setup_buf[0] & USB_DIR_IN) { ! 141: /* transfer OK */ ! 142: } else { ! 143: goto fail; ! 144: } ! 145: break; ! 146: case SETUP_STATE_DATA: ! 147: if (!(s->setup_buf[0] & USB_DIR_IN)) { ! 148: l = s->setup_len - s->setup_index; ! 149: if (l > len) ! 150: l = len; ! 151: memcpy(s->data_buf + s->setup_index, data, l); ! 152: s->setup_index += l; ! 153: if (s->setup_index >= s->setup_len) ! 154: s->setup_state = SETUP_STATE_ACK; ! 155: ret = l; ! 156: } else { ! 157: s->setup_state = SETUP_STATE_IDLE; ! 158: goto fail; ! 159: } ! 160: break; ! 161: default: ! 162: goto fail; ! 163: } ! 164: break; ! 165: default: ! 166: ret = s->handle_data(s, pid, devep, data, len); ! 167: break; ! 168: } ! 169: break; ! 170: default: ! 171: fail: ! 172: ret = USB_RET_STALL; ! 173: break; ! 174: } ! 175: return ret; ! 176: } ! 177: ! 178: /* XXX: fix overflow */ ! 179: int set_usb_string(uint8_t *buf, const char *str) ! 180: { ! 181: int len, i; ! 182: uint8_t *q; ! 183: ! 184: q = buf; ! 185: len = strlen(str); ! 186: *q++ = 2 * len + 1; ! 187: *q++ = 3; ! 188: for(i = 0; i < len; i++) { ! 189: *q++ = str[i]; ! 190: *q++ = 0; ! 191: } ! 192: return q - buf; ! 193: } ! 194: ! 195: /**********************/ ! 196: /* USB hub emulation */ ! 197: ! 198: //#define DEBUG ! 199: ! 200: #define MAX_PORTS 8 ! 201: ! 202: typedef struct USBHubPort { ! 203: USBPort port; ! 204: uint16_t wPortStatus; ! 205: uint16_t wPortChange; ! 206: } USBHubPort; ! 207: ! 208: typedef struct USBHubState { ! 209: USBDevice dev; ! 210: int nb_ports; ! 211: USBHubPort ports[MAX_PORTS]; ! 212: } USBHubState; ! 213: ! 214: #define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) ! 215: #define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) ! 216: #define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) ! 217: #define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) ! 218: #define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) ! 219: #define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) ! 220: #define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) ! 221: ! 222: #define PORT_STAT_CONNECTION 0x0001 ! 223: #define PORT_STAT_ENABLE 0x0002 ! 224: #define PORT_STAT_SUSPEND 0x0004 ! 225: #define PORT_STAT_OVERCURRENT 0x0008 ! 226: #define PORT_STAT_RESET 0x0010 ! 227: #define PORT_STAT_POWER 0x0100 ! 228: #define PORT_STAT_LOW_SPEED 0x0200 ! 229: #define PORT_STAT_HIGH_SPEED 0x0400 ! 230: #define PORT_STAT_TEST 0x0800 ! 231: #define PORT_STAT_INDICATOR 0x1000 ! 232: ! 233: #define PORT_STAT_C_CONNECTION 0x0001 ! 234: #define PORT_STAT_C_ENABLE 0x0002 ! 235: #define PORT_STAT_C_SUSPEND 0x0004 ! 236: #define PORT_STAT_C_OVERCURRENT 0x0008 ! 237: #define PORT_STAT_C_RESET 0x0010 ! 238: ! 239: #define PORT_CONNECTION 0 ! 240: #define PORT_ENABLE 1 ! 241: #define PORT_SUSPEND 2 ! 242: #define PORT_OVERCURRENT 3 ! 243: #define PORT_RESET 4 ! 244: #define PORT_POWER 8 ! 245: #define PORT_LOWSPEED 9 ! 246: #define PORT_HIGHSPEED 10 ! 247: #define PORT_C_CONNECTION 16 ! 248: #define PORT_C_ENABLE 17 ! 249: #define PORT_C_SUSPEND 18 ! 250: #define PORT_C_OVERCURRENT 19 ! 251: #define PORT_C_RESET 20 ! 252: #define PORT_TEST 21 ! 253: #define PORT_INDICATOR 22 ! 254: ! 255: /* same as Linux kernel root hubs */ ! 256: ! 257: static const uint8_t qemu_hub_dev_descriptor[] = { ! 258: 0x12, /* u8 bLength; */ ! 259: 0x01, /* u8 bDescriptorType; Device */ ! 260: 0x10, 0x01, /* u16 bcdUSB; v1.1 */ ! 261: ! 262: 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */ ! 263: 0x00, /* u8 bDeviceSubClass; */ ! 264: 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ ! 265: 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ ! 266: ! 267: 0x00, 0x00, /* u16 idVendor; */ ! 268: 0x00, 0x00, /* u16 idProduct; */ ! 269: 0x01, 0x01, /* u16 bcdDevice */ ! 270: ! 271: 0x03, /* u8 iManufacturer; */ ! 272: 0x02, /* u8 iProduct; */ ! 273: 0x01, /* u8 iSerialNumber; */ ! 274: 0x01 /* u8 bNumConfigurations; */ ! 275: }; ! 276: ! 277: /* XXX: patch interrupt size */ ! 278: static const uint8_t qemu_hub_config_descriptor[] = { ! 279: ! 280: /* one configuration */ ! 281: 0x09, /* u8 bLength; */ ! 282: 0x02, /* u8 bDescriptorType; Configuration */ ! 283: 0x19, 0x00, /* u16 wTotalLength; */ ! 284: 0x01, /* u8 bNumInterfaces; (1) */ ! 285: 0x01, /* u8 bConfigurationValue; */ ! 286: 0x00, /* u8 iConfiguration; */ ! 287: 0xc0, /* u8 bmAttributes; ! 288: Bit 7: must be set, ! 289: 6: Self-powered, ! 290: 5: Remote wakeup, ! 291: 4..0: resvd */ ! 292: 0x00, /* u8 MaxPower; */ ! 293: ! 294: /* USB 1.1: ! 295: * USB 2.0, single TT organization (mandatory): ! 296: * one interface, protocol 0 ! 297: * ! 298: * USB 2.0, multiple TT organization (optional): ! 299: * two interfaces, protocols 1 (like single TT) ! 300: * and 2 (multiple TT mode) ... config is ! 301: * sometimes settable ! 302: * NOT IMPLEMENTED ! 303: */ ! 304: ! 305: /* one interface */ ! 306: 0x09, /* u8 if_bLength; */ ! 307: 0x04, /* u8 if_bDescriptorType; Interface */ ! 308: 0x00, /* u8 if_bInterfaceNumber; */ ! 309: 0x00, /* u8 if_bAlternateSetting; */ ! 310: 0x01, /* u8 if_bNumEndpoints; */ ! 311: 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */ ! 312: 0x00, /* u8 if_bInterfaceSubClass; */ ! 313: 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ ! 314: 0x00, /* u8 if_iInterface; */ ! 315: ! 316: /* one endpoint (status change endpoint) */ ! 317: 0x07, /* u8 ep_bLength; */ ! 318: 0x05, /* u8 ep_bDescriptorType; Endpoint */ ! 319: 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ ! 320: 0x03, /* u8 ep_bmAttributes; Interrupt */ ! 321: 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ ! 322: 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ ! 323: }; ! 324: ! 325: static const uint8_t qemu_hub_hub_descriptor[] = ! 326: { ! 327: 0x09, /* u8 bLength; */ ! 328: 0x29, /* u8 bDescriptorType; Hub-descriptor */ ! 329: 0x00, /* u8 bNbrPorts; (patched later) */ ! 330: 0x0a, /* u16 wHubCharacteristics; */ ! 331: 0x00, /* (per-port OC, no power switching) */ ! 332: 0x01, /* u8 bPwrOn2pwrGood; 2ms */ ! 333: 0x00, /* u8 bHubContrCurrent; 0 mA */ ! 334: 0x00, /* u8 DeviceRemovable; *** 7 Ports max *** */ ! 335: 0xff /* u8 PortPwrCtrlMask; *** 7 ports max *** */ ! 336: }; ! 337: ! 338: static void usb_hub_attach(USBPort *port1, USBDevice *dev) ! 339: { ! 340: USBHubState *s = port1->opaque; ! 341: USBHubPort *port = &s->ports[port1->index]; ! 342: ! 343: if (dev) { ! 344: if (port->port.dev) ! 345: usb_attach(port1, NULL); ! 346: ! 347: port->wPortStatus |= PORT_STAT_CONNECTION; ! 348: port->wPortChange |= PORT_STAT_C_CONNECTION; ! 349: if (dev->speed == USB_SPEED_LOW) ! 350: port->wPortStatus |= PORT_STAT_LOW_SPEED; ! 351: else ! 352: port->wPortStatus &= ~PORT_STAT_LOW_SPEED; ! 353: port->port.dev = dev; ! 354: } else { ! 355: dev = port->port.dev; ! 356: if (dev) { ! 357: port->wPortStatus &= ~PORT_STAT_CONNECTION; ! 358: port->wPortChange |= PORT_STAT_C_CONNECTION; ! 359: if (port->wPortStatus & PORT_STAT_ENABLE) { ! 360: port->wPortStatus &= ~PORT_STAT_ENABLE; ! 361: port->wPortChange |= PORT_STAT_C_ENABLE; ! 362: } ! 363: port->port.dev = NULL; ! 364: } ! 365: } ! 366: } ! 367: ! 368: static void usb_hub_handle_reset(USBDevice *dev) ! 369: { ! 370: /* XXX: do it */ ! 371: } ! 372: ! 373: static int usb_hub_handle_control(USBDevice *dev, int request, int value, ! 374: int index, int length, uint8_t *data) ! 375: { ! 376: USBHubState *s = (USBHubState *)dev; ! 377: int ret; ! 378: ! 379: switch(request) { ! 380: case DeviceRequest | USB_REQ_GET_STATUS: ! 381: data[0] = (1 << USB_DEVICE_SELF_POWERED) | ! 382: (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); ! 383: data[1] = 0x00; ! 384: ret = 2; ! 385: break; ! 386: case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: ! 387: if (value == USB_DEVICE_REMOTE_WAKEUP) { ! 388: dev->remote_wakeup = 0; ! 389: } else { ! 390: goto fail; ! 391: } ! 392: ret = 0; ! 393: break; ! 394: case DeviceOutRequest | USB_REQ_SET_FEATURE: ! 395: if (value == USB_DEVICE_REMOTE_WAKEUP) { ! 396: dev->remote_wakeup = 1; ! 397: } else { ! 398: goto fail; ! 399: } ! 400: ret = 0; ! 401: break; ! 402: case DeviceOutRequest | USB_REQ_SET_ADDRESS: ! 403: dev->addr = value; ! 404: ret = 0; ! 405: break; ! 406: case DeviceRequest | USB_REQ_GET_DESCRIPTOR: ! 407: switch(value >> 8) { ! 408: case USB_DT_DEVICE: ! 409: memcpy(data, qemu_hub_dev_descriptor, ! 410: sizeof(qemu_hub_dev_descriptor)); ! 411: ret = sizeof(qemu_hub_dev_descriptor); ! 412: break; ! 413: case USB_DT_CONFIG: ! 414: memcpy(data, qemu_hub_config_descriptor, ! 415: sizeof(qemu_hub_config_descriptor)); ! 416: ret = sizeof(qemu_hub_config_descriptor); ! 417: break; ! 418: case USB_DT_STRING: ! 419: switch(value & 0xff) { ! 420: case 0: ! 421: /* language ids */ ! 422: data[0] = 4; ! 423: data[1] = 3; ! 424: data[2] = 0x09; ! 425: data[3] = 0x04; ! 426: ret = 4; ! 427: break; ! 428: case 1: ! 429: /* serial number */ ! 430: ret = set_usb_string(data, "314159"); ! 431: break; ! 432: case 2: ! 433: /* product description */ ! 434: ret = set_usb_string(data, "QEMU USB Hub"); ! 435: break; ! 436: case 3: ! 437: /* vendor description */ ! 438: ret = set_usb_string(data, "QEMU " QEMU_VERSION); ! 439: break; ! 440: default: ! 441: goto fail; ! 442: } ! 443: break; ! 444: default: ! 445: goto fail; ! 446: } ! 447: break; ! 448: case DeviceRequest | USB_REQ_GET_CONFIGURATION: ! 449: data[0] = 1; ! 450: ret = 1; ! 451: break; ! 452: case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: ! 453: ret = 0; ! 454: break; ! 455: case DeviceRequest | USB_REQ_GET_INTERFACE: ! 456: data[0] = 0; ! 457: ret = 1; ! 458: break; ! 459: case DeviceOutRequest | USB_REQ_SET_INTERFACE: ! 460: ret = 0; ! 461: break; ! 462: /* usb specific requests */ ! 463: case GetHubStatus: ! 464: data[0] = 0; ! 465: data[1] = 0; ! 466: data[2] = 0; ! 467: data[3] = 0; ! 468: ret = 4; ! 469: break; ! 470: case GetPortStatus: ! 471: { ! 472: unsigned int n = index - 1; ! 473: USBHubPort *port; ! 474: if (n >= s->nb_ports) ! 475: goto fail; ! 476: port = &s->ports[n]; ! 477: data[0] = port->wPortStatus; ! 478: data[1] = port->wPortStatus >> 8; ! 479: data[2] = port->wPortChange; ! 480: data[3] = port->wPortChange >> 8; ! 481: ret = 4; ! 482: } ! 483: break; ! 484: case SetHubFeature: ! 485: case ClearHubFeature: ! 486: if (value == 0 || value == 1) { ! 487: } else { ! 488: goto fail; ! 489: } ! 490: ret = 0; ! 491: break; ! 492: case SetPortFeature: ! 493: { ! 494: unsigned int n = index - 1; ! 495: USBHubPort *port; ! 496: USBDevice *dev; ! 497: if (n >= s->nb_ports) ! 498: goto fail; ! 499: port = &s->ports[n]; ! 500: dev = port->port.dev; ! 501: switch(value) { ! 502: case PORT_SUSPEND: ! 503: port->wPortStatus |= PORT_STAT_SUSPEND; ! 504: break; ! 505: case PORT_RESET: ! 506: if (dev) { ! 507: dev->handle_packet(dev, ! 508: USB_MSG_RESET, 0, 0, NULL, 0); ! 509: port->wPortChange |= PORT_STAT_C_RESET; ! 510: /* set enable bit */ ! 511: port->wPortChange |= PORT_STAT_C_ENABLE; ! 512: port->wPortStatus |= PORT_STAT_ENABLE; ! 513: } ! 514: break; ! 515: case PORT_POWER: ! 516: break; ! 517: default: ! 518: goto fail; ! 519: } ! 520: ret = 0; ! 521: } ! 522: break; ! 523: case ClearPortFeature: ! 524: { ! 525: unsigned int n = index - 1; ! 526: USBHubPort *port; ! 527: USBDevice *dev; ! 528: if (n >= s->nb_ports) ! 529: goto fail; ! 530: port = &s->ports[n]; ! 531: dev = port->port.dev; ! 532: switch(value) { ! 533: case PORT_ENABLE: ! 534: port->wPortStatus &= ~PORT_STAT_ENABLE; ! 535: break; ! 536: case PORT_C_ENABLE: ! 537: port->wPortChange &= ~PORT_STAT_C_ENABLE; ! 538: break; ! 539: case PORT_SUSPEND: ! 540: port->wPortStatus &= ~PORT_STAT_SUSPEND; ! 541: break; ! 542: case PORT_C_SUSPEND: ! 543: port->wPortChange &= ~PORT_STAT_C_SUSPEND; ! 544: break; ! 545: case PORT_C_CONNECTION: ! 546: port->wPortChange &= ~PORT_STAT_C_CONNECTION; ! 547: break; ! 548: case PORT_C_OVERCURRENT: ! 549: port->wPortChange &= ~PORT_STAT_C_OVERCURRENT; ! 550: break; ! 551: case PORT_C_RESET: ! 552: port->wPortChange &= ~PORT_STAT_C_RESET; ! 553: break; ! 554: default: ! 555: goto fail; ! 556: } ! 557: ret = 0; ! 558: } ! 559: break; ! 560: case GetHubDescriptor: ! 561: memcpy(data, qemu_hub_hub_descriptor, ! 562: sizeof(qemu_hub_hub_descriptor)); ! 563: data[2] = s->nb_ports; ! 564: ret = sizeof(qemu_hub_hub_descriptor); ! 565: break; ! 566: default: ! 567: fail: ! 568: ret = USB_RET_STALL; ! 569: break; ! 570: } ! 571: return ret; ! 572: } ! 573: ! 574: static int usb_hub_handle_data(USBDevice *dev, int pid, ! 575: uint8_t devep, uint8_t *data, int len) ! 576: { ! 577: USBHubState *s = (USBHubState *)dev; ! 578: int ret; ! 579: ! 580: switch(pid) { ! 581: case USB_TOKEN_IN: ! 582: if (devep == 1) { ! 583: USBHubPort *port; ! 584: unsigned int status; ! 585: int i, n; ! 586: n = (s->nb_ports + 1 + 7) / 8; ! 587: if (n > len) ! 588: return USB_RET_BABBLE; ! 589: status = 0; ! 590: for(i = 0; i < s->nb_ports; i++) { ! 591: port = &s->ports[i]; ! 592: if (port->wPortChange) ! 593: status |= (1 << (i + 1)); ! 594: } ! 595: if (status != 0) { ! 596: for(i = 0; i < n; i++) { ! 597: data[i] = status >> (8 * i); ! 598: } ! 599: ret = n; ! 600: } else { ! 601: ret = 0; ! 602: } ! 603: } else { ! 604: goto fail; ! 605: } ! 606: break; ! 607: case USB_TOKEN_OUT: ! 608: default: ! 609: fail: ! 610: ret = USB_RET_STALL; ! 611: break; ! 612: } ! 613: return ret; ! 614: } ! 615: ! 616: static int usb_hub_broadcast_packet(USBHubState *s, int pid, ! 617: uint8_t devaddr, uint8_t devep, ! 618: uint8_t *data, int len) ! 619: { ! 620: USBHubPort *port; ! 621: USBDevice *dev; ! 622: int i, ret; ! 623: ! 624: for(i = 0; i < s->nb_ports; i++) { ! 625: port = &s->ports[i]; ! 626: dev = port->port.dev; ! 627: if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { ! 628: ret = dev->handle_packet(dev, pid, ! 629: devaddr, devep, ! 630: data, len); ! 631: if (ret != USB_RET_NODEV) { ! 632: return ret; ! 633: } ! 634: } ! 635: } ! 636: return USB_RET_NODEV; ! 637: } ! 638: ! 639: static int usb_hub_handle_packet(USBDevice *dev, int pid, ! 640: uint8_t devaddr, uint8_t devep, ! 641: uint8_t *data, int len) ! 642: { ! 643: USBHubState *s = (USBHubState *)dev; ! 644: ! 645: #if defined(DEBUG) && 0 ! 646: printf("usb_hub: pid=0x%x\n", pid); ! 647: #endif ! 648: if (dev->state == USB_STATE_DEFAULT && ! 649: dev->addr != 0 && ! 650: devaddr != dev->addr && ! 651: (pid == USB_TOKEN_SETUP || ! 652: pid == USB_TOKEN_OUT || ! 653: pid == USB_TOKEN_IN)) { ! 654: /* broadcast the packet to the devices */ ! 655: return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len); ! 656: } ! 657: return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); ! 658: } ! 659: ! 660: USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) ! 661: { ! 662: USBHubState *s; ! 663: USBHubPort *port; ! 664: int i; ! 665: ! 666: if (nb_ports > MAX_PORTS) ! 667: return NULL; ! 668: s = qemu_mallocz(sizeof(USBHubState)); ! 669: if (!s) ! 670: return NULL; ! 671: s->dev.speed = USB_SPEED_FULL; ! 672: s->dev.handle_packet = usb_hub_handle_packet; ! 673: ! 674: /* generic USB device init */ ! 675: s->dev.handle_reset = usb_hub_handle_reset; ! 676: s->dev.handle_control = usb_hub_handle_control; ! 677: s->dev.handle_data = usb_hub_handle_data; ! 678: ! 679: s->nb_ports = nb_ports; ! 680: for(i = 0; i < s->nb_ports; i++) { ! 681: port = &s->ports[i]; ! 682: port->wPortStatus = PORT_STAT_POWER; ! 683: port->wPortChange = 0; ! 684: port->port.attach = usb_hub_attach; ! 685: port->port.opaque = s; ! 686: port->port.index = i; ! 687: usb_ports[i] = &port->port; ! 688: } ! 689: return (USBDevice *)s; ! 690: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.