Files
DS5Dongle-OLED-Edition-stea…/src/usb_descriptors.cpp
T

882 lines
36 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* The MIT License (MIT)
*
* Copyright (c) 2023 HiFiPhile
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "bsp/board_api.h"
#include "tusb.h"
#include "config.h"
#ifndef ENABLE_SERIAL
#define ENABLE_SERIAL 0
#endif
bool ds_mode() {
if (get_config().controller_mode == 2) {
return !is_dse;
}
return get_config().controller_mode == 0;
}
enum {
ITF_NUM_AUDIO_CONTROL = 0,
ITF_NUM_AUDIO_STREAMING_OUT,
ITF_NUM_AUDIO_STREAMING_IN,
ITF_NUM_HID,
#if ENABLE_SERIAL
ITF_NUM_CDC,
ITF_NUM_CDC_DATA,
#endif
ITF_NUM_TOTAL,
CONFIG_DESC_LEN_AUDIO_IAD =
#if ENABLE_SERIAL
8,
#else
0,
#endif
CONFIG_DESC_LEN_BASE = 0x00E3 + CONFIG_DESC_LEN_AUDIO_IAD,
CONFIG_DESC_LEN_TOTAL = CONFIG_DESC_LEN_BASE
#if ENABLE_SERIAL
+ TUD_CDC_DESC_LEN
#endif
};
// String Descriptor Index
enum {
STRID_LANGID = 0,
STRID_MANUFACTURER,
STRID_PRODUCT,
STRID_SERIAL,
#if ENABLE_SERIAL
STRID_CDC,
#endif
};
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
// Use Interface Association Descriptor (IAD) for Audio
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
#if ENABLE_SERIAL
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
#else
.bDeviceClass = 0x00,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
#endif
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0x054C,
// .idProduct = 0x0CE6, // DS
// .idProduct = 0x0DF2, // DSE
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x00,
.bNumConfigurations = 0x01
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const *tud_descriptor_device_cb(void) {
desc_device.idProduct = ds_mode() ? 0x0CE6 : 0x0DF2;
return reinterpret_cast<uint8_t const *>(&desc_device);
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
uint8_t descriptor_configuration[] = {
// --- CONFIGURATION DESCRIPTOR ---
0x09, // bLength
0x02, // bDescriptorType (CONFIGURATION)
U16_TO_U8S_LE(CONFIG_DESC_LEN_TOTAL), // wTotalLength
ITF_NUM_TOTAL, // bNumInterfaces
0x01, // bConfigurationValue: 1
0x00, // iConfiguration: 0
0xC0, // bmAttributes: SELF-POWERED, NO REMOTE-WAKEUP
0xFA, // bMaxPower: 500mA (250 * 2mA)
#if ENABLE_SERIAL
// --- INTERFACE ASSOCIATION DESCRIPTOR: Audio function (interfaces 0-2) ---
0x08, // bLength
TUSB_DESC_INTERFACE_ASSOCIATION, // bDescriptorType
ITF_NUM_AUDIO_CONTROL, // bFirstInterface
0x03, // bInterfaceCount
0x01, // bFunctionClass: Audio
0x01, // bFunctionSubClass: Audio Control
0x00, // bFunctionProtocol
0x00, // iFunction
#endif
// --- INTERFACE DESCRIPTOR (0.0): Audio Control ---
0x09, // bLength
0x04, // bDescriptorType (INTERFACE)
0x00, // bInterfaceNumber: 0
0x00, // bAlternateSetting: 0
0x00, // bNumEndpoints: 0
0x01, // bInterfaceClass: Audio (0x01)
0x01, // bInterfaceSubClass: Audio Control (0x01)
0x00, // bInterfaceProtocol: 0x00
0x00, // iInterface: 0
// Class-specific AC Interface Header Descriptor
0x0A, // bLength: 10
0x24, // bDescriptorType: CS_INTERFACE (0x24)
0x01, // bDescriptorSubtype: Header (0x01)
0x00, 0x01, // bcdADC: 1.00
0x49, 0x00, // wTotalLength: 73 (0x0049)
0x02, // bInCollection: 2 streaming interfaces
0x01, // baInterfaceNr(1): Interface 1
0x02, // baInterfaceNr(2): Interface 2
// Input Terminal Descriptor (Terminal ID 1: USB Streaming → Output to Speaker)
0x0C, // bLength: 12
0x24, // bDescriptorType: CS_INTERFACE
0x02, // bDescriptorSubtype: Input Terminal
0x01, // bTerminalID: 1
0x01, 0x01, // wTerminalType: USB Streaming (0x0101)
0x06, // bAssocTerminal: 6 (paired with USB OUT terminal)
0x04, // bNrChannels: 4
0x33, 0x00, // wChannelConfig: L/R Front + L/R Surround (0x0033)
0x00, // iChannelNames: 0
0x00, // iTerminal: 0
// Feature Unit Descriptor (Unit ID 2 ← from Terminal 1)
0x0C, // bLength: 12
0x24, // bDescriptorType: CS_INTERFACE
0x06, // bDescriptorSubtype: Feature Unit
0x02, // bUnitID: 2
0x01, // bSourceID: 1
0x01, // bControlSize: 1 byte per control
0x03, // bmaControls[0]: Master Mute, Volume
0x00, 0x00, 0x00, 0x00, 0x00, // bmaControls[1..4]: No per-channel controls
// Output Terminal Descriptor (Terminal ID 3: Speaker ← from Unit 2)
0x09, // bLength: 9
0x24, // bDescriptorType: CS_INTERFACE
0x03, // bDescriptorSubtype: Output Terminal
0x03, // bTerminalID: 3
0x01, 0x03, // wTerminalType: Speaker (0x0301)
0x04, // bAssocTerminal: 4 (paired with mic input)
0x02, // bSourceID: 2 (Feature Unit)
0x00, // iTerminal: 0
// Input Terminal Descriptor (Terminal ID 4: Headset Mic)
0x0C, // bLength: 12
0x24, // bDescriptorType: CS_INTERFACE
0x02, // bDescriptorSubtype: Input Terminal
0x04, // bTerminalID: 4
0x02, 0x04, // wTerminalType: Headset (0x0402)
0x03, // bAssocTerminal: 3 (paired with speaker)
0x02, // bNrChannels: 2
0x03, 0x00, // wChannelConfig: L/R Front (0x0003)
0x00, // iChannelNames: 0
0x00, // iTerminal: 0
// Feature Unit Descriptor (Unit ID 5 ← from Terminal 4)
0x09, // bLength: 9
0x24, // bDescriptorType: CS_INTERFACE
0x06, // bDescriptorSubtype: Feature Unit
0x05, // bUnitID: 5
0x04, // bSourceID: 4
0x01, // bControlSize: 1
0x03, // bmaControls[0]: Master Mute, Volume
0x00, // bmaControls[1]: Ch1 no controls
0x00, // iFeature: 0
// Output Terminal Descriptor (Terminal ID 6: USB Streaming ← from Unit 5)
0x09, // bLength: 9
0x24, // bDescriptorType: CS_INTERFACE
0x03, // bDescriptorSubtype: Output Terminal
0x06, // bTerminalID: 6
0x01, 0x01, // wTerminalType: USB Streaming (0x0101)
0x01, // bAssocTerminal: 1
0x05, // bSourceID: 5
0x00, // iTerminal: 0
// --- INTERFACE DESCRIPTOR (1.0): Audio Streaming (OUT - Alternate 0) ---
0x09, // bLength
0x04, // bDescriptorType (INTERFACE)
0x01, // bInterfaceNumber: 1
0x00, // bAlternateSetting: 0
0x00, // bNumEndpoints: 0
0x01, // bInterfaceClass: Audio
0x02, // bInterfaceSubClass: Audio Streaming
0x00, // bInterfaceProtocol
0x00, // iInterface
// --- INTERFACE DESCRIPTOR (1.1): Audio Streaming (OUT - Alternate 1) ---
0x09, // bLength
0x04, // bDescriptorType (INTERFACE)
0x01, // bInterfaceNumber: 1
0x01, // bAlternateSetting: 1
0x01, // bNumEndpoints: 1
0x01, // bInterfaceClass: Audio
0x02, // bInterfaceSubClass: Audio Streaming
0x00, // bInterfaceProtocol
0x00, // iInterface
// AS General Descriptor (for Interface 1.1)
0x07, // bLength: 7
0x24, // bDescriptorType: CS_INTERFACE
0x01, // bDescriptorSubtype: AS_GENERAL
0x01, // bTerminalLink: connected to Terminal ID 1
0x01, // bDelay: 1 frame
0x01, 0x00, // wFormatTag: PCM (0x0001)
// Format Type Descriptor (4-channel, 16-bit, 48kHz)
0x0B, // bLength: 11
0x24, // bDescriptorType: CS_INTERFACE
0x02, // bDescriptorSubtype: FORMAT_TYPE
0x01, // bFormatType: TYPE_I
0x04, // bNrChannels: 4
0x02, // bSubframeSize: 2 bytes/sample
0x10, // bBitResolution: 16 bits
0x01, // bSamFreqType: 1 discrete frequency
0x80, 0xBB, 0x00, // tSamFreq: 48000 Hz (0x00BB80)
// Endpoint Descriptor (Audio OUT: EP1)
0x09, // bLength
0x05, // bDescriptorType (ENDPOINT)
0x01, // bEndpointAddress: OUT EP1
0x09, // bmAttributes: Isochronous, Adaptive
0x88, 0x01, // wMaxPacketSize: 392 bytes
0x01, // bInterval: 1
0x00, // bRefresh
0x00, // bSynchAddress
// Class-specific Audio Streaming Endpoint Descriptor (EP1)
0x07, // bLength
0x25, // bDescriptorType: CS_ENDPOINT
0x01, // bDescriptorSubtype: GENERAL
0x00, // Attributes: No pitch/sampling freq control
0x00, // Lock Delay Units: Undefined
0x00, 0x00, // Lock Delay: 0
// --- INTERFACE DESCRIPTOR (2.0): Audio Streaming IN (Alternate 0) ---
0x09, // bLength
0x04, // bDescriptorType (INTERFACE)
0x02, // bInterfaceNumber: 2
0x00, // bAlternateSetting: 0
0x00, // bNumEndpoints: 0
0x01, // bInterfaceClass: Audio
0x02, // bInterfaceSubClass: Audio Streaming
0x00, // bInterfaceProtocol
0x00, // iInterface
// --- INTERFACE DESCRIPTOR (2.1): Audio Streaming IN (Alternate 1) ---
0x09, // bLength
0x04, // bDescriptorType (INTERFACE)
0x02, // bInterfaceNumber: 2
0x01, // bAlternateSetting: 1
0x01, // bNumEndpoints: 1
0x01, // bInterfaceClass: Audio
0x02, // bInterfaceSubClass: Audio Streaming
0x00, // bInterfaceProtocol
0x00, // iInterface
// AS General Descriptor (for Interface 2.1)
0x07, // bLength: 7
0x24, // bDescriptorType: CS_INTERFACE
0x01, // bDescriptorSubtype: AS_GENERAL
0x06, // bTerminalLink: connected to Terminal ID 6
0x01, // bDelay: 1 frame
0x01, 0x00, // wFormatTag: PCM (0x0001)
// Format Type Descriptor (2-channel, 16-bit, 48kHz)
0x0B, // bLength: 11
0x24, // bDescriptorType: CS_INTERFACE
0x02, // bDescriptorSubtype: FORMAT_TYPE
0x01, // bFormatType: TYPE_I
0x02, // bNrChannels: 2
0x02, // bSubframeSize: 2
0x10, // bBitResolution: 16
0x01, // bSamFreqType: 1
0x80, 0xBB, 0x00, // tSamFreq: 48000 Hz
// Endpoint Descriptor (Audio IN: EP2)
0x09, // bLength
0x05, // bDescriptorType (ENDPOINT)
0x82, // bEndpointAddress: IN EP2
0x05, // bmAttributes: Isochronous, Asynchronous
0xC4, 0x00, // wMaxPacketSize: 196 bytes
0x01, // bInterval: 1
0x00, // bRefresh
0x00, // bSynchAddress
// Class-specific Audio Streaming Endpoint Descriptor (EP2)
0x07, // bLength
0x25, // bDescriptorType: CS_ENDPOINT
0x01, // bDescriptorSubtype: GENERAL
0x00, // Attributes: No controls
0x00, // Lock Delay Units
0x00, 0x00, // Lock Delay
// --- INTERFACE DESCRIPTOR (3.0): HID (DualSense 5 Gamepad + Touchpad) ---
0x09, // bLength
0x04, // bDescriptorType (INTERFACE)
0x03, // bInterfaceNumber: 3
0x00, // bAlternateSetting: 0
0x02, // bNumEndpoints: 2 (IN + OUT)
0x03, // bInterfaceClass: HID
0x00, // bInterfaceSubClass: None
0x00, // bInterfaceProtocol: None
0x00, // iInterface
// HID Descriptor
0x09, // bLength: 9
0x21, // bDescriptorType (HID)
0x11, 0x01, // bcdHID: 1.11
0x00, // bCountryCode: Not localized
0x01, // bNumDescriptors: 1 report descriptor
0x22, // bDescriptorType: Report
0x41, 0x01, // wDescriptorLength: 321 (0x0141) DS
// 0xB5, 0x01, // wDescriptorLength: 437 (0x01B5) DSE
// Endpoint Descriptor (HID IN: EP4)
0x07, // bLength
0x05, // bDescriptorType (ENDPOINT)
0x84, // bEndpointAddress: IN EP4
0x03, // bmAttributes: Interrupt
0x40, 0x00, // wMaxPacketSize: 64
0x01, // bInterval: 1 (polling every 4ms -> 1ms)
// Endpoint Descriptor (HID OUT: EP3)
0x07, // bLength
0x05, // bDescriptorType (ENDPOINT)
0x03, // bEndpointAddress: OUT EP3
0x03, // bmAttributes: Interrupt
0x40, 0x00, // wMaxPacketSize: 64
0x01, // bInterval: 1 (polling every 4ms -> 1ms)
#if ENABLE_SERIAL
// --- CDC ACM (USB Serial) ---
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, STRID_CDC, 0x85, 0x08, 0x06, 0x86, 0x40),
#endif
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
auto bInterval = 0x01;
switch (get_config().polling_rate_mode) {
case 0:
bInterval = 0x04;
break;
case 1:
bInterval = 0x02;
break;
case 2:
bInterval = 0x01;
break;
}
constexpr auto offset = CONFIG_DESC_LEN_BASE;
descriptor_configuration[offset - 1] = bInterval;
descriptor_configuration[offset - 8] = bInterval;
if (ds_mode()) {
descriptor_configuration[offset - 16] = 0x41;
}else {
descriptor_configuration[offset - 16] = 0xB5;
}
return descriptor_configuration;
}
//--------------------------------------------------------------------+
// HID Report Descriptor
//--------------------------------------------------------------------+
uint8_t const desc_hid_report_ds[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x06, // Report Count (6)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x20, // Usage (0x20)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x39, // Usage (Hat switch)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00, // Unit (None)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0F, // Usage Maximum (0x0F)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x0F, // Report Count (15)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x21, // Usage (0x21)
0x95, 0x0D, // Report Count (13)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x22, // Usage (0x22)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x34, // Report Count (52)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x85, 0x02, // Report ID (2)
0x09, 0x23, // Usage (0x23)
0x95, 0x2F, // Report Count (47)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x05, // Report ID (5)
0x09, 0x33, // Usage (0x33)
0x95, 0x28, // Report Count (40)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x08, // Report ID (8)
0x09, 0x34, // Usage (0x34)
0x95, 0x2F, // Report Count (47)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x09, // Report ID (9)
0x09, 0x24, // Usage (0x24)
0x95, 0x13, // Report Count (19)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x0A, // Report ID (10)
0x09, 0x25, // Usage (0x25)
0x95, 0x1A, // Report Count (26)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x0B, // Report ID (11)
0x09, 0x41, // Usage (0x41)
0x95, 0x29, // Report Count (41)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x0C, // Report ID (12)
0x09, 0x42, // Usage (0x42)
0x95, 0x29, // Report Count (41)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x20, // Report ID (32)
0x09, 0x26, // Usage (0x26)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x21, // Report ID (33)
0x09, 0x27, // Usage (0x27)
0x95, 0x04, // Report Count (4)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x22, // Report ID (34)
0x09, 0x40, // Usage (0x40)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x80, // Report ID (-128)
0x09, 0x28, // Usage (0x28)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x81, // Report ID (-127)
0x09, 0x29, // Usage (0x29)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x82, // Report ID (-126)
0x09, 0x2A, // Usage (0x2A)
0x95, 0x09, // Report Count (9)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x83, // Report ID (-125)
0x09, 0x2B, // Usage (0x2B)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x84, // Report ID (-124)
0x09, 0x2C, // Usage (0x2C)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x85, // Report ID (-123)
0x09, 0x2D, // Usage (0x2D)
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA0, // Report ID (-96)
0x09, 0x2E, // Usage (0x2E)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xE0, // Report ID (-32)
0x09, 0x2F, // Usage (0x2F)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF0, // Report ID (-16)
0x09, 0x30, // Usage (0x30)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF1, // Report ID (-15)
0x09, 0x31, // Usage (0x31)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF2, // Report ID (-14)
0x09, 0x32, // Usage (0x32)
0x95, 0x0F, // Report Count (15)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF4, // Report ID (-12)
0x09, 0x35, // Usage (0x35)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF5, // Report ID (-11)
0x09, 0x36, // Usage (0x36)
0x95, 0x03, // Report Count (3)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF6, // Report ID (-10)
0x09, 0x37, // Usage (Vendor 0x37)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF7, // Report ID (-9)
0x09, 0x38, // Usage (Vendor 0x38)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF8, // Report ID (-8)
0x09, 0x39, // Usage (Vendor 0x39)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF9, // Report ID (-7)
0x09, 0x3A, // Usage (Vendor 0x3A)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
// 321 bytes
};
static_assert(sizeof(desc_hid_report_ds) == 0x0141);
uint8_t const desc_hid_report_dse[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x06, // Report Count (6)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x20, // Usage (0x20)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x39, // Usage (Hat switch)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00, // Unit (None)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0F, // Usage Maximum (0x0F)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x0F, // Report Count (15)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x21, // Usage (0x21)
0x95, 0x0D, // Report Count (13)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x22, // Usage (0x22)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x34, // Report Count (52)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x85, 0x02, // Report ID (2)
0x09, 0x23, // Usage (0x23)
0x95, 0x3F, // Report Count (63)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x05, // Report ID (5)
0x09, 0x33, // Usage (0x33)
0x95, 0x28, // Report Count (40)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x08, // Report ID (8)
0x09, 0x34, // Usage (0x34)
0x95, 0x2F, // Report Count (47)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x09, // Report ID (9)
0x09, 0x24, // Usage (0x24)
0x95, 0x13, // Report Count (19)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x0A, // Report ID (10)
0x09, 0x25, // Usage (0x25)
0x95, 0x1A, // Report Count (26)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x0B, // Report ID (11)
0x09, 0x41, // Usage (0x41)
0x95, 0x29, // Report Count (41)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x0C, // Report ID (12)
0x09, 0x42, // Usage (0x42)
0x95, 0x29, // Report Count (41)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x20, // Report ID (32)
0x09, 0x26, // Usage (0x26)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x21, // Report ID (33)
0x09, 0x27, // Usage (0x27)
0x95, 0x04, // Report Count (4)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x22, // Report ID (34)
0x09, 0x40, // Usage (0x40)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x80, // Report ID (-128)
0x09, 0x28, // Usage (0x28)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x81, // Report ID (-127)
0x09, 0x29, // Usage (0x29)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x82, // Report ID (-126)
0x09, 0x2A, // Usage (0x2A)
0x95, 0x09, // Report Count (9)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x83, // Report ID (-125)
0x09, 0x2B, // Usage (0x2B)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x84, // Report ID (-124)
0x09, 0x2C, // Usage (0x2C)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x85, // Report ID (-123)
0x09, 0x2D, // Usage (0x2D)
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA0, // Report ID (-96)
0x09, 0x2E, // Usage (0x2E)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xE0, // Report ID (-32)
0x09, 0x2F, // Usage (0x2F)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF0, // Report ID (-16)
0x09, 0x30, // Usage (0x30)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF1, // Report ID (-15)
0x09, 0x31, // Usage (0x31)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF2, // Report ID (-14)
0x09, 0x32, // Usage (0x32)
0x95, 0x34, // Report Count (52)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF4, // Report ID (-12)
0x09, 0x35, // Usage (0x35)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF5, // Report ID (-11)
0x09, 0x36, // Usage (0x36)
0x95, 0x03, // Report Count (3)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x60, // Report ID (96)
0x09, 0x41, // Usage (0x41)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x61, // Report ID (97)
0x09, 0x42, // Usage (0x42)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x62, // Report ID (98)
0x09, 0x43, // Usage (0x43)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x63, // Report ID (99)
0x09, 0x44, // Usage (0x44)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x64, // Report ID (100)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x65, // Report ID (101)
0x09, 0x46, // Usage (0x46)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x68, // Report ID (104)
0x09, 0x47, // Usage (0x47)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x70, // Report ID (112)
0x09, 0x48, // Usage (0x48)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x71, // Report ID (113)
0x09, 0x49, // Usage (0x49)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x72, // Report ID (114)
0x09, 0x4A, // Usage (0x4A)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x73, // Report ID (115)
0x09, 0x4B, // Usage (0x4B)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x74, // Report ID (116)
0x09, 0x4C, // Usage (0x4C)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x75, // Report ID (117)
0x09, 0x4D, // Usage (0x4D)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x76, // Report ID (118)
0x09, 0x4E, // Usage (0x4E)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x77, // Report ID (119)
0x09, 0x4F, // Usage (0x4F)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x78, // Report ID (120)
0x09, 0x50, // Usage (0x50)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x79, // Report ID (121)
0x09, 0x51, // Usage (0x51)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x7A, // Report ID (122)
0x09, 0x52, // Usage (0x52)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x7B, // Report ID (123)
0x09, 0x53, // Usage (0x53)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF6, // Report ID (-10)
0x09, 0x37, // Usage (Vendor 0x37)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF7, // Report ID (-9)
0x09, 0x38, // Usage (Vendor 0x38)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF8, // Report ID (-8)
0x09, 0x39, // Usage (Vendor 0x39)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF9, // Report ID (-7)
0x09, 0x3A, // Usage (Vendor 0x3A)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
// 437 bytes
};
static_assert(sizeof(desc_hid_report_dse) == 0x01B5);
// Invoked when received GET HID REPORT DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) {
(void) itf;
if (ds_mode()) {
return desc_hid_report_ds;
}
return desc_hid_report_dse;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
static char const *string_desc_arr[] =
{
(const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
"Sony Interactive Entertainment", // 1: Manufacturer
NULL, // 2: Product
NULL, // 3: Serials will use unique ID if possible
#if ENABLE_SERIAL
"USB Serial", // 4: CDC interface
#endif
};
static uint16_t _desc_str[60 + 1];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void) langid;
size_t chr_count;
if (ds_mode()) {
string_desc_arr[2] = "DualSense Wireless Controller";
}else {
string_desc_arr[2] = "DualSense Edge Wireless Controller";
}
switch (index) {
case STRID_LANGID:
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
break;
case STRID_SERIAL:
chr_count = board_usb_get_serial(_desc_str + 1, 32);
break;
default:
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) return NULL;
const char *str = string_desc_arr[index];
// Cap at max char
chr_count = strlen(str);
size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
if (chr_count > max_count) chr_count = max_count;
// Convert ASCII string into UTF-16
for (size_t i = 0; i < chr_count; i++) {
_desc_str[1 + i] = str[i];
}
break;
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}