Reverse engineering¶
Those observations come from different sources:
- https://eleccelerator.com/wiki/index.php?title=DualShock_4
- The Linux kernel sony-hid driver: https://github.com/torvalds/linux/blob/master/drivers/hid/hid-sony.c
- My own experiments
The Dualshock used is a recent version (product 0x9cc).
PS4/Dualshock¶
Device descriptor¶
Not much to see here.
Descriptor Length: 12
Descriptor type: 01
USB version: 0200
Device class: 00
Device Subclass: 00
Device Protocol: 00
Max.packet size: 40
Vendor ID: 054C
Product ID: 09CC
Revision ID: 0100
Mfg.string index: 01
Prod.string index: 02
Serial number index: 00
Number of conf.: 01
Configuration descriptor¶
Decoded from a raw dump courtesy of https://eleccelerator.com/usbdescreqparser/
225 bytes
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0xE1, 0x00, // wTotalLength 225
0x04, // bNumInterfaces 4
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0xC0, // bmAttributes Self Powered
0xFA, // bMaxPower 500mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x00, // bNumEndpoints 0
0x01, // bInterfaceClass (Audio)
0x01, // bInterfaceSubClass (Audio Control)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x0A, // bLength
0x24, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_INTERFACE -> HEADER)
0x00, 0x01, // bcdADC 1.00
0x47, 0x00, // wTotalLength 71
0x02, // binCollection 0x02
0x01, // baInterfaceNr 1
0x02, // baInterfaceNr 2
0x0C, // bLength
0x24, // bDescriptorType (See Next Line)
0x02, // bDescriptorSubtype (CS_INTERFACE -> INPUT_TERMINAL)
0x01, // bTerminalID
0x01, 0x01, // wTerminalType (USB Streaming)
0x06, // bAssocTerminal
0x02, // bNrChannels 2
0x03, 0x00, // wChannelConfig (Left and Right Front)
0x00, // iChannelNames
0x00, // iTerminal
0x0A, // bLength
0x24, // bDescriptorType (See Next Line)
0x06, // bDescriptorSubtype (CS_INTERFACE -> FEATURE_UNIT)
0x02, // bUnitID
0x01, // bSourceID
0x01, // bControlSize 1
0x03, 0x00, // bmaControls[0] (Mute,Volume)
0x00, 0x00, // bmaControls[1] (None)
0x09, // bLength
0x24, // bDescriptorType (See Next Line)
0x03, // bDescriptorSubtype (CS_INTERFACE -> OUTPUT_TERMINAL)
0x03, // bTerminalID
0x02, 0x04, // wTerminalType (Headset)
0x04, // bAssocTerminal
0x02, // bSourceID
0x00, // iTerminal
0x0C, // bLength
0x24, // bDescriptorType (See Next Line)
0x02, // bDescriptorSubtype (CS_INTERFACE -> INPUT_TERMINAL)
0x04, // bTerminalID
0x02, 0x04, // wTerminalType (Headset)
0x03, // bAssocTerminal
0x01, // bNrChannels 1
0x00, 0x00, // wChannelConfig
0x00, // iChannelNames
0x00, // iTerminal
0x09, // bLength
0x24, // bDescriptorType (See Next Line)
0x06, // bDescriptorSubtype (CS_INTERFACE -> FEATURE_UNIT)
0x05, // bUnitID
0x04, // bSourceID
0x01, // bControlSize 1
0x03, 0x00, // bmaControls[0] (Mute,Volume)
0x00, // iFeature
0x09, // bLength
0x24, // bDescriptorType (See Next Line)
0x03, // bDescriptorSubtype (CS_INTERFACE -> OUTPUT_TERMINAL)
0x06, // bTerminalID
0x01, 0x01, // wTerminalType (USB Streaming)
0x01, // bAssocTerminal
0x05, // bSourceID
0x00, // iTerminal
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x01, // bInterfaceNumber 1
0x00, // bAlternateSetting
0x00, // bNumEndpoints 0
0x01, // bInterfaceClass (Audio)
0x02, // bInterfaceSubClass (Audio Streaming)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x01, // bInterfaceNumber 1
0x01, // bAlternateSetting
0x01, // bNumEndpoints 1
0x01, // bInterfaceClass (Audio)
0x02, // bInterfaceSubClass (Audio Streaming)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x07, // bLength
0x24, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_INTERFACE -> AS_GENERAL)
0x01, // bTerminalLink
0x01, // bDelay 1
0x01, 0x00, // wFormatTag (PCM)
0x0B, // bLength
0x24, // bDescriptorType (See Next Line)
0x02, // bDescriptorSubtype (CS_INTERFACE -> FORMAT_TYPE)
0x01, // bFormatType 1
0x02, // bNrChannels (Stereo)
0x02, // bSubFrameSize 2
0x10, // bBitResolution 16
0x01, // bSamFreqType 1
0x00, 0x7D, 0x00, // tSamFreq[1] 32000 Hz
0x09, // bLength
0x05, // bDescriptorType (See Next Line)
0x01, // bEndpointAddress (OUT/H2D)
0x09, // bmAttributes (Isochronous, Adaptive, Data EP)
0x84, 0x00, // wMaxPacketSize 132
0x01, // bInterval 1 (unit depends on device speed)
0x00, // bRefresh
0x00, // bSyncAddress
0x07, // bLength
0x25, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_ENDPOINT -> EP_GENERAL)
0x00, // bmAttributes (None)
0x00, // bLockDelayUnits
0x00, 0x00, // wLockDelay 0
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x02, // bInterfaceNumber 2
0x00, // bAlternateSetting
0x00, // bNumEndpoints 0
0x01, // bInterfaceClass (Audio)
0x02, // bInterfaceSubClass (Audio Streaming)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x02, // bInterfaceNumber 2
0x01, // bAlternateSetting
0x01, // bNumEndpoints 1
0x01, // bInterfaceClass (Audio)
0x02, // bInterfaceSubClass (Audio Streaming)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x07, // bLength
0x24, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_INTERFACE -> AS_GENERAL)
0x06, // bTerminalLink
0x01, // bDelay 1
0x01, 0x00, // wFormatTag (PCM)
0x0B, // bLength
0x24, // bDescriptorType (See Next Line)
0x02, // bDescriptorSubtype (CS_INTERFACE -> FORMAT_TYPE)
0x01, // bFormatType 1
0x01, // bNrChannels (Mono)
0x02, // bSubFrameSize 2
0x10, // bBitResolution 16
0x01, // bSamFreqType 1
0x80, 0x3E, 0x00, // tSamFreq[1] 16000 Hz
0x09, // bLength
0x05, // bDescriptorType (See Next Line)
0x82, // bEndpointAddress (IN/D2H)
0x05, // bmAttributes (Isochronous, Async, Data EP)
0x22, 0x00, // wMaxPacketSize 34
0x01, // bInterval 1 (unit depends on device speed)
0x00, // bRefresh
0x00, // bSyncAddress
0x07, // bLength
0x25, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_ENDPOINT -> EP_GENERAL)
0x00, // bmAttributes (None)
0x00, // bLockDelayUnits
0x00, 0x00, // wLockDelay 0
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x03, // bInterfaceNumber 3
0x00, // bAlternateSetting
0x02, // bNumEndpoints 2
0x03, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x21, // bDescriptorType (HID)
0x11, 0x01, // bcdHID 1.11
0x00, // bCountryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType[0] (HID)
0xFB, 0x01, // wDescriptorLength[0] 507
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x84, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x05, // bInterval 5 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x03, // bEndpointAddress (OUT/H2D)
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x05, // bInterval 5 (unit depends on device speed)
HID report descriptor¶
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)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
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, 0x0E, // Usage Maximum (0x0E)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x0E, // Report Count (14)
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)
0x75, 0x06, // Report Size (6)
0x95, 0x01, // Report Count (1)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x7F, // Logical Maximum (127)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
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, 0x02, // Report Count (2)
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, 0x36, // Report Count (54)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x85, 0x05, // Report ID (5)
0x09, 0x22, // Usage (0x22)
0x95, 0x1F, // Report Count (31)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x04, // Report ID (4)
0x09, 0x23, // Usage (0x23)
0x95, 0x24, // Report Count (36)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x02, // Report ID (2)
0x09, 0x24, // Usage (0x24)
0x95, 0x24, // Report Count (36)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x08, // Report ID (8)
0x09, 0x25, // Usage (0x25)
0x95, 0x03, // Report Count (3)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x10, // Report ID (16)
0x09, 0x26, // Usage (0x26)
0x95, 0x04, // Report Count (4)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x11, // Report ID (17)
0x09, 0x27, // Usage (0x27)
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x12, // Report ID (18)
0x06, 0x02, 0xFF, // Usage Page (Vendor Defined 0xFF02)
0x09, 0x21, // Usage (0x21)
0x95, 0x0F, // Report Count (15)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x13, // Report ID (19)
0x09, 0x22, // Usage (0x22)
0x95, 0x16, // Report Count (22)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x14, // Report ID (20)
0x06, 0x05, 0xFF, // Usage Page (Vendor Defined 0xFF05)
0x09, 0x20, // Usage (0x20)
0x95, 0x10, // Report Count (16)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x15, // Report ID (21)
0x09, 0x21, // Usage (0x21)
0x95, 0x2C, // Report Count (44)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x80, 0xFF, // Usage Page (Vendor Defined 0xFF80)
0x85, 0x80, // Report ID (-128)
0x09, 0x20, // Usage (0x20)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x81, // Report ID (-127)
0x09, 0x21, // Usage (0x21)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x82, // Report ID (-126)
0x09, 0x22, // Usage (0x22)
0x95, 0x05, // Report Count (5)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x83, // Report ID (-125)
0x09, 0x23, // Usage (0x23)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x84, // Report ID (-124)
0x09, 0x24, // Usage (0x24)
0x95, 0x04, // Report Count (4)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x85, // Report ID (-123)
0x09, 0x25, // Usage (0x25)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x86, // Report ID (-122)
0x09, 0x26, // Usage (0x26)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x87, // Report ID (-121)
0x09, 0x27, // Usage (0x27)
0x95, 0x23, // Report Count (35)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x88, // Report ID (-120)
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, 0x89, // Report ID (-119)
0x09, 0x29, // Usage (0x29)
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x90, // Report ID (-112)
0x09, 0x30, // Usage (0x30)
0x95, 0x05, // Report Count (5)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x91, // Report ID (-111)
0x09, 0x31, // Usage (0x31)
0x95, 0x03, // Report Count (3)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x92, // Report ID (-110)
0x09, 0x32, // Usage (0x32)
0x95, 0x03, // Report Count (3)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x93, // Report ID (-109)
0x09, 0x33, // Usage (0x33)
0x95, 0x0C, // Report Count (12)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x94, // Report ID (-108)
0x09, 0x34, // Usage (0x34)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA0, // Report ID (-96)
0x09, 0x40, // Usage (0x40)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA1, // Report ID (-95)
0x09, 0x41, // Usage (0x41)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA2, // Report ID (-94)
0x09, 0x42, // Usage (0x42)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA3, // Report ID (-93)
0x09, 0x43, // Usage (0x43)
0x95, 0x30, // Report Count (48)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA4, // Report ID (-92)
0x09, 0x44, // Usage (0x44)
0x95, 0x0D, // Report Count (13)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF0, // Report ID (-16)
0x09, 0x47, // Usage (0x47)
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, 0x48, // Usage (0x48)
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, 0x49, // Usage (0x49)
0x95, 0x0F, // Report Count (15)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA7, // Report ID (-89)
0x09, 0x4A, // Usage (0x4A)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA8, // Report ID (-88)
0x09, 0x4B, // Usage (0x4B)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA9, // Report ID (-87)
0x09, 0x4C, // Usage (0x4C)
0x95, 0x08, // Report Count (8)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAA, // Report ID (-86)
0x09, 0x4E, // Usage (0x4E)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAB, // Report ID (-85)
0x09, 0x4F, // Usage (0x4F)
0x95, 0x39, // Report Count (57)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAC, // Report ID (-84)
0x09, 0x50, // Usage (0x50)
0x95, 0x39, // Report Count (57)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAD, // Report ID (-83)
0x09, 0x51, // Usage (0x51)
0x95, 0x0B, // Report Count (11)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAE, // Report ID (-82)
0x09, 0x52, // Usage (0x52)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAF, // Report ID (-81)
0x09, 0x53, // Usage (0x53)
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xB0, // Report ID (-80)
0x09, 0x54, // Usage (0x54)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xE0, // Report ID (-32)
0x09, 0x57, // Usage (0x57)
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xB3, // Report ID (-77)
0x09, 0x55, // Usage (0x55)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xB4, // Report ID (-76)
0x09, 0x55, // Usage (0x55)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xB5, // Report ID (-75)
0x09, 0x56, // Usage (0x56)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xD0, // Report ID (-48)
0x09, 0x58, // Usage (0x58)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xD4, // Report ID (-44)
0x09, 0x59, // Usage (0x59)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
Sony likes its vendor-defined stuff.
Input report structure¶
This is the USB 0x01 report descriptor. Over BT, the report ID is 0x11 and it’s followed by two bytes (0xc0 0x00), so all subsequent offsets must be adjusted.
Offset | Type | Meaning |
---|---|---|
0 | uint8 | Report ID |
1 | uint8 | Left pad X (0x00 is left, 0xFF right) |
2 | uint8 | Left pad Y (0x00 is up, 0xFF down) |
3 | uint8 | Right pad X |
4 | uint8 | Right pad Y |
5 | uint4 | DPAD (bits 0-3). 0x8 is released, 0x0 is N, 0x1 is NE, etc. |
5 | bool | Square (bit 4) |
5 | bool | Cross (bit 5) |
5 | bool | Circle (bit 6) |
5 | bool | Triangle (bit 7) |
6 | bool | L1 (bit 0) |
6 | bool | R1 (bit 1) |
6 | bool | L2 (bit 2) |
6 | bool | R2 (bit 3) |
6 | bool | Share (bit 4) |
6 | bool | Options (bit 5) |
6 | bool | L3 (bit 6) |
6 | bool | R3 (bit 7) |
7 | bool | PS (bit 0) |
7 | bool | TPad (bit 1) |
7 | uint6 | Incremental counter (bits 2-7). |
8 | uint8 | L2 value (0x00 = released, 0xFF = fully pressed) |
9 | uint8 | R2 value |
10-11 | uint16 | Timestamp in 5.33 microseconds units |
12 | uint8 | Unknown, maybe battery level, but this would be redundant with offset 23 |
13-14 | int16 | Gyro X raw value |
15-16 | int16 | Gyro Y raw value |
17-18 | int16 | Gyro Z raw value |
19-20 | int16 | Accelerometer X raw value |
21-22 | int16 | Accelerometer Y raw value |
23-24 | int16 | Accelerometer Z raw value |
25-29 | Unknown, set to 0x00 | |
30 | uint4 | Battery level (bits 0-3). See below. |
30 | bool | Cable state (bit 4) |
30 | Unknown (bits 5-7) | |
31-32 | Unknown | |
33 | uint8 | Touch event count |
34 | Unknown | |
About the battery level at offset 23: according to the sony-hid driver sources, the range is 0..9 when running on battery, 0..10 when connected to power. More than 10 and connected means battery fully charged.
The rest of the report starting at offset 35 is an array of touchpad events. Each event has the following structure:
Offset | Type | Meaning |
---|---|---|
0 | uint8 | Timestamp |
1 | uint7 | Previous event counter (bits 0-6) |
1 | bool | Previous event finger down (bit 7, 0=touch) |
2-4 | Previous position, in 12 bits coordinates X/Y | |
5 | uint7 | Current event counter (bits 0-6) |
5 | bool | Current event finger down (bit 7) |
6-8 | Current position | |
Note
The maximum number of touch events is 3 over USB and 4 over BT. In each case the rest of the report (2 remaining bytes for USB, 5 for BT) is “unknown”.
Remarks¶
The configuration descriptor defines 3 audio interfaces (0, 1, 2) with 1 and 2 having alternate settings. The PS4 is very picky about this. Only spoofing the HID interface will seem to work, in the sense that the “boot” sequence will be identical, but the PS4 will not acknowledge the controller completely and will get stuck on the “Press PS” screen.
So, when spoofing the DualShock, the device must send the exact same USB descriptor. The actual audio interfaces do not need to be implemented when dealing with the PS4. On the other hand, mac OS (and probably others) will reset the device if they aren’t implemented. That is why Host.cpp has some logic to detect if it’s plugged to a PS4 or a PC; in the latter case audio interfaces are not included in the USB descriptor.
Known feature reports¶
GET_REPORT 0x02¶
This report contains IMU calibration data. When the Dualshock is paired via Bluetooth, this has the additional side effect of changing the input report type from the default 0x01 (pretty limited, with only buttons and triggers, see DS4Structs.h) to 0x11, which is identical in structure to the USB input reports 0x01, only larger (4 possible touch events instead of 3).
Everything is little-endian.
Offset | Type | Meaning |
---|---|---|
0 | uint8 | Report ID (0x02) |
1-2 | int16 | Gyroscope X bias |
3-4 | int16 | Gyroscope Y bias |
5-6 | int16 | Gyroscope Z bias |
7-8 | int16 | Gyroscope X maximum |
9-10 | int16 | Gyroscope X minimum |
11-12 | int16 | Gyroscope Y maximum |
13-14 | int16 | Gyroscope Y minimum |
15-16 | int16 | Gyroscope Z maximum |
17-18 | int16 | Gyroscope Z minimum |
18-19 | int16 | Gyroscope speed maximum |
20-21 | int16 | Gyroscope speed minimum |
22-23 | int16 | Accelerometer X maximum |
24-25 | int16 | Accelerometer X minimum |
26-27 | int16 | Accelerometer Y maximum |
28-29 | int16 | Accelerometer Y minimum |
30-31 | int16 | Accelerometer Z maximum |
32-33 | int16 | Accelerometer Z minimum |
34-36 | Unknown | |
See IMU calibration
GET_REPORT 0xa3¶
This contains some time of manufacture information, part of it in plain text. Not entirely deciphered though. There is a human-readable date and time. According to the Linux kernel driver, the hardware version of the controller lies at offset 35 and the firmware version at offset 41 (both little-endian 16 bits unsigned).
GET_REPORT 0x12¶
This contains information about the Dualshock pairing “state”.
Offset | Type | Meaning |
---|---|---|
0 | uint8 | Report ID (0x12) |
1-6 | BT address of the Dualshock | |
7-9 | Seems constant to 0x08 0x25 0x00 | |
10-15 | BT address of the last device the DualShock paired with | |
The last 6 bytes are set to 0x00 if the Dualshock was never paired.
GET_REPORT 0x81¶
This contains the Dualshock’s BT address.
Offset | Type | Meaning |
---|---|---|
0 | uint8 | Report ID (0x81) |
1-6 | BT address of the Dualshock | |
SET_REPORT 0x13¶
This contains the PS4 BT address, and the link key for BT encryption.
Offset | Type | Meaning |
---|---|---|
0 | uint8 | Report ID (0x13) |
1-6 | Host (PS4) BT address | |
7-22 | Link key | |
SET_REPORT 0x14¶
Offset | Type | Meaning |
---|---|---|
0 | uint8 | Report ID (0x14) |
1 | uint8 | Command (see below) |
2-15 | Filled with NUL | |
‘Command’ may take the following values:
- 0x01: Pair with the PS4
- 0x02: Unpair
See also Bluetooth is mandatory
Authentication challenge¶
The host sends several SET_REPORT 0xf0 containing challenge data, then checks challenge response availability through GET_REPORT 0xf2, and finally collects the response with GET_REPORT 0xf1. This is all explained in https://eleccelerator.com/wiki/index.php?title=DualShock_4#0xf1
Boot sequence¶
When the Dualshock is plugged to the Playstation, the following happens:
- GET_REPORT 0x02
- GET_REPORT 0xa3
- GET_REPORT 0x12
Then, if the paired address from report 0x12 did not match the PS4’s:
- SET_REPORT 0x13
- SET_REPORT 0x14 with value 0x02
Then, after pressing PS
- SET_REPORT 0x14 with value 0x01
Interrupt OUT reports start coming in after this (actually after the Dualshock is connected through Bluetooth).
IMU calibration¶
The 0x02 report contains IMU calibration data as explained above; calibrated values can be computed from the raw ones using the following formulae.
Gyroscope¶
speed = (max_speed + min_speed) / 2
value = speed * (raw_value - bias) / (max_value - min_value)
In degrees/s.
Note
There’s a 2 factor in the Linux driver, i.e. max_speed and min_speed are added instead of averaged. Either there’s something I don’t get, or the factor is taken care of in the resolution constant, or it’s a bug.
Bluetooth is mandatory¶
Even when the PS4 is configured to communicate with the Dualshock through USB using the appropriate system setting, it has to connect through Bluetooth after receiving the 0x14 SET_REPORT, or the PS4 will not acknowledge it.
PS5/DualSense¶
Device descriptor¶
Descriptor Length: 12
Descriptor type: 01
USB version: 0200
Device class: 00
Device Subclass: 00
Device Protocol: 00
Max.packet size: 40
Vendor ID: 054C
Product ID: 0CE6
Revision ID: 0100
Mfg.string index: 01
Prod.string index: 02
Serial number index: 00
Number of conf.: 01
Configuration descriptor¶
227 bytes
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0xE3, 0x00, // wTotalLength 227
0x04, // bNumInterfaces 4
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0xC0, // bmAttributes Self Powered
0xFA, // bMaxPower 500mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x00, // bNumEndpoints 0
0x01, // bInterfaceClass (Audio)
0x01, // bInterfaceSubClass (Audio Control)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x0A, // bLength
0x24, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_INTERFACE -> HEADER)
0x00, 0x01, // bcdADC 1.00
0x49, 0x00, // wTotalLength 73
0x02, // binCollection 0x02
0x01, // baInterfaceNr 1
0x02, // baInterfaceNr 2
0x0C, // bLength
0x24, // bDescriptorType (See Next Line)
0x02, // bDescriptorSubtype (CS_INTERFACE -> INPUT_TERMINAL)
0x01, // bTerminalID
0x01, 0x01, // wTerminalType (USB Streaming)
0x06, // bAssocTerminal
0x04, // bNrChannels 4
0x33, 0x00, // wChannelConfig (Left and Right Front,Left and Right Surround)
0x00, // iChannelNames
0x00, // iTerminal
0x0C, // bLength
0x24, // bDescriptorType (See Next Line)
0x06, // bDescriptorSubtype (CS_INTERFACE -> FEATURE_UNIT)
0x02, // bUnitID
0x01, // bSourceID
0x01, // bControlSize 1
0x03, 0x00, // bmaControls[0] (Mute,Volume)
0x00, 0x00, // bmaControls[1] (None)
0x00, 0x00, // bmaControls[2] (None)
0x09, // bLength
0x24, // bDescriptorType (See Next Line)
0x03, // bDescriptorSubtype (CS_INTERFACE -> OUTPUT_TERMINAL)
0x03, // bTerminalID
0x01, 0x03, // wTerminalType (Speaker)
0x04, // bAssocTerminal
0x02, // bSourceID
0x00, // iTerminal
0x0C, // bLength
0x24, // bDescriptorType (See Next Line)
0x02, // bDescriptorSubtype (CS_INTERFACE -> INPUT_TERMINAL)
0x04, // bTerminalID
0x02, 0x04, // wTerminalType (Headset)
0x03, // bAssocTerminal
0x01, // bNrChannels 1
0x00, 0x00, // wChannelConfig
0x00, // iChannelNames
0x00, // iTerminal
0x09, // bLength
0x24, // bDescriptorType (See Next Line)
0x06, // bDescriptorSubtype (CS_INTERFACE -> FEATURE_UNIT)
0x05, // bUnitID
0x04, // bSourceID
0x01, // bControlSize 1
0x03, 0x00, // bmaControls[0] (Mute,Volume)
0x00, // iFeature
0x09, // bLength
0x24, // bDescriptorType (See Next Line)
0x03, // bDescriptorSubtype (CS_INTERFACE -> OUTPUT_TERMINAL)
0x06, // bTerminalID
0x01, 0x01, // wTerminalType (USB Streaming)
0x01, // bAssocTerminal
0x05, // bSourceID
0x00, // iTerminal
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x01, // bInterfaceNumber 1
0x00, // bAlternateSetting
0x00, // bNumEndpoints 0
0x01, // bInterfaceClass (Audio)
0x02, // bInterfaceSubClass (Audio Streaming)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x01, // bInterfaceNumber 1
0x01, // bAlternateSetting
0x01, // bNumEndpoints 1
0x01, // bInterfaceClass (Audio)
0x02, // bInterfaceSubClass (Audio Streaming)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x07, // bLength
0x24, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_INTERFACE -> AS_GENERAL)
0x01, // bTerminalLink
0x01, // bDelay 1
0x01, 0x00, // wFormatTag (PCM)
0x0B, // bLength
0x24, // bDescriptorType (See Next Line)
0x02, // bDescriptorSubtype (CS_INTERFACE -> FORMAT_TYPE)
0x01, // bFormatType 1
0x04, // bNrChannels 4
0x02, // bSubFrameSize 2
0x10, // bBitResolution 16
0x01, // bSamFreqType 1
0x80, 0xBB, 0x00, // tSamFreq[1] 48000 Hz
0x09, // bLength
0x05, // bDescriptorType (See Next Line)
0x01, // bEndpointAddress (OUT/H2D)
0x09, // bmAttributes (Isochronous, Adaptive, Data EP)
0x88, 0x01, // wMaxPacketSize 392
0x01, // bInterval 1 (unit depends on device speed)
0x00, // bRefresh
0x00, // bSyncAddress
0x07, // bLength
0x25, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_ENDPOINT -> EP_GENERAL)
0x01, // bmAttributes (Sampling Freq Control)
0x00, // bLockDelayUnits
0x00, 0x00, // wLockDelay 0
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x02, // bInterfaceNumber 2
0x00, // bAlternateSetting
0x00, // bNumEndpoints 0
0x01, // bInterfaceClass (Audio)
0x02, // bInterfaceSubClass (Audio Streaming)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x02, // bInterfaceNumber 2
0x01, // bAlternateSetting
0x01, // bNumEndpoints 1
0x01, // bInterfaceClass (Audio)
0x02, // bInterfaceSubClass (Audio Streaming)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x07, // bLength
0x24, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_INTERFACE -> AS_GENERAL)
0x06, // bTerminalLink
0x01, // bDelay 1
0x01, 0x00, // wFormatTag (PCM)
0x0B, // bLength
0x24, // bDescriptorType (See Next Line)
0x02, // bDescriptorSubtype (CS_INTERFACE -> FORMAT_TYPE)
0x01, // bFormatType 1
0x02, // bNrChannels (Stereo)
0x02, // bSubFrameSize 2
0x10, // bBitResolution 16
0x01, // bSamFreqType 1
0x80, 0xBB, 0x00, // tSamFreq[1] 48000 Hz
0x09, // bLength
0x05, // bDescriptorType (See Next Line)
0x82, // bEndpointAddress (IN/D2H)
0x05, // bmAttributes (Isochronous, Async, Data EP)
0xC4, 0x00, // wMaxPacketSize 196
0x01, // bInterval 1 (unit depends on device speed)
0x00, // bRefresh
0x00, // bSyncAddress
0x07, // bLength
0x25, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_ENDPOINT -> EP_GENERAL)
0x00, // bmAttributes (None)
0x00, // bLockDelayUnits
0x00, 0x00, // wLockDelay 0
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x03, // bInterfaceNumber 3
0x00, // bAlternateSetting
0x02, // bNumEndpoints 2
0x03, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x21, // bDescriptorType (HID)
0x11, 0x01, // bcdHID 1.11
0x00, // bCountryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType[0] (HID)
0x11, 0x01, // wDescriptorLength[0] 273
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x84, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x04, // bInterval 4 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x03, // bEndpointAddress (OUT/H2D)
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x04, // bInterval 4 (unit depends on device speed)
This is basically the same as the Dualshock, with twice as much audio channels.
HID report descriptor¶
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, 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)
0xC0, // End Collection
Input report structure¶
The report ID is 0x01 over USB. Over Bluetooth, report 0x01 is a simplified version, as for the Dualshock, but after GET_REPORT 0x20 it becomes 0x31 which is similar to this in structure, but the report ID is followed by a single byte (0x51), so offsets have to be adjusted.
Offset | Type | Meaning |
---|---|---|
0 | uint8 | Report ID |
1 | uint8 | Left pad X (0x00 is left, 0xFF right) |
2 | uint8 | Left pad Y (0x00 is up, 0xFF down) |
3 | uint8 | Right pad X |
4 | uint8 | Right pad Y |
5 | uint8 | L2 value |
6 | uint8 | R2 value |
7 | uint8 | A counter. This is incremented for each report. |
8 | uint4 | DPad |
8 | bool | Square |
8 | bool | Cross |
8 | bool | Circle |
8 | bool | Triangle |
9 | bool | R3 |
9 | bool | L3 |
9 | bool | Options |
9 | bool | Share |
9 | bool | L1 |
9 | bool | R1 |
9 | bool | L2 |
9 | bool | R2 |
10 | uint5 | Unknown |
10 | bool | Mute |
10 | bool | TPad |
10 | bool | PS |
11 | uint8 | Unknown |
12-15 | uint32 | Another counter, on 32 bits. Not sure about the highest byte. |
16-29 | Probably IMU values, yet to confirm | |
30 | uint16 | Timestamp (unit is probably 5.33ms) |
32 | uint8 | Unknown, probably battery |
33-63 | Unknown, probably touchpad (among other stuff) | |
Known feature reports¶
GET_REPORT 0x05¶
IMU calibration data. Details still to be investigated.
GET_REPORT 0x20¶
Manufacturing info; this is the equivalent of the Dualshock’s 0xa3 report.
GET_REPORT 0x09¶
Exact same structure as the Dualshock’s 0x12 report (pairing state).
SET_REPORT 0x0a¶
Exact same structure as the Dualshock’s 0x13 report (set pairing and link key).
SET_REPORT 0x08¶
Exact same structure as the Dualshock’s 0x14 report (connect/disconnect).