Reverse engineering

Those observations come from different sources:

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.

Accelerometer

oneG = (max_value - min_value) / 2
value = (value - oneG) / oneG

In Gs.

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).