Skip to content

Instantly share code, notes, and snippets.

@dogtopus
Last active September 19, 2024 07:45
Show Gist options
  • Save dogtopus/894da226d73afb3bdd195df41b3a26aa to your computer and use it in GitHub Desktop.
Save dogtopus/894da226d73afb3bdd195df41b3a26aa to your computer and use it in GitHub Desktop.
DualSense descriptor
<?xml version="1.0"?>
<!--
DualSense (DS5) USB HID Report Descriptor
Documentation WIP
TODO: Extract info from hid-playstation and cross-verify with us.
-->
<descriptor xmlns="http://digimend.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://digimend.sourceforge.net hidrd.xsd">
<usage_page>desktop<!-- Generic desktop controls (01h) --></usage_page>
<usage>desktop_gamepad<!-- Gamepad (05h, application collection) --></usage>
<COLLECTION type="application">
<!-- Generic Report Begin -->
<report_id>1</report_id>
<!-- Analog Sticks ((X, Y), (Z, RZ)) and Triggers (RX, RY) -->
<usage>desktop_x<!-- X (30h, dynamic value) --></usage>
<usage>desktop_y<!-- Y (31h, dynamic value) --></usage>
<usage>desktop_z<!-- Z (32h, dynamic value) --></usage>
<usage>desktop_rz<!-- Rz (35h, dynamic value) --></usage>
<usage>desktop_rx<!-- Rx (33h, dynamic value) --></usage>
<usage>desktop_ry<!-- Ry (34h, dynamic value) --></usage>
<logical_minimum>0</logical_minimum>
<logical_maximum>255</logical_maximum>
<report_size>8</report_size>
<report_count>6</report_count>
<input>
<variable/>
</input>
<!-- 8-bit Report Sequence ID (increments by 1 between reports) -->
<usage_page>FF00<!-- FF00h, vendor-defined --></usage_page>
<usage>20</usage>
<report_count>1</report_count>
<input>
<variable/>
</input>
<!-- D-Pad -->
<usage_page>desktop<!-- Generic desktop controls (01h) --></usage_page>
<usage>desktop_hat_switch<!-- Hat switch (39h, dynamic value) --></usage>
<logical_minimum>0</logical_minimum>
<logical_maximum>7</logical_maximum>
<physical_minimum>0</physical_minimum>
<physical_maximum>315</physical_maximum>
<unit>
<english_rotation>
<degrees/>
</english_rotation>
</unit>
<report_size>4</report_size>
<report_count>1</report_count>
<input>
<variable/>
<null_state/>
</input>
<unit>
<none/>
</unit>
<!-- Buttons -->
<!-- S X O T L1 R1 L2 R2 SHR OPT L3 R3 PS TP MIC -->
<usage_page>button<!-- Button (09h) --></usage_page>
<usage_minimum>01</usage_minimum>
<usage_maximum>0F</usage_maximum>
<logical_minimum>0</logical_minimum>
<logical_maximum>1</logical_maximum>
<report_size>1</report_size>
<report_count>15</report_count>
<input>
<variable/>
</input>
<!-- Padding for buttons (?) -->
<usage_page>FF00<!-- FF00h, vendor-defined --></usage_page>
<usage>21</usage>
<report_count>13</report_count>
<input>
<variable/>
</input>
<!-- Extended Report -->
<!--
typedef struct {
union {
struct {
int16_t pitch;
int16_t yaw;
int16_t roll;
};
struct {
int16_t x;
int16_t y; // up
int16_t z;
};
};
} ds5_vec3_t;
typedef struct {
union {
int16_t raw[6];
struct {
ds5_vec3_t gyro;
ds5_vec3_t accel;
};
};
} ds5_imu_t;
typedef struct {
uint32_t pos[2]; // probably the same as ds4 (i.e. yyyyyyyyyyyyxxxxxxxxxxxxrsssssss, r: released, s: sequence_id). Too lazy to check...
uint8_t touch_timestamp;
} ds5_touch_t;
typedef struct {
uint32_t coarse_timestamp; // 1/256 seconds? random value on startup?
ds5_imu_t imu_data; // TODO calibrations?
uint32_t fine_timestamp; // 1/3 us increments
uint8_t TODO1; // seems to change between 8 and 18. Could be battery and charging related.
ds5_touch_t touchpad_data;
uint8_t TODO2[7]; // reads 09090000000000
uint32_t another_fine_timestamp; // 1/3 us increments. Seems to have a delay of couple us compare to fine_timestamp.
uint8_t TODO3; // 0x28 or 0x17 for me.
uint8_t state_ext; // optional peripheral state. 0x08: nothing, 0x09: trs 3.5mm connector, 0x0b: trrs 3.5mm connector
uint8_t TODO4; // padding?
uint8_t checksum[8]; // custom poly crc64? some sort of MAC?
} ds5_ext_report_t;
-->
<usage_page>FF00<!-- FF00h, vendor-defined --></usage_page>
<usage>22</usage>
<logical_minimum>0</logical_minimum>
<logical_maximum>255</logical_maximum>
<report_size>8</report_size>
<report_count>52</report_count>
<input>
<variable/>
</input>
<!-- Generic Report End -->
<!-- Feedback Report (Rumble?, LED, etc.) -->
<!--
typedef struct {
// Screw this I'll leave it to hid-sony maintainer's internal doc S:
// No he won't implement it. So maybe use DS4Windows docs for now.
uint8_t type; // TODO. 0x6: vibrating, 0x23: 2step
uint8_t params[10]; // 0x6: 0: frequency (1-255), 1: off time (1-255). 0x23: 0: step1 resistance (0-15), 1: step2 resistance (0-15)
} ds5_trigger_t;
typedef struct {
uint16_t flags; // @ 0-1. bitfield fedcba9876543210. 012: rumble emulation (seems that the lowest nibble has to be 0x7 (????????????0111) in order to trigger this), 2: trigger_r, 3: trigger_l, 8: mic_led, a: lightbar, c: player_led
uint8_t rumble_r; // @ 2
uint8_t rumble_l; // @ 3
uint8_t unk3[4]; // @ 4-7
uint8_t mic_led; // @ 8. 0: off, 1: on, 2: pulse
uint8_t unk9; // @ 9
ds5_trigger_t trigger_r;// 10-20
ds5_trigger_t trigger_l; // 21-31
uint8_t unk28[11]; // @ 32-42
uint8_t player_led; // @ 43. 5-bit. LSB is left.
union {
uint8_t lightbar_rgb[3];
struct {
uint8_t lightbar_r;
uint8_t lightbar_g;
uint8_t lightbar_b;
};
}; // @ 44-46
} ds5_feedback_t;
-->
<report_id>2</report_id>
<usage>23</usage>
<report_count>47</report_count>
<output>
<variable/>
</output>
<!-- Get Sensor Calibration -->
<!-- See https://github.com/torvalds/linux/blob/c500bee1c5b2f1d59b1081ac879d73268ab0ff17/drivers/hid/hid-playstation.c#L652-L668 for details -->
<!-- Last 4 bytes are CRC32 (Bluetooth-only, SBZ on USB) -->
<report_id>5</report_id>
<usage>33</usage>
<report_count>40</report_count>
<feature>
<variable/>
</feature>
<!-- SET -->
<report_id>8</report_id>
<usage>34</usage>
<report_count>47</report_count>
<feature>
<variable/>
</feature>
<!-- Get Pair Info (Device and Host BDADDR) -->
<!--
typedef struct {
uint8_t device_bdaddr[6]; // Little endian
uint8_t unk[3]; // seems to be constant. Purpose unknown.
uint8_t host_bdaddr[6]; // Little endian
uint32_t crc32_optional;
} ds5_pair_info_t;
-->
<report_id>9</report_id>
<usage>24</usage>
<report_count>19</report_count>
<feature>
<variable/>
</feature>
<!-- Perform Easy Pair (Set Link Key) -->
<!--
typedef struct {
uint8_t host_bdaddr[6]; // Little endian
uint8_t link_key[16];
uint32_t crc32_optional;
} ds5_pair_info_t;
-->
<report_id>10</report_id>
<usage>25</usage>
<report_count>26</report_count>
<feature>
<variable/>
</feature>
<!-- Get Controller Revision -->
<!-- Mine has build timestamp 2020-05-19 02:04:33, fw vesion 0x128 (pre-PS5 launch) -->
<!-- PS5 launch bundle: 2020-08-18 06:20:29, fw vesion 0x204 (https://github.com/Ryochan7/DS4Windows/issues/1545#issuecomment-728173979)-->
<!--
typedef struct {
char timestamp[19];
uint32_t versions[10]; // versions[6]: firmware version
uint32_t crc32; // 0 via USB
} ds5_revision_t;
-->
<report_id>32</report_id>
<usage>26</usage>
<report_count>63</report_count>
<feature>
<variable/>
</feature>
<!-- SET -->
<report_id>33</report_id>
<usage>27</usage>
<report_count>4</report_count>
<feature>
<variable/>
</feature>
<!-- GET -->
<report_id>34</report_id>
<usage>40</usage>
<report_count>63</report_count>
<feature>
<variable/>
</feature>
<!-- SET -->
<report_id>128</report_id>
<usage>28</usage>
<report_count>63</report_count>
<feature>
<variable/>
</feature>
<!-- GET -->
<report_id>129</report_id>
<usage>29</usage>
<report_count>63</report_count>
<feature>
<variable/>
</feature>
<!-- SET -->
<report_id>130</report_id>
<usage>2A</usage>
<report_count>9</report_count>
<feature>
<variable/>
</feature>
<!-- GET -->
<report_id>131</report_id>
<usage>2B</usage>
<report_count>63</report_count>
<feature>
<variable/>
</feature>
<!-- SET -->
<report_id>132</report_id>
<usage>2C</usage>
<report_count>63</report_count>
<feature>
<variable/>
</feature>
<!-- GET (DS5 returned 3 bytes?) -->
<report_id>133</report_id>
<usage>2D</usage>
<report_count>2</report_count>
<feature>
<variable/>
</feature>
<!-- SET -->
<report_id>160</report_id>
<usage>2E</usage>
<report_count>1</report_count>
<feature>
<variable/>
</feature>
<!-- GET -->
<report_id>224</report_id>
<usage>2F</usage>
<report_count>63</report_count>
<feature>
<variable/>
</feature>
<!-- Authentication Begin -->
<!-- Set Challenge -->
<!--
typedef struct {
uint8_t request_type; // very wild guesses: 0: exchange certificate? 1: set salt? 2: actual encrypted challenge?
uint8_t seq;
uint8_t page;
uint8_t payload[56];
uint32_t checksum; // VANILLA zlib crc32
} ds4_auth_req_t;
-->
<report_id>240</report_id>
<usage>30</usage>
<report_count>63</report_count>
<feature>
<variable/>
</feature>
<!-- Get Response -->
<!--
typedef struct {
uint8_t response_type; // corresponding to request type
uint8_t seq;
uint8_t page; // 0-3?
uint8_t payload[56];
uint32_t checksum; // 0 via USB, unconfirmed via Bluetooth
} ds4_auth_res_t;
-->
<report_id>241</report_id>
<usage>31</usage>
<report_count>63</report_count>
<feature>
<variable/>
</feature>
<!-- Get Status -->
<!--
typedef struct {
uint8_t unk0; // 0?
uint8_t seq;
uint8_t status; // 0x10: ready, 0x80: wrong checksum?, 0x51: page out of order?, 0x0: ok?
uint8_t sbz[8]; // Structure unknown
uint32_t checksum; // 0 via USB, unconfirmed via Bluetooth
} ds4_auth_res_t;
-->
<report_id>242</report_id>
<usage>32</usage>
<report_count>15</report_count>
<feature>
<variable/>
</feature>
<!-- Authentication End (?) -->
<!-- SET -->
<report_id>244</report_id>
<usage>35</usage>
<report_count>63</report_count>
<feature>
<variable/>
</feature>
<!-- GET -->
<report_id>245</report_id>
<usage>36</usage>
<report_count>3</report_count>
<feature>
<variable/>
</feature>
</COLLECTION>
</descriptor>
00000000: 0501 0905 a101 8501 0930 0931 0932 0935 .........0.1.2.5
00000010: 0933 0934 1500 26ff 0075 0895 0681 0206 .3.4..&..u......
00000020: 00ff 0920 9501 8102 0501 0939 1500 2507 ... .......9..%.
00000030: 3500 463b 0165 1475 0495 0181 4265 0005 5.F;.e.u....Be..
00000040: 0919 0129 0f15 0025 0175 0195 0f81 0206 ...)...%.u......
00000050: 00ff 0921 950d 8102 0600 ff09 2215 0026 ...!........"..&
00000060: ff00 7508 9534 8102 8502 0923 952f 9102 ..u..4.....#./..
00000070: 8505 0933 9528 b102 8508 0934 952f b102 ...3.(.....4./..
00000080: 8509 0924 9513 b102 850a 0925 951a b102 ...$.......%....
00000090: 8520 0926 953f b102 8521 0927 9504 b102 . .&.?...!.'....
000000a0: 8522 0940 953f b102 8580 0928 953f b102 .".@.?.....(.?..
000000b0: 8581 0929 953f b102 8582 092a 9509 b102 ...).?.....*....
000000c0: 8583 092b 953f b102 8584 092c 953f b102 ...+.?.....,.?..
000000d0: 8585 092d 9502 b102 85a0 092e 9501 b102 ...-............
000000e0: 85e0 092f 953f b102 85f0 0930 953f b102 .../.?.....0.?..
000000f0: 85f1 0931 953f b102 85f2 0932 950f b102 ...1.?.....2....
00000100: 85f4 0935 953f b102 85f5 0936 9503 b102 ...5.?.....6....
00000110: c0
typedef struct {
uint16_t unk_0; // always 0x10? key type?
uint16_t device_type; // ?. 1: console, 2: ds5
uint8_t padding[12]; // ?
char serial_number[16]; // in ASCII
uint8_t unk_32[128]; // ecc 512-bit signature?
} ds5_identity_t;
typedef struct {
uint32_t unk0; // always 0x01?
uint8_t hash_ish[16]; // MAC?
ds5_identity_t identity;
} ds5_auth_type_0_request_t;
typedef struct {
uint8_t hash_ish[16]; // MAC?
ds5_identity_t identity;
} ds5_auth_type_0_response_t;
typedef struct {
uint8_t hash_ish_1[16]; // MAC?
uint32_t unk0; // always 0x01?
uint32_t padding[2]; // ?
uint8_t hash_ish_2[16]; // 128-bit salt?
} ds5_auth_type_1_request_t;
typedef struct {
uint32_t unk0; // always 0x01?
uint8_t hash_ish[16]; // challenge?
} ds5_auth_type_2_request_t;
typedef struct {
uint8_t hash_ish[32]; // ecc signature? sha256-hmac? hash+response?
} ds5_auth_type_2_response_t;
$ sudo lsusb -vd 054c:0ce6
Bus 002 Device 017: ID 054c:0ce6 Sony Corp. Wireless Controller
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x054c Sony Corp.
idProduct 0x0ce6
bcdDevice 1.00
iManufacturer 1 Sony Interactive Entertainment
iProduct 2 Wireless Controller
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x00e3
bNumInterfaces 4
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xc0
Self Powered
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 1 Audio
bInterfaceSubClass 1 Control Device
bInterfaceProtocol 0
iInterface 0
AudioControl Interface Descriptor:
bLength 10
bDescriptorType 36
bDescriptorSubtype 1 (HEADER)
bcdADC 1.00
wTotalLength 0x0049
bInCollection 2
baInterfaceNr(0) 1
baInterfaceNr(1) 2
AudioControl Interface Descriptor:
bLength 12
bDescriptorType 36
bDescriptorSubtype 2 (INPUT_TERMINAL)
bTerminalID 1
wTerminalType 0x0101 USB Streaming
bAssocTerminal 6
bNrChannels 4
wChannelConfig 0x0033
Left Front (L)
Right Front (R)
Left Surround (LS)
Right Surround (RS)
iChannelNames 0
iTerminal 0
AudioControl Interface Descriptor:
bLength 12
bDescriptorType 36
bDescriptorSubtype 6 (FEATURE_UNIT)
bUnitID 2
bSourceID 1
bControlSize 1
bmaControls(0) 0x03
Mute Control
Volume Control
bmaControls(1) 0x00
bmaControls(2) 0x00
bmaControls(3) 0x00
bmaControls(4) 0x00
iFeature 0
AudioControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 3 (OUTPUT_TERMINAL)
bTerminalID 3
wTerminalType 0x0301 Speaker
bAssocTerminal 4
bSourceID 2
iTerminal 0
AudioControl Interface Descriptor:
bLength 12
bDescriptorType 36
bDescriptorSubtype 2 (INPUT_TERMINAL)
bTerminalID 4
wTerminalType 0x0402 Headset
bAssocTerminal 3
bNrChannels 2
wChannelConfig 0x0003
Left Front (L)
Right Front (R)
iChannelNames 0
iTerminal 0
AudioControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 6 (FEATURE_UNIT)
bUnitID 5
bSourceID 4
bControlSize 1
bmaControls(0) 0x03
Mute Control
Volume Control
bmaControls(1) 0x00
iFeature 0
AudioControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 3 (OUTPUT_TERMINAL)
bTerminalID 6
wTerminalType 0x0101 USB Streaming
bAssocTerminal 1
bSourceID 5
iTerminal 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 0
iInterface 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 1
bNumEndpoints 1
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 0
iInterface 0
AudioStreaming Interface Descriptor:
bLength 7
bDescriptorType 36
bDescriptorSubtype 1 (AS_GENERAL)
bTerminalLink 1
bDelay 1 frames
wFormatTag 0x0001 PCM
AudioStreaming Interface Descriptor:
bLength 11
bDescriptorType 36
bDescriptorSubtype 2 (FORMAT_TYPE)
bFormatType 1 (FORMAT_TYPE_I)
bNrChannels 4
bSubframeSize 2
bBitResolution 16
bSamFreqType 1 Discrete
tSamFreq[ 0] 48000
Endpoint Descriptor:
bLength 9
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 9
Transfer Type Isochronous
Synch Type Adaptive
Usage Type Data
wMaxPacketSize 0x0188 1x 392 bytes
bInterval 4
bRefresh 0
bSynchAddress 0
AudioStreaming Endpoint Descriptor:
bLength 7
bDescriptorType 37
bDescriptorSubtype 1 (EP_GENERAL)
bmAttributes 0x00
bLockDelayUnits 0 Undefined
wLockDelay 0x0000
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 0
iInterface 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 1
bNumEndpoints 1
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 0
iInterface 0
AudioStreaming Interface Descriptor:
bLength 7
bDescriptorType 36
bDescriptorSubtype 1 (AS_GENERAL)
bTerminalLink 6
bDelay 1 frames
wFormatTag 0x0001 PCM
AudioStreaming Interface Descriptor:
bLength 11
bDescriptorType 36
bDescriptorSubtype 2 (FORMAT_TYPE)
bFormatType 1 (FORMAT_TYPE_I)
bNrChannels 2
bSubframeSize 2
bBitResolution 16
bSamFreqType 1 Discrete
tSamFreq[ 0] 48000
Endpoint Descriptor:
bLength 9
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x00c4 1x 196 bytes
bInterval 4
bRefresh 0
bSynchAddress 0
AudioStreaming Endpoint Descriptor:
bLength 7
bDescriptorType 37
bDescriptorSubtype 1 (EP_GENERAL)
bmAttributes 0x00
bLockDelayUnits 0 Undefined
wLockDelay 0x0000
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 3
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.11
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 273
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x84 EP 4 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 6
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 6
Device Qualifier (for other device speed):
bLength 10
bDescriptorType 6
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
bNumConfigurations 1
can't get debug descriptor: Resource temporarily unavailable
Device Status: 0x0000
(Bus Powered)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment