|
|
1.1 ! root 1: #include <ctype.h> ! 2: ! 3: #include "hw/usb.h" ! 4: #include "hw/usb/desc.h" ! 5: #include "trace.h" ! 6: ! 7: /* ------------------------------------------------------------------ */ ! 8: ! 9: static uint8_t usb_lo(uint16_t val) ! 10: { ! 11: return val & 0xff; ! 12: } ! 13: ! 14: static uint8_t usb_hi(uint16_t val) ! 15: { ! 16: return (val >> 8) & 0xff; ! 17: } ! 18: ! 19: int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, ! 20: uint8_t *dest, size_t len) ! 21: { ! 22: uint8_t bLength = 0x12; ! 23: USBDescriptor *d = (void *)dest; ! 24: ! 25: if (len < bLength) { ! 26: return -1; ! 27: } ! 28: ! 29: d->bLength = bLength; ! 30: d->bDescriptorType = USB_DT_DEVICE; ! 31: ! 32: d->u.device.bcdUSB_lo = usb_lo(dev->bcdUSB); ! 33: d->u.device.bcdUSB_hi = usb_hi(dev->bcdUSB); ! 34: d->u.device.bDeviceClass = dev->bDeviceClass; ! 35: d->u.device.bDeviceSubClass = dev->bDeviceSubClass; ! 36: d->u.device.bDeviceProtocol = dev->bDeviceProtocol; ! 37: d->u.device.bMaxPacketSize0 = dev->bMaxPacketSize0; ! 38: ! 39: d->u.device.idVendor_lo = usb_lo(id->idVendor); ! 40: d->u.device.idVendor_hi = usb_hi(id->idVendor); ! 41: d->u.device.idProduct_lo = usb_lo(id->idProduct); ! 42: d->u.device.idProduct_hi = usb_hi(id->idProduct); ! 43: d->u.device.bcdDevice_lo = usb_lo(id->bcdDevice); ! 44: d->u.device.bcdDevice_hi = usb_hi(id->bcdDevice); ! 45: d->u.device.iManufacturer = id->iManufacturer; ! 46: d->u.device.iProduct = id->iProduct; ! 47: d->u.device.iSerialNumber = id->iSerialNumber; ! 48: ! 49: d->u.device.bNumConfigurations = dev->bNumConfigurations; ! 50: ! 51: return bLength; ! 52: } ! 53: ! 54: int usb_desc_device_qualifier(const USBDescDevice *dev, ! 55: uint8_t *dest, size_t len) ! 56: { ! 57: uint8_t bLength = 0x0a; ! 58: USBDescriptor *d = (void *)dest; ! 59: ! 60: if (len < bLength) { ! 61: return -1; ! 62: } ! 63: ! 64: d->bLength = bLength; ! 65: d->bDescriptorType = USB_DT_DEVICE_QUALIFIER; ! 66: ! 67: d->u.device_qualifier.bcdUSB_lo = usb_lo(dev->bcdUSB); ! 68: d->u.device_qualifier.bcdUSB_hi = usb_hi(dev->bcdUSB); ! 69: d->u.device_qualifier.bDeviceClass = dev->bDeviceClass; ! 70: d->u.device_qualifier.bDeviceSubClass = dev->bDeviceSubClass; ! 71: d->u.device_qualifier.bDeviceProtocol = dev->bDeviceProtocol; ! 72: d->u.device_qualifier.bMaxPacketSize0 = dev->bMaxPacketSize0; ! 73: d->u.device_qualifier.bNumConfigurations = dev->bNumConfigurations; ! 74: d->u.device_qualifier.bReserved = 0; ! 75: ! 76: return bLength; ! 77: } ! 78: ! 79: int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) ! 80: { ! 81: uint8_t bLength = 0x09; ! 82: uint16_t wTotalLength = 0; ! 83: USBDescriptor *d = (void *)dest; ! 84: int i, rc; ! 85: ! 86: if (len < bLength) { ! 87: return -1; ! 88: } ! 89: ! 90: d->bLength = bLength; ! 91: d->bDescriptorType = USB_DT_CONFIG; ! 92: ! 93: d->u.config.bNumInterfaces = conf->bNumInterfaces; ! 94: d->u.config.bConfigurationValue = conf->bConfigurationValue; ! 95: d->u.config.iConfiguration = conf->iConfiguration; ! 96: d->u.config.bmAttributes = conf->bmAttributes; ! 97: d->u.config.bMaxPower = conf->bMaxPower; ! 98: wTotalLength += bLength; ! 99: ! 100: /* handle grouped interfaces if any */ ! 101: for (i = 0; i < conf->nif_groups; i++) { ! 102: rc = usb_desc_iface_group(&(conf->if_groups[i]), ! 103: dest + wTotalLength, ! 104: len - wTotalLength); ! 105: if (rc < 0) { ! 106: return rc; ! 107: } ! 108: wTotalLength += rc; ! 109: } ! 110: ! 111: /* handle normal (ungrouped / no IAD) interfaces if any */ ! 112: for (i = 0; i < conf->nif; i++) { ! 113: rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength); ! 114: if (rc < 0) { ! 115: return rc; ! 116: } ! 117: wTotalLength += rc; ! 118: } ! 119: ! 120: d->u.config.wTotalLength_lo = usb_lo(wTotalLength); ! 121: d->u.config.wTotalLength_hi = usb_hi(wTotalLength); ! 122: return wTotalLength; ! 123: } ! 124: ! 125: int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, ! 126: size_t len) ! 127: { ! 128: int pos = 0; ! 129: int i = 0; ! 130: ! 131: /* handle interface association descriptor */ ! 132: uint8_t bLength = 0x08; ! 133: ! 134: if (len < bLength) { ! 135: return -1; ! 136: } ! 137: ! 138: dest[0x00] = bLength; ! 139: dest[0x01] = USB_DT_INTERFACE_ASSOC; ! 140: dest[0x02] = iad->bFirstInterface; ! 141: dest[0x03] = iad->bInterfaceCount; ! 142: dest[0x04] = iad->bFunctionClass; ! 143: dest[0x05] = iad->bFunctionSubClass; ! 144: dest[0x06] = iad->bFunctionProtocol; ! 145: dest[0x07] = iad->iFunction; ! 146: pos += bLength; ! 147: ! 148: /* handle associated interfaces in this group */ ! 149: for (i = 0; i < iad->nif; i++) { ! 150: int rc = usb_desc_iface(&(iad->ifs[i]), dest + pos, len - pos); ! 151: if (rc < 0) { ! 152: return rc; ! 153: } ! 154: pos += rc; ! 155: } ! 156: ! 157: return pos; ! 158: } ! 159: ! 160: int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) ! 161: { ! 162: uint8_t bLength = 0x09; ! 163: int i, rc, pos = 0; ! 164: USBDescriptor *d = (void *)dest; ! 165: ! 166: if (len < bLength) { ! 167: return -1; ! 168: } ! 169: ! 170: d->bLength = bLength; ! 171: d->bDescriptorType = USB_DT_INTERFACE; ! 172: ! 173: d->u.interface.bInterfaceNumber = iface->bInterfaceNumber; ! 174: d->u.interface.bAlternateSetting = iface->bAlternateSetting; ! 175: d->u.interface.bNumEndpoints = iface->bNumEndpoints; ! 176: d->u.interface.bInterfaceClass = iface->bInterfaceClass; ! 177: d->u.interface.bInterfaceSubClass = iface->bInterfaceSubClass; ! 178: d->u.interface.bInterfaceProtocol = iface->bInterfaceProtocol; ! 179: d->u.interface.iInterface = iface->iInterface; ! 180: pos += bLength; ! 181: ! 182: for (i = 0; i < iface->ndesc; i++) { ! 183: rc = usb_desc_other(iface->descs + i, dest + pos, len - pos); ! 184: if (rc < 0) { ! 185: return rc; ! 186: } ! 187: pos += rc; ! 188: } ! 189: ! 190: for (i = 0; i < iface->bNumEndpoints; i++) { ! 191: rc = usb_desc_endpoint(iface->eps + i, dest + pos, len - pos); ! 192: if (rc < 0) { ! 193: return rc; ! 194: } ! 195: pos += rc; ! 196: } ! 197: ! 198: return pos; ! 199: } ! 200: ! 201: int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) ! 202: { ! 203: uint8_t bLength = ep->is_audio ? 0x09 : 0x07; ! 204: uint8_t extralen = ep->extra ? ep->extra[0] : 0; ! 205: USBDescriptor *d = (void *)dest; ! 206: ! 207: if (len < bLength + extralen) { ! 208: return -1; ! 209: } ! 210: ! 211: d->bLength = bLength; ! 212: d->bDescriptorType = USB_DT_ENDPOINT; ! 213: ! 214: d->u.endpoint.bEndpointAddress = ep->bEndpointAddress; ! 215: d->u.endpoint.bmAttributes = ep->bmAttributes; ! 216: d->u.endpoint.wMaxPacketSize_lo = usb_lo(ep->wMaxPacketSize); ! 217: d->u.endpoint.wMaxPacketSize_hi = usb_hi(ep->wMaxPacketSize); ! 218: d->u.endpoint.bInterval = ep->bInterval; ! 219: if (ep->is_audio) { ! 220: d->u.endpoint.bRefresh = ep->bRefresh; ! 221: d->u.endpoint.bSynchAddress = ep->bSynchAddress; ! 222: } ! 223: if (ep->extra) { ! 224: memcpy(dest + bLength, ep->extra, extralen); ! 225: } ! 226: ! 227: return bLength + extralen; ! 228: } ! 229: ! 230: int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) ! 231: { ! 232: int bLength = desc->length ? desc->length : desc->data[0]; ! 233: ! 234: if (len < bLength) { ! 235: return -1; ! 236: } ! 237: ! 238: memcpy(dest, desc->data, bLength); ! 239: return bLength; ! 240: } ! 241: ! 242: /* ------------------------------------------------------------------ */ ! 243: ! 244: static void usb_desc_ep_init(USBDevice *dev) ! 245: { ! 246: const USBDescIface *iface; ! 247: int i, e, pid, ep; ! 248: ! 249: usb_ep_init(dev); ! 250: for (i = 0; i < dev->ninterfaces; i++) { ! 251: iface = dev->ifaces[i]; ! 252: if (iface == NULL) { ! 253: continue; ! 254: } ! 255: for (e = 0; e < iface->bNumEndpoints; e++) { ! 256: pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ? ! 257: USB_TOKEN_IN : USB_TOKEN_OUT; ! 258: ep = iface->eps[e].bEndpointAddress & 0x0f; ! 259: usb_ep_set_type(dev, pid, ep, iface->eps[e].bmAttributes & 0x03); ! 260: usb_ep_set_ifnum(dev, pid, ep, iface->bInterfaceNumber); ! 261: usb_ep_set_max_packet_size(dev, pid, ep, ! 262: iface->eps[e].wMaxPacketSize); ! 263: } ! 264: } ! 265: } ! 266: ! 267: static const USBDescIface *usb_desc_find_interface(USBDevice *dev, ! 268: int nif, int alt) ! 269: { ! 270: const USBDescIface *iface; ! 271: int g, i; ! 272: ! 273: if (!dev->config) { ! 274: return NULL; ! 275: } ! 276: for (g = 0; g < dev->config->nif_groups; g++) { ! 277: for (i = 0; i < dev->config->if_groups[g].nif; i++) { ! 278: iface = &dev->config->if_groups[g].ifs[i]; ! 279: if (iface->bInterfaceNumber == nif && ! 280: iface->bAlternateSetting == alt) { ! 281: return iface; ! 282: } ! 283: } ! 284: } ! 285: for (i = 0; i < dev->config->nif; i++) { ! 286: iface = &dev->config->ifs[i]; ! 287: if (iface->bInterfaceNumber == nif && ! 288: iface->bAlternateSetting == alt) { ! 289: return iface; ! 290: } ! 291: } ! 292: return NULL; ! 293: } ! 294: ! 295: static int usb_desc_set_interface(USBDevice *dev, int index, int value) ! 296: { ! 297: const USBDescIface *iface; ! 298: int old; ! 299: ! 300: iface = usb_desc_find_interface(dev, index, value); ! 301: if (iface == NULL) { ! 302: return -1; ! 303: } ! 304: ! 305: old = dev->altsetting[index]; ! 306: dev->altsetting[index] = value; ! 307: dev->ifaces[index] = iface; ! 308: usb_desc_ep_init(dev); ! 309: ! 310: if (old != value) { ! 311: usb_device_set_interface(dev, index, old, value); ! 312: } ! 313: return 0; ! 314: } ! 315: ! 316: static int usb_desc_set_config(USBDevice *dev, int value) ! 317: { ! 318: int i; ! 319: ! 320: if (value == 0) { ! 321: dev->configuration = 0; ! 322: dev->ninterfaces = 0; ! 323: dev->config = NULL; ! 324: } else { ! 325: for (i = 0; i < dev->device->bNumConfigurations; i++) { ! 326: if (dev->device->confs[i].bConfigurationValue == value) { ! 327: dev->configuration = value; ! 328: dev->ninterfaces = dev->device->confs[i].bNumInterfaces; ! 329: dev->config = dev->device->confs + i; ! 330: assert(dev->ninterfaces <= USB_MAX_INTERFACES); ! 331: } ! 332: } ! 333: if (i < dev->device->bNumConfigurations) { ! 334: return -1; ! 335: } ! 336: } ! 337: ! 338: for (i = 0; i < dev->ninterfaces; i++) { ! 339: usb_desc_set_interface(dev, i, 0); ! 340: } ! 341: for (; i < USB_MAX_INTERFACES; i++) { ! 342: dev->altsetting[i] = 0; ! 343: dev->ifaces[i] = NULL; ! 344: } ! 345: ! 346: return 0; ! 347: } ! 348: ! 349: static void usb_desc_setdefaults(USBDevice *dev) ! 350: { ! 351: const USBDesc *desc = usb_device_get_usb_desc(dev); ! 352: ! 353: assert(desc != NULL); ! 354: switch (dev->speed) { ! 355: case USB_SPEED_LOW: ! 356: case USB_SPEED_FULL: ! 357: dev->device = desc->full; ! 358: break; ! 359: case USB_SPEED_HIGH: ! 360: dev->device = desc->high; ! 361: break; ! 362: } ! 363: usb_desc_set_config(dev, 0); ! 364: } ! 365: ! 366: void usb_desc_init(USBDevice *dev) ! 367: { ! 368: const USBDesc *desc = usb_device_get_usb_desc(dev); ! 369: ! 370: assert(desc != NULL); ! 371: dev->speed = USB_SPEED_FULL; ! 372: dev->speedmask = 0; ! 373: if (desc->full) { ! 374: dev->speedmask |= USB_SPEED_MASK_FULL; ! 375: } ! 376: if (desc->high) { ! 377: dev->speedmask |= USB_SPEED_MASK_HIGH; ! 378: } ! 379: usb_desc_setdefaults(dev); ! 380: } ! 381: ! 382: void usb_desc_attach(USBDevice *dev) ! 383: { ! 384: const USBDesc *desc = usb_device_get_usb_desc(dev); ! 385: ! 386: assert(desc != NULL); ! 387: if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) { ! 388: dev->speed = USB_SPEED_HIGH; ! 389: } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) { ! 390: dev->speed = USB_SPEED_FULL; ! 391: } else { ! 392: fprintf(stderr, "usb: port/device speed mismatch for \"%s\"\n", ! 393: usb_device_get_product_desc(dev)); ! 394: return; ! 395: } ! 396: usb_desc_setdefaults(dev); ! 397: } ! 398: ! 399: void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str) ! 400: { ! 401: USBDescString *s; ! 402: ! 403: QLIST_FOREACH(s, &dev->strings, next) { ! 404: if (s->index == index) { ! 405: break; ! 406: } ! 407: } ! 408: if (s == NULL) { ! 409: s = g_malloc0(sizeof(*s)); ! 410: s->index = index; ! 411: QLIST_INSERT_HEAD(&dev->strings, s, next); ! 412: } ! 413: g_free(s->str); ! 414: s->str = g_strdup(str); ! 415: } ! 416: ! 417: /* ! 418: * This function creates a serial number for a usb device. ! 419: * The serial number should: ! 420: * (a) Be unique within the virtual machine. ! 421: * (b) Be constant, so you don't get a new one each ! 422: * time the guest is started. ! 423: * So we are using the physical location to generate a serial number ! 424: * from it. It has three pieces: First a fixed, device-specific ! 425: * prefix. Second the device path of the host controller (which is ! 426: * the pci address in most cases). Third the physical port path. ! 427: * Results in serial numbers like this: "314159-0000:00:1d.7-3". ! 428: */ ! 429: void usb_desc_create_serial(USBDevice *dev) ! 430: { ! 431: DeviceState *hcd = dev->qdev.parent_bus->parent; ! 432: const USBDesc *desc = usb_device_get_usb_desc(dev); ! 433: int index = desc->id.iSerialNumber; ! 434: char serial[64]; ! 435: int dst; ! 436: ! 437: assert(index != 0 && desc->str[index] != NULL); ! 438: dst = snprintf(serial, sizeof(serial), "%s", desc->str[index]); ! 439: if (hcd && hcd->parent_bus && hcd->parent_bus->info->get_dev_path) { ! 440: char *path = hcd->parent_bus->info->get_dev_path(hcd); ! 441: dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", path); ! 442: } ! 443: dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", dev->port->path); ! 444: usb_desc_set_string(dev, index, serial); ! 445: } ! 446: ! 447: const char *usb_desc_get_string(USBDevice *dev, uint8_t index) ! 448: { ! 449: USBDescString *s; ! 450: ! 451: QLIST_FOREACH(s, &dev->strings, next) { ! 452: if (s->index == index) { ! 453: return s->str; ! 454: } ! 455: } ! 456: return NULL; ! 457: } ! 458: ! 459: int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len) ! 460: { ! 461: uint8_t bLength, pos, i; ! 462: const char *str; ! 463: ! 464: if (len < 4) { ! 465: return -1; ! 466: } ! 467: ! 468: if (index == 0) { ! 469: /* language ids */ ! 470: dest[0] = 4; ! 471: dest[1] = USB_DT_STRING; ! 472: dest[2] = 0x09; ! 473: dest[3] = 0x04; ! 474: return 4; ! 475: } ! 476: ! 477: str = usb_desc_get_string(dev, index); ! 478: if (str == NULL) { ! 479: str = usb_device_get_usb_desc(dev)->str[index]; ! 480: if (str == NULL) { ! 481: return 0; ! 482: } ! 483: } ! 484: ! 485: bLength = strlen(str) * 2 + 2; ! 486: dest[0] = bLength; ! 487: dest[1] = USB_DT_STRING; ! 488: i = 0; pos = 2; ! 489: while (pos+1 < bLength && pos+1 < len) { ! 490: dest[pos++] = str[i++]; ! 491: dest[pos++] = 0; ! 492: } ! 493: return pos; ! 494: } ! 495: ! 496: int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len) ! 497: { ! 498: const USBDesc *desc = usb_device_get_usb_desc(dev); ! 499: const USBDescDevice *other_dev; ! 500: uint8_t buf[256]; ! 501: uint8_t type = value >> 8; ! 502: uint8_t index = value & 0xff; ! 503: int ret = -1; ! 504: ! 505: if (dev->speed == USB_SPEED_HIGH) { ! 506: other_dev = usb_device_get_usb_desc(dev)->full; ! 507: } else { ! 508: other_dev = usb_device_get_usb_desc(dev)->high; ! 509: } ! 510: ! 511: switch(type) { ! 512: case USB_DT_DEVICE: ! 513: ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf)); ! 514: trace_usb_desc_device(dev->addr, len, ret); ! 515: break; ! 516: case USB_DT_CONFIG: ! 517: if (index < dev->device->bNumConfigurations) { ! 518: ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf)); ! 519: } ! 520: trace_usb_desc_config(dev->addr, index, len, ret); ! 521: break; ! 522: case USB_DT_STRING: ! 523: ret = usb_desc_string(dev, index, buf, sizeof(buf)); ! 524: trace_usb_desc_string(dev->addr, index, len, ret); ! 525: break; ! 526: ! 527: case USB_DT_DEVICE_QUALIFIER: ! 528: if (other_dev != NULL) { ! 529: ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf)); ! 530: } ! 531: trace_usb_desc_device_qualifier(dev->addr, len, ret); ! 532: break; ! 533: case USB_DT_OTHER_SPEED_CONFIG: ! 534: if (other_dev != NULL && index < other_dev->bNumConfigurations) { ! 535: ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf)); ! 536: buf[0x01] = USB_DT_OTHER_SPEED_CONFIG; ! 537: } ! 538: trace_usb_desc_other_speed_config(dev->addr, index, len, ret); ! 539: break; ! 540: ! 541: case USB_DT_DEBUG: ! 542: /* ignore silently */ ! 543: break; ! 544: ! 545: default: ! 546: fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__, ! 547: dev->addr, type, len); ! 548: break; ! 549: } ! 550: ! 551: if (ret > 0) { ! 552: if (ret > len) { ! 553: ret = len; ! 554: } ! 555: memcpy(dest, buf, ret); ! 556: } ! 557: return ret; ! 558: } ! 559: ! 560: int usb_desc_handle_control(USBDevice *dev, USBPacket *p, ! 561: int request, int value, int index, int length, uint8_t *data) ! 562: { ! 563: const USBDesc *desc = usb_device_get_usb_desc(dev); ! 564: int ret = -1; ! 565: ! 566: assert(desc != NULL); ! 567: switch(request) { ! 568: case DeviceOutRequest | USB_REQ_SET_ADDRESS: ! 569: dev->addr = value; ! 570: trace_usb_set_addr(dev->addr); ! 571: ret = 0; ! 572: break; ! 573: ! 574: case DeviceRequest | USB_REQ_GET_DESCRIPTOR: ! 575: ret = usb_desc_get_descriptor(dev, value, data, length); ! 576: break; ! 577: ! 578: case DeviceRequest | USB_REQ_GET_CONFIGURATION: ! 579: /* ! 580: * 9.4.2: 0 should be returned if the device is unconfigured, otherwise ! 581: * the non zero value of bConfigurationValue. ! 582: */ ! 583: data[0] = dev->config ? dev->config->bConfigurationValue : 0; ! 584: ret = 1; ! 585: break; ! 586: case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: ! 587: ret = usb_desc_set_config(dev, value); ! 588: trace_usb_set_config(dev->addr, value, ret); ! 589: break; ! 590: ! 591: case DeviceRequest | USB_REQ_GET_STATUS: { ! 592: const USBDescConfig *config = dev->config ? ! 593: dev->config : &dev->device->confs[0]; ! 594: ! 595: data[0] = 0; ! 596: /* ! 597: * Default state: Device behavior when this request is received while ! 598: * the device is in the Default state is not specified. ! 599: * We return the same value that a configured device would return if ! 600: * it used the first configuration. ! 601: */ ! 602: if (config->bmAttributes & 0x40) { ! 603: data[0] |= 1 << USB_DEVICE_SELF_POWERED; ! 604: } ! 605: if (dev->remote_wakeup) { ! 606: data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP; ! 607: } ! 608: data[1] = 0x00; ! 609: ret = 2; ! 610: break; ! 611: } ! 612: case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: ! 613: if (value == USB_DEVICE_REMOTE_WAKEUP) { ! 614: dev->remote_wakeup = 0; ! 615: ret = 0; ! 616: } ! 617: trace_usb_clear_device_feature(dev->addr, value, ret); ! 618: break; ! 619: case DeviceOutRequest | USB_REQ_SET_FEATURE: ! 620: if (value == USB_DEVICE_REMOTE_WAKEUP) { ! 621: dev->remote_wakeup = 1; ! 622: ret = 0; ! 623: } ! 624: trace_usb_set_device_feature(dev->addr, value, ret); ! 625: break; ! 626: ! 627: case InterfaceRequest | USB_REQ_GET_INTERFACE: ! 628: if (index < 0 || index >= dev->ninterfaces) { ! 629: break; ! 630: } ! 631: data[0] = dev->altsetting[index]; ! 632: ret = 1; ! 633: break; ! 634: case InterfaceOutRequest | USB_REQ_SET_INTERFACE: ! 635: ret = usb_desc_set_interface(dev, index, value); ! 636: trace_usb_set_interface(dev->addr, index, value, ret); ! 637: break; ! 638: ! 639: } ! 640: return ret; ! 641: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.