diff --git a/src/hid.cc b/src/hid.cc index fede1dd..7656676 100644 --- a/src/hid.cc +++ b/src/hid.cc @@ -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 diff --git a/src/usb_descriptors.cc b/src/usb_descriptors.cc index 71e039d..e4a68ac 100644 --- a/src/usb_descriptors.cc +++ b/src/usb_descriptors.cc @@ -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) }; @@ -151,4 +142,67 @@ 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; -} \ No newline at end of file +} + +//--------------------------------------------------------------------+ +// 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"); + diff --git a/src/usb_descriptors.hh b/src/usb_descriptors.hh index 240aa28..1566d61 100644 --- a/src/usb_descriptors.hh +++ b/src/usb_descriptors.hh @@ -3,4 +3,24 @@ enum class descriptor { gamepad = 1, _count -}; \ No newline at end of file +}; + +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; \ No newline at end of file diff --git a/src/vendor.cc b/src/vendor.cc index ec87ef3..228a3a0 100644 --- a/src/vendor.cc +++ b/src/vendor.cc @@ -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(static_cast(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);