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