PSVR USB Protocol
PSVR, PlayStation VR, is sold with a headset and a "processing unit". Some people report that the processing unit can be connected to any HDMI video source but with some caveats. When it is not connected to a PS4 through an USB cable: It is difficult to re-center the screen. It is impossible to adjust the virtual screen size. It is impossible to adjust the screen brightness.
Contents |
Enumeration
Descriptors
Device Descriptor
0x12, // bLength 0x01, // bDescriptorType (Device) 0x00, 0x02, // bcdUSB 2.00 0x00, // bDeviceClass (Use class information in the Interface Descriptors) 0x00, // bDeviceSubClass 0x00, // bDeviceProtocol 0x40, // bMaxPacketSize0 64 0x4C, 0x05, // idVendor 0x054C 0xAF, 0x09, // idProduct 0x09AF 0x07, 0x01, // bcdDevice 2.07 0x01, // iManufacturer (String Index) 0x02, // iProduct (String Index) 0x00, // iSerialNumber (String Index) 0x01, // bNumConfigurations 1
Configuration Descriptor
0x09, // bLength 0x02, // bDescriptorType (Configuration) 0x7F, 0x01, // wTotalLength 383 0x09, // bNumInterfaces 9 0x01, // bConfigurationValue 0x00, // iConfiguration (String Index) 0xC0, // bmAttributes Self Powered 0x01, // bMaxPower 2mA 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x00, // bInterfaceNumber 0 0x00, // bAlternateSetting 0x00, // bNumEndpoints 0 0xFF, // bInterfaceClass 0x00, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x03, // iInterface (String Index) 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x00, // bInterfaceNumber 0 0x01, // bAlternateSetting 0x01, // bNumEndpoints 1 0xFF, // bInterfaceClass 0x00, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x03, // iInterface (String Index) 0x07, // bLength 0x05, // bDescriptorType (Endpoint) 0x01, // bEndpointAddress (OUT/H2D) 0x05, // bmAttributes (Isochronous, Async, Data EP) 0x00, 0x04, // wMaxPacketSize 1024 0x01, // bInterval 1 (unit depends on device speed) 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x01, // bInterfaceNumber 1 0x00, // bAlternateSetting 0x00, // bNumEndpoints 0 0x01, // bInterfaceClass 0x01, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x04, // iInterface (String Index) 0x0A, // bLength 0x24, // bDescriptorType (Unknown) 0x01, 0x00, 0x01, 0x4A, 0x00, 0x02, 0x02, 0x03, 0x0C, // bLength 0x24, // bDescriptorType (Unknown) 0x02, 0x01, 0x01, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, // bLength 0x24, // bDescriptorType (Unknown) 0x06, 0x05, 0x01, 0x01, 0x03, 0x00, 0x00, 0x09, // bLength 0x24, // bDescriptorType (Unknown) 0x03, 0x03, 0x01, 0x01, 0x00, 0x05, 0x00, 0x0C, // bLength 0x24, // bDescriptorType (Unknown) 0x02, 0x02, 0x01, 0x01, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x0D, // bLength 0x24, // bDescriptorType (Unknown) 0x06, 0x06, 0x02, 0x02, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x09, // bLength 0x24, // bDescriptorType (Unknown) 0x03, 0x04, 0x01, 0x03, 0x00, 0x06, 0x00, 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x02, // bInterfaceNumber 2 0x00, // bAlternateSetting 0x00, // bNumEndpoints 0 0x01, // bInterfaceClass 0x02, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x05, // iInterface (String Index) 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x02, // bInterfaceNumber 2 0x01, // bAlternateSetting 0x01, // bNumEndpoints 1 0x01, // bInterfaceClass 0x02, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x05, // iInterface (String Index) 0x07, // bLength 0x24, // bDescriptorType (Unknown) 0x01, 0x03, 0x00, 0x01, 0x00, 0x0B, // bLength 0x24, // bDescriptorType (Unknown) 0x02, 0x01, 0x01, 0x02, 0x10, 0x01, 0x80, 0xBB, 0x00, 0x09, // bLength 0x05, // bDescriptorType (Endpoint) 0x82, // bEndpointAddress (IN/D2H) 0x05, // bmAttributes (Isochronous, Async, Data EP) 0xC0, 0x00, // wMaxPacketSize 192 0x04, // bInterval 4 (unit depends on device speed) 0x00, 0x00, 0x07, // bLength 0x25, // bDescriptorType (Unknown) 0x01, 0x80, 0x00, 0x00, 0x00, 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x03, // bInterfaceNumber 3 0x00, // bAlternateSetting 0x00, // bNumEndpoints 0 0x01, // bInterfaceClass 0x02, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x06, // iInterface (String Index) 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x03, // bInterfaceNumber 3 0x01, // bAlternateSetting 0x01, // bNumEndpoints 1 0x01, // bInterfaceClass 0x02, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x06, // iInterface (String Index) 0x07, // bLength 0x24, // bDescriptorType (Unknown) 0x01, 0x02, 0x00, 0x01, 0x00, 0x0B, // bLength 0x24, // bDescriptorType (Unknown) 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, 0x80, 0xBB, 0x00, 0x09, // bLength 0x05, // bDescriptorType (Endpoint) 0x02, // bEndpointAddress (OUT/H2D) 0x05, // bmAttributes (Isochronous, Async, Data EP) 0xC0, 0x00, // wMaxPacketSize 192 0x04, // bInterval 4 (unit depends on device speed) 0x00, 0x00, 0x07, // bLength 0x25, // bDescriptorType (Unknown) 0x01, 0x80, 0x00, 0x00, 0x00, 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x04, // bInterfaceNumber 4 0x00, // bAlternateSetting 0x01, // bNumEndpoints 1 0x03, // bInterfaceClass 0x00, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x07, // iInterface (String Index) 0x09, // bLength 0x21, // bDescriptorType (HID) 0x11, 0x01, // bcdHID 1.11 0x00, // bCountryCode 0x01, // bNumDescriptors 0x22, // bDescriptorType[0] (HID) 0x15, 0x00, // wDescriptorLength[0] 21 0x07, // bLength 0x05, // bDescriptorType (Endpoint) 0x83, // bEndpointAddress (IN/D2H) 0x03, // bmAttributes (Interrupt) 0x40, 0x00, // wMaxPacketSize 64 0x03, // bInterval 3 (unit depends on device speed) 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x05, // bInterfaceNumber 5 0x00, // bAlternateSetting 0x02, // bNumEndpoints 2 0x03, // bInterfaceClass 0x00, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x08, // iInterface (String Index) 0x09, // bLength 0x21, // bDescriptorType (HID) 0x11, 0x01, // bcdHID 1.11 0x00, // bCountryCode 0x01, // bNumDescriptors 0x22, // bDescriptorType[0] (HID) 0x17, 0x00, // wDescriptorLength[0] 23 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) 0x04, // bEndpointAddress (OUT/H2D) 0x03, // bmAttributes (Interrupt) 0x40, 0x00, // wMaxPacketSize 64 0x04, // bInterval 4 (unit depends on device speed) 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x06, // bInterfaceNumber 6 0x00, // bAlternateSetting 0x00, // bNumEndpoints 0 0xFF, // bInterfaceClass 0x00, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x09, // iInterface (String Index) 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x06, // bInterfaceNumber 6 0x01, // bAlternateSetting 0x01, // bNumEndpoints 1 0xFF, // bInterfaceClass 0x00, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x09, // iInterface (String Index) 0x07, // bLength 0x05, // bDescriptorType (Endpoint) 0x05, // bEndpointAddress (OUT/H2D) 0x05, // bmAttributes (Isochronous, Async, Data EP) 0x00, 0x04, // wMaxPacketSize 1024 0x03, // bInterval 3 (unit depends on device speed) 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x06, // bInterfaceNumber 6 0x02, // bAlternateSetting 0x01, // bNumEndpoints 1 0xFF, // bInterfaceClass 0x00, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x00, // iInterface (String Index) 0x07, // bLength 0x05, // bDescriptorType (Endpoint) 0x05, // bEndpointAddress (OUT/H2D) 0x05, // bmAttributes (Isochronous, Async, Data EP) 0x00, 0x04, // wMaxPacketSize 1024 0x02, // bInterval 2 (unit depends on device speed) 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x06, // bInterfaceNumber 6 0x03, // bAlternateSetting 0x01, // bNumEndpoints 1 0xFF, // bInterfaceClass 0x00, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x00, // iInterface (String Index) 0x07, // bLength 0x05, // bDescriptorType (Endpoint) 0x05, // bEndpointAddress (OUT/H2D) 0x05, // bmAttributes (Isochronous, Async, Data EP) 0x00, 0x04, // wMaxPacketSize 1024 0x01, // bInterval 1 (unit depends on device speed) 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x07, // bInterfaceNumber 7 0x00, // bAlternateSetting 0x01, // bNumEndpoints 1 0xFF, // bInterfaceClass 0x01, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x0A, // iInterface (String Index) 0x07, // bLength 0x05, // bDescriptorType (Endpoint) 0x87, // bEndpointAddress (IN/D2H) 0x02, // bmAttributes (Bulk) 0x00, 0x02, // wMaxPacketSize 512 0x00, // bInterval 0 (unit depends on device speed) 0x09, // bLength 0x04, // bDescriptorType (Interface) 0x08, // bInterfaceNumber 8 0x00, // bAlternateSetting 0x02, // bNumEndpoints 2 0x03, // bInterfaceClass 0x00, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x0B, // iInterface (String Index) 0x09, // bLength 0x21, // bDescriptorType (HID) 0x11, 0x01, // bcdHID 1.11 0x00, // bCountryCode 0x01, // bNumDescriptors 0x22, // bDescriptorType[0] (HID) 0x9F, 0x00, // wDescriptorLength[0] 159 0x07, // bLength 0x05, // bDescriptorType (Endpoint) 0x86, // bEndpointAddress (IN/D2H) 0x03, // bmAttributes (Interrupt) 0x40, 0x00, // wMaxPacketSize 64 0x04, // bInterval 4 (unit depends on device speed) 0x07, // bLength 0x05, // bDescriptorType (Endpoint) 0x06, // bEndpointAddress (OUT/H2D) 0x03, // bmAttributes (Interrupt) 0x40, 0x00, // wMaxPacketSize 64 0x04, // bInterval 4 (unit depends on device speed) // 383 bytes
HID Report Descriptors
Index 4
0x06, 0x01, 0xFF, // Usage Page (Vendor Defined 0xFF01) 0x09, 0x01, // Usage (0x01) 0xA1, 0x01, // Collection (Application) 0x09, 0x10, // Usage (0x10) 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Size (8) 0x95, 0x40, // Report Count (64) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection // 21 bytes
Index 5
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x09, 0x08, // Usage (0x08) 0xA1, 0x01, // Collection (Application) 0x09, 0x80, // Usage (0x80) 0x85, 0x40, // Report ID (64) 0x75, 0x08, // Report Size (8) 0x95, 0x04, // Report Count (4) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0xC0, // End Collection // 23 bytes
Index 8
0x06, 0xF0, 0xFF, // Usage Page (Vendor Defined 0xFFF0) 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Size (8) 0x95, 0x3F, // Report Count (63) 0x09, 0x01, // Usage (0x01) 0xA1, 0x01, // Collection (Application) 0x85, 0xD0, // Report ID (208) 0x09, 0xD0, // Usage (0xD0) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xD1, // Report ID (209) 0x09, 0xD1, // Usage (0xD1) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xD2, // Report ID (210) 0x09, 0xD2, // Usage (0xD2) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xD3, // Report ID (211) 0x09, 0xD3, // Usage (0xD3) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0xC0, // End Collection 0x09, 0x02, // Usage (0x02) 0xA1, 0x01, // Collection (Application) 0x85, 0xE0, // Report ID (224) 0x09, 0xE0, // Usage (0xE0) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xE1, // Report ID (225) 0x09, 0xE1, // Usage (0xE1) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xE2, // Report ID (226) 0x09, 0xE2, // Usage (0xE2) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xE3, // Report ID (227) 0x09, 0xE3, // Usage (0xE3) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xE4, // Report ID (228) 0x09, 0xE4, // Usage (0xE4) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xE5, // Report ID (229) 0x09, 0xE5, // Usage (0xE5) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xE6, // Report ID (230) 0x09, 0xE6, // Usage (0xE6) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xE7, // Report ID (231) 0x09, 0xE7, // Usage (0xE7) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xE8, // Report ID (232) 0x09, 0xE8, // Usage (0xE8) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xE9, // Report ID (233) 0x09, 0xE9, // Usage (0xE9) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x85, 0xEF, // Report ID (239) 0x09, 0xEF, // Usage (0xEF) 0x95, 0x04, // Report Count (4) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0xC0, // End Collection 0x09, 0x40, // Usage (0x40) 0xA1, 0x01, // Collection (Application) 0x85, 0xF0, // Report ID (240) 0x09, 0x47, // Usage (0x47) 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Size (8) 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 (241) 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 (242) 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, 0xF3, // Report ID (243) 0x0A, 0x01, 0x47, // Usage (0x4701) 0x95, 0x07, // Report Count (7) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0xC0, // End Collection // 159 bytes
Functions
For now, we are only interested in the functions I've analyzed below. This is enough to make a portable battery powered PSVR "backpack" without a PS4.
Center Screen
Endpoint 4, direction is OUT (host to device), data is
1B 00 AA 00
Adjust Screen Size/Brightness
My theory is that if the PSVR is showing the USB error icon, sending this HID packet will initialize the screen.
Endpoint 4, direction is OUT (host to device), data is
21 00 AA 10 XX YY 19 14 00 00 00 00 00 00 ZZ 00 00 00 00 00
Where XX YY changes screen size
Small: XX YY = 00 1A Medium: XX YY = C0 24 Large: XX YY = C0 32
Where ZZ is screen brightness, a range between 0x00 and 0x20 (0 to 32), in steps of 1 0x00 = dimmest 0x20 = brightest
Volume Buttons
Endpoint 4, direction is IN (device to host), data is
F0 00 AA 10 XX YY 00 00 00 FF 00 00 02 00 00 00 00 00 00 00
XX is a byte containing bit flags, so far, I can see the earbuds and the mic mute button flags
No earbuds and unmuted: XX = 0x87 No earbuds and muted: XX = 0xA7 Yes earbuds and unmuted: XX = 0x97 Yes earbuds and muted: XX = 0xB7
YY seems to be the volume, between 0x00 and 0x32 in steps of 2
Head Detector
Endpoint 4, direction is IN (device to host)
Same packet as above in "volume buttons"
No earbuds and unmuted, head is in: XX = 0x87 No earbuds and unmuted, head is out: XX = 0x85
Motion Tracking
I can't identify what packet correlates to motion, even when a game is running. I think the PS4 renders everything without caring about where you are looking, and the processing unit simply has to decide which part to show you. This makes perfect sense when you think about how they are able to achieve 120FPS with reprojection and have low enough latency to not make you motion sick.
This means the long proprietary cable between the headset and the processing unit carries the data somehow.
Microphone
Endpoint 2 seems to be just 16 bit mic data. That's all I know. Take a look at the descriptor for more info.
Cryptographic Authentication
Sony is using a similar cryptographic challenge and response scheme for authenticating a PSVR. This means it is almost impossible to clone a PSVR. I am not going to investigate this any further, it's just not worth the effort.