Skip to content

Instantly share code, notes, and snippets.

@kuro68k
Last active November 5, 2021 01:30
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kuro68k/22f1e9c691e8d1ef46d3 to your computer and use it in GitHub Desktop.
Save kuro68k/22f1e9c691e8d1ef46d3 to your computer and use it in GitHub Desktop.
Add Microsoft WCID descriptors to Atmel's ASF USB stack
To add MS USB extended descriptors to an ASF project:
0. Optionally disable disabling peripheral clocks in common/services/clock/xmega/sysclk.c -> sysclk_init()
1. Configure clocks and oscillators in config/conf_board.h:
// required for the ASF clock module
#define BOARD_XOSC_HZ F_CPU
#define BOARD_XOSC_STARTUP_US 1024
#define BOARD_XOSC_TYPE XOSC_TYPE_XTAL
and config/conf_clock.
2. Optionally disable sleep manager in config/conf_sleepmgr.h
3. Optionally set up a custom serial number in config/conf_usb.h:
#define USB_DEVICE_SERIAL_NAME
#define USB_DEVICE_GET_SERIAL_NAME_POINTER USB_serial_number
#define USB_DEVICE_GET_SERIAL_NAME_LENGTH 25
extern uint8_t USB_serial_number[];
4. Add functions to get extra strings to config/conf_usb.h:
#define UDC_GET_EXTRA_STRING() usb_msft_string()
#define USB_DEVICE_SPECIFIC_REQUEST() usb_other_requests()
5. Add usb.h:
#ifndef USB_H_
#define USB_H_
/// Microsoft WCID descriptor
typedef struct USB_MicrosoftCompatibleDescriptor_Interface {
uint8_t bFirstInterfaceNumber;
uint8_t reserved1;
uint8_t compatibleID[8];
uint8_t subCompatibleID[8];
uint8_t reserved2[6];
} __attribute__((packed)) USB_MicrosoftCompatibleDescriptor_Interface;
typedef struct USB_MicrosoftCompatibleDescriptor {
uint32_t dwLength;
uint16_t bcdVersion;
uint16_t wIndex;
uint8_t bCount;
uint8_t reserved[7];
USB_MicrosoftCompatibleDescriptor_Interface interfaces[];
} __attribute__((packed)) USB_MicrosoftCompatibleDescriptor;
typedef struct USB_MicrosoftExtendedPropertiesDescriptor {
uint32_t dwLength;
uint16_t bcdVersion;
uint16_t wIndex;
uint16_t bCount;
uint32_t dwPropertySize;
uint32_t dwPropertyDataType;
uint16_t wPropertyNameLength;
wchar_t PropertyName[21];
uint32_t dwPropertyDataLength;
wchar_t PropertyData[40];
} __attribute__((packed)) USB_MicrosoftExtendedPropertiesDescriptor;
extern bool usb_msft_string(void);
extern bool usb_other_requests(void);
#endif /* USB_H_ */
6. Add usb.c:
#include <avr/io.h>
#include <stdbool.h>
#include "asf.h"
#include "usb.h"
/// Based on: https://github.com/cjameshuff/m1k-fw/blob/master/src/main.c
static USB_MicrosoftCompatibleDescriptor microsoft_compatible_id_descriptor = {
.dwLength = sizeof(USB_MicrosoftCompatibleDescriptor) +
1*sizeof(USB_MicrosoftCompatibleDescriptor_Interface),
.bcdVersion = 0x0100,
.wIndex = 0x0004,
.bCount = 1,
.reserved = {0, 0, 0, 0, 0, 0, 0},
.interfaces = {
{
.bFirstInterfaceNumber = 1,
.reserved1 = 1,
.compatibleID = "WINUSB\0\0",
.subCompatibleID = {0, 0, 0, 0, 0, 0, 0, 0},
.reserved2 = {0, 0, 0, 0, 0, 0},
}
}
};
static USB_MicrosoftExtendedPropertiesDescriptor microsoft_extended_properties_descriptor = {
.dwLength = sizeof(USB_MicrosoftExtendedPropertiesDescriptor),
.bcdVersion = 0x0100,
.wIndex = 0x0005,
.bCount = 2,
.dwPropertySize = 136,
.dwPropertyDataType = 7,
.wPropertyNameLength = 21*2,
.PropertyName = L"DeviceInterfaceGUIDs",
.dwPropertyDataLength = 40*2,
.PropertyData = L"{00000000-0000-0000-0000-000000000000}\0",
};
/**************************************************************************************************
** WCID configuration information
** Hooked into UDC via UDC_GET_EXTRA_STRING #define.
*/
bool usb_msft_string(void)
{
uint8_t udi_msft_magic[] = "MSFT100";
/*
struct extra_strings_desc_t{
usb_str_desc_t header;
le16_t string[sizeof(udi_msft_magic)];
};
*/
struct extra_strings_desc_t{
usb_str_desc_t header;
le16_t string[7];
uint8_t vendor_code;
uint8_t padding;
};
static UDC_DESC_STORAGE struct extra_strings_desc_t extra_strings_desc = {
.header.bDescriptorType = USB_DT_STRING,
};
uint8_t i;
uint8_t *str;
uint8_t str_lgt=0;
if ((udd_g_ctrlreq.req.wValue & 0xff) == 0xEE) {
str_lgt = sizeof(udi_msft_magic)-1;
str = udi_msft_magic;
}
else {
return false;
}
if (str_lgt!=0) {
for( i=0; i<str_lgt; i++) {
extra_strings_desc.string[i] = cpu_to_le16((le16_t)str[i]);
}
extra_strings_desc.vendor_code = 0x22;
extra_strings_desc.padding = 0;
//extra_strings_desc.header.bLength = 2+ (str_lgt)*2;
extra_strings_desc.header.bLength = 18;
udd_g_ctrlreq.payload_size = extra_strings_desc.header.bLength;
udd_g_ctrlreq.payload = (uint8_t *) &extra_strings_desc;
}
// if the string is larger than request length, then cut it
if (udd_g_ctrlreq.payload_size > udd_g_ctrlreq.req.wLength) {
udd_g_ctrlreq.payload_size = udd_g_ctrlreq.req.wLength;
}
return true;
}
/**************************************************************************************************
** Handle device requests that the ASF stack doesn't
*/
bool usb_other_requests(void)
{
uint8_t* ptr = 0;
uint16_t size = 0;
if (Udd_setup_type() == USB_REQ_TYPE_VENDOR)
{
//if (udd_g_ctrlreq.req.bRequest == 0x30)
if (1)
{
if (udd_g_ctrlreq.req.wIndex == 0x04)
{
ptr = (uint8_t*)&microsoft_compatible_id_descriptor;
size = (udd_g_ctrlreq.req.wLength);
if (size > microsoft_compatible_id_descriptor.dwLength)
size = microsoft_compatible_id_descriptor.dwLength;
}
else if (udd_g_ctrlreq.req.wIndex == 0x05)
{
ptr = (uint8_t*)&microsoft_extended_properties_descriptor;
size = (udd_g_ctrlreq.req.wLength);
if (size > microsoft_extended_properties_descriptor.dwLength)
size = microsoft_extended_properties_descriptor.dwLength;
}
else
return false;
}
}
udd_g_ctrlreq.payload_size = size;
if ( size == 0 )
{
udd_g_ctrlreq.callback = 0;
udd_g_ctrlreq.over_under_run = 0;
}
else
udd_g_ctrlreq.payload = ptr;
return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment