├── .gitignore ├── CMakeLists.txt ├── README.md ├── include ├── raw-gadget.hpp ├── magicPro.h ├── raw-helper.h ├── magicpro_generated.h ├── dualsense.h ├── ds4.h └── ps5_generated.h ├── src ├── passthrough.cpp ├── libusbhax.c ├── raw-helper.c ├── raw-helper.cpp ├── hid.c └── raw-gadget.cpp └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeLists.txt.user 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Testing 6 | Makefile 7 | cmake_install.cmake 8 | install_manifest.txt 9 | compile_commands.json 10 | CTestTestfile.cmake 11 | _deps 12 | .DS_Store 13 | build 14 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(usb-sniffily) 4 | 5 | find_package(PkgConfig) 6 | pkg_check_modules(LIBUSB REQUIRED libusb-1.0) 7 | include_directories( ${LIBUSB_INCLUDE_DIRS} ) 8 | 9 | find_package(Threads REQUIRED) 10 | 11 | include_directories( include ) 12 | 13 | #add_library(sniffifyc src/raw-helper.c 14 | # include/raw-helper.h) 15 | 16 | add_library(sniffify src/raw-helper.cpp 17 | src/raw-gadget.cpp 18 | src/raw-gadget-passthrough.cpp 19 | include/raw-gadget.hpp 20 | include/raw-helper.h) 21 | 22 | #add_executable(passthroughc src/passthrough.c) 23 | #add_executable(passthrough src/passthrough.cpp) 24 | #add_executable(libusbhax src/libusbhax.c) 25 | #add_executable(hid src/hid.c) 26 | 27 | #target_link_libraries(passthroughc sniffifyc ${LIBUSB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} m) 28 | #target_link_libraries(passthrough sniffify ${LIBUSB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} m) 29 | #target_link_libraries(libusbhax ${LIBUSB_LIBRARIES} ) 30 | #target_link_libraries(hid sniffifyc ${LIBUSB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # usb-sniffify 2 | Raspberry Pi 4 USB Forwarder, Sniffer, Injector 3 | 4 | This is example code that can be used to open USB device and duplicate messages one the USB peripheral/power port on a Raspebrry Pi 4. This framework lets a host device recognize the Raspberry Pi as the client device connected to the Raspberry Pi. Doing so allows an arbitrary host send and recieve all protocols while allowing usb-sniffiy to read the transmitted messages. A few small tweaks to the code can also let you block transmissions or inject new messages. Sniffiy is derived from Sniff + Modify. 5 | 6 | - Gadget Handling: raw-gadget 7 | - Device Handling: libusb-1.0 8 | 9 | The original motivation of this project is to decode USB protcol from a Dualsense controller connected to a PS5 over USB, as well as modify the inputs being sent to the console for projects like chaos%. 10 | 11 | There exist some generated headers based on HID report descriptors using the following tool: 12 | - hidrdd 13 | 14 | The passthrough.c is the latest program that can pass a device from the PCB-closest USB 2.0 port. This requires running the insmod.sh to have been priorly run from raw-gadget. 15 | 16 | $ cd src 17 | $ make 18 | $ ls /sys/class/udc 19 | fe980000.usb 20 | $ sudo ./passthrough fe980000.usb fe980000.usb 21 | 22 | This project is very new so expect frequent updates. Though the intent is to pass through all USB funcitonality certain limitations in raw_gadget or libusb may make perfect transparency impossible. 23 | 24 | Status: 25 | - passthrough.c works with dualsense and DS4 controllers, audio can be passed to the controller 26 | - Audio cannot be passed to the host (mic audio -> console) 27 | 28 | TODO: 29 | - bulk trasnfer endpoint threads 30 | - isochronous device -> host thread 31 | - Turn into a library with better interfaces 32 | -------------------------------------------------------------------------------- /include/raw-gadget.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RAW_GADGET_H 2 | #define RAW_GADGET_H 3 | 4 | #include 5 | #include 6 | 7 | 8 | #include "raw-helper.h" 9 | 10 | // Functions to help maintain the configuration state: 11 | void setEndpoint(AlternateInfo* info, int endpoint, bool enable); 12 | void setAlternate(InterfaceInfo* info, int alternate); 13 | void setInterface(libusb_device_handle *deviceHandle, ConfigurationInfo* info, int interface, int alternate); 14 | void setConfiguration(EndpointZeroInfo* info, int configuration); 15 | 16 | //char dummyBuffer[4096]; 17 | bool ep0_request(EndpointZeroInfo* info, struct usb_raw_control_event *event, struct usb_raw_control_io *io, bool *done); 18 | 19 | bool ep0_loop(EndpointZeroInfo* info); 20 | void* ep0_loop_thread( void* data ); 21 | 22 | static void cb_transfer_out(struct libusb_transfer *xfr); 23 | void ep_out_work_interrupt( EndpointInfo* epInfo ); 24 | 25 | static void cb_transfer_in(struct libusb_transfer *xfr); 26 | void ep_in_work_interrupt( EndpointInfo* epInfo ); 27 | 28 | void ep_in_work_isochronous( EndpointInfo* epInfo ); 29 | void ep_out_work_isochronous( EndpointInfo* epInfo ); 30 | 31 | void* ep_loop_thread( void* data ); 32 | 33 | 34 | 35 | 36 | 37 | class EndpointObserver { 38 | friend RawGadgetPassthrough; 39 | public: 40 | void setEndpoint(unsigned char endpoint) { 41 | this->endpoint = endpoint; 42 | }; 43 | char getEndpoint() { 44 | return endpoint; 45 | } 46 | private: 47 | unsigned char endpoint; 48 | protected: 49 | /* 50 | the buffer is specifically non-const so that is can be modified 51 | */ 52 | virtual void notification(unsigned char* buffer, int length) = 0; 53 | 54 | }; 55 | 56 | 57 | 58 | 59 | class RawGadgetPassthrough { 60 | 61 | public: 62 | int initialize(); 63 | 64 | /* 65 | Begins the passthrough structure 66 | */ 67 | void start(); 68 | 69 | /* 70 | Stops the passthrough structure 71 | */ 72 | void stop(); 73 | 74 | void addObserver(EndpointObserver* observer); 75 | 76 | 77 | bool readyProductVendor(); 78 | int getVendor(); 79 | int getProduct(); 80 | 81 | private: 82 | int product; 83 | int vendor; 84 | bool haveProductVendor; 85 | std::vector observers; 86 | 87 | bool keepRunning; 88 | pthread_t libusbEventThread; 89 | 90 | pthread_t threadEp0; 91 | 92 | int fd; // for ioctl raw_gadget 93 | EndpointZeroInfo mEndpointZeroInfo; 94 | pthread_t endpointThreads[60]; // crawl before I walk 95 | 96 | 97 | libusb_device **devices; 98 | libusb_device_handle *deviceHandle; 99 | libusb_context *context; 100 | 101 | void setEndpoint(AlternateInfo* info, int endpoint, bool enable); 102 | void setAlternate(InterfaceInfo* info, int alternate); 103 | void setInterface(ConfigurationInfo* info, int interface, int alternate); 104 | void setConfiguration( int configuration); 105 | 106 | static bool ep0Request(RawGadgetPassthrough* mRawGadgetPassthrough, struct usb_raw_control_event *event, 107 | struct usb_raw_control_io *io, bool *done); 108 | static bool ep0Loop(void* rawgadgetobject ); 109 | static void* ep0LoopThread( void* rawgadgetobject ); 110 | static void* libusbEventHandler( void* rawgadgetobject ); 111 | static void* epLoopThread( void* rawgadgetobject ); 112 | 113 | void epDeviceToHostWorkInterrupt( EndpointInfo* epInfo ); 114 | static void cbTransferIn(struct libusb_transfer *xfr); 115 | }; 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /src/passthrough.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | 3 | #include 4 | #include 5 | 6 | #include "raw-gadget.hpp" 7 | 8 | #define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" 9 | #define BYTE_TO_BINARY(byte) \ 10 | (byte & 0x80 ? '1' : '0'), \ 11 | (byte & 0x40 ? '1' : '0'), \ 12 | (byte & 0x20 ? '1' : '0'), \ 13 | (byte & 0x10 ? '1' : '0'), \ 14 | (byte & 0x08 ? '1' : '0'), \ 15 | (byte & 0x04 ? '1' : '0'), \ 16 | (byte & 0x02 ? '1' : '0'), \ 17 | (byte & 0x01 ? '1' : '0') 18 | 19 | class DualsenseSniffer : public EndpointObserver { 20 | public: 21 | DualsenseSniffer() { 22 | count = 0; 23 | totalSamples = 1; 24 | gettimeofday(&oldTime, NULL); 25 | } 26 | private: 27 | int count; 28 | int totalSamples; 29 | bool shouldHold; 30 | double dtime; 31 | struct timeval oldTime; 32 | void notification(unsigned char* buffer, int length) { 33 | count++; 34 | if(count >= totalSamples) { 35 | struct timeval currentTime; 36 | gettimeofday(¤tTime, NULL); 37 | 38 | double difftime = (currentTime.tv_sec - oldTime.tv_sec) + 39 | (currentTime.tv_usec - oldTime.tv_usec)*0.000001; 40 | 41 | 42 | printf("Read: "); 43 | for (int i = 0; i < length; i++) { 44 | printf("%02X ", buffer[i]); 45 | } 46 | printf("\n"); 47 | // 48 | // printf("Reverse: "); 49 | // for (int i = length-1; i >= 0; i--) { 50 | // printf("%02X ", buffer[i]); 51 | // } 52 | // printf("\n"); 53 | // 54 | // printf("Compact: "); 55 | // for (int i = 0; i < length; i++) { 56 | // printf("%02X", buffer[i]); 57 | // } 58 | // printf("\n"); 59 | // printf("Compact Reverse: "); 60 | // for (int i = length-1; i >= 0; i--) { 61 | // printf("%02X", buffer[i]); 62 | // } 63 | // printf("\n"); 64 | 65 | // for (int i = 0; i < length-8; i++) { 66 | // printf("%02X", buffer[i]); 67 | // } 68 | // for (int i = length-1; i >= length-8; i--) { 69 | // printf("%02X", buffer[i]); 70 | // } 71 | // printf(" \\\n"); 72 | /* 73 | //static int firstTime = true; 74 | static int savedCount = 0; 75 | const int totalToSave = 8192*8; 76 | static unsigned long long savedBuffer[totalToSave][8]; 77 | 78 | unsigned long long* bufferAsInt = (unsigned long long*) buffer; 79 | unsigned long long bufferSuccess[8]; 80 | if(savedCount < totalToSave) { 81 | for (int i = 0; i < 8; i++) { 82 | savedBuffer[savedCount][i] = bufferAsInt[i]; 83 | } 84 | //printf("savedCount = %d\n", savedCount); 85 | savedCount++; 86 | } 87 | 88 | for (int i = 0; i < savedCount; i++) { 89 | if (savedBuffer[i][7] == bufferAsInt[7]) { 90 | if (savedCount-1 != i) { 91 | 92 | 93 | printf("Read: "); 94 | for (int j = 0; j < length; j++) { 95 | printf("%02X ", buffer[j]); 96 | } 97 | printf("\n"); 98 | printf(" - Found a match!\n"); 99 | printf("Match: "); 100 | for (int j = 0; j < length; j++) { 101 | printf("%02X ", ((unsigned char*)savedBuffer[i])[j]); 102 | } 103 | printf("\n"); 104 | } 105 | } 106 | } 107 | */ 108 | 109 | /* 110 | unsigned long long sum = 0; 111 | for (int i = 0; i < 7; i++) { 112 | sum += bufferAsInt[i]; 113 | } 114 | printf("unsigned long long sum: "); 115 | for (int i = 0; i < 8; i++) { 116 | printf("%02X ", ((unsigned char*)&sum)[i]); 117 | } 118 | printf("\n"); 119 | 120 | sum = 1; 121 | for (int i = 0; i < 7; i++) { 122 | sum *= bufferAsInt[i]; 123 | } 124 | printf("unsigned long long mult: "); 125 | for (int i = 0; i < 8; i++) { 126 | printf("%02X ", ((unsigned char*)&sum)[i]); 127 | } 128 | printf("\n"); 129 | 130 | sum = 0; 131 | for (int i = 0; i < 7; i++) { 132 | sum ^= bufferAsInt[i]; 133 | } 134 | printf("unsigned long long xor: "); 135 | for (int i = 0; i < 8; i++) { 136 | printf("%02X ", ((unsigned char*)&sum)[i]); 137 | } 138 | printf("\n"); 139 | */ 140 | //printf("Byte 7: "BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(buffer[7])); 141 | 142 | // printf("Frequency: %0.2f\n", (double)totalSamples/difftime); 143 | 144 | count = 0; 145 | oldTime = currentTime; 146 | 147 | // shouldHold = !shouldHold; 148 | // printf("Should Hold: %d\n", shouldHold); 149 | } 150 | 151 | // if (shouldHold) { 152 | // buffer[8] |= 0x20; 153 | // } 154 | } 155 | }; 156 | 157 | int main(int argc, char **argv) { 158 | 159 | 160 | RawGadgetPassthrough mRawGadgetPassthrough; 161 | 162 | DualsenseSniffer mDualsenseSniffer; 163 | mDualsenseSniffer.setEndpoint(0x84); 164 | // mDualsenseSniffer.setEndpoint(0x03); 165 | mRawGadgetPassthrough.addObserver( &mDualsenseSniffer ); 166 | 167 | mRawGadgetPassthrough.initialize(); 168 | mRawGadgetPassthrough.start(); 169 | 170 | printf("Press any key to quit\n"); 171 | getc(stdin); 172 | 173 | 174 | mRawGadgetPassthrough.stop(); 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /include/magicPro.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | 3 | #include "magicpro_generated.h" 4 | 5 | #define MAGIC_PRO 6 | /*----------------------------------------------------------------------*/ 7 | // DEvice: 8 | #define BCD_USB 0x0200 9 | 10 | //#define USB_VENDOR 0x1d6b 11 | //#define USB_PRODUCT 0x0104 12 | //#define USB_VENDOR 0x0525 13 | //#define USB_PRODUCT 0xa4a0 14 | #define USB_VENDOR 0x2f24 15 | #define USB_PRODUCT 0x00f8 16 | 17 | #define STRING_ID_MANUFACTURER 1 18 | #define STRING_ID_PRODUCT 2 19 | #define STRING_ID_SERIAL 0 20 | #define STRING_ID_CONFIG 0 21 | #define STRING_ID_INTERFACE 0 22 | 23 | #define EP_MAX_PACKET_CONTROL 64 24 | #define EP_MAX_PACKET_INT 64 25 | 26 | // struct usb_device_descriptor usb_device = { 27 | #define B_DEVICE_CLASS 0 28 | #define B_DEVICE_SUBCLASS 0 29 | #define B_DEVICE_PROTOCOL 0 30 | #define BCD_DEVICE 0x0100 31 | #define NUM_COFIGURATIONS 1 32 | 33 | // Configuraiton Descriptor: 34 | // struct usb_config_descriptor usb_config = { 35 | #define B_NUM_INTERFACES 1 36 | #define B_CONFIGURATION_VALUE 1 37 | #define B_MAX_POWER 0x32*5 38 | 39 | #define B_INTERVAL 5 40 | 41 | // Assigned dynamically. 42 | #define EP_NUM_INT_IN 0x0 43 | 44 | // String list (based on reports) 45 | #define REPORT_ID_BT_MAC 0xff 46 | #define REPORT_ID_CALIBRATION 0xfe 47 | #define REPORT_ID_HARDWARE_FIRMWARE 0xfd 48 | #define REPORT_NOIDEAWTF 0xfc 49 | 50 | const char manufacturerString[] = ".";//Sony Interactive Entertainment"; 51 | const char productString[] = "MAGIC-S PRO";//Wireless Controller"; 52 | 53 | const char usb_hid_report[] = { 54 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 55 | 0x09, 0x05, // Usage (Game Pad) 56 | 0xA1, 0x01, // Collection (Application) 57 | 0x85, 0x01, // Report ID (1) 58 | 0x09, 0x30, // Usage (X) 59 | 0x09, 0x31, // Usage (Y) 60 | 0x09, 0x32, // Usage (Z) 61 | 0x09, 0x35, // Usage (Rz) 62 | 0x15, 0x00, // Logical Minimum (0) 63 | 0x26, 0xFF, 0x00, // Logical Maximum (255) 64 | 0x75, 0x08, // Report Size (8) 65 | 0x95, 0x04, // Report Count (4) 66 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 67 | 0x09, 0x39, // Usage (Hat switch) 68 | 0x15, 0x00, // Logical Minimum (0) 69 | 0x25, 0x07, // Logical Maximum (7) 70 | 0x35, 0x00, // Physical Minimum (0) 71 | 0x46, 0x3B, 0x01, // Physical Maximum (315) 72 | 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) 73 | 0x75, 0x04, // Report Size (4) 74 | 0x95, 0x01, // Report Count (1) 75 | 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) 76 | 0x65, 0x00, // Unit (None) 77 | 0x05, 0x09, // Usage Page (Button) 78 | 0x19, 0x01, // Usage Minimum (0x01) 79 | 0x29, 0x0E, // Usage Maximum (0x0E) 80 | 0x15, 0x00, // Logical Minimum (0) 81 | 0x25, 0x01, // Logical Maximum (1) 82 | 0x75, 0x01, // Report Size (1) 83 | 0x95, 0x0E, // Report Count (14) 84 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 85 | 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) 86 | 0x09, 0x20, // Usage (0x20) 87 | 0x75, 0x06, // Report Size (6) 88 | 0x95, 0x01, // Report Count (1) 89 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 90 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 91 | 0x09, 0x33, // Usage (Rx) 92 | 0x09, 0x34, // Usage (Ry) 93 | 0x15, 0x00, // Logical Minimum (0) 94 | 0x26, 0xFF, 0x00, // Logical Maximum (255) 95 | 0x75, 0x08, // Report Size (8) 96 | 0x95, 0x02, // Report Count (2) 97 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 98 | 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) 99 | 0x09, 0x21, // Usage (0x21) 100 | 0x95, 0x36, // Report Count (54) 101 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 102 | 0x85, 0x05, // Report ID (5) 103 | 0x09, 0x22, // Usage (0x22) 104 | 0x95, 0x1F, // Report Count (31) 105 | 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 106 | 0x85, 0x03, // Report ID (3) 107 | 0x0A, 0x21, 0x27, // Usage (0x2721) 108 | 0x95, 0x2F, // Report Count (47) 109 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 110 | 0xC0, // End Collection 111 | 0x06, 0xF0, 0xFF, // Usage Page (Vendor Defined 0xFFF0) 112 | 0x09, 0x40, // Usage (0x40) 113 | 0xA1, 0x01, // Collection (Application) 114 | 0x85, 0xF0, // Report ID (-16) 115 | 0x09, 0x47, // Usage (0x47) 116 | 0x95, 0x3F, // Report Count (63) 117 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 118 | 0x85, 0xF1, // Report ID (-15) 119 | 0x09, 0x48, // Usage (0x48) 120 | 0x95, 0x3F, // Report Count (63) 121 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 122 | 0x85, 0xF2, // Report ID (-14) 123 | 0x09, 0x49, // Usage (0x49) 124 | 0x95, 0x0F, // Report Count (15) 125 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 126 | 0x85, 0xF3, // Report ID (-13) 127 | 0x0A, 0x01, 0x47, // Usage (0x4701) 128 | 0x95, 0x07, // Report Count (7) 129 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 130 | 0xC0, // End Collection 131 | 132 | // 160 bytes 133 | }; 134 | 135 | 136 | 137 | featureReport03_t magicMagic = { 138 | .reportId = 0x03, 139 | .VEN_GamePad2721 = { 140 | 0x21 , 0x27 , 0x04 , 0xcd , 0x00 , 0x2c , 0x56 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x0d , 0x0d , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 141 | } 142 | }; 143 | -------------------------------------------------------------------------------- /include/raw-helper.h: -------------------------------------------------------------------------------- 1 | #ifndef RAW_HELPER_H 2 | #define RAW_HELPER_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | //#include 10 | #include 11 | 12 | #include 13 | 14 | /*----------------------------------------------------------------------*/ 15 | 16 | struct hid_class_descriptor { 17 | __u8 bDescriptorType; 18 | __le16 wDescriptorLength; 19 | } __attribute__ ((packed)); 20 | 21 | struct hid_descriptor { 22 | __u8 bLength; 23 | __u8 bDescriptorType; 24 | __le16 bcdHID; 25 | __u8 bCountryCode; 26 | __u8 bNumDescriptors; 27 | 28 | struct hid_class_descriptor desc[1]; 29 | } __attribute__ ((packed)); 30 | 31 | struct audio_control_descriptor_1 { // HEADER 32 | __u8 bLength; 33 | __u8 bDescriptorType; 34 | __u8 bDescriptorSubType; 35 | __le16 bcdADC; 36 | __le16 wTotalLength; 37 | __u8 bInCollection; 38 | __u8 baInterfaceNr0; 39 | __u8 baInterfaceNr1; 40 | } __attribute__ ((packed)); 41 | 42 | struct audio_control_descriptor_2 { // INPUT_TERMINAL 43 | __u8 bLength; 44 | __u8 bDescriptorType; 45 | __u8 bDescriptorSubType; 46 | __u8 bTerminalID; 47 | __le16 wTerminalType; 48 | 49 | __u8 bAssocTerminal; 50 | __u8 bNrChannels; 51 | __le16 wChannelConfig; 52 | __u8 iChannelNames; 53 | __u8 iTerminal; 54 | } __attribute__ ((packed)); 55 | 56 | struct audio_control_descriptor_6 { // FEATURE_UNIT 57 | __u8 bLength; 58 | __u8 bDescriptorType; 59 | __u8 bDescriptorSubType; 60 | __u8 bUnitID; 61 | __u8 bSourceID; 62 | __u8 bControlSize; 63 | __u8 bmaControls0; 64 | __u8 bmaControls1; 65 | __u8 bmaControls2; 66 | __u8 bmaControls3; 67 | __u8 bmaControls4; 68 | __u8 iFeature; 69 | } __attribute__ ((packed)); 70 | 71 | struct audio_control_descriptor_3 { // OUTPUT_TERMINAL 72 | __u8 bLength; 73 | __u8 bDescriptorType; 74 | __u8 bDescriptorSubType; 75 | __u8 bTerminalID; 76 | __le16 wTerminalType; 77 | 78 | __u8 bAssocTerminal; 79 | __u8 bSourceID; 80 | __u8 iTerminal; 81 | } __attribute__ ((packed)); 82 | 83 | /*----------------------------------------------------------------------*/ 84 | 85 | #define UDC_NAME_LENGTH_MAX 128 86 | 87 | struct usb_raw_init { 88 | __u8 driver_name[UDC_NAME_LENGTH_MAX]; 89 | __u8 device_name[UDC_NAME_LENGTH_MAX]; 90 | __u8 speed; 91 | }; 92 | 93 | enum usb_raw_event_type { 94 | USB_RAW_EVENT_INVALID, 95 | USB_RAW_EVENT_CONNECT, 96 | USB_RAW_EVENT_CONTROL, 97 | }; 98 | 99 | struct usb_raw_event { 100 | __u32 type; 101 | __u32 length; 102 | __u8 data[0]; 103 | // __u8* data; 104 | }; 105 | 106 | struct usb_raw_ep_io { 107 | __u16 ep; 108 | __u16 flags; 109 | __u32 length; 110 | __u8 data[0]; 111 | // __u8* data; 112 | }; 113 | 114 | #define USB_RAW_EPS_NUM_MAX 30 115 | #define USB_RAW_EP_NAME_MAX 16 116 | #define USB_RAW_EP_ADDR_ANY 0xff 117 | 118 | struct usb_raw_ep_caps { 119 | __u32 type_control : 1; 120 | __u32 type_iso : 1; 121 | __u32 type_bulk : 1; 122 | __u32 type_int : 1; 123 | __u32 dir_in : 1; 124 | __u32 dir_out : 1; 125 | }; 126 | 127 | struct usb_raw_ep_limits { 128 | __u16 maxpacket_limit; 129 | __u16 max_streams; 130 | __u32 reserved; 131 | }; 132 | 133 | struct usb_raw_ep_info { 134 | __u8 name[USB_RAW_EP_NAME_MAX]; 135 | __u32 addr; 136 | struct usb_raw_ep_caps caps; 137 | struct usb_raw_ep_limits limits; 138 | }; 139 | 140 | struct usb_raw_eps_info { 141 | struct usb_raw_ep_info eps[USB_RAW_EPS_NUM_MAX]; 142 | }; 143 | 144 | #define USB_RAW_IOCTL_INIT _IOW('U', 0, struct usb_raw_init) 145 | #define USB_RAW_IOCTL_RUN _IO('U', 1) 146 | #define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event) 147 | #define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io) 148 | #define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io) 149 | #define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor) 150 | #define USB_RAW_IOCTL_EP_DISABLE _IOW('U', 6, __u32) 151 | #define USB_RAW_IOCTL_EP_WRITE _IOW('U', 7, struct usb_raw_ep_io) 152 | #define USB_RAW_IOCTL_EP_READ _IOWR('U', 8, struct usb_raw_ep_io) 153 | #define USB_RAW_IOCTL_CONFIGURE _IO('U', 9) 154 | #define USB_RAW_IOCTL_VBUS_DRAW _IOW('U', 10, __u32) 155 | #define USB_RAW_IOCTL_EPS_INFO _IOR('U', 11, struct usb_raw_eps_info) 156 | #define USB_RAW_IOCTL_EP0_STALL _IO('U', 12) 157 | #define USB_RAW_IOCTL_EP_SET_HALT _IOW('U', 13, __u32) 158 | #define USB_RAW_IOCTL_EP_CLEAR_HALT _IOW('U', 14, __u32) 159 | #define USB_RAW_IOCTL_EP_SET_WEDGE _IOW('U', 15, __u32) 160 | 161 | /*----------------------------------------------------------------------*/ 162 | 163 | #define EP0_MAX_DATA 512 // increased to 512 due to size 507 ds4 report descriptor 164 | #define EP_MAX_PACKET_INT 1024 165 | 166 | struct usb_raw_control_event { 167 | struct usb_raw_event inner; 168 | struct usb_ctrlrequest ctrl; 169 | }; 170 | 171 | struct usb_raw_control_io { 172 | struct usb_raw_ep_io inner; 173 | char data[EP0_MAX_DATA]; 174 | }; 175 | 176 | struct usb_raw_int_io { 177 | struct usb_raw_ep_io inner; 178 | char data[EP_MAX_PACKET_INT]; 179 | }; 180 | 181 | /*----------------------------------------------------------------------*/ 182 | 183 | class RawGadgetPassthrough; // dirty 184 | 185 | struct EndpointZeroInfo; 186 | struct ConfigurationInfo; 187 | struct InterfaceInfo; 188 | struct AlternateInfo; 189 | 190 | typedef struct EndpointInfo { 191 | int fd; // raw_gadget descriptor 192 | int ep_int;// endpoint handler 193 | libusb_device_handle *deviceHandle; 194 | bool keepRunning; // thread management, mostly unused 195 | bool stop; // for endpoint termination from interface switching 196 | int busyPackets; // to notice then EP is safe to be diasbled 197 | 198 | pthread_t thread; // for runnign data transfers 199 | 200 | struct usb_endpoint_descriptor usb_endpoint; 201 | int bIntervalInMicroseconds; 202 | unsigned char* data; 203 | 204 | struct AlternateInfo* parent; 205 | } EndpointInfo; 206 | 207 | typedef struct AlternateInfo{ 208 | // bool active; 209 | uint8_t bInterfaceNumber; 210 | int bNumEndpoints; 211 | EndpointInfo *mEndpointInfos; 212 | 213 | struct InterfaceInfo* parent; 214 | } AlternateInfo; 215 | 216 | typedef struct InterfaceInfo { 217 | // bool active; 218 | int activeAlternate; 219 | int bNumAlternates; 220 | AlternateInfo *mAlternateInfos; 221 | 222 | struct ConfigurationInfo* parent; 223 | } InterfaceInfo; 224 | 225 | typedef struct ConfigurationInfo { 226 | // bool active; 227 | int activeInterface; 228 | int bNumInterfaces; 229 | InterfaceInfo *mInterfaceInfos; 230 | 231 | struct EndpointZeroInfo* parent; 232 | } ConfigurationInfo; 233 | 234 | typedef struct EndpointZeroInfo { 235 | // int totalEndpoints; 236 | // EndpointInfo *mEndpointInfos; 237 | // InterfaceInfo *mInterfaceInfos; 238 | int bNumConfigurations; 239 | int activeConfiguration; 240 | ConfigurationInfo* mConfigurationInfos; 241 | int fd; 242 | libusb_device_handle *dev_handle; 243 | //struct libusb_config_descriptor* configDescriptor; 244 | 245 | RawGadgetPassthrough* parent; 246 | } EndpointZeroInfo; 247 | 248 | /*----------------------------------------------------------------------*/ 249 | bool assign_ep_address(struct usb_raw_ep_info *info, struct usb_endpoint_descriptor *ep); 250 | void process_eps_info(EndpointZeroInfo* epZeroInfo); 251 | 252 | /*----------------------------------------------------------------------*/ 253 | 254 | int usb_raw_open(); 255 | void usb_raw_init(int fd, enum usb_device_speed speed, const char *driver, const char *device); 256 | void usb_raw_run(int fd); 257 | void usb_raw_event_fetch(int fd, struct usb_raw_event *event); 258 | 259 | int usb_raw_ep0_read(int fd, struct usb_raw_ep_io *io); 260 | int usb_raw_ep0_write(int fd, struct usb_raw_ep_io *io); 261 | 262 | int usb_raw_ep_enable(int fd, struct usb_endpoint_descriptor *desc); 263 | int usb_raw_ep_disable(int fd, uint32_t something); 264 | int usb_raw_ep_write(int fd, struct usb_raw_ep_io *io); 265 | int usb_raw_ep_read(int fd, struct usb_raw_ep_io *io); 266 | 267 | void usb_raw_configure(int fd); 268 | void usb_raw_vbus_draw(int fd, uint32_t power); 269 | 270 | int usb_raw_eps_info(int fd, struct usb_raw_eps_info *info); 271 | void usb_raw_ep0_stall(int fd); 272 | void usb_raw_ep_set_halt(int fd, int ep); 273 | 274 | /*----------------------------------------------------------------------*/ 275 | 276 | void log_control_request(struct usb_ctrlrequest *ctrl); 277 | void log_event(struct usb_raw_event *event); 278 | 279 | 280 | /*----------------------------------------------------------------------*/ 281 | // from another resource 282 | //inline void put_unaligned_le16(__u16 val, __u16 *cp) 283 | //{ 284 | // __u8 *p = (void *)cp; 285 | // 286 | // *p++ = (__u8) val; 287 | // *p++ = (__u8) (val >> 8); 288 | //} 289 | int utf8_to_utf16le(const char *s, __u16 *cp, unsigned len); 290 | 291 | #endif 292 | -------------------------------------------------------------------------------- /src/libusbhax.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | typedef struct _ControlTransfer { 12 | uint8_t bmRequestType; 13 | uint8_t bRequest; 14 | uint16_t wValue; 15 | uint16_t wIndex; 16 | // unsigned char * data, 17 | uint16_t wLength; 18 | // unsigned int timeout 19 | } ControlTransfer; 20 | 21 | // From a PS5 -> ds4 controller 22 | //#define VENDOR 0x054c 23 | //#define PRODUCT 0x09cc 24 | //ControlTransfer mControlTransfers[] = { 25 | // { 0x80, 0x6, 0x100, 0x0, 18}, 26 | // { 0x80, 0x6, 0x300, 0x0, 2}, 27 | // { 0x80, 0x6, 0x300, 0x0, 4}, 28 | // { 0x80, 0x6, 0x301, 0x409, 2}, 29 | // { 0x80, 0x6, 0x301, 0x409, 62}, 30 | // { 0x80, 0x6, 0x302, 0x409, 2}, 31 | // { 0x80, 0x6, 0x302, 0x409, 40}, 32 | // { 0x80, 0x6, 0x200, 0x0, 9}, 33 | // { 0x80, 0x6, 0x200, 0x0, 41}, 34 | // { 0x00, 0x9, 0x1, 0x0, 0}, 35 | // { 0x81, 0x6, 0x2200, 0x0, 507}, 36 | // { 0x21, 0xa, 0x0, 0x0, 0}, 37 | // { 0xa1, 0x1, 0x302, 0x0, 37}, 38 | // { 0xa1, 0x1, 0x3a3, 0x0, 49}, 39 | // { 0xa1, 0x1, 0x312, 0x0, 16}, 40 | // { 0x21, 0x9, 0x313, 0x0, 23}, 41 | // { 0x21, 0x9, 0x314, 0x0, 17} 42 | //}; 43 | //char length23[] = {0x13,0x85 ,0xcc ,0x44 ,0xc1 ,0x98 ,0x1c ,0x1d ,0x1e ,0x01 ,0x81 ,0xf3 ,0x56 ,0xd1 ,0xdf ,0x24 ,0x8c ,0x1a ,0xdc ,0x05 ,0xbe ,0x1b ,0x2d 44 | // 45 | //}; 46 | // 47 | //char length17[] = { 0x14 ,0x02 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00}; 48 | 49 | //// From ps5 -> magicpro 50 | //#define VENDOR 0x2f24 51 | //#define PRODUCT 0x00f8 52 | //ControlTransfer mControlTransfers[] = { 53 | // { 0x80, 0x6, 0x100, 0x0, 18}, 54 | // { 0x80, 0x6, 0x300, 0x0, 2}, 55 | // { 0x80, 0x6, 0x300, 0x0, 4}, 56 | // { 0x80, 0x6, 0x301, 0x409, 2}, 57 | // { 0x80, 0x6, 0x301, 0x409, 4}, 58 | // { 0x80, 0x6, 0x302, 0x409, 2}, 59 | // { 0x80, 0x6, 0x302, 0x409, 24}, 60 | // { 0x80, 0x6, 0x200, 0x0, 9}, 61 | // { 0x80, 0x6, 0x200, 0x0, 41}, 62 | // { 0x00, 0x9, 0x1, 0x0, 0}, 63 | // { 0x81, 0x6, 0x2200, 0x0, 160}, 64 | // { 0x21, 0xa, 0x0, 0x0, 0}, 65 | // { 0xa1, 0x1, 0x303, 0x0, 48} 66 | //}; 67 | 68 | // From ps5 -> ps5 69 | #define VENDOR 0x054c 70 | #define PRODUCT 0x0ce6 71 | ControlTransfer mControlTransfers[] = { 72 | { 0x80, 0x6, 0x100, 0x0, 18}, 73 | { 0x80, 0x6, 0x300, 0x0, 2}, 74 | { 0x80, 0x6, 0x300, 0x0, 4}, 75 | { 0x80, 0x6, 0x301, 0x409, 2}, 76 | { 0x80, 0x6, 0x301, 0x409, 62}, 77 | { 0x80, 0x6, 0x302, 0x409, 2}, 78 | { 0x80, 0x6, 0x302, 0x409, 40}, 79 | { 0x80, 0x6, 0x200, 0x0, 9}, 80 | { 0x80, 0x6, 0x200, 0x0, 227}, 81 | { 0x00, 0x9, 0x1, 0x0, 0}, 82 | { 0xa1, 0x82, 0x200, 0x500, 2}, 83 | { 0xa1, 0x83, 0x200, 0x500, 2}, 84 | { 0xa1, 0x84, 0x200, 0x500, 2}, 85 | { 0xa1, 0x82, 0x200, 0x200, 2}, 86 | { 0xa1, 0x83, 0x200, 0x200, 2}, 87 | { 0xa1, 0x84, 0x200, 0x200, 2}, 88 | { 0x21, 0x1, 0x200, 0x200, 2}, 89 | { 0x1, 0xb, 0x1, 0x1, 0}, 90 | { 0x1, 0xb, 0x1, 0x2, 0}, 91 | 92 | { 0x81, 0x6, 0x2200, 0x3, 273}, 93 | { 0x21, 0xa, 0x0, 0x3, 0}, 94 | { 0xa1, 0x1, 0x305, 0x3, 41}, 95 | { 0xa1, 0x1, 0x320, 0x3, 64}, 96 | { 0xa1, 0x1, 0x309, 0x3, 16} , 97 | { 0x21, 0x9, 0x30a, 0x0, 23}, 98 | { 0x21, 0x9, 0x308, 0x0, 17} 99 | 100 | }; 101 | //char length23[] = {0x0a, 0x85 , 0xcc , 0x44 , 0xc1 , 0x98 , 0x1c , 0xd6 , 0xcb , 0xb9 , 0x9c , 0x5f , 0x78 , 0x66 , 0x41 , 0x6b , 0xb3 , 0xa3 , 0xdc , 0xca , 0x2e , 0xe4 , 0xbc}; 102 | char length23[] = {0x0a , 0x85 , 0xcc , 0x44 , 0xc1 , 0x98 , 0x1c , 0xa9 , 0xdf , 0x91 , 0x5b , 0x4f , 0x9d , 0xa7 , 0xfc , 0x39 , 0xdc , 0x36 , 0xfb , 0xbe , 0x03 , 0x80 , 0xa7}; 103 | 104 | char length17[] = { 0x08 ,0x01 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00}; 105 | char length2[] = {0xe6, 0xe6}; 106 | 107 | int main() { 108 | libusb_device **devices; 109 | libusb_device_handle *deviceHandle; 110 | libusb_context *context = NULL; 111 | 112 | int r = libusb_init(&context); 113 | if(r < 0) { 114 | printf("libusb_init() Error %d\n", r); 115 | return 1; 116 | } 117 | //libusb_set_debug(context, 0); 118 | libusb_set_option(context, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO); 119 | 120 | ssize_t deviceCount = libusb_get_device_list(context, &devices); 121 | if(deviceCount < 0) { 122 | printf("libusb_get_device_list() Error\n"); 123 | return 1; 124 | } 125 | printf("%zd Devices.\n", deviceCount); 126 | 127 | int devIndex = -1; 128 | for (int i = 0; i < deviceCount; i++) { 129 | printf("Device : %d", i); 130 | printf(" | Bus %d", libusb_get_bus_number(devices[i])); 131 | printf(" Port %d", libusb_get_port_number(devices[i])); 132 | // printf(" - Addr %d\n", libusb_get_device_address(devices[i])); 133 | 134 | if (libusb_get_bus_number(devices[i]) == 1 && // specific for lower USB2 port on rPi 4 with raspbian 135 | libusb_get_port_number(devices[i]) == 4) { 136 | devIndex = i; 137 | printf(" |-- This is the device of interest!\n"); 138 | } 139 | } 140 | if (devIndex < 0) { 141 | printf("ERROR! No USB on the lower rPi USB 2.0 port?\n"); 142 | exit(EXIT_FAILURE); 143 | } 144 | if( libusb_open(devices[devIndex], &deviceHandle) != LIBUSB_SUCCESS ) { 145 | printf("FAILED! libusb_open()\n"); 146 | exit(EXIT_FAILURE); 147 | } 148 | printf("Device has been opened!\n"); 149 | // deviceHandle = libusb_open_device_with_vid_pid(context, VENDOR, PRODUCT); //these are vendorID and productID I found for my usb device 150 | // if(deviceHandle == NULL) 151 | // cout<<"Cannot open device"<bLength); 202 | printf(" - bDescriptorType : %d\n", configDescriptor->bDescriptorType); 203 | printf(" - wTotalLength : %d\n", configDescriptor->wTotalLength); 204 | printf(" - bNumInterfaces : %d\n", configDescriptor->bNumInterfaces); 205 | printf(" - bConfigurationValue: %d\n", configDescriptor->bConfigurationValue); 206 | printf(" - iConfiguration : %d\n", configDescriptor->iConfiguration); 207 | printf(" - bmAttributes : %d\n", configDescriptor->bmAttributes); 208 | printf(" - MaxPower : %d\n", configDescriptor->MaxPower); 209 | printf(" - extra_length : %d\n", configDescriptor->extra_length); 210 | 211 | 212 | int numInterfaces = configDescriptor->bNumInterfaces; 213 | int totalEndpoints = 0; 214 | for (int i = 0; i < numInterfaces; i++) { 215 | int numAlternates = configDescriptor->interface[i].num_altsetting; 216 | 217 | for (int a = 0; a < numAlternates; a++) { 218 | const struct libusb_interface_descriptor *interfaceDescriptor = &configDescriptor->interface[i].altsetting[a]; 219 | printf(" | - Interface %d Alternate %d\n", interfaceDescriptor->bInterfaceNumber, a); 220 | 221 | r = libusb_claim_interface(deviceHandle, interfaceDescriptor->bInterfaceNumber); //claim interface 0 (the first) of device (mine had jsut 1) 222 | if(r < 0) { 223 | printf("Cannot Claim Interface\n"); 224 | return 1; 225 | } 226 | // printf("Claimed Interface %d\n", configDescriptor->interfaces[i].altsetting->bInterfaceNumber); 227 | 228 | totalEndpoints += interfaceDescriptor->bNumEndpoints; 229 | printf(" - bNumEndpoints : %d\n", interfaceDescriptor->bNumEndpoints); 230 | printf(" - Endpoints : \n"); 231 | for (int e = 0; e < interfaceDescriptor->bNumEndpoints; e++) { 232 | libusb_set_interface_alt_setting(deviceHandle, i, a ); // no idea how to use this properly, but putting htis here wrok son a PS5 controller 233 | 234 | const struct libusb_endpoint_descriptor *endpointDescriptor = &interfaceDescriptor->endpoint[e]; 235 | printf(" | - bEndpointAddress : 0x%02x\n", endpointDescriptor->bEndpointAddress); 236 | printf(" - wMaxPacketSize : %d\n", endpointDescriptor->wMaxPacketSize); 237 | printf(" - bmAttributes : %d\n", endpointDescriptor->bmAttributes); 238 | 239 | switch (endpointDescriptor->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) { 240 | case LIBUSB_TRANSFER_TYPE_CONTROL: printf(" | - Control\n"); break; 241 | case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: printf(" | - Isochronous\n"); break; 242 | case LIBUSB_TRANSFER_TYPE_BULK: printf(" | - Bulk\n"); break; 243 | case LIBUSB_TRANSFER_TYPE_INTERRUPT: printf(" | - Interrupt\n"); break; 244 | default: 245 | break; 246 | } 247 | 248 | } 249 | } 250 | } 251 | 252 | // r = libusb_set_interface_alt_setting(deviceHandle, 3, 1); 253 | // if(r != 0) { 254 | // std::cout << "Cannot configure alternate setting" << std::endl; 255 | // return 3; 256 | // } 257 | 258 | 259 | 260 | //r = libusb_bulk_transfer(deviceHandle, (2 | LIBUSB_ENDPOINT_OUT), data, 4, &actual, 0); //my device's out endpoint was 2, found with trial- the device had 2 endpoints: 2 and 129 261 | 262 | unsigned char data[256]; 263 | 264 | int count = sizeof(mControlTransfers)/sizeof(mControlTransfers[0]); 265 | printf("count = %d\n", count); 266 | 267 | for(int i = 0; i < count * 0; i++) { 268 | memset(data, 0, mControlTransfers[i].wLength); 269 | if (mControlTransfers[i].wLength == 23) { // for PS5->DS4 270 | memcpy(data, length23, 23); 271 | } 272 | if (mControlTransfers[i].wLength == 2) { // for PS5->DS4 273 | memcpy(data, length2, 2); 274 | } 275 | else if (mControlTransfers[i].wLength == 17) { 276 | memcpy(data, length17, 17); 277 | } 278 | r = libusb_control_transfer( deviceHandle, 279 | mControlTransfers[i].bmRequestType, 280 | mControlTransfers[i].bRequest, 281 | mControlTransfers[i].wValue, 282 | mControlTransfers[i].wIndex, 283 | data, 284 | mControlTransfers[i].wLength, 285 | 0); 286 | 287 | printf("Requested %d, got %d : ", mControlTransfers[i].wLength, r); 288 | for (int j = 0; j < r; j++) { 289 | printf("%02x ", data[j]); 290 | } 291 | printf("\n"); 292 | } 293 | 294 | // the following may be responislbe for a PS5 asking a DS4 to pair over BT 295 | // while(1) { 296 | // sleep(1); 297 | // memset(data, 0, mControlTransfers[16].wLength); 298 | // memcpy(data, length17, 17); 299 | // data[1] = 1; 300 | // r = libusb_control_transfer( deviceHandle, 301 | // mControlTransfers[16].bmRequestType, 302 | // mControlTransfers[16].bRequest, 303 | // mControlTransfers[16].wValue, 304 | // mControlTransfers[16].wIndex, 305 | // data, 306 | // mControlTransfers[16].wLength, 307 | // 0); 308 | // 309 | // printf("Requested %d, got %d : ", mControlTransfers[16].wLength, r); 310 | // for (int i = 0; i < r; i++) { 311 | // printf("%02x ", data[i]); 312 | // } 313 | // printf("\n"); 314 | // } 315 | // if(r == 0 && actual == 4) //we wrote the 4 bytes successfully 316 | // cout<<"Writing Successful!"< Host) 68 | //-------------------------------------------------------------------------------- 69 | 70 | typedef struct 71 | { 72 | uint8_t reportId; // Report ID = 0x03 (3) 73 | // Collection: CA:GamePad 74 | uint8_t VEN_GamePad2721[47]; // Usage 0xFF002721: , Value = 0 to 255, Physical = Value x 21 / 17 75 | } featureReport03_t; 76 | 77 | 78 | //-------------------------------------------------------------------------------- 79 | // Generic Desktop Page inputReport 01 (Device --> Host) 80 | //-------------------------------------------------------------------------------- 81 | 82 | typedef struct 83 | { 84 | uint8_t reportId; // Report ID = 0x01 (1) 85 | // Collection: CA:GamePad 86 | uint8_t GD_GamePadX; // Usage 0x00010030: X, Value = 0 to 255 87 | uint8_t GD_GamePadY; // Usage 0x00010031: Y, Value = 0 to 255 88 | uint8_t GD_GamePadZ; // Usage 0x00010032: Z, Value = 0 to 255 89 | uint8_t GD_GamePadRz; // Usage 0x00010035: Rz, Value = 0 to 255 90 | uint8_t GD_GamePadHatSwitch : 4; // Usage 0x00010039: Hat switch, Value = 0 to 7, Physical = Value x 45 in degrees 91 | uint8_t BTN_GamePadButton1 : 1; // Usage 0x00090001: Button 1 Primary/trigger, Value = 0 to 1, Physical = Value x 315 92 | uint8_t BTN_GamePadButton2 : 1; // Usage 0x00090002: Button 2 Secondary, Value = 0 to 1, Physical = Value x 315 93 | uint8_t BTN_GamePadButton3 : 1; // Usage 0x00090003: Button 3 Tertiary, Value = 0 to 1, Physical = Value x 315 94 | uint8_t BTN_GamePadButton4 : 1; // Usage 0x00090004: Button 4, Value = 0 to 1, Physical = Value x 315 95 | uint8_t BTN_GamePadButton5 : 1; // Usage 0x00090005: Button 5, Value = 0 to 1, Physical = Value x 315 96 | uint8_t BTN_GamePadButton6 : 1; // Usage 0x00090006: Button 6, Value = 0 to 1, Physical = Value x 315 97 | uint8_t BTN_GamePadButton7 : 1; // Usage 0x00090007: Button 7, Value = 0 to 1, Physical = Value x 315 98 | uint8_t BTN_GamePadButton8 : 1; // Usage 0x00090008: Button 8, Value = 0 to 1, Physical = Value x 315 99 | uint8_t BTN_GamePadButton9 : 1; // Usage 0x00090009: Button 9, Value = 0 to 1, Physical = Value x 315 100 | uint8_t BTN_GamePadButton10 : 1; // Usage 0x0009000A: Button 10, Value = 0 to 1, Physical = Value x 315 101 | uint8_t BTN_GamePadButton11 : 1; // Usage 0x0009000B: Button 11, Value = 0 to 1, Physical = Value x 315 102 | uint8_t BTN_GamePadButton12 : 1; // Usage 0x0009000C: Button 12, Value = 0 to 1, Physical = Value x 315 103 | uint8_t BTN_GamePadButton13 : 1; // Usage 0x0009000D: Button 13, Value = 0 to 1, Physical = Value x 315 104 | uint8_t BTN_GamePadButton14 : 1; // Usage 0x0009000E: Button 14, Value = 0 to 1, Physical = Value x 315 105 | uint8_t VEN_GamePad0020 : 6; // Usage 0xFF000020: , Value = 0 to 1, Physical = Value x 315 106 | uint8_t GD_GamePadRx; // Usage 0x00010033: Rx, Value = 0 to 255, Physical = Value x 21 / 17 107 | uint8_t GD_GamePadRy; // Usage 0x00010034: Ry, Value = 0 to 255, Physical = Value x 21 / 17 108 | uint8_t VEN_GamePad0021[54]; // Usage 0xFF000021: , Value = 0 to 255, Physical = Value x 21 / 17 109 | } inputReport01_t; 110 | 111 | 112 | //-------------------------------------------------------------------------------- 113 | // Vendor-defined outputReport 05 (Device <-- Host) 114 | //-------------------------------------------------------------------------------- 115 | 116 | typedef struct 117 | { 118 | uint8_t reportId; // Report ID = 0x05 (5) 119 | // Collection: CA:GamePad 120 | uint8_t VEN_GamePad0022[31]; // Usage 0xFF000022: , Value = 0 to 255, Physical = Value x 21 / 17 121 | } outputReport05_t; 122 | 123 | 124 | //-------------------------------------------------------------------------------- 125 | // Decoded Application Collection 126 | //-------------------------------------------------------------------------------- 127 | 128 | /* 129 | 06 F0FF (GLOBAL) USAGE_PAGE 0xFFF0 Vendor-defined 130 | 09 40 (LOCAL) USAGE 0xFFF00040 <-- Warning: Undocumented usage (document it by inserting 0040 into file FFF0.conf) 131 | A1 01 (MAIN) COLLECTION 0x01 Application (Usage=0xFFF00040: Page=Vendor-defined, Usage=, Type=) <-- Error: COLLECTION must be preceded by a known USAGE 132 | 85 F0 (GLOBAL) REPORT_ID 0xF0 (240) 133 | 09 47 (LOCAL) USAGE 0xFFF00047 <-- Warning: Undocumented usage (document it by inserting 0047 into file FFF0.conf) 134 | 95 3F (GLOBAL) REPORT_COUNT 0x3F (63) Number of fields 135 | B1 02 (MAIN) FEATURE 0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 136 | 85 F1 (GLOBAL) REPORT_ID 0xF1 (241) 137 | 09 48 (LOCAL) USAGE 0xFFF00048 <-- Warning: Undocumented usage (document it by inserting 0048 into file FFF0.conf) 138 | 95 3F (GLOBAL) REPORT_COUNT 0x3F (63) Number of fields <-- Redundant: REPORT_COUNT is already 63 139 | B1 02 (MAIN) FEATURE 0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 140 | 85 F2 (GLOBAL) REPORT_ID 0xF2 (242) 141 | 09 49 (LOCAL) USAGE 0xFFF00049 <-- Warning: Undocumented usage (document it by inserting 0049 into file FFF0.conf) 142 | 95 0F (GLOBAL) REPORT_COUNT 0x0F (15) Number of fields 143 | B1 02 (MAIN) FEATURE 0x00000002 (15 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 144 | 85 F3 (GLOBAL) REPORT_ID 0xF3 (243) 145 | 0A 0147 (LOCAL) USAGE 0xFFF04701 <-- Warning: Undocumented usage (document it by inserting 4701 into file FFF0.conf) 146 | 95 07 (GLOBAL) REPORT_COUNT 0x07 (7) Number of fields 147 | B1 02 (MAIN) FEATURE 0x00000002 (7 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 148 | C0 (MAIN) END_COLLECTION Application <-- Warning: Physical units are still in effect PHYSICAL(MIN=0,MAX=315) UNIT(0x00000000,EXP=0) 149 | */ 150 | 151 | //-------------------------------------------------------------------------------- 152 | // Vendor-defined featureReport F0 (Device <-> Host) 153 | //-------------------------------------------------------------------------------- 154 | 155 | typedef struct 156 | { 157 | uint8_t reportId; // Report ID = 0xF0 (240) 158 | // Collection: CA: 159 | uint8_t VEN_0047[63]; // Usage 0xFFF00047: , Value = 0 to 255, Physical = Value x 21 / 17 160 | } featureReportF0_t; 161 | 162 | 163 | //-------------------------------------------------------------------------------- 164 | // Vendor-defined featureReport F1 (Device <-> Host) 165 | //-------------------------------------------------------------------------------- 166 | 167 | typedef struct 168 | { 169 | uint8_t reportId; // Report ID = 0xF1 (241) 170 | // Collection: CA: 171 | uint8_t VEN_0048[63]; // Usage 0xFFF00048: , Value = 0 to 255, Physical = Value x 21 / 17 172 | } featureReportF1_t; 173 | 174 | 175 | //-------------------------------------------------------------------------------- 176 | // Vendor-defined featureReport F2 (Device <-> Host) 177 | //-------------------------------------------------------------------------------- 178 | 179 | typedef struct 180 | { 181 | uint8_t reportId; // Report ID = 0xF2 (242) 182 | // Collection: CA: 183 | uint8_t VEN_0049[15]; // Usage 0xFFF00049: , Value = 0 to 255, Physical = Value x 21 / 17 184 | } featureReportF2_t; 185 | 186 | 187 | //-------------------------------------------------------------------------------- 188 | // Vendor-defined featureReport F3 (Device <-> Host) 189 | //-------------------------------------------------------------------------------- 190 | 191 | typedef struct 192 | { 193 | uint8_t reportId; // Report ID = 0xF3 (243) 194 | // Collection: CA: 195 | uint8_t VEN_4701[7]; // Usage 0xFFF04701: , Value = 0 to 255, Physical = Value x 21 / 17 196 | } featureReportF3_t; 197 | 198 | -------------------------------------------------------------------------------- /src/raw-helper.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | 3 | #include "raw-helper.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | //#include 13 | //#include 14 | 15 | #include 16 | 17 | /*----------------------------------------------------------------------*/ 18 | bool assign_ep_address(struct usb_raw_ep_info *info, 19 | struct usb_endpoint_descriptor *ep) { 20 | if (usb_endpoint_num(ep) != 0) 21 | return false; // Already assigned. 22 | if (usb_endpoint_dir_in(ep) && !info->caps.dir_in) 23 | return false; 24 | if (usb_endpoint_dir_out(ep) && !info->caps.dir_out) 25 | return false; 26 | switch (usb_endpoint_type(ep)) { 27 | case USB_ENDPOINT_XFER_CONTROL: // 0 28 | if (!info->caps.type_control) 29 | return false; 30 | break; 31 | case USB_ENDPOINT_XFER_ISOC: // 1 32 | if (!info->caps.type_iso) 33 | return false; 34 | break; 35 | case USB_ENDPOINT_XFER_BULK: // 2 36 | if (!info->caps.type_bulk) 37 | return false; 38 | break; 39 | case USB_ENDPOINT_XFER_INT: // 3 40 | if (!info->caps.type_int) 41 | return false; 42 | break; 43 | default: // Never reached 44 | assert(false); 45 | } 46 | if (info->addr == USB_RAW_EP_ADDR_ANY) { 47 | static int addr = 1; 48 | ep->bEndpointAddress |= addr++; 49 | } else 50 | ep->bEndpointAddress |= info->addr; 51 | return true; 52 | } 53 | 54 | void process_eps_info(EndpointZeroInfo* epZeroInfo) { 55 | struct usb_raw_eps_info info; 56 | memset(&info, 0, sizeof(info)); 57 | 58 | int num = usb_raw_eps_info(epZeroInfo->fd, &info); 59 | for (int i = 0; i < num; i++) { 60 | printf("ep #%d:\n", i); 61 | printf(" name: %s\n", &info.eps[i].name[0]); 62 | printf(" addr: %u\n", info.eps[i].addr); 63 | printf(" type: %s %s %s\n", 64 | info.eps[i].caps.type_iso ? "iso" : "___", 65 | info.eps[i].caps.type_bulk ? "blk" : "___", 66 | info.eps[i].caps.type_int ? "int" : "___"); 67 | printf(" dir : %s %s\n", 68 | info.eps[i].caps.dir_in ? "in " : "___", 69 | info.eps[i].caps.dir_out ? "out" : "___"); 70 | printf(" maxpacket_limit: %u\n", 71 | info.eps[i].limits.maxpacket_limit); 72 | printf(" max_streams: %u\n", info.eps[i].limits.max_streams); 73 | } 74 | 75 | // for (int e = 0; e < epZeroInfo->totalEndpoints; e++) { 76 | // for (int i = 0; i < num; i++) { 77 | // if (assign_ep_address(&info.eps[i], &epZeroInfo->mEndpointInfos[e].usb_endpoint)) 78 | // continue; 79 | // } 80 | // 81 | // int int_in_addr = usb_endpoint_num(&epZeroInfo->mEndpointInfos[e].usb_endpoint); 82 | // assert(int_in_addr != 0); 83 | // printf("int_in: addr = %u\n", int_in_addr); 84 | // } 85 | for (int c = 0; c < epZeroInfo->bNumConfigurations; c++) { 86 | ConfigurationInfo* cInfo = &epZeroInfo->mConfigurationInfos[c]; 87 | for (int i = 0; i < cInfo->bNumInterfaces; i++) { 88 | InterfaceInfo* iInfo = &cInfo->mInterfaceInfos[i]; 89 | for (int a = 0; a < iInfo->bNumAlternates; a++) { 90 | AlternateInfo* aInfo = &iInfo->mAlternateInfos[a]; 91 | for (int e = 0; e < aInfo->bNumEndpoints; e++) { 92 | EndpointInfo* eInfo = &aInfo->mEndpointInfos[e]; 93 | for (int k = 0; k < num; k++) { 94 | if (assign_ep_address(&info.eps[k], &eInfo->usb_endpoint)) 95 | break; // shouldn't this be a break? 96 | } 97 | 98 | int int_in_addr = usb_endpoint_num(&eInfo->usb_endpoint); 99 | assert(int_in_addr != 0); 100 | printf("int_in: addr = %u\n", int_in_addr); 101 | } 102 | } 103 | } 104 | } 105 | } 106 | 107 | /*----------------------------------------------------------------------*/ 108 | 109 | int usb_raw_open() { 110 | int fd = open("/dev/raw-gadget", O_RDWR | O_NONBLOCK ); 111 | if (fd < 0) { 112 | perror("open()"); 113 | exit(EXIT_FAILURE); 114 | } 115 | return fd; 116 | } 117 | 118 | void usb_raw_init(int fd, enum usb_device_speed speed, 119 | const char *driver, const char *device) { 120 | struct usb_raw_init arg; 121 | strcpy((char *)&arg.driver_name[0], driver); 122 | strcpy((char *)&arg.device_name[0], device); 123 | arg.speed = speed; 124 | int rv = ioctl(fd, USB_RAW_IOCTL_INIT, &arg); 125 | if (rv < 0) { 126 | perror("ioctl(USB_RAW_IOCTL_INIT)"); 127 | exit(EXIT_FAILURE); 128 | } 129 | } 130 | 131 | void usb_raw_run(int fd) { 132 | int rv = ioctl(fd, USB_RAW_IOCTL_RUN, 0); 133 | if (rv < 0) { 134 | perror("ioctl(USB_RAW_IOCTL_RUN)"); 135 | exit(EXIT_FAILURE); 136 | } 137 | } 138 | 139 | void usb_raw_event_fetch(int fd, struct usb_raw_event *event) { 140 | int rv = ioctl(fd, USB_RAW_IOCTL_EVENT_FETCH, event); 141 | if (rv < 0) { 142 | perror("ioctl(USB_RAW_IOCTL_EVENT_FETCH)"); 143 | exit(EXIT_FAILURE); 144 | } 145 | } 146 | 147 | int usb_raw_ep0_read(int fd, struct usb_raw_ep_io *io) { 148 | int rv = ioctl(fd, USB_RAW_IOCTL_EP0_READ, io); 149 | if (rv < 0) { 150 | perror("ioctl(USB_RAW_IOCTL_EP0_READ)"); 151 | exit(EXIT_FAILURE); 152 | } 153 | return rv; 154 | } 155 | 156 | int usb_raw_ep0_write(int fd, struct usb_raw_ep_io *io) { 157 | int rv = ioctl(fd, USB_RAW_IOCTL_EP0_WRITE, io); 158 | if (rv < 0) { 159 | perror("ioctl(USB_RAW_IOCTL_EP0_WRITE)"); 160 | exit(EXIT_FAILURE); 161 | } 162 | return rv; 163 | } 164 | 165 | int usb_raw_ep_enable(int fd, struct usb_endpoint_descriptor *desc) { 166 | int rv = ioctl(fd, USB_RAW_IOCTL_EP_ENABLE, desc); 167 | if (rv < 0) { 168 | perror("ioctl(USB_RAW_IOCTL_EP_ENABLE)"); 169 | exit(EXIT_FAILURE); 170 | } 171 | return rv; 172 | } 173 | 174 | int usb_raw_ep_disable(int fd, uint32_t something) { 175 | int rv = ioctl(fd, USB_RAW_IOCTL_EP_DISABLE, something); 176 | if (rv < 0) { 177 | perror("ioctl(USB_RAW_IOCTL_EP_DISABLE)"); 178 | exit(EXIT_FAILURE); 179 | } 180 | return rv; 181 | } 182 | 183 | int usb_raw_ep_read(int fd, struct usb_raw_ep_io *io) { 184 | int rv = ioctl(fd, USB_RAW_IOCTL_EP_READ, io); 185 | if (rv < 0) { 186 | perror("ioctl(USB_RAW_IOCTL_EP_READ)"); 187 | //exit(EXIT_FAILURE); 188 | } 189 | return rv; 190 | } 191 | 192 | int usb_raw_ep_write(int fd, struct usb_raw_ep_io *io) { 193 | int rv = ioctl(fd, USB_RAW_IOCTL_EP_WRITE, io); 194 | if (rv < 0) { 195 | perror("ioctl(USB_RAW_IOCTL_EP_WRITE)"); 196 | //exit(EXIT_FAILURE); 197 | } 198 | return rv; 199 | } 200 | 201 | void usb_raw_configure(int fd) { 202 | int rv = ioctl(fd, USB_RAW_IOCTL_CONFIGURE, 0); 203 | if (rv < 0) { 204 | perror("ioctl(USB_RAW_IOCTL_CONFIGURED)"); 205 | exit(EXIT_FAILURE); 206 | } 207 | } 208 | 209 | void usb_raw_vbus_draw(int fd, uint32_t power) { 210 | int rv = ioctl(fd, USB_RAW_IOCTL_VBUS_DRAW, power); 211 | if (rv < 0) { 212 | perror("ioctl(USB_RAW_IOCTL_VBUS_DRAW)"); 213 | exit(EXIT_FAILURE); 214 | } 215 | } 216 | 217 | int usb_raw_eps_info(int fd, struct usb_raw_eps_info *info) { 218 | int rv = ioctl(fd, USB_RAW_IOCTL_EPS_INFO, info); 219 | if (rv < 0) { 220 | perror("ioctl(USB_RAW_IOCTL_EPS_INFO)"); 221 | exit(EXIT_FAILURE); 222 | } 223 | return rv; 224 | } 225 | 226 | void usb_raw_ep0_stall(int fd) { 227 | int rv = ioctl(fd, USB_RAW_IOCTL_EP0_STALL, 0); 228 | if (rv < 0) { 229 | perror("ioctl(USB_RAW_IOCTL_EP0_STALL)"); 230 | exit(EXIT_FAILURE); 231 | } 232 | } 233 | 234 | void usb_raw_ep_set_halt(int fd, int ep) { 235 | int rv = ioctl(fd, USB_RAW_IOCTL_EP_SET_HALT, ep); 236 | if (rv < 0) { 237 | perror("ioctl(USB_RAW_IOCTL_EP_SET_HALT)"); 238 | exit(EXIT_FAILURE); 239 | } 240 | } 241 | 242 | /*----------------------------------------------------------------------*/ 243 | // for unknown descriptors: https://elixir.bootlin.com/linux/v5.7/source/include/uapi/linux/usb 244 | 245 | void log_control_request(struct usb_ctrlrequest *ctrl) { 246 | printf(" bRequestType: 0x%x (%s), bRequest: 0x%x, wValue: 0x%x," 247 | " wIndex: 0x%x, wLength: %d\n", ctrl->bRequestType, 248 | (ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT", 249 | ctrl->bRequest, ctrl->wValue, ctrl->wIndex, ctrl->wLength); 250 | 251 | switch (ctrl->bRequestType & USB_TYPE_MASK) { 252 | case USB_TYPE_STANDARD: 253 | printf(" type = USB_TYPE_STANDARD\n"); 254 | break; 255 | case USB_TYPE_CLASS: 256 | printf(" type = USB_TYPE_CLASS\n"); 257 | break; 258 | case USB_TYPE_VENDOR: 259 | printf(" type = USB_TYPE_VENDOR\n"); 260 | break; 261 | default: 262 | printf(" type = unknown = %d\n", (int)ctrl->bRequestType); 263 | break; 264 | } 265 | 266 | switch (ctrl->bRequestType & USB_TYPE_MASK) { 267 | case USB_TYPE_STANDARD: 268 | switch (ctrl->bRequest) { 269 | case USB_REQ_GET_DESCRIPTOR: 270 | printf(" req = USB_REQ_GET_DESCRIPTOR\n"); 271 | switch (ctrl->wValue >> 8) { 272 | case USB_DT_DEVICE: 273 | printf(" desc = USB_DT_DEVICE\n"); 274 | break; 275 | case USB_DT_CONFIG: 276 | printf(" desc = USB_DT_CONFIG\n"); 277 | break; 278 | case USB_DT_STRING: 279 | printf(" desc = USB_DT_STRING\n"); 280 | break; 281 | case USB_DT_INTERFACE: 282 | printf(" desc = USB_DT_INTERFACE\n"); 283 | break; 284 | case USB_DT_ENDPOINT: 285 | printf(" desc = USB_DT_ENDPOINT\n"); 286 | break; 287 | case USB_DT_DEVICE_QUALIFIER: 288 | printf(" desc = USB_DT_DEVICE_QUALIFIER\n"); 289 | break; 290 | case USB_DT_OTHER_SPEED_CONFIG: 291 | printf(" desc = USB_DT_OTHER_SPEED_CONFIG\n"); 292 | break; 293 | case USB_DT_INTERFACE_POWER: 294 | printf(" desc = USB_DT_INTERFACE_POWER\n"); 295 | break; 296 | case USB_DT_OTG: 297 | printf(" desc = USB_DT_OTG\n"); 298 | break; 299 | case USB_DT_DEBUG: 300 | printf(" desc = USB_DT_DEBUG\n"); 301 | break; 302 | case USB_DT_INTERFACE_ASSOCIATION: 303 | printf(" desc = USB_DT_INTERFACE_ASSOCIATION\n"); 304 | break; 305 | case USB_DT_SECURITY: 306 | printf(" desc = USB_DT_SECURITY\n"); 307 | break; 308 | case USB_DT_KEY: 309 | printf(" desc = USB_DT_KEY\n"); 310 | break; 311 | case USB_DT_ENCRYPTION_TYPE: 312 | printf(" desc = USB_DT_ENCRYPTION_TYPE\n"); 313 | break; 314 | case USB_DT_BOS: 315 | printf(" desc = USB_DT_BOS\n"); 316 | break; 317 | case USB_DT_DEVICE_CAPABILITY: 318 | printf(" desc = USB_DT_DEVICE_CAPABILITY\n"); 319 | break; 320 | case USB_DT_WIRELESS_ENDPOINT_COMP: 321 | printf(" desc = USB_DT_WIRELESS_ENDPOINT_COMP\n"); 322 | break; 323 | case USB_DT_PIPE_USAGE: 324 | printf(" desc = USB_DT_PIPE_USAGE\n"); 325 | break; 326 | case USB_DT_SS_ENDPOINT_COMP: 327 | printf(" desc = USB_DT_SS_ENDPOINT_COMP\n"); 328 | break; 329 | case HID_DT_HID: 330 | printf(" descriptor = HID_DT_HID\n"); 331 | return; 332 | case HID_DT_REPORT: 333 | printf(" descriptor = HID_DT_REPORT\n"); 334 | return; 335 | case HID_DT_PHYSICAL: 336 | printf(" descriptor = HID_DT_PHYSICAL\n"); 337 | return; 338 | default: 339 | printf(" desc = unknown = 0x%x\n", 340 | ctrl->wValue >> 8); 341 | break; 342 | } 343 | break; 344 | case USB_REQ_SET_CONFIGURATION: 345 | printf(" req = USB_REQ_SET_CONFIGURATION\n"); 346 | break; 347 | case USB_REQ_GET_CONFIGURATION: 348 | printf(" req = USB_REQ_GET_CONFIGURATION\n"); 349 | break; 350 | case USB_REQ_SET_INTERFACE: 351 | printf(" req = USB_REQ_SET_INTERFACE\n"); 352 | break; 353 | case USB_REQ_GET_INTERFACE: 354 | printf(" req = USB_REQ_GET_INTERFACE\n"); 355 | break; 356 | case USB_REQ_GET_STATUS: 357 | printf(" req = USB_REQ_GET_STATUS\n"); 358 | break; 359 | case USB_REQ_CLEAR_FEATURE: 360 | printf(" req = USB_REQ_CLEAR_FEATURE\n"); 361 | break; 362 | case USB_REQ_SET_FEATURE: 363 | printf(" req = USB_REQ_SET_FEATURE\n"); 364 | break; 365 | default: 366 | printf(" req = unknown = 0x%x\n", ctrl->bRequest); 367 | break; 368 | } 369 | break; 370 | case USB_TYPE_CLASS: 371 | switch (ctrl->bRequest) { 372 | case HID_REQ_GET_REPORT: 373 | printf(" req = HID_REQ_GET_REPORT\n"); 374 | break; 375 | case HID_REQ_GET_IDLE: 376 | printf(" req = HID_REQ_GET_IDLE\n"); 377 | break; 378 | case HID_REQ_GET_PROTOCOL: 379 | printf(" req = HID_REQ_GET_PROTOCOL\n"); 380 | break; 381 | case HID_REQ_SET_REPORT: 382 | printf(" req = HID_REQ_SET_REPORT\n"); 383 | break; 384 | case HID_REQ_SET_IDLE: 385 | printf(" req = HID_REQ_SET_IDLE\n"); 386 | break; 387 | case HID_REQ_SET_PROTOCOL: 388 | printf(" req = HID_REQ_SET_PROTOCOL\n"); 389 | break; 390 | default: 391 | printf(" req = unknown = 0x%x\n", ctrl->bRequest); 392 | break; 393 | } 394 | break; 395 | default: 396 | printf(" req = unknown = 0x%x\n", ctrl->bRequest); 397 | break; 398 | } 399 | } 400 | 401 | void log_event(struct usb_raw_event *event) { 402 | switch (event->type) { 403 | case USB_RAW_EVENT_CONNECT: 404 | printf("event: connect, length: %u\n", event->length); 405 | break; 406 | case USB_RAW_EVENT_CONTROL: 407 | printf("event: control, length: %u\n", event->length); 408 | log_control_request((struct usb_ctrlrequest *)&event->data[0]); 409 | break; 410 | default: 411 | printf("event: unknown, length: %u\n", event->length); 412 | } 413 | } 414 | 415 | /*----------------------------------------------------------------------*/ 416 | // from another resource 417 | static inline void put_unaligned_le16(__u16 val, __u16 *cp) 418 | { 419 | // __u8 *p = (void *)cp; 420 | __u8 *p = (__u8 *)cp; 421 | 422 | *p++ = (__u8) val; 423 | *p++ = (__u8) (val >> 8); 424 | } 425 | int utf8_to_utf16le(const char *s, __u16 *cp, unsigned len) 426 | { 427 | int count = 0; 428 | __u8 c; 429 | __u16 uchar; 430 | 431 | /* this insists on correct encodings, though not minimal ones. 432 | * BUT it currently rejects legit 4-byte UTF-8 code points, 433 | * which need surrogate pairs. (Unicode 3.1 can use them.) 434 | */ 435 | while (len != 0 && (c = (__u8) *s++) != 0) { 436 | if (c & 0x80) { 437 | // 2-byte sequence: 438 | // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx 439 | if ((c & 0xe0) == 0xc0) { 440 | uchar = (c & 0x1f) << 6; 441 | 442 | c = (__u8) *s++; 443 | if ((c & 0xc0) != 0xc0) 444 | goto fail; 445 | c &= 0x3f; 446 | uchar |= c; 447 | 448 | // 3-byte sequence (most CJKV characters): 449 | // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx 450 | } else if ((c & 0xf0) == 0xe0) { 451 | uchar = (c & 0x0f) << 12; 452 | 453 | c = (__u8) *s++; 454 | if ((c & 0xc0) != 0xc0) 455 | goto fail; 456 | c &= 0x3f; 457 | uchar |= c << 6; 458 | 459 | c = (__u8) *s++; 460 | if ((c & 0xc0) != 0xc0) 461 | goto fail; 462 | c &= 0x3f; 463 | uchar |= c; 464 | 465 | /* no bogus surrogates */ 466 | if (0xd800 <= uchar && uchar <= 0xdfff) 467 | goto fail; 468 | 469 | // 4-byte sequence (surrogate pairs, currently rare): 470 | // 11101110wwwwzzzzyy + 110111yyyyxxxxxx 471 | // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 472 | // (uuuuu = wwww + 1) 473 | // FIXME accept the surrogate code points (only) 474 | 475 | } else 476 | goto fail; 477 | } else 478 | uchar = c; 479 | put_unaligned_le16 (uchar, cp++); 480 | count++; 481 | len--; 482 | } 483 | return count; 484 | fail: 485 | return -1; 486 | } 487 | -------------------------------------------------------------------------------- /src/raw-helper.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | 3 | #include "raw-helper.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | //#include 15 | //#include 16 | 17 | #include 18 | 19 | /*----------------------------------------------------------------------*/ 20 | bool assign_ep_address(struct usb_raw_ep_info *info, 21 | struct usb_endpoint_descriptor *ep) { 22 | if (usb_endpoint_num(ep) != 0) 23 | return false; // Already assigned. 24 | if (usb_endpoint_dir_in(ep) && !info->caps.dir_in) 25 | return false; 26 | if (usb_endpoint_dir_out(ep) && !info->caps.dir_out) 27 | return false; 28 | switch (usb_endpoint_type(ep)) { 29 | case USB_ENDPOINT_XFER_CONTROL: // 0 30 | if (!info->caps.type_control) 31 | return false; 32 | break; 33 | case USB_ENDPOINT_XFER_ISOC: // 1 34 | if (!info->caps.type_iso) 35 | return false; 36 | break; 37 | case USB_ENDPOINT_XFER_BULK: // 2 38 | if (!info->caps.type_bulk) 39 | return false; 40 | break; 41 | case USB_ENDPOINT_XFER_INT: // 3 42 | if (!info->caps.type_int) 43 | return false; 44 | break; 45 | default: // Never reached 46 | assert(false); 47 | } 48 | if (info->addr == USB_RAW_EP_ADDR_ANY) { 49 | static int addr = 1; 50 | ep->bEndpointAddress |= addr++; 51 | } else 52 | ep->bEndpointAddress |= info->addr; 53 | return true; 54 | } 55 | 56 | void process_eps_info(EndpointZeroInfo* epZeroInfo) { 57 | struct usb_raw_eps_info info; 58 | memset(&info, 0, sizeof(info)); 59 | 60 | int num = usb_raw_eps_info(epZeroInfo->fd, &info); 61 | for (int i = 0; i < num; i++) { 62 | printf("ep #%d:\n", i); 63 | printf(" name: %s\n", &info.eps[i].name[0]); 64 | printf(" addr: %u\n", info.eps[i].addr); 65 | printf(" type: %s %s %s\n", 66 | info.eps[i].caps.type_iso ? "iso" : "___", 67 | info.eps[i].caps.type_bulk ? "blk" : "___", 68 | info.eps[i].caps.type_int ? "int" : "___"); 69 | printf(" dir : %s %s\n", 70 | info.eps[i].caps.dir_in ? "in " : "___", 71 | info.eps[i].caps.dir_out ? "out" : "___"); 72 | printf(" maxpacket_limit: %u\n", 73 | info.eps[i].limits.maxpacket_limit); 74 | printf(" max_streams: %u\n", info.eps[i].limits.max_streams); 75 | } 76 | 77 | // for (int e = 0; e < epZeroInfo->totalEndpoints; e++) { 78 | // for (int i = 0; i < num; i++) { 79 | // if (assign_ep_address(&info.eps[i], &epZeroInfo->mEndpointInfos[e].usb_endpoint)) 80 | // continue; 81 | // } 82 | // 83 | // int int_in_addr = usb_endpoint_num(&epZeroInfo->mEndpointInfos[e].usb_endpoint); 84 | // assert(int_in_addr != 0); 85 | // printf("int_in: addr = %u\n", int_in_addr); 86 | // } 87 | for (int c = 0; c < epZeroInfo->bNumConfigurations; c++) { 88 | ConfigurationInfo* cInfo = &epZeroInfo->mConfigurationInfos[c]; 89 | for (int i = 0; i < cInfo->bNumInterfaces; i++) { 90 | InterfaceInfo* iInfo = &cInfo->mInterfaceInfos[i]; 91 | for (int a = 0; a < iInfo->bNumAlternates; a++) { 92 | AlternateInfo* aInfo = &iInfo->mAlternateInfos[a]; 93 | for (int e = 0; e < aInfo->bNumEndpoints; e++) { 94 | EndpointInfo* eInfo = &aInfo->mEndpointInfos[e]; 95 | for (int k = 0; k < num; k++) { 96 | if (assign_ep_address(&info.eps[k], &eInfo->usb_endpoint)) 97 | break; // shouldn't this be a break? 98 | } 99 | 100 | int int_in_addr = usb_endpoint_num(&eInfo->usb_endpoint); 101 | assert(int_in_addr != 0); 102 | printf("int_in: addr = %u\n", int_in_addr); 103 | } 104 | } 105 | } 106 | } 107 | } 108 | 109 | /*----------------------------------------------------------------------*/ 110 | 111 | int usb_raw_open() { 112 | //int fd = open("/dev/raw-gadget", O_RDWR | O_NONBLOCK ); 113 | int fd = open("/dev/raw-gadget", O_RDWR ); 114 | if (fd < 0) { 115 | perror("open()"); 116 | exit(EXIT_FAILURE); 117 | } 118 | return fd; 119 | } 120 | 121 | void usb_raw_init(int fd, enum usb_device_speed speed, 122 | const char *driver, const char *device) { 123 | struct usb_raw_init arg; 124 | strcpy((char *)&arg.driver_name[0], driver); 125 | strcpy((char *)&arg.device_name[0], device); 126 | arg.speed = speed; 127 | int rv = ioctl(fd, USB_RAW_IOCTL_INIT, &arg); 128 | if (rv < 0) { 129 | perror("ioctl(USB_RAW_IOCTL_INIT)"); 130 | exit(EXIT_FAILURE); 131 | } 132 | } 133 | 134 | void usb_raw_run(int fd) { 135 | int rv = ioctl(fd, USB_RAW_IOCTL_RUN, 0); 136 | if (rv < 0) { 137 | perror("ioctl(USB_RAW_IOCTL_RUN)"); 138 | exit(EXIT_FAILURE); 139 | } 140 | } 141 | 142 | void usb_raw_event_fetch(int fd, struct usb_raw_event *event) { 143 | int rv = ioctl(fd, USB_RAW_IOCTL_EVENT_FETCH, event); 144 | if (rv < 0) { 145 | perror("ioctl(USB_RAW_IOCTL_EVENT_FETCH)"); 146 | exit(EXIT_FAILURE); 147 | } 148 | } 149 | 150 | int usb_raw_ep0_read(int fd, struct usb_raw_ep_io *io) { 151 | int rv = ioctl(fd, USB_RAW_IOCTL_EP0_READ, io); 152 | if (rv < 0) { 153 | perror("ioctl(USB_RAW_IOCTL_EP0_READ)"); 154 | exit(EXIT_FAILURE); 155 | } 156 | return rv; 157 | } 158 | 159 | int usb_raw_ep0_write(int fd, struct usb_raw_ep_io *io) { 160 | int rv = ioctl(fd, USB_RAW_IOCTL_EP0_WRITE, io); 161 | if (rv < 0) { 162 | perror("ioctl(USB_RAW_IOCTL_EP0_WRITE)"); 163 | exit(EXIT_FAILURE); 164 | } 165 | return rv; 166 | } 167 | 168 | int usb_raw_ep_enable(int fd, struct usb_endpoint_descriptor *desc) { 169 | int rv = ioctl(fd, USB_RAW_IOCTL_EP_ENABLE, desc); 170 | if (rv < 0) { 171 | perror("ioctl(USB_RAW_IOCTL_EP_ENABLE)"); 172 | exit(EXIT_FAILURE); 173 | } 174 | return rv; 175 | } 176 | 177 | int usb_raw_ep_disable(int fd, uint32_t something) { 178 | int rv = ioctl(fd, USB_RAW_IOCTL_EP_DISABLE, something); 179 | if (rv < 0) { 180 | perror("ioctl(USB_RAW_IOCTL_EP_DISABLE)"); 181 | exit(EXIT_FAILURE); 182 | } 183 | return rv; 184 | } 185 | 186 | int usb_raw_ep_read(int fd, struct usb_raw_ep_io *io) { 187 | int rv = ioctl(fd, USB_RAW_IOCTL_EP_READ, io); 188 | if (rv < 0) { 189 | if(errno == ETIMEDOUT ) { 190 | return rv; 191 | } 192 | //printf("Error = %d\n ", rv); 193 | perror("ioctl(USB_RAW_IOCTL_EP_READ)"); 194 | exit(EXIT_FAILURE); 195 | } 196 | return rv; 197 | } 198 | 199 | int usb_raw_ep_write(int fd, struct usb_raw_ep_io *io) { 200 | int rv = ioctl(fd, USB_RAW_IOCTL_EP_WRITE, io); 201 | if (rv < 0) { 202 | if(errno == ETIMEDOUT ) { 203 | return rv; 204 | } 205 | //printf("Error = %d\n ", rv); 206 | perror("ioctl(USB_RAW_IOCTL_EP_WRITE)"); 207 | exit(EXIT_FAILURE); 208 | } 209 | return rv; 210 | } 211 | 212 | void usb_raw_configure(int fd) { 213 | int rv = ioctl(fd, USB_RAW_IOCTL_CONFIGURE, 0); 214 | if (rv < 0) { 215 | perror("ioctl(USB_RAW_IOCTL_CONFIGURED)"); 216 | exit(EXIT_FAILURE); 217 | } 218 | } 219 | 220 | void usb_raw_vbus_draw(int fd, uint32_t power) { 221 | int rv = ioctl(fd, USB_RAW_IOCTL_VBUS_DRAW, power); 222 | if (rv < 0) { 223 | perror("ioctl(USB_RAW_IOCTL_VBUS_DRAW)"); 224 | exit(EXIT_FAILURE); 225 | } 226 | } 227 | 228 | int usb_raw_eps_info(int fd, struct usb_raw_eps_info *info) { 229 | int rv = ioctl(fd, USB_RAW_IOCTL_EPS_INFO, info); 230 | if (rv < 0) { 231 | perror("ioctl(USB_RAW_IOCTL_EPS_INFO)"); 232 | exit(EXIT_FAILURE); 233 | } 234 | return rv; 235 | } 236 | 237 | void usb_raw_ep0_stall(int fd) { 238 | int rv = ioctl(fd, USB_RAW_IOCTL_EP0_STALL, 0); 239 | if (rv < 0) { 240 | perror("ioctl(USB_RAW_IOCTL_EP0_STALL)"); 241 | exit(EXIT_FAILURE); 242 | } 243 | } 244 | 245 | void usb_raw_ep_set_halt(int fd, int ep) { 246 | int rv = ioctl(fd, USB_RAW_IOCTL_EP_SET_HALT, ep); 247 | if (rv < 0) { 248 | perror("ioctl(USB_RAW_IOCTL_EP_SET_HALT)"); 249 | exit(EXIT_FAILURE); 250 | } 251 | } 252 | 253 | /*----------------------------------------------------------------------*/ 254 | // for unknown descriptors: https://elixir.bootlin.com/linux/v5.7/source/include/uapi/linux/usb 255 | 256 | void log_control_request(struct usb_ctrlrequest *ctrl) { 257 | printf(" bRequestType: 0x%x (%s), bRequest: 0x%x, wValue: 0x%x," 258 | " wIndex: 0x%x, wLength: %d\n", ctrl->bRequestType, 259 | (ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT", 260 | ctrl->bRequest, ctrl->wValue, ctrl->wIndex, ctrl->wLength); 261 | 262 | switch (ctrl->bRequestType & USB_TYPE_MASK) { 263 | case USB_TYPE_STANDARD: 264 | printf(" type = USB_TYPE_STANDARD\n"); 265 | break; 266 | case USB_TYPE_CLASS: 267 | printf(" type = USB_TYPE_CLASS\n"); 268 | break; 269 | case USB_TYPE_VENDOR: 270 | printf(" type = USB_TYPE_VENDOR\n"); 271 | break; 272 | default: 273 | printf(" type = unknown = %d\n", (int)ctrl->bRequestType); 274 | break; 275 | } 276 | 277 | switch (ctrl->bRequestType & USB_TYPE_MASK) { 278 | case USB_TYPE_STANDARD: 279 | switch (ctrl->bRequest) { 280 | case USB_REQ_GET_DESCRIPTOR: 281 | printf(" req = USB_REQ_GET_DESCRIPTOR\n"); 282 | switch (ctrl->wValue >> 8) { 283 | case USB_DT_DEVICE: 284 | printf(" desc = USB_DT_DEVICE\n"); 285 | break; 286 | case USB_DT_CONFIG: 287 | printf(" desc = USB_DT_CONFIG\n"); 288 | break; 289 | case USB_DT_STRING: 290 | printf(" desc = USB_DT_STRING\n"); 291 | break; 292 | case USB_DT_INTERFACE: 293 | printf(" desc = USB_DT_INTERFACE\n"); 294 | break; 295 | case USB_DT_ENDPOINT: 296 | printf(" desc = USB_DT_ENDPOINT\n"); 297 | break; 298 | case USB_DT_DEVICE_QUALIFIER: 299 | printf(" desc = USB_DT_DEVICE_QUALIFIER\n"); 300 | break; 301 | case USB_DT_OTHER_SPEED_CONFIG: 302 | printf(" desc = USB_DT_OTHER_SPEED_CONFIG\n"); 303 | break; 304 | case USB_DT_INTERFACE_POWER: 305 | printf(" desc = USB_DT_INTERFACE_POWER\n"); 306 | break; 307 | case USB_DT_OTG: 308 | printf(" desc = USB_DT_OTG\n"); 309 | break; 310 | case USB_DT_DEBUG: 311 | printf(" desc = USB_DT_DEBUG\n"); 312 | break; 313 | case USB_DT_INTERFACE_ASSOCIATION: 314 | printf(" desc = USB_DT_INTERFACE_ASSOCIATION\n"); 315 | break; 316 | case USB_DT_SECURITY: 317 | printf(" desc = USB_DT_SECURITY\n"); 318 | break; 319 | case USB_DT_KEY: 320 | printf(" desc = USB_DT_KEY\n"); 321 | break; 322 | case USB_DT_ENCRYPTION_TYPE: 323 | printf(" desc = USB_DT_ENCRYPTION_TYPE\n"); 324 | break; 325 | case USB_DT_BOS: 326 | printf(" desc = USB_DT_BOS\n"); 327 | break; 328 | case USB_DT_DEVICE_CAPABILITY: 329 | printf(" desc = USB_DT_DEVICE_CAPABILITY\n"); 330 | break; 331 | case USB_DT_WIRELESS_ENDPOINT_COMP: 332 | printf(" desc = USB_DT_WIRELESS_ENDPOINT_COMP\n"); 333 | break; 334 | case USB_DT_PIPE_USAGE: 335 | printf(" desc = USB_DT_PIPE_USAGE\n"); 336 | break; 337 | case USB_DT_SS_ENDPOINT_COMP: 338 | printf(" desc = USB_DT_SS_ENDPOINT_COMP\n"); 339 | break; 340 | case HID_DT_HID: 341 | printf(" descriptor = HID_DT_HID\n"); 342 | return; 343 | case HID_DT_REPORT: 344 | printf(" descriptor = HID_DT_REPORT\n"); 345 | return; 346 | case HID_DT_PHYSICAL: 347 | printf(" descriptor = HID_DT_PHYSICAL\n"); 348 | return; 349 | default: 350 | printf(" desc = unknown = 0x%x\n", 351 | ctrl->wValue >> 8); 352 | break; 353 | } 354 | break; 355 | case USB_REQ_SET_CONFIGURATION: 356 | printf(" req = USB_REQ_SET_CONFIGURATION\n"); 357 | break; 358 | case USB_REQ_GET_CONFIGURATION: 359 | printf(" req = USB_REQ_GET_CONFIGURATION\n"); 360 | break; 361 | case USB_REQ_SET_INTERFACE: 362 | printf(" req = USB_REQ_SET_INTERFACE\n"); 363 | break; 364 | case USB_REQ_GET_INTERFACE: 365 | printf(" req = USB_REQ_GET_INTERFACE\n"); 366 | break; 367 | case USB_REQ_GET_STATUS: 368 | printf(" req = USB_REQ_GET_STATUS\n"); 369 | break; 370 | case USB_REQ_CLEAR_FEATURE: 371 | printf(" req = USB_REQ_CLEAR_FEATURE\n"); 372 | break; 373 | case USB_REQ_SET_FEATURE: 374 | printf(" req = USB_REQ_SET_FEATURE\n"); 375 | break; 376 | default: 377 | printf(" req = unknown = 0x%x\n", ctrl->bRequest); 378 | break; 379 | } 380 | break; 381 | case USB_TYPE_CLASS: 382 | switch (ctrl->bRequest) { 383 | case HID_REQ_GET_REPORT: 384 | printf(" req = HID_REQ_GET_REPORT\n"); 385 | break; 386 | case HID_REQ_GET_IDLE: 387 | printf(" req = HID_REQ_GET_IDLE\n"); 388 | break; 389 | case HID_REQ_GET_PROTOCOL: 390 | printf(" req = HID_REQ_GET_PROTOCOL\n"); 391 | break; 392 | case HID_REQ_SET_REPORT: 393 | printf(" req = HID_REQ_SET_REPORT\n"); 394 | break; 395 | case HID_REQ_SET_IDLE: 396 | printf(" req = HID_REQ_SET_IDLE\n"); 397 | break; 398 | case HID_REQ_SET_PROTOCOL: 399 | printf(" req = HID_REQ_SET_PROTOCOL\n"); 400 | break; 401 | default: 402 | printf(" req = unknown = 0x%x\n", ctrl->bRequest); 403 | break; 404 | } 405 | break; 406 | default: 407 | printf(" req = unknown = 0x%x\n", ctrl->bRequest); 408 | break; 409 | } 410 | } 411 | 412 | void log_event(struct usb_raw_event *event) { 413 | switch (event->type) { 414 | case USB_RAW_EVENT_CONNECT: 415 | printf("event: connect, length: %u\n", event->length); 416 | break; 417 | case USB_RAW_EVENT_CONTROL: 418 | printf("event: control, length: %u\n", event->length); 419 | log_control_request((struct usb_ctrlrequest *)&event->data[0]); 420 | break; 421 | default: 422 | printf("event: unknown, length: %u\n", event->length); 423 | } 424 | } 425 | 426 | /*----------------------------------------------------------------------*/ 427 | // from another resource 428 | static inline void put_unaligned_le16(__u16 val, __u16 *cp) 429 | { 430 | // __u8 *p = (void *)cp; 431 | __u8 *p = (__u8 *)cp; 432 | 433 | *p++ = (__u8) val; 434 | *p++ = (__u8) (val >> 8); 435 | } 436 | int utf8_to_utf16le(const char *s, __u16 *cp, unsigned len) 437 | { 438 | int count = 0; 439 | __u8 c; 440 | __u16 uchar; 441 | 442 | /* this insists on correct encodings, though not minimal ones. 443 | * BUT it currently rejects legit 4-byte UTF-8 code points, 444 | * which need surrogate pairs. (Unicode 3.1 can use them.) 445 | */ 446 | while (len != 0 && (c = (__u8) *s++) != 0) { 447 | if (c & 0x80) { 448 | // 2-byte sequence: 449 | // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx 450 | if ((c & 0xe0) == 0xc0) { 451 | uchar = (c & 0x1f) << 6; 452 | 453 | c = (__u8) *s++; 454 | if ((c & 0xc0) != 0xc0) 455 | goto fail; 456 | c &= 0x3f; 457 | uchar |= c; 458 | 459 | // 3-byte sequence (most CJKV characters): 460 | // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx 461 | } else if ((c & 0xf0) == 0xe0) { 462 | uchar = (c & 0x0f) << 12; 463 | 464 | c = (__u8) *s++; 465 | if ((c & 0xc0) != 0xc0) 466 | goto fail; 467 | c &= 0x3f; 468 | uchar |= c << 6; 469 | 470 | c = (__u8) *s++; 471 | if ((c & 0xc0) != 0xc0) 472 | goto fail; 473 | c &= 0x3f; 474 | uchar |= c; 475 | 476 | /* no bogus surrogates */ 477 | if (0xd800 <= uchar && uchar <= 0xdfff) 478 | goto fail; 479 | 480 | // 4-byte sequence (surrogate pairs, currently rare): 481 | // 11101110wwwwzzzzyy + 110111yyyyxxxxxx 482 | // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 483 | // (uuuuu = wwww + 1) 484 | // FIXME accept the surrogate code points (only) 485 | 486 | } else 487 | goto fail; 488 | } else 489 | uchar = c; 490 | put_unaligned_le16 (uchar, cp++); 491 | count++; 492 | len--; 493 | } 494 | return count; 495 | fail: 496 | return -1; 497 | } 498 | -------------------------------------------------------------------------------- /include/dualsense.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | 3 | /*----------------------------------------------------------------------*/ 4 | 5 | #include 6 | #include "ps5_generated.h" 7 | 8 | #define PS5_STRING 9 | 10 | #define BCD_USB 0x0200 11 | 12 | //#define USB_VENDOR 0x1d6b 13 | //#define USB_PRODUCT 0x0104 14 | //#define USB_VENDOR 0x0525 15 | //#define USB_PRODUCT 0xa4a0 16 | #define USB_VENDOR 0x054c 17 | #define USB_PRODUCT 0x0ce6 18 | 19 | #define STRING_ID_MANUFACTURER 1 20 | #define STRING_ID_PRODUCT 2 21 | #define STRING_ID_SERIAL 0 22 | #define STRING_ID_CONFIG 0 23 | #define STRING_ID_INTERFACE 0 24 | 25 | #define EP_MAX_PACKET_CONTROL 64 26 | //#define EP_MAX_PACKET_INT 64 27 | 28 | // struct usb_device_descriptor usb_device = { 29 | #define B_DEVICE_CLASS 0 30 | #define B_DEVICE_SUBCLASS 0 31 | #define B_DEVICE_PROTOCOL 0 32 | #define BCD_DEVICE 0x0100 33 | #define NUM_COFIGURATIONS 1 34 | 35 | // struct usb_config_descriptor usb_config = { 36 | #define B_NUM_INTERFACES 4 37 | #define B_CONFIGURATION_VALUE 1 38 | #define B_MAX_POWER 0x32*5 39 | 40 | #define B_INTERVAL 6 41 | 42 | // Assigned dynamically. 43 | #define EP_NUM_INT_IN 0x0 44 | 45 | #define REPORT_ID_BT_MAC 0x81 46 | #define REPORT_ID_CALIBRATION 0x02 47 | #define REPORT_ID_HARDWARE_FIRMWARE 0xa3 48 | #define REPORT_NOIDEAWTF 0x12 49 | 50 | 51 | const char manufacturerString[] = "Sony Interactive Entertainment"; 52 | const char productString[] = "Wireless Controller"; 53 | 54 | const char usb_hid_report[] = { 55 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 56 | 0x09, 0x05, // Usage (Game Pad) 57 | 0xA1, 0x01, // Collection (Application) 58 | 0x85, 0x01, // Report ID (1) 59 | 0x09, 0x30, // Usage (X) 60 | 0x09, 0x31, // Usage (Y) 61 | 0x09, 0x32, // Usage (Z) 62 | 0x09, 0x35, // Usage (Rz) 63 | 0x09, 0x33, // Usage (Rx) 64 | 0x09, 0x34, // Usage (Ry) 65 | 0x15, 0x00, // Logical Minimum (0) 66 | 0x26, 0xFF, 0x00, // Logical Maximum (255) 67 | 0x75, 0x08, // Report Size (8) 68 | 0x95, 0x06, // Report Count (6) 69 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 70 | 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) 71 | 0x09, 0x20, // Usage (0x20) 72 | 0x95, 0x01, // Report Count (1) 73 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 74 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 75 | 0x09, 0x39, // Usage (Hat switch) 76 | 0x15, 0x00, // Logical Minimum (0) 77 | 0x25, 0x07, // Logical Maximum (7) 78 | 0x35, 0x00, // Physical Minimum (0) 79 | 0x46, 0x3B, 0x01, // Physical Maximum (315) 80 | 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) 81 | 0x75, 0x04, // Report Size (4) 82 | 0x95, 0x01, // Report Count (1) 83 | 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) 84 | 0x65, 0x00, // Unit (None) 85 | 0x05, 0x09, // Usage Page (Button) 86 | 0x19, 0x01, // Usage Minimum (0x01) 87 | 0x29, 0x0F, // Usage Maximum (0x0F) 88 | 0x15, 0x00, // Logical Minimum (0) 89 | 0x25, 0x01, // Logical Maximum (1) 90 | 0x75, 0x01, // Report Size (1) 91 | 0x95, 0x0F, // Report Count (15) 92 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 93 | 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) 94 | 0x09, 0x21, // Usage (0x21) 95 | 0x95, 0x0D, // Report Count (13) 96 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 97 | 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) 98 | 0x09, 0x22, // Usage (0x22) 99 | 0x15, 0x00, // Logical Minimum (0) 100 | 0x26, 0xFF, 0x00, // Logical Maximum (255) 101 | 0x75, 0x08, // Report Size (8) 102 | 0x95, 0x34, // Report Count (52) 103 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 104 | 0x85, 0x02, // Report ID (2) 105 | 0x09, 0x23, // Usage (0x23) 106 | 0x95, 0x2F, // Report Count (47) 107 | 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 108 | 0x85, 0x05, // Report ID (5) 109 | 0x09, 0x33, // Usage (0x33) 110 | 0x95, 0x28, // Report Count (40) 111 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 112 | 0x85, 0x08, // Report ID (8) 113 | 0x09, 0x34, // Usage (0x34) 114 | 0x95, 0x2F, // Report Count (47) 115 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 116 | 0x85, 0x09, // Report ID (9) 117 | 0x09, 0x24, // Usage (0x24) 118 | 0x95, 0x13, // Report Count (19) 119 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 120 | 0x85, 0x0A, // Report ID (10) 121 | 0x09, 0x25, // Usage (0x25) 122 | 0x95, 0x1A, // Report Count (26) 123 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 124 | 0x85, 0x20, // Report ID (32) 125 | 0x09, 0x26, // Usage (0x26) 126 | 0x95, 0x3F, // Report Count (63) 127 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 128 | 0x85, 0x21, // Report ID (33) 129 | 0x09, 0x27, // Usage (0x27) 130 | 0x95, 0x04, // Report Count (4) 131 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 132 | 0x85, 0x22, // Report ID (34) 133 | 0x09, 0x40, // Usage (0x40) 134 | 0x95, 0x3F, // Report Count (63) 135 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 136 | 0x85, 0x80, // Report ID (-128) 137 | 0x09, 0x28, // Usage (0x28) 138 | 0x95, 0x3F, // Report Count (63) 139 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 140 | 0x85, 0x81, // Report ID (-127) 141 | 0x09, 0x29, // Usage (0x29) 142 | 0x95, 0x3F, // Report Count (63) 143 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 144 | 0x85, 0x82, // Report ID (-126) 145 | 0x09, 0x2A, // Usage (0x2A) 146 | 0x95, 0x09, // Report Count (9) 147 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 148 | 0x85, 0x83, // Report ID (-125) 149 | 0x09, 0x2B, // Usage (0x2B) 150 | 0x95, 0x3F, // Report Count (63) 151 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 152 | 0x85, 0x84, // Report ID (-124) 153 | 0x09, 0x2C, // Usage (0x2C) 154 | 0x95, 0x3F, // Report Count (63) 155 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 156 | 0x85, 0x85, // Report ID (-123) 157 | 0x09, 0x2D, // Usage (0x2D) 158 | 0x95, 0x02, // Report Count (2) 159 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 160 | 0x85, 0xA0, // Report ID (-96) 161 | 0x09, 0x2E, // Usage (0x2E) 162 | 0x95, 0x01, // Report Count (1) 163 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 164 | 0x85, 0xE0, // Report ID (-32) 165 | 0x09, 0x2F, // Usage (0x2F) 166 | 0x95, 0x3F, // Report Count (63) 167 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 168 | 0x85, 0xF0, // Report ID (-16) 169 | 0x09, 0x30, // Usage (0x30) 170 | 0x95, 0x3F, // Report Count (63) 171 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 172 | 0x85, 0xF1, // Report ID (-15) 173 | 0x09, 0x31, // Usage (0x31) 174 | 0x95, 0x3F, // Report Count (63) 175 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 176 | 0x85, 0xF2, // Report ID (-14) 177 | 0x09, 0x32, // Usage (0x32) 178 | 0x95, 0x0F, // Report Count (15) 179 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 180 | 0x85, 0xF4, // Report ID (-12) 181 | 0x09, 0x35, // Usage (0x35) 182 | 0x95, 0x3F, // Report Count (63) 183 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 184 | 0x85, 0xF5, // Report ID (-11) 185 | 0x09, 0x36, // Usage (0x36) 186 | 0x95, 0x03, // Report Count (3) 187 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 188 | 0xC0, // End Collection 189 | 190 | // 273 bytes 191 | 192 | }; 193 | 194 | //typedef struct 195 | //{ 196 | // uint8_t reportId; // Report ID = 0x81 (129) sony_check_add() sony:hid 197 | // // Collection: CA:GamePad 198 | // uint8_t VEN_GamePad0021[6]; // Usage 0xFF800021: , Value = 0 to 255, Physical = Value x 21 / 17 199 | //} featureReport81_t; 200 | 201 | //featureReport81_t blueMacAddress = 202 | //{ 203 | // .reportId = 0x81, // Report ID = 0x81 (129) sony_check_add() sony:hid 204 | // // Collection: CA:GamePad 205 | // .VEN_GamePad0021 = { 206 | // 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 207 | // }, // Usage 0xFF800021: , Value = 0 to 255, Physical = Value x 21 / 17 208 | //}; 209 | 210 | //typedef struct 211 | //{ 212 | // uint8_t reportId; // Report ID = 0x02 (2) dualshock4_get_calibration_data() https://github.com/torvalds/linux/blob/master/drivers/hid/hid-sony.c 213 | // // Collection: CA:GamePad 214 | // uint8_t VEN_GamePad0024[36]; // Usage 0xFF000024: , Value = 0 to 255, Physical = Value x 21 / 17 215 | //} featureReport02_t; 216 | 217 | //featureReport02_t calibrationData = 218 | //{ 219 | // .reportId = 0x02, 220 | // .VEN_GamePad0024 = { 221 | //// 0x00,0x00, //gyro_pitch_bias 222 | //// 0x00,0x00, //gyro_yaw_bias 223 | //// 0x00,0x00, //gyro_roll_bias 224 | //// 0x01,0x00, // pithc plus 225 | //// 0x00,0x00, // pithc minus 226 | //// 0x01,0x00, // yaw plus 227 | //// 0x00,0x00, // yaw minuw 228 | //// 0x01,0x00, // roll plus 229 | //// 0x00,0x00, // roll minus 230 | //// 0x01,0x00, // gyro speed plu 231 | //// 0x00,0x00, // gyro speed minus 232 | //// 0x01,0x00, // x plus 233 | //// 0x00,0x00, // x minus 234 | //// 0x01,0x00, // y plus 235 | //// 0x00,0x00, // y minus 236 | //// 0x01,0x00, // z plus 237 | //// 0x00,0x00, // z minus 238 | //// 0x00,0x00, // ? 239 | // 0x15, 0x00 , 240 | // 0x04 , 0x00 , 241 | // 0x09 , 0x00 , 242 | // 0x0b , 0x22 , 243 | // 0x22 , 0xde , 244 | // 0xb6 , 0x22 , 245 | // 0x4a , 0xdd , 246 | // 0x05 , 0x24 , 247 | // 0x02 , 0xdc , 248 | // 0x1c , 0x02 , 249 | // 0x1c , 0x02 , 250 | // 0xfc , 0x1f , 251 | // 0x03 , 0xe0 , 252 | // 0x83 , 0x20 , 253 | // 0x7d , 0xdf , 254 | // 0xca , 0x1f , 255 | // 0x36 , 0xe0 , 256 | // 0x06 , 0x00 257 | // } 258 | //}; 259 | 260 | //typedef struct 261 | //{ 262 | // uint8_t reportId; // Report ID = 0xA3 (163) dualshock4_get_version_info() sony:hid 263 | // // Collection: CA:GamePad 264 | // uint8_t VEN_GamePad0043[48]; // Usage 0xFF800043: , Value = 0 to 255, Physical = Value x 21 / 17 265 | //} featureReportA3_t; 266 | 267 | //featureReportA3_t hardFirmVersion = { 268 | // .reportId = 0xa3, 269 | // .VEN_GamePad0043 = { 270 | //// 0, 0, 0, 0, 0, 0, 0, 271 | //// 0, 0, 0, 0, 0, 0, 0, 0, 272 | //// 0, 0, 0, 0, 0, 0, 0, 0, 273 | //// 0, 0, 0, 0, 0, 0, 0, 0, 274 | //// 0, 0, 0, 275 | //// 0x00, 0x74, 276 | //// 0, 0, 0, 0, 277 | //// 0x07, 0x80, 278 | //// 0, 0, 0, 0, 0 279 | // 0x4a, 0x75 , 0x6c , 0x20 , 0x31 , 0x31 , 0x20 , 0x32 , 0x30 , 0x31 , 0x36 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x31 , 0x31 , 0x3a , 0x30 , 0x38 , 0x3a , 0x32 , 0x32 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x74 , 0x01 , 0x00 , 0x00 , 0x00 , 0x07 , 0x80 , 0x00 , 0x05 , 0x00 , 0x80 , 0x03 , 0x00 280 | // } 281 | // 282 | //}; 283 | 284 | //typedef struct 285 | //{ 286 | // uint8_t reportId; // Report ID = 0x12 (18) 287 | // // Collection: CA:GamePad 288 | // uint8_t VEN_GamePad0021[15]; // Usage 0xFF020021: , Value = 0 to 255, Physical = Value x 21 / 17 289 | //} featureReport12_t; 290 | 291 | //featureReport12_t noIdeaWTF = { 292 | // .reportId = 0x12, 293 | // .VEN_GamePad0021 = { 294 | // 0x03 , 0xac , 0x39 , 0x84 , 295 | // 0x20 , 0x70 , 0x08 , 0x25 , 296 | // 0x00 , 0x00 , 0x00 , 0x00 , 297 | // 0x00 , 0x00 , 0x00 298 | // } 299 | //}; 300 | 301 | 302 | featureReport05_t unsure05 = { 303 | .reportId = 0x05, 304 | .VEN_GamePad0033 = { 305 | 0xfc , 0xff , 0xf8 , 0xff , 0xff , 306 | 0xff , 0x73 , 0x22 , 0x82 , 0xdd , 307 | 0x8f , 0x22 , 0x5a , 0xdd , 0xb9 , 308 | 0x22 , 0x42 , 0xdd , 0x1c , 0x02 , 309 | 0x1c , 0x02 , 0xd6 , 0x1f , 0xd5 , 310 | 0xdf , 0x8e , 0x1f , 0x95 , 0xdf , 311 | 0x00 , 0x20 , 0xf3 , 0xdf , 0x03 , 312 | 0x00 , 0x00 , 0x00 , 0x00 , 0x00 313 | } 314 | }; 315 | 316 | featureReport20_t unsure20 = { 317 | .reportId = 0x20, 318 | .VEN_GamePad0026 = { 319 | 0x4e , 0x6f , 0x76 , 0x20 , 0x32 , 0x30 , 0x20 , 0x32 , 320 | 0x30 , 0x32 , 0x30 , 0x31 , 0x32 , 0x3a , 0x35 , 0x39 , 321 | 0x3a , 0x35 , 0x35 , 0x02 , 0x00 , 0x04 , 0x00 , 0x13 , 322 | 0x03 , 0x00 , 0x00 , 0x37 , 0x00 , 0x00 , 0x01 , 0x41 , 323 | 0x0a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 324 | 0x00 , 0x00 , 0x00 , 0x10 , 0x02 , 0x00 , 0x00 , 0x2a , 325 | 0x00 , 0x01 , 0x00 , 0x06 , 0x00 , 0x01 , 0x00 , 0x06 , 326 | 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 327 | } 328 | 329 | }; 330 | 331 | featureReport09_t unsure09 = { 332 | .reportId = 0x09, 333 | .VEN_GamePad0024 = { 334 | 0x8c , 0xdc , 0x2b , 335 | 0x9b , 0xb9 , 0x4c , 0x08 , 336 | 0x25 , 0x00, 0x85 , 0xcc , 0x44 , 0xc1 , 0x98 , 0x1c 337 | } 338 | 339 | }; 340 | 341 | featureReport82_t unsure82 = { 342 | .reportId = 0x82, 343 | .VEN_GamePad002A = { 344 | 0, 0 345 | } 346 | }; 347 | 348 | featureReportF2_t unsureF2 = { 349 | .reportId = 0xf2, 350 | .VEN_GamePad0032 = { 351 | 0, 0, 0, 0, 0, 0, 0, 352 | 0, 0, 0, 0, 0, 0, 0, 0 353 | } 354 | 355 | }; 356 | 357 | 358 | 359 | char rawDualsenseConfig[] = { 360 | 0x09, 0x02, 0xe3, 0x00, 0x04, 0x01, 0x00, 0xc0, 0xfa, 0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x0a, 0x24, 0x01, 0x00, 0x01, 0x49, 0x00, 0x02, 0x01, 0x02, 0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x06, 0x04, 0x33, 0x00, 0x00, 0x00, 0x0c, 0x24, 0x06, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x04, 0x02, 0x00, 0x0c, 0x24, 0x02, 0x04, 0x02, 0x04, 0x03, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x24, 0x06, 0x05, 0x04, 0x01, 0x03, 0x00, 0x00, 0x09, 0x24, 0x03, 0x06, 0x01, 0x01, 0x01, 0x05, 0x00, 0x09, 0x04, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, 0x04, 0x01, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00, 0x07, 0x24, 0x01, 0x01, 0x01, 0x01, 0x00, 0x0b, 0x24, 0x02, 0x01, 0x04, 0x02, 0x10, 0x01, 0x80, 0xbb, 0x00, 0x09, 0x05, 0x01, 0x09, 0x88, 0x01, 0x04, 0x00, 0x00, 0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00, 0x07, 0x24, 0x01, 0x06, 0x01, 0x01, 0x00, 0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, 0x80, 0xbb, 0x00, 0x09, 0x05, 0x82, 0x05, 0xc4, 0x00, 0x04, 0x00, 0x00, 0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x03, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x11, 0x01, 0x07, 0x05, 0x84, 0x03, 0x40, 0x00, 0x06, 0x07, 0x05, 0x03, 0x03, 0x40, 0x00, 0x06 361 | }; 362 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /include/ds4.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | 3 | /*----------------------------------------------------------------------*/ 4 | 5 | #include "ps4_generated.h" 6 | 7 | #define PS4_STRING 8 | 9 | #define BCD_USB 0x0200 10 | 11 | //#define USB_VENDOR 0x1d6b 12 | //#define USB_PRODUCT 0x0104 13 | //#define USB_VENDOR 0x0525 14 | //#define USB_PRODUCT 0xa4a0 15 | #define USB_VENDOR 0x054c 16 | #define USB_PRODUCT 0x09cc 17 | 18 | #define STRING_ID_MANUFACTURER 1 19 | #define STRING_ID_PRODUCT 2 20 | #define STRING_ID_SERIAL 0 21 | #define STRING_ID_CONFIG 0 22 | #define STRING_ID_INTERFACE 0 23 | 24 | #define EP_MAX_PACKET_CONTROL 64 25 | #define EP_MAX_PACKET_INT 64 26 | 27 | // struct usb_device_descriptor usb_device = { 28 | #define B_DEVICE_CLASS 0 29 | #define B_DEVICE_SUBCLASS 0 30 | #define B_DEVICE_PROTOCOL 0 31 | #define BCD_DEVICE 0x0100 32 | #define NUM_COFIGURATIONS 1 33 | 34 | // struct usb_config_descriptor usb_config = { 35 | #define B_NUM_INTERFACES 1 36 | #define B_CONFIGURATION_VALUE 1 37 | #define B_MAX_POWER 0x32*5 38 | 39 | #define B_INTERVAL 5 40 | 41 | // Assigned dynamically. 42 | #define EP_NUM_INT_IN 0x0 43 | 44 | #define REPORT_ID_BT_MAC 0x81 45 | #define REPORT_ID_CALIBRATION 0x02 46 | #define REPORT_ID_HARDWARE_FIRMWARE 0xa3 47 | #define REPORT_NOIDEAWTF 0x12 48 | 49 | const char manufacturerString[] = "Sony Interactive Entertainment"; 50 | const char productString[] = "Wireless Controller"; 51 | 52 | const char usb_hid_report[] = { 53 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 54 | 0x09, 0x05, // Usage (Game Pad) 55 | 0xA1, 0x01, // Collection (Application) 56 | 0x85, 0x01, // Report ID (1) 57 | 0x09, 0x30, // Usage (X) 58 | 0x09, 0x31, // Usage (Y) 59 | 0x09, 0x32, // Usage (Z) 60 | 0x09, 0x35, // Usage (Rz) 61 | 0x15, 0x00, // Logical Minimum (0) 62 | 0x26, 0xFF, 0x00, // Logical Maximum (255) 63 | 0x75, 0x08, // Report Size (8) 64 | 0x95, 0x04, // Report Count (4) 65 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 66 | 0x09, 0x39, // Usage (Hat switch) 67 | 0x15, 0x00, // Logical Minimum (0) 68 | 0x25, 0x07, // Logical Maximum (7) 69 | 0x35, 0x00, // Physical Minimum (0) 70 | 0x46, 0x3B, 0x01, // Physical Maximum (315) 71 | 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) 72 | 0x75, 0x04, // Report Size (4) 73 | 0x95, 0x01, // Report Count (1) 74 | 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) 75 | 0x65, 0x00, // Unit (None) 76 | 0x05, 0x09, // Usage Page (Button) 77 | 0x19, 0x01, // Usage Minimum (0x01) 78 | 0x29, 0x0E, // Usage Maximum (0x0E) 79 | 0x15, 0x00, // Logical Minimum (0) 80 | 0x25, 0x01, // Logical Maximum (1) 81 | 0x75, 0x01, // Report Size (1) 82 | 0x95, 0x0E, // Report Count (14) 83 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 84 | 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) 85 | 0x09, 0x20, // Usage (0x20) 86 | 0x75, 0x06, // Report Size (6) 87 | 0x95, 0x01, // Report Count (1) 88 | 0x15, 0x00, // Logical Minimum (0) 89 | 0x25, 0x7F, // Logical Maximum (127) 90 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 91 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 92 | 0x09, 0x33, // Usage (Rx) 93 | 0x09, 0x34, // Usage (Ry) 94 | 0x15, 0x00, // Logical Minimum (0) 95 | 0x26, 0xFF, 0x00, // Logical Maximum (255) 96 | 0x75, 0x08, // Report Size (8) 97 | 0x95, 0x02, // Report Count (2) 98 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 99 | 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) 100 | 0x09, 0x21, // Usage (0x21) 101 | 0x95, 0x36, // Report Count (54) 102 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 103 | 0x85, 0x05, // Report ID (5) 104 | 0x09, 0x22, // Usage (0x22) 105 | 0x95, 0x1F, // Report Count (31) 106 | 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 107 | 0x85, 0x04, // Report ID (4) 108 | 0x09, 0x23, // Usage (0x23) 109 | 0x95, 0x24, // Report Count (36) 110 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 111 | 0x85, 0x02, // Report ID (2) 112 | 0x09, 0x24, // Usage (0x24) 113 | 0x95, 0x24, // Report Count (36) 114 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 115 | 0x85, 0x08, // Report ID (8) 116 | 0x09, 0x25, // Usage (0x25) 117 | 0x95, 0x03, // Report Count (3) 118 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 119 | 0x85, 0x10, // Report ID (16) 120 | 0x09, 0x26, // Usage (0x26) 121 | 0x95, 0x04, // Report Count (4) 122 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 123 | 0x85, 0x11, // Report ID (17) 124 | 0x09, 0x27, // Usage (0x27) 125 | 0x95, 0x02, // Report Count (2) 126 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 127 | 0x85, 0x12, // Report ID (18) 128 | 0x06, 0x02, 0xFF, // Usage Page (Vendor Defined 0xFF02) 129 | 0x09, 0x21, // Usage (0x21) 130 | 0x95, 0x0F, // Report Count (15) 131 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 132 | 0x85, 0x13, // Report ID (19) 133 | 0x09, 0x22, // Usage (0x22) 134 | 0x95, 0x16, // Report Count (22) 135 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 136 | 0x85, 0x14, // Report ID (20) 137 | 0x06, 0x05, 0xFF, // Usage Page (Vendor Defined 0xFF05) 138 | 0x09, 0x20, // Usage (0x20) 139 | 0x95, 0x10, // Report Count (16) 140 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 141 | 0x85, 0x15, // Report ID (21) 142 | 0x09, 0x21, // Usage (0x21) 143 | 0x95, 0x2C, // Report Count (44) 144 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 145 | 0x06, 0x80, 0xFF, // Usage Page (Vendor Defined 0xFF80) 146 | 0x85, 0x80, // Report ID (-128) 147 | 0x09, 0x20, // Usage (0x20) 148 | 0x95, 0x06, // Report Count (6) 149 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 150 | 0x85, 0x81, // Report ID (-127) 151 | 0x09, 0x21, // Usage (0x21) 152 | 0x95, 0x06, // Report Count (6) 153 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 154 | 0x85, 0x82, // Report ID (-126) 155 | 0x09, 0x22, // Usage (0x22) 156 | 0x95, 0x05, // Report Count (5) 157 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 158 | 0x85, 0x83, // Report ID (-125) 159 | 0x09, 0x23, // Usage (0x23) 160 | 0x95, 0x01, // Report Count (1) 161 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 162 | 0x85, 0x84, // Report ID (-124) 163 | 0x09, 0x24, // Usage (0x24) 164 | 0x95, 0x04, // Report Count (4) 165 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 166 | 0x85, 0x85, // Report ID (-123) 167 | 0x09, 0x25, // Usage (0x25) 168 | 0x95, 0x06, // Report Count (6) 169 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 170 | 0x85, 0x86, // Report ID (-122) 171 | 0x09, 0x26, // Usage (0x26) 172 | 0x95, 0x06, // Report Count (6) 173 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 174 | 0x85, 0x87, // Report ID (-121) 175 | 0x09, 0x27, // Usage (0x27) 176 | 0x95, 0x23, // Report Count (35) 177 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 178 | 0x85, 0x88, // Report ID (-120) 179 | 0x09, 0x28, // Usage (0x28) 180 | 0x95, 0x22, // Report Count (34) 181 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 182 | 0x85, 0x89, // Report ID (-119) 183 | 0x09, 0x29, // Usage (0x29) 184 | 0x95, 0x02, // Report Count (2) 185 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 186 | 0x85, 0x90, // Report ID (-112) 187 | 0x09, 0x30, // Usage (0x30) 188 | 0x95, 0x05, // Report Count (5) 189 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 190 | 0x85, 0x91, // Report ID (-111) 191 | 0x09, 0x31, // Usage (0x31) 192 | 0x95, 0x03, // Report Count (3) 193 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 194 | 0x85, 0x92, // Report ID (-110) 195 | 0x09, 0x32, // Usage (0x32) 196 | 0x95, 0x03, // Report Count (3) 197 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 198 | 0x85, 0x93, // Report ID (-109) 199 | 0x09, 0x33, // Usage (0x33) 200 | 0x95, 0x0C, // Report Count (12) 201 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 202 | 0x85, 0xA0, // Report ID (-96) 203 | 0x09, 0x40, // Usage (0x40) 204 | 0x95, 0x06, // Report Count (6) 205 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 206 | 0x85, 0xA1, // Report ID (-95) 207 | 0x09, 0x41, // Usage (0x41) 208 | 0x95, 0x01, // Report Count (1) 209 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 210 | 0x85, 0xA2, // Report ID (-94) 211 | 0x09, 0x42, // Usage (0x42) 212 | 0x95, 0x01, // Report Count (1) 213 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 214 | 0x85, 0xA3, // Report ID (-93) 215 | 0x09, 0x43, // Usage (0x43) 216 | 0x95, 0x30, // Report Count (48) 217 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 218 | 0x85, 0xA4, // Report ID (-92) 219 | 0x09, 0x44, // Usage (0x44) 220 | 0x95, 0x0D, // Report Count (13) 221 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 222 | 0x85, 0xA5, // Report ID (-91) 223 | 0x09, 0x45, // Usage (0x45) 224 | 0x95, 0x15, // Report Count (21) 225 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 226 | 0x85, 0xA6, // Report ID (-90) 227 | 0x09, 0x46, // Usage (0x46) 228 | 0x95, 0x15, // Report Count (21) 229 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 230 | 0x85, 0xF0, // Report ID (-16) 231 | 0x09, 0x47, // Usage (0x47) 232 | 0x95, 0x3F, // Report Count (63) 233 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 234 | 0x85, 0xF1, // Report ID (-15) 235 | 0x09, 0x48, // Usage (0x48) 236 | 0x95, 0x3F, // Report Count (63) 237 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 238 | 0x85, 0xF2, // Report ID (-14) 239 | 0x09, 0x49, // Usage (0x49) 240 | 0x95, 0x0F, // Report Count (15) 241 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 242 | 0x85, 0xA7, // Report ID (-89) 243 | 0x09, 0x4A, // Usage (0x4A) 244 | 0x95, 0x01, // Report Count (1) 245 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 246 | 0x85, 0xA8, // Report ID (-88) 247 | 0x09, 0x4B, // Usage (0x4B) 248 | 0x95, 0x01, // Report Count (1) 249 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 250 | 0x85, 0xA9, // Report ID (-87) 251 | 0x09, 0x4C, // Usage (0x4C) 252 | 0x95, 0x08, // Report Count (8) 253 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 254 | 0x85, 0xAA, // Report ID (-86) 255 | 0x09, 0x4E, // Usage (0x4E) 256 | 0x95, 0x01, // Report Count (1) 257 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 258 | 0x85, 0xAB, // Report ID (-85) 259 | 0x09, 0x4F, // Usage (0x4F) 260 | 0x95, 0x39, // Report Count (57) 261 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 262 | 0x85, 0xAC, // Report ID (-84) 263 | 0x09, 0x50, // Usage (0x50) 264 | 0x95, 0x39, // Report Count (57) 265 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 266 | 0x85, 0xAD, // Report ID (-83) 267 | 0x09, 0x51, // Usage (0x51) 268 | 0x95, 0x0B, // Report Count (11) 269 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 270 | 0x85, 0xAE, // Report ID (-82) 271 | 0x09, 0x52, // Usage (0x52) 272 | 0x95, 0x01, // Report Count (1) 273 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 274 | 0x85, 0xAF, // Report ID (-81) 275 | 0x09, 0x53, // Usage (0x53) 276 | 0x95, 0x02, // Report Count (2) 277 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 278 | 0x85, 0xB0, // Report ID (-80) 279 | 0x09, 0x54, // Usage (0x54) 280 | 0x95, 0x3F, // Report Count (63) 281 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 282 | 0x85, 0xB1, // Report ID (-79) 283 | 0x09, 0x55, // Usage (0x55) 284 | 0x95, 0x02, // Report Count (2) 285 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 286 | 0x85, 0xB2, // Report ID (-78) 287 | 0x09, 0x56, // Usage (0x56) 288 | 0x95, 0x02, // Report Count (2) 289 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 290 | 0x85, 0xE0, // Report ID (-32) 291 | 0x09, 0x57, // Usage (0x57) 292 | 0x95, 0x02, // Report Count (2) 293 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 294 | 0x85, 0xB3, // Report ID (-77) 295 | 0x09, 0x55, // Usage (0x55) 296 | 0x95, 0x3F, // Report Count (63) 297 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 298 | 0x85, 0xB4, // Report ID (-76) 299 | 0x09, 0x55, // Usage (0x55) 300 | 0x95, 0x3F, // Report Count (63) 301 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 302 | 0xC0, // End Collection 303 | 304 | // 507 bytes 305 | }; 306 | 307 | //typedef struct 308 | //{ 309 | // uint8_t reportId; // Report ID = 0x81 (129) sony_check_add() sony:hid 310 | // // Collection: CA:GamePad 311 | // uint8_t VEN_GamePad0021[6]; // Usage 0xFF800021: , Value = 0 to 255, Physical = Value x 21 / 17 312 | //} featureReport81_t; 313 | 314 | featureReport81_t blueMacAddress = 315 | { 316 | .reportId = 0x81, // Report ID = 0x81 (129) sony_check_add() sony:hid 317 | // Collection: CA:GamePad 318 | .VEN_GamePad0021 = { 319 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 320 | }, // Usage 0xFF800021: , Value = 0 to 255, Physical = Value x 21 / 17 321 | }; 322 | 323 | //typedef struct 324 | //{ 325 | // uint8_t reportId; // Report ID = 0x02 (2) dualshock4_get_calibration_data() https://github.com/torvalds/linux/blob/master/drivers/hid/hid-sony.c 326 | // // Collection: CA:GamePad 327 | // uint8_t VEN_GamePad0024[36]; // Usage 0xFF000024: , Value = 0 to 255, Physical = Value x 21 / 17 328 | //} featureReport02_t; 329 | 330 | featureReport02_t calibrationData = 331 | { 332 | .reportId = 0x02, 333 | .VEN_GamePad0024 = { 334 | // 0x00,0x00, //gyro_pitch_bias 335 | // 0x00,0x00, //gyro_yaw_bias 336 | // 0x00,0x00, //gyro_roll_bias 337 | // 0x01,0x00, // pithc plus 338 | // 0x00,0x00, // pithc minus 339 | // 0x01,0x00, // yaw plus 340 | // 0x00,0x00, // yaw minuw 341 | // 0x01,0x00, // roll plus 342 | // 0x00,0x00, // roll minus 343 | // 0x01,0x00, // gyro speed plu 344 | // 0x00,0x00, // gyro speed minus 345 | // 0x01,0x00, // x plus 346 | // 0x00,0x00, // x minus 347 | // 0x01,0x00, // y plus 348 | // 0x00,0x00, // y minus 349 | // 0x01,0x00, // z plus 350 | // 0x00,0x00, // z minus 351 | // 0x00,0x00, // ? 352 | 0x15, 0x00 , 353 | 0x04 , 0x00 , 354 | 0x09 , 0x00 , 355 | 0x0b , 0x22 , 356 | 0x22 , 0xde , 357 | 0xb6 , 0x22 , 358 | 0x4a , 0xdd , 359 | 0x05 , 0x24 , 360 | 0x02 , 0xdc , 361 | 0x1c , 0x02 , 362 | 0x1c , 0x02 , 363 | 0xfc , 0x1f , 364 | 0x03 , 0xe0 , 365 | 0x83 , 0x20 , 366 | 0x7d , 0xdf , 367 | 0xca , 0x1f , 368 | 0x36 , 0xe0 , 369 | 0x06 , 0x00 370 | } 371 | }; 372 | 373 | //typedef struct 374 | //{ 375 | // uint8_t reportId; // Report ID = 0xA3 (163) dualshock4_get_version_info() sony:hid 376 | // // Collection: CA:GamePad 377 | // uint8_t VEN_GamePad0043[48]; // Usage 0xFF800043: , Value = 0 to 255, Physical = Value x 21 / 17 378 | //} featureReportA3_t; 379 | 380 | featureReportA3_t hardFirmVersion = { 381 | .reportId = 0xa3, 382 | .VEN_GamePad0043 = { 383 | // 0, 0, 0, 0, 0, 0, 0, 384 | // 0, 0, 0, 0, 0, 0, 0, 0, 385 | // 0, 0, 0, 0, 0, 0, 0, 0, 386 | // 0, 0, 0, 0, 0, 0, 0, 0, 387 | // 0, 0, 0, 388 | // 0x00, 0x74, 389 | // 0, 0, 0, 0, 390 | // 0x07, 0x80, 391 | // 0, 0, 0, 0, 0 392 | 0x4a, 0x75 , 0x6c , 0x20 , 0x31 , 0x31 , 0x20 , 0x32 , 0x30 , 0x31 , 0x36 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x31 , 0x31 , 0x3a , 0x30 , 0x38 , 0x3a , 0x32 , 0x32 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x74 , 0x01 , 0x00 , 0x00 , 0x00 , 0x07 , 0x80 , 0x00 , 0x05 , 0x00 , 0x80 , 0x03 , 0x00 393 | } 394 | 395 | }; 396 | 397 | //typedef struct 398 | //{ 399 | // uint8_t reportId; // Report ID = 0x12 (18) 400 | // // Collection: CA:GamePad 401 | // uint8_t VEN_GamePad0021[15]; // Usage 0xFF020021: , Value = 0 to 255, Physical = Value x 21 / 17 402 | //} featureReport12_t; 403 | 404 | featureReport12_t noIdeaWTF = { 405 | .reportId = 0x12, 406 | .VEN_GamePad0021 = { 407 | 0x03 , 0xac , 0x39 , 0x84 , 408 | 0x20 , 0x70 , 0x08 , 0x25 , 409 | 0x00 , 0x00 , 0x00 , 0x00 , 410 | 0x00 , 0x00 , 0x00 411 | } 412 | }; 413 | 414 | 415 | 416 | //typedef struct 417 | //{ 418 | // uint8_t reportId; // Report ID = 0x01 (1) 419 | // // Collection: CA:GamePad 420 | // uint8_t GD_GamePadX; // Usage 0x00010030: X, Value = 0 to 255 421 | // uint8_t GD_GamePadY; // Usage 0x00010031: Y, Value = 0 to 255 422 | // uint8_t GD_GamePadZ; // Usage 0x00010032: Z, Value = 0 to 255 423 | // uint8_t GD_GamePadRz; // Usage 0x00010035: Rz, Value = 0 to 255 424 | // uint8_t GD_GamePadHatSwitch : 4; // Usage 0x00010039: Hat switch, Value = 0 to 7, Physical = Value x 45 in degrees 425 | // uint8_t BTN_GamePadButton1 : 1; // Usage 0x00090001: Button 1 Primary/trigger, Value = 0 to 1, Physical = Value x 315 426 | // uint8_t BTN_GamePadButton2 : 1; // Usage 0x00090002: Button 2 Secondary, Value = 0 to 1, Physical = Value x 315 427 | // uint8_t BTN_GamePadButton3 : 1; // Usage 0x00090003: Button 3 Tertiary, Value = 0 to 1, Physical = Value x 315 428 | // uint8_t BTN_GamePadButton4 : 1; // Usage 0x00090004: Button 4, Value = 0 to 1, Physical = Value x 315 429 | // uint8_t BTN_GamePadButton5 : 1; // Usage 0x00090005: Button 5, Value = 0 to 1, Physical = Value x 315 430 | // uint8_t BTN_GamePadButton6 : 1; // Usage 0x00090006: Button 6, Value = 0 to 1, Physical = Value x 315 431 | // uint8_t BTN_GamePadButton7 : 1; // Usage 0x00090007: Button 7, Value = 0 to 1, Physical = Value x 315 432 | // uint8_t BTN_GamePadButton8 : 1; // Usage 0x00090008: Button 8, Value = 0 to 1, Physical = Value x 315 433 | // uint8_t BTN_GamePadButton9 : 1; // Usage 0x00090009: Button 9, Value = 0 to 1, Physical = Value x 315 434 | // uint8_t BTN_GamePadButton10 : 1; // Usage 0x0009000A: Button 10, Value = 0 to 1, Physical = Value x 315 435 | // uint8_t BTN_GamePadButton11 : 1; // Usage 0x0009000B: Button 11, Value = 0 to 1, Physical = Value x 315 436 | // uint8_t BTN_GamePadButton12 : 1; // Usage 0x0009000C: Button 12, Value = 0 to 1, Physical = Value x 315 437 | // uint8_t BTN_GamePadButton13 : 1; // Usage 0x0009000D: Button 13, Value = 0 to 1, Physical = Value x 315 438 | // uint8_t BTN_GamePadButton14 : 1; // Usage 0x0009000E: Button 14, Value = 0 to 1, Physical = Value x 315 439 | // uint8_t VEN_GamePad0020 : 6; // Usage 0xFF000020: , Value = 0 to 127, Physical = Value x 315 / 127 440 | // uint8_t GD_GamePadRx; // Usage 0x00010033: Rx, Value = 0 to 255, Physical = Value x 21 / 17 441 | // uint8_t GD_GamePadRy; // Usage 0x00010034: Ry, Value = 0 to 255, Physical = Value x 21 / 17 442 | // uint8_t VEN_GamePad0021[54]; // Usage 0xFF000021: , Value = 0 to 255, Physical = Value x 21 / 17 443 | //} inputReport01_t; 444 | -------------------------------------------------------------------------------- /src/hid.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | //#include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | //#include 22 | 23 | #include 24 | 25 | //#include "ds4.h" 26 | #include "dualsense.h" 27 | //#include "magicPro.h" 28 | 29 | 30 | 31 | #include "raw-helper.h" 32 | 33 | 34 | /*----------------------------------------------------------------------*/ 35 | 36 | //#define BCD_USB 0x0200 37 | // 38 | ////#define USB_VENDOR 0x1d6b 39 | ////#define USB_PRODUCT 0x0104 40 | ////#define USB_VENDOR 0x0525 41 | ////#define USB_PRODUCT 0xa4a0 42 | //#define USB_VENDOR 0x054c 43 | //#define USB_PRODUCT 0x09cc 44 | // 45 | //#define STRING_ID_MANUFACTURER 1 46 | //#define STRING_ID_PRODUCT 2 47 | //#define STRING_ID_SERIAL 0 48 | //#define STRING_ID_CONFIG 0 49 | //#define STRING_ID_INTERFACE 0 50 | // 51 | //#define EP_MAX_PACKET_CONTROL 64 52 | //#define EP_MAX_PACKET_INT 64 53 | // 54 | //// Assigned dynamically. 55 | //#define EP_NUM_INT_IN 0x0 56 | 57 | struct usb_device_descriptor usb_device = { 58 | .bLength = USB_DT_DEVICE_SIZE, 59 | .bDescriptorType = USB_DT_DEVICE, 60 | .bcdUSB = __constant_cpu_to_le16(BCD_USB), 61 | .bDeviceClass = B_DEVICE_CLASS, 62 | .bDeviceSubClass = B_DEVICE_SUBCLASS, 63 | .bDeviceProtocol = B_DEVICE_PROTOCOL, 64 | .bMaxPacketSize0 = EP_MAX_PACKET_CONTROL, 65 | .idVendor = __constant_cpu_to_le16(USB_VENDOR), 66 | .idProduct = __constant_cpu_to_le16(USB_PRODUCT), 67 | .bcdDevice = BCD_DEVICE, 68 | .iManufacturer = STRING_ID_MANUFACTURER, 69 | .iProduct = STRING_ID_PRODUCT, 70 | .iSerialNumber = STRING_ID_SERIAL, 71 | .bNumConfigurations = NUM_COFIGURATIONS, 72 | }; 73 | 74 | struct usb_qualifier_descriptor usb_qualifier = { 75 | .bLength = sizeof(struct usb_qualifier_descriptor), 76 | .bDescriptorType = USB_DT_DEVICE_QUALIFIER, 77 | .bcdUSB = __constant_cpu_to_le16(BCD_USB), 78 | .bDeviceClass = 0, 79 | .bDeviceSubClass = 0, 80 | .bDeviceProtocol = 0, 81 | .bMaxPacketSize0 = EP_MAX_PACKET_CONTROL, 82 | .bNumConfigurations = 1, 83 | .bRESERVED = 0, 84 | }; 85 | 86 | struct usb_config_descriptor usb_config = { 87 | .bLength = USB_DT_CONFIG_SIZE, 88 | .bDescriptorType = USB_DT_CONFIG, 89 | .wTotalLength = 0, // computed later 90 | .bNumInterfaces = B_NUM_INTERFACES, 91 | .bConfigurationValue = B_CONFIGURATION_VALUE, 92 | .iConfiguration = STRING_ID_CONFIG, 93 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, 94 | .bMaxPower = B_MAX_POWER, 95 | }; 96 | 97 | #define NUM_ENDPOINTS 2 98 | 99 | struct usb_interface_descriptor usb_interface_audio1 = { 100 | .bLength = USB_DT_INTERFACE_SIZE, 101 | .bDescriptorType = USB_DT_INTERFACE, 102 | .bInterfaceNumber = 0, 103 | .bAlternateSetting = 0, 104 | .bNumEndpoints = 0, 105 | .bInterfaceClass = USB_CLASS_AUDIO, //USB_CLASS_HID, 106 | .bInterfaceSubClass = 1, // Control DEvice 107 | .bInterfaceProtocol = 0, 108 | .iInterface = 0, 109 | }; 110 | 111 | 112 | 113 | struct usb_interface_descriptor usb_interface = { 114 | .bLength = USB_DT_INTERFACE_SIZE, 115 | .bDescriptorType = USB_DT_INTERFACE, 116 | .bInterfaceNumber = 3, 117 | .bAlternateSetting = 0, 118 | .bNumEndpoints = NUM_ENDPOINTS, 119 | .bInterfaceClass = USB_CLASS_HID, 120 | .bInterfaceSubClass = 0, 121 | .bInterfaceProtocol = 0, 122 | .iInterface = STRING_ID_INTERFACE, 123 | }; 124 | 125 | //struct usb_endpoint_descriptor usb_endpoints[NUM_ENDPOINTS] = { 126 | // { 127 | // .bLength = USB_DT_ENDPOINT_SIZE, 128 | // .bDescriptorType = USB_DT_ENDPOINT, 129 | // .bEndpointAddress = USB_DIR_IN | EP_NUM_INT_IN | 0X04, 130 | // .bmAttributes = USB_ENDPOINT_XFER_INT, 131 | // .wMaxPacketSize = EP_MAX_PACKET_INT, 132 | // .bInterval = B_INTERVAL, 133 | // }, { 134 | // .bLength = USB_DT_ENDPOINT_SIZE, 135 | // .bDescriptorType = USB_DT_ENDPOINT, 136 | // .bEndpointAddress = USB_DIR_OUT | EP_NUM_INT_IN | 0x03, 137 | // .bmAttributes = USB_ENDPOINT_XFER_INT, 138 | // .wMaxPacketSize = EP_MAX_PACKET_INT, 139 | // .bInterval = B_INTERVAL, 140 | // } 141 | //}; 142 | 143 | struct usb_endpoint_descriptor usb_endpoints[4] = { 144 | { 145 | .bLength = USB_DT_ENDPOINT_SIZE, 146 | .bDescriptorType = USB_DT_ENDPOINT, 147 | .bEndpointAddress = USB_DIR_IN | EP_NUM_INT_IN | 0X04, 148 | .bmAttributes = USB_ENDPOINT_XFER_INT, 149 | .wMaxPacketSize = EP_MAX_PACKET_INT, 150 | .bInterval = B_INTERVAL, 151 | }, { 152 | .bLength = USB_DT_ENDPOINT_SIZE, 153 | .bDescriptorType = USB_DT_ENDPOINT, 154 | .bEndpointAddress = USB_DIR_OUT | EP_NUM_INT_IN | 0x03, 155 | .bmAttributes = USB_ENDPOINT_XFER_INT, 156 | .wMaxPacketSize = EP_MAX_PACKET_INT, 157 | .bInterval = B_INTERVAL, 158 | }, { 159 | .bLength = 9, 160 | .bDescriptorType = 5, 161 | .bEndpointAddress = USB_DIR_IN | EP_NUM_INT_IN | 0X02, 162 | .bmAttributes = 5, 163 | .wMaxPacketSize = 0x00c4, 164 | .bInterval = 4, 165 | }, { 166 | .bLength = 9, 167 | .bDescriptorType = 5, 168 | .bEndpointAddress = USB_DIR_OUT | EP_NUM_INT_IN | 0x01, 169 | .bmAttributes = 9, 170 | .wMaxPacketSize = 0x0188, 171 | .bInterval = 4, 172 | } 173 | }; 174 | 175 | 176 | 177 | struct hid_descriptor usb_hid = { 178 | .bLength = 9, 179 | .bDescriptorType = HID_DT_HID, 180 | .bcdHID = __constant_cpu_to_le16(0x0111), 181 | .bCountryCode = 0, 182 | .bNumDescriptors = 1, 183 | .desc = { 184 | { 185 | .bDescriptorType = HID_DT_REPORT, 186 | .wDescriptorLength = sizeof(usb_hid_report), 187 | } 188 | }, 189 | }; 190 | 191 | int build_config(char *data, int length) { 192 | // struct usb_config_descriptor *config = 193 | // (struct usb_config_descriptor *)data; 194 | // int total_length = 0; 195 | // 196 | // assert(length >= sizeof(usb_config)); 197 | // memcpy(data, &usb_config, sizeof(usb_config)); 198 | // data += sizeof(usb_config); 199 | // length -= sizeof(usb_config); 200 | // total_length += sizeof(usb_config); 201 | // 202 | // assert(length >= sizeof(usb_interface)); 203 | // memcpy(data, &usb_interface, sizeof(usb_interface)); 204 | // data += sizeof(usb_interface); 205 | // length -= sizeof(usb_interface); 206 | // total_length += sizeof(usb_interface); 207 | // 208 | // assert(length >= sizeof(usb_hid)); 209 | // memcpy(data, &usb_hid, sizeof(usb_hid)); 210 | // data += sizeof(usb_hid); 211 | // length -= sizeof(usb_hid); 212 | // total_length += sizeof(usb_hid); 213 | // 214 | // for (int i = 0; i < usb_interface.bNumEndpoints; i++) { 215 | // assert(length >= USB_DT_ENDPOINT_SIZE); 216 | // memcpy(data, &usb_endpoints[i], USB_DT_ENDPOINT_SIZE); 217 | // data += USB_DT_ENDPOINT_SIZE; 218 | // length -= USB_DT_ENDPOINT_SIZE; 219 | // total_length += USB_DT_ENDPOINT_SIZE; 220 | // } 221 | // 222 | // 223 | //// assert(length >= USB_DT_ENDPOINT_SIZE); 224 | //// memcpy(data, &usb_endpoint2, USB_DT_ENDPOINT_SIZE); 225 | //// data += USB_DT_ENDPOINT_SIZE; 226 | //// length -= USB_DT_ENDPOINT_SIZE; 227 | //// total_length += USB_DT_ENDPOINT_SIZE; 228 | // 229 | // config->wTotalLength = __cpu_to_le16(total_length); 230 | // printf("config->wTotalLength: %d\n", total_length); 231 | // 232 | // return total_length; 233 | 234 | memcpy(data, rawDualsenseConfig, 227); 235 | return 227; 236 | } 237 | 238 | /*----------------------------------------------------------------------*/ 239 | 240 | //bool assign_ep_address(struct usb_raw_ep_info *info, 241 | // struct usb_endpoint_descriptor *ep) { 242 | // if (usb_endpoint_num(ep) != 0) 243 | // return false; // Already assigned. 244 | // if (usb_endpoint_dir_in(ep) && !info->caps.dir_in) 245 | // return false; 246 | // if (usb_endpoint_dir_out(ep) && !info->caps.dir_out) 247 | // return false; 248 | // switch (usb_endpoint_type(ep)) { 249 | // case USB_ENDPOINT_XFER_BULK: 250 | // if (!info->caps.type_bulk) 251 | // return false; 252 | // break; 253 | // case USB_ENDPOINT_XFER_INT: 254 | // if (!info->caps.type_int) 255 | // return false; 256 | // break; 257 | // default: 258 | // assert(false); 259 | // } 260 | // if (info->addr == USB_RAW_EP_ADDR_ANY) { 261 | // static int addr = 1; 262 | // ep->bEndpointAddress |= addr++; 263 | // } else 264 | // ep->bEndpointAddress |= info->addr; 265 | // return true; 266 | //} 267 | 268 | void process_eps_info_fd(int fd) { 269 | struct usb_raw_eps_info info; 270 | memset(&info, 0, sizeof(info)); 271 | 272 | int num = usb_raw_eps_info(fd, &info); 273 | for (int i = 0; i < num; i++) { 274 | printf("ep #%d:\n", i); 275 | printf(" name: %s\n", &info.eps[i].name[0]); 276 | printf(" addr: %u\n", info.eps[i].addr); 277 | printf(" type: %s %s %s\n", 278 | info.eps[i].caps.type_iso ? "iso" : "___", 279 | info.eps[i].caps.type_bulk ? "blk" : "___", 280 | info.eps[i].caps.type_int ? "int" : "___"); 281 | printf(" dir : %s %s\n", 282 | info.eps[i].caps.dir_in ? "in " : "___", 283 | info.eps[i].caps.dir_out ? "out" : "___"); 284 | printf(" maxpacket_limit: %u\n", 285 | info.eps[i].limits.maxpacket_limit); 286 | printf(" max_streams: %u\n", info.eps[i].limits.max_streams); 287 | } 288 | 289 | for (int e = 0; e < usb_interface.bNumEndpoints; e++) { 290 | for (int i = 0; i < num; i++) { 291 | if (assign_ep_address(&info.eps[i], &usb_endpoints[e])) 292 | continue; 293 | } 294 | 295 | int int_in_addr = usb_endpoint_num(&usb_endpoints[e]); 296 | assert(int_in_addr != 0); 297 | printf("int_in: addr = %u\n", int_in_addr); 298 | } 299 | } 300 | 301 | 302 | 303 | 304 | 305 | 306 | int len; 307 | 308 | int ep_int_in = -1; 309 | int ep_int_out = -1; 310 | char dummyBuffer[128]; 311 | bool ep0_request(int fd, struct usb_raw_control_event *event, 312 | struct usb_raw_control_io *io, bool *done) { 313 | switch (event->ctrl.bRequestType & USB_TYPE_MASK) { 314 | case USB_TYPE_STANDARD: 315 | switch (event->ctrl.bRequest) { 316 | case USB_REQ_GET_DESCRIPTOR: 317 | switch (event->ctrl.wValue >> 8) { 318 | case USB_DT_DEVICE: 319 | memcpy(&io->data[0], &usb_device, sizeof(usb_device)); 320 | io->inner.length = sizeof(usb_device); 321 | return true; 322 | case USB_DT_DEVICE_QUALIFIER: 323 | memcpy(&io->data[0], &usb_qualifier, sizeof(usb_qualifier)); 324 | io->inner.length = sizeof(usb_qualifier); 325 | return true; 326 | case USB_DT_CONFIG: 327 | io->inner.length = build_config(&io->data[0], sizeof(io->data)); 328 | return true; 329 | case USB_DT_STRING: 330 | io->data[0] = 4; 331 | io->data[1] = USB_DT_STRING; 332 | switch (event->ctrl.wValue & 0xff) { 333 | case STRING_ID_MANUFACTURER: 334 | // memcpy(&io->data[2],"x0",2); 335 | // io->inner.length = 2+2; 336 | // io->data[0] = 6; 337 | // usb_gadget_get_string(); 338 | 339 | 340 | len = strlen(manufacturerString); 341 | // memcpy(&io->data[2],"Wireless Controller",19); 342 | memset (io->data + 2, 0, 2 * len); 343 | len = utf8_to_utf16le(manufacturerString, (__u16 *)&io->data[2], len); 344 | io->data[0] = (len + 1) * 2; 345 | break; 346 | // 347 | // 348 | case STRING_ID_PRODUCT: 349 | len = strlen(productString); 350 | // memcpy(&io->data[2],"Wireless Controller",19); 351 | memset (io->data + 2, 0, 2 * len); 352 | len = utf8_to_utf16le(productString, (__u16 *)&io->data[2], len); 353 | //io->inner.length = 19+2; 354 | io->data[0] = (len + 1) * 2; 355 | break; 356 | // case STRING_ID_SERIAL: 357 | case 0x00: 358 | io->data[2] = 0x09; 359 | io->data[3] = 0x04; 360 | //io->inner.length = 4; 361 | break; 362 | default: 363 | io->data[2] = 'x'; 364 | io->data[3] = 0x00; 365 | //io->inner.length = 4; 366 | break; 367 | } 368 | 369 | io->inner.length = event->ctrl.wLength < io->data[0] ? event->ctrl.wLength : io->data[0];//io->data[0]; 370 | return true; 371 | case HID_DT_REPORT: 372 | memcpy(&io->data[0], &usb_hid_report[0], 373 | sizeof(usb_hid_report)); 374 | io->inner.length = sizeof(usb_hid_report); 375 | printf(" ------ sizeof(usb_hid_report) = %d\n", (int) sizeof(usb_hid_report)); 376 | //io->inner.addr = 3; 377 | //*done = true; 378 | return true; 379 | case USB_DT_DEBUG: 380 | 381 | return false; 382 | default: 383 | printf("fail: event->ctrl.wValue >> 8 no response\n"); 384 | exit(EXIT_FAILURE); 385 | } 386 | break; 387 | case USB_REQ_SET_CONFIGURATION: 388 | if (ep_int_in < 0) { 389 | ep_int_in = usb_raw_ep_enable(fd, &usb_endpoints[0]); 390 | } 391 | if (ep_int_out < 0) { 392 | ep_int_out = usb_raw_ep_enable(fd, &usb_endpoints[1]); 393 | usb_raw_ep_enable(fd, &usb_endpoints[2]); 394 | usb_raw_ep_enable(fd, &usb_endpoints[3]); 395 | } 396 | printf(" ---- ep_int_in = %d\n", ep_int_in); 397 | printf(" ---- ep_int_out = %d\n", ep_int_out); 398 | usb_raw_vbus_draw(fd, usb_config.bMaxPower); 399 | usb_raw_configure(fd); 400 | io->inner.length = 0; 401 | return true; 402 | case USB_REQ_GET_INTERFACE: 403 | io->data[0] = usb_interface.bAlternateSetting; 404 | io->inner.length = 1; 405 | return true; 406 | 407 | case USB_REQ_SET_INTERFACE: 408 | printf("No ide what to do"); 409 | return true; 410 | default: 411 | printf("fail: USB_TYPE_STANDARD no response\n"); 412 | exit(EXIT_FAILURE); 413 | } 414 | break; 415 | case USB_TYPE_CLASS: 416 | switch (event->ctrl.bRequest) { 417 | case HID_REQ_SET_REPORT: 418 | io->inner.length = event->ctrl.wLength;//1; 419 | // io->inner.length = 1; 420 | *done = true; 421 | return true; 422 | case HID_REQ_SET_IDLE: 423 | io->inner.length = 0; 424 | //*done = true; 425 | return true; 426 | case HID_REQ_SET_PROTOCOL: 427 | io->inner.length = 0; 428 | *done = true; 429 | return true; 430 | 431 | case HID_REQ_GET_REPORT: 432 | // printf("fail: HID_REQ_GET_REPORT e\n", (int)event->ctrl.wLength); 433 | switch (event->ctrl.wValue & 0xff) { 434 | #ifdef PS4_STRING 435 | case REPORT_ID_BT_MAC: 436 | memcpy(&io->data[0], &blueMacAddress, sizeof(blueMacAddress)); 437 | io->inner.length = event->ctrl.wLength; 438 | return true; 439 | case REPORT_ID_CALIBRATION: 440 | memcpy(&io->data[0], &calibrationData, sizeof(calibrationData)); 441 | io->inner.length = event->ctrl.wLength; 442 | return true; 443 | case REPORT_ID_HARDWARE_FIRMWARE: 444 | memcpy(&io->data[0], &hardFirmVersion, sizeof(hardFirmVersion)); 445 | io->inner.length = event->ctrl.wLength; 446 | *done = true; 447 | return true; 448 | case REPORT_NOIDEAWTF: 449 | memcpy(&io->data[0], &noIdeaWTF, sizeof(noIdeaWTF)); 450 | io->inner.length = event->ctrl.wLength; 451 | *done = true; 452 | return true; 453 | #endif 454 | #ifdef PS5_STRING 455 | case 0x05: 456 | memcpy(&io->data[0], &unsure05, sizeof(unsure05)); 457 | io->inner.length = event->ctrl.wLength; 458 | 459 | return true; 460 | case 0x20: 461 | memcpy(&io->data[0], &unsure20, sizeof(unsure20)); 462 | io->inner.length = event->ctrl.wLength; 463 | 464 | return true; 465 | case 0x09: 466 | memcpy(&io->data[0], &unsure09, sizeof(unsure09)); 467 | io->inner.length = event->ctrl.wLength; 468 | 469 | return true; 470 | case 0x00: 471 | io->data[0] = 0; 472 | io->data[1] = 0; 473 | io->inner.length = event->ctrl.wLength; 474 | 475 | return true; 476 | 477 | case 0xf2: 478 | memcpy(&io->data[0], &unsureF2, sizeof(unsureF2)); 479 | io->inner.length = event->ctrl.wLength; 480 | 481 | return true; 482 | #endif 483 | #ifdef MAGIC_PRO 484 | case 0x03: 485 | memcpy(&io->data[0], &magicMagic, sizeof(magicMagic)); 486 | io->inner.length = event->ctrl.wLength; 487 | //*done = true; 488 | return true; 489 | #endif 490 | 491 | default: 492 | printf("|||| UNHANDLED HID_REQ_GET_REPORT - event->ctrl.wValue & 0xff == %02x\n", event->ctrl.wValue & 0xff ); 493 | memcpy(&io->data[0], dummyBuffer, event->ctrl.wLength); 494 | io->data[0] = event->ctrl.wValue & 0xff; // all responses have same header, but this feel hacky 495 | io->inner.length = event->ctrl.wLength; 496 | return true; 497 | } 498 | case HID_REQ_GET_IDLE: 499 | printf("fail: HID_REQ_GET_IDLE\n"); 500 | // io->data[0] = 1; 501 | // io->inner.length = 1; 502 | exit(EXIT_FAILURE); // HACK 503 | break; 504 | case HID_REQ_GET_PROTOCOL: 505 | printf("fail: HID_REQ_GET_PROTOCOL\n"); 506 | exit(EXIT_FAILURE); // HACK 507 | break; 508 | 509 | case 0x81: 510 | case 0x82: 511 | if (event->ctrl.wIndex == 0x500) { 512 | io->data[0] = 0; 513 | io->data[1] = 0; 514 | } else { 515 | io->data[0] = 0; 516 | io->data[1] = 0x9c; 517 | } 518 | io->inner.length = event->ctrl.wLength; 519 | return true; 520 | case 0x83: 521 | if (event->ctrl.wIndex == 0x500) { 522 | io->data[0] = 0; 523 | io->data[1] = 0x30; 524 | } else { 525 | io->data[0] = 0; 526 | io->data[1] = 0; 527 | } 528 | io->inner.length = event->ctrl.wLength; 529 | return true; 530 | case 0x84: 531 | if (event->ctrl.wIndex == 0x500) { 532 | io->data[0] = 0x7a; 533 | io->data[1] = 0x00; 534 | } else { 535 | io->data[0] = 0; 536 | io->data[1] = 0x01; 537 | } 538 | io->inner.length = event->ctrl.wLength; 539 | return true; 540 | // case 0x01: 541 | // case 0x02: 542 | // 543 | // case 0x03: 544 | case 0x04: 545 | // if (event->ctrl.wIndex == 0x500) { 546 | // io->data[0] = 0x7a; 547 | // io->data[1] = 0x00; 548 | // } else { 549 | // io->data[0] = 0; 550 | // io->data[1] = 0x01; 551 | // } 552 | io->inner.length = event->ctrl.wLength; 553 | return true; 554 | default: 555 | printf("fail: USB_TYPE_CLASS no response: event->ctrl.bRequest = %d\n", (int)event->ctrl.bRequest); 556 | exit(EXIT_FAILURE); // HACK 557 | // *done = true; 558 | // return true; 559 | } 560 | break; 561 | case USB_TYPE_VENDOR: 562 | switch (event->ctrl.bRequest) { 563 | default: 564 | printf("fail: USB_TYPE_VENDOR no response\n"); 565 | exit(EXIT_FAILURE); 566 | } 567 | break; 568 | default: 569 | printf("fail: default: no response\n"); 570 | exit(EXIT_FAILURE); 571 | } 572 | } 573 | 574 | // Not technically a loop as we stop processing ep0 requests to make the 575 | // example simpler. 576 | bool ep0_loop(int fd) { 577 | bool done = false; 578 | //while (!done) { 579 | struct usb_raw_control_event event; 580 | event.inner.type = 0; 581 | event.inner.length = sizeof(event.ctrl); 582 | 583 | usb_raw_event_fetch(fd, (struct usb_raw_event *)&event); 584 | log_event((struct usb_raw_event *)&event); 585 | 586 | if (event.inner.type == USB_RAW_EVENT_CONNECT) 587 | process_eps_info_fd(fd); 588 | 589 | if (event.inner.type != USB_RAW_EVENT_CONTROL) 590 | return false;//continue; 591 | 592 | struct usb_raw_control_io io; 593 | io.inner.ep = 0; 594 | io.inner.flags = 0; 595 | io.inner.length = 0; 596 | 597 | bool reply = ep0_request(fd, &event, &io, &done); 598 | if (!reply) { 599 | printf("ep0: stalling\n"); 600 | usb_raw_ep0_stall(fd); 601 | return false;//continue; 602 | } 603 | 604 | if (event.ctrl.wLength < io.inner.length) 605 | io.inner.length = event.ctrl.wLength; 606 | int rv = -1; 607 | if (event.ctrl.bRequestType & USB_DIR_IN) { 608 | rv = usb_raw_ep0_write(fd, (struct usb_raw_ep_io *)&io); 609 | printf("ep0: transferred %d bytes (in) - ", rv); 610 | } else { 611 | rv = usb_raw_ep0_read(fd, (struct usb_raw_ep_io *)&io); 612 | printf("ep0: transferred %d bytes (out) - ", rv); 613 | 614 | } 615 | for (int i = 0; i < io.inner.length; i++) { 616 | printf("%02x ", io.inner.data[i]); 617 | } 618 | printf("\n"); 619 | //} 620 | 621 | return done; 622 | } 623 | 624 | void* ep0_loop_thread( void* data ) { 625 | int fd = *(int*)data; 626 | while(1) 627 | ep0_loop(fd); 628 | } 629 | 630 | 631 | void ep_int_in_loop(int fd) { 632 | //printf(" -- FINALLY in ep_int_in_loop\n"); 633 | struct usb_raw_int_io io; 634 | io.inner.ep = ep_int_in;// | 0X04; 635 | io.inner.flags = 0; 636 | io.inner.length = 64; 637 | 638 | 639 | 640 | static unsigned int button = 16; 641 | 642 | inputReport01_t joy; 643 | 644 | 645 | 646 | memset(&joy, 0, sizeof(joy)); 647 | joy.reportId = 0x01; 648 | 649 | *((unsigned int*)(8+(unsigned char*)&joy)) |= button; 650 | 651 | if (button >= 0x80000000) { 652 | button = 0x001; 653 | } else { 654 | button = button << 1; 655 | } 656 | 657 | //while (true) { 658 | // joy.BTN_GamePadButton5 = 1; 659 | // joy.BTN_GamePadButton1 = 0; 660 | memcpy(&io.inner.data[0], &joy, sizeof(joy)); 661 | //printf(" -- sending...\n"); 662 | int rv = usb_raw_ep_write(fd, (struct usb_raw_ep_io *)&io); 663 | if (rv < 0) { 664 | // error? 665 | } 666 | //printf("int_in: key down: %d\n", rv); 667 | 668 | // if(0) { 669 | // io.inner.ep = ep_int_out;// | 0X04; 670 | // io.inner.flags = 0; 671 | // io.inner.length = 32; 672 | // rv = usb_raw_ep_read(fd, (struct usb_raw_ep_io *)&io); 673 | // printf("int_out: key down: %d - ", rv); 674 | // for (int i = 0; i < rv; i++) { 675 | // printf("%02x ", io.inner.data[i]); 676 | // } 677 | // printf("\n"); 678 | // } 679 | // usleep(50000); 680 | 681 | // joy.BTN_GamePadButton5 = 0; 682 | // joy.BTN_GamePadButton1 = 1; 683 | // memcpy(&io.inner.data[0], &joy, sizeof(joy)); 684 | // rv = usb_raw_ep_write(fd, (struct usb_raw_ep_io *)&io); 685 | // printf("int_in: key up: %d\n", rv); 686 | 687 | // usleep(500000); 688 | //} 689 | } 690 | 691 | void ep_int_out_loop(int fd) { 692 | //printf(" -- FINALLY in ep_int_in_loop\n"); 693 | struct usb_raw_int_io io; 694 | 695 | io.inner.ep = ep_int_out;// | 0X04; 696 | io.inner.flags = 0; 697 | io.inner.length = 48;//32; 698 | 699 | 700 | 701 | 702 | 703 | //inputReport01_t joy; 704 | 705 | 706 | int rv = usb_raw_ep_read(fd, (struct usb_raw_ep_io *)&io); 707 | printf("int_out: key down: %d - ", rv); 708 | for (int i = 0; i < rv; i++) { 709 | printf("%02x ", io.inner.data[i]); 710 | } 711 | printf("\n"); 712 | 713 | 714 | // joy.BTN_GamePadButton5 = 0; 715 | // joy.BTN_GamePadButton1 = 1; 716 | // memcpy(&io.inner.data[0], &joy, sizeof(joy)); 717 | // rv = usb_raw_ep_write(fd, (struct usb_raw_ep_io *)&io); 718 | // printf("int_in: key up: %d\n", rv); 719 | 720 | // usleep(500000); 721 | //} 722 | } 723 | 724 | 725 | 726 | void* epin_loop_thread( void* data ) { 727 | int fd = *(int*)data; 728 | while(1) { 729 | if (ep_int_in >= 0) { 730 | ep_int_in_loop(fd); 731 | usleep(200000); 732 | } else { 733 | usleep(100000); 734 | } 735 | } 736 | } 737 | 738 | void* epout_loop_thread( void* data ) { 739 | int fd = *(int*)data; 740 | while(1) { 741 | if (ep_int_out >= 0) { 742 | ep_int_out_loop(fd); 743 | usleep(1000); 744 | } else { 745 | usleep(100000); 746 | } 747 | } 748 | } 749 | 750 | int main(int argc, char **argv) { 751 | const char *device = "dummy_udc.0"; 752 | const char *driver = "dummy_udc"; 753 | if (argc >= 2) 754 | device = argv[1]; 755 | if (argc >= 3) 756 | driver = argv[2]; 757 | 758 | int fd = usb_raw_open(); 759 | usb_raw_init(fd, USB_SPEED_HIGH, driver, device); 760 | usb_raw_run(fd); 761 | 762 | 763 | pthread_t threadEp0; 764 | 765 | pthread_create(&threadEp0, NULL, ep0_loop_thread, &fd); 766 | 767 | pthread_t threadEpOut; 768 | pthread_t threadEpIn; 769 | pthread_create(&threadEpIn, NULL, epin_loop_thread, &fd); 770 | pthread_create(&threadEpOut, NULL, epout_loop_thread, &fd); 771 | 772 | //sleep(10); 773 | //bool allGood = false; 774 | while(1) { 775 | //printf(" ---- ep0_loop(fd): start\n"); 776 | sleep(1); 777 | 778 | 779 | //if(ep0_loop(fd)) 780 | // allGood = true; 781 | 782 | // if (allGood) { 783 | // while(1) { 784 | // ep_int_in_loop(fd); 785 | //printf(" ---- ep_int_in_loop(fd): done\n"); 786 | // } 787 | // }/ 788 | } 789 | close(fd); 790 | 791 | return 0; 792 | } 793 | -------------------------------------------------------------------------------- /src/raw-gadget.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "raw-gadget.hpp" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | 25 | void setEndpoint(AlternateInfo* info, int endpoint, bool enable) { 26 | EndpointInfo* endpointInfo = &info->mEndpointInfos[endpoint]; 27 | if (enable) { 28 | printf(" - - - Attempting to enable EP 0x%02x\n", endpointInfo->usb_endpoint.bEndpointAddress); 29 | endpointInfo->ep_int = usb_raw_ep_enable(endpointInfo->fd, &endpointInfo->usb_endpoint); 30 | //libusb_set_interface_alt_setting 31 | //usb_raw_ep_set_halt(endpointInfo->fd, endpointInfo->ep_int); 32 | endpointInfo->stop = false; 33 | endpointInfo->keepRunning = true; 34 | pthread_create(&endpointInfo->thread, NULL, ep_loop_thread, endpointInfo); 35 | } else { // may need mutex here 36 | int temp = endpointInfo->ep_int; 37 | endpointInfo->stop = true; 38 | endpointInfo->keepRunning = false; 39 | // while(endpointInfo->busyPackets > 0) { 40 | // usleep(100); 41 | // } 42 | pthread_join(endpointInfo->thread, NULL); 43 | 44 | printf(" - - - Attempting to disable EP with: %d\n", temp); 45 | int ret = usb_raw_ep_disable(endpointInfo->fd, temp); 46 | printf(" - - - No idea about this ep disable return: %d\n", ret); 47 | endpointInfo->ep_int = ret; 48 | 49 | } 50 | printf(" ---- 0x%02x ep_int = %d\n", endpointInfo->usb_endpoint.bEndpointAddress, endpointInfo->ep_int); 51 | } 52 | 53 | void setAlternate(InterfaceInfo* info, int alternate) { 54 | AlternateInfo* alternateInfo = &info->mAlternateInfos[alternate]; 55 | if (alternate >= 0) { 56 | alternateInfo = &info->mAlternateInfos[alternate]; 57 | } else { 58 | alternateInfo = &info->mAlternateInfos[info->activeAlternate]; 59 | } 60 | 61 | 62 | if (info->activeAlternate != alternate && 63 | info->activeAlternate >= 0 && 64 | alternate >= 0) { 65 | printf(" - - Need to disable current Alternate %d!\n", info->activeAlternate); // TODO; 66 | for (int i = 0; i < info->mAlternateInfos[info->activeAlternate].bNumEndpoints; i++) { 67 | printf(" - - | setEndpoint(?, %d, %d)\n", i, false); 68 | setEndpoint(&info->mAlternateInfos[info->activeAlternate], i, false); 69 | } 70 | } 71 | for (int i = 0; i < alternateInfo->bNumEndpoints; i++) { 72 | printf(" - - setEndpoint(?, %d, %d)\n", i, alternate >= 0 ? true : false); 73 | setEndpoint(alternateInfo, i, alternate >= 0 ? true : false); 74 | } 75 | 76 | 77 | 78 | info->activeAlternate = alternate; 79 | } 80 | 81 | void setInterface(libusb_device_handle *deviceHandle, ConfigurationInfo* info, int interface, int alternate) { 82 | InterfaceInfo* interfaceInfo = &info->mInterfaceInfos[interface]; 83 | 84 | if (info->activeInterface != interface && 85 | info->activeInterface >= 0 && 86 | alternate > 0) { 87 | //printf(" - Need to disable current Interface of %d,%d!\n", info->activeInterface, info->mInterfaceInfos[info->activeInterface].activeAlternate); 88 | //setAlternate(&info->mInterfaceInfos[info->activeInterface], -1); 89 | } 90 | 91 | printf(" - setAlternate(?, %d)\n", alternate); 92 | setAlternate(interfaceInfo, alternate); 93 | info->activeInterface = interface; 94 | if (alternate >= 0) { 95 | if(libusb_set_interface_alt_setting(deviceHandle, interface, alternate ) != LIBUSB_SUCCESS) { 96 | printf("LIBUSB_ERROR! libusb_set_interface_alt_setting()"); 97 | } 98 | } 99 | 100 | } 101 | 102 | void setConfiguration(EndpointZeroInfo* info, int configuration) { 103 | ConfigurationInfo* configInfo = &info->mConfigurationInfos[configuration]; 104 | 105 | 106 | if (info->activeConfiguration != configuration && 107 | info->activeConfiguration >= 0 && 108 | configuration >= 0) { 109 | printf("Need to disable current configuration!"); 110 | for (int i = 0; i < info->mConfigurationInfos[info->activeConfiguration].bNumInterfaces; i++) { 111 | setInterface(info->dev_handle, &info->mConfigurationInfos[info->activeConfiguration], i, -1); // unsure if this is needed in set config 112 | } 113 | } 114 | 115 | for (int i = 0; i < configInfo->bNumInterfaces; i++) { 116 | printf("setInterface(?, %d, %d)\n", i, 0); 117 | setInterface(info->dev_handle, configInfo, i, 0); // unsure if this is needed in set config 118 | } 119 | info->activeConfiguration = configuration; 120 | } 121 | 122 | 123 | //char dummyBuffer[4096]; 124 | bool ep0_request(EndpointZeroInfo* info, struct usb_raw_control_event *event, 125 | struct usb_raw_control_io *io, bool *done) { 126 | int r; 127 | 128 | io->inner.length = event->ctrl.wLength; 129 | // if (event->ctrl.bRequestType & 0x80) { 130 | // printf("copying %d bytes\n", event->ctrl.wLength); 131 | // // memcpy(dummyBuffer, &event->inner.data[0], event->ctrl.wLength); 132 | // 133 | // r = libusb_control_transfer( info->dev_handle, 134 | // event->ctrl.bRequestType, 135 | // event->ctrl.bRequest, 136 | // event->ctrl.wValue, 137 | // event->ctrl.wIndex, 138 | // // event->inner.data, 139 | // // dummyBuffer, 140 | // (unsigned char*)&io->data[0], 141 | // event->ctrl.wLength, 142 | // 0); 143 | // if (r < 0) { 144 | // printf("libusb_control_transfer error: %s\n", libusb_error_name(r)); 145 | // return false; 146 | // } 147 | // 148 | // // memcpy(&io->inner.data[0], dummyBuffer, r); 149 | // // memcpy(&io->data[0], dummyBuffer, r); 150 | // // memcpy(&io->inner.data[0], event->inner.data, r); 151 | // io->inner.length = r; 152 | // } 153 | 154 | if( (event->ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 155 | switch(event->ctrl.bRequest) { 156 | case USB_REQ_SET_CONFIGURATION: 157 | printf(" - Setting Configuration to: %d\n", event->ctrl.wValue & 0xff); // "The lower byte of the wValue field specifies the desired configuration" 158 | 159 | // from: https://usb.ktemkin.com/files/8a35f1350a32d1b2ab2efa5c3e5036e30b9cdcac53a4f772a8db122fcbe2a1a1/usb_device_framework_chapter.pdf 160 | //8. Based on the configuration information and how the USB device will be used, the host assigns a configuration value to the device. The device is now in the Configured state and all of the endpoints in this configuration have taken on their described characteristics. The USB device may now draw the amount of VBUS power described in its descriptor for the selected configuration. From the device’s point of view, it is now ready for use. 161 | setConfiguration(info, (event->ctrl.wValue & 0xff) -1); 162 | 163 | usb_raw_vbus_draw(info->fd, 0x32*5); // TODO: grab from descriptor for passthrough 164 | usb_raw_configure(info->fd); 165 | // io->inner.length = 0; 166 | break; 167 | case USB_REQ_SET_INTERFACE: 168 | printf(" - Setting Interface to: %d Alternate: %d\n", event->ctrl.wIndex, event->ctrl.wValue); 169 | setInterface(info->dev_handle, &info->mConfigurationInfos[info->activeConfiguration], event->ctrl.wIndex, event->ctrl.wValue); 170 | break; 171 | default: 172 | break; 173 | } 174 | } 175 | return true; 176 | } 177 | 178 | 179 | bool ep0_loop(EndpointZeroInfo* info) { 180 | bool done = false; 181 | //while (!done) { 182 | struct usb_raw_control_event event; 183 | event.inner.type = 0; 184 | event.inner.length = sizeof(event.ctrl); 185 | 186 | usb_raw_event_fetch(info->fd, (struct usb_raw_event *)&event); 187 | log_event((struct usb_raw_event *)&event); 188 | 189 | switch (event.inner.type) { 190 | case USB_RAW_EVENT_CONNECT: 191 | printf("ep0_loop(): Recieved a USB_RAW_EVENT_CONNECT\n"); 192 | process_eps_info(info); 193 | return false; 194 | break; 195 | 196 | case USB_RAW_EVENT_CONTROL: 197 | break; // continue for processing 198 | 199 | default: 200 | printf("ep0_loop(): event.inner.type != USB_RAW_EVENT_CONTROL, event.inner.type = %d\n", event.inner.type); 201 | return false; 202 | break; 203 | } 204 | // if (event.inner.type == USB_RAW_EVENT_CONNECT) { 205 | // printf("ep0_loop(): Recieved a USB_RAW_EVENT_CONNECT\n"); 206 | // process_eps_info(info); 207 | // } 208 | // 209 | // if (event.inner.type != USB_RAW_EVENT_CONTROL) { 210 | // printf("ep0_loop(): event.inner.type != USB_RAW_EVENT_CONTROL, event.inner.type = %d\n", event.inner.type); 211 | // return false;//continue; 212 | // } 213 | 214 | struct usb_raw_control_io io; 215 | io.inner.ep = 0; 216 | io.inner.flags = 0; 217 | io.inner.length = 0; 218 | 219 | bool reply = ep0_request(info, &event, &io, &done); 220 | if (!reply) { 221 | printf("ep0: stalling\n"); 222 | usb_raw_ep0_stall(info->fd); 223 | return false;//continue; 224 | } 225 | //printf("ep0: ep0_request() Success!\n"); 226 | 227 | if (event.ctrl.wLength < io.inner.length) 228 | io.inner.length = event.ctrl.wLength; 229 | int rv = -1; 230 | if (event.ctrl.bRequestType & USB_DIR_IN) { 231 | printf("copying %d bytes\n", event.ctrl.wLength); 232 | // memcpy(dummyBuffer, &event->inner.data[0], event->ctrl.wLength); 233 | 234 | rv = libusb_control_transfer( info->dev_handle, 235 | event.ctrl.bRequestType, 236 | event.ctrl.bRequest, 237 | event.ctrl.wValue, 238 | event.ctrl.wIndex, 239 | // event->inner.data, 240 | // dummyBuffer, 241 | (unsigned char*)&io.data[0], 242 | event.ctrl.wLength, 243 | 0); 244 | if (rv < 0) { 245 | printf("libusb_control_transfer error: %s\n", libusb_error_name(rv)); 246 | printf("ep0: stalling\n"); 247 | usb_raw_ep0_stall(info->fd); 248 | return false; 249 | } 250 | 251 | // memcpy(&io->inner.data[0], dummyBuffer, r); 252 | // memcpy(&io->data[0], dummyBuffer, r); 253 | // memcpy(&io->inner.data[0], event->inner.data, r); 254 | io.inner.length = rv; 255 | rv = usb_raw_ep0_write(info->fd, (struct usb_raw_ep_io *)&io); 256 | printf("ep0: transferred %d bytes (in: DEVICE -> HOST) - ", rv); 257 | } else { 258 | rv = usb_raw_ep0_read(info->fd, (struct usb_raw_ep_io *)&io); 259 | printf("ep0: transferred %d bytes (out: HOST -> DEVICE) - ", rv); 260 | 261 | 262 | int r = libusb_control_transfer( info->dev_handle, 263 | event.ctrl.bRequestType, 264 | event.ctrl.bRequest, 265 | event.ctrl.wValue, 266 | event.ctrl.wIndex, 267 | // event->inner.data, 268 | (unsigned char*)&io.data[0], 269 | // dummyBuffer, 270 | io.inner.length, 271 | // event->ctrl.wLength, 272 | 0); 273 | 274 | if (r < 0) { 275 | printf(" ERROR libusb_control_transfer() returned < 0 in ep0_loop(). r = %d\n", r); 276 | } 277 | } 278 | for (__u32 i = 0; i < io.inner.length; i++) { 279 | printf("%02x ", io.inner.data[i]); 280 | } 281 | printf("\n"); 282 | //} 283 | 284 | return done; 285 | } 286 | 287 | void* ep0_loop_thread( void* data ) { 288 | // int fd = *(int*)data; 289 | EndpointZeroInfo* info = (EndpointZeroInfo *)data; 290 | while(1) 291 | ep0_loop(info);//fd); 292 | } 293 | 294 | 295 | static void cb_transfer_out(struct libusb_transfer *xfr) { 296 | EndpointInfo* epInfo = (EndpointInfo*)xfr->user_data; 297 | epInfo->busyPackets--; 298 | if (xfr->status != LIBUSB_TRANSFER_COMPLETED) { 299 | fprintf(stderr, "transfer status %d\n", xfr->status); 300 | 301 | 302 | return; 303 | } 304 | 305 | // printf("xfr Success!\n"); 306 | //epInfo->busyPackets--; 307 | libusb_free_transfer(xfr); 308 | } 309 | void ep_out_work_interrupt( EndpointInfo* epInfo ) { 310 | if (epInfo->busyPackets >= 1) { 311 | usleep(epInfo->bIntervalInMicroseconds); 312 | return; 313 | } 314 | 315 | struct usb_raw_int_io io; 316 | io.inner.ep = epInfo->ep_int;//ep_int_in;// | 0X04; 317 | io.inner.flags = 0; 318 | io.inner.length = epInfo->usb_endpoint.wMaxPacketSize; 319 | 320 | int transferred = usb_raw_ep_read(epInfo->fd, (struct usb_raw_ep_io *)&io); 321 | // printf("ep_out_work_interrupt(): %d - ", rv); 322 | // for (int i = 0; i < rv; i++) { 323 | // printf("%02x ", io.inner.data[i]); 324 | // } 325 | // printf("\n"); 326 | if (transferred <= 0) { // Shoudl we stil relay a packet of size 0? 327 | if (transferred < 0) { 328 | //printf("WARNING: usb_raw_ep_read() returned %d in ep_out_work_interrupt()\n", transferred); 329 | static int errorCount = 0; 330 | if (errorCount++ > 100) { 331 | errorCount = 0; 332 | printf("WARNING: usb_raw_ep_read() has seen another 100 timeouts\n"); 333 | } 334 | } 335 | usleep(epInfo->bIntervalInMicroseconds); 336 | return; 337 | } 338 | //unsigned char data[48]; 339 | //int transferred = rv; 340 | 341 | //memcpy(epInfo->data, &io.inner.data[0], transferred); 342 | 343 | //epInfo->busyPackets++; 344 | struct libusb_transfer *transfer; 345 | transfer = libusb_alloc_transfer(0); 346 | if (transfer == NULL) { 347 | printf("ERROR: libusb_alloc_transfer(0) no memory"); 348 | } 349 | switch(epInfo->usb_endpoint.bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) { 350 | case LIBUSB_TRANSFER_TYPE_INTERRUPT: 351 | libusb_fill_interrupt_transfer( transfer, 352 | epInfo->deviceHandle, 353 | epInfo->usb_endpoint.bEndpointAddress, 354 | &io.inner.data[0],//epInfo->data, 355 | transferred,//epInfo->usb_endpoint.wMaxPacketSize, 356 | cb_transfer_out, 357 | epInfo, 358 | 0 ); 359 | break; 360 | case LIBUSB_TRANSFER_TYPE_BULK: 361 | libusb_fill_bulk_transfer( transfer, 362 | epInfo->deviceHandle, 363 | epInfo->usb_endpoint.bEndpointAddress, 364 | &io.inner.data[0],//epInfo->data, 365 | transferred,//epInfo->usb_endpoint.wMaxPacketSize, 366 | cb_transfer_out, 367 | epInfo, 368 | 0 ); 369 | break; 370 | default: 371 | printf("ERROR! p_out_work_interrupt() unknopwn transfer type\n"); 372 | return; 373 | } 374 | 375 | 376 | epInfo->busyPackets++; 377 | if(libusb_submit_transfer(transfer) != LIBUSB_SUCCESS) { 378 | printf("ERROR! libusb_submit_transfer(transfer) in ep_out_work_interrupt()\n"); 379 | exit(EXIT_FAILURE); 380 | } 381 | } 382 | 383 | static void cb_transfer_in(struct libusb_transfer *xfr) { 384 | if (xfr->status != LIBUSB_TRANSFER_COMPLETED) { 385 | fprintf(stderr, "transfer status %d\n", xfr->status); 386 | return; 387 | } 388 | 389 | EndpointInfo* epInfo = (EndpointInfo*)xfr->user_data; 390 | struct usb_raw_int_io io; 391 | io.inner.ep = epInfo->ep_int; 392 | io.inner.flags = 0; 393 | 394 | if (xfr->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { 395 | //printf("cb_transfer_iso_in() nmeeds to handle %d iso packets\n",xfr->num_iso_packets ); 396 | for (int i = 0; i < xfr->num_iso_packets; i++) { 397 | struct libusb_iso_packet_descriptor *pack = &xfr->iso_packet_desc[i]; 398 | 399 | if (pack->status != LIBUSB_TRANSFER_COMPLETED) { 400 | fprintf(stderr, "Error: pack %u status %d\n", i, pack->status); 401 | continue; 402 | } 403 | 404 | // printf("pack%u length:%u, actual_length:%u\n", i, pack->length, pack->actual_length); 405 | 406 | 407 | io.inner.length = pack->actual_length;//0;//epInfo->wMaxPacketSize; 408 | 409 | // TODO: everything, really 410 | //printf("Sending to ep 0x%02x %d\n", io.inner.ep, io.inner.length); 411 | // memcpy(&io.inner.data[0], epInfo->data, pack->actual_length); 412 | memcpy(&io.inner.data[0], xfr->buffer, pack->actual_length); 413 | 414 | // struct pollfd fds[1]; 415 | // fds[0].fd = epInfo->fd; 416 | // fds[0].events = POLLOUT; 417 | // int timeout = 1; 418 | // int ready; 419 | // if ( (ready = poll ( fds, 1, 1 )) == 0 ) 420 | // { 421 | // printf("Not ready to send!\n"); 422 | // libusb_free_transfer(xfr); 423 | // return; 424 | // } 425 | // printf("Ready: %d\n", ready); 426 | // int flags; 427 | // flags = fcntl(epInfo->fd, F_GETFL, 0); 428 | // if (-1 == flags) { 429 | // printf("-1 == flagsd %d\n", flags); 430 | // return ; 431 | // } 432 | // fcntl(epInfo->fd, F_SETFL, flags | O_NONBLOCK); 433 | // int rv = usb_raw_ep_write(epInfo->fd, (struct usb_raw_ep_io *)&io); 434 | int rv = pack->actual_length;//usb_raw_ep_write(epInfo->fd, (struct usb_raw_ep_io *)&io); 435 | if (rv < 0) { 436 | printf("Error! iso write to host usb_raw_ep_write() returned %d\n", rv); 437 | } else if (rv != pack->actual_length) { 438 | printf("WARNSSSING! Only sent %d bytes instead of %d\n", rv, pack->actual_length); 439 | } 440 | //printf("Dine!\n"); 441 | } 442 | } else { 443 | io.inner.length = xfr->actual_length;//0;//epInfo->wMaxPacketSize; 444 | 445 | //printf("Sending to ep 0x%02x %d\n", io.inner.ep, io.inner.length); 446 | // memcpy(&io.inner.data[0], epInfo->data, pack->actual_length); 447 | memcpy(&io.inner.data[0], xfr->buffer, xfr->actual_length); 448 | 449 | int rv = usb_raw_ep_write(epInfo->fd, (struct usb_raw_ep_io *)&io); 450 | if (rv < 0) { 451 | printf("Error! bulk/interrupt write to host usb_raw_ep_write() returned %d\n", rv); 452 | } else if (rv != xfr->actual_length) { 453 | printf("WARNING! Only sent %d bytes instead of %d\n", rv, xfr->actual_length); 454 | } 455 | } 456 | 457 | epInfo->busyPackets--; 458 | libusb_free_transfer(xfr); 459 | } 460 | void ep_in_work_interrupt( EndpointInfo* epInfo ) { 461 | 462 | if (epInfo->busyPackets >= 1) { 463 | usleep(epInfo->bIntervalInMicroseconds); 464 | return; 465 | } 466 | epInfo->busyPackets++; 467 | struct libusb_transfer *transfer; 468 | transfer = libusb_alloc_transfer(0); 469 | if (transfer == NULL) { 470 | printf("ERROR: libusb_alloc_transfer(0) no memory"); 471 | } 472 | switch(epInfo->usb_endpoint.bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) { 473 | case LIBUSB_TRANSFER_TYPE_INTERRUPT: 474 | libusb_fill_interrupt_transfer( transfer, 475 | epInfo->deviceHandle, 476 | epInfo->usb_endpoint.bEndpointAddress, 477 | epInfo->data, 478 | epInfo->usb_endpoint.wMaxPacketSize, 479 | cb_transfer_in, 480 | epInfo, 481 | 0 ); 482 | break; 483 | case LIBUSB_TRANSFER_TYPE_BULK: // TODO: need to accounf fo bulk streams maybe 484 | libusb_fill_bulk_transfer( transfer, 485 | epInfo->deviceHandle, 486 | epInfo->usb_endpoint.bEndpointAddress, 487 | epInfo->data, 488 | epInfo->usb_endpoint.wMaxPacketSize, 489 | cb_transfer_in, 490 | epInfo, 491 | 0 ); 492 | 493 | break; 494 | default: 495 | printf("ERROR! ep_in_work_interrupt) unknopwn transfer type\n"); 496 | return; 497 | } 498 | 499 | if(libusb_submit_transfer(transfer) != LIBUSB_SUCCESS) { 500 | printf("ERROR! libusb_submit_transfer(transfer) in ep_in_work_interrupt()\n"); 501 | exit(EXIT_FAILURE); 502 | } 503 | } 504 | 505 | ////int yesImDone = true; 506 | //static void cb_transfer_iso_in(struct libusb_transfer *xfr) { 507 | // if (xfr->status != LIBUSB_TRANSFER_COMPLETED) { 508 | // fprintf(stderr, "transfer status %d\n", xfr->status); 509 | // return; 510 | // } 511 | // EndpointInfo* epInfo = (EndpointInfo*)xfr->user_data; 512 | // if (xfr->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { 513 | // //printf("cb_transfer_iso_in() nmeeds to handle %d iso packets\n",xfr->num_iso_packets ); 514 | // for (int i = 0; i < xfr->num_iso_packets; i++) { 515 | // struct libusb_iso_packet_descriptor *pack = &xfr->iso_packet_desc[i]; 516 | // 517 | // if (pack->status != LIBUSB_TRANSFER_COMPLETED) { 518 | // fprintf(stderr, "Error: pack %u status %d\n", i, pack->status); 519 | // continue; 520 | // } 521 | // 522 | // // printf("pack%u length:%u, actual_length:%u\n", i, pack->length, pack->actual_length); 523 | // 524 | // 525 | // 526 | // 527 | // struct usb_raw_int_io io; 528 | // io.inner.ep = epInfo->ep_int; 529 | // io.inner.flags = 0; 530 | // io.inner.length = pack->actual_length;//0;//epInfo->wMaxPacketSize; 531 | // 532 | // // TODO: everything, really 533 | // //printf("Sending to ep 0x%02x %d\n", io.inner.ep, io.inner.length); 534 | // // memcpy(&io.inner.data[0], epInfo->data, pack->actual_length); 535 | // memcpy(&io.inner.data[0], xfr->buffer, pack->actual_length); 536 | // 537 | // // struct pollfd fds[1]; 538 | // // fds[0].fd = epInfo->fd; 539 | // // fds[0].events = POLLOUT; 540 | // // int timeout = 1; 541 | // // int ready; 542 | // // if ( (ready = poll ( fds, 1, 1 )) == 0 ) 543 | // // { 544 | // // printf("Not ready to send!\n"); 545 | // // libusb_free_transfer(xfr); 546 | // // return; 547 | // // } 548 | // // printf("Ready: %d\n", ready); 549 | //// int flags; 550 | //// flags = fcntl(epInfo->fd, F_GETFL, 0); 551 | //// if (-1 == flags) { 552 | //// printf("-1 == flagsd %d\n", flags); 553 | //// return ; 554 | //// } 555 | //// fcntl(epInfo->fd, F_SETFL, flags | O_NONBLOCK); 556 | // int rv = usb_raw_ep_write(epInfo->fd, (struct usb_raw_ep_io *)&io); 557 | // if (rv < 0) { 558 | // printf("Error! iso write to host usb_raw_ep_write() returned %d\n", rv); 559 | // } 560 | // //printf("Dine!\n"); 561 | // } 562 | // } 563 | // epInfo->busyPackets--; 564 | // //yesImDone = true; 565 | // libusb_free_transfer(xfr); 566 | //} 567 | 568 | void ep_in_work_isochronous( EndpointInfo* epInfo ) { 569 | if (epInfo->busyPackets >= 1) { 570 | //printf("ep_in_work_isochronous() is waiting on packets!\n"); 571 | usleep(epInfo->bIntervalInMicroseconds); 572 | return; 573 | } 574 | epInfo->busyPackets++; 575 | struct libusb_transfer *xfr; 576 | int num_iso_pack = 1; // When should this be non-1? 577 | xfr = libusb_alloc_transfer(num_iso_pack); 578 | //char buffer[200]; 579 | libusb_fill_iso_transfer(xfr, 580 | epInfo->deviceHandle, 581 | epInfo->usb_endpoint.bEndpointAddress, 582 | //buffer,// 583 | epInfo->data, 584 | epInfo->usb_endpoint.wMaxPacketSize, 585 | num_iso_pack, 586 | cb_transfer_in, 587 | epInfo, 588 | 0); 589 | libusb_set_iso_packet_lengths(xfr, epInfo->usb_endpoint.wMaxPacketSize/num_iso_pack); 590 | 591 | libusb_submit_transfer(xfr); 592 | //yesImDone = false; 593 | 594 | //usleep(10000); 595 | } 596 | 597 | void ep_out_work_isochronous( EndpointInfo* epInfo ) { 598 | if (epInfo->busyPackets >= 128) { 599 | //printf("ep_out_work_isochronous() (audio out) is busy with packets\n"); 600 | usleep(epInfo->bIntervalInMicroseconds); 601 | return; 602 | } 603 | epInfo->busyPackets++; 604 | struct usb_raw_int_io io; 605 | io.inner.ep = epInfo->ep_int; 606 | io.inner.flags = 0; 607 | io.inner.length = epInfo->usb_endpoint.wMaxPacketSize; 608 | static int errorCount = 0; 609 | int transferred = usb_raw_ep_read(epInfo->fd, (struct usb_raw_ep_io *)&io); 610 | if (transferred <= 0) { 611 | if (errorCount++ % 50) { 612 | printf("ep_out_work_isochronous() error count %d: No data available I guess? transferred = %d\n", errorCount, transferred); 613 | 614 | } 615 | usleep(epInfo->bIntervalInMicroseconds); 616 | epInfo->busyPackets--; 617 | return; 618 | } 619 | 620 | // if (epInfo->busyPackets >= 3) { 621 | // 622 | // epInfo->busyPackets--; 623 | // return; 624 | // } 625 | // printf("ep_out_work_isochronous(): %d - ", transferred); 626 | // for (int i = 0; i < transferred; i++) { 627 | // printf("%02x ", io.inner.data[i]); 628 | // } 629 | // printf("\n"); 630 | // int transferred = rv; 631 | // memcpy(epInfo->data, &io.inner.data[0], transferred); 632 | 633 | static struct libusb_transfer *xfr; 634 | int num_iso_pack = 1; 635 | xfr = libusb_alloc_transfer(num_iso_pack); 636 | libusb_fill_iso_transfer(xfr, 637 | epInfo->deviceHandle, 638 | epInfo->usb_endpoint.bEndpointAddress, 639 | &io.inner.data[0],//epInfo->data, 640 | transferred, 641 | num_iso_pack, 642 | cb_transfer_out, 643 | epInfo, 644 | 0); 645 | libusb_set_iso_packet_lengths(xfr, transferred/num_iso_pack); 646 | 647 | libusb_submit_transfer(xfr); 648 | 649 | // if (rv < 0) { 650 | // // ? error 651 | // } 652 | } 653 | 654 | void* ep_loop_thread( void* data ) { 655 | EndpointInfo *ep = (EndpointInfo*)data; 656 | 657 | printf("Starting thread for endpoint 0x%02x\n", ep->usb_endpoint.bEndpointAddress); 658 | int idleDelay = 1000000; 659 | int idleCount = 0; 660 | bool priorenable = false; 661 | while(ep->keepRunning || (ep->busyPackets > 0)) { 662 | if (ep->ep_int >= 0 && !ep->stop) { 663 | if (priorenable == false && 664 | (ep->usb_endpoint.bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { 665 | priorenable = true; 666 | usleep(1000000); 667 | //continue; 668 | } 669 | if (ep->usb_endpoint.bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) { // data in 670 | switch (ep->usb_endpoint.bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) { 671 | case LIBUSB_TRANSFER_TYPE_INTERRUPT: 672 | case LIBUSB_TRANSFER_TYPE_BULK: 673 | ep_in_work_interrupt( ep ); 674 | //usleep(pow(2, ep->usb_endpoint.bInterval-1) * 125); 675 | //usleep(1000); 676 | break; 677 | case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 678 | //usleep(125); 679 | ep_in_work_isochronous( ep ); 680 | 681 | // if (idleCount++ > 100) { 682 | // idleCount = 0; 683 | // printf("Audio in buffered: "); 684 | // for (int i = 0; i < ep->busyPackets; i++) { 685 | // printf("."); 686 | // } 687 | // printf("\n"); 688 | // } 689 | break; 690 | case LIBUSB_TRANSFER_TYPE_CONTROL: 691 | default: 692 | printf("Unsupported ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK\n"); 693 | usleep(1000); 694 | break; 695 | } 696 | } else { // data out 697 | switch (ep->usb_endpoint.bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) { 698 | case LIBUSB_TRANSFER_TYPE_INTERRUPT: 699 | case LIBUSB_TRANSFER_TYPE_BULK: 700 | //usleep(pow(2, ep->usb_endpoint.bInterval-1) * 125); 701 | //usleep(1000); 702 | ep_out_work_interrupt( ep ); 703 | break; 704 | case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 705 | ep_out_work_isochronous( ep ); 706 | 707 | if (idleCount++ > 300) { 708 | idleCount = 0; 709 | fprintf(stderr, "Audio out buffered: "); 710 | for (int i = 0; i < ep->busyPackets; i++) { 711 | fprintf(stderr, "."); 712 | } 713 | fprintf(stderr, " \r"); 714 | } 715 | //usleep(125); 716 | break; 717 | case LIBUSB_TRANSFER_TYPE_CONTROL: 718 | default: 719 | printf("Unsupported ep->bEndpointAddress\n"); 720 | usleep(1000); 721 | break; 722 | } 723 | } 724 | 725 | //usleep(pow(2, ep->usb_endpoint.bInterval-1) * 125);// not sure if binterval should be trusted, nor if it's 125 or 1000. should also be 2^(interval-1) 726 | } else { // reaching here means we are simply cleaning things up 727 | idleCount++; 728 | if (idleCount > 1000000/idleDelay) { 729 | idleCount = 0; 730 | printf("Idle: Endpoint 0x%02x - ep->busyPackets=%d\n", ep->usb_endpoint.bEndpointAddress, ep->busyPackets); 731 | } 732 | //printf("Idle: Endpoint 0x%02x\n", ep->usb_endpoint.bEndpointAddress); 733 | //if((ep->usb_endpoint.bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) 734 | // usleep(1000000); 735 | usleep(idleDelay); 736 | } 737 | } 738 | 739 | printf("Terminating thread for endpoint 0x%02x\n", ep->usb_endpoint.bEndpointAddress); 740 | 741 | return NULL; 742 | } 743 | 744 | -------------------------------------------------------------------------------- /include/ps5_generated.h: -------------------------------------------------------------------------------- 1 | 2 | //-------------------------------------------------------------------------------- 3 | // Decoded Application Collection 4 | //-------------------------------------------------------------------------------- 5 | 6 | /* 7 | 05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page 8 | 09 05 (LOCAL) USAGE 0x00010005 Game Pad (Application Collection) 9 | A1 01 (MAIN) COLLECTION 0x01 Application (Usage=0x00010005: Page=Generic Desktop Page, Usage=Game Pad, Type=Application Collection) 10 | 85 01 (GLOBAL) REPORT_ID 0x01 (1) 11 | 09 30 (LOCAL) USAGE 0x00010030 X (Dynamic Value) 12 | 09 31 (LOCAL) USAGE 0x00010031 Y (Dynamic Value) 13 | 09 32 (LOCAL) USAGE 0x00010032 Z (Dynamic Value) 14 | 09 35 (LOCAL) USAGE 0x00010035 Rz (Dynamic Value) 15 | 09 33 (LOCAL) USAGE 0x00010033 Rx (Dynamic Value) 16 | 09 34 (LOCAL) USAGE 0x00010034 Ry (Dynamic Value) 17 | 15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Info: Consider replacing 15 00 with 14 18 | 26 FF00 (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255) 19 | 75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field 20 | 95 06 (GLOBAL) REPORT_COUNT 0x06 (6) Number of fields 21 | 81 02 (MAIN) INPUT 0x00000002 (6 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 22 | 06 00FF (GLOBAL) USAGE_PAGE 0xFF00 Vendor-defined 23 | 09 20 (LOCAL) USAGE 0xFF000020 <-- Warning: Undocumented usage (document it by inserting 0020 into file FF00.conf) 24 | 95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields 25 | 81 02 (MAIN) INPUT 0x00000002 (1 field x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 26 | 05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page 27 | 09 39 (LOCAL) USAGE 0x00010039 Hat switch (Dynamic Value) 28 | 15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14 29 | 25 07 (GLOBAL) LOGICAL_MAXIMUM 0x07 (7) 30 | 35 00 (GLOBAL) PHYSICAL_MINIMUM 0x00 (0) <-- Info: Consider replacing 35 00 with 34 31 | 46 3B01 (GLOBAL) PHYSICAL_MAXIMUM 0x013B (315) 32 | 65 14 (GLOBAL) UNIT 0x14 Rotation in degrees [1° units] (4=System=English Rotation, 1=Rotation=Degrees) 33 | 75 04 (GLOBAL) REPORT_SIZE 0x04 (4) Number of bits per field 34 | 95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1 35 | 81 42 (MAIN) INPUT 0x00000042 (1 field x 4 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 1=Null 0=NonVolatile 0=Bitmap 36 | 65 00 (GLOBAL) UNIT 0x00 No unit (0=None) <-- Info: Consider replacing 65 00 with 64 37 | 05 09 (GLOBAL) USAGE_PAGE 0x0009 Button Page 38 | 19 01 (LOCAL) USAGE_MINIMUM 0x00090001 Button 1 Primary/trigger (Selector, On/Off Control, Momentary Control, or One Shot Control) 39 | 29 0F (LOCAL) USAGE_MAXIMUM 0x0009000F Button 15 (Selector, On/Off Control, Momentary Control, or One Shot Control) 40 | 15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14 41 | 25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1) 42 | 75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field 43 | 95 0F (GLOBAL) REPORT_COUNT 0x0F (15) Number of fields 44 | 81 02 (MAIN) INPUT 0x00000002 (15 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 45 | 06 00FF (GLOBAL) USAGE_PAGE 0xFF00 Vendor-defined 46 | 09 21 (LOCAL) USAGE 0xFF000021 <-- Warning: Undocumented usage (document it by inserting 0021 into file FF00.conf) 47 | 95 0D (GLOBAL) REPORT_COUNT 0x0D (13) Number of fields 48 | 81 02 (MAIN) INPUT 0x00000002 (13 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 49 | 06 00FF (GLOBAL) USAGE_PAGE 0xFF00 Vendor-defined <-- Redundant: USAGE_PAGE is already 0xFF00 50 | 09 22 (LOCAL) USAGE 0xFF000022 <-- Warning: Undocumented usage (document it by inserting 0022 into file FF00.conf) 51 | 15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14 52 | 26 FF00 (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255) 53 | 75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field 54 | 95 34 (GLOBAL) REPORT_COUNT 0x34 (52) Number of fields 55 | 81 02 (MAIN) INPUT 0x00000002 (52 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 56 | 85 02 (GLOBAL) REPORT_ID 0x02 (2) 57 | 09 23 (LOCAL) USAGE 0xFF000023 <-- Warning: Undocumented usage (document it by inserting 0023 into file FF00.conf) 58 | 95 2F (GLOBAL) REPORT_COUNT 0x2F (47) Number of fields 59 | 91 02 (MAIN) OUTPUT 0x00000002 (47 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 60 | 85 05 (GLOBAL) REPORT_ID 0x05 (5) 61 | 09 33 (LOCAL) USAGE 0xFF000033 <-- Warning: Undocumented usage (document it by inserting 0033 into file FF00.conf) 62 | 95 28 (GLOBAL) REPORT_COUNT 0x28 (40) Number of fields 63 | B1 02 (MAIN) FEATURE 0x00000002 (40 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 64 | 85 08 (GLOBAL) REPORT_ID 0x08 (8) 65 | 09 34 (LOCAL) USAGE 0xFF000034 <-- Warning: Undocumented usage (document it by inserting 0034 into file FF00.conf) 66 | 95 2F (GLOBAL) REPORT_COUNT 0x2F (47) Number of fields 67 | B1 02 (MAIN) FEATURE 0x00000002 (47 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 68 | 85 09 (GLOBAL) REPORT_ID 0x09 (9) 69 | 09 24 (LOCAL) USAGE 0xFF000024 <-- Warning: Undocumented usage (document it by inserting 0024 into file FF00.conf) 70 | 95 13 (GLOBAL) REPORT_COUNT 0x13 (19) Number of fields 71 | B1 02 (MAIN) FEATURE 0x00000002 (19 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 72 | 85 0A (GLOBAL) REPORT_ID 0x0A (10) 73 | 09 25 (LOCAL) USAGE 0xFF000025 <-- Warning: Undocumented usage (document it by inserting 0025 into file FF00.conf) 74 | 95 1A (GLOBAL) REPORT_COUNT 0x1A (26) Number of fields 75 | B1 02 (MAIN) FEATURE 0x00000002 (26 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 76 | 85 20 (GLOBAL) REPORT_ID 0x20 (32) 77 | 09 26 (LOCAL) USAGE 0xFF000026 <-- Warning: Undocumented usage (document it by inserting 0026 into file FF00.conf) 78 | 95 3F (GLOBAL) REPORT_COUNT 0x3F (63) Number of fields 79 | B1 02 (MAIN) FEATURE 0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 80 | 85 21 (GLOBAL) REPORT_ID 0x21 (33) 81 | 09 27 (LOCAL) USAGE 0xFF000027 <-- Warning: Undocumented usage (document it by inserting 0027 into file FF00.conf) 82 | 95 04 (GLOBAL) REPORT_COUNT 0x04 (4) Number of fields 83 | B1 02 (MAIN) FEATURE 0x00000002 (4 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 84 | 85 22 (GLOBAL) REPORT_ID 0x22 (34) 85 | 09 40 (LOCAL) USAGE 0xFF000040 <-- Warning: Undocumented usage (document it by inserting 0040 into file FF00.conf) 86 | 95 3F (GLOBAL) REPORT_COUNT 0x3F (63) Number of fields 87 | B1 02 (MAIN) FEATURE 0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 88 | 85 80 (GLOBAL) REPORT_ID 0x80 (128) 89 | 09 28 (LOCAL) USAGE 0xFF000028 <-- Warning: Undocumented usage (document it by inserting 0028 into file FF00.conf) 90 | 95 3F (GLOBAL) REPORT_COUNT 0x3F (63) Number of fields <-- Redundant: REPORT_COUNT is already 63 91 | B1 02 (MAIN) FEATURE 0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 92 | 85 81 (GLOBAL) REPORT_ID 0x81 (129) 93 | 09 29 (LOCAL) USAGE 0xFF000029 <-- Warning: Undocumented usage (document it by inserting 0029 into file FF00.conf) 94 | 95 3F (GLOBAL) REPORT_COUNT 0x3F (63) Number of fields <-- Redundant: REPORT_COUNT is already 63 95 | B1 02 (MAIN) FEATURE 0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 96 | 85 82 (GLOBAL) REPORT_ID 0x82 (130) 97 | 09 2A (LOCAL) USAGE 0xFF00002A <-- Warning: Undocumented usage (document it by inserting 002A into file FF00.conf) 98 | 95 09 (GLOBAL) REPORT_COUNT 0x09 (9) Number of fields 99 | B1 02 (MAIN) FEATURE 0x00000002 (9 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 100 | 85 83 (GLOBAL) REPORT_ID 0x83 (131) 101 | 09 2B (LOCAL) USAGE 0xFF00002B <-- Warning: Undocumented usage (document it by inserting 002B into file FF00.conf) 102 | 95 3F (GLOBAL) REPORT_COUNT 0x3F (63) Number of fields 103 | B1 02 (MAIN) FEATURE 0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 104 | 85 84 (GLOBAL) REPORT_ID 0x84 (132) 105 | 09 2C (LOCAL) USAGE 0xFF00002C <-- Warning: Undocumented usage (document it by inserting 002C into file FF00.conf) 106 | 95 3F (GLOBAL) REPORT_COUNT 0x3F (63) Number of fields <-- Redundant: REPORT_COUNT is already 63 107 | B1 02 (MAIN) FEATURE 0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 108 | 85 85 (GLOBAL) REPORT_ID 0x85 (133) 109 | 09 2D (LOCAL) USAGE 0xFF00002D <-- Warning: Undocumented usage (document it by inserting 002D into file FF00.conf) 110 | 95 02 (GLOBAL) REPORT_COUNT 0x02 (2) Number of fields 111 | B1 02 (MAIN) FEATURE 0x00000002 (2 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 112 | 85 A0 (GLOBAL) REPORT_ID 0xA0 (160) 113 | 09 2E (LOCAL) USAGE 0xFF00002E <-- Warning: Undocumented usage (document it by inserting 002E into file FF00.conf) 114 | 95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields 115 | B1 02 (MAIN) FEATURE 0x00000002 (1 field x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 116 | 85 E0 (GLOBAL) REPORT_ID 0xE0 (224) 117 | 09 2F (LOCAL) USAGE 0xFF00002F <-- Warning: Undocumented usage (document it by inserting 002F into file FF00.conf) 118 | 95 3F (GLOBAL) REPORT_COUNT 0x3F (63) Number of fields 119 | B1 02 (MAIN) FEATURE 0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 120 | 85 F0 (GLOBAL) REPORT_ID 0xF0 (240) 121 | 09 30 (LOCAL) USAGE 0xFF000030 <-- Warning: Undocumented usage (document it by inserting 0030 into file FF00.conf) 122 | 95 3F (GLOBAL) REPORT_COUNT 0x3F (63) Number of fields <-- Redundant: REPORT_COUNT is already 63 123 | B1 02 (MAIN) FEATURE 0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 124 | 85 F1 (GLOBAL) REPORT_ID 0xF1 (241) 125 | 09 31 (LOCAL) USAGE 0xFF000031 <-- Warning: Undocumented usage (document it by inserting 0031 into file FF00.conf) 126 | 95 3F (GLOBAL) REPORT_COUNT 0x3F (63) Number of fields <-- Redundant: REPORT_COUNT is already 63 127 | B1 02 (MAIN) FEATURE 0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 128 | 85 F2 (GLOBAL) REPORT_ID 0xF2 (242) 129 | 09 32 (LOCAL) USAGE 0xFF000032 <-- Warning: Undocumented usage (document it by inserting 0032 into file FF00.conf) 130 | 95 0F (GLOBAL) REPORT_COUNT 0x0F (15) Number of fields 131 | B1 02 (MAIN) FEATURE 0x00000002 (15 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 132 | 85 F4 (GLOBAL) REPORT_ID 0xF4 (244) 133 | 09 35 (LOCAL) USAGE 0xFF000035 <-- Warning: Undocumented usage (document it by inserting 0035 into file FF00.conf) 134 | 95 3F (GLOBAL) REPORT_COUNT 0x3F (63) Number of fields 135 | B1 02 (MAIN) FEATURE 0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 136 | 85 F5 (GLOBAL) REPORT_ID 0xF5 (245) 137 | 09 36 (LOCAL) USAGE 0xFF000036 <-- Warning: Undocumented usage (document it by inserting 0036 into file FF00.conf) 138 | 95 03 (GLOBAL) REPORT_COUNT 0x03 (3) Number of fields 139 | B1 02 (MAIN) FEATURE 0x00000002 (3 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 140 | C0 (MAIN) END_COLLECTION Application <-- Warning: Physical units are still in effect PHYSICAL(MIN=0,MAX=315) UNIT(0x00000000,EXP=0) 141 | */ 142 | 143 | //-------------------------------------------------------------------------------- 144 | // Vendor-defined featureReport 05 (Device <-> Host) 145 | //-------------------------------------------------------------------------------- 146 | 147 | typedef struct 148 | { 149 | uint8_t reportId; // Report ID = 0x05 (5) 150 | // Collection: CA:GamePad 151 | uint8_t VEN_GamePad0033[40]; // Usage 0xFF000033: , Value = 0 to 255, Physical = Value x 21 / 17 152 | } featureReport05_t; 153 | 154 | 155 | //-------------------------------------------------------------------------------- 156 | // Vendor-defined featureReport 08 (Device <-> Host) 157 | //-------------------------------------------------------------------------------- 158 | 159 | typedef struct 160 | { 161 | uint8_t reportId; // Report ID = 0x08 (8) 162 | // Collection: CA:GamePad 163 | uint8_t VEN_GamePad0034[47]; // Usage 0xFF000034: , Value = 0 to 255, Physical = Value x 21 / 17 164 | } featureReport08_t; 165 | 166 | 167 | //-------------------------------------------------------------------------------- 168 | // Vendor-defined featureReport 09 (Device <-> Host) 169 | //-------------------------------------------------------------------------------- 170 | 171 | typedef struct 172 | { 173 | uint8_t reportId; // Report ID = 0x09 (9) 174 | // Collection: CA:GamePad 175 | uint8_t VEN_GamePad0024[19]; // Usage 0xFF000024: , Value = 0 to 255, Physical = Value x 21 / 17 176 | } featureReport09_t; 177 | 178 | 179 | //-------------------------------------------------------------------------------- 180 | // Vendor-defined featureReport 0A (Device <-> Host) 181 | //-------------------------------------------------------------------------------- 182 | 183 | typedef struct 184 | { 185 | uint8_t reportId; // Report ID = 0x0A (10) 186 | // Collection: CA:GamePad 187 | uint8_t VEN_GamePad0025[26]; // Usage 0xFF000025: , Value = 0 to 255, Physical = Value x 21 / 17 188 | } featureReport0A_t; 189 | 190 | 191 | //-------------------------------------------------------------------------------- 192 | // Vendor-defined featureReport 20 (Device <-> Host) 193 | //-------------------------------------------------------------------------------- 194 | 195 | typedef struct 196 | { 197 | uint8_t reportId; // Report ID = 0x20 (32) 198 | // Collection: CA:GamePad 199 | uint8_t VEN_GamePad0026[63]; // Usage 0xFF000026: , Value = 0 to 255, Physical = Value x 21 / 17 200 | } featureReport20_t; 201 | 202 | 203 | //-------------------------------------------------------------------------------- 204 | // Vendor-defined featureReport 21 (Device <-> Host) 205 | //-------------------------------------------------------------------------------- 206 | 207 | typedef struct 208 | { 209 | uint8_t reportId; // Report ID = 0x21 (33) 210 | // Collection: CA:GamePad 211 | uint8_t VEN_GamePad0027[4]; // Usage 0xFF000027: , Value = 0 to 255, Physical = Value x 21 / 17 212 | } featureReport21_t; 213 | 214 | 215 | //-------------------------------------------------------------------------------- 216 | // Vendor-defined featureReport 22 (Device <-> Host) 217 | //-------------------------------------------------------------------------------- 218 | 219 | typedef struct 220 | { 221 | uint8_t reportId; // Report ID = 0x22 (34) 222 | // Collection: CA:GamePad 223 | uint8_t VEN_GamePad0040[63]; // Usage 0xFF000040: , Value = 0 to 255, Physical = Value x 21 / 17 224 | } featureReport22_t; 225 | 226 | 227 | //-------------------------------------------------------------------------------- 228 | // Vendor-defined featureReport 80 (Device <-> Host) 229 | //-------------------------------------------------------------------------------- 230 | 231 | typedef struct 232 | { 233 | uint8_t reportId; // Report ID = 0x80 (128) 234 | // Collection: CA:GamePad 235 | uint8_t VEN_GamePad0028[63]; // Usage 0xFF000028: , Value = 0 to 255, Physical = Value x 21 / 17 236 | } featureReport80_t; 237 | 238 | 239 | //-------------------------------------------------------------------------------- 240 | // Vendor-defined featureReport 81 (Device <-> Host) 241 | //-------------------------------------------------------------------------------- 242 | 243 | typedef struct 244 | { 245 | uint8_t reportId; // Report ID = 0x81 (129) 246 | // Collection: CA:GamePad 247 | uint8_t VEN_GamePad0029[63]; // Usage 0xFF000029: , Value = 0 to 255, Physical = Value x 21 / 17 248 | } featureReport81_t; 249 | 250 | 251 | //-------------------------------------------------------------------------------- 252 | // Vendor-defined featureReport 82 (Device <-> Host) 253 | //-------------------------------------------------------------------------------- 254 | 255 | typedef struct 256 | { 257 | uint8_t reportId; // Report ID = 0x82 (130) 258 | // Collection: CA:GamePad 259 | uint8_t VEN_GamePad002A[9]; // Usage 0xFF00002A: , Value = 0 to 255, Physical = Value x 21 / 17 260 | } featureReport82_t; 261 | 262 | 263 | //-------------------------------------------------------------------------------- 264 | // Vendor-defined featureReport 83 (Device <-> Host) 265 | //-------------------------------------------------------------------------------- 266 | 267 | typedef struct 268 | { 269 | uint8_t reportId; // Report ID = 0x83 (131) 270 | // Collection: CA:GamePad 271 | uint8_t VEN_GamePad002B[63]; // Usage 0xFF00002B: , Value = 0 to 255, Physical = Value x 21 / 17 272 | } featureReport83_t; 273 | 274 | 275 | //-------------------------------------------------------------------------------- 276 | // Vendor-defined featureReport 84 (Device <-> Host) 277 | //-------------------------------------------------------------------------------- 278 | 279 | typedef struct 280 | { 281 | uint8_t reportId; // Report ID = 0x84 (132) 282 | // Collection: CA:GamePad 283 | uint8_t VEN_GamePad002C[63]; // Usage 0xFF00002C: , Value = 0 to 255, Physical = Value x 21 / 17 284 | } featureReport84_t; 285 | 286 | 287 | //-------------------------------------------------------------------------------- 288 | // Vendor-defined featureReport 85 (Device <-> Host) 289 | //-------------------------------------------------------------------------------- 290 | 291 | typedef struct 292 | { 293 | uint8_t reportId; // Report ID = 0x85 (133) 294 | // Collection: CA:GamePad 295 | uint8_t VEN_GamePad002D[2]; // Usage 0xFF00002D: , Value = 0 to 255, Physical = Value x 21 / 17 296 | } featureReport85_t; 297 | 298 | 299 | //-------------------------------------------------------------------------------- 300 | // Vendor-defined featureReport A0 (Device <-> Host) 301 | //-------------------------------------------------------------------------------- 302 | 303 | typedef struct 304 | { 305 | uint8_t reportId; // Report ID = 0xA0 (160) 306 | // Collection: CA:GamePad 307 | uint8_t VEN_GamePad002E; // Usage 0xFF00002E: , Value = 0 to 255, Physical = Value x 21 / 17 308 | } featureReportA0_t; 309 | 310 | 311 | //-------------------------------------------------------------------------------- 312 | // Vendor-defined featureReport E0 (Device <-> Host) 313 | //-------------------------------------------------------------------------------- 314 | 315 | typedef struct 316 | { 317 | uint8_t reportId; // Report ID = 0xE0 (224) 318 | // Collection: CA:GamePad 319 | uint8_t VEN_GamePad002F[63]; // Usage 0xFF00002F: , Value = 0 to 255, Physical = Value x 21 / 17 320 | } featureReportE0_t; 321 | 322 | 323 | //-------------------------------------------------------------------------------- 324 | // Vendor-defined featureReport F0 (Device <-> Host) 325 | //-------------------------------------------------------------------------------- 326 | 327 | typedef struct 328 | { 329 | uint8_t reportId; // Report ID = 0xF0 (240) 330 | // Collection: CA:GamePad 331 | uint8_t VEN_GamePad0030[63]; // Usage 0xFF000030: , Value = 0 to 255, Physical = Value x 21 / 17 332 | } featureReportF0_t; 333 | 334 | 335 | //-------------------------------------------------------------------------------- 336 | // Vendor-defined featureReport F1 (Device <-> Host) 337 | //-------------------------------------------------------------------------------- 338 | 339 | typedef struct 340 | { 341 | uint8_t reportId; // Report ID = 0xF1 (241) 342 | // Collection: CA:GamePad 343 | uint8_t VEN_GamePad0031[63]; // Usage 0xFF000031: , Value = 0 to 255, Physical = Value x 21 / 17 344 | } featureReportF1_t; 345 | 346 | 347 | //-------------------------------------------------------------------------------- 348 | // Vendor-defined featureReport F2 (Device <-> Host) 349 | //-------------------------------------------------------------------------------- 350 | 351 | typedef struct 352 | { 353 | uint8_t reportId; // Report ID = 0xF2 (242) 354 | // Collection: CA:GamePad 355 | uint8_t VEN_GamePad0032[15]; // Usage 0xFF000032: , Value = 0 to 255, Physical = Value x 21 / 17 356 | } featureReportF2_t; 357 | 358 | 359 | //-------------------------------------------------------------------------------- 360 | // Vendor-defined featureReport F4 (Device <-> Host) 361 | //-------------------------------------------------------------------------------- 362 | 363 | typedef struct 364 | { 365 | uint8_t reportId; // Report ID = 0xF4 (244) 366 | // Collection: CA:GamePad 367 | uint8_t VEN_GamePad0035[63]; // Usage 0xFF000035: , Value = 0 to 255, Physical = Value x 21 / 17 368 | } featureReportF4_t; 369 | 370 | 371 | //-------------------------------------------------------------------------------- 372 | // Vendor-defined featureReport F5 (Device <-> Host) 373 | //-------------------------------------------------------------------------------- 374 | 375 | typedef struct 376 | { 377 | uint8_t reportId; // Report ID = 0xF5 (245) 378 | // Collection: CA:GamePad 379 | uint8_t VEN_GamePad0036[3]; // Usage 0xFF000036: , Value = 0 to 255, Physical = Value x 21 / 17 380 | } featureReportF5_t; 381 | 382 | 383 | //-------------------------------------------------------------------------------- 384 | // Generic Desktop Page inputReport 01 (Device --> Host) 385 | //-------------------------------------------------------------------------------- 386 | 387 | typedef struct 388 | { 389 | uint8_t reportId; // Report ID = 0x01 (1) 390 | // Collection: CA:GamePad 391 | uint8_t GD_GamePadX; // Usage 0x00010030: X, Value = 0 to 255 392 | uint8_t GD_GamePadY; // Usage 0x00010031: Y, Value = 0 to 255 393 | uint8_t GD_GamePadZ; // Usage 0x00010032: Z, Value = 0 to 255 394 | uint8_t GD_GamePadRz; // Usage 0x00010035: Rz, Value = 0 to 255 395 | uint8_t GD_GamePadRx; // Usage 0x00010033: Rx, Value = 0 to 255 396 | uint8_t GD_GamePadRy; // Usage 0x00010034: Ry, Value = 0 to 255 397 | uint8_t VEN_GamePad0020; // Usage 0xFF000020: , Value = 0 to 255 398 | uint8_t GD_GamePadHatSwitch : 4; // Usage 0x00010039: Hat switch, Value = 0 to 7, Physical = Value x 45 in degrees 399 | uint8_t BTN_GamePadButton1 : 1; // Usage 0x00090001: Button 1 Primary/trigger, Value = 0 to 1, Physical = Value x 315 400 | uint8_t BTN_GamePadButton2 : 1; // Usage 0x00090002: Button 2 Secondary, Value = 0 to 1, Physical = Value x 315 401 | uint8_t BTN_GamePadButton3 : 1; // Usage 0x00090003: Button 3 Tertiary, Value = 0 to 1, Physical = Value x 315 402 | uint8_t BTN_GamePadButton4 : 1; // Usage 0x00090004: Button 4, Value = 0 to 1, Physical = Value x 315 403 | uint8_t BTN_GamePadButton5 : 1; // Usage 0x00090005: Button 5, Value = 0 to 1, Physical = Value x 315 404 | uint8_t BTN_GamePadButton6 : 1; // Usage 0x00090006: Button 6, Value = 0 to 1, Physical = Value x 315 405 | uint8_t BTN_GamePadButton7 : 1; // Usage 0x00090007: Button 7, Value = 0 to 1, Physical = Value x 315 406 | uint8_t BTN_GamePadButton8 : 1; // Usage 0x00090008: Button 8, Value = 0 to 1, Physical = Value x 315 407 | uint8_t BTN_GamePadButton9 : 1; // Usage 0x00090009: Button 9, Value = 0 to 1, Physical = Value x 315 408 | uint8_t BTN_GamePadButton10 : 1; // Usage 0x0009000A: Button 10, Value = 0 to 1, Physical = Value x 315 409 | uint8_t BTN_GamePadButton11 : 1; // Usage 0x0009000B: Button 11, Value = 0 to 1, Physical = Value x 315 410 | uint8_t BTN_GamePadButton12 : 1; // Usage 0x0009000C: Button 12, Value = 0 to 1, Physical = Value x 315 411 | uint8_t BTN_GamePadButton13 : 1; // Usage 0x0009000D: Button 13, Value = 0 to 1, Physical = Value x 315 412 | uint8_t BTN_GamePadButton14 : 1; // Usage 0x0009000E: Button 14, Value = 0 to 1, Physical = Value x 315 413 | uint8_t BTN_GamePadButton15 : 1; // Usage 0x0009000F: Button 15, Value = 0 to 1, Physical = Value x 315 414 | uint8_t VEN_GamePad0021 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 415 | uint8_t VEN_GamePad00211 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 416 | uint8_t VEN_GamePad00212 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 417 | uint8_t VEN_GamePad00213 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 418 | uint8_t VEN_GamePad00214 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 419 | uint8_t VEN_GamePad00215 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 420 | uint8_t VEN_GamePad00216 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 421 | uint8_t VEN_GamePad00217 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 422 | uint8_t VEN_GamePad00218 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 423 | uint8_t VEN_GamePad00219 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 424 | uint8_t VEN_GamePad002110 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 425 | uint8_t VEN_GamePad002111 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 426 | uint8_t VEN_GamePad002112 : 1; // Usage 0xFF000021: , Value = 0 to 1, Physical = Value x 315 427 | uint8_t VEN_GamePad0022[52]; // Usage 0xFF000022: , Value = 0 to 255, Physical = Value x 21 / 17 428 | } inputReport01_t; 429 | 430 | 431 | //-------------------------------------------------------------------------------- 432 | // Vendor-defined outputReport 02 (Device <-- Host) 433 | //-------------------------------------------------------------------------------- 434 | 435 | typedef struct 436 | { 437 | uint8_t reportId; // Report ID = 0x02 (2) 438 | // Collection: CA:GamePad 439 | uint8_t VEN_GamePad0023[47]; // Usage 0xFF000023: , Value = 0 to 255, Physical = Value x 21 / 17 440 | } outputReport02_t; 441 | 442 | --------------------------------------------------------------------------------