Get BOS/WinUSB set up

This commit is contained in:
Justin C. Miller
2025-01-31 18:00:52 -08:00
parent 90c38b731e
commit 7a0cfebf52
4 changed files with 115 additions and 21 deletions

View File

@@ -3,7 +3,7 @@
#include "blink.hh"
#include "hid.hh"
#include "usb_descriptors.hh"
#include "hid/hid_device.h"
#include "class/hid/hid_device.h"
extern "C" {
// TinyUSB Callbacks

View File

@@ -1,7 +1,9 @@
#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.hh"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
@@ -13,7 +15,7 @@
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
#define USB_VID 0x4a33 // J3 in ascii
#define USB_BCD 0x0200
#define USB_BCD 0x0201
extern "C" {
// TinyUSB callbacks
@@ -21,6 +23,7 @@ extern "C" {
uint8_t const * tud_hid_descriptor_report_cb(uint8_t);
uint8_t const * tud_descriptor_configuration_cb(uint8_t);
uint16_t const * tud_descriptor_string_cb(uint8_t, uint16_t);
uint8_t const * tud_descriptor_bos_cb();
}
//--------------------------------------------------------------------+
@@ -71,22 +74,13 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t) {
// String Descriptors
//--------------------------------------------------------------------+
enum class strings : uint8_t {
language_id,
manufacturer,
product,
serial,
interface,
_count
};
// array of pointer to string descriptors
char16_t const *string_desc_arr[size_t(strings::_count)] = {
u"\u0409", // 0: is supported language is English (0x0409)
u"j3gaming", // 1: Manufacturer
u"EDMFD", // 2: Product
nullptr, // 3: Serials will use unique ID if possible
u"screen control", // 4: screen interface
u"EDMFD Screen", // 4: screen interface
};
static constexpr size_t desc_len = 32;
@@ -123,21 +117,18 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
static constexpr size_t config_total_len = TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN + TUD_VENDOR_DESC_LEN;
enum class interface : uint8_t { HID, vendor, _count };
enum class endpoint : uint8_t { HID = 0x81, vendor_out = 0x02, vendor_in = 0x82 };
uint8_t const desc_configuration[config_total_len] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, uint8_t(interface::_count), 0, config_total_len, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
// Interface number, string index, EP Out & IN address, EP size
TUD_VENDOR_DESCRIPTOR(uint8_t(interface::vendor), uint8_t(strings::interface), uint8_t(endpoint::vendor_out), uint8_t(endpoint::vendor_in), 64),
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
TUD_HID_DESCRIPTOR(uint8_t(interface::HID), 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), uint8_t(endpoint::HID), CFG_TUD_HID_EP_BUFSIZE, 5),
// Interface number, string index, EP Out & IN address, EP size
TUD_VENDOR_DESCRIPTOR(uint8_t(interface::vendor), uint8_t(strings::interface), uint8_t(endpoint::vendor_out), uint8_t(endpoint::vendor_in), 64)
// CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
//TUD_CDC_DESCRIPTOR(uint8_t(interface::CDC), 4, uint8_t(endpoint::CDCnotify), 8, uint8_t(endpoint::CDCout), uint8_t(endpoint::CDCin), 64)
};
@@ -152,3 +143,66 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index) {
// This example use the same configuration for both high and full speed mode
return desc_configuration;
}
//--------------------------------------------------------------------+
// BOS Descriptor
//--------------------------------------------------------------------+
static constexpr uint8_t bos_total_len = (TUD_BOS_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN);
uint8_t const desc_bos[] = {
// total length, number of device caps
TUD_BOS_DESCRIPTOR(bos_total_len, 1),
// Microsoft OS 2.0 descriptor
TUD_BOS_MS_OS_20_DESCRIPTOR(ms_os_20_desc_len, uint8_t(vendor_req::microsoft)),
};
static_assert(sizeof(desc_bos) == bos_total_len, "Incorrect BOS length");
uint8_t const * tud_descriptor_bos_cb() { return desc_bos; }
uint8_t const desc_ms_os_20[ms_os_20_desc_len] = {
// Set header
U16_TO_U8S_LE(0x000A), // length
U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), // type
U32_TO_U8S_LE(0x06030000), // windows version
U16_TO_U8S_LE(ms_os_20_desc_len), // total length
// Configuration subset header
U16_TO_U8S_LE(0x0008), // length
U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), // type
0, // configuration index
0, // reserved
U16_TO_U8S_LE(ms_os_20_desc_len-0x0A), // configuration total length
// Function Subset header: length, type, first interface, reserved, subset length
U16_TO_U8S_LE(0x0008), // length
U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), // type
uint8_t(interface::vendor), // first interface
0, // reserved
U16_TO_U8S_LE(ms_os_20_desc_len-0x0A-0x08), // subset total length
// MS OS 2.0 Compatible ID descriptor
U16_TO_U8S_LE(0x0014), // length
U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), // type
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // compatible ID
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible
// MS OS 2.0 Registry property descriptor: length, type
U16_TO_U8S_LE(ms_os_20_desc_len-0x0A-0x08-0x08-0x14), // length
U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY), // type
U16_TO_U8S_LE(0x0007), // wPropertyDataType
U16_TO_U8S_LE(0x002A), // wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00,
'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00,
U16_TO_U8S_LE(0x0050), // wPropertyDataLength and bPropertyData: “{4b028455-9b3c-4cf4-8992-3c4c40b76d96}\0”.
'{', 0x00, '4', 0x00, 'B', 0x00, '0', 0x00, '2', 0x00, '8', 0x00, '4', 0x00, '5', 0x00, '5', 0x00, '-', 0x00,
'9', 0x00, 'B', 0x00, '3', 0x00, 'C', 0x00, '-', 0x00, '4', 0x00, 'C', 0x00, 'F', 0x00, '4', 0x00, '-', 0x00,
'8', 0x00, '9', 0x00, '9', 0x00, '2', 0x00, '-', 0x00, '3', 0x00, 'C', 0x00, '4', 0x00, 'C', 0x00, '4', 0x00,
'0', 0x00, 'B', 0x00, '7', 0x00, '6', 0x00, 'D', 0x00, '9', 0x00, '6', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00,
};
static_assert(sizeof(desc_ms_os_20) == ms_os_20_desc_len, "Incorrect MS OS Desc size");

View File

@@ -4,3 +4,23 @@ enum class descriptor {
gamepad = 1,
_count
};
enum class strings : uint8_t {
language_id,
manufacturer,
product,
serial,
interface,
_count
};
enum class interface : uint8_t { vendor, HID, _count };
enum class endpoint : uint8_t { HID = 0x81, vendor_out = 0x02, vendor_in = 0x82 };
enum class vendor_req : uint8_t {
microsoft = 1,
edmfd
};
extern uint8_t const desc_ms_os_20[];
static constexpr size_t ms_os_20_desc_len = 0xb2;

View File

@@ -1,13 +1,33 @@
#include "bsp/board_api.h"
#include "vendor/vendor_device.h"
#include "class/vendor/vendor_device.h"
#include "blink.hh"
#include "usb_descriptors.hh"
extern "C" {
// TinyUSB callbacks
bool tud_Ivendor_control_xfer_cb(uint8_t, uint8_t, tusb_control_request_t const*);
void tud_vendor_rx_cb(uint8_t, uint8_t const*, uint16_t);
void tud_vendor_tx_cb(uint8_t, uint32_t);
}
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) {
// nothing to with DATA & ACK stage
if (stage != CONTROL_STAGE_SETUP) return true;
if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR &&
vendor_req(request->bRequest) == vendor_req::microsoft &&
request->wIndex == 7) {
// Get Microsoft OS 2.0 compatible descriptor
return tud_control_xfer(rhport, request, const_cast<void*>(static_cast<const void*>(desc_ms_os_20)), ms_os_20_desc_len);
}
// stall unknown request
return false;
}
// Invoked when received new data
void tud_vendor_rx_cb(uint8_t, uint8_t const* buffer, uint16_t bufsize) {
tud_vendor_write(buffer, bufsize);