[usb] Windows Device Descriptor

Change-Id: Ibaa37ce94b17ea3a5313f690cfb4b74f93bae899
This commit is contained in:
Léa Saviot
2018-02-13 16:33:35 +01:00
parent 11630f8f62
commit 954c24bf9c
2 changed files with 201 additions and 1 deletions

View File

@@ -66,6 +66,46 @@ static const struct InterfaceDescriptor interfaceDescriptor = {
.iInterface = 0
};
static const struct OSStringDescriptor osStringDescriptor = {
.bLength = USB_DT_OS_STRING_SIZE,
.bDescriptorType = USB_DT_OS_STRING,
.qwSignature = {'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0},
.bMS_VendorCode = USB_OS_STRING_BMS_VENDOR_CODE,
.bPad = USB_OS_STRING_PAD
};
static const struct OSExtendedCompatIDHeader osExtendedCompatIDHeader = {
.dwLength = USB_OS_EXTENDED_COMPAT_ID_HEADER_SIZE + USB_OS_EXTENDED_COMPAT_ID_FUNCTION_SIZE,
.bcdVersion = USB_EXTENDED_COMPAT_ID_HEADER_BCD_VERSION,
.wIndex = USB_OS_FEATURE_EXTENDED_COMPAT_ID,
.bCount = 1,
.reserved = {0, 0, 0, 0, 0, 0, 0}
};
static const struct OSExtendedCompatIDFunction osExtendedCompatIDFunction = {
.bFirstInterfaceNumber = 0,
.bReserved = 0,
.compatibleID = {'W', 'I', 'N', 'U', 'S', 'B', 0, 0},
.subCompatibleID = {0, 0, 0, 0, 0, 0, 0, 0},
.reserved = {0, 0, 0, 0, 0, 0},
};
static const struct OSExtendedPropertiesHeader osExtendedPropertiesHeader = {
.dwLength = 0,
.bcdVersion = USB_EXTENDED_PROPERTIES_HEADER_BCD_VERSION,
.wIndex = USB_OS_FEATURE_EXTENDED_PROPERTIES,
.wCount = 1,
};
static const struct OSExtendedPropertiesGUIDFunction osExtendedPropertiesGUIDFunction = {
.dwSize = USB_OS_EXTENDED_PROPERTIES_FUNCTION_SIZE_WITHOUT_DATA + USB_GUID_PROPERTY_NAME_LENGTH + USB_GUID_PROPERTY_DATA_LENGTH,
.dwPropertyDataType = USB_PROPERTY_DATA_TYPE_UTF_16_LITTLE_ENDIAN,
.wPropertyNameLength = USB_GUID_PROPERTY_NAME_LENGTH,
.bPropertyName = {'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, 'G', 0, 'U', 0, 'I', 0, 'D', 0, 0, 0},
.dwPropertyDataLength = USB_GUID_PROPERTY_DATA_LENGTH,
.bPropertyData = {'{', 0, '9', 0, '5', 0, '2', 0, '3', 0, '6', 0, '2', 0, 'C', 0, '1', 0, '-', 0, '3', 0, 'D', 0, '9', 0, '3', 0, '-', 0, '4', 0, 'D', 0, '2', 0, 'A', 0, '-', 0, '9', 0, 'A', 0, '2', 0, '0', 0, '-', 0, '6', 0, '5', 0, '5', 0, '3', 0, '2', 0, '0', 0, '1', 0, '4', 0, '7', 0, 'C', 0, '6', 0, 'F', 0, '}', 0, 0, 0}
};
SetupData sSetupData;
uint16_t sRxPacketSize;
/* Buffer used for control requests. */
@@ -334,7 +374,6 @@ int controlSetupGetDescriptor() {
return (int) RequestReturnCodes::USBD_REQ_HANDLED;
case USB_DT_STRING:
struct StringDescriptor * stringDescriptor = (struct StringDescriptor *)sControlBufferInit;
if (descriptorIndex == 0) {
/* Send sane Language ID descriptor. */
stringDescriptor->wData[0] = USB_LANGID_ENGLISH_US;
@@ -342,6 +381,13 @@ int controlSetupGetDescriptor() {
sizeof(stringDescriptor->bDescriptorType) +
sizeof(stringDescriptor->wData[0]);
sControlBufferLength = MIN(sControlBufferLength, stringDescriptor->bLength);
} else if (descriptorIndex == 0xEE) {
// Windows OS String Descriptor
assert(sSetupData.wIndex == 0);
assert(sSetupData.wLength == 0x12);
sControlBuffer = (uint8_t *)(&osStringDescriptor);
sControlBufferLength = MIN(sControlBufferLength, osStringDescriptor.bLength);
return (int) RequestReturnCodes::USBD_REQ_HANDLED;
} else {
int arrayIndex = descriptorIndex - 1;
/* Check that string index is in range. */
@@ -389,6 +435,13 @@ int controlSetupSetConfiguration() {
}
int controlRequestDispatch() {
if (bmRequestTypeType(sSetupData.bmRequestType) == RequestTypeType::Vendor) {
return controlCustomSetup();
}
return controlStandardRequest();
}
int controlStandardRequest() {
switch (sSetupData.bRequest) {
case USB_REQ_GET_STATUS:
//TODO Not needed for enumeration?
@@ -424,6 +477,26 @@ int controlRequestDispatch() {
return 0;
}
int controlCustomSetup() {
switch (sSetupData.bRequest) {
case USB_OS_STRING_BMS_VENDOR_CODE:
if (sSetupData.wIndex == USB_OS_FEATURE_EXTENDED_COMPAT_ID) {
sControlBuffer = sControlBufferInit;
sControlBufferLength = buildExtendedCompatIDDescriptor();
return (int) RequestReturnCodes::USBD_REQ_HANDLED;
}
if (sSetupData.wIndex == USB_OS_FEATURE_EXTENDED_PROPERTIES) {
sControlBuffer = sControlBufferInit;
sControlBufferLength = buildExtendedPropertiesDescriptor();
return (int) RequestReturnCodes::USBD_REQ_HANDLED;
}
break;
default:
break;
}
return (int) RequestReturnCodes::USBD_REQ_NOTSUPP;
}
void controlOut() {
switch (sControlState) {
case ControlState::DATA_OUT:
@@ -698,6 +771,56 @@ uint16_t buildConfigDescriptor(uint8_t index) {
return total;
}
uint16_t buildExtendedCompatIDDescriptor() {
uint8_t *tmpbuf = sControlBuffer;
/* Copy the header */
uint16_t count = MIN(sControlBufferLength, USB_OS_EXTENDED_COMPAT_ID_HEADER_SIZE);
memcpy(sControlBuffer, &osExtendedCompatIDHeader, count);
sControlBuffer += count;
sControlBufferLength -= count;
uint16_t total = count;
uint16_t totalLength = USB_OS_EXTENDED_COMPAT_ID_HEADER_SIZE;
/* Copy the function */
count = MIN(sControlBufferLength, USB_OS_EXTENDED_COMPAT_ID_FUNCTION_SIZE);
memcpy(sControlBuffer, &osExtendedCompatIDFunction, count);
sControlBuffer += count;
sControlBufferLength -= count;
total += count;
totalLength += USB_OS_EXTENDED_COMPAT_ID_FUNCTION_SIZE;
sControlBuffer = tmpbuf;
return total;
}
uint16_t buildExtendedPropertiesDescriptor() {
uint8_t *tmpbuf = sControlBuffer;
/* Copy the header */
uint16_t count = MIN(sControlBufferLength, USB_OS_EXTENDED_PROPERTIES_HEADER_SIZE);
memcpy(sControlBuffer, &osExtendedPropertiesHeader, count);
sControlBuffer += count;
sControlBufferLength -= count;
uint16_t total = count;
uint16_t totalLength = USB_OS_EXTENDED_PROPERTIES_HEADER_SIZE;
/* Copy the GUID Property function */
count = MIN(sControlBufferLength, osExtendedPropertiesGUIDFunction.dwSize);
memcpy(sControlBuffer, &osExtendedPropertiesGUIDFunction, count);
sControlBuffer += count;
sControlBufferLength -= count;
total += count;
totalLength += osExtendedPropertiesGUIDFunction.dwSize;
/* Fill in dwLength. */
*(uint16_t *)(tmpbuf) = totalLength;
sControlBuffer = tmpbuf;
return total;
}
DataDirection bmRequestTypeDirection(uint8_t bmRequestType) {
if (bmRequestType & 0x80) {
return DataDirection::In;
@@ -705,6 +828,11 @@ DataDirection bmRequestTypeDirection(uint8_t bmRequestType) {
return DataDirection::Out;
}
RequestTypeType bmRequestTypeType(uint8_t bmRequestType) {
int type = (bmRequestType & 0b01100000) >> 5;
return (RequestTypeType)type;
}
int descriptorIndexFromWValue(uint16_t wValue) {
return wValue & 0xFF;
}

View File

@@ -37,6 +37,12 @@ enum class DataDirection {
Out
};
enum class RequestTypeType {
Standard = 0,
Class = 1,
Vendor = 2
};
/* USB Standard Request Codes */
#define USB_REQ_GET_STATUS 0
#define USB_REQ_CLEAR_FEATURE 1
@@ -160,6 +166,7 @@ void controlSetupOut();
int controlSetupGetDescriptor();
int controlSetupSetConfiguration();
int controlRequestDispatch();
int controlStandardRequest();
// Control In and Out
void controlOut();
void controlIn();
@@ -186,6 +193,7 @@ void usb_set_address(uint8_t address);
// Helpers
uint16_t buildConfigDescriptor(uint8_t index);
DataDirection bmRequestTypeDirection(uint8_t bmRequestType);
RequestTypeType bmRequestTypeType(uint8_t bmRequestType);
int descriptorIndexFromWValue(uint16_t wValue);
int descriptorTypeFromWValue(uint16_t wValue);
bool zlpIsNeeded(uint16_t dataLength, uint16_t dataExpectedLength, uint8_t endpointMaxPacketSize);
@@ -205,6 +213,70 @@ constexpr static GPIOPin VbusPin = GPIOPin(GPIOA, 9);
constexpr static GPIOPin DmPin = GPIOPin(GPIOA, 11);
constexpr static GPIOPin DpPin = GPIOPin(GPIOA, 12);
/* Windows OS Descriptor */
#define USB_DT_OS_STRING_SIZE 0x12
#define USB_DT_OS_STRING 3
#define USB_OS_STRING_BMS_VENDOR_CODE 2 // Arbitrarily chosen
#define USB_OS_STRING_PAD 0
#define USB_OS_FEATURE_EXTENDED_COMPAT_ID 0x04
#define USB_OS_FEATURE_EXTENDED_PROPERTIES 0x05
#define USB_EXTENDED_COMPAT_ID_HEADER_BCD_VERSION 0x0100
#define USB_EXTENDED_PROPERTIES_HEADER_BCD_VERSION 0x0100
#define USB_OS_EXTENDED_COMPAT_ID_HEADER_SIZE 16
#define USB_OS_EXTENDED_COMPAT_ID_FUNCTION_SIZE 24
#define USB_OS_EXTENDED_PROPERTIES_HEADER_SIZE 10
#define USB_OS_EXTENDED_PROPERTIES_FUNCTION_SIZE_WITHOUT_DATA 14
#define USB_PROPERTY_DATA_TYPE_UTF_16_LITTLE_ENDIAN 1
#define USB_GUID_PROPERTY_NAME_LENGTH 0x28
#define USB_GUID_PROPERTY_DATA_LENGTH 0x4E
struct OSStringDescriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t qwSignature[14];
uint8_t bMS_VendorCode;
uint8_t bPad;
} __attribute__((packed));
struct OSExtendedCompatIDHeader {
uint32_t dwLength; // The length, in bytes, of the complete extended compat ID descriptor
uint16_t bcdVersion; // The descriptors version number, in binary coded decimal (BCD) format
uint16_t wIndex; // An index that identifies the particular OS feature descriptor
uint8_t bCount; // The number of custom property sections
uint8_t reserved[7]; // Reserved
} __attribute__((packed));
struct OSExtendedCompatIDFunction {
uint8_t bFirstInterfaceNumber; // The interface or function number
uint8_t bReserved; // Reserved
uint8_t compatibleID[8]; // The functions compatible ID
uint8_t subCompatibleID[8]; // The functions subcompatible ID
uint8_t reserved[6]; // Reserved
} __attribute__((packed));
struct OSExtendedPropertiesHeader {
uint32_t dwLength; // The length, in bytes, of the complete extended properties descriptor
uint16_t bcdVersion; // The descriptors version number, in binary coded decimal (BCD) format
uint16_t wIndex; // The index for extended properties OS descriptors
uint16_t wCount; // The number of custom property sections that follow the header section
} __attribute__((packed));
struct OSExtendedPropertiesGUIDFunction {
uint32_t dwSize; // The size of this custom properties section
uint32_t dwPropertyDataType; // Property data format
uint16_t wPropertyNameLength;
uint8_t bPropertyName[USB_GUID_PROPERTY_NAME_LENGTH]; // Number of custom property sections that follow the header
uint32_t dwPropertyDataLength; // Length of the buffer holding the property data
uint8_t bPropertyData[USB_GUID_PROPERTY_DATA_LENGTH]; // Format-dependent Property data
} __attribute__((packed));
int controlCustomSetup();
uint16_t buildExtendedCompatIDDescriptor();
uint16_t buildExtendedPropertiesDescriptor();
}
}
}