mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-25 16:50:50 +01:00
[usb] Windows Device Descriptor
Change-Id: Ibaa37ce94b17ea3a5313f690cfb4b74f93bae899
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 descriptor’s 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 function’s compatible ID
|
||||
uint8_t subCompatibleID[8]; // The function’s 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 descriptor’s 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();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user