19d55d1adSGerd Hoffmann #include <ctype.h> 29d55d1adSGerd Hoffmann 3f1ae32a1SGerd Hoffmann #include "hw/usb.h" 4f1ae32a1SGerd Hoffmann #include "hw/usb/desc.h" 5f1ae32a1SGerd Hoffmann #include "trace.h" 6f1ae32a1SGerd Hoffmann 7f1ae32a1SGerd Hoffmann /* ------------------------------------------------------------------ */ 8f1ae32a1SGerd Hoffmann 9f1ae32a1SGerd Hoffmann static uint8_t usb_lo(uint16_t val) 10f1ae32a1SGerd Hoffmann { 11f1ae32a1SGerd Hoffmann return val & 0xff; 12f1ae32a1SGerd Hoffmann } 13f1ae32a1SGerd Hoffmann 14f1ae32a1SGerd Hoffmann static uint8_t usb_hi(uint16_t val) 15f1ae32a1SGerd Hoffmann { 16f1ae32a1SGerd Hoffmann return (val >> 8) & 0xff; 17f1ae32a1SGerd Hoffmann } 18f1ae32a1SGerd Hoffmann 19f1ae32a1SGerd Hoffmann int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, 20f1ae32a1SGerd Hoffmann uint8_t *dest, size_t len) 21f1ae32a1SGerd Hoffmann { 22f1ae32a1SGerd Hoffmann uint8_t bLength = 0x12; 23d3f904eaSGerd Hoffmann USBDescriptor *d = (void *)dest; 24f1ae32a1SGerd Hoffmann 25f1ae32a1SGerd Hoffmann if (len < bLength) { 26f1ae32a1SGerd Hoffmann return -1; 27f1ae32a1SGerd Hoffmann } 28f1ae32a1SGerd Hoffmann 29d3f904eaSGerd Hoffmann d->bLength = bLength; 30d3f904eaSGerd Hoffmann d->bDescriptorType = USB_DT_DEVICE; 31f1ae32a1SGerd Hoffmann 32d3f904eaSGerd Hoffmann d->u.device.bcdUSB_lo = usb_lo(dev->bcdUSB); 33d3f904eaSGerd Hoffmann d->u.device.bcdUSB_hi = usb_hi(dev->bcdUSB); 34d3f904eaSGerd Hoffmann d->u.device.bDeviceClass = dev->bDeviceClass; 35d3f904eaSGerd Hoffmann d->u.device.bDeviceSubClass = dev->bDeviceSubClass; 36d3f904eaSGerd Hoffmann d->u.device.bDeviceProtocol = dev->bDeviceProtocol; 37d3f904eaSGerd Hoffmann d->u.device.bMaxPacketSize0 = dev->bMaxPacketSize0; 38f1ae32a1SGerd Hoffmann 39d3f904eaSGerd Hoffmann d->u.device.idVendor_lo = usb_lo(id->idVendor); 40d3f904eaSGerd Hoffmann d->u.device.idVendor_hi = usb_hi(id->idVendor); 41d3f904eaSGerd Hoffmann d->u.device.idProduct_lo = usb_lo(id->idProduct); 42d3f904eaSGerd Hoffmann d->u.device.idProduct_hi = usb_hi(id->idProduct); 43d3f904eaSGerd Hoffmann d->u.device.bcdDevice_lo = usb_lo(id->bcdDevice); 44d3f904eaSGerd Hoffmann d->u.device.bcdDevice_hi = usb_hi(id->bcdDevice); 45d3f904eaSGerd Hoffmann d->u.device.iManufacturer = id->iManufacturer; 46d3f904eaSGerd Hoffmann d->u.device.iProduct = id->iProduct; 47d3f904eaSGerd Hoffmann d->u.device.iSerialNumber = id->iSerialNumber; 48f1ae32a1SGerd Hoffmann 49d3f904eaSGerd Hoffmann d->u.device.bNumConfigurations = dev->bNumConfigurations; 50f1ae32a1SGerd Hoffmann 51f1ae32a1SGerd Hoffmann return bLength; 52f1ae32a1SGerd Hoffmann } 53f1ae32a1SGerd Hoffmann 54f1ae32a1SGerd Hoffmann int usb_desc_device_qualifier(const USBDescDevice *dev, 55f1ae32a1SGerd Hoffmann uint8_t *dest, size_t len) 56f1ae32a1SGerd Hoffmann { 57f1ae32a1SGerd Hoffmann uint8_t bLength = 0x0a; 583cfeee61SGerd Hoffmann USBDescriptor *d = (void *)dest; 59f1ae32a1SGerd Hoffmann 60f1ae32a1SGerd Hoffmann if (len < bLength) { 61f1ae32a1SGerd Hoffmann return -1; 62f1ae32a1SGerd Hoffmann } 63f1ae32a1SGerd Hoffmann 643cfeee61SGerd Hoffmann d->bLength = bLength; 653cfeee61SGerd Hoffmann d->bDescriptorType = USB_DT_DEVICE_QUALIFIER; 66f1ae32a1SGerd Hoffmann 673cfeee61SGerd Hoffmann d->u.device_qualifier.bcdUSB_lo = usb_lo(dev->bcdUSB); 683cfeee61SGerd Hoffmann d->u.device_qualifier.bcdUSB_hi = usb_hi(dev->bcdUSB); 693cfeee61SGerd Hoffmann d->u.device_qualifier.bDeviceClass = dev->bDeviceClass; 703cfeee61SGerd Hoffmann d->u.device_qualifier.bDeviceSubClass = dev->bDeviceSubClass; 713cfeee61SGerd Hoffmann d->u.device_qualifier.bDeviceProtocol = dev->bDeviceProtocol; 723cfeee61SGerd Hoffmann d->u.device_qualifier.bMaxPacketSize0 = dev->bMaxPacketSize0; 733cfeee61SGerd Hoffmann d->u.device_qualifier.bNumConfigurations = dev->bNumConfigurations; 743cfeee61SGerd Hoffmann d->u.device_qualifier.bReserved = 0; 75f1ae32a1SGerd Hoffmann 76f1ae32a1SGerd Hoffmann return bLength; 77f1ae32a1SGerd Hoffmann } 78f1ae32a1SGerd Hoffmann 79b43a2851SGerd Hoffmann int usb_desc_config(const USBDescConfig *conf, int flags, 80b43a2851SGerd Hoffmann uint8_t *dest, size_t len) 81f1ae32a1SGerd Hoffmann { 82f1ae32a1SGerd Hoffmann uint8_t bLength = 0x09; 83f1ae32a1SGerd Hoffmann uint16_t wTotalLength = 0; 840a263db1SGerd Hoffmann USBDescriptor *d = (void *)dest; 85f1ae32a1SGerd Hoffmann int i, rc; 86f1ae32a1SGerd Hoffmann 87f1ae32a1SGerd Hoffmann if (len < bLength) { 88f1ae32a1SGerd Hoffmann return -1; 89f1ae32a1SGerd Hoffmann } 90f1ae32a1SGerd Hoffmann 910a263db1SGerd Hoffmann d->bLength = bLength; 920a263db1SGerd Hoffmann d->bDescriptorType = USB_DT_CONFIG; 930a263db1SGerd Hoffmann 940a263db1SGerd Hoffmann d->u.config.bNumInterfaces = conf->bNumInterfaces; 950a263db1SGerd Hoffmann d->u.config.bConfigurationValue = conf->bConfigurationValue; 960a263db1SGerd Hoffmann d->u.config.iConfiguration = conf->iConfiguration; 970a263db1SGerd Hoffmann d->u.config.bmAttributes = conf->bmAttributes; 980a263db1SGerd Hoffmann d->u.config.bMaxPower = conf->bMaxPower; 99f1ae32a1SGerd Hoffmann wTotalLength += bLength; 100f1ae32a1SGerd Hoffmann 101f1ae32a1SGerd Hoffmann /* handle grouped interfaces if any */ 102f1ae32a1SGerd Hoffmann for (i = 0; i < conf->nif_groups; i++) { 103b43a2851SGerd Hoffmann rc = usb_desc_iface_group(&(conf->if_groups[i]), flags, 104f1ae32a1SGerd Hoffmann dest + wTotalLength, 105f1ae32a1SGerd Hoffmann len - wTotalLength); 106f1ae32a1SGerd Hoffmann if (rc < 0) { 107f1ae32a1SGerd Hoffmann return rc; 108f1ae32a1SGerd Hoffmann } 109f1ae32a1SGerd Hoffmann wTotalLength += rc; 110f1ae32a1SGerd Hoffmann } 111f1ae32a1SGerd Hoffmann 112f1ae32a1SGerd Hoffmann /* handle normal (ungrouped / no IAD) interfaces if any */ 113f1ae32a1SGerd Hoffmann for (i = 0; i < conf->nif; i++) { 114b43a2851SGerd Hoffmann rc = usb_desc_iface(conf->ifs + i, flags, 115b43a2851SGerd Hoffmann dest + wTotalLength, len - wTotalLength); 116f1ae32a1SGerd Hoffmann if (rc < 0) { 117f1ae32a1SGerd Hoffmann return rc; 118f1ae32a1SGerd Hoffmann } 119f1ae32a1SGerd Hoffmann wTotalLength += rc; 120f1ae32a1SGerd Hoffmann } 121f1ae32a1SGerd Hoffmann 1220a263db1SGerd Hoffmann d->u.config.wTotalLength_lo = usb_lo(wTotalLength); 1230a263db1SGerd Hoffmann d->u.config.wTotalLength_hi = usb_hi(wTotalLength); 124f1ae32a1SGerd Hoffmann return wTotalLength; 125f1ae32a1SGerd Hoffmann } 126f1ae32a1SGerd Hoffmann 127b43a2851SGerd Hoffmann int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags, 128b43a2851SGerd Hoffmann uint8_t *dest, size_t len) 129f1ae32a1SGerd Hoffmann { 130f1ae32a1SGerd Hoffmann int pos = 0; 131f1ae32a1SGerd Hoffmann int i = 0; 132f1ae32a1SGerd Hoffmann 133f1ae32a1SGerd Hoffmann /* handle interface association descriptor */ 134f1ae32a1SGerd Hoffmann uint8_t bLength = 0x08; 135f1ae32a1SGerd Hoffmann 136f1ae32a1SGerd Hoffmann if (len < bLength) { 137f1ae32a1SGerd Hoffmann return -1; 138f1ae32a1SGerd Hoffmann } 139f1ae32a1SGerd Hoffmann 140f1ae32a1SGerd Hoffmann dest[0x00] = bLength; 141f1ae32a1SGerd Hoffmann dest[0x01] = USB_DT_INTERFACE_ASSOC; 142f1ae32a1SGerd Hoffmann dest[0x02] = iad->bFirstInterface; 143f1ae32a1SGerd Hoffmann dest[0x03] = iad->bInterfaceCount; 144f1ae32a1SGerd Hoffmann dest[0x04] = iad->bFunctionClass; 145f1ae32a1SGerd Hoffmann dest[0x05] = iad->bFunctionSubClass; 146f1ae32a1SGerd Hoffmann dest[0x06] = iad->bFunctionProtocol; 147f1ae32a1SGerd Hoffmann dest[0x07] = iad->iFunction; 148f1ae32a1SGerd Hoffmann pos += bLength; 149f1ae32a1SGerd Hoffmann 150f1ae32a1SGerd Hoffmann /* handle associated interfaces in this group */ 151f1ae32a1SGerd Hoffmann for (i = 0; i < iad->nif; i++) { 152b43a2851SGerd Hoffmann int rc = usb_desc_iface(&(iad->ifs[i]), flags, dest + pos, len - pos); 153f1ae32a1SGerd Hoffmann if (rc < 0) { 154f1ae32a1SGerd Hoffmann return rc; 155f1ae32a1SGerd Hoffmann } 156f1ae32a1SGerd Hoffmann pos += rc; 157f1ae32a1SGerd Hoffmann } 158f1ae32a1SGerd Hoffmann 159f1ae32a1SGerd Hoffmann return pos; 160f1ae32a1SGerd Hoffmann } 161f1ae32a1SGerd Hoffmann 162b43a2851SGerd Hoffmann int usb_desc_iface(const USBDescIface *iface, int flags, 163b43a2851SGerd Hoffmann uint8_t *dest, size_t len) 164f1ae32a1SGerd Hoffmann { 165f1ae32a1SGerd Hoffmann uint8_t bLength = 0x09; 166f1ae32a1SGerd Hoffmann int i, rc, pos = 0; 167feafd797SGerd Hoffmann USBDescriptor *d = (void *)dest; 168f1ae32a1SGerd Hoffmann 169f1ae32a1SGerd Hoffmann if (len < bLength) { 170f1ae32a1SGerd Hoffmann return -1; 171f1ae32a1SGerd Hoffmann } 172f1ae32a1SGerd Hoffmann 173feafd797SGerd Hoffmann d->bLength = bLength; 174feafd797SGerd Hoffmann d->bDescriptorType = USB_DT_INTERFACE; 175feafd797SGerd Hoffmann 176feafd797SGerd Hoffmann d->u.interface.bInterfaceNumber = iface->bInterfaceNumber; 177feafd797SGerd Hoffmann d->u.interface.bAlternateSetting = iface->bAlternateSetting; 178feafd797SGerd Hoffmann d->u.interface.bNumEndpoints = iface->bNumEndpoints; 179feafd797SGerd Hoffmann d->u.interface.bInterfaceClass = iface->bInterfaceClass; 180feafd797SGerd Hoffmann d->u.interface.bInterfaceSubClass = iface->bInterfaceSubClass; 181feafd797SGerd Hoffmann d->u.interface.bInterfaceProtocol = iface->bInterfaceProtocol; 182feafd797SGerd Hoffmann d->u.interface.iInterface = iface->iInterface; 183f1ae32a1SGerd Hoffmann pos += bLength; 184f1ae32a1SGerd Hoffmann 185f1ae32a1SGerd Hoffmann for (i = 0; i < iface->ndesc; i++) { 186f1ae32a1SGerd Hoffmann rc = usb_desc_other(iface->descs + i, dest + pos, len - pos); 187f1ae32a1SGerd Hoffmann if (rc < 0) { 188f1ae32a1SGerd Hoffmann return rc; 189f1ae32a1SGerd Hoffmann } 190f1ae32a1SGerd Hoffmann pos += rc; 191f1ae32a1SGerd Hoffmann } 192f1ae32a1SGerd Hoffmann 193f1ae32a1SGerd Hoffmann for (i = 0; i < iface->bNumEndpoints; i++) { 194b43a2851SGerd Hoffmann rc = usb_desc_endpoint(iface->eps + i, flags, dest + pos, len - pos); 195f1ae32a1SGerd Hoffmann if (rc < 0) { 196f1ae32a1SGerd Hoffmann return rc; 197f1ae32a1SGerd Hoffmann } 198f1ae32a1SGerd Hoffmann pos += rc; 199f1ae32a1SGerd Hoffmann } 200f1ae32a1SGerd Hoffmann 201f1ae32a1SGerd Hoffmann return pos; 202f1ae32a1SGerd Hoffmann } 203f1ae32a1SGerd Hoffmann 204b43a2851SGerd Hoffmann int usb_desc_endpoint(const USBDescEndpoint *ep, int flags, 205b43a2851SGerd Hoffmann uint8_t *dest, size_t len) 206f1ae32a1SGerd Hoffmann { 207f1ae32a1SGerd Hoffmann uint8_t bLength = ep->is_audio ? 0x09 : 0x07; 208f1ae32a1SGerd Hoffmann uint8_t extralen = ep->extra ? ep->extra[0] : 0; 209b43a2851SGerd Hoffmann uint8_t superlen = (flags & USB_DESC_FLAG_SUPER) ? 0x06 : 0; 210e36a20d3SGerd Hoffmann USBDescriptor *d = (void *)dest; 211f1ae32a1SGerd Hoffmann 212b43a2851SGerd Hoffmann if (len < bLength + extralen + superlen) { 213f1ae32a1SGerd Hoffmann return -1; 214f1ae32a1SGerd Hoffmann } 215f1ae32a1SGerd Hoffmann 216e36a20d3SGerd Hoffmann d->bLength = bLength; 217e36a20d3SGerd Hoffmann d->bDescriptorType = USB_DT_ENDPOINT; 218e36a20d3SGerd Hoffmann 219e36a20d3SGerd Hoffmann d->u.endpoint.bEndpointAddress = ep->bEndpointAddress; 220e36a20d3SGerd Hoffmann d->u.endpoint.bmAttributes = ep->bmAttributes; 221e36a20d3SGerd Hoffmann d->u.endpoint.wMaxPacketSize_lo = usb_lo(ep->wMaxPacketSize); 222e36a20d3SGerd Hoffmann d->u.endpoint.wMaxPacketSize_hi = usb_hi(ep->wMaxPacketSize); 223e36a20d3SGerd Hoffmann d->u.endpoint.bInterval = ep->bInterval; 224f1ae32a1SGerd Hoffmann if (ep->is_audio) { 225e36a20d3SGerd Hoffmann d->u.endpoint.bRefresh = ep->bRefresh; 226e36a20d3SGerd Hoffmann d->u.endpoint.bSynchAddress = ep->bSynchAddress; 227f1ae32a1SGerd Hoffmann } 228f1ae32a1SGerd Hoffmann if (ep->extra) { 229f1ae32a1SGerd Hoffmann memcpy(dest + bLength, ep->extra, extralen); 230f1ae32a1SGerd Hoffmann } 231f1ae32a1SGerd Hoffmann 232b43a2851SGerd Hoffmann if (superlen) { 233b43a2851SGerd Hoffmann USBDescriptor *d = (void *)(dest + bLength + extralen); 234b43a2851SGerd Hoffmann 235b43a2851SGerd Hoffmann d->bLength = 0x06; 236b43a2851SGerd Hoffmann d->bDescriptorType = USB_DT_ENDPOINT_COMPANION; 237b43a2851SGerd Hoffmann 238b43a2851SGerd Hoffmann d->u.super_endpoint.bMaxBurst = ep->bMaxBurst; 239b43a2851SGerd Hoffmann d->u.super_endpoint.bmAttributes = ep->bmAttributes_super; 240b43a2851SGerd Hoffmann d->u.super_endpoint.wBytesPerInterval_lo = 241b43a2851SGerd Hoffmann usb_lo(ep->wBytesPerInterval); 242b43a2851SGerd Hoffmann d->u.super_endpoint.wBytesPerInterval_hi = 243b43a2851SGerd Hoffmann usb_hi(ep->wBytesPerInterval); 244b43a2851SGerd Hoffmann } 245b43a2851SGerd Hoffmann 246b43a2851SGerd Hoffmann return bLength + extralen + superlen; 247f1ae32a1SGerd Hoffmann } 248f1ae32a1SGerd Hoffmann 249f1ae32a1SGerd Hoffmann int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) 250f1ae32a1SGerd Hoffmann { 251f1ae32a1SGerd Hoffmann int bLength = desc->length ? desc->length : desc->data[0]; 252f1ae32a1SGerd Hoffmann 253f1ae32a1SGerd Hoffmann if (len < bLength) { 254f1ae32a1SGerd Hoffmann return -1; 255f1ae32a1SGerd Hoffmann } 256f1ae32a1SGerd Hoffmann 257f1ae32a1SGerd Hoffmann memcpy(dest, desc->data, bLength); 258f1ae32a1SGerd Hoffmann return bLength; 259f1ae32a1SGerd Hoffmann } 260f1ae32a1SGerd Hoffmann 261*2077469bSGerd Hoffmann static int usb_desc_cap_usb2_ext(const USBDesc *desc, uint8_t *dest, size_t len) 262*2077469bSGerd Hoffmann { 263*2077469bSGerd Hoffmann uint8_t bLength = 0x07; 264*2077469bSGerd Hoffmann USBDescriptor *d = (void *)dest; 265*2077469bSGerd Hoffmann 266*2077469bSGerd Hoffmann if (len < bLength) { 267*2077469bSGerd Hoffmann return -1; 268*2077469bSGerd Hoffmann } 269*2077469bSGerd Hoffmann 270*2077469bSGerd Hoffmann d->bLength = bLength; 271*2077469bSGerd Hoffmann d->bDescriptorType = USB_DT_DEVICE_CAPABILITY; 272*2077469bSGerd Hoffmann d->u.cap.bDevCapabilityType = USB_DEV_CAP_USB2_EXT; 273*2077469bSGerd Hoffmann 274*2077469bSGerd Hoffmann d->u.cap.u.usb2_ext.bmAttributes_1 = (1 << 1); /* LPM */ 275*2077469bSGerd Hoffmann d->u.cap.u.usb2_ext.bmAttributes_2 = 0; 276*2077469bSGerd Hoffmann d->u.cap.u.usb2_ext.bmAttributes_3 = 0; 277*2077469bSGerd Hoffmann d->u.cap.u.usb2_ext.bmAttributes_4 = 0; 278*2077469bSGerd Hoffmann 279*2077469bSGerd Hoffmann return bLength; 280*2077469bSGerd Hoffmann } 281*2077469bSGerd Hoffmann 282*2077469bSGerd Hoffmann static int usb_desc_cap_super(const USBDesc *desc, uint8_t *dest, size_t len) 283*2077469bSGerd Hoffmann { 284*2077469bSGerd Hoffmann uint8_t bLength = 0x0a; 285*2077469bSGerd Hoffmann USBDescriptor *d = (void *)dest; 286*2077469bSGerd Hoffmann 287*2077469bSGerd Hoffmann if (len < bLength) { 288*2077469bSGerd Hoffmann return -1; 289*2077469bSGerd Hoffmann } 290*2077469bSGerd Hoffmann 291*2077469bSGerd Hoffmann d->bLength = bLength; 292*2077469bSGerd Hoffmann d->bDescriptorType = USB_DT_DEVICE_CAPABILITY; 293*2077469bSGerd Hoffmann d->u.cap.bDevCapabilityType = USB_DEV_CAP_SUPERSPEED; 294*2077469bSGerd Hoffmann 295*2077469bSGerd Hoffmann d->u.cap.u.super.bmAttributes = 0; 296*2077469bSGerd Hoffmann d->u.cap.u.super.wSpeedsSupported_lo = 0; 297*2077469bSGerd Hoffmann d->u.cap.u.super.wSpeedsSupported_hi = 0; 298*2077469bSGerd Hoffmann d->u.cap.u.super.bFunctionalitySupport = 0; 299*2077469bSGerd Hoffmann d->u.cap.u.super.bU1DevExitLat = 0x0a; 300*2077469bSGerd Hoffmann d->u.cap.u.super.wU2DevExitLat_lo = 0x20; 301*2077469bSGerd Hoffmann d->u.cap.u.super.wU2DevExitLat_hi = 0; 302*2077469bSGerd Hoffmann 303*2077469bSGerd Hoffmann if (desc->full) { 304*2077469bSGerd Hoffmann d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 1); 305*2077469bSGerd Hoffmann d->u.cap.u.super.bFunctionalitySupport = 1; 306*2077469bSGerd Hoffmann } 307*2077469bSGerd Hoffmann if (desc->high) { 308*2077469bSGerd Hoffmann d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 2); 309*2077469bSGerd Hoffmann if (!d->u.cap.u.super.bFunctionalitySupport) { 310*2077469bSGerd Hoffmann d->u.cap.u.super.bFunctionalitySupport = 2; 311*2077469bSGerd Hoffmann } 312*2077469bSGerd Hoffmann } 313*2077469bSGerd Hoffmann if (desc->super) { 314*2077469bSGerd Hoffmann d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 3); 315*2077469bSGerd Hoffmann if (!d->u.cap.u.super.bFunctionalitySupport) { 316*2077469bSGerd Hoffmann d->u.cap.u.super.bFunctionalitySupport = 3; 317*2077469bSGerd Hoffmann } 318*2077469bSGerd Hoffmann } 319*2077469bSGerd Hoffmann 320*2077469bSGerd Hoffmann return bLength; 321*2077469bSGerd Hoffmann } 322*2077469bSGerd Hoffmann 323*2077469bSGerd Hoffmann static int usb_desc_bos(const USBDesc *desc, uint8_t *dest, size_t len) 324*2077469bSGerd Hoffmann { 325*2077469bSGerd Hoffmann uint8_t bLength = 0x05; 326*2077469bSGerd Hoffmann uint16_t wTotalLength = 0; 327*2077469bSGerd Hoffmann uint8_t bNumDeviceCaps = 0; 328*2077469bSGerd Hoffmann USBDescriptor *d = (void *)dest; 329*2077469bSGerd Hoffmann int rc; 330*2077469bSGerd Hoffmann 331*2077469bSGerd Hoffmann if (len < bLength) { 332*2077469bSGerd Hoffmann return -1; 333*2077469bSGerd Hoffmann } 334*2077469bSGerd Hoffmann 335*2077469bSGerd Hoffmann d->bLength = bLength; 336*2077469bSGerd Hoffmann d->bDescriptorType = USB_DT_BOS; 337*2077469bSGerd Hoffmann 338*2077469bSGerd Hoffmann wTotalLength += bLength; 339*2077469bSGerd Hoffmann 340*2077469bSGerd Hoffmann if (desc->high != NULL) { 341*2077469bSGerd Hoffmann rc = usb_desc_cap_usb2_ext(desc, dest + wTotalLength, 342*2077469bSGerd Hoffmann len - wTotalLength); 343*2077469bSGerd Hoffmann if (rc < 0) { 344*2077469bSGerd Hoffmann return rc; 345*2077469bSGerd Hoffmann } 346*2077469bSGerd Hoffmann wTotalLength += rc; 347*2077469bSGerd Hoffmann bNumDeviceCaps++; 348*2077469bSGerd Hoffmann } 349*2077469bSGerd Hoffmann 350*2077469bSGerd Hoffmann if (desc->super != NULL) { 351*2077469bSGerd Hoffmann rc = usb_desc_cap_super(desc, dest + wTotalLength, 352*2077469bSGerd Hoffmann len - wTotalLength); 353*2077469bSGerd Hoffmann if (rc < 0) { 354*2077469bSGerd Hoffmann return rc; 355*2077469bSGerd Hoffmann } 356*2077469bSGerd Hoffmann wTotalLength += rc; 357*2077469bSGerd Hoffmann bNumDeviceCaps++; 358*2077469bSGerd Hoffmann } 359*2077469bSGerd Hoffmann 360*2077469bSGerd Hoffmann d->u.bos.wTotalLength_lo = usb_lo(wTotalLength); 361*2077469bSGerd Hoffmann d->u.bos.wTotalLength_hi = usb_hi(wTotalLength); 362*2077469bSGerd Hoffmann d->u.bos.bNumDeviceCaps = bNumDeviceCaps; 363*2077469bSGerd Hoffmann return wTotalLength; 364*2077469bSGerd Hoffmann } 365*2077469bSGerd Hoffmann 366f1ae32a1SGerd Hoffmann /* ------------------------------------------------------------------ */ 367f1ae32a1SGerd Hoffmann 368f1ae32a1SGerd Hoffmann static void usb_desc_ep_init(USBDevice *dev) 369f1ae32a1SGerd Hoffmann { 370f1ae32a1SGerd Hoffmann const USBDescIface *iface; 371f1ae32a1SGerd Hoffmann int i, e, pid, ep; 372f1ae32a1SGerd Hoffmann 373f1ae32a1SGerd Hoffmann usb_ep_init(dev); 374f1ae32a1SGerd Hoffmann for (i = 0; i < dev->ninterfaces; i++) { 375f1ae32a1SGerd Hoffmann iface = dev->ifaces[i]; 376f1ae32a1SGerd Hoffmann if (iface == NULL) { 377f1ae32a1SGerd Hoffmann continue; 378f1ae32a1SGerd Hoffmann } 379f1ae32a1SGerd Hoffmann for (e = 0; e < iface->bNumEndpoints; e++) { 380f1ae32a1SGerd Hoffmann pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ? 381f1ae32a1SGerd Hoffmann USB_TOKEN_IN : USB_TOKEN_OUT; 382f1ae32a1SGerd Hoffmann ep = iface->eps[e].bEndpointAddress & 0x0f; 383f1ae32a1SGerd Hoffmann usb_ep_set_type(dev, pid, ep, iface->eps[e].bmAttributes & 0x03); 384f1ae32a1SGerd Hoffmann usb_ep_set_ifnum(dev, pid, ep, iface->bInterfaceNumber); 385f1ae32a1SGerd Hoffmann usb_ep_set_max_packet_size(dev, pid, ep, 386f1ae32a1SGerd Hoffmann iface->eps[e].wMaxPacketSize); 387f1ae32a1SGerd Hoffmann } 388f1ae32a1SGerd Hoffmann } 389f1ae32a1SGerd Hoffmann } 390f1ae32a1SGerd Hoffmann 391f1ae32a1SGerd Hoffmann static const USBDescIface *usb_desc_find_interface(USBDevice *dev, 392f1ae32a1SGerd Hoffmann int nif, int alt) 393f1ae32a1SGerd Hoffmann { 394f1ae32a1SGerd Hoffmann const USBDescIface *iface; 395f1ae32a1SGerd Hoffmann int g, i; 396f1ae32a1SGerd Hoffmann 397f1ae32a1SGerd Hoffmann if (!dev->config) { 398f1ae32a1SGerd Hoffmann return NULL; 399f1ae32a1SGerd Hoffmann } 400f1ae32a1SGerd Hoffmann for (g = 0; g < dev->config->nif_groups; g++) { 401f1ae32a1SGerd Hoffmann for (i = 0; i < dev->config->if_groups[g].nif; i++) { 402f1ae32a1SGerd Hoffmann iface = &dev->config->if_groups[g].ifs[i]; 403f1ae32a1SGerd Hoffmann if (iface->bInterfaceNumber == nif && 404f1ae32a1SGerd Hoffmann iface->bAlternateSetting == alt) { 405f1ae32a1SGerd Hoffmann return iface; 406f1ae32a1SGerd Hoffmann } 407f1ae32a1SGerd Hoffmann } 408f1ae32a1SGerd Hoffmann } 409f1ae32a1SGerd Hoffmann for (i = 0; i < dev->config->nif; i++) { 410f1ae32a1SGerd Hoffmann iface = &dev->config->ifs[i]; 411f1ae32a1SGerd Hoffmann if (iface->bInterfaceNumber == nif && 412f1ae32a1SGerd Hoffmann iface->bAlternateSetting == alt) { 413f1ae32a1SGerd Hoffmann return iface; 414f1ae32a1SGerd Hoffmann } 415f1ae32a1SGerd Hoffmann } 416f1ae32a1SGerd Hoffmann return NULL; 417f1ae32a1SGerd Hoffmann } 418f1ae32a1SGerd Hoffmann 419f1ae32a1SGerd Hoffmann static int usb_desc_set_interface(USBDevice *dev, int index, int value) 420f1ae32a1SGerd Hoffmann { 421f1ae32a1SGerd Hoffmann const USBDescIface *iface; 422f1ae32a1SGerd Hoffmann int old; 423f1ae32a1SGerd Hoffmann 424f1ae32a1SGerd Hoffmann iface = usb_desc_find_interface(dev, index, value); 425f1ae32a1SGerd Hoffmann if (iface == NULL) { 426f1ae32a1SGerd Hoffmann return -1; 427f1ae32a1SGerd Hoffmann } 428f1ae32a1SGerd Hoffmann 429f1ae32a1SGerd Hoffmann old = dev->altsetting[index]; 430f1ae32a1SGerd Hoffmann dev->altsetting[index] = value; 431f1ae32a1SGerd Hoffmann dev->ifaces[index] = iface; 432f1ae32a1SGerd Hoffmann usb_desc_ep_init(dev); 433f1ae32a1SGerd Hoffmann 434f1ae32a1SGerd Hoffmann if (old != value) { 435f1ae32a1SGerd Hoffmann usb_device_set_interface(dev, index, old, value); 436f1ae32a1SGerd Hoffmann } 437f1ae32a1SGerd Hoffmann return 0; 438f1ae32a1SGerd Hoffmann } 439f1ae32a1SGerd Hoffmann 440f1ae32a1SGerd Hoffmann static int usb_desc_set_config(USBDevice *dev, int value) 441f1ae32a1SGerd Hoffmann { 442f1ae32a1SGerd Hoffmann int i; 443f1ae32a1SGerd Hoffmann 444f1ae32a1SGerd Hoffmann if (value == 0) { 445f1ae32a1SGerd Hoffmann dev->configuration = 0; 446f1ae32a1SGerd Hoffmann dev->ninterfaces = 0; 447f1ae32a1SGerd Hoffmann dev->config = NULL; 448f1ae32a1SGerd Hoffmann } else { 449f1ae32a1SGerd Hoffmann for (i = 0; i < dev->device->bNumConfigurations; i++) { 450f1ae32a1SGerd Hoffmann if (dev->device->confs[i].bConfigurationValue == value) { 451f1ae32a1SGerd Hoffmann dev->configuration = value; 452f1ae32a1SGerd Hoffmann dev->ninterfaces = dev->device->confs[i].bNumInterfaces; 453f1ae32a1SGerd Hoffmann dev->config = dev->device->confs + i; 454f1ae32a1SGerd Hoffmann assert(dev->ninterfaces <= USB_MAX_INTERFACES); 455f1ae32a1SGerd Hoffmann } 456f1ae32a1SGerd Hoffmann } 457f1ae32a1SGerd Hoffmann if (i < dev->device->bNumConfigurations) { 458f1ae32a1SGerd Hoffmann return -1; 459f1ae32a1SGerd Hoffmann } 460f1ae32a1SGerd Hoffmann } 461f1ae32a1SGerd Hoffmann 462f1ae32a1SGerd Hoffmann for (i = 0; i < dev->ninterfaces; i++) { 463f1ae32a1SGerd Hoffmann usb_desc_set_interface(dev, i, 0); 464f1ae32a1SGerd Hoffmann } 465f1ae32a1SGerd Hoffmann for (; i < USB_MAX_INTERFACES; i++) { 466f1ae32a1SGerd Hoffmann dev->altsetting[i] = 0; 467f1ae32a1SGerd Hoffmann dev->ifaces[i] = NULL; 468f1ae32a1SGerd Hoffmann } 469f1ae32a1SGerd Hoffmann 470f1ae32a1SGerd Hoffmann return 0; 471f1ae32a1SGerd Hoffmann } 472f1ae32a1SGerd Hoffmann 473f1ae32a1SGerd Hoffmann static void usb_desc_setdefaults(USBDevice *dev) 474f1ae32a1SGerd Hoffmann { 475f1ae32a1SGerd Hoffmann const USBDesc *desc = usb_device_get_usb_desc(dev); 476f1ae32a1SGerd Hoffmann 477f1ae32a1SGerd Hoffmann assert(desc != NULL); 478f1ae32a1SGerd Hoffmann switch (dev->speed) { 479f1ae32a1SGerd Hoffmann case USB_SPEED_LOW: 480f1ae32a1SGerd Hoffmann case USB_SPEED_FULL: 481f1ae32a1SGerd Hoffmann dev->device = desc->full; 482f1ae32a1SGerd Hoffmann break; 483f1ae32a1SGerd Hoffmann case USB_SPEED_HIGH: 484f1ae32a1SGerd Hoffmann dev->device = desc->high; 485f1ae32a1SGerd Hoffmann break; 4866d51b2bbSGerd Hoffmann case USB_SPEED_SUPER: 4876d51b2bbSGerd Hoffmann dev->device = desc->super; 4886d51b2bbSGerd Hoffmann break; 489f1ae32a1SGerd Hoffmann } 490f1ae32a1SGerd Hoffmann usb_desc_set_config(dev, 0); 491f1ae32a1SGerd Hoffmann } 492f1ae32a1SGerd Hoffmann 493f1ae32a1SGerd Hoffmann void usb_desc_init(USBDevice *dev) 494f1ae32a1SGerd Hoffmann { 495f1ae32a1SGerd Hoffmann const USBDesc *desc = usb_device_get_usb_desc(dev); 496f1ae32a1SGerd Hoffmann 497f1ae32a1SGerd Hoffmann assert(desc != NULL); 498f1ae32a1SGerd Hoffmann dev->speed = USB_SPEED_FULL; 499f1ae32a1SGerd Hoffmann dev->speedmask = 0; 500f1ae32a1SGerd Hoffmann if (desc->full) { 501f1ae32a1SGerd Hoffmann dev->speedmask |= USB_SPEED_MASK_FULL; 502f1ae32a1SGerd Hoffmann } 503f1ae32a1SGerd Hoffmann if (desc->high) { 504f1ae32a1SGerd Hoffmann dev->speedmask |= USB_SPEED_MASK_HIGH; 505f1ae32a1SGerd Hoffmann } 5066d51b2bbSGerd Hoffmann if (desc->super) { 5076d51b2bbSGerd Hoffmann dev->speedmask |= USB_SPEED_MASK_SUPER; 5086d51b2bbSGerd Hoffmann } 509f1ae32a1SGerd Hoffmann usb_desc_setdefaults(dev); 510f1ae32a1SGerd Hoffmann } 511f1ae32a1SGerd Hoffmann 512f1ae32a1SGerd Hoffmann void usb_desc_attach(USBDevice *dev) 513f1ae32a1SGerd Hoffmann { 514f1ae32a1SGerd Hoffmann const USBDesc *desc = usb_device_get_usb_desc(dev); 515f1ae32a1SGerd Hoffmann 516f1ae32a1SGerd Hoffmann assert(desc != NULL); 5176d51b2bbSGerd Hoffmann if (desc->super && (dev->port->speedmask & USB_SPEED_MASK_SUPER)) { 5186d51b2bbSGerd Hoffmann dev->speed = USB_SPEED_SUPER; 5196d51b2bbSGerd Hoffmann } else if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) { 520f1ae32a1SGerd Hoffmann dev->speed = USB_SPEED_HIGH; 521f1ae32a1SGerd Hoffmann } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) { 522f1ae32a1SGerd Hoffmann dev->speed = USB_SPEED_FULL; 523f1ae32a1SGerd Hoffmann } else { 524f1ae32a1SGerd Hoffmann fprintf(stderr, "usb: port/device speed mismatch for \"%s\"\n", 525f1ae32a1SGerd Hoffmann usb_device_get_product_desc(dev)); 526f1ae32a1SGerd Hoffmann return; 527f1ae32a1SGerd Hoffmann } 528f1ae32a1SGerd Hoffmann usb_desc_setdefaults(dev); 529f1ae32a1SGerd Hoffmann } 530f1ae32a1SGerd Hoffmann 531f1ae32a1SGerd Hoffmann void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str) 532f1ae32a1SGerd Hoffmann { 533f1ae32a1SGerd Hoffmann USBDescString *s; 534f1ae32a1SGerd Hoffmann 535f1ae32a1SGerd Hoffmann QLIST_FOREACH(s, &dev->strings, next) { 536f1ae32a1SGerd Hoffmann if (s->index == index) { 537f1ae32a1SGerd Hoffmann break; 538f1ae32a1SGerd Hoffmann } 539f1ae32a1SGerd Hoffmann } 540f1ae32a1SGerd Hoffmann if (s == NULL) { 541f1ae32a1SGerd Hoffmann s = g_malloc0(sizeof(*s)); 542f1ae32a1SGerd Hoffmann s->index = index; 543f1ae32a1SGerd Hoffmann QLIST_INSERT_HEAD(&dev->strings, s, next); 544f1ae32a1SGerd Hoffmann } 545f1ae32a1SGerd Hoffmann g_free(s->str); 546f1ae32a1SGerd Hoffmann s->str = g_strdup(str); 547f1ae32a1SGerd Hoffmann } 548f1ae32a1SGerd Hoffmann 5499d55d1adSGerd Hoffmann /* 5509d55d1adSGerd Hoffmann * This function creates a serial number for a usb device. 5519d55d1adSGerd Hoffmann * The serial number should: 5529d55d1adSGerd Hoffmann * (a) Be unique within the virtual machine. 5539d55d1adSGerd Hoffmann * (b) Be constant, so you don't get a new one each 5549d55d1adSGerd Hoffmann * time the guest is started. 5559d55d1adSGerd Hoffmann * So we are using the physical location to generate a serial number 5569d55d1adSGerd Hoffmann * from it. It has three pieces: First a fixed, device-specific 5579d55d1adSGerd Hoffmann * prefix. Second the device path of the host controller (which is 5589d55d1adSGerd Hoffmann * the pci address in most cases). Third the physical port path. 5599d55d1adSGerd Hoffmann * Results in serial numbers like this: "314159-0000:00:1d.7-3". 5609d55d1adSGerd Hoffmann */ 5619d55d1adSGerd Hoffmann void usb_desc_create_serial(USBDevice *dev) 5629d55d1adSGerd Hoffmann { 5639d55d1adSGerd Hoffmann DeviceState *hcd = dev->qdev.parent_bus->parent; 5649d55d1adSGerd Hoffmann const USBDesc *desc = usb_device_get_usb_desc(dev); 5659d55d1adSGerd Hoffmann int index = desc->id.iSerialNumber; 5669d55d1adSGerd Hoffmann char serial[64]; 56709e5ab63SAnthony Liguori char *path; 5689d55d1adSGerd Hoffmann int dst; 5699d55d1adSGerd Hoffmann 5709d55d1adSGerd Hoffmann assert(index != 0 && desc->str[index] != NULL); 5719d55d1adSGerd Hoffmann dst = snprintf(serial, sizeof(serial), "%s", desc->str[index]); 57209e5ab63SAnthony Liguori path = qdev_get_dev_path(hcd); 57309e5ab63SAnthony Liguori if (path) { 5749d55d1adSGerd Hoffmann dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", path); 5759d55d1adSGerd Hoffmann } 5769d55d1adSGerd Hoffmann dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", dev->port->path); 5779d55d1adSGerd Hoffmann usb_desc_set_string(dev, index, serial); 5789d55d1adSGerd Hoffmann } 5799d55d1adSGerd Hoffmann 580f1ae32a1SGerd Hoffmann const char *usb_desc_get_string(USBDevice *dev, uint8_t index) 581f1ae32a1SGerd Hoffmann { 582f1ae32a1SGerd Hoffmann USBDescString *s; 583f1ae32a1SGerd Hoffmann 584f1ae32a1SGerd Hoffmann QLIST_FOREACH(s, &dev->strings, next) { 585f1ae32a1SGerd Hoffmann if (s->index == index) { 586f1ae32a1SGerd Hoffmann return s->str; 587f1ae32a1SGerd Hoffmann } 588f1ae32a1SGerd Hoffmann } 589f1ae32a1SGerd Hoffmann return NULL; 590f1ae32a1SGerd Hoffmann } 591f1ae32a1SGerd Hoffmann 592f1ae32a1SGerd Hoffmann int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len) 593f1ae32a1SGerd Hoffmann { 594f1ae32a1SGerd Hoffmann uint8_t bLength, pos, i; 595f1ae32a1SGerd Hoffmann const char *str; 596f1ae32a1SGerd Hoffmann 597f1ae32a1SGerd Hoffmann if (len < 4) { 598f1ae32a1SGerd Hoffmann return -1; 599f1ae32a1SGerd Hoffmann } 600f1ae32a1SGerd Hoffmann 601f1ae32a1SGerd Hoffmann if (index == 0) { 602f1ae32a1SGerd Hoffmann /* language ids */ 603f1ae32a1SGerd Hoffmann dest[0] = 4; 604f1ae32a1SGerd Hoffmann dest[1] = USB_DT_STRING; 605f1ae32a1SGerd Hoffmann dest[2] = 0x09; 606f1ae32a1SGerd Hoffmann dest[3] = 0x04; 607f1ae32a1SGerd Hoffmann return 4; 608f1ae32a1SGerd Hoffmann } 609f1ae32a1SGerd Hoffmann 610f1ae32a1SGerd Hoffmann str = usb_desc_get_string(dev, index); 611f1ae32a1SGerd Hoffmann if (str == NULL) { 612f1ae32a1SGerd Hoffmann str = usb_device_get_usb_desc(dev)->str[index]; 613f1ae32a1SGerd Hoffmann if (str == NULL) { 614f1ae32a1SGerd Hoffmann return 0; 615f1ae32a1SGerd Hoffmann } 616f1ae32a1SGerd Hoffmann } 617f1ae32a1SGerd Hoffmann 618f1ae32a1SGerd Hoffmann bLength = strlen(str) * 2 + 2; 619f1ae32a1SGerd Hoffmann dest[0] = bLength; 620f1ae32a1SGerd Hoffmann dest[1] = USB_DT_STRING; 621f1ae32a1SGerd Hoffmann i = 0; pos = 2; 622f1ae32a1SGerd Hoffmann while (pos+1 < bLength && pos+1 < len) { 623f1ae32a1SGerd Hoffmann dest[pos++] = str[i++]; 624f1ae32a1SGerd Hoffmann dest[pos++] = 0; 625f1ae32a1SGerd Hoffmann } 626f1ae32a1SGerd Hoffmann return pos; 627f1ae32a1SGerd Hoffmann } 628f1ae32a1SGerd Hoffmann 629f1ae32a1SGerd Hoffmann int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len) 630f1ae32a1SGerd Hoffmann { 631f1ae32a1SGerd Hoffmann const USBDesc *desc = usb_device_get_usb_desc(dev); 632f1ae32a1SGerd Hoffmann const USBDescDevice *other_dev; 633f1ae32a1SGerd Hoffmann uint8_t buf[256]; 634f1ae32a1SGerd Hoffmann uint8_t type = value >> 8; 635f1ae32a1SGerd Hoffmann uint8_t index = value & 0xff; 636b43a2851SGerd Hoffmann int flags, ret = -1; 637f1ae32a1SGerd Hoffmann 638f1ae32a1SGerd Hoffmann if (dev->speed == USB_SPEED_HIGH) { 639f1ae32a1SGerd Hoffmann other_dev = usb_device_get_usb_desc(dev)->full; 640f1ae32a1SGerd Hoffmann } else { 641f1ae32a1SGerd Hoffmann other_dev = usb_device_get_usb_desc(dev)->high; 642f1ae32a1SGerd Hoffmann } 643f1ae32a1SGerd Hoffmann 644b43a2851SGerd Hoffmann flags = 0; 645b43a2851SGerd Hoffmann if (dev->device->bcdUSB >= 0x0300) { 646b43a2851SGerd Hoffmann flags |= USB_DESC_FLAG_SUPER; 647b43a2851SGerd Hoffmann } 648b43a2851SGerd Hoffmann 649f1ae32a1SGerd Hoffmann switch(type) { 650f1ae32a1SGerd Hoffmann case USB_DT_DEVICE: 651f1ae32a1SGerd Hoffmann ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf)); 652f1ae32a1SGerd Hoffmann trace_usb_desc_device(dev->addr, len, ret); 653f1ae32a1SGerd Hoffmann break; 654f1ae32a1SGerd Hoffmann case USB_DT_CONFIG: 655f1ae32a1SGerd Hoffmann if (index < dev->device->bNumConfigurations) { 656b43a2851SGerd Hoffmann ret = usb_desc_config(dev->device->confs + index, flags, 657b43a2851SGerd Hoffmann buf, sizeof(buf)); 658f1ae32a1SGerd Hoffmann } 659f1ae32a1SGerd Hoffmann trace_usb_desc_config(dev->addr, index, len, ret); 660f1ae32a1SGerd Hoffmann break; 661f1ae32a1SGerd Hoffmann case USB_DT_STRING: 662f1ae32a1SGerd Hoffmann ret = usb_desc_string(dev, index, buf, sizeof(buf)); 663f1ae32a1SGerd Hoffmann trace_usb_desc_string(dev->addr, index, len, ret); 664f1ae32a1SGerd Hoffmann break; 665f1ae32a1SGerd Hoffmann case USB_DT_DEVICE_QUALIFIER: 666f1ae32a1SGerd Hoffmann if (other_dev != NULL) { 667f1ae32a1SGerd Hoffmann ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf)); 668f1ae32a1SGerd Hoffmann } 669f1ae32a1SGerd Hoffmann trace_usb_desc_device_qualifier(dev->addr, len, ret); 670f1ae32a1SGerd Hoffmann break; 671f1ae32a1SGerd Hoffmann case USB_DT_OTHER_SPEED_CONFIG: 672f1ae32a1SGerd Hoffmann if (other_dev != NULL && index < other_dev->bNumConfigurations) { 673b43a2851SGerd Hoffmann ret = usb_desc_config(other_dev->confs + index, flags, 674b43a2851SGerd Hoffmann buf, sizeof(buf)); 675f1ae32a1SGerd Hoffmann buf[0x01] = USB_DT_OTHER_SPEED_CONFIG; 676f1ae32a1SGerd Hoffmann } 677f1ae32a1SGerd Hoffmann trace_usb_desc_other_speed_config(dev->addr, index, len, ret); 678f1ae32a1SGerd Hoffmann break; 679*2077469bSGerd Hoffmann case USB_DT_BOS: 680*2077469bSGerd Hoffmann ret = usb_desc_bos(desc, buf, sizeof(buf)); 681*2077469bSGerd Hoffmann trace_usb_desc_bos(dev->addr, len, ret); 682*2077469bSGerd Hoffmann break; 683f1ae32a1SGerd Hoffmann 684f1ae32a1SGerd Hoffmann case USB_DT_DEBUG: 685f1ae32a1SGerd Hoffmann /* ignore silently */ 686f1ae32a1SGerd Hoffmann break; 687f1ae32a1SGerd Hoffmann 688f1ae32a1SGerd Hoffmann default: 689f1ae32a1SGerd Hoffmann fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__, 690f1ae32a1SGerd Hoffmann dev->addr, type, len); 691f1ae32a1SGerd Hoffmann break; 692f1ae32a1SGerd Hoffmann } 693f1ae32a1SGerd Hoffmann 694f1ae32a1SGerd Hoffmann if (ret > 0) { 695f1ae32a1SGerd Hoffmann if (ret > len) { 696f1ae32a1SGerd Hoffmann ret = len; 697f1ae32a1SGerd Hoffmann } 698f1ae32a1SGerd Hoffmann memcpy(dest, buf, ret); 699f1ae32a1SGerd Hoffmann } 700f1ae32a1SGerd Hoffmann return ret; 701f1ae32a1SGerd Hoffmann } 702f1ae32a1SGerd Hoffmann 703f1ae32a1SGerd Hoffmann int usb_desc_handle_control(USBDevice *dev, USBPacket *p, 704f1ae32a1SGerd Hoffmann int request, int value, int index, int length, uint8_t *data) 705f1ae32a1SGerd Hoffmann { 706f1ae32a1SGerd Hoffmann const USBDesc *desc = usb_device_get_usb_desc(dev); 707f1ae32a1SGerd Hoffmann int ret = -1; 708f1ae32a1SGerd Hoffmann 709f1ae32a1SGerd Hoffmann assert(desc != NULL); 710f1ae32a1SGerd Hoffmann switch(request) { 711f1ae32a1SGerd Hoffmann case DeviceOutRequest | USB_REQ_SET_ADDRESS: 712f1ae32a1SGerd Hoffmann dev->addr = value; 713f1ae32a1SGerd Hoffmann trace_usb_set_addr(dev->addr); 714f1ae32a1SGerd Hoffmann ret = 0; 715f1ae32a1SGerd Hoffmann break; 716f1ae32a1SGerd Hoffmann 717f1ae32a1SGerd Hoffmann case DeviceRequest | USB_REQ_GET_DESCRIPTOR: 718f1ae32a1SGerd Hoffmann ret = usb_desc_get_descriptor(dev, value, data, length); 719f1ae32a1SGerd Hoffmann break; 720f1ae32a1SGerd Hoffmann 721f1ae32a1SGerd Hoffmann case DeviceRequest | USB_REQ_GET_CONFIGURATION: 722f1ae32a1SGerd Hoffmann /* 723f1ae32a1SGerd Hoffmann * 9.4.2: 0 should be returned if the device is unconfigured, otherwise 724f1ae32a1SGerd Hoffmann * the non zero value of bConfigurationValue. 725f1ae32a1SGerd Hoffmann */ 726f1ae32a1SGerd Hoffmann data[0] = dev->config ? dev->config->bConfigurationValue : 0; 727f1ae32a1SGerd Hoffmann ret = 1; 728f1ae32a1SGerd Hoffmann break; 729f1ae32a1SGerd Hoffmann case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: 730f1ae32a1SGerd Hoffmann ret = usb_desc_set_config(dev, value); 731f1ae32a1SGerd Hoffmann trace_usb_set_config(dev->addr, value, ret); 732f1ae32a1SGerd Hoffmann break; 733f1ae32a1SGerd Hoffmann 734f1ae32a1SGerd Hoffmann case DeviceRequest | USB_REQ_GET_STATUS: { 735f1ae32a1SGerd Hoffmann const USBDescConfig *config = dev->config ? 736f1ae32a1SGerd Hoffmann dev->config : &dev->device->confs[0]; 737f1ae32a1SGerd Hoffmann 738f1ae32a1SGerd Hoffmann data[0] = 0; 739f1ae32a1SGerd Hoffmann /* 740f1ae32a1SGerd Hoffmann * Default state: Device behavior when this request is received while 741f1ae32a1SGerd Hoffmann * the device is in the Default state is not specified. 742f1ae32a1SGerd Hoffmann * We return the same value that a configured device would return if 743f1ae32a1SGerd Hoffmann * it used the first configuration. 744f1ae32a1SGerd Hoffmann */ 745f1ae32a1SGerd Hoffmann if (config->bmAttributes & 0x40) { 746f1ae32a1SGerd Hoffmann data[0] |= 1 << USB_DEVICE_SELF_POWERED; 747f1ae32a1SGerd Hoffmann } 748f1ae32a1SGerd Hoffmann if (dev->remote_wakeup) { 749f1ae32a1SGerd Hoffmann data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP; 750f1ae32a1SGerd Hoffmann } 751f1ae32a1SGerd Hoffmann data[1] = 0x00; 752f1ae32a1SGerd Hoffmann ret = 2; 753f1ae32a1SGerd Hoffmann break; 754f1ae32a1SGerd Hoffmann } 755f1ae32a1SGerd Hoffmann case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: 756f1ae32a1SGerd Hoffmann if (value == USB_DEVICE_REMOTE_WAKEUP) { 757f1ae32a1SGerd Hoffmann dev->remote_wakeup = 0; 758f1ae32a1SGerd Hoffmann ret = 0; 759f1ae32a1SGerd Hoffmann } 760f1ae32a1SGerd Hoffmann trace_usb_clear_device_feature(dev->addr, value, ret); 761f1ae32a1SGerd Hoffmann break; 762f1ae32a1SGerd Hoffmann case DeviceOutRequest | USB_REQ_SET_FEATURE: 763f1ae32a1SGerd Hoffmann if (value == USB_DEVICE_REMOTE_WAKEUP) { 764f1ae32a1SGerd Hoffmann dev->remote_wakeup = 1; 765f1ae32a1SGerd Hoffmann ret = 0; 766f1ae32a1SGerd Hoffmann } 767f1ae32a1SGerd Hoffmann trace_usb_set_device_feature(dev->addr, value, ret); 768f1ae32a1SGerd Hoffmann break; 769f1ae32a1SGerd Hoffmann 770f1ae32a1SGerd Hoffmann case InterfaceRequest | USB_REQ_GET_INTERFACE: 771f1ae32a1SGerd Hoffmann if (index < 0 || index >= dev->ninterfaces) { 772f1ae32a1SGerd Hoffmann break; 773f1ae32a1SGerd Hoffmann } 774f1ae32a1SGerd Hoffmann data[0] = dev->altsetting[index]; 775f1ae32a1SGerd Hoffmann ret = 1; 776f1ae32a1SGerd Hoffmann break; 777f1ae32a1SGerd Hoffmann case InterfaceOutRequest | USB_REQ_SET_INTERFACE: 778f1ae32a1SGerd Hoffmann ret = usb_desc_set_interface(dev, index, value); 779f1ae32a1SGerd Hoffmann trace_usb_set_interface(dev->addr, index, value, ret); 780f1ae32a1SGerd Hoffmann break; 781f1ae32a1SGerd Hoffmann 782f1ae32a1SGerd Hoffmann } 783f1ae32a1SGerd Hoffmann return ret; 784f1ae32a1SGerd Hoffmann } 785