├── .gitignore ├── vixen.yml ├── src ├── controllers │ ├── utils │ │ └── bit.h │ ├── xbox_controller.h │ ├── xbox_360_controller.h │ ├── dinput_controller.h │ ├── ds3_controller.h │ ├── xbox_360w_controller.h │ ├── xbox_360_report.h │ ├── ds3_report.h │ ├── dinput │ │ ├── neogeox.h │ │ ├── logitech_wingman.h │ │ ├── sfcconverter.h │ │ ├── dpad_angle.h │ │ ├── horidiva.h │ │ ├── horidiva_ps4.h │ │ ├── mayflash.h │ │ ├── logitech.h │ │ ├── p3converter.h │ │ ├── p2top3converter.h │ │ ├── psclassic.h │ │ ├── smartjoypad.h │ │ └── raphnetpsx.h │ ├── xbox_controller.c │ ├── dinput_controller.c │ ├── xbox_360_controller.c │ ├── xbox_360w_controller.c │ └── ds3_controller.c ├── devicelist.h ├── controller.h ├── controller.c ├── devicelist.c └── main.c ├── LICENSE.md ├── .clang-format ├── CMakeLists.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /vixen.yml: -------------------------------------------------------------------------------- 1 | vixen: 2 | attributes: 0 3 | version: 4 | major: 1 5 | minor: 0 6 | main: 7 | start: module_start 8 | stop: module_stop 9 | -------------------------------------------------------------------------------- /src/controllers/utils/bit.h: -------------------------------------------------------------------------------- 1 | #ifndef __BIT_H__ 2 | #define __BIT_H__ 3 | 4 | static inline uint8_t bit(uint8_t *data, int bit) 5 | { 6 | return (*data >> bit) & 1; 7 | } 8 | 9 | #endif -------------------------------------------------------------------------------- /src/controllers/xbox_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef __XBOX_CONTROLLER_H__ 2 | #define __XBOX_CONTROLLER_H__ 3 | 4 | #include "../controller.h" 5 | 6 | uint8_t XboxController_probe(Controller *c, int device_id, int port); 7 | uint8_t XboxController_processReport(Controller *c, size_t length); 8 | void XboxController_setRumble(Controller *c, uint8_t small, uint8_t large); 9 | 10 | #endif // __XBOX_CONTROLLER_H__ 11 | -------------------------------------------------------------------------------- /src/controllers/xbox_360_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef __XBOX_360_CONTROLLER_H__ 2 | #define __XBOX_360_CONTROLLER_H__ 3 | 4 | #include "../controller.h" 5 | 6 | uint8_t Xbox360Controller_probe(Controller *c, int device_id, int port); 7 | uint8_t Xbox360Controller_processReport(Controller *c, size_t length); 8 | void Xbox360Controller_setRumble(Controller *c, uint8_t small, uint8_t large); 9 | 10 | #endif // __XBOX_360_CONTROLLER_H__ 11 | -------------------------------------------------------------------------------- /src/controllers/dinput_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_CONTROLLER_H__ 2 | #define __DINPUT_CONTROLLER_H__ 3 | 4 | #include "../controller.h" 5 | 6 | uint8_t DinputController_probe(Controller *c, int device_id, int port, int vendor, int product); 7 | uint8_t DinputController_processReport(Controller *c, size_t length); 8 | void DinputController_setRumble(Controller *c, uint8_t small, uint8_t large); 9 | 10 | #endif // __DINPUT_CONTROLLER_H__ 11 | -------------------------------------------------------------------------------- /src/controllers/ds3_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef __DS3_CONTROLLER_H__ 2 | #define __DS3_CONTROLLER_H__ 3 | 4 | #include "../controller.h" 5 | 6 | uint8_t DS3Controller_probe(Controller *c, int device_id, int port); 7 | uint8_t DS3Controller_processReport(Controller *c, size_t length); 8 | void DS3Controller_setRumble(Controller *c, uint8_t small, uint8_t large); 9 | void DS3Controller_setLed(Controller *c, uint8_t led); 10 | 11 | #endif // __DS3_CONTROLLER_H__ 12 | -------------------------------------------------------------------------------- /src/devicelist.h: -------------------------------------------------------------------------------- 1 | #ifndef __DEVICELIST_H__ 2 | #define __DEVICELIST_H__ 3 | 4 | #include 5 | 6 | typedef enum 7 | { 8 | PAD_UNKNOWN, 9 | PAD_XBOX, 10 | PAD_XBOX360, 11 | PAD_XBOX360W, 12 | PAD_DS3, 13 | PAD_DINPUT, 14 | } vixenPadType; 15 | 16 | typedef struct 17 | { 18 | vixenPadType type; 19 | uint16_t idVendor; 20 | uint16_t idProduct; 21 | } gamepad_t; 22 | 23 | extern gamepad_t _devices[]; 24 | 25 | #endif // __DEVICELIST_H__ 26 | -------------------------------------------------------------------------------- /src/controllers/xbox_360w_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef __XBOX_360W_CONTROLLER_H__ 2 | #define __XBOX_360W_CONTROLLER_H__ 3 | 4 | #include "../controller.h" 5 | 6 | uint8_t Xbox360WController_probe(Controller *c, int device_id, int port); 7 | uint8_t Xbox360WController_processReport(Controller *c, size_t length); 8 | void Xbox360WController_setLed(Controller *c, uint8_t led); 9 | void Xbox360WController_setRumble(Controller *c, uint8_t small, uint8_t large); 10 | void Xbox360WController_turnOff(Controller *c); 11 | 12 | #endif // __XBOX_360W_CONTROLLER_H__ 13 | -------------------------------------------------------------------------------- /src/controllers/xbox_360_report.h: -------------------------------------------------------------------------------- 1 | #ifndef __XBOX_360_REPORT_H__ 2 | #define __XBOX_360_REPORT_H__ 3 | 4 | #include 5 | 6 | typedef struct 7 | { 8 | uint8_t dpad_up : 1; 9 | uint8_t dpad_down : 1; 10 | uint8_t dpad_left : 1; 11 | uint8_t dpad_right : 1; 12 | 13 | uint8_t start : 1; 14 | uint8_t back : 1; 15 | 16 | uint8_t thumb_l : 1; 17 | uint8_t thumb_r : 1; 18 | 19 | uint8_t lb : 1; 20 | uint8_t rb : 1; 21 | uint8_t guide : 1; 22 | 23 | uint8_t a : 1; 24 | uint8_t b : 1; 25 | uint8_t x : 1; 26 | uint8_t y : 1; 27 | 28 | uint8_t lt : 8; 29 | uint8_t rt : 8; 30 | 31 | uint16_t x1 : 16; 32 | uint16_t y1 : 16; 33 | 34 | uint16_t x2 : 16; 35 | uint16_t y2 : 16; 36 | } Xbox360Report; 37 | 38 | #endif // __XBOX_360_REPORT_H__ 39 | -------------------------------------------------------------------------------- /src/controllers/ds3_report.h: -------------------------------------------------------------------------------- 1 | #ifndef __DS3_REPORT_H__ 2 | #define __DS3_REPORT_H__ 3 | 4 | #include 5 | 6 | typedef struct 7 | { 8 | uint8_t dpad_up : 1; 9 | uint8_t dpad_down : 1; 10 | uint8_t dpad_left : 1; 11 | uint8_t dpad_right : 1; 12 | 13 | uint8_t start : 1; 14 | uint8_t select : 1; 15 | 16 | uint8_t l3 : 1; 17 | uint8_t r3 : 1; 18 | 19 | uint8_t l1 : 1; 20 | uint8_t r1 : 1; 21 | uint8_t ps : 1; 22 | 23 | uint8_t cross : 1; 24 | uint8_t circle : 1; 25 | uint8_t square : 1; 26 | uint8_t triangle : 1; 27 | 28 | uint8_t l2 : 8; 29 | uint8_t r2 : 8; 30 | 31 | uint8_t l2a : 8; 32 | uint8_t r2a : 8; 33 | 34 | int16_t x1 : 16; 35 | int16_t y1 : 16; 36 | 37 | int16_t x2 : 16; 38 | int16_t y2 : 16; 39 | 40 | } DS3Report; 41 | 42 | #endif // __DS3_REPORT_H__ 43 | -------------------------------------------------------------------------------- /src/controllers/dinput/neogeox.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_NEOGEOX_H__ 2 | #define __DINPUT_NEOGEOX_H__ 3 | #include 4 | #include "dpad_angle.h" 5 | 6 | uint8_t neogeox_processReport(Controller *c, size_t length) 7 | { 8 | process_dpad_angle(c, 2); 9 | 10 | if (bit(c->buffer, 0)) 11 | c->controlData.buttons |= SCE_CTRL_CROSS; 12 | if (bit(c->buffer, 1)) 13 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 14 | if (bit(c->buffer, 2)) 15 | c->controlData.buttons |= SCE_CTRL_SQUARE; 16 | if (bit(c->buffer, 3)) 17 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 18 | 19 | 20 | if (bit(c->buffer + 1, 0)) 21 | c->controlData.buttons |= SCE_CTRL_SELECT; 22 | if (bit(c->buffer + 1, 1)) 23 | c->controlData.buttons |= SCE_CTRL_START; 24 | 25 | return 1; 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/controllers/dinput/logitech_wingman.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_LOGITECH_WINGMAN_H__ 2 | #define __DINPUT_LOGITECH_WINGMAN_H__ 3 | #include 4 | 5 | uint8_t logitechWingman_processReport(Controller *c, size_t length) 6 | { 7 | if (c->buffer[2] == 0x01) 8 | c->controlData.buttons |= SCE_CTRL_UP; 9 | if (c->buffer[2] == 0xFE) 10 | c->controlData.buttons |= SCE_CTRL_DOWN; 11 | 12 | if (c->buffer[1] == 0x01) 13 | c->controlData.buttons |= SCE_CTRL_LEFT; 14 | if (c->buffer[1] == 0xFE) 15 | c->controlData.buttons |= SCE_CTRL_RIGHT; 16 | 17 | if (bit(c->buffer, 0)) 18 | c->controlData.buttons |= SCE_CTRL_CROSS; 19 | if (bit(c->buffer, 1)) 20 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 21 | if (bit(c->buffer, 2)) 22 | c->controlData.buttons |= SCE_CTRL_SQUARE; 23 | if (bit(c->buffer, 3)) 24 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 25 | 26 | return 1; 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2022 Cat (Epifanov Ivan) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/controller.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONTROLLER_H__ 2 | #define __CONTROLLER_H__ 3 | 4 | #include "devicelist.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | typedef struct 12 | { 13 | uint32_t buttons; 14 | uint8_t leftX; 15 | uint8_t leftY; 16 | uint8_t rightX; 17 | uint8_t rightY; 18 | uint8_t lt; 19 | uint8_t rt; 20 | } ControlData; 21 | 22 | typedef struct 23 | { 24 | uint8_t type; 25 | uint8_t attached; // actual gamepad attached 26 | uint8_t inited; // usb device attached and inited 27 | uint8_t battery_level; 28 | ControlData controlData; 29 | int device_id; 30 | uint8_t port; 31 | SceUID pipe_in; 32 | SceUID pipe_out; 33 | SceUID pipe_control; 34 | unsigned char buffer[64] __attribute__((aligned(64))); 35 | size_t buffer_size; 36 | int vendor; 37 | int product; 38 | 39 | } Controller; 40 | 41 | void usb_read(Controller *c); 42 | void usb_write(Controller *c, uint8_t *data, int len); 43 | 44 | #endif // __CONTROLLER_H__ 45 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Webkit 3 | --- 4 | Language: Cpp 5 | PointerAlignment: Right 6 | BreakBeforeBraces: Allman 7 | AllowShortBlocksOnASingleLine: false 8 | AllowShortFunctionsOnASingleLine: Empty 9 | Cpp11BracedListStyle: true 10 | Standard: Cpp11 11 | ColumnLimit: 120 12 | IndentWidth: 2 13 | AccessModifierOffset: -2 14 | FixNamespaceComments: true 15 | NamespaceIndentation: None 16 | IncludeBlocks: Regroup 17 | IndentCaseLabels: true 18 | MaxEmptyLinesToKeep: 1 19 | UseTab: Never 20 | AlignAfterOpenBracket: Align 21 | AlignConsecutiveAssignments: true 22 | AlignOperands: true 23 | AlignTrailingComments: true 24 | AllowShortCaseLabelsOnASingleLine: false 25 | AllowShortIfStatementsOnASingleLine: false 26 | AllowShortLoopsOnASingleLine: false 27 | CommentPragmas: '^ NOLINT' 28 | --- 29 | -------------------------------------------------------------------------------- /src/controllers/dinput/sfcconverter.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_SFCCONVERTER_H__ 2 | #define __DINPUT_SFCCONVERTER_H__ 3 | #include 4 | #include "dpad_angle.h" 5 | 6 | uint8_t sfcconverter_processReport(Controller *c, size_t length) 7 | { 8 | process_dpad_angle(c, 2); 9 | 10 | if (bit(c->buffer, 0)) 11 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 12 | if (bit(c->buffer, 1)) 13 | c->controlData.buttons |= SCE_CTRL_CROSS; 14 | if (bit(c->buffer, 2)) 15 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 16 | if (bit(c->buffer, 3)) 17 | c->controlData.buttons |= SCE_CTRL_SQUARE; 18 | 19 | if (bit(c->buffer, 4)) 20 | c->controlData.buttons |= SCE_CTRL_L1; 21 | if (bit(c->buffer, 5)) 22 | c->controlData.buttons |= SCE_CTRL_R1; 23 | 24 | if (bit(c->buffer, 6)) 25 | c->controlData.buttons |= SCE_CTRL_SELECT; 26 | if (bit(c->buffer, 7)) 27 | c->controlData.buttons |= SCE_CTRL_START; 28 | 29 | if (bit(c->buffer, 4) && bit(c->buffer, 5) && bit(c->buffer, 7)) // L+R+START combo 30 | { 31 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 32 | c->controlData.buttons &= ~SCE_CTRL_START; 33 | } 34 | 35 | return 1; 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/controllers/dinput/dpad_angle.h: -------------------------------------------------------------------------------- 1 | #ifndef __DPAD_ANGLE_H__ 2 | #define __DPAD_ANGLE_H__ 3 | 4 | static inline void process_dpad_angle(Controller *c, int idx) 5 | { 6 | uint8_t dpad = c->buffer[idx] & 0x0F; 7 | switch (dpad) 8 | { 9 | case 0x0: 10 | c->controlData.buttons |= SCE_CTRL_UP; 11 | break; 12 | case 0x1: 13 | c->controlData.buttons |= SCE_CTRL_UP; 14 | c->controlData.buttons |= SCE_CTRL_RIGHT; 15 | break; 16 | case 0x2: 17 | c->controlData.buttons |= SCE_CTRL_RIGHT; 18 | break; 19 | case 0x3: 20 | c->controlData.buttons |= SCE_CTRL_RIGHT; 21 | c->controlData.buttons |= SCE_CTRL_DOWN; 22 | break; 23 | case 0x4: 24 | c->controlData.buttons |= SCE_CTRL_DOWN; 25 | break; 26 | case 0x5: 27 | c->controlData.buttons |= SCE_CTRL_DOWN; 28 | c->controlData.buttons |= SCE_CTRL_LEFT; 29 | break; 30 | case 0x6: 31 | c->controlData.buttons |= SCE_CTRL_LEFT; 32 | break; 33 | case 0x7: 34 | c->controlData.buttons |= SCE_CTRL_LEFT; 35 | c->controlData.buttons |= SCE_CTRL_UP; 36 | break; 37 | case 0x8: 38 | default: 39 | break; 40 | } 41 | } 42 | 43 | #endif -------------------------------------------------------------------------------- /src/controllers/dinput/horidiva.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_HORIDIVA_H__ 2 | #define __DINPUT_HORIDIVA_H__ 3 | #include 4 | #include "dpad_angle.h" 5 | 6 | uint8_t horiDiva_processReport(Controller *c, size_t length) 7 | { 8 | process_dpad_angle(c, 2); 9 | 10 | if (bit(c->buffer, 3)) 11 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 12 | if (bit(c->buffer, 2)) 13 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 14 | if (bit(c->buffer, 1)) 15 | c->controlData.buttons |= SCE_CTRL_CROSS; 16 | if (bit(c->buffer, 0)) 17 | c->controlData.buttons |= SCE_CTRL_SQUARE; 18 | 19 | if (bit(c->buffer, 4)) 20 | c->controlData.buttons |= SCE_CTRL_L1; 21 | if (bit(c->buffer, 5)) 22 | c->controlData.buttons |= SCE_CTRL_R1; 23 | 24 | if (bit(c->buffer + 1, 2)) 25 | c->controlData.buttons |= SCE_CTRL_L3; 26 | if (bit(c->buffer + 1, 3)) 27 | c->controlData.buttons |= SCE_CTRL_R3; 28 | 29 | if (bit(c->buffer, 6)) 30 | { 31 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 32 | c->controlData.lt = 0xFF; 33 | } 34 | 35 | if (bit(c->buffer, 7)) 36 | { 37 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 38 | c->controlData.rt = 0xFF; 39 | } 40 | 41 | if (bit(c->buffer + 1, 1)) 42 | c->controlData.buttons |= SCE_CTRL_START; 43 | if (bit(c->buffer + 1, 0)) 44 | c->controlData.buttons |= SCE_CTRL_SELECT; 45 | 46 | if (bit(c->buffer + 1, 4)) 47 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 48 | 49 | c->controlData.leftX = c->buffer[3]; 50 | c->controlData.leftY = c->buffer[4]; 51 | 52 | c->controlData.rightX = c->buffer[5]; 53 | c->controlData.rightY = c->buffer[6]; 54 | 55 | return 1; 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/controllers/dinput/horidiva_ps4.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_HORIDIVAPS4_H__ 2 | #define __DINPUT_HORIDIVAPS4_H__ 3 | #include 4 | #include "dpad_angle.h" 5 | 6 | uint8_t horiDivaps4_processReport(Controller *c, size_t length) 7 | { 8 | process_dpad_angle(c, 5); 9 | 10 | if (bit(c->buffer+5, 7)) 11 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 12 | if (bit(c->buffer+5, 6)) 13 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 14 | if (bit(c->buffer+5, 5)) 15 | c->controlData.buttons |= SCE_CTRL_CROSS; 16 | if (bit(c->buffer+5, 4)) 17 | c->controlData.buttons |= SCE_CTRL_SQUARE; 18 | 19 | if (bit(c->buffer+6, 0)) 20 | c->controlData.buttons |= SCE_CTRL_L1; 21 | if (bit(c->buffer+6, 1)) 22 | c->controlData.buttons |= SCE_CTRL_R1; 23 | 24 | if (bit(c->buffer + 6, 6)) 25 | c->controlData.buttons |= SCE_CTRL_L3; 26 | if (bit(c->buffer + 6, 7)) 27 | c->controlData.buttons |= SCE_CTRL_R3; 28 | 29 | if (bit(c->buffer+6, 2)) 30 | { 31 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 32 | c->controlData.lt = c->buffer[8]; 33 | } 34 | 35 | if (bit(c->buffer+6, 3)) 36 | { 37 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 38 | c->controlData.rt = c->buffer[9]; 39 | } 40 | 41 | if (bit(c->buffer + 6, 5)) 42 | c->controlData.buttons |= SCE_CTRL_START; 43 | if (bit(c->buffer + 6, 4)) 44 | c->controlData.buttons |= SCE_CTRL_SELECT; 45 | 46 | if (bit(c->buffer + 7, 0)) 47 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 48 | 49 | c->controlData.leftX = c->buffer[1]; 50 | c->controlData.leftY = c->buffer[2]; 51 | 52 | c->controlData.rightX = c->buffer[3]; 53 | c->controlData.rightY = c->buffer[4]; 54 | 55 | return 1; 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/controllers/dinput/mayflash.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_MAYFLASH_H__ 2 | #define __DINPUT_MAYFLASH_H__ 3 | #include 4 | #include "dpad_angle.h" 5 | 6 | uint8_t mayflash_processReport(Controller *c, size_t length) 7 | { 8 | process_dpad_angle(c, 2); 9 | 10 | if (bit(c->buffer, 0)) 11 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 12 | if (bit(c->buffer, 1)) 13 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 14 | if (bit(c->buffer, 2)) 15 | c->controlData.buttons |= SCE_CTRL_CROSS; 16 | if (bit(c->buffer, 3)) 17 | c->controlData.buttons |= SCE_CTRL_SQUARE; 18 | 19 | if (bit(c->buffer, 5)) 20 | c->controlData.buttons |= SCE_CTRL_L1; 21 | if (bit(c->buffer, 7)) 22 | c->controlData.buttons |= SCE_CTRL_R1; 23 | 24 | if (bit(c->buffer, 4)) 25 | { 26 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 27 | c->controlData.lt = 0xFF; 28 | } 29 | 30 | if (bit(c->buffer, 6)) 31 | { 32 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 33 | c->controlData.rt = 0xFF; 34 | } 35 | 36 | if (bit(c->buffer + 1, 2)) 37 | c->controlData.buttons |= SCE_CTRL_L3; 38 | if (bit(c->buffer + 1, 3)) 39 | c->controlData.buttons |= SCE_CTRL_R3; 40 | 41 | 42 | if (bit(c->buffer + 1, 0)) 43 | c->controlData.buttons |= SCE_CTRL_START; 44 | if (bit(c->buffer + 1, 1)) 45 | c->controlData.buttons |= SCE_CTRL_SELECT; 46 | 47 | if (bit(c->buffer, 5) && bit(c->buffer, 7) && bit(c->buffer + 1, 0)) // L+R+START combo 48 | { 49 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 50 | c->controlData.buttons &= ~SCE_CTRL_START; 51 | } 52 | 53 | c->controlData.leftX = c->buffer[3]; 54 | c->controlData.leftY = c->buffer[4]; 55 | c->controlData.rightX = c->buffer[5]; 56 | c->controlData.rightY = c->buffer[6]; 57 | 58 | return 1; 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/controllers/dinput/logitech.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_LOGITECH_H__ 2 | #define __DINPUT_LOGITECH_H__ 3 | #include 4 | #include "dpad_angle.h" 5 | 6 | uint8_t logitech_processReport(Controller *c, size_t length) 7 | { 8 | process_dpad_angle(c, 4); 9 | 10 | if (bit(c->buffer + 4, 5)) 11 | c->controlData.buttons |= SCE_CTRL_CROSS; 12 | if (bit(c->buffer + 4, 6)) 13 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 14 | if (bit(c->buffer + 4, 7)) 15 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 16 | if (bit(c->buffer + 4, 4)) 17 | c->controlData.buttons |= SCE_CTRL_SQUARE; 18 | 19 | if (bit(c->buffer + 5, 0)) 20 | c->controlData.buttons |= SCE_CTRL_L1; 21 | if (bit(c->buffer + 5, 1)) 22 | c->controlData.buttons |= SCE_CTRL_R1; 23 | if (bit(c->buffer + 5, 6)) 24 | c->controlData.buttons |= SCE_CTRL_L3; 25 | if (bit(c->buffer + 5, 7)) 26 | c->controlData.buttons |= SCE_CTRL_R3; 27 | 28 | if (bit(c->buffer + 5, 2)) 29 | { 30 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 31 | c->controlData.lt = 0xFF; 32 | } 33 | 34 | if (bit(c->buffer + 5, 3)) 35 | { 36 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 37 | c->controlData.rt = 0xFF; 38 | } 39 | 40 | if (bit(c->buffer + 5, 5)) 41 | c->controlData.buttons |= SCE_CTRL_START; 42 | if (bit(c->buffer + 5, 4)) 43 | c->controlData.buttons |= SCE_CTRL_SELECT; 44 | 45 | if (bit(c->buffer + 5, 0) && bit(c->buffer + 5, 1) && bit(c->buffer + 5, 5)) // L+R+START combo 46 | { 47 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 48 | c->controlData.buttons &= ~SCE_CTRL_START; 49 | } 50 | 51 | c->controlData.leftX = c->buffer[0]; 52 | c->controlData.leftY = c->buffer[1]; 53 | c->controlData.rightX = c->buffer[2]; 54 | c->controlData.rightY = c->buffer[3]; 55 | return 1; 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/controllers/dinput/p3converter.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_P3CONVERTER_H__ 2 | #define __DINPUT_P3CONVERTER_H__ 3 | #include 4 | #include "dpad_angle.h" 5 | 6 | uint8_t p3converter_processReport(Controller *c, size_t length) 7 | { 8 | process_dpad_angle(c, 5); 9 | 10 | if (bit(c->buffer + 5, 6)) 11 | c->controlData.buttons |= SCE_CTRL_CROSS; 12 | if (bit(c->buffer + 5, 5)) 13 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 14 | if (bit(c->buffer + 5, 4)) 15 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 16 | if (bit(c->buffer + 5, 7)) 17 | c->controlData.buttons |= SCE_CTRL_SQUARE; 18 | 19 | 20 | 21 | if (bit(c->buffer + 6, 2)) 22 | c->controlData.buttons |= SCE_CTRL_L1; 23 | if (bit(c->buffer + 6, 3)) 24 | c->controlData.buttons |= SCE_CTRL_R1; 25 | if (bit(c->buffer + 6, 6)) 26 | c->controlData.buttons |= SCE_CTRL_L3; 27 | if (bit(c->buffer + 6, 7)) 28 | c->controlData.buttons |= SCE_CTRL_R3; 29 | 30 | if (bit(c->buffer + 6, 0)) 31 | { 32 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 33 | c->controlData.lt = 0xFF; 34 | } 35 | 36 | if (bit(c->buffer + 6, 1)) 37 | { 38 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 39 | c->controlData.rt = 0xFF; 40 | } 41 | 42 | if (bit(c->buffer + 6, 5)) 43 | c->controlData.buttons |= SCE_CTRL_START; 44 | if (bit(c->buffer + 6, 4)) 45 | c->controlData.buttons |= SCE_CTRL_SELECT; 46 | 47 | if (bit(c->buffer + 6, 2) && bit(c->buffer + 6, 3) && bit(c->buffer + 6, 5)) // L+R+START combo 48 | { 49 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 50 | c->controlData.buttons &= ~SCE_CTRL_START; 51 | } 52 | 53 | c->controlData.leftX = c->buffer[2]; 54 | c->controlData.leftY = c->buffer[3]; 55 | c->controlData.rightX = c->buffer[1]; 56 | c->controlData.rightY = c->buffer[0]; 57 | return 1; 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/controllers/dinput/p2top3converter.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_P2TOP3CONVERTER_H__ 2 | #define __DINPUT_P2TOP3CONVERTER_H__ 3 | #include 4 | #include "dpad_angle.h" 5 | 6 | uint8_t p2top3converter_processReport(Controller *c, size_t length) 7 | { 8 | process_dpad_angle(c, 5); 9 | 10 | if (bit(c->buffer + 5, 6)) 11 | c->controlData.buttons |= SCE_CTRL_CROSS; 12 | if (bit(c->buffer + 5, 5)) 13 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 14 | if (bit(c->buffer + 5, 4)) 15 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 16 | if (bit(c->buffer + 5, 7)) 17 | c->controlData.buttons |= SCE_CTRL_SQUARE; 18 | 19 | 20 | 21 | if (bit(c->buffer + 6, 2)) 22 | c->controlData.buttons |= SCE_CTRL_L1; 23 | if (bit(c->buffer + 6, 3)) 24 | c->controlData.buttons |= SCE_CTRL_R1; 25 | if (bit(c->buffer + 6, 6)) 26 | c->controlData.buttons |= SCE_CTRL_L3; 27 | if (bit(c->buffer + 6, 7)) 28 | c->controlData.buttons |= SCE_CTRL_R3; 29 | 30 | if (bit(c->buffer + 6, 0)) 31 | { 32 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 33 | c->controlData.lt = 0xFF; 34 | } 35 | 36 | if (bit(c->buffer + 6, 1)) 37 | { 38 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 39 | c->controlData.rt = 0xFF; 40 | } 41 | 42 | if (bit(c->buffer + 6, 5)) 43 | c->controlData.buttons |= SCE_CTRL_START; 44 | if (bit(c->buffer + 6, 4)) 45 | c->controlData.buttons |= SCE_CTRL_SELECT; 46 | 47 | if (bit(c->buffer + 6, 2) && bit(c->buffer + 6, 3) && bit(c->buffer + 6, 5)) // L+R+START combo 48 | { 49 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 50 | c->controlData.buttons &= ~SCE_CTRL_START; 51 | } 52 | 53 | c->controlData.leftX = c->buffer[3]; 54 | c->controlData.leftY = c->buffer[4]; 55 | c->controlData.rightX = c->buffer[2]; 56 | c->controlData.rightY = c->buffer[1]; 57 | 58 | return 1; 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/controllers/dinput/psclassic.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_PSCLASSIC_H__ 2 | #define __DINPUT_PSCLASSIC_H__ 3 | #include 4 | 5 | uint8_t psclassic_processReport(Controller *c, size_t length) 6 | { 7 | uint8_t dpadx = (c->buffer[1] >> 2) & 0x03; 8 | uint8_t dpady = (c->buffer[1] >> 4) & 0x03; 9 | 10 | switch (dpadx) 11 | { 12 | case 0x0: 13 | c->controlData.buttons |= SCE_CTRL_LEFT; 14 | break; 15 | case 0x2: 16 | c->controlData.buttons |= SCE_CTRL_RIGHT; 17 | break; 18 | case 0x1: 19 | default: 20 | break; 21 | } 22 | 23 | switch (dpady) 24 | { 25 | case 0x0: 26 | c->controlData.buttons |= SCE_CTRL_UP; 27 | break; 28 | case 0x2: 29 | c->controlData.buttons |= SCE_CTRL_DOWN; 30 | break; 31 | case 0x1: 32 | default: 33 | break; 34 | } 35 | 36 | if (bit(c->buffer, 0)) 37 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 38 | if (bit(c->buffer, 1)) 39 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 40 | if (bit(c->buffer, 2)) 41 | c->controlData.buttons |= SCE_CTRL_CROSS; 42 | if (bit(c->buffer, 3)) 43 | c->controlData.buttons |= SCE_CTRL_SQUARE; 44 | 45 | if (bit(c->buffer, 6)) 46 | c->controlData.buttons |= SCE_CTRL_L1; 47 | if (bit(c->buffer, 7)) 48 | c->controlData.buttons |= SCE_CTRL_R1; 49 | 50 | if (bit(c->buffer, 4)) 51 | { 52 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 53 | c->controlData.lt = 0xFF; 54 | } 55 | 56 | if (bit(c->buffer, 5)) 57 | { 58 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 59 | c->controlData.rt = 0xFF; 60 | } 61 | 62 | if (bit(c->buffer + 1, 1)) 63 | c->controlData.buttons |= SCE_CTRL_START; 64 | if (bit(c->buffer + 1, 0)) 65 | c->controlData.buttons |= SCE_CTRL_SELECT; 66 | 67 | if (bit(c->buffer, 6) && bit(c->buffer, 7) && bit(c->buffer + 1, 1)) // L+R+START combo 68 | { 69 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 70 | c->controlData.buttons &= ~SCE_CTRL_START; 71 | } 72 | 73 | return 1; 74 | } 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /src/controllers/dinput/smartjoypad.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_SMARTJOYPAD_H__ 2 | #define __DINPUT_SMARTJOYPAD_H__ 3 | #include 4 | 5 | uint8_t smartjoypad_processReport(Controller *c, size_t length) 6 | { 7 | 8 | if (bit(c->buffer + 1, 4)) 9 | c->controlData.buttons |= SCE_CTRL_UP; 10 | if (bit(c->buffer + 1, 5)) 11 | c->controlData.buttons |= SCE_CTRL_RIGHT; 12 | if (bit(c->buffer + 1, 6)) 13 | c->controlData.buttons |= SCE_CTRL_DOWN; 14 | if (bit(c->buffer + 1, 7)) 15 | c->controlData.buttons |= SCE_CTRL_LEFT; 16 | 17 | 18 | if (bit(c->buffer, 0)) 19 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 20 | if (bit(c->buffer, 1)) 21 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 22 | if (bit(c->buffer, 2)) 23 | c->controlData.buttons |= SCE_CTRL_CROSS; 24 | if (bit(c->buffer, 3)) 25 | c->controlData.buttons |= SCE_CTRL_SQUARE; 26 | 27 | 28 | if (bit(c->buffer, 6)) 29 | c->controlData.buttons |= SCE_CTRL_L1; 30 | if (bit(c->buffer, 7)) 31 | c->controlData.buttons |= SCE_CTRL_R1; 32 | 33 | if (bit(c->buffer, 4)) 34 | { 35 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 36 | c->controlData.lt = 0xFF; 37 | } 38 | 39 | if (bit(c->buffer, 5)) 40 | { 41 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 42 | c->controlData.rt = 0xFF; 43 | } 44 | 45 | if (bit(c->buffer + 1, 2)) 46 | c->controlData.buttons |= SCE_CTRL_L3; 47 | if (bit(c->buffer + 1, 3)) 48 | c->controlData.buttons |= SCE_CTRL_R3; 49 | 50 | if (bit(c->buffer + 1, 0)) 51 | c->controlData.buttons |= SCE_CTRL_SELECT; 52 | if (bit(c->buffer + 1, 1)) 53 | c->controlData.buttons |= SCE_CTRL_START; 54 | 55 | if (bit(c->buffer, 6) && bit(c->buffer, 7) && bit(c->buffer + 1, 1)) // L+R+START combo 56 | { 57 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 58 | c->controlData.buttons &= ~SCE_CTRL_START; 59 | } 60 | 61 | c->controlData.leftX = c->buffer[2]; 62 | c->controlData.leftY = c->buffer[3]; 63 | 64 | c->controlData.rightX = c->buffer[4]; 65 | c->controlData.rightY = c->buffer[5]; 66 | 67 | return 1; 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/controller.c: -------------------------------------------------------------------------------- 1 | #include "controller.h" 2 | 3 | #include "controllers/dinput_controller.h" 4 | #include "controllers/ds3_controller.h" 5 | #include "controllers/xbox_360_controller.h" 6 | #include "controllers/xbox_360w_controller.h" 7 | #include "controllers/xbox_controller.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | void on_read_data(int32_t result, int32_t count, void *arg) 14 | { 15 | // process buffer 16 | 17 | Controller *c = (Controller *)arg; 18 | if (result == 0 && count > 0 && arg) 19 | { 20 | if (c->inited) 21 | { 22 | int ret = 0; 23 | switch (c->type) 24 | { 25 | case PAD_XBOX: 26 | ret = XboxController_processReport(c, count); 27 | break; 28 | case PAD_XBOX360: 29 | ret = Xbox360Controller_processReport(c, count); 30 | break; 31 | case PAD_XBOX360W: 32 | ret = Xbox360WController_processReport(c, count); 33 | break; 34 | case PAD_DS3: 35 | ret = DS3Controller_processReport(c, count); 36 | break; 37 | case PAD_DINPUT: 38 | ret = DinputController_processReport(c, count); 39 | break; 40 | default: 41 | break; 42 | } 43 | if (ret) 44 | ksceKernelPowerTick(0); // cancel sleep timers. 45 | } 46 | } 47 | 48 | usb_read(c); 49 | } 50 | 51 | void on_write_data(int32_t result, int32_t count, void *arg) 52 | { 53 | // check status 54 | // do nothing? 55 | } 56 | 57 | void usb_read(Controller *c) 58 | { 59 | int ret; 60 | 61 | if (!c->inited) 62 | return; 63 | 64 | ret = ksceUsbdInterruptTransfer(c->pipe_in, c->buffer, c->buffer_size, on_read_data, c); 65 | 66 | if (ret < 0) 67 | { 68 | ksceDebugPrintf("ksceUsbdInterruptTransfer(in) error: 0x%08x\n", ret); 69 | // error out 70 | } 71 | } 72 | 73 | void usb_write(Controller *c, uint8_t *data, int len) 74 | { 75 | int ret; 76 | ret = ksceUsbdInterruptTransfer(c->pipe_out, data, len, on_write_data, c); 77 | 78 | if (ret < 0) 79 | { 80 | ksceDebugPrintf("ksceUsbdInterruptTransfer(out) error: 0x%08x\n", ret); 81 | // error out 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) 4 | if(DEFINED ENV{VITASDK}) 5 | set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file") 6 | else() 7 | message(FATAL_ERROR "Please define VITASDK to point to your SDK path!") 8 | endif() 9 | endif() 10 | 11 | project(vixen) 12 | include("${VITASDK}/share/vita.cmake" REQUIRED) 13 | 14 | add_executable(${PROJECT_NAME} 15 | src/main.c 16 | src/devicelist.c 17 | src/controller.c 18 | src/controllers/xbox_controller.c 19 | src/controllers/xbox_360_controller.c 20 | src/controllers/xbox_360w_controller.c 21 | src/controllers/ds3_controller.c 22 | src/controllers/dinput_controller.c 23 | ) 24 | 25 | target_link_libraries(${PROJECT_NAME} 26 | SceDebugForDriver_stub 27 | SceSblAIMgrForDriver_stub 28 | SceCtrlForDriver_stub 29 | SceKernelSuspendForDriver_stub 30 | SceSysclibForDriver_stub 31 | SceSysmemForDriver_stub 32 | SceThreadmgrForDriver_stub 33 | SceUsbdForDriver_stub 34 | SceUsbServForDriver_stub 35 | taihenForKernel_stub 36 | ) 37 | 38 | set_target_properties(${PROJECT_NAME} 39 | PROPERTIES LINK_FLAGS "-nostdlib" 40 | ) 41 | 42 | vita_create_self(${PROJECT_NAME}.skprx ${PROJECT_NAME} 43 | CONFIG vixen.yml 44 | UNSAFE 45 | ) 46 | 47 | add_executable(${PROJECT_NAME}_ds3 48 | src/main.c 49 | src/devicelist.c 50 | src/controller.c 51 | src/controllers/xbox_controller.c 52 | src/controllers/xbox_360_controller.c 53 | src/controllers/xbox_360w_controller.c 54 | src/controllers/ds3_controller.c 55 | src/controllers/dinput_controller.c 56 | ) 57 | 58 | target_link_libraries(${PROJECT_NAME}_ds3 59 | SceDebugForDriver_stub 60 | SceSblAIMgrForDriver_stub 61 | SceCtrlForDriver_stub 62 | SceKernelSuspendForDriver_stub 63 | SceSysclibForDriver_stub 64 | SceSysmemForDriver_stub 65 | SceThreadmgrForDriver_stub 66 | SceUsbdForDriver_stub 67 | SceUsbServForDriver_stub 68 | taihenForKernel_stub 69 | ) 70 | 71 | set_target_properties(${PROJECT_NAME}_ds3 72 | PROPERTIES LINK_FLAGS "-nostdlib" 73 | ) 74 | 75 | target_compile_definitions(${PROJECT_NAME}_ds3 76 | PRIVATE WITH_DS3 77 | ) 78 | 79 | vita_create_self(${PROJECT_NAME}_ds3.skprx ${PROJECT_NAME}_ds3 80 | CONFIG vixen.yml 81 | UNSAFE 82 | ) 83 | -------------------------------------------------------------------------------- /src/controllers/dinput/raphnetpsx.h: -------------------------------------------------------------------------------- 1 | #ifndef __DINPUT_RAPHNETPSX_H__ 2 | #define __DINPUT_RAPHNETPSX_H__ 3 | #include 4 | 5 | uint8_t raphnetpsx_processReport(Controller *c, size_t length) 6 | { 7 | if (length >= 15) 8 | { 9 | // dpad 10 | if (bit(c->buffer + 14, 4)) 11 | c->controlData.buttons |= SCE_CTRL_UP; 12 | if (bit(c->buffer + 14, 5)) 13 | c->controlData.buttons |= SCE_CTRL_DOWN; 14 | if (bit(c->buffer + 14, 6)) 15 | c->controlData.buttons |= SCE_CTRL_LEFT; 16 | if (bit(c->buffer + 14, 7)) 17 | c->controlData.buttons |= SCE_CTRL_RIGHT; 18 | 19 | if (bit(c->buffer + 13, 0)) 20 | c->controlData.buttons |= SCE_CTRL_SQUARE; 21 | if (bit(c->buffer + 13, 1)) 22 | c->controlData.buttons |= SCE_CTRL_CROSS; 23 | if (bit(c->buffer + 13, 2)) 24 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 25 | if (bit(c->buffer + 13, 3)) 26 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 27 | 28 | if (bit(c->buffer + 13, 4)) 29 | c->controlData.buttons |= SCE_CTRL_START; 30 | if (bit(c->buffer + 13, 5)) 31 | c->controlData.buttons |= SCE_CTRL_SELECT; 32 | 33 | if (bit(c->buffer + 13, 6)) 34 | c->controlData.buttons |= SCE_CTRL_L1; 35 | if (bit(c->buffer + 13, 7)) 36 | c->controlData.buttons |= SCE_CTRL_R1; 37 | 38 | if (bit(c->buffer + 14, 2)) 39 | c->controlData.buttons |= SCE_CTRL_L3; 40 | if (bit(c->buffer + 14, 3)) 41 | c->controlData.buttons |= SCE_CTRL_R3; 42 | 43 | // triggers 44 | int16_t ltx = *(int16_t*)(c->buffer + 11); 45 | c->controlData.lt = ((int32_t)ltx - 16000) * 255 / 16000; 46 | int16_t rtx = *(int16_t*)(c->buffer + 9); 47 | c->controlData.rt = ((int32_t)rtx - 16000) * 255 / 16000; 48 | 49 | // set buttons with little deadzone 50 | if (c->controlData.lt > 10) 51 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 52 | if (c->controlData.rt > 10) 53 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 54 | 55 | if (bit(c->buffer + 14, 0)) 56 | { 57 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 58 | c->controlData.lt = 0xFF; 59 | } 60 | if (bit(c->buffer + 14, 1)) 61 | { 62 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 63 | c->controlData.rt = 0xFF; 64 | } 65 | 66 | // axes 67 | int16_t lx = *(int16_t*)(c->buffer + 1); 68 | c->controlData.leftX = (int32_t)lx * 255 / 32000; 69 | int16_t ly = *(int16_t*)(c->buffer + 3); 70 | c->controlData.leftY = (int32_t)ly * 255 / 32000; 71 | 72 | int16_t rx = *(int16_t*)(c->buffer + 5); 73 | c->controlData.rightX = (int32_t)rx * 255 / 32000; 74 | int16_t ry = *(int16_t*)(c->buffer + 7); 75 | c->controlData.rightY = (int32_t)ry * 255 / 32000; 76 | 77 | if (bit(c->buffer + 13, 6) && bit(c->buffer + 13, 7) && bit(c->buffer + 13, 4)) // L+R+START combo 78 | { 79 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 80 | c->controlData.buttons &= ~SCE_CTRL_START; 81 | } 82 | } 83 | return 1; 84 | } 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ViXEn 2 | **Vi**ta **X**-input **En**abler 3 | 4 | PSVita kernel driver for x-input gamepads (e.g. xbox360) 5 | 6 | ## Features 7 | 8 | * Support for up to 4 wired usb x-input, original xbox or ps3 devices, Logitech Rumblepad/DualAction and Playstation Classic controllers. 9 | * Support for up to 4 wireless Xbox 360 gamepads via 1 wired usb receiver. 10 | * Auto turn-off wireless controllers on suspend. 11 | 12 | Note: xbox 360 wireless receiver takes over all 4 gamepad ports, so you can't use wired and wireless gamepads simultaniously. 13 | 14 | For full list of supported devices see [here](src/devicelist.c) 15 | 16 | ## Read this carefully 17 | There two versions of plugins: `vixen.skprx` and `vixen_ds3.skprx`. Second one supports wired ds3-alike pads. 18 | If you use `vixen_ds3.skprx` you 19 | 1. need to make sure it's first plugin under `*KERNEL` 20 | 2. **will** lose ability to pair wireless ds3 via usb on pstv. So if you need to - temporarily comment-out plugin. 21 | 3. ds3 support is very unstable atm. 22 | Tl;dr if you don't use anything, that presents itself as ds3 (except wireless ds3 itself) - use `vixen.skprx`. Otherwise you may try `vixen_ds3.skprx` 23 | 24 | ## Installing 25 | * Copy `vixen.skprx` or `vixen_ds3.skprx` into `ur0:tai` folder 26 | * Add `ur0:tai/vixen.skprx` or `ur0:tai/vixen.skprx` line under `*KERNEL` in tai config and reboot. 27 | * For vita you need usb Y-cable and external power. See [this](https://github.com/isage/vita-usb-ether#hardware) for example. 28 | * For pstv it is **highly** recommended to use usb-hub with external power for gamepads with force-feedback. 29 | 30 | ## FAQ 31 | * **Does it support joycon, xbox one s, _insert another wireless controller here_?** 32 | NO. It supports **wired USB** controllers only. Yes, Xbox 360 is also wired (because you need receiver) 33 | For wireless (bluetooth) use [ds34vita](https://github.com/MERLev/ds34vita), [VitaControl](https://github.com/Hydr8gon/VitaControl) or [MiniVitaTV](https://github.com/TheOfficialFloW/MiniVitaTV) 34 | * **Can i connect my Xbox 360 pad via charge'n'play?** 35 | No. Because it's more charge than play. It doesn't support data. You need wireless receiver. 36 | * **Does it support _insert controller name here_?** 37 | Currently it supports plenty of x-input devices, original xbox devices (via xbox->usb adapter) and some wired HID gamepads. See [here](src/devicelist.c) 38 | If your device isn't in that list (or doesn't present itself as ds3 or xbox or xbox360 pad), see [that list](https://github.com/xboxdrv/xboxdrv/blob/stable/src/xpad_device.cpp#L29) 39 | If it's in that list - i can add support. If it isn't - i, most likely, can't (yet) without having such device. 40 | * **Can i install it alongside another input plugin?** 41 | Generally that isn't recommended. Most input plugins (ds34vita/vitacontrol) hook same functions, conflicts will definitely arise. 42 | You can use it with ds4touch/ds4motion. 43 | * **There's no guide/home/ps button on my pad** 44 | Use L+R+Start combo instead 45 | 46 | ## Requesting support for new controllers 47 | See [ViXEn Helper](https://github.com/isage/vixen-helper) 48 | 49 | ## Building 50 | 51 | * Install [vitasdk](https://vitasdk.org) 52 | * `mkdir build && cmake -DCMAKE_BUILD_TYPE=Release .. && make` 53 | 54 | ## License 55 | 56 | MIT, see LICENSE.md 57 | 58 | ## Credits 59 | 60 | * [xboxdrv](https://github.com/xboxdrv/xboxdrv) - for vid/pid pairs and protocol description 61 | * [xerpi](https://github.com/xerpi) - for ds3vita 62 | * **CBPS discord** - for support and stupid ideas 63 | * **rem** - for being lazy/buzy to do the same :P 64 | * [Graphene](https://github.com/GrapheneCt) - for testing and ideas 65 | * [Paddel06](https://github.com/paddel06) - for testing og xbox support 66 | * **null** for requesting and testing mini diva controller support and adrenaline bug 67 | * [Raphaël Assenat](https://github.com/raphnet) for providing Raphnet Technologies PSX to USB report description 68 | -------------------------------------------------------------------------------- /src/controllers/xbox_controller.c: -------------------------------------------------------------------------------- 1 | #include "xbox_controller.h" 2 | 3 | #include "utils/bit.h" 4 | #include "xbox_360_report.h" 5 | 6 | #include 7 | #include 8 | 9 | #define USB_ENDPOINT_OUT 0x02 10 | #define USB_ENDPOINT_IN 0x81 11 | 12 | uint8_t XboxController_probe(Controller *c, int device_id, int port) 13 | { 14 | c->type = PAD_XBOX; 15 | c->buffer_size = 32; 16 | c->device_id = device_id; 17 | c->port = port; 18 | c->battery_level = 5; 19 | 20 | // init endpoints and stuff 21 | SceUsbdEndpointDescriptor *endpoint; 22 | #if defined(DEBUG) 23 | ksceDebugPrintf("scanning endpoints for device %d\n", device_id); 24 | #endif 25 | endpoint = (SceUsbdEndpointDescriptor *)ksceUsbdScanStaticDescriptor(device_id, 0, SCE_USBD_DESCRIPTOR_ENDPOINT); 26 | while (endpoint) 27 | { 28 | #if defined(DEBUG) 29 | ksceDebugPrintf("got EP: %02x\n", endpoint->bEndpointAddress); 30 | #endif 31 | if (endpoint->bEndpointAddress == USB_ENDPOINT_IN) 32 | { 33 | #if defined(DEBUG) 34 | ksceDebugPrintf("opening in pipe\n"); 35 | #endif 36 | c->pipe_in = ksceUsbdOpenPipe(device_id, endpoint); 37 | #if defined(DEBUG) 38 | ksceDebugPrintf("= 0x%08x\n", c->pipe_in); 39 | ksceDebugPrintf("bmAttributes = %x\n", endpoint->bmAttributes); 40 | #endif 41 | } 42 | else if (endpoint->bEndpointAddress == USB_ENDPOINT_OUT) 43 | { 44 | #if defined(DEBUG) 45 | ksceDebugPrintf("opening out pipe\n"); 46 | #endif 47 | c->pipe_out = ksceUsbdOpenPipe(device_id, endpoint); 48 | #if defined(DEBUG) 49 | ksceDebugPrintf("= 0x%08x\n", c->pipe_out); 50 | ksceDebugPrintf("bmAttributes = %x\n", endpoint->bmAttributes); 51 | #endif 52 | } 53 | endpoint 54 | = (SceUsbdEndpointDescriptor *)ksceUsbdScanStaticDescriptor(device_id, endpoint, SCE_USBD_DESCRIPTOR_ENDPOINT); 55 | } 56 | 57 | if (c->pipe_in > 0 && c->pipe_out > 0) 58 | { 59 | SceUsbdConfigurationDescriptor *cdesc; 60 | if ((cdesc = (SceUsbdConfigurationDescriptor *)ksceUsbdScanStaticDescriptor(device_id, NULL, 61 | SCE_USBD_DESCRIPTOR_CONFIGURATION)) 62 | == NULL) 63 | return 0; 64 | 65 | SceUID control_pipe_id = ksceUsbdOpenPipe(device_id, NULL); 66 | // set default config 67 | int r = ksceUsbdSetConfiguration(control_pipe_id, cdesc->bConfigurationValue, NULL, NULL); 68 | #if defined(DEBUG) 69 | ksceDebugPrintf("ksceUsbdSetConfiguration = 0x%08x\n", r); 70 | #endif 71 | if (r < 0) 72 | return 0; 73 | c->attached = 1; 74 | c->inited = 1; 75 | } 76 | 77 | usb_read(c); 78 | return 1; 79 | } 80 | 81 | void XboxController_setRumble(Controller *c, uint8_t small, uint8_t large) 82 | { 83 | uint8_t rumblecmd[] __attribute__((aligned(64))) = {0x00, 0x06, 0x00, small, 0x00, large}; 84 | 85 | usb_write(c, rumblecmd, 6); 86 | } 87 | 88 | uint8_t XboxController_processReport(Controller *c, size_t length) 89 | { 90 | if (length == 20 && c->buffer[0] == 0x00 && c->buffer[1] == 0x14) 91 | { 92 | Xbox360Report report; 93 | 94 | report.dpad_up = bit(c->buffer + 2, 0); 95 | report.dpad_down = bit(c->buffer + 2, 1); 96 | report.dpad_left = bit(c->buffer + 2, 2); 97 | report.dpad_right = bit(c->buffer + 2, 3); 98 | 99 | report.start = bit(c->buffer + 2, 4); 100 | report.back = bit(c->buffer + 2, 5); 101 | report.thumb_l = bit(c->buffer + 2, 6); 102 | report.thumb_r = bit(c->buffer + 2, 7); 103 | 104 | report.a = c->buffer[4] > 0; 105 | report.b = c->buffer[5] > 0; 106 | report.x = c->buffer[6] > 0; 107 | report.y = c->buffer[7] > 0; 108 | 109 | report.rb = c->buffer[8] > 0; 110 | report.lb = c->buffer[9] > 0; 111 | 112 | // TODO 113 | report.guide = 0; 114 | 115 | report.lt = c->buffer[10]; 116 | report.rt = c->buffer[11]; 117 | 118 | report.x1 = *((int16_t *)(c->buffer + 12)); 119 | report.y1 = *((int16_t *)(c->buffer + 14)); 120 | 121 | report.x2 = *((int16_t *)(c->buffer + 16)); 122 | report.y2 = *((int16_t *)(c->buffer + 18)); 123 | 124 | c->controlData.buttons = 0; 125 | 126 | if (report.a) 127 | c->controlData.buttons |= SCE_CTRL_CROSS; 128 | if (report.b) 129 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 130 | if (report.y) 131 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 132 | if (report.x) 133 | c->controlData.buttons |= SCE_CTRL_SQUARE; 134 | 135 | if (report.dpad_up) 136 | c->controlData.buttons |= SCE_CTRL_UP; 137 | if (report.dpad_down) 138 | c->controlData.buttons |= SCE_CTRL_DOWN; 139 | if (report.dpad_left) 140 | c->controlData.buttons |= SCE_CTRL_LEFT; 141 | if (report.dpad_right) 142 | c->controlData.buttons |= SCE_CTRL_RIGHT; 143 | 144 | if (report.lb) 145 | c->controlData.buttons |= SCE_CTRL_L1; 146 | if (report.rb) 147 | c->controlData.buttons |= SCE_CTRL_R1; 148 | if (report.thumb_l) 149 | c->controlData.buttons |= SCE_CTRL_L3; 150 | if (report.thumb_r) 151 | c->controlData.buttons |= SCE_CTRL_R3; 152 | 153 | if (report.lt > 0) 154 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 155 | if (report.rt > 0) 156 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 157 | 158 | if (report.start) 159 | c->controlData.buttons |= SCE_CTRL_START; 160 | if (report.back) 161 | c->controlData.buttons |= SCE_CTRL_SELECT; 162 | 163 | if (report.guide) // todo, no guide 164 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 165 | 166 | c->controlData.leftX = report.x1 / 256 + 128; 167 | c->controlData.leftY = report.y1 / 256 + 128; 168 | c->controlData.rightX = report.x2 / 256 + 128; 169 | c->controlData.rightY = report.y2 / 256 + 128; 170 | 171 | // up and down are reversed 172 | c->controlData.leftY = 255 - c->controlData.leftY; 173 | c->controlData.rightY = 255 - c->controlData.rightY; 174 | 175 | c->controlData.lt = report.lt; 176 | c->controlData.rt = report.rt; 177 | return 1; 178 | } 179 | else 180 | { 181 | // ksceDebugPrintf("unknown report\n"); 182 | } 183 | return 0; 184 | } 185 | -------------------------------------------------------------------------------- /src/controllers/dinput_controller.c: -------------------------------------------------------------------------------- 1 | #include "dinput_controller.h" 2 | 3 | #include "utils/bit.h" 4 | #include "xbox_360_report.h" 5 | 6 | #include 7 | #include 8 | 9 | #include "dinput/logitech.h" 10 | #include "dinput/logitech_wingman.h" 11 | #include "dinput/psclassic.h" 12 | #include "dinput/horidiva.h" 13 | #include "dinput/horidiva_ps4.h" 14 | #include "dinput/raphnetpsx.h" 15 | #include "dinput/p3converter.h" 16 | #include "dinput/sfcconverter.h" 17 | #include "dinput/p2top3converter.h" 18 | #include "dinput/smartjoypad.h" 19 | #include "dinput/mayflash.h" 20 | #include "dinput/neogeox.h" 21 | 22 | uint8_t DinputController_probe(Controller *c, int device_id, int port, int vendor, int product) 23 | { 24 | c->type = PAD_DINPUT; 25 | c->buffer_size = 8; 26 | c->device_id = device_id; 27 | c->port = port; 28 | c->battery_level = 5; 29 | c->vendor = vendor; 30 | c->product = product; 31 | 32 | // init endpoints and stuff 33 | SceUsbdEndpointDescriptor *endpoint; 34 | #if defined(DEBUG) 35 | ksceDebugPrintf("scanning endpoints for device %d\n", device_id); 36 | #endif 37 | endpoint = (SceUsbdEndpointDescriptor *)ksceUsbdScanStaticDescriptor(device_id, 0, SCE_USBD_DESCRIPTOR_ENDPOINT); 38 | while (endpoint) 39 | { 40 | #if defined(DEBUG) 41 | ksceDebugPrintf("got EP: %02x\n", endpoint->bEndpointAddress); 42 | #endif 43 | if ((endpoint->bEndpointAddress & SCE_USBD_ENDPOINT_DIRECTION_BITS) == SCE_USBD_ENDPOINT_DIRECTION_IN) 44 | { 45 | #if defined(DEBUG) 46 | ksceDebugPrintf("opening in pipe\n"); 47 | #endif 48 | c->pipe_in = ksceUsbdOpenPipe(device_id, endpoint); 49 | #if defined(DEBUG) 50 | ksceDebugPrintf("= 0x%08x\n", c->pipe_in); 51 | ksceDebugPrintf("bmAttributes = %x\n", endpoint->bmAttributes); 52 | #endif 53 | c->buffer_size = endpoint->wMaxPacketSize; 54 | if (c->buffer_size > 64) 55 | { 56 | ksceDebugPrintf("Packet size too big = %d\n", endpoint->wMaxPacketSize); 57 | return 0; 58 | } 59 | } 60 | else if ((endpoint->bEndpointAddress & SCE_USBD_ENDPOINT_DIRECTION_BITS) == SCE_USBD_ENDPOINT_DIRECTION_OUT) 61 | { 62 | #if defined(DEBUG) 63 | ksceDebugPrintf("opening out pipe\n"); 64 | #endif 65 | c->pipe_out = ksceUsbdOpenPipe(device_id, endpoint); 66 | #if defined(DEBUG) 67 | ksceDebugPrintf("= 0x%08x\n", c->pipe_out); 68 | ksceDebugPrintf("bmAttributes = %x\n", endpoint->bmAttributes); 69 | #endif 70 | } 71 | if (c->pipe_in > 0 && c->pipe_out > 0) 72 | break; 73 | endpoint 74 | = (SceUsbdEndpointDescriptor *)ksceUsbdScanStaticDescriptor(device_id, endpoint, SCE_USBD_DESCRIPTOR_ENDPOINT); 75 | } 76 | 77 | if (c->pipe_in > 0) 78 | { 79 | SceUsbdConfigurationDescriptor *cdesc; 80 | if ((cdesc = (SceUsbdConfigurationDescriptor *)ksceUsbdScanStaticDescriptor(device_id, NULL, 81 | SCE_USBD_DESCRIPTOR_CONFIGURATION)) 82 | == NULL) 83 | return 0; 84 | 85 | SceUID control_pipe_id = ksceUsbdOpenPipe(device_id, NULL); 86 | // set default config 87 | int r = ksceUsbdSetConfiguration(control_pipe_id, cdesc->bConfigurationValue, NULL, NULL); 88 | #if defined(DEBUG) 89 | ksceDebugPrintf("ksceUsbdSetConfiguration = 0x%08x\n", r); 90 | #endif 91 | if (r < 0) 92 | return 0; 93 | c->attached = 1; 94 | c->inited = 1; 95 | } 96 | 97 | usb_read(c); 98 | return 1; 99 | } 100 | 101 | uint8_t DinputController_processReport(Controller *c, size_t length) 102 | { 103 | // For Dual PSX Adaptor consider only first controller port 104 | if (c->vendor == 0x0810 && c->product == 0x0001 && c->buffer[0] != 1) 105 | { 106 | return 1; 107 | } 108 | 109 | // reset everything 110 | c->controlData.buttons = 0; 111 | c->controlData.leftX = 128; 112 | c->controlData.leftY = 128; 113 | c->controlData.rightX = 128; 114 | c->controlData.rightY = 128; 115 | c->controlData.lt = 0; 116 | c->controlData.rt = 0; 117 | 118 | if (c->vendor == 0x054c && c->product == 0x0cda) // playstation classic 119 | { 120 | return psclassic_processReport(c, length); 121 | } 122 | else if (c->vendor == 0x0F0D && 123 | ( 124 | c->product == 0x0049 || c->product == 0x00a6 || c->product == 0x0022 || c->product == 0x0092 || c->product == 0x0102 125 | ) 126 | ) // Hori ps3 mini diva / Hori divaX/DX ps3 mode / Brook universal ds3 mode / Raspberry Pi Pico GP2040CE 127 | { 128 | return horiDiva_processReport(c, length); 129 | } 130 | else if (c->vendor == 0x12ba && c->product == 0x0100) // Raspberry Pi Pico GH 131 | { 132 | return horiDiva_processReport(c, length); 133 | } 134 | else if (c->vendor == 0x0F0D && (c->product == 0x00a5 || c->product == 0x0101)) // Hori divaX/DX ps4 mode 135 | { 136 | return horiDivaps4_processReport(c, length); 137 | } 138 | else if (c->vendor == 0x0c12 && c->product == 0x0c30) // Brook Universal Fighting Board DS4 mode 139 | { 140 | return horiDivaps4_processReport(c, length); 141 | } 142 | else if (c->vendor == 0x046d && (c->product == 0xc216 || c->product == 0xc218)) // logitech 143 | { 144 | return logitech_processReport(c, length); 145 | } 146 | else if (c->vendor == 0x046d && c->product == 0xc20c) // logitech wingman 147 | { 148 | return logitechWingman_processReport(c, length); 149 | } 150 | else if (c->vendor == 0x289b && c->product == 0x0044) // raphnet 151 | { 152 | return raphnetpsx_processReport(c, length); 153 | } 154 | else if (c->vendor == 0x0e8f && c->product == 0x0003) // PIII Converter Model: 538 155 | { 156 | return p3converter_processReport(c, length); 157 | } 158 | else if (c->vendor == 0x0079 && c->product == 0x1804) // NES/FC/SFC Joypad TO USB BOX 159 | { 160 | return sfcconverter_processReport(c, length); 161 | } 162 | else if (c->vendor == 0x0810 && c->product == 0x0001) // Dual PSX Adaptor 163 | { 164 | return p2top3converter_processReport(c, length); 165 | } 166 | else if (c->vendor == 0x0810 && c->product == 0x0003) // P2 to P3 167 | { 168 | return p2top3converter_processReport(c, length); 169 | } 170 | else if (c->vendor == 0x0b43 && c->product == 0x0001) // Smart Joypad 3 adapter 171 | { 172 | return smartjoypad_processReport(c, length); 173 | } 174 | else if (c->vendor == 0x0925 && c->product == 0x1700) // Mayflash SS 175 | { 176 | return mayflash_processReport(c, length); 177 | } 178 | else if (c->vendor == 0x1292 && c->product == 0x4e47) // Neogeo X 179 | { 180 | return neogeox_processReport(c, length); 181 | } 182 | else 183 | { 184 | return 0; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/controllers/xbox_360_controller.c: -------------------------------------------------------------------------------- 1 | #include "xbox_360_controller.h" 2 | 3 | #include "utils/bit.h" 4 | #include "xbox_360_report.h" 5 | 6 | #include 7 | #include 8 | 9 | #define USB_IF_PROTOCOL 0x01 10 | 11 | uint8_t Xbox360Controller_probe(Controller *c, int device_id, int port) 12 | { 13 | c->type = PAD_XBOX360; 14 | c->buffer_size = 32; 15 | c->device_id = device_id; 16 | c->port = port; 17 | c->battery_level = 5; 18 | 19 | #if defined(DEBUG) 20 | ksceDebugPrintf("scanning endpoints for device %d\n", device_id); 21 | #endif 22 | 23 | // init endpoints and stuff 24 | 25 | SceUsbdInterfaceDescriptor *interface; 26 | interface = (SceUsbdInterfaceDescriptor *)ksceUsbdScanStaticDescriptor(device_id, 0, SCE_USBD_DESCRIPTOR_ENDPOINT); 27 | while (interface) 28 | { 29 | if (interface->bInterfaceProtocol == USB_IF_PROTOCOL) 30 | break; 31 | interface = (SceUsbdInterfaceDescriptor *)ksceUsbdScanStaticDescriptor(device_id, interface, 32 | SCE_USBD_DESCRIPTOR_ENDPOINT); 33 | } 34 | 35 | SceUsbdEndpointDescriptor *endpoint; 36 | 37 | endpoint 38 | = (SceUsbdEndpointDescriptor *)ksceUsbdScanStaticDescriptor(device_id, interface, SCE_USBD_DESCRIPTOR_ENDPOINT); 39 | while (endpoint) 40 | { 41 | #if defined(DEBUG) 42 | ksceDebugPrintf("got EP: %02x\n", endpoint->bEndpointAddress); 43 | #endif 44 | if ((endpoint->bEndpointAddress & SCE_USBD_ENDPOINT_DIRECTION_BITS) == SCE_USBD_ENDPOINT_DIRECTION_IN) 45 | { 46 | #if defined(DEBUG) 47 | ksceDebugPrintf("opening in pipe\n"); 48 | #endif 49 | c->pipe_in = ksceUsbdOpenPipe(device_id, endpoint); 50 | #if defined(DEBUG) 51 | ksceDebugPrintf("= 0x%08x\n", c->pipe_in); 52 | ksceDebugPrintf("bmAttributes = %x\n", endpoint->bmAttributes); 53 | #endif 54 | } 55 | else if ((endpoint->bEndpointAddress & SCE_USBD_ENDPOINT_DIRECTION_BITS) == SCE_USBD_ENDPOINT_DIRECTION_OUT) 56 | { 57 | #if defined(DEBUG) 58 | ksceDebugPrintf("opening out pipe\n"); 59 | #endif 60 | c->pipe_out = ksceUsbdOpenPipe(device_id, endpoint); 61 | #if defined(DEBUG) 62 | ksceDebugPrintf("= 0x%08x\n", c->pipe_out); 63 | ksceDebugPrintf("bmAttributes = %x\n", endpoint->bmAttributes); 64 | #endif 65 | } 66 | 67 | if (c->pipe_in > 0 && c->pipe_out > 0) 68 | break; 69 | 70 | endpoint 71 | = (SceUsbdEndpointDescriptor *)ksceUsbdScanStaticDescriptor(device_id, endpoint, SCE_USBD_DESCRIPTOR_ENDPOINT); 72 | } 73 | 74 | if (c->pipe_in > 0 && c->pipe_out > 0) 75 | { 76 | SceUsbdConfigurationDescriptor *cdesc; 77 | if ((cdesc = (SceUsbdConfigurationDescriptor *)ksceUsbdScanStaticDescriptor(device_id, NULL, 78 | SCE_USBD_DESCRIPTOR_CONFIGURATION)) 79 | == NULL) 80 | return 0; 81 | 82 | SceUID control_pipe_id = ksceUsbdOpenPipe(device_id, NULL); 83 | // set default config 84 | int r = ksceUsbdSetConfiguration(control_pipe_id, cdesc->bConfigurationValue, NULL, NULL); 85 | #if defined(DEBUG) 86 | ksceDebugPrintf("ksceUsbdSetConfiguration = 0x%08x\n", r); 87 | #endif 88 | if (r < 0) 89 | return 0; 90 | c->attached = 1; 91 | c->inited = 1; 92 | } 93 | 94 | usb_read(c); 95 | return 1; 96 | } 97 | 98 | void Xbox360Controller_setRumble(Controller *c, uint8_t small, uint8_t large) 99 | { 100 | uint8_t rumblecmd[] __attribute__((aligned(64))) = {0x00, 0x08, 0x00, small, large, 0x00, 0x00, 0x00}; 101 | 102 | usb_write(c, rumblecmd, 8); 103 | } 104 | 105 | uint8_t Xbox360Controller_processReport(Controller *c, size_t length) 106 | { 107 | if (length == 3 && c->buffer[0] == 0x01 && c->buffer[1] == 0x03) 108 | { 109 | #if defined(DEBUG) 110 | ksceDebugPrintf("Xbox360Controller: LED Status: %d\n", (c->buffer[2])); 111 | #endif 112 | } 113 | else if (length == 3 && c->buffer[0] == 0x03 && c->buffer[1] == 0x03) 114 | { 115 | #if defined(DEBUG) 116 | ksceDebugPrintf("rumble status: %d\n", (c->buffer[2])); 117 | #endif 118 | } 119 | else if (length == 3 && c->buffer[0] == 0x08 && c->buffer[1] == 0x03) 120 | { 121 | #if defined(DEBUG) 122 | if (c->buffer[2] == 0x00) 123 | { 124 | ksceDebugPrintf("peripheral: none"); 125 | } 126 | else if (c->buffer[2] == 0x01) 127 | { 128 | ksceDebugPrintf("peripheral: chatpad"); 129 | } 130 | else if (c->buffer[2] == 0x02) 131 | { 132 | ksceDebugPrintf("peripheral: headset"); 133 | } 134 | else if (c->buffer[2] == 0x03) 135 | { 136 | ksceDebugPrintf("peripheral: headset, chatpad"); 137 | } 138 | else 139 | { 140 | ksceDebugPrintf("peripheral: unknown: %d", (c->buffer[2])); 141 | } 142 | #endif 143 | } 144 | else if (length == 20 && c->buffer[0] == 0x00 && (c->buffer[1] == 0x14 || c->buffer[1] == 0x00)) 145 | { 146 | Xbox360Report report; 147 | 148 | report.dpad_up = bit(c->buffer + 2, 0); 149 | report.dpad_down = bit(c->buffer + 2, 1); 150 | report.dpad_left = bit(c->buffer + 2, 2); 151 | report.dpad_right = bit(c->buffer + 2, 3); 152 | 153 | report.start = bit(c->buffer + 2, 4); 154 | report.back = bit(c->buffer + 2, 5); 155 | report.thumb_l = bit(c->buffer + 2, 6); 156 | report.thumb_r = bit(c->buffer + 2, 7); 157 | 158 | report.lb = bit(c->buffer + 3, 0); 159 | report.rb = bit(c->buffer + 3, 1); 160 | report.guide = bit(c->buffer + 3, 2); 161 | 162 | report.a = bit(c->buffer + 3, 4); 163 | report.b = bit(c->buffer + 3, 5); 164 | report.x = bit(c->buffer + 3, 6); 165 | report.y = bit(c->buffer + 3, 7); 166 | 167 | report.lt = c->buffer[4]; 168 | report.rt = c->buffer[5]; 169 | 170 | report.x1 = *((int16_t *)(c->buffer + 6)); 171 | report.y1 = *((int16_t *)(c->buffer + 8)); 172 | 173 | report.x2 = *((int16_t *)(c->buffer + 10)); 174 | report.y2 = *((int16_t *)(c->buffer + 12)); 175 | 176 | c->controlData.buttons = 0; 177 | 178 | if (report.a) 179 | c->controlData.buttons |= SCE_CTRL_CROSS; 180 | if (report.b) 181 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 182 | if (report.y) 183 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 184 | if (report.x) 185 | c->controlData.buttons |= SCE_CTRL_SQUARE; 186 | 187 | if (report.dpad_up) 188 | c->controlData.buttons |= SCE_CTRL_UP; 189 | if (report.dpad_down) 190 | c->controlData.buttons |= SCE_CTRL_DOWN; 191 | if (report.dpad_left) 192 | c->controlData.buttons |= SCE_CTRL_LEFT; 193 | if (report.dpad_right) 194 | c->controlData.buttons |= SCE_CTRL_RIGHT; 195 | 196 | if (report.lb) 197 | c->controlData.buttons |= SCE_CTRL_L1; 198 | if (report.rb) 199 | c->controlData.buttons |= SCE_CTRL_R1; 200 | if (report.thumb_l) 201 | c->controlData.buttons |= SCE_CTRL_L3; 202 | if (report.thumb_r) 203 | c->controlData.buttons |= SCE_CTRL_R3; 204 | 205 | if (report.lt > 0) 206 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 207 | if (report.rt > 0) 208 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 209 | 210 | if (report.start) 211 | c->controlData.buttons |= SCE_CTRL_START; 212 | if (report.back) 213 | c->controlData.buttons |= SCE_CTRL_SELECT; 214 | if (report.guide) 215 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 216 | 217 | c->controlData.leftX = report.x1 / 256 + 128; 218 | c->controlData.leftY = report.y1 / 256 + 128; 219 | c->controlData.rightX = report.x2 / 256 + 128; 220 | c->controlData.rightY = report.y2 / 256 + 128; 221 | 222 | // up and down are reversed 223 | c->controlData.leftY = 255 - c->controlData.leftY; 224 | c->controlData.rightY = 255 - c->controlData.rightY; 225 | 226 | c->controlData.lt = report.lt; 227 | c->controlData.rt = report.rt; 228 | return 1; 229 | } 230 | else 231 | { 232 | // ksceDebugPrintf("unknown report. len = %d\n", length); 233 | } 234 | return 0; 235 | } 236 | -------------------------------------------------------------------------------- /src/controllers/xbox_360w_controller.c: -------------------------------------------------------------------------------- 1 | #include "xbox_360w_controller.h" 2 | 3 | #include "utils/bit.h" 4 | #include "xbox_360_report.h" 5 | 6 | #include 7 | #include 8 | 9 | #define USB_ENDPOINT_OUT 0x01 10 | #define USB_ENDPOINT_IN 0x81 11 | 12 | uint8_t Xbox360WController_probe(Controller *c, int device_id, int port) 13 | { 14 | c->type = PAD_XBOX360W; 15 | c->buffer_size = 32; 16 | c->device_id = device_id; 17 | c->port = port; 18 | c->battery_level = 5; 19 | 20 | // init endpoints and stuff 21 | SceUsbdEndpointDescriptor *endpoint; 22 | #if defined(DEBUG) 23 | ksceDebugPrintf("scanning endpoints\n"); 24 | #endif 25 | endpoint = (SceUsbdEndpointDescriptor *)ksceUsbdScanStaticDescriptor(device_id, 0, SCE_USBD_DESCRIPTOR_ENDPOINT); 26 | while (endpoint) 27 | { 28 | #if defined(DEBUG) 29 | ksceDebugPrintf("got EP: %02x\n", endpoint->bEndpointAddress); 30 | #endif 31 | if (endpoint->bEndpointAddress == USB_ENDPOINT_IN + port) 32 | { 33 | #if defined(DEBUG) 34 | ksceDebugPrintf("opening in pipe\n"); 35 | #endif 36 | c->pipe_in = ksceUsbdOpenPipe(device_id, endpoint); 37 | #if defined(DEBUG) 38 | ksceDebugPrintf("= 0x%08x\n", c->pipe_in); 39 | ksceDebugPrintf("bmAttributes = %x\n", endpoint->bmAttributes); 40 | #endif 41 | } 42 | else if (endpoint->bEndpointAddress == USB_ENDPOINT_OUT + port) 43 | { 44 | #if defined(DEBUG) 45 | ksceDebugPrintf("opening out pipe\n"); 46 | #endif 47 | c->pipe_out = ksceUsbdOpenPipe(device_id, endpoint); 48 | #if defined(DEBUG) 49 | ksceDebugPrintf("= 0x%08x\n", c->pipe_out); 50 | ksceDebugPrintf("bmAttributes = %x\n", endpoint->bmAttributes); 51 | #endif 52 | } 53 | 54 | if (c->pipe_in > 0 && c->pipe_out > 0) 55 | break; 56 | 57 | endpoint 58 | = (SceUsbdEndpointDescriptor *)ksceUsbdScanStaticDescriptor(device_id, endpoint, SCE_USBD_DESCRIPTOR_ENDPOINT); 59 | } 60 | 61 | if (c->pipe_in > 0 && c->pipe_out > 0) 62 | { 63 | SceUsbdConfigurationDescriptor *cdesc; 64 | if ((cdesc = (SceUsbdConfigurationDescriptor *)ksceUsbdScanStaticDescriptor(device_id, NULL, 65 | SCE_USBD_DESCRIPTOR_CONFIGURATION)) 66 | == NULL) 67 | return 0; 68 | 69 | SceUID control_pipe_id = ksceUsbdOpenPipe(device_id, NULL); 70 | // set default config 71 | int r = ksceUsbdSetConfiguration(control_pipe_id, cdesc->bConfigurationValue, NULL, NULL); 72 | #if defined(DEBUG) 73 | ksceDebugPrintf("ksceUsbdSetConfiguration = 0x%08x\n", r); 74 | #endif 75 | if (r < 0) 76 | return 0; 77 | c->attached = 0; 78 | c->inited = 1; 79 | } 80 | 81 | usb_read(c); 82 | return 1; 83 | } 84 | 85 | void Xbox360WController_setLed(Controller *c, uint8_t led) 86 | { 87 | uint8_t ledcmd[] __attribute__((aligned(64))) 88 | = {0x00, 0x00, 0x08, (uint8_t)(0x40 + led), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 89 | 90 | usb_write(c, ledcmd, 12); 91 | } 92 | 93 | void Xbox360WController_setRumble(Controller *c, uint8_t small, uint8_t large) 94 | { 95 | uint8_t rumblecmd[] __attribute__((aligned(64))) 96 | = {0x00, 0x01, 0x0f, 0xc0, 0x00, small, large, 0x00, 0x00, 0x00, 0x00, 0x00}; 97 | 98 | usb_write(c, rumblecmd, 12); 99 | } 100 | 101 | void Xbox360WController_turnOff(Controller *c) 102 | { 103 | uint8_t powercmd[] __attribute__((aligned(64))) 104 | = {0x00, 0x00, 0x08, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 105 | 106 | usb_write(c, powercmd, 12); 107 | c->attached = 0; 108 | } 109 | 110 | uint8_t Xbox360WController_processReport(Controller *c, size_t length) 111 | { 112 | if (length == 2 && c->buffer[0] == 0x08) 113 | { // Connection Status Message 114 | if (c->buffer[1] == 0x00) 115 | { 116 | ksceDebugPrintf("controler disconnected\n"); 117 | 118 | // reset the controller into neutral position on disconnect 119 | c->controlData.buttons = 0; 120 | c->controlData.leftX = 127; 121 | c->controlData.leftY = 127; 122 | c->controlData.rightX = 127; 123 | c->controlData.rightY = 127; 124 | c->controlData.lt = 0; 125 | c->controlData.rt = 0; 126 | c->attached = 0; 127 | 128 | return 1; 129 | } 130 | else if (c->buffer[1] == 0x80) 131 | { 132 | ksceDebugPrintf("connection status: controller connected\n"); 133 | Xbox360WController_setLed(c, c->port + 2); 134 | c->attached = 1; 135 | return 1; 136 | } 137 | else if (c->buffer[1] == 0x40) 138 | { 139 | ksceDebugPrintf("Connection status: headset connected\n"); 140 | return 1; 141 | } 142 | else if (c->buffer[1] == 0xc0) 143 | { 144 | ksceDebugPrintf("Connection status: controller and headset connected\n"); 145 | Xbox360WController_setLed(c, c->port + 2); 146 | c->attached = 1; 147 | return 1; 148 | } 149 | else 150 | { 151 | ksceDebugPrintf("Connection status: unknown\n"); 152 | return 1; 153 | } 154 | } 155 | else if (length == 29) 156 | { 157 | if (c->buffer[0] == 0x00 && c->buffer[1] == 0x0f && c->buffer[2] == 0x00 && c->buffer[3] == 0xf0) 158 | { 159 | // Initial Announce Message 160 | c->battery_level = c->buffer[17] / 44; // crudely map 0-255 -> 0-5 161 | } 162 | else if (c->buffer[0] == 0x00 && c->buffer[1] == 0x00 && c->buffer[2] == 0x00 && c->buffer[3] == 0x13) 163 | { 164 | // Battery status 165 | c->battery_level = c->buffer[4] / 44; 166 | } 167 | else if (c->buffer[0] == 0x00 && c->buffer[1] == 0x01 && c->buffer[2] == 0x00 && c->buffer[3] == 0xf0 168 | && c->buffer[4] == 0x00 && c->buffer[5] == 0x13) 169 | { 170 | // Event message 171 | uint8_t *ptr = c->buffer + 4; 172 | Xbox360Report report; 173 | 174 | report.dpad_up = bit(ptr + 2, 0); 175 | report.dpad_down = bit(ptr + 2, 1); 176 | report.dpad_left = bit(ptr + 2, 2); 177 | report.dpad_right = bit(ptr + 2, 3); 178 | 179 | report.start = bit(ptr + 2, 4); 180 | report.back = bit(ptr + 2, 5); 181 | report.thumb_l = bit(ptr + 2, 6); 182 | report.thumb_r = bit(ptr + 2, 7); 183 | 184 | report.lb = bit(ptr + 3, 0); 185 | report.rb = bit(ptr + 3, 1); 186 | report.guide = bit(ptr + 3, 2); 187 | 188 | report.a = bit(ptr + 3, 4); 189 | report.b = bit(ptr + 3, 5); 190 | report.x = bit(ptr + 3, 6); 191 | report.y = bit(ptr + 3, 7); 192 | 193 | report.lt = ptr[4]; 194 | report.rt = ptr[5]; 195 | 196 | report.x1 = *((int16_t *)(ptr + 6)); 197 | report.y1 = *((int16_t *)(ptr + 8)); 198 | 199 | report.x2 = *((int16_t *)(ptr + 10)); 200 | report.y2 = *((int16_t *)(ptr + 12)); 201 | 202 | c->controlData.buttons = 0; 203 | 204 | if (report.a) 205 | c->controlData.buttons |= SCE_CTRL_CROSS; 206 | if (report.b) 207 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 208 | if (report.y) 209 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 210 | if (report.x) 211 | c->controlData.buttons |= SCE_CTRL_SQUARE; 212 | 213 | if (report.dpad_up) 214 | c->controlData.buttons |= SCE_CTRL_UP; 215 | if (report.dpad_down) 216 | c->controlData.buttons |= SCE_CTRL_DOWN; 217 | if (report.dpad_left) 218 | c->controlData.buttons |= SCE_CTRL_LEFT; 219 | if (report.dpad_right) 220 | c->controlData.buttons |= SCE_CTRL_RIGHT; 221 | 222 | if (report.lb) 223 | c->controlData.buttons |= SCE_CTRL_L1; 224 | if (report.rb) 225 | c->controlData.buttons |= SCE_CTRL_R1; 226 | if (report.thumb_l) 227 | c->controlData.buttons |= SCE_CTRL_L3; 228 | if (report.thumb_r) 229 | c->controlData.buttons |= SCE_CTRL_R3; 230 | 231 | if (report.lt > 0) 232 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 233 | if (report.rt > 0) 234 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 235 | 236 | if (report.start) 237 | c->controlData.buttons |= SCE_CTRL_START; 238 | if (report.back) 239 | c->controlData.buttons |= SCE_CTRL_SELECT; 240 | if (report.guide) 241 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 242 | 243 | c->controlData.leftX = report.x1 / 256 + 128; 244 | c->controlData.leftY = report.y1 / 256 + 128; 245 | c->controlData.rightX = report.x2 / 256 + 128; 246 | c->controlData.rightY = report.y2 / 256 + 128; 247 | 248 | // up and down are reversed 249 | c->controlData.leftY = 255 - c->controlData.leftY; 250 | c->controlData.rightY = 255 - c->controlData.rightY; 251 | 252 | c->controlData.lt = report.lt; 253 | c->controlData.rt = report.rt; 254 | 255 | return 1; 256 | } 257 | else 258 | { 259 | #if defined(DEBUG) 260 | // ksceDebugPrintf("unknown packet\n"); 261 | #endif 262 | } 263 | } 264 | else 265 | { 266 | #if defined(DEBUG) 267 | // ksceDebugPrintf("unknown packet\n"); 268 | #endif 269 | } 270 | 271 | return 0; 272 | } 273 | -------------------------------------------------------------------------------- /src/controllers/ds3_controller.c: -------------------------------------------------------------------------------- 1 | #include "ds3_controller.h" 2 | 3 | #include "utils/bit.h" 4 | #include "ds3_report.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #define HID_GET_REPORT 0x01 11 | #define HID_GET_IDLE 0x02 12 | #define HID_GET_PROTOCOL 0x03 13 | #define HID_SET_REPORT 0x09 14 | #define HID_SET_IDLE 0x0A 15 | #define HID_SET_PROTOCOL 0x0B 16 | 17 | #define HID_REPORT_TYPE_INPUT 0x01 18 | #define HID_REPORT_TYPE_OUTPUT 0x02 19 | #define HID_REPORT_TYPE_FEATURE 0x03 20 | 21 | void oncontrol(int32_t result, int32_t count, void *arg) 22 | { 23 | #if defined(DEBUG) 24 | ksceDebugPrintf("oncontrol: %x %d\n", result, count); 25 | #endif 26 | } 27 | 28 | uint8_t DS3Controller_probe(Controller *c, int device_id, int port) 29 | { 30 | c->type = PAD_DS3; 31 | c->buffer_size = 64; 32 | c->device_id = device_id; 33 | c->port = port; 34 | c->battery_level = 5; 35 | 36 | // init endpoints and stuff 37 | SceUsbdEndpointDescriptor *endpoint; 38 | #if defined(DEBUG) 39 | ksceDebugPrintf("scanning endpoints for device %d\n", device_id); 40 | #endif 41 | endpoint = (SceUsbdEndpointDescriptor *)ksceUsbdScanStaticDescriptor(device_id, 0, SCE_USBD_DESCRIPTOR_ENDPOINT); 42 | while (endpoint) 43 | { 44 | #if defined(DEBUG) 45 | ksceDebugPrintf("got EP: %02x\n", endpoint->bEndpointAddress); 46 | #endif 47 | if ((endpoint->bEndpointAddress & SCE_USBD_ENDPOINT_DIRECTION_BITS) == SCE_USBD_ENDPOINT_DIRECTION_IN) 48 | { 49 | #if defined(DEBUG) 50 | ksceDebugPrintf("opening in pipe\n"); 51 | #endif 52 | c->pipe_in = ksceUsbdOpenPipe(device_id, endpoint); 53 | #if defined(DEBUG) 54 | ksceDebugPrintf("= 0x%08x\n", c->pipe_in); 55 | ksceDebugPrintf("bmAttributes = %x\n", endpoint->bmAttributes); 56 | #endif 57 | } 58 | else if ((endpoint->bEndpointAddress & SCE_USBD_ENDPOINT_DIRECTION_BITS) == SCE_USBD_ENDPOINT_DIRECTION_OUT) 59 | { 60 | #if defined(DEBUG) 61 | ksceDebugPrintf("opening out pipe\n"); 62 | #endif 63 | c->pipe_out = ksceUsbdOpenPipe(device_id, endpoint); 64 | #if defined(DEBUG) 65 | ksceDebugPrintf("= 0x%08x\n", c->pipe_out); 66 | ksceDebugPrintf("bmAttributes = %x\n", endpoint->bmAttributes); 67 | #endif 68 | } 69 | 70 | if (c->pipe_in > 0 && c->pipe_out > 0) 71 | break; 72 | 73 | endpoint 74 | = (SceUsbdEndpointDescriptor *)ksceUsbdScanStaticDescriptor(device_id, endpoint, SCE_USBD_DESCRIPTOR_ENDPOINT); 75 | } 76 | 77 | if (c->pipe_in > 0 && c->pipe_out > 0) 78 | { 79 | SceUsbdConfigurationDescriptor *cdesc; 80 | if ((cdesc = (SceUsbdConfigurationDescriptor *)ksceUsbdScanStaticDescriptor(device_id, NULL, 81 | SCE_USBD_DESCRIPTOR_CONFIGURATION)) 82 | == NULL) 83 | return 0; 84 | 85 | SceUID control_pipe_id = ksceUsbdOpenPipe(device_id, NULL); 86 | c->pipe_control = control_pipe_id; 87 | // set default config 88 | int r = ksceUsbdSetConfiguration(control_pipe_id, cdesc->bConfigurationValue, &oncontrol, NULL); 89 | #if defined(DEBUG) 90 | ksceDebugPrintf("ksceUsbdSetConfiguration = 0x%08x\n", r); 91 | #endif 92 | if (r < 0) 93 | return 0; 94 | c->attached = 1; 95 | c->inited = 1; 96 | } 97 | 98 | // init command 99 | // TODO: use eventflag? 100 | ksceKernelDelayThread(500000); 101 | uint8_t cmd[] __attribute__((aligned(64))) 102 | = {0x42, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 103 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 106 | 107 | SceUsbdDeviceRequest _dr; 108 | _dr.bmRequestType = 0x21; 109 | _dr.bRequest = HID_SET_REPORT; 110 | _dr.wValue = 0x03F4; 111 | _dr.wIndex = 0; 112 | _dr.wLength = 4; 113 | ksceUsbdControlTransfer(c->pipe_control, (&_dr), (uint8_t *)&cmd, &oncontrol, NULL); 114 | 115 | // TODO: use eventflag? 116 | ksceKernelDelayThread(500000); 117 | DS3Controller_setLed(c, port + 1); 118 | 119 | usb_read(c); 120 | return 1; 121 | } 122 | 123 | void DS3Controller_setRumble(Controller *c, uint8_t small, uint8_t large) 124 | { 125 | uint8_t cmd[] __attribute__((aligned(64))) = {0x00, 0xFE, small > 0 ? 0x01 : 0x00, 126 | 0xFE, large, // rumble values 127 | 0x00, 0x00, 0x00, 128 | 0x00, 0x03, // 0x10=LED1 .. 0x02=LED4 129 | 0xff, 0x27, 0x10, 130 | 0x00, 0x32, // LED 4 131 | 0xff, 0x27, 0x10, 132 | 0x00, 0x32, // LED 3 133 | 0xff, 0x27, 0x10, 134 | 0x00, 0x32, // LED 2 135 | 0xff, 0x27, 0x10, 136 | 0x00, 0x32, // LED 1 137 | 0x00, 0x00, 0x00, 138 | 0x00, 0x00, 0x00, 139 | 0x00, 0x00, 0x00, 140 | 0x00, 0x00, 0x00, 141 | 0x00, 0x00, 0x00, 142 | 0x00, 0x00, 0x00, 143 | 0x00, 0x00, 0x00, 144 | 0x00, 0x00, 0x00, 145 | 0x00, 0x00, 0x00, 146 | 0x00, 0x00, 0x00, 147 | 0x00, 0x00, 0x00, 148 | 0x00}; 149 | 150 | SceUsbdDeviceRequest _dr; 151 | _dr.bmRequestType = 0x21; 152 | _dr.bRequest = HID_SET_REPORT; 153 | _dr.wValue = (HID_REPORT_TYPE_OUTPUT << 8) | 0x01; 154 | _dr.wIndex = 0; 155 | _dr.wLength = sizeof(cmd); 156 | int ret = ksceUsbdControlTransfer(c->pipe_control, (&_dr), (uint8_t *)&cmd, NULL, NULL); 157 | } 158 | 159 | void DS3Controller_setLed(Controller *c, uint8_t led) 160 | { 161 | uint8_t cmd[] __attribute__((aligned(64))) 162 | = {0x00, 0x00, 0x00, 0x00, 0x00, // rumble values 163 | 0x00, 0x00, 0x00, 0x00, 0x01 << led, // 0x10=LED1 .. 0x02=LED4 164 | 0xff, 0x27, 0x10, 0x00, 0x32, // LED 4 165 | 0xff, 0x27, 0x10, 0x00, 0x32, // LED 3 166 | 0xff, 0x27, 0x10, 0x00, 0x32, // LED 2 167 | 0xff, 0x27, 0x10, 0x00, 0x32, // LED 1 168 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 170 | 171 | SceUsbdDeviceRequest _dr; 172 | _dr.bmRequestType = 0x21; 173 | _dr.bRequest = HID_SET_REPORT; 174 | _dr.wValue = (HID_REPORT_TYPE_OUTPUT << 8) | 0x01; 175 | _dr.wIndex = 0; 176 | _dr.wLength = sizeof(cmd); 177 | ksceUsbdControlTransfer(c->pipe_control, (&_dr), (uint8_t *)&cmd, &oncontrol, NULL); 178 | } 179 | 180 | uint8_t DS3Controller_processReport(Controller *c, size_t length) 181 | { 182 | DS3Report report; 183 | 184 | report.select = bit(c->buffer + 2, 0); 185 | report.l3 = bit(c->buffer + 2, 1); 186 | report.r3 = bit(c->buffer + 2, 2); 187 | report.start = bit(c->buffer + 2, 3); 188 | 189 | report.dpad_up = bit(c->buffer + 2, 4); 190 | report.dpad_right = bit(c->buffer + 2, 5); 191 | report.dpad_down = bit(c->buffer + 2, 6); 192 | report.dpad_left = bit(c->buffer + 2, 7); 193 | 194 | report.l2 = bit(c->buffer + 3, 0); 195 | report.r2 = bit(c->buffer + 3, 1); 196 | report.l1 = bit(c->buffer + 3, 2); 197 | report.r1 = bit(c->buffer + 3, 3); 198 | 199 | report.triangle = bit(c->buffer + 3, 4); 200 | report.circle = bit(c->buffer + 3, 5); 201 | report.cross = bit(c->buffer + 3, 6); 202 | report.square = bit(c->buffer + 3, 7); 203 | 204 | report.ps = bit(c->buffer + 4, 0); 205 | 206 | report.x1 = c->buffer[6]; 207 | report.y1 = c->buffer[7]; 208 | report.x2 = c->buffer[8]; 209 | report.y2 = c->buffer[9]; 210 | 211 | report.l2a = c->buffer[18]; 212 | report.r2a = c->buffer[19]; 213 | 214 | c->controlData.buttons = 0; 215 | 216 | if (report.cross) 217 | c->controlData.buttons |= SCE_CTRL_CROSS; 218 | if (report.circle) 219 | c->controlData.buttons |= SCE_CTRL_CIRCLE; 220 | if (report.triangle) 221 | c->controlData.buttons |= SCE_CTRL_TRIANGLE; 222 | if (report.square) 223 | c->controlData.buttons |= SCE_CTRL_SQUARE; 224 | 225 | if (report.dpad_up) 226 | c->controlData.buttons |= SCE_CTRL_UP; 227 | if (report.dpad_down) 228 | c->controlData.buttons |= SCE_CTRL_DOWN; 229 | if (report.dpad_left) 230 | c->controlData.buttons |= SCE_CTRL_LEFT; 231 | if (report.dpad_right) 232 | c->controlData.buttons |= SCE_CTRL_RIGHT; 233 | 234 | if (report.l1) 235 | c->controlData.buttons |= SCE_CTRL_L1; 236 | if (report.r1) 237 | c->controlData.buttons |= SCE_CTRL_R1; 238 | if (report.l3) 239 | c->controlData.buttons |= SCE_CTRL_L3; 240 | if (report.r3) 241 | c->controlData.buttons |= SCE_CTRL_R3; 242 | 243 | if (report.l2) 244 | c->controlData.buttons |= SCE_CTRL_LTRIGGER; 245 | if (report.r2) 246 | c->controlData.buttons |= SCE_CTRL_RTRIGGER; 247 | 248 | if (report.start) 249 | c->controlData.buttons |= SCE_CTRL_START; 250 | if (report.select) 251 | c->controlData.buttons |= SCE_CTRL_SELECT; 252 | if (report.ps) 253 | c->controlData.buttons |= SCE_CTRL_PSBUTTON; 254 | 255 | c->controlData.leftX = report.x1; // / 256 + 128; 256 | c->controlData.leftY = report.y1; // / 256 + 128; 257 | c->controlData.rightX = report.x2; // / 256 + 128; 258 | c->controlData.rightY = report.y2; // / 256 + 128; 259 | 260 | c->controlData.lt = report.l2a; 261 | c->controlData.rt = report.r2a; 262 | return 1; 263 | } 264 | -------------------------------------------------------------------------------- /src/devicelist.c: -------------------------------------------------------------------------------- 1 | #include "devicelist.h" 2 | 3 | gamepad_t _devices[] = {{PAD_XBOX360, 0x045e, 0x028e}, // Microsoft X-Box 360 pad 4 | {PAD_XBOX360, 0x045e, 0x028f}, // Microsoft X-Box 360 pad v2 5 | {PAD_XBOX360, 0x0738, 0x4716}, // Mad Catz Wired Xbox 360 Controller 6 | {PAD_XBOX360, 0x0738, 0x4726}, // Mad Catz Xbox 360 Controller 7 | {PAD_XBOX360, 0x0738, 0x4728}, // Mad Catz Street Fighter IV FightPad 8 | {PAD_XBOX360, 0x0738, 0x4740}, // Mad Catz Beat Pad 9 | {PAD_XBOX360, 0x0738, 0xb726}, // Mad Catz Xbox controller - MW2 10 | {PAD_XBOX360, 0x0738, 0xf738}, // Super SFIV FightStick TE S 11 | {PAD_XBOX360, 0x0738, 0x4718}, // Mad Catz Street Fighter IV FightStick SE 12 | {PAD_XBOX360, 0x0738, 0x4738}, // Mad Catz Wired Xbox 360 Controller (SFIV) 13 | {PAD_XBOX360, 0x0738, 0xbeef}, // Mad Catz JOYTECH NEO SE Advanced GamePad 14 | {PAD_XBOX360, 0x0f0d, 0x000a}, // Hori Co. DOA4 FightStick 15 | {PAD_XBOX360, 0x0f0d, 0x000d}, // Hori Fighting Stick EX2 16 | {PAD_XBOX360, 0x0f0d, 0x0016}, // Hori Real Arcade Pro.EX 17 | {PAD_XBOX360, 0x056e, 0x2004}, // Elecom JC-U3613M 18 | {PAD_XBOX360, 0x24c6, 0x5501}, // Hori Real Arcade Pro VX-SA 19 | {PAD_XBOX360, 0x24c6, 0x5303}, // Xbox Airflo wired controller 20 | {PAD_XBOX360, 0x24c6, 0x531a}, // PowerA Pro Ex 21 | {PAD_XBOX360, 0x24c6, 0x5397}, // FUS1ON Tournament Controller 22 | {PAD_XBOX360, 0x24c6, 0x5503}, // Hori Fighting Edge 23 | {PAD_XBOX360, 0x24c6, 0x550d}, // Hori GEM Xbox controller 24 | {PAD_XBOX360, 0x24c6, 0x5b03}, // Thrustmaster Ferrari 458 Racing Wheel 25 | {PAD_XBOX360, 0x162e, 0xbeef}, // Joytech Neo-Se Take2 26 | {PAD_XBOX360, 0x044f, 0xb326}, // Thrustmaster Gamepad GP XID 27 | {PAD_XBOX360, 0x046d, 0xc21d}, // Logitech Gamepad F310 28 | {PAD_XBOX360, 0x046d, 0xc21e}, // Logitech Gamepad F510 29 | {PAD_XBOX360, 0x046d, 0xc21f}, // Logitech Gamepad F710 30 | {PAD_XBOX360, 0x046d, 0xc242}, // Logitech Chillstream Controller 31 | {PAD_XBOX360, 0x0738, 0xcb03}, // Saitek P3200 Rumble Pad - PC/Xbox 360 32 | {PAD_XBOX360, 0x0738, 0xcb02}, // Saitek Cyborg Rumble Pad - PC/Xbox 360 33 | {PAD_XBOX360, 0x0e6f, 0x0201}, // Pelican PL-3601 'TSZ' Wired Xbox 360 Controller 34 | {PAD_XBOX360, 0x0e6f, 0x0105}, // HSM3 Xbox360 dancepad 35 | {PAD_XBOX360, 0x0e6f, 0x0113}, // Afterglow AX.1 Gamepad for Xbox 360 36 | {PAD_XBOX360, 0x0e6f, 0x0413}, // Afterglow AX.1 Gamepad for Xbox 360 37 | {PAD_XBOX360, 0x0e6f, 0x0213}, // Afterglow Gamepad for Xbox 360 38 | {PAD_XBOX360, 0x0e6f, 0x0401}, // Logic3 Controller 39 | {PAD_XBOX360, 0x0e6f, 0x0301}, // Logic3 Controller 40 | {PAD_XBOX360, 0x12ab, 0x0301}, // PDP AFTERGLOW AX.1 41 | {PAD_XBOX360, 0x1430, 0x4748}, // RedOctane Guitar Hero X-plorer 42 | {PAD_XBOX360, 0x146b, 0x0601}, // BigBen Interactive XBOX 360 Controller 43 | {PAD_XBOX360, 0x1bad, 0x0002}, // Harmonix Guitar for Xbox 360 44 | {PAD_XBOX360, 0x1bad, 0x0003}, // Harmonix Drum Kit for Xbox 360 45 | {PAD_XBOX360, 0x1bad, 0xf016}, // Mad Catz Xbox 360 Controller 46 | {PAD_XBOX360, 0x1bad, 0xf018}, // Mad Catz Street Fighter IV SE Fighting Stick 47 | {PAD_XBOX360, 0x1bad, 0xf021}, // Mad Cats Ghost Recon FS GamePad 48 | {PAD_XBOX360, 0x1bad, 0xf023}, // MLG Pro Circuit Controller (Xbox) 49 | {PAD_XBOX360, 0x1bad, 0xf028}, // Street Fighter IV FightPad 50 | {PAD_XBOX360, 0x1bad, 0xf02e}, // Mad Catz Fightpad 51 | {PAD_XBOX360, 0x1bad, 0xf038}, // Street Fighter IV FightStick TE 52 | {PAD_XBOX360, 0x1bad, 0xf03a}, // Mad Catz SFxT Fightstick Pro 53 | {PAD_XBOX360, 0x1bad, 0xf900}, // Harmonix Xbox 360 Controller 54 | {PAD_XBOX360, 0x1bad, 0xf901}, // Gamestop Xbox 360 Controller 55 | {PAD_XBOX360, 0x1bad, 0xf903}, // Tron Xbox 360 controller 56 | {PAD_XBOX360, 0x1bad, 0xfa01}, // MadCatz GamePad 57 | {PAD_XBOX360, 0x15e4, 0x3f00}, // Power A Mini Pro Elite 58 | {PAD_XBOX360, 0x15e4, 0x3f10}, // Batarang Xbox 360 controller 59 | {PAD_XBOX360, 0x24c6, 0x5000}, // Razer Atrox Arcade Stick 60 | {PAD_XBOX360, 0x1689, 0xfd00}, // Razer Onza Tournament Edition 61 | {PAD_XBOX360, 0x1689, 0xfd01}, // Razer Onza Classic Edition 62 | {PAD_XBOX360, 0x1532, 0x0037}, // Razer Sabertooth 63 | {PAD_XBOX360, 0x12ab, 0x0004}, // Honey Bee Xbox360 dancepad 64 | {PAD_XBOX360, 0x15e4, 0x3f0a}, // Xbox Airflo wired controller 65 | {PAD_XBOX360, 0x24c6, 0x5300}, // PowerA MINI PROEX Controller 66 | {PAD_XBOX360, 0x24c6, 0x5500}, // Hori XBOX 360 EX 2 with Turbo 67 | {PAD_XBOX360, 0x24c6, 0x5506}, // Hori SOULCALIBUR V Stick 68 | {PAD_XBOX360, 0x24c6, 0x5b02}, // Thrustmaster, Inc. GPX Controller 69 | {PAD_XBOX360, 0x24c6, 0x5d04}, // Razer Sabertooth 70 | {PAD_XBOX360, 0x0e6f, 0x011f}, // Rock Candy Gamepad Wired Controller 71 | {PAD_XBOX360, 0x0e6f, 0x021f}, // Rock Candy Gamepad for Xbox 360 72 | {PAD_XBOX360W, 0x045e, 0x0719}, // Xbox 360 Wireless Receiver 73 | {PAD_XBOX360W, 0x045e, 0x0291}, // Xbox 360 Wireless Receiver (xbox) 74 | {PAD_XBOX360, 0x045e, 0x02a1}, // Open-Frame1 75 | 76 | {PAD_XBOX, 0x0d2f, 0x0002}, // Andamiro Pump It Up pad 77 | {PAD_XBOX, 0x045e, 0x0202}, // Microsoft X-Box pad v1 (US) 78 | {PAD_XBOX, 0x045e, 0x0285}, // Microsoft X-Box pad (Japan) 79 | {PAD_XBOX, 0x045e, 0x0287}, // Microsoft Xbox Controller S 80 | {PAD_XBOX, 0x045e, 0x0289}, // Microsoft X-Box pad v2 (US) 81 | {PAD_XBOX, 0x046d, 0xca84}, // Logitech Xbox Cordless Controller 82 | {PAD_XBOX, 0x046d, 0xca88}, // Logitech Compact Controller for Xbox 83 | {PAD_XBOX, 0x05fd, 0x1007}, // Mad Catz Controller (unverified) 84 | {PAD_XBOX, 0x05fd, 0x107a}, // InterAct 'PowerPad Pro' X-Box pad (Germany) 85 | {PAD_XBOX, 0x0738, 0x4516}, // Mad Catz Control Pad 86 | {PAD_XBOX, 0x0738, 0x4522}, // Mad Catz LumiCON 87 | {PAD_XBOX, 0x0738, 0x4526}, // Mad Catz Control Pad Pro 88 | {PAD_XBOX, 0x0738, 0x4536}, // Mad Catz MicroCON 89 | {PAD_XBOX, 0x0738, 0x4556}, // Mad Catz Lynx Wireless Controller 90 | {PAD_XBOX, 0x0c12, 0x8802}, // Zeroplus Xbox Controller 91 | {PAD_XBOX, 0x0c12, 0x8810}, // Zeroplus Xbox Controller 92 | {PAD_XBOX, 0x0c12, 0x9902}, // HAMA VibraX - *FAULTY HARDWARE* 93 | {PAD_XBOX, 0x0e4c, 0x1097}, // Radica Gamester Controller 94 | {PAD_XBOX, 0x0e4c, 0x2390}, // Radica Games Jtech Controller 95 | {PAD_XBOX, 0x0e6f, 0x0003}, // Logic3 Freebird wireless Controller 96 | {PAD_XBOX, 0x0e6f, 0x0005}, // Eclipse wireless Controller 97 | {PAD_XBOX, 0x0e6f, 0x0006}, // Edge wireless Controller 98 | {PAD_XBOX, 0x0e8f, 0x0201}, // SmartJoy Frag Xpad/PS2 adaptor 99 | {PAD_XBOX, 0x0f30, 0x0202}, // Joytech Advanced Controller 100 | {PAD_XBOX, 0x0f30, 0x8888}, // BigBen XBMiniPad Controller 101 | {PAD_XBOX, 0x102c, 0xff0c}, // Joytech Wireless Advanced Controller 102 | {PAD_XBOX, 0x044f, 0x0f07}, // Thrustmaster, Inc. Controller 103 | {PAD_XBOX, 0x0e8f, 0x3008}, // Generic xbox control (dealextreme) 104 | #if defined(WITH_DS3) 105 | {PAD_DS3, 0x054c, 0x0268}, // DS3 wired 106 | #endif 107 | {PAD_DINPUT, 0x046d, 0xc218}, // Logitech F510 Gamepad [DirectInput Mode] / Rumblepad 2 108 | {PAD_DINPUT, 0x046d, 0xc216}, // Logitech F310 Gamepad [DirectInput Mode] / DualAction 109 | {PAD_DINPUT, 0x046d, 0xc20c}, // Logitech Wingman 110 | {PAD_DINPUT, 0x054c, 0x0cda}, // Playstation Classic 111 | {PAD_DINPUT, 0x0f0d, 0x0049}, // Hori ps3 mini diva 112 | {PAD_DINPUT, 0x0f0d, 0x00a6}, // Hori diva X ps3 113 | {PAD_DINPUT, 0x0f0d, 0x00a5}, // Hori diva X ps4 114 | {PAD_DINPUT, 0x0f0d, 0x0101}, // Hori diva FT DX ps4 115 | {PAD_DINPUT, 0x0f0d, 0x0102}, // Hori diva FT DX ps3 116 | {PAD_DINPUT, 0x289b, 0x0044}, // Raphnet Technologies PSX to USB v.1.0 117 | {PAD_DINPUT, 0x0e8f, 0x0003}, // PIII Converter Model: 538 118 | {PAD_DINPUT, 0x0079, 0x1804}, // NES/FC/SFC Joypad TO USB BOX 119 | {PAD_DINPUT, 0x0810, 0x0001}, // Dual PSX Adaptor 120 | {PAD_DINPUT, 0x0810, 0x0003}, // PS2 to PS3 USB 121 | 122 | {PAD_DINPUT, 0x0f0d, 0x0022}, // Brook universal fighting board (ds3 mode, same as hori diva X ds3) 123 | {PAD_DINPUT, 0x0c12, 0x0c30}, // Brook universal fighting board (ds4 mode, same as hori diva X ds4) 124 | 125 | {PAD_DINPUT, 0x12ba, 0x0100}, // Raspberry Pi Pico GH 126 | {PAD_DINPUT, 0x0f0d, 0x0092}, // Raspberry Pi Pico GP2040CE 127 | 128 | {PAD_DINPUT, 0x0b43, 0x0001}, // Smart Joypad 3 adapter 129 | {PAD_DINPUT, 0x0925, 0x1700}, // Mayflash SS 130 | {PAD_DINPUT, 0x1292, 0x4e47}, // NEOGEO X 131 | 132 | {PAD_UNKNOWN, 0x0000, 0x0000}}; // Null 133 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include "controller.h" 2 | #include "controllers/dinput_controller.h" 3 | #include "controllers/ds3_controller.h" 4 | #include "controllers/xbox_360_controller.h" 5 | #include "controllers/xbox_360w_controller.h" 6 | #include "controllers/xbox_controller.h" 7 | #include "devicelist.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #define MAX_CONTROLLERS 4 24 | 25 | #define DECL_FUNC_HOOK(name, ...) \ 26 | static tai_hook_ref_t name##HookRef; \ 27 | static SceUID name##HookUid = -1; \ 28 | static int name##HookFunc(__VA_ARGS__) 29 | 30 | #define BIND_FUNC_OFFSET_HOOK(name, pid, modid, segidx, offset, thumb) \ 31 | name##HookUid = taiHookFunctionOffsetForKernel((pid), &name##HookRef, (modid), (segidx), (offset), thumb, \ 32 | (const void *)name##HookFunc) 33 | 34 | #define BIND_FUNC_EXPORT_HOOK(name, pid, module, lib_nid, func_nid) \ 35 | name##HookUid = taiHookFunctionExportForKernel((pid), &name##HookRef, (module), (lib_nid), (func_nid), \ 36 | (const void *)name##HookFunc) 37 | 38 | #define UNBIND_FUNC_HOOK(name) \ 39 | ({ \ 40 | if (name##HookUid > 0) \ 41 | taiHookReleaseForKernel(name##HookUid, name##HookRef); \ 42 | }) 43 | 44 | static int started = 0; 45 | 46 | static Controller controllers[MAX_CONTROLLERS]; 47 | 48 | static inline int clamp(int value, int min, int max) 49 | { 50 | if (value <= min) 51 | return min; 52 | if (value >= max) 53 | return max; 54 | return value; 55 | } 56 | 57 | DECL_FUNC_HOOK(ksceCtrlGetControllerPortInfo, SceCtrlPortInfo *info) 58 | { 59 | int ret = TAI_CONTINUE(int, ksceCtrlGetControllerPortInfoHookRef, info); 60 | 61 | if (ret >= 0) 62 | { 63 | // Spoof connected controllers to be DualShock 3 controllers 64 | for (int i = 0; i < MAX_CONTROLLERS; i++) 65 | { 66 | if (controllers[i].inited && controllers[i].attached) 67 | { 68 | if (info->port[i + 1] < 3) 69 | info->port[i + 1] = SCE_CTRL_TYPE_DS3; // no touch, so ds3 70 | } 71 | } 72 | } 73 | 74 | return ret; 75 | } 76 | 77 | DECL_FUNC_HOOK(sceCtrlGetBatteryInfo, int port, uint8_t *batt) 78 | { 79 | if (port > 0 && controllers[port - 1].attached && controllers[port - 1].inited && controllers[port - 1].type == PAD_XBOX360W) 80 | { 81 | // Override the battery level for connected controllers 82 | uint8_t data; 83 | ksceKernelMemcpyUserToKernel(&data, (void *)batt, sizeof(uint8_t)); 84 | data = controllers[port - 1].battery_level; 85 | ksceKernelMemcpyKernelToUser((void *)batt, &data, sizeof(uint8_t)); 86 | return 0; 87 | } 88 | 89 | return TAI_CONTINUE(int, sceCtrlGetBatteryInfoHookRef, port, batt); 90 | } 91 | 92 | DECL_FUNC_HOOK(sceCtrlSetActuator, int port, const SceCtrlActuator *pState) 93 | { 94 | if (port > 0 && controllers[port - 1].attached && controllers[port - 1].inited) 95 | { 96 | SceCtrlActuator lpState; 97 | ksceKernelMemcpyUserToKernel(&lpState, (void *)pState, sizeof(SceCtrlActuator)); 98 | switch (controllers[port - 1].type) 99 | { 100 | case PAD_XBOX360: 101 | Xbox360Controller_setRumble(&controllers[port - 1], lpState.small, lpState.large); 102 | break; 103 | case PAD_DS3: 104 | DS3Controller_setRumble(&controllers[port - 1], lpState.small, lpState.large); 105 | break; 106 | case PAD_XBOX360W: 107 | Xbox360WController_setRumble(&controllers[port - 1], lpState.small, lpState.large); 108 | break; 109 | case PAD_XBOX: 110 | XboxController_setRumble(&controllers[port - 1], lpState.small, lpState.large); 111 | break; 112 | default: 113 | break; 114 | } 115 | return 0; 116 | } 117 | 118 | return TAI_CONTINUE(int, sceCtrlSetActuatorHookRef, port, pState); 119 | } 120 | 121 | DECL_FUNC_HOOK(sceCtrlDisconnect, int port) 122 | { 123 | if (port > 0 && controllers[port - 1].attached && controllers[port - 1].inited) 124 | { 125 | if (controllers[port - 1].type == PAD_XBOX360W) 126 | { 127 | Xbox360WController_turnOff(&controllers[port - 1]); 128 | return 0; 129 | } 130 | } 131 | return TAI_CONTINUE(int, sceCtrlDisconnectHookRef, port); 132 | } 133 | 134 | static void patchControlData(int port, SceCtrlData *data, int count, uint8_t negative, uint8_t triggers_ext) 135 | { 136 | // Use controller 1 data for port 0, or controllers 1-4 for ports 1-4 137 | int cont = (port > 0) ? (port - 1) : 0; 138 | 139 | if (!controllers[cont].inited || !controllers[cont].attached) 140 | return; 141 | 142 | ControlData *controlData = &(controllers[cont].controlData); 143 | 144 | if (port == 0) { // for port 0 use button emulation 145 | uint32_t buttons = 0x00000000; 146 | buttons |= controlData->buttons; 147 | ksceCtrlSetButtonEmulation(0, 0, buttons, buttons, 16); 148 | } 149 | 150 | for (int i = 0; i < count; i++) 151 | { 152 | if (port > 0) 153 | { 154 | // todo: figure-out drift? 155 | // data[i].buttons = (negative ? 0xFFFFFFFF : 0x00000000); 156 | // data[i].lx = data[i].ly = data[i].rx = data[i].ry = 127; 157 | 158 | // Set the button data from the controller, with optional negative logic 159 | if (negative) 160 | data[i].buttons &= ~controlData->buttons; 161 | else 162 | data[i].buttons |= controlData->buttons; 163 | } 164 | 165 | data[i].lt = clamp(data[i].lt + controlData->lt, 0, 255); 166 | data[i].rt = clamp(data[i].rt + controlData->rt, 0, 255); 167 | 168 | // Set the stick data from the controller 169 | data[i].lx = clamp(data[i].lx + controlData->leftX - 127, 0, 255); 170 | data[i].ly = clamp(data[i].ly + controlData->leftY - 127, 0, 255); 171 | data[i].rx = clamp(data[i].rx + controlData->rightX - 127, 0, 255); 172 | data[i].ry = clamp(data[i].ry + controlData->rightY - 127, 0, 255); 173 | } 174 | } 175 | 176 | #define DECL_FUNC_HOOK_CTRL(name, negative, triggers) \ 177 | DECL_FUNC_HOOK(name, int port, SceCtrlData *data, int count) \ 178 | { \ 179 | int ret = TAI_CONTINUE(int, name##HookRef, port, data, count); \ 180 | if (ret >= 0) \ 181 | patchControlData(port, data, count, (negative), (triggers)); \ 182 | return ret; \ 183 | } 184 | 185 | DECL_FUNC_HOOK_CTRL(ksceCtrlPeekBufferPositive, 0, 0) 186 | DECL_FUNC_HOOK_CTRL(ksceCtrlReadBufferPositive, 0, 0) 187 | DECL_FUNC_HOOK_CTRL(ksceCtrlPeekBufferNegative, 1, 0) 188 | DECL_FUNC_HOOK_CTRL(ksceCtrlReadBufferNegative, 1, 0) 189 | DECL_FUNC_HOOK_CTRL(ksceCtrlPeekBufferPositiveExt, 0, 0) 190 | DECL_FUNC_HOOK_CTRL(ksceCtrlReadBufferPositiveExt, 0, 0) 191 | 192 | DECL_FUNC_HOOK_CTRL(ksceCtrlPeekBufferPositive2, 0, 1) 193 | DECL_FUNC_HOOK_CTRL(ksceCtrlReadBufferPositive2, 0, 1) 194 | DECL_FUNC_HOOK_CTRL(ksceCtrlPeekBufferNegative2, 1, 1) 195 | DECL_FUNC_HOOK_CTRL(ksceCtrlReadBufferNegative2, 1, 1) 196 | DECL_FUNC_HOOK_CTRL(ksceCtrlPeekBufferPositiveExt2, 0, 1) 197 | DECL_FUNC_HOOK_CTRL(ksceCtrlReadBufferPositiveExt2, 0, 1) 198 | 199 | int libvixen_probe(int device_id); 200 | int libvixen_attach(int device_id); 201 | int libvixen_detach(int device_id); 202 | 203 | static const SceUsbdDriver libvixenDriver = { 204 | .name = "libvixen", 205 | .probe = libvixen_probe, 206 | .attach = libvixen_attach, 207 | .detach = libvixen_detach, 208 | }; 209 | 210 | int libvixen_usbcharge_probe(int device_id) { return SCE_USBD_PROBE_FAILED; } 211 | int libvixen_usbcharge_attach(int device_id) { return SCE_USBD_PROBE_FAILED; } 212 | int libvixen_usbcharge_detach(int device_id) { return SCE_USBD_PROBE_FAILED; } 213 | 214 | static const SceUsbdDriver libvixenFakeUsbchargeDriver = { 215 | .name = "usb_charge", 216 | .probe = libvixen_usbcharge_probe, 217 | .attach = libvixen_usbcharge_attach, 218 | .detach = libvixen_usbcharge_detach, 219 | }; 220 | 221 | int libvixen_probe(int device_id) 222 | { 223 | SceUsbdDeviceDescriptor *device; 224 | ksceDebugPrintf("probing device: %x\n", device_id); 225 | device = (SceUsbdDeviceDescriptor *)ksceUsbdScanStaticDescriptor(device_id, 0, SCE_USBD_DESCRIPTOR_DEVICE); 226 | if (device) 227 | { 228 | ksceDebugPrintf("vendor: %04x\n", device->idVendor); 229 | ksceDebugPrintf("product: %04x\n", device->idProduct); 230 | int i; 231 | for (i = 0; _devices[i].type != PAD_UNKNOWN; i++) 232 | { 233 | if (_devices[i].idVendor == device->idVendor && _devices[i].idProduct == device->idProduct) 234 | break; 235 | } 236 | 237 | if (_devices[i].type == PAD_UNKNOWN) 238 | { 239 | // TODO: try generic? 240 | ksceDebugPrintf("Not supported!\n"); 241 | return SCE_USBD_PROBE_FAILED; 242 | } 243 | return SCE_USBD_PROBE_SUCCEEDED; 244 | } 245 | return SCE_USBD_PROBE_FAILED; 246 | } 247 | 248 | int libvixen_attach(int device_id) 249 | { 250 | SceUsbdDeviceDescriptor *device; 251 | ksceDebugPrintf("attaching device: %x\n", device_id); 252 | device = (SceUsbdDeviceDescriptor *)ksceUsbdScanStaticDescriptor(device_id, 0, SCE_USBD_DESCRIPTOR_DEVICE); 253 | if (device) 254 | { 255 | ksceDebugPrintf("vendor: %04x\n", device->idVendor); 256 | ksceDebugPrintf("product: %04x\n", device->idProduct); 257 | int i; 258 | for (i = 0; _devices[i].type != PAD_UNKNOWN; i++) 259 | { 260 | if (_devices[i].idVendor == device->idVendor && _devices[i].idProduct == device->idProduct) 261 | { 262 | ksceDebugPrintf("Found, attaching\n"); 263 | break; 264 | } 265 | } 266 | 267 | if (_devices[i].type == PAD_UNKNOWN) 268 | { 269 | // TODO: try generic? 270 | return SCE_USBD_ATTACH_FAILED; 271 | } 272 | 273 | // wireless takes all 4 ports, sorry 274 | if (_devices[i].type == PAD_XBOX360W) 275 | { 276 | 277 | for (int cont = 0; cont < MAX_CONTROLLERS; cont++) 278 | { 279 | Xbox360WController_probe(&controllers[cont], device_id, cont); 280 | if (!controllers[cont].inited) 281 | { 282 | ksceDebugPrintf("Can't init gamepad (wireless)\n"); 283 | return SCE_USBD_ATTACH_FAILED; 284 | } 285 | } 286 | ksceDebugPrintf("Attached!\n"); 287 | return SCE_USBD_ATTACH_SUCCEEDED; 288 | } 289 | else 290 | { 291 | int cont = -1; 292 | 293 | // find free slot 294 | for (int i = 0; i < MAX_CONTROLLERS; i++) 295 | { 296 | if (!controllers[i].attached || !controllers[i].inited) 297 | { 298 | cont = i; 299 | break; 300 | } 301 | } 302 | 303 | if (cont == -1) 304 | return SCE_USBD_ATTACH_FAILED; 305 | 306 | if (!controllers[cont].attached) 307 | { 308 | switch (_devices[i].type) 309 | { 310 | case PAD_XBOX: 311 | XboxController_probe(&controllers[cont], device_id, cont); 312 | break; 313 | case PAD_XBOX360: 314 | Xbox360Controller_probe(&controllers[cont], device_id, cont); 315 | break; 316 | case PAD_DS3: 317 | DS3Controller_probe(&controllers[cont], device_id, cont); 318 | break; 319 | case PAD_DINPUT: 320 | DinputController_probe(&controllers[cont], device_id, cont, device->idVendor, device->idProduct); 321 | break; 322 | default: 323 | break; 324 | } 325 | 326 | // something gone wrong during usb init 327 | if (!controllers[cont].inited) 328 | { 329 | ksceDebugPrintf("Can't init gamepad (wired)\n"); 330 | return SCE_USBD_ATTACH_FAILED; 331 | } 332 | ksceDebugPrintf("Attached!\n"); 333 | return SCE_USBD_ATTACH_SUCCEEDED; 334 | } 335 | } 336 | } 337 | return SCE_USBD_ATTACH_FAILED; 338 | } 339 | 340 | int libvixen_detach(int device_id) 341 | { 342 | 343 | for (int i = 0; i < MAX_CONTROLLERS; i++) 344 | { 345 | if (controllers[i].inited && controllers[i].device_id == device_id) 346 | { 347 | if (controllers[i].type == PAD_XBOX360W) 348 | { 349 | for (int j = 0; j < MAX_CONTROLLERS; j++) 350 | { 351 | if (controllers[j].inited) 352 | { 353 | controllers[j].attached = 0; 354 | controllers[j].inited = 0; 355 | controllers[i].pipe_in = 0; 356 | controllers[i].pipe_out = 0; 357 | controllers[i].pipe_control = 0; 358 | } 359 | } 360 | } 361 | else 362 | { 363 | controllers[i].attached = 0; 364 | controllers[i].inited = 0; 365 | controllers[i].pipe_in = 0; 366 | controllers[i].pipe_out = 0; 367 | controllers[i].pipe_control = 0; 368 | } 369 | return SCE_USBD_DETACH_SUCCEEDED; 370 | } 371 | } 372 | 373 | return SCE_USBD_DETACH_FAILED; 374 | } 375 | 376 | static int libvixen_sysevent_handler(int resume, int eventid, void *args, void *opt) 377 | { 378 | if (resume && started) 379 | { 380 | if (ksceSblAimgrIsGenuineVITA()) 381 | ksceUsbServMacSelect(2, 0); // re-set host mode 382 | } 383 | else if (started && eventid == 256) 384 | { 385 | // turn off wireless controllers 386 | for (int i = 0; i < MAX_CONTROLLERS; i++) 387 | { 388 | if (controllers[i].attached && controllers[i].type == PAD_XBOX360W) 389 | { 390 | Xbox360WController_turnOff(&controllers[i]); 391 | } 392 | } 393 | } 394 | return 0; 395 | } 396 | 397 | int module_start(SceSize args, void *argp) 398 | { 399 | tai_module_info_t modInfo; 400 | modInfo.size = sizeof(tai_module_info_t); 401 | 402 | for (int i = 0; i < MAX_CONTROLLERS; i++) 403 | { 404 | controllers[i].inited = 0; 405 | controllers[i].attached = 0; 406 | } 407 | 408 | // Hook controller info functions 409 | BIND_FUNC_EXPORT_HOOK(ksceCtrlGetControllerPortInfo, KERNEL_PID, "SceCtrl", TAI_ANY_LIBRARY, 0xF11D0D30); 410 | BIND_FUNC_EXPORT_HOOK(sceCtrlGetBatteryInfo, KERNEL_PID, "SceCtrl", TAI_ANY_LIBRARY, 0x8F9B1CE5); 411 | BIND_FUNC_EXPORT_HOOK(sceCtrlSetActuator, KERNEL_PID, "SceCtrl", TAI_ANY_LIBRARY, 0xDBCAA0C9); 412 | 413 | if (taiGetModuleInfoForKernel(KERNEL_PID, "SceCtrl", &modInfo) < 0) 414 | return SCE_KERNEL_START_FAILED; 415 | 416 | // Hook control data functions 417 | BIND_FUNC_EXPORT_HOOK(ksceCtrlPeekBufferPositive, KERNEL_PID, "SceCtrl", TAI_ANY_LIBRARY, 0xEA1D3A34); 418 | BIND_FUNC_EXPORT_HOOK(ksceCtrlReadBufferPositive, KERNEL_PID, "SceCtrl", TAI_ANY_LIBRARY, 0x9B96A1AA); 419 | BIND_FUNC_EXPORT_HOOK(ksceCtrlPeekBufferNegative, KERNEL_PID, "SceCtrl", TAI_ANY_LIBRARY, 0x19895843); 420 | BIND_FUNC_EXPORT_HOOK(ksceCtrlReadBufferNegative, KERNEL_PID, "SceCtrl", TAI_ANY_LIBRARY, 0x8D4E0DD1); 421 | BIND_FUNC_OFFSET_HOOK(ksceCtrlPeekBufferPositiveExt, KERNEL_PID, modInfo.modid, 0, 0x3928 | 1, 1); 422 | BIND_FUNC_OFFSET_HOOK(ksceCtrlReadBufferPositiveExt, KERNEL_PID, modInfo.modid, 0, 0x3BCC | 1, 1); 423 | 424 | // Hook extended control data functions 425 | BIND_FUNC_OFFSET_HOOK(ksceCtrlPeekBufferPositive2, KERNEL_PID, modInfo.modid, 0, 0x3EF8 | 1, 1); 426 | BIND_FUNC_OFFSET_HOOK(ksceCtrlReadBufferPositive2, KERNEL_PID, modInfo.modid, 0, 0x449C | 1, 1); 427 | BIND_FUNC_OFFSET_HOOK(ksceCtrlPeekBufferNegative2, KERNEL_PID, modInfo.modid, 0, 0x41C8 | 1, 1); 428 | BIND_FUNC_OFFSET_HOOK(ksceCtrlReadBufferNegative2, KERNEL_PID, modInfo.modid, 0, 0x47F0 | 1, 1); 429 | BIND_FUNC_OFFSET_HOOK(ksceCtrlPeekBufferPositiveExt2, KERNEL_PID, modInfo.modid, 0, 0x4B48 | 1, 1); 430 | BIND_FUNC_OFFSET_HOOK(ksceCtrlReadBufferPositiveExt2, KERNEL_PID, modInfo.modid, 0, 0x4E14 | 1, 1); 431 | 432 | BIND_FUNC_EXPORT_HOOK(sceCtrlDisconnect, KERNEL_PID, "SceCtrl", TAI_ANY_LIBRARY, 0x16D26DC7); 433 | 434 | started = 1; 435 | 436 | if (ksceSblAimgrIsGenuineVITA()) 437 | { 438 | ksceUsbServMacSelect(2, 0); 439 | } 440 | 441 | int ret_drv = ksceUsbdRegisterDriver(&libvixenDriver); 442 | ksceDebugPrintf("ksceUsbdRegisterDriver = 0x%08x\n", ret_drv); 443 | 444 | // remove sony usb_charge driver that intercepts HID devices 445 | ret_drv = ksceUsbdUnregisterDriver(&libvixenFakeUsbchargeDriver); 446 | ksceDebugPrintf("ksceUsbdUnregisterDriver = 0x%08x\n", ret_drv); 447 | 448 | ksceKernelRegisterSysEventHandler("zvixen_sysevent", libvixen_sysevent_handler, NULL); 449 | 450 | return SCE_KERNEL_START_SUCCESS; 451 | } 452 | 453 | int module_stop(SceSize args, void *argp) 454 | { 455 | // Unhook controller info functions 456 | UNBIND_FUNC_HOOK(ksceCtrlGetControllerPortInfo); 457 | UNBIND_FUNC_HOOK(sceCtrlGetBatteryInfo); 458 | UNBIND_FUNC_HOOK(sceCtrlSetActuator); 459 | UNBIND_FUNC_HOOK(sceCtrlDisconnect); 460 | 461 | // Unhook control data functions 462 | UNBIND_FUNC_HOOK(ksceCtrlReadBufferNegative); 463 | UNBIND_FUNC_HOOK(ksceCtrlPeekBufferPositive); 464 | UNBIND_FUNC_HOOK(ksceCtrlReadBufferPositive); 465 | UNBIND_FUNC_HOOK(ksceCtrlPeekBufferNegative); 466 | UNBIND_FUNC_HOOK(ksceCtrlPeekBufferPositiveExt); 467 | UNBIND_FUNC_HOOK(ksceCtrlReadBufferPositiveExt); 468 | 469 | // Unhook extended control data functions 470 | UNBIND_FUNC_HOOK(ksceCtrlPeekBufferPositive2); 471 | UNBIND_FUNC_HOOK(ksceCtrlReadBufferPositive2); 472 | UNBIND_FUNC_HOOK(ksceCtrlPeekBufferNegative2); 473 | UNBIND_FUNC_HOOK(ksceCtrlReadBufferNegative2); 474 | UNBIND_FUNC_HOOK(ksceCtrlPeekBufferPositiveExt2); 475 | UNBIND_FUNC_HOOK(ksceCtrlReadBufferPositiveExt2); 476 | 477 | return SCE_KERNEL_STOP_SUCCESS; 478 | } 479 | 480 | void _start() 481 | { 482 | module_start(0, NULL); 483 | } 484 | --------------------------------------------------------------------------------