|
|
1.1 ! root 1: #include "usb.h" ! 2: #include "usb-desc.h" ! 3: #include "trace.h" ! 4: ! 5: /* ------------------------------------------------------------------ */ ! 6: ! 7: static uint8_t usb_lo(uint16_t val) ! 8: { ! 9: return val & 0xff; ! 10: } ! 11: ! 12: static uint8_t usb_hi(uint16_t val) ! 13: { ! 14: return (val >> 8) & 0xff; ! 15: } ! 16: ! 17: int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, ! 18: uint8_t *dest, size_t len) ! 19: { ! 20: uint8_t bLength = 0x12; ! 21: ! 22: if (len < bLength) { ! 23: return -1; ! 24: } ! 25: ! 26: dest[0x00] = bLength; ! 27: dest[0x01] = USB_DT_DEVICE; ! 28: ! 29: dest[0x02] = usb_lo(dev->bcdUSB); ! 30: dest[0x03] = usb_hi(dev->bcdUSB); ! 31: dest[0x04] = dev->bDeviceClass; ! 32: dest[0x05] = dev->bDeviceSubClass; ! 33: dest[0x06] = dev->bDeviceProtocol; ! 34: dest[0x07] = dev->bMaxPacketSize0; ! 35: ! 36: dest[0x08] = usb_lo(id->idVendor); ! 37: dest[0x09] = usb_hi(id->idVendor); ! 38: dest[0x0a] = usb_lo(id->idProduct); ! 39: dest[0x0b] = usb_hi(id->idProduct); ! 40: dest[0x0c] = usb_lo(id->bcdDevice); ! 41: dest[0x0d] = usb_hi(id->bcdDevice); ! 42: dest[0x0e] = id->iManufacturer; ! 43: dest[0x0f] = id->iProduct; ! 44: dest[0x10] = id->iSerialNumber; ! 45: ! 46: dest[0x11] = dev->bNumConfigurations; ! 47: ! 48: return bLength; ! 49: } ! 50: ! 51: int usb_desc_device_qualifier(const USBDescDevice *dev, ! 52: uint8_t *dest, size_t len) ! 53: { ! 54: uint8_t bLength = 0x0a; ! 55: ! 56: if (len < bLength) { ! 57: return -1; ! 58: } ! 59: ! 60: dest[0x00] = bLength; ! 61: dest[0x01] = USB_DT_DEVICE_QUALIFIER; ! 62: ! 63: dest[0x02] = usb_lo(dev->bcdUSB); ! 64: dest[0x03] = usb_hi(dev->bcdUSB); ! 65: dest[0x04] = dev->bDeviceClass; ! 66: dest[0x05] = dev->bDeviceSubClass; ! 67: dest[0x06] = dev->bDeviceProtocol; ! 68: dest[0x07] = dev->bMaxPacketSize0; ! 69: dest[0x08] = dev->bNumConfigurations; ! 70: dest[0x09] = 0; /* reserved */ ! 71: ! 72: return bLength; ! 73: } ! 74: ! 75: int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) ! 76: { ! 77: uint8_t bLength = 0x09; ! 78: uint16_t wTotalLength = 0; ! 79: int i, rc, count; ! 80: ! 81: if (len < bLength) { ! 82: return -1; ! 83: } ! 84: ! 85: dest[0x00] = bLength; ! 86: dest[0x01] = USB_DT_CONFIG; ! 87: dest[0x04] = conf->bNumInterfaces; ! 88: dest[0x05] = conf->bConfigurationValue; ! 89: dest[0x06] = conf->iConfiguration; ! 90: dest[0x07] = conf->bmAttributes; ! 91: dest[0x08] = conf->bMaxPower; ! 92: wTotalLength += bLength; ! 93: ! 94: count = conf->nif ? conf->nif : conf->bNumInterfaces; ! 95: for (i = 0; i < count; i++) { ! 96: rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength); ! 97: if (rc < 0) { ! 98: return rc; ! 99: } ! 100: wTotalLength += rc; ! 101: } ! 102: ! 103: dest[0x02] = usb_lo(wTotalLength); ! 104: dest[0x03] = usb_hi(wTotalLength); ! 105: return wTotalLength; ! 106: } ! 107: ! 108: int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) ! 109: { ! 110: uint8_t bLength = 0x09; ! 111: int i, rc, pos = 0; ! 112: ! 113: if (len < bLength) { ! 114: return -1; ! 115: } ! 116: ! 117: dest[0x00] = bLength; ! 118: dest[0x01] = USB_DT_INTERFACE; ! 119: dest[0x02] = iface->bInterfaceNumber; ! 120: dest[0x03] = iface->bAlternateSetting; ! 121: dest[0x04] = iface->bNumEndpoints; ! 122: dest[0x05] = iface->bInterfaceClass; ! 123: dest[0x06] = iface->bInterfaceSubClass; ! 124: dest[0x07] = iface->bInterfaceProtocol; ! 125: dest[0x08] = iface->iInterface; ! 126: pos += bLength; ! 127: ! 128: for (i = 0; i < iface->ndesc; i++) { ! 129: rc = usb_desc_other(iface->descs + i, dest + pos, len - pos); ! 130: if (rc < 0) { ! 131: return rc; ! 132: } ! 133: pos += rc; ! 134: } ! 135: ! 136: for (i = 0; i < iface->bNumEndpoints; i++) { ! 137: rc = usb_desc_endpoint(iface->eps + i, dest + pos, len - pos); ! 138: if (rc < 0) { ! 139: return rc; ! 140: } ! 141: pos += rc; ! 142: } ! 143: ! 144: return pos; ! 145: } ! 146: ! 147: int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) ! 148: { ! 149: uint8_t bLength = 0x07; ! 150: ! 151: if (len < bLength) { ! 152: return -1; ! 153: } ! 154: ! 155: dest[0x00] = bLength; ! 156: dest[0x01] = USB_DT_ENDPOINT; ! 157: dest[0x02] = ep->bEndpointAddress; ! 158: dest[0x03] = ep->bmAttributes; ! 159: dest[0x04] = usb_lo(ep->wMaxPacketSize); ! 160: dest[0x05] = usb_hi(ep->wMaxPacketSize); ! 161: dest[0x06] = ep->bInterval; ! 162: ! 163: return bLength; ! 164: } ! 165: ! 166: int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) ! 167: { ! 168: int bLength = desc->length ? desc->length : desc->data[0]; ! 169: ! 170: if (len < bLength) { ! 171: return -1; ! 172: } ! 173: ! 174: memcpy(dest, desc->data, bLength); ! 175: return bLength; ! 176: } ! 177: ! 178: /* ------------------------------------------------------------------ */ ! 179: ! 180: static void usb_desc_setdefaults(USBDevice *dev) ! 181: { ! 182: const USBDesc *desc = dev->info->usb_desc; ! 183: ! 184: assert(desc != NULL); ! 185: switch (dev->speed) { ! 186: case USB_SPEED_LOW: ! 187: case USB_SPEED_FULL: ! 188: dev->device = desc->full; ! 189: break; ! 190: case USB_SPEED_HIGH: ! 191: dev->device = desc->high; ! 192: break; ! 193: } ! 194: dev->config = dev->device->confs; ! 195: } ! 196: ! 197: void usb_desc_init(USBDevice *dev) ! 198: { ! 199: dev->speed = USB_SPEED_FULL; ! 200: usb_desc_setdefaults(dev); ! 201: } ! 202: ! 203: void usb_desc_attach(USBDevice *dev) ! 204: { ! 205: const USBDesc *desc = dev->info->usb_desc; ! 206: ! 207: assert(desc != NULL); ! 208: if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) { ! 209: dev->speed = USB_SPEED_HIGH; ! 210: } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) { ! 211: dev->speed = USB_SPEED_FULL; ! 212: } else { ! 213: fprintf(stderr, "usb: port/device speed mismatch for \"%s\"\n", ! 214: dev->info->product_desc); ! 215: return; ! 216: } ! 217: usb_desc_setdefaults(dev); ! 218: } ! 219: ! 220: void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str) ! 221: { ! 222: USBDescString *s; ! 223: ! 224: QLIST_FOREACH(s, &dev->strings, next) { ! 225: if (s->index == index) { ! 226: break; ! 227: } ! 228: } ! 229: if (s == NULL) { ! 230: s = qemu_mallocz(sizeof(*s)); ! 231: s->index = index; ! 232: QLIST_INSERT_HEAD(&dev->strings, s, next); ! 233: } ! 234: qemu_free(s->str); ! 235: s->str = qemu_strdup(str); ! 236: } ! 237: ! 238: const char *usb_desc_get_string(USBDevice *dev, uint8_t index) ! 239: { ! 240: USBDescString *s; ! 241: ! 242: QLIST_FOREACH(s, &dev->strings, next) { ! 243: if (s->index == index) { ! 244: return s->str; ! 245: } ! 246: } ! 247: return NULL; ! 248: } ! 249: ! 250: int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len) ! 251: { ! 252: uint8_t bLength, pos, i; ! 253: const char *str; ! 254: ! 255: if (len < 4) { ! 256: return -1; ! 257: } ! 258: ! 259: if (index == 0) { ! 260: /* language ids */ ! 261: dest[0] = 4; ! 262: dest[1] = USB_DT_STRING; ! 263: dest[2] = 0x09; ! 264: dest[3] = 0x04; ! 265: return 4; ! 266: } ! 267: ! 268: str = usb_desc_get_string(dev, index); ! 269: if (str == NULL) { ! 270: str = dev->info->usb_desc->str[index]; ! 271: if (str == NULL) { ! 272: return 0; ! 273: } ! 274: } ! 275: ! 276: bLength = strlen(str) * 2 + 2; ! 277: dest[0] = bLength; ! 278: dest[1] = USB_DT_STRING; ! 279: i = 0; pos = 2; ! 280: while (pos+1 < bLength && pos+1 < len) { ! 281: dest[pos++] = str[i++]; ! 282: dest[pos++] = 0; ! 283: } ! 284: return pos; ! 285: } ! 286: ! 287: int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len) ! 288: { ! 289: const USBDesc *desc = dev->info->usb_desc; ! 290: const USBDescDevice *other_dev; ! 291: uint8_t buf[256]; ! 292: uint8_t type = value >> 8; ! 293: uint8_t index = value & 0xff; ! 294: int ret = -1; ! 295: ! 296: if (dev->speed == USB_SPEED_HIGH) { ! 297: other_dev = dev->info->usb_desc->full; ! 298: } else { ! 299: other_dev = dev->info->usb_desc->high; ! 300: } ! 301: ! 302: switch(type) { ! 303: case USB_DT_DEVICE: ! 304: ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf)); ! 305: trace_usb_desc_device(dev->addr, len, ret); ! 306: break; ! 307: case USB_DT_CONFIG: ! 308: if (index < dev->device->bNumConfigurations) { ! 309: ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf)); ! 310: } ! 311: trace_usb_desc_config(dev->addr, index, len, ret); ! 312: break; ! 313: case USB_DT_STRING: ! 314: ret = usb_desc_string(dev, index, buf, sizeof(buf)); ! 315: trace_usb_desc_string(dev->addr, index, len, ret); ! 316: break; ! 317: ! 318: case USB_DT_DEVICE_QUALIFIER: ! 319: if (other_dev != NULL) { ! 320: ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf)); ! 321: } ! 322: trace_usb_desc_device_qualifier(dev->addr, len, ret); ! 323: break; ! 324: case USB_DT_OTHER_SPEED_CONFIG: ! 325: if (other_dev != NULL && index < other_dev->bNumConfigurations) { ! 326: ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf)); ! 327: buf[0x01] = USB_DT_OTHER_SPEED_CONFIG; ! 328: } ! 329: trace_usb_desc_other_speed_config(dev->addr, index, len, ret); ! 330: break; ! 331: ! 332: default: ! 333: fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__, ! 334: dev->addr, type, len); ! 335: break; ! 336: } ! 337: ! 338: if (ret > 0) { ! 339: if (ret > len) { ! 340: ret = len; ! 341: } ! 342: memcpy(dest, buf, ret); ! 343: } ! 344: return ret; ! 345: } ! 346: ! 347: int usb_desc_handle_control(USBDevice *dev, int request, int value, ! 348: int index, int length, uint8_t *data) ! 349: { ! 350: const USBDesc *desc = dev->info->usb_desc; ! 351: int i, ret = -1; ! 352: ! 353: assert(desc != NULL); ! 354: switch(request) { ! 355: case DeviceOutRequest | USB_REQ_SET_ADDRESS: ! 356: dev->addr = value; ! 357: trace_usb_set_addr(dev->addr); ! 358: ret = 0; ! 359: break; ! 360: ! 361: case DeviceRequest | USB_REQ_GET_DESCRIPTOR: ! 362: ret = usb_desc_get_descriptor(dev, value, data, length); ! 363: break; ! 364: ! 365: case DeviceRequest | USB_REQ_GET_CONFIGURATION: ! 366: data[0] = dev->config->bConfigurationValue; ! 367: ret = 1; ! 368: break; ! 369: case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: ! 370: for (i = 0; i < dev->device->bNumConfigurations; i++) { ! 371: if (dev->device->confs[i].bConfigurationValue == value) { ! 372: dev->config = dev->device->confs + i; ! 373: ret = 0; ! 374: } ! 375: } ! 376: trace_usb_set_config(dev->addr, value, ret); ! 377: break; ! 378: ! 379: case DeviceRequest | USB_REQ_GET_STATUS: ! 380: data[0] = 0; ! 381: if (dev->config->bmAttributes & 0x40) { ! 382: data[0] |= 1 << USB_DEVICE_SELF_POWERED; ! 383: } ! 384: if (dev->remote_wakeup) { ! 385: data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP; ! 386: } ! 387: data[1] = 0x00; ! 388: ret = 2; ! 389: break; ! 390: case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: ! 391: if (value == USB_DEVICE_REMOTE_WAKEUP) { ! 392: dev->remote_wakeup = 0; ! 393: ret = 0; ! 394: } ! 395: trace_usb_clear_device_feature(dev->addr, value, ret); ! 396: break; ! 397: case DeviceOutRequest | USB_REQ_SET_FEATURE: ! 398: if (value == USB_DEVICE_REMOTE_WAKEUP) { ! 399: dev->remote_wakeup = 1; ! 400: ret = 0; ! 401: } ! 402: trace_usb_set_device_feature(dev->addr, value, ret); ! 403: break; ! 404: } ! 405: return ret; ! 406: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.