1e532b2e0SPeter Maydell #include "qemu/osdep.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 int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, 105319dc7bSGerd Hoffmann bool msos, uint8_t *dest, size_t len) 11f1ae32a1SGerd Hoffmann { 12f1ae32a1SGerd Hoffmann uint8_t bLength = 0x12; 13d3f904eaSGerd Hoffmann USBDescriptor *d = (void *)dest; 14f1ae32a1SGerd Hoffmann 15f1ae32a1SGerd Hoffmann if (len < bLength) { 16f1ae32a1SGerd Hoffmann return -1; 17f1ae32a1SGerd Hoffmann } 18f1ae32a1SGerd Hoffmann 19d3f904eaSGerd Hoffmann d->bLength = bLength; 20d3f904eaSGerd Hoffmann d->bDescriptorType = USB_DT_DEVICE; 21f1ae32a1SGerd Hoffmann 225319dc7bSGerd Hoffmann if (msos && dev->bcdUSB < 0x0200) { 235319dc7bSGerd Hoffmann /* 245319dc7bSGerd Hoffmann * Version 2.0+ required for microsoft os descriptors to work. 255319dc7bSGerd Hoffmann * Done this way so msos-desc compat property will handle both 265319dc7bSGerd Hoffmann * the version and the new descriptors being present. 275319dc7bSGerd Hoffmann */ 285319dc7bSGerd Hoffmann d->u.device.bcdUSB_lo = usb_lo(0x0200); 295319dc7bSGerd Hoffmann d->u.device.bcdUSB_hi = usb_hi(0x0200); 305319dc7bSGerd Hoffmann } else { 31d3f904eaSGerd Hoffmann d->u.device.bcdUSB_lo = usb_lo(dev->bcdUSB); 32d3f904eaSGerd Hoffmann d->u.device.bcdUSB_hi = usb_hi(dev->bcdUSB); 335319dc7bSGerd Hoffmann } 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 229b43a2851SGerd Hoffmann if (superlen) { 2302e5df36dSGerd Hoffmann USBDescriptor *d = (void *)(dest + bLength); 231b43a2851SGerd Hoffmann 232b43a2851SGerd Hoffmann d->bLength = 0x06; 233b43a2851SGerd Hoffmann d->bDescriptorType = USB_DT_ENDPOINT_COMPANION; 234b43a2851SGerd Hoffmann 235b43a2851SGerd Hoffmann d->u.super_endpoint.bMaxBurst = ep->bMaxBurst; 236b43a2851SGerd Hoffmann d->u.super_endpoint.bmAttributes = ep->bmAttributes_super; 237b43a2851SGerd Hoffmann d->u.super_endpoint.wBytesPerInterval_lo = 238b43a2851SGerd Hoffmann usb_lo(ep->wBytesPerInterval); 239b43a2851SGerd Hoffmann d->u.super_endpoint.wBytesPerInterval_hi = 240b43a2851SGerd Hoffmann usb_hi(ep->wBytesPerInterval); 241b43a2851SGerd Hoffmann } 242b43a2851SGerd Hoffmann 2432e5df36dSGerd Hoffmann if (ep->extra) { 2442e5df36dSGerd Hoffmann memcpy(dest + bLength + superlen, ep->extra, extralen); 2452e5df36dSGerd Hoffmann } 2462e5df36dSGerd Hoffmann 247b43a2851SGerd Hoffmann return bLength + extralen + superlen; 248f1ae32a1SGerd Hoffmann } 249f1ae32a1SGerd Hoffmann 250f1ae32a1SGerd Hoffmann int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) 251f1ae32a1SGerd Hoffmann { 252f1ae32a1SGerd Hoffmann int bLength = desc->length ? desc->length : desc->data[0]; 253f1ae32a1SGerd Hoffmann 254f1ae32a1SGerd Hoffmann if (len < bLength) { 255f1ae32a1SGerd Hoffmann return -1; 256f1ae32a1SGerd Hoffmann } 257f1ae32a1SGerd Hoffmann 258f1ae32a1SGerd Hoffmann memcpy(dest, desc->data, bLength); 259f1ae32a1SGerd Hoffmann return bLength; 260f1ae32a1SGerd Hoffmann } 261f1ae32a1SGerd Hoffmann 2622077469bSGerd Hoffmann static int usb_desc_cap_usb2_ext(const USBDesc *desc, uint8_t *dest, size_t len) 2632077469bSGerd Hoffmann { 2642077469bSGerd Hoffmann uint8_t bLength = 0x07; 2652077469bSGerd Hoffmann USBDescriptor *d = (void *)dest; 2662077469bSGerd Hoffmann 2672077469bSGerd Hoffmann if (len < bLength) { 2682077469bSGerd Hoffmann return -1; 2692077469bSGerd Hoffmann } 2702077469bSGerd Hoffmann 2712077469bSGerd Hoffmann d->bLength = bLength; 2722077469bSGerd Hoffmann d->bDescriptorType = USB_DT_DEVICE_CAPABILITY; 2732077469bSGerd Hoffmann d->u.cap.bDevCapabilityType = USB_DEV_CAP_USB2_EXT; 2742077469bSGerd Hoffmann 2752077469bSGerd Hoffmann d->u.cap.u.usb2_ext.bmAttributes_1 = (1 << 1); /* LPM */ 2762077469bSGerd Hoffmann d->u.cap.u.usb2_ext.bmAttributes_2 = 0; 2772077469bSGerd Hoffmann d->u.cap.u.usb2_ext.bmAttributes_3 = 0; 2782077469bSGerd Hoffmann d->u.cap.u.usb2_ext.bmAttributes_4 = 0; 2792077469bSGerd Hoffmann 2802077469bSGerd Hoffmann return bLength; 2812077469bSGerd Hoffmann } 2822077469bSGerd Hoffmann 2832077469bSGerd Hoffmann static int usb_desc_cap_super(const USBDesc *desc, uint8_t *dest, size_t len) 2842077469bSGerd Hoffmann { 2852077469bSGerd Hoffmann uint8_t bLength = 0x0a; 2862077469bSGerd Hoffmann USBDescriptor *d = (void *)dest; 2872077469bSGerd Hoffmann 2882077469bSGerd Hoffmann if (len < bLength) { 2892077469bSGerd Hoffmann return -1; 2902077469bSGerd Hoffmann } 2912077469bSGerd Hoffmann 2922077469bSGerd Hoffmann d->bLength = bLength; 2932077469bSGerd Hoffmann d->bDescriptorType = USB_DT_DEVICE_CAPABILITY; 2942077469bSGerd Hoffmann d->u.cap.bDevCapabilityType = USB_DEV_CAP_SUPERSPEED; 2952077469bSGerd Hoffmann 2962077469bSGerd Hoffmann d->u.cap.u.super.bmAttributes = 0; 2972077469bSGerd Hoffmann d->u.cap.u.super.wSpeedsSupported_lo = 0; 2982077469bSGerd Hoffmann d->u.cap.u.super.wSpeedsSupported_hi = 0; 2992077469bSGerd Hoffmann d->u.cap.u.super.bFunctionalitySupport = 0; 3002077469bSGerd Hoffmann d->u.cap.u.super.bU1DevExitLat = 0x0a; 3012077469bSGerd Hoffmann d->u.cap.u.super.wU2DevExitLat_lo = 0x20; 3022077469bSGerd Hoffmann d->u.cap.u.super.wU2DevExitLat_hi = 0; 3032077469bSGerd Hoffmann 3042077469bSGerd Hoffmann if (desc->full) { 3052077469bSGerd Hoffmann d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 1); 3062077469bSGerd Hoffmann d->u.cap.u.super.bFunctionalitySupport = 1; 3072077469bSGerd Hoffmann } 3082077469bSGerd Hoffmann if (desc->high) { 3092077469bSGerd Hoffmann d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 2); 3102077469bSGerd Hoffmann if (!d->u.cap.u.super.bFunctionalitySupport) { 3112077469bSGerd Hoffmann d->u.cap.u.super.bFunctionalitySupport = 2; 3122077469bSGerd Hoffmann } 3132077469bSGerd Hoffmann } 3142077469bSGerd Hoffmann if (desc->super) { 3152077469bSGerd Hoffmann d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 3); 3162077469bSGerd Hoffmann if (!d->u.cap.u.super.bFunctionalitySupport) { 3172077469bSGerd Hoffmann d->u.cap.u.super.bFunctionalitySupport = 3; 3182077469bSGerd Hoffmann } 3192077469bSGerd Hoffmann } 3202077469bSGerd Hoffmann 3212077469bSGerd Hoffmann return bLength; 3222077469bSGerd Hoffmann } 3232077469bSGerd Hoffmann 3242077469bSGerd Hoffmann static int usb_desc_bos(const USBDesc *desc, uint8_t *dest, size_t len) 3252077469bSGerd Hoffmann { 3262077469bSGerd Hoffmann uint8_t bLength = 0x05; 3272077469bSGerd Hoffmann uint16_t wTotalLength = 0; 3282077469bSGerd Hoffmann uint8_t bNumDeviceCaps = 0; 3292077469bSGerd Hoffmann USBDescriptor *d = (void *)dest; 3302077469bSGerd Hoffmann int rc; 3312077469bSGerd Hoffmann 3322077469bSGerd Hoffmann if (len < bLength) { 3332077469bSGerd Hoffmann return -1; 3342077469bSGerd Hoffmann } 3352077469bSGerd Hoffmann 3362077469bSGerd Hoffmann d->bLength = bLength; 3372077469bSGerd Hoffmann d->bDescriptorType = USB_DT_BOS; 3382077469bSGerd Hoffmann 3392077469bSGerd Hoffmann wTotalLength += bLength; 3402077469bSGerd Hoffmann 3412077469bSGerd Hoffmann if (desc->high != NULL) { 3422077469bSGerd Hoffmann rc = usb_desc_cap_usb2_ext(desc, dest + wTotalLength, 3432077469bSGerd Hoffmann len - wTotalLength); 3442077469bSGerd Hoffmann if (rc < 0) { 3452077469bSGerd Hoffmann return rc; 3462077469bSGerd Hoffmann } 3472077469bSGerd Hoffmann wTotalLength += rc; 3482077469bSGerd Hoffmann bNumDeviceCaps++; 3492077469bSGerd Hoffmann } 3502077469bSGerd Hoffmann 3512077469bSGerd Hoffmann if (desc->super != NULL) { 3522077469bSGerd Hoffmann rc = usb_desc_cap_super(desc, dest + wTotalLength, 3532077469bSGerd Hoffmann len - wTotalLength); 3542077469bSGerd Hoffmann if (rc < 0) { 3552077469bSGerd Hoffmann return rc; 3562077469bSGerd Hoffmann } 3572077469bSGerd Hoffmann wTotalLength += rc; 3582077469bSGerd Hoffmann bNumDeviceCaps++; 3592077469bSGerd Hoffmann } 3602077469bSGerd Hoffmann 3612077469bSGerd Hoffmann d->u.bos.wTotalLength_lo = usb_lo(wTotalLength); 3622077469bSGerd Hoffmann d->u.bos.wTotalLength_hi = usb_hi(wTotalLength); 3632077469bSGerd Hoffmann d->u.bos.bNumDeviceCaps = bNumDeviceCaps; 3642077469bSGerd Hoffmann return wTotalLength; 3652077469bSGerd Hoffmann } 3662077469bSGerd Hoffmann 367f1ae32a1SGerd Hoffmann /* ------------------------------------------------------------------ */ 368f1ae32a1SGerd Hoffmann 369f1ae32a1SGerd Hoffmann static void usb_desc_ep_init(USBDevice *dev) 370f1ae32a1SGerd Hoffmann { 371f1ae32a1SGerd Hoffmann const USBDescIface *iface; 372f1ae32a1SGerd Hoffmann int i, e, pid, ep; 373f1ae32a1SGerd Hoffmann 374f1ae32a1SGerd Hoffmann usb_ep_init(dev); 375f1ae32a1SGerd Hoffmann for (i = 0; i < dev->ninterfaces; i++) { 376f1ae32a1SGerd Hoffmann iface = dev->ifaces[i]; 377f1ae32a1SGerd Hoffmann if (iface == NULL) { 378f1ae32a1SGerd Hoffmann continue; 379f1ae32a1SGerd Hoffmann } 380f1ae32a1SGerd Hoffmann for (e = 0; e < iface->bNumEndpoints; e++) { 381f1ae32a1SGerd Hoffmann pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ? 382f1ae32a1SGerd Hoffmann USB_TOKEN_IN : USB_TOKEN_OUT; 383f1ae32a1SGerd Hoffmann ep = iface->eps[e].bEndpointAddress & 0x0f; 384f1ae32a1SGerd Hoffmann usb_ep_set_type(dev, pid, ep, iface->eps[e].bmAttributes & 0x03); 385f1ae32a1SGerd Hoffmann usb_ep_set_ifnum(dev, pid, ep, iface->bInterfaceNumber); 386f1ae32a1SGerd Hoffmann usb_ep_set_max_packet_size(dev, pid, ep, 387f1ae32a1SGerd Hoffmann iface->eps[e].wMaxPacketSize); 38804b300f8SHans de Goede usb_ep_set_max_streams(dev, pid, ep, 38904b300f8SHans de Goede iface->eps[e].bmAttributes_super); 390f1ae32a1SGerd Hoffmann } 391f1ae32a1SGerd Hoffmann } 392f1ae32a1SGerd Hoffmann } 393f1ae32a1SGerd Hoffmann 394f1ae32a1SGerd Hoffmann static const USBDescIface *usb_desc_find_interface(USBDevice *dev, 395f1ae32a1SGerd Hoffmann int nif, int alt) 396f1ae32a1SGerd Hoffmann { 397f1ae32a1SGerd Hoffmann const USBDescIface *iface; 398f1ae32a1SGerd Hoffmann int g, i; 399f1ae32a1SGerd Hoffmann 400f1ae32a1SGerd Hoffmann if (!dev->config) { 401f1ae32a1SGerd Hoffmann return NULL; 402f1ae32a1SGerd Hoffmann } 403f1ae32a1SGerd Hoffmann for (g = 0; g < dev->config->nif_groups; g++) { 404f1ae32a1SGerd Hoffmann for (i = 0; i < dev->config->if_groups[g].nif; i++) { 405f1ae32a1SGerd Hoffmann iface = &dev->config->if_groups[g].ifs[i]; 406f1ae32a1SGerd Hoffmann if (iface->bInterfaceNumber == nif && 407f1ae32a1SGerd Hoffmann iface->bAlternateSetting == alt) { 408f1ae32a1SGerd Hoffmann return iface; 409f1ae32a1SGerd Hoffmann } 410f1ae32a1SGerd Hoffmann } 411f1ae32a1SGerd Hoffmann } 412f1ae32a1SGerd Hoffmann for (i = 0; i < dev->config->nif; i++) { 413f1ae32a1SGerd Hoffmann iface = &dev->config->ifs[i]; 414f1ae32a1SGerd Hoffmann if (iface->bInterfaceNumber == nif && 415f1ae32a1SGerd Hoffmann iface->bAlternateSetting == alt) { 416f1ae32a1SGerd Hoffmann return iface; 417f1ae32a1SGerd Hoffmann } 418f1ae32a1SGerd Hoffmann } 419f1ae32a1SGerd Hoffmann return NULL; 420f1ae32a1SGerd Hoffmann } 421f1ae32a1SGerd Hoffmann 422f1ae32a1SGerd Hoffmann static int usb_desc_set_interface(USBDevice *dev, int index, int value) 423f1ae32a1SGerd Hoffmann { 424f1ae32a1SGerd Hoffmann const USBDescIface *iface; 425f1ae32a1SGerd Hoffmann int old; 426f1ae32a1SGerd Hoffmann 427f1ae32a1SGerd Hoffmann iface = usb_desc_find_interface(dev, index, value); 428f1ae32a1SGerd Hoffmann if (iface == NULL) { 429f1ae32a1SGerd Hoffmann return -1; 430f1ae32a1SGerd Hoffmann } 431f1ae32a1SGerd Hoffmann 432f1ae32a1SGerd Hoffmann old = dev->altsetting[index]; 433f1ae32a1SGerd Hoffmann dev->altsetting[index] = value; 434f1ae32a1SGerd Hoffmann dev->ifaces[index] = iface; 435f1ae32a1SGerd Hoffmann usb_desc_ep_init(dev); 436f1ae32a1SGerd Hoffmann 437f1ae32a1SGerd Hoffmann if (old != value) { 438f1ae32a1SGerd Hoffmann usb_device_set_interface(dev, index, old, value); 439f1ae32a1SGerd Hoffmann } 440f1ae32a1SGerd Hoffmann return 0; 441f1ae32a1SGerd Hoffmann } 442f1ae32a1SGerd Hoffmann 443f1ae32a1SGerd Hoffmann static int usb_desc_set_config(USBDevice *dev, int value) 444f1ae32a1SGerd Hoffmann { 445f1ae32a1SGerd Hoffmann int i; 446f1ae32a1SGerd Hoffmann 447f1ae32a1SGerd Hoffmann if (value == 0) { 448f1ae32a1SGerd Hoffmann dev->configuration = 0; 449f1ae32a1SGerd Hoffmann dev->ninterfaces = 0; 450f1ae32a1SGerd Hoffmann dev->config = NULL; 451f1ae32a1SGerd Hoffmann } else { 452f1ae32a1SGerd Hoffmann for (i = 0; i < dev->device->bNumConfigurations; i++) { 453f1ae32a1SGerd Hoffmann if (dev->device->confs[i].bConfigurationValue == value) { 454f1ae32a1SGerd Hoffmann dev->configuration = value; 455f1ae32a1SGerd Hoffmann dev->ninterfaces = dev->device->confs[i].bNumInterfaces; 456f1ae32a1SGerd Hoffmann dev->config = dev->device->confs + i; 457f1ae32a1SGerd Hoffmann assert(dev->ninterfaces <= USB_MAX_INTERFACES); 458f1ae32a1SGerd Hoffmann } 459f1ae32a1SGerd Hoffmann } 460f1ae32a1SGerd Hoffmann if (i < dev->device->bNumConfigurations) { 461f1ae32a1SGerd Hoffmann return -1; 462f1ae32a1SGerd Hoffmann } 463f1ae32a1SGerd Hoffmann } 464f1ae32a1SGerd Hoffmann 465f1ae32a1SGerd Hoffmann for (i = 0; i < dev->ninterfaces; i++) { 466f1ae32a1SGerd Hoffmann usb_desc_set_interface(dev, i, 0); 467f1ae32a1SGerd Hoffmann } 468f1ae32a1SGerd Hoffmann for (; i < USB_MAX_INTERFACES; i++) { 469f1ae32a1SGerd Hoffmann dev->altsetting[i] = 0; 470f1ae32a1SGerd Hoffmann dev->ifaces[i] = NULL; 471f1ae32a1SGerd Hoffmann } 472f1ae32a1SGerd Hoffmann 473f1ae32a1SGerd Hoffmann return 0; 474f1ae32a1SGerd Hoffmann } 475f1ae32a1SGerd Hoffmann 476f1ae32a1SGerd Hoffmann static void usb_desc_setdefaults(USBDevice *dev) 477f1ae32a1SGerd Hoffmann { 478f1ae32a1SGerd Hoffmann const USBDesc *desc = usb_device_get_usb_desc(dev); 479f1ae32a1SGerd Hoffmann 480f1ae32a1SGerd Hoffmann assert(desc != NULL); 481f1ae32a1SGerd Hoffmann switch (dev->speed) { 482f1ae32a1SGerd Hoffmann case USB_SPEED_LOW: 483f1ae32a1SGerd Hoffmann case USB_SPEED_FULL: 484f1ae32a1SGerd Hoffmann dev->device = desc->full; 485f1ae32a1SGerd Hoffmann break; 486f1ae32a1SGerd Hoffmann case USB_SPEED_HIGH: 487f1ae32a1SGerd Hoffmann dev->device = desc->high; 488f1ae32a1SGerd Hoffmann break; 4896d51b2bbSGerd Hoffmann case USB_SPEED_SUPER: 4906d51b2bbSGerd Hoffmann dev->device = desc->super; 4916d51b2bbSGerd Hoffmann break; 492f1ae32a1SGerd Hoffmann } 493f1ae32a1SGerd Hoffmann usb_desc_set_config(dev, 0); 494f1ae32a1SGerd Hoffmann } 495f1ae32a1SGerd Hoffmann 496f1ae32a1SGerd Hoffmann void usb_desc_init(USBDevice *dev) 497f1ae32a1SGerd Hoffmann { 498f1ae32a1SGerd Hoffmann const USBDesc *desc = usb_device_get_usb_desc(dev); 499f1ae32a1SGerd Hoffmann 500f1ae32a1SGerd Hoffmann assert(desc != NULL); 501f1ae32a1SGerd Hoffmann dev->speed = USB_SPEED_FULL; 502f1ae32a1SGerd Hoffmann dev->speedmask = 0; 503f1ae32a1SGerd Hoffmann if (desc->full) { 504f1ae32a1SGerd Hoffmann dev->speedmask |= USB_SPEED_MASK_FULL; 505f1ae32a1SGerd Hoffmann } 506f1ae32a1SGerd Hoffmann if (desc->high) { 507f1ae32a1SGerd Hoffmann dev->speedmask |= USB_SPEED_MASK_HIGH; 508f1ae32a1SGerd Hoffmann } 5096d51b2bbSGerd Hoffmann if (desc->super) { 5106d51b2bbSGerd Hoffmann dev->speedmask |= USB_SPEED_MASK_SUPER; 5116d51b2bbSGerd Hoffmann } 5125319dc7bSGerd Hoffmann if (desc->msos && (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_ENABLE))) { 5135319dc7bSGerd Hoffmann dev->flags |= (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE); 5145319dc7bSGerd Hoffmann usb_desc_set_string(dev, 0xee, "MSFT100Q"); 5155319dc7bSGerd Hoffmann } 516f1ae32a1SGerd Hoffmann usb_desc_setdefaults(dev); 517f1ae32a1SGerd Hoffmann } 518f1ae32a1SGerd Hoffmann 519f1ae32a1SGerd Hoffmann void usb_desc_attach(USBDevice *dev) 520f1ae32a1SGerd Hoffmann { 521f1ae32a1SGerd Hoffmann usb_desc_setdefaults(dev); 522f1ae32a1SGerd Hoffmann } 523f1ae32a1SGerd Hoffmann 524f1ae32a1SGerd Hoffmann void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str) 525f1ae32a1SGerd Hoffmann { 526f1ae32a1SGerd Hoffmann USBDescString *s; 527f1ae32a1SGerd Hoffmann 528f1ae32a1SGerd Hoffmann QLIST_FOREACH(s, &dev->strings, next) { 529f1ae32a1SGerd Hoffmann if (s->index == index) { 530f1ae32a1SGerd Hoffmann break; 531f1ae32a1SGerd Hoffmann } 532f1ae32a1SGerd Hoffmann } 533f1ae32a1SGerd Hoffmann if (s == NULL) { 534f1ae32a1SGerd Hoffmann s = g_malloc0(sizeof(*s)); 535f1ae32a1SGerd Hoffmann s->index = index; 536f1ae32a1SGerd Hoffmann QLIST_INSERT_HEAD(&dev->strings, s, next); 537f1ae32a1SGerd Hoffmann } 538f1ae32a1SGerd Hoffmann g_free(s->str); 539f1ae32a1SGerd Hoffmann s->str = g_strdup(str); 540f1ae32a1SGerd Hoffmann } 541f1ae32a1SGerd Hoffmann 5429d55d1adSGerd Hoffmann /* 5439d55d1adSGerd Hoffmann * This function creates a serial number for a usb device. 5449d55d1adSGerd Hoffmann * The serial number should: 5459d55d1adSGerd Hoffmann * (a) Be unique within the virtual machine. 5469d55d1adSGerd Hoffmann * (b) Be constant, so you don't get a new one each 5479d55d1adSGerd Hoffmann * time the guest is started. 5489d55d1adSGerd Hoffmann * So we are using the physical location to generate a serial number 5499d55d1adSGerd Hoffmann * from it. It has three pieces: First a fixed, device-specific 5509d55d1adSGerd Hoffmann * prefix. Second the device path of the host controller (which is 5519d55d1adSGerd Hoffmann * the pci address in most cases). Third the physical port path. 5529d55d1adSGerd Hoffmann * Results in serial numbers like this: "314159-0000:00:1d.7-3". 5539d55d1adSGerd Hoffmann */ 5549d55d1adSGerd Hoffmann void usb_desc_create_serial(USBDevice *dev) 5559d55d1adSGerd Hoffmann { 5569d55d1adSGerd Hoffmann DeviceState *hcd = dev->qdev.parent_bus->parent; 5579d55d1adSGerd Hoffmann const USBDesc *desc = usb_device_get_usb_desc(dev); 5589d55d1adSGerd Hoffmann int index = desc->id.iSerialNumber; 5590136464dSGerd Hoffmann char *path, *serial; 5609d55d1adSGerd Hoffmann 56171938a09SGerd Hoffmann if (dev->serial) { 56271938a09SGerd Hoffmann /* 'serial' usb bus property has priority if present */ 56371938a09SGerd Hoffmann usb_desc_set_string(dev, index, dev->serial); 56471938a09SGerd Hoffmann return; 56571938a09SGerd Hoffmann } 56671938a09SGerd Hoffmann 5679d55d1adSGerd Hoffmann assert(index != 0 && desc->str[index] != NULL); 56809e5ab63SAnthony Liguori path = qdev_get_dev_path(hcd); 56909e5ab63SAnthony Liguori if (path) { 5700136464dSGerd Hoffmann serial = g_strdup_printf("%s-%s-%s", desc->str[index], 5710136464dSGerd Hoffmann path, dev->port->path); 5720136464dSGerd Hoffmann } else { 5730136464dSGerd Hoffmann serial = g_strdup_printf("%s-%s", desc->str[index], dev->port->path); 5749d55d1adSGerd Hoffmann } 5759d55d1adSGerd Hoffmann usb_desc_set_string(dev, index, serial); 5769ef61724SMarc-André Lureau g_free(path); 5770136464dSGerd Hoffmann g_free(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 6299a77a0f5SHans de Goede int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p, 6309a77a0f5SHans de Goede int value, uint8_t *dest, size_t len) 631f1ae32a1SGerd Hoffmann { 6325319dc7bSGerd Hoffmann bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE)); 633f1ae32a1SGerd Hoffmann const USBDesc *desc = usb_device_get_usb_desc(dev); 634f1ae32a1SGerd Hoffmann const USBDescDevice *other_dev; 635f1ae32a1SGerd Hoffmann uint8_t buf[256]; 636f1ae32a1SGerd Hoffmann uint8_t type = value >> 8; 637f1ae32a1SGerd Hoffmann uint8_t index = value & 0xff; 638b43a2851SGerd Hoffmann int flags, ret = -1; 639f1ae32a1SGerd Hoffmann 640f1ae32a1SGerd Hoffmann if (dev->speed == USB_SPEED_HIGH) { 641f1ae32a1SGerd Hoffmann other_dev = usb_device_get_usb_desc(dev)->full; 642f1ae32a1SGerd Hoffmann } else { 643f1ae32a1SGerd Hoffmann other_dev = usb_device_get_usb_desc(dev)->high; 644f1ae32a1SGerd Hoffmann } 645f1ae32a1SGerd Hoffmann 646b43a2851SGerd Hoffmann flags = 0; 647b43a2851SGerd Hoffmann if (dev->device->bcdUSB >= 0x0300) { 648b43a2851SGerd Hoffmann flags |= USB_DESC_FLAG_SUPER; 649b43a2851SGerd Hoffmann } 650b43a2851SGerd Hoffmann 651f1ae32a1SGerd Hoffmann switch(type) { 652f1ae32a1SGerd Hoffmann case USB_DT_DEVICE: 6535319dc7bSGerd Hoffmann ret = usb_desc_device(&desc->id, dev->device, msos, buf, sizeof(buf)); 654f1ae32a1SGerd Hoffmann trace_usb_desc_device(dev->addr, len, ret); 655f1ae32a1SGerd Hoffmann break; 656f1ae32a1SGerd Hoffmann case USB_DT_CONFIG: 657f1ae32a1SGerd Hoffmann if (index < dev->device->bNumConfigurations) { 658b43a2851SGerd Hoffmann ret = usb_desc_config(dev->device->confs + index, flags, 659b43a2851SGerd Hoffmann buf, sizeof(buf)); 660f1ae32a1SGerd Hoffmann } 661f1ae32a1SGerd Hoffmann trace_usb_desc_config(dev->addr, index, len, ret); 662f1ae32a1SGerd Hoffmann break; 663f1ae32a1SGerd Hoffmann case USB_DT_STRING: 664f1ae32a1SGerd Hoffmann ret = usb_desc_string(dev, index, buf, sizeof(buf)); 665f1ae32a1SGerd Hoffmann trace_usb_desc_string(dev->addr, index, len, ret); 666f1ae32a1SGerd Hoffmann break; 667f1ae32a1SGerd Hoffmann case USB_DT_DEVICE_QUALIFIER: 668f1ae32a1SGerd Hoffmann if (other_dev != NULL) { 669f1ae32a1SGerd Hoffmann ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf)); 670f1ae32a1SGerd Hoffmann } 671f1ae32a1SGerd Hoffmann trace_usb_desc_device_qualifier(dev->addr, len, ret); 672f1ae32a1SGerd Hoffmann break; 673f1ae32a1SGerd Hoffmann case USB_DT_OTHER_SPEED_CONFIG: 674f1ae32a1SGerd Hoffmann if (other_dev != NULL && index < other_dev->bNumConfigurations) { 675b43a2851SGerd Hoffmann ret = usb_desc_config(other_dev->confs + index, flags, 676b43a2851SGerd Hoffmann buf, sizeof(buf)); 677f1ae32a1SGerd Hoffmann buf[0x01] = USB_DT_OTHER_SPEED_CONFIG; 678f1ae32a1SGerd Hoffmann } 679f1ae32a1SGerd Hoffmann trace_usb_desc_other_speed_config(dev->addr, index, len, ret); 680f1ae32a1SGerd Hoffmann break; 6812077469bSGerd Hoffmann case USB_DT_BOS: 6822077469bSGerd Hoffmann ret = usb_desc_bos(desc, buf, sizeof(buf)); 6832077469bSGerd Hoffmann trace_usb_desc_bos(dev->addr, len, ret); 6842077469bSGerd Hoffmann break; 685f1ae32a1SGerd Hoffmann 686f1ae32a1SGerd Hoffmann case USB_DT_DEBUG: 687f1ae32a1SGerd Hoffmann /* ignore silently */ 688f1ae32a1SGerd Hoffmann break; 689f1ae32a1SGerd Hoffmann 690f1ae32a1SGerd Hoffmann default: 691f1ae32a1SGerd Hoffmann fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__, 692f1ae32a1SGerd Hoffmann dev->addr, type, len); 693f1ae32a1SGerd Hoffmann break; 694f1ae32a1SGerd Hoffmann } 695f1ae32a1SGerd Hoffmann 696f1ae32a1SGerd Hoffmann if (ret > 0) { 697f1ae32a1SGerd Hoffmann if (ret > len) { 698f1ae32a1SGerd Hoffmann ret = len; 699f1ae32a1SGerd Hoffmann } 700f1ae32a1SGerd Hoffmann memcpy(dest, buf, ret); 7019a77a0f5SHans de Goede p->actual_length = ret; 7029a77a0f5SHans de Goede ret = 0; 703f1ae32a1SGerd Hoffmann } 704f1ae32a1SGerd Hoffmann return ret; 705f1ae32a1SGerd Hoffmann } 706f1ae32a1SGerd Hoffmann 707f1ae32a1SGerd Hoffmann int usb_desc_handle_control(USBDevice *dev, USBPacket *p, 708f1ae32a1SGerd Hoffmann int request, int value, int index, int length, uint8_t *data) 709f1ae32a1SGerd Hoffmann { 7105319dc7bSGerd Hoffmann bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE)); 711f1ae32a1SGerd Hoffmann const USBDesc *desc = usb_device_get_usb_desc(dev); 712f1ae32a1SGerd Hoffmann int ret = -1; 713f1ae32a1SGerd Hoffmann 714f1ae32a1SGerd Hoffmann assert(desc != NULL); 715f1ae32a1SGerd Hoffmann switch(request) { 716f1ae32a1SGerd Hoffmann case DeviceOutRequest | USB_REQ_SET_ADDRESS: 717f1ae32a1SGerd Hoffmann dev->addr = value; 718f1ae32a1SGerd Hoffmann trace_usb_set_addr(dev->addr); 719f1ae32a1SGerd Hoffmann ret = 0; 720f1ae32a1SGerd Hoffmann break; 721f1ae32a1SGerd Hoffmann 722f1ae32a1SGerd Hoffmann case DeviceRequest | USB_REQ_GET_DESCRIPTOR: 7239a77a0f5SHans de Goede ret = usb_desc_get_descriptor(dev, p, value, data, length); 724f1ae32a1SGerd Hoffmann break; 725f1ae32a1SGerd Hoffmann 726f1ae32a1SGerd Hoffmann case DeviceRequest | USB_REQ_GET_CONFIGURATION: 727f1ae32a1SGerd Hoffmann /* 728f1ae32a1SGerd Hoffmann * 9.4.2: 0 should be returned if the device is unconfigured, otherwise 729f1ae32a1SGerd Hoffmann * the non zero value of bConfigurationValue. 730f1ae32a1SGerd Hoffmann */ 731f1ae32a1SGerd Hoffmann data[0] = dev->config ? dev->config->bConfigurationValue : 0; 7329a77a0f5SHans de Goede p->actual_length = 1; 7339a77a0f5SHans de Goede ret = 0; 734f1ae32a1SGerd Hoffmann break; 735f1ae32a1SGerd Hoffmann case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: 736f1ae32a1SGerd Hoffmann ret = usb_desc_set_config(dev, value); 737f1ae32a1SGerd Hoffmann trace_usb_set_config(dev->addr, value, ret); 738f1ae32a1SGerd Hoffmann break; 739f1ae32a1SGerd Hoffmann 740f1ae32a1SGerd Hoffmann case DeviceRequest | USB_REQ_GET_STATUS: { 741f1ae32a1SGerd Hoffmann const USBDescConfig *config = dev->config ? 742f1ae32a1SGerd Hoffmann dev->config : &dev->device->confs[0]; 743f1ae32a1SGerd Hoffmann 744f1ae32a1SGerd Hoffmann data[0] = 0; 745f1ae32a1SGerd Hoffmann /* 746f1ae32a1SGerd Hoffmann * Default state: Device behavior when this request is received while 747f1ae32a1SGerd Hoffmann * the device is in the Default state is not specified. 748f1ae32a1SGerd Hoffmann * We return the same value that a configured device would return if 749f1ae32a1SGerd Hoffmann * it used the first configuration. 750f1ae32a1SGerd Hoffmann */ 751bd93976aSPantelis Koukousoulas if (config->bmAttributes & USB_CFG_ATT_SELFPOWER) { 752f1ae32a1SGerd Hoffmann data[0] |= 1 << USB_DEVICE_SELF_POWERED; 753f1ae32a1SGerd Hoffmann } 754f1ae32a1SGerd Hoffmann if (dev->remote_wakeup) { 755f1ae32a1SGerd Hoffmann data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP; 756f1ae32a1SGerd Hoffmann } 757f1ae32a1SGerd Hoffmann data[1] = 0x00; 7589a77a0f5SHans de Goede p->actual_length = 2; 7599a77a0f5SHans de Goede ret = 0; 760f1ae32a1SGerd Hoffmann break; 761f1ae32a1SGerd Hoffmann } 762f1ae32a1SGerd Hoffmann case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: 763f1ae32a1SGerd Hoffmann if (value == USB_DEVICE_REMOTE_WAKEUP) { 764f1ae32a1SGerd Hoffmann dev->remote_wakeup = 0; 765f1ae32a1SGerd Hoffmann ret = 0; 766f1ae32a1SGerd Hoffmann } 767f1ae32a1SGerd Hoffmann trace_usb_clear_device_feature(dev->addr, value, ret); 768f1ae32a1SGerd Hoffmann break; 769f1ae32a1SGerd Hoffmann case DeviceOutRequest | USB_REQ_SET_FEATURE: 770f1ae32a1SGerd Hoffmann if (value == USB_DEVICE_REMOTE_WAKEUP) { 771f1ae32a1SGerd Hoffmann dev->remote_wakeup = 1; 772f1ae32a1SGerd Hoffmann ret = 0; 773f1ae32a1SGerd Hoffmann } 774f1ae32a1SGerd Hoffmann trace_usb_set_device_feature(dev->addr, value, ret); 775f1ae32a1SGerd Hoffmann break; 776f1ae32a1SGerd Hoffmann 777*811ad5d8SGerd Hoffmann case DeviceOutRequest | USB_REQ_SET_SEL: 778*811ad5d8SGerd Hoffmann case DeviceOutRequest | USB_REQ_SET_ISOCH_DELAY: 779*811ad5d8SGerd Hoffmann if (dev->speed == USB_SPEED_SUPER) { 780*811ad5d8SGerd Hoffmann ret = 0; 781*811ad5d8SGerd Hoffmann } 782*811ad5d8SGerd Hoffmann break; 783*811ad5d8SGerd Hoffmann 784f1ae32a1SGerd Hoffmann case InterfaceRequest | USB_REQ_GET_INTERFACE: 785f1ae32a1SGerd Hoffmann if (index < 0 || index >= dev->ninterfaces) { 786f1ae32a1SGerd Hoffmann break; 787f1ae32a1SGerd Hoffmann } 788f1ae32a1SGerd Hoffmann data[0] = dev->altsetting[index]; 7899a77a0f5SHans de Goede p->actual_length = 1; 7909a77a0f5SHans de Goede ret = 0; 791f1ae32a1SGerd Hoffmann break; 792f1ae32a1SGerd Hoffmann case InterfaceOutRequest | USB_REQ_SET_INTERFACE: 793f1ae32a1SGerd Hoffmann ret = usb_desc_set_interface(dev, index, value); 794f1ae32a1SGerd Hoffmann trace_usb_set_interface(dev->addr, index, value, ret); 795f1ae32a1SGerd Hoffmann break; 796f1ae32a1SGerd Hoffmann 7975319dc7bSGerd Hoffmann case VendorDeviceRequest | 'Q': 7985319dc7bSGerd Hoffmann if (msos) { 7995319dc7bSGerd Hoffmann ret = usb_desc_msos(desc, p, index, data, length); 8005319dc7bSGerd Hoffmann trace_usb_desc_msos(dev->addr, index, length, ret); 8015319dc7bSGerd Hoffmann } 8025319dc7bSGerd Hoffmann break; 8035319dc7bSGerd Hoffmann case VendorInterfaceRequest | 'Q': 8045319dc7bSGerd Hoffmann if (msos) { 8055319dc7bSGerd Hoffmann ret = usb_desc_msos(desc, p, index, data, length); 8065319dc7bSGerd Hoffmann trace_usb_desc_msos(dev->addr, index, length, ret); 8075319dc7bSGerd Hoffmann } 8085319dc7bSGerd Hoffmann break; 8095319dc7bSGerd Hoffmann 810f1ae32a1SGerd Hoffmann } 811f1ae32a1SGerd Hoffmann return ret; 812f1ae32a1SGerd Hoffmann } 813