├── CMakeLists.txt ├── README.md ├── ds3vita.yml ├── log.c ├── log.h └── main.c /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | set(CMAKE_SYSTEM_NAME "Generic") 4 | set(CMAKE_C_COMPILER "arm-vita-eabi-gcc") 5 | set(CMAKE_CXX_COMPILER "arm-vita-eabi-g++") 6 | 7 | project(ds3vita) 8 | 9 | set(CMAKE_C_FLAGS "-Wl,-q -Wall -O3 -std=gnu99") 10 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11 -fno-rtti -fno-exceptions") 11 | 12 | include_directories( 13 | ) 14 | 15 | link_directories( 16 | ${CMAKE_CURRENT_BINARY_DIR} 17 | ) 18 | 19 | option(RELEASE "Release build" OFF) 20 | 21 | if (RELEASE) 22 | add_definitions(-DRELEASE) 23 | endif(RELEASE) 24 | 25 | add_executable(${PROJECT_NAME}.elf 26 | main.c 27 | log.c 28 | ) 29 | 30 | target_link_libraries(${PROJECT_NAME}.elf 31 | m 32 | gcc 33 | taihenForKernel_stub 34 | SceSysclibForDriver_stub 35 | SceSysmemForDriver_stub 36 | SceSysmemForKernel_stub 37 | SceThreadmgrForDriver_stub 38 | SceIofilemgrForDriver_stub 39 | SceBtForDriver_stub 40 | SceKernelSuspendForDriver_stub 41 | SceCtrlForDriver_stub 42 | ) 43 | 44 | set_target_properties(${PROJECT_NAME}.elf 45 | PROPERTIES LINK_FLAGS "-nostdlib" 46 | COMPILE_FLAGS "-D__VITA_KERNEL__" 47 | ) 48 | 49 | add_custom_target(${PROJECT_NAME}.skprx ALL 50 | COMMAND vita-elf-create -e ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}.yml ${PROJECT_NAME}.elf ${PROJECT_NAME}.velf 51 | COMMAND vita-make-fself -c ${PROJECT_NAME}.velf ${PROJECT_NAME}.skprx 52 | ) 53 | add_dependencies(${PROJECT_NAME}.skprx ${PROJECT_NAME}.elf) 54 | 55 | add_custom_target(send 56 | COMMAND curl -T ${PROJECT_NAME}.skprx ftp://$(PSVITAIP):1337/ux0:/data/tai/kplugin.skprx 57 | DEPENDS ${PROJECT_NAME}.skprx 58 | ) 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ds3vita 2 | 3 | **Download**: https://github.com/xerpi/ds3vita/releases 4 | 5 | **Enable the plugin:** 6 | 1. Add ds3vita.skprx to taiHEN's config (ux0:/tai/config.txt): 7 | ``` 8 | *KERNEL 9 | ux0:tai/ds3vita.skprx 10 | ``` 11 | 2. You need to refresh the config.txt by rebooting or through VitaShell. 12 | 13 | **Pairing the controller:** 14 | 1. Download [this](https://web.archive.org/web/20190120201936/http://dancingpixelstudios.com/sixaxis-controller/sixaxispairtool/)) tool (or [this](https://help.ubuntu.com/community/Sixaxis?action=AttachFile&do=get&target=sixpair.c) other one if you want to compile it yourself) 15 | 2. Connect your DS3 or Sixaxis to the PC and open the tool 16 | 3. Introduce the Vita's **MAC address plus 1** to the tool (Settings -> System -> System information) 17 | 18 | **Using it once paired (see above):** 19 | 1. Just press the PS button and it will connect to the Vita 20 | 21 | **Note**: If you use Mai, don't put the plugin inside ux0:/plugins because Mai will load all stuff you put in there... 22 | -------------------------------------------------------------------------------- /ds3vita.yml: -------------------------------------------------------------------------------- 1 | ds3vita: 2 | attributes: 0 3 | version: 4 | major: 1 5 | minor: 1 6 | main: 7 | start: module_start 8 | stop: module_stop 9 | -------------------------------------------------------------------------------- /log.c: -------------------------------------------------------------------------------- 1 | #include "log.h" 2 | #include 3 | 4 | extern int ksceIoMkdir(const char *, int); 5 | 6 | #ifndef RELEASE 7 | static unsigned int log_buf_ptr = 0; 8 | static char log_buf[16 * 1024]; 9 | #endif 10 | 11 | void log_reset() 12 | { 13 | #ifndef RELEASE 14 | SceUID fd = ksceIoOpen(LOG_FILE, 15 | SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 6); 16 | if (fd < 0) 17 | return; 18 | 19 | ksceIoClose(fd); 20 | 21 | memset(log_buf, 0, sizeof(log_buf)); 22 | #endif 23 | } 24 | 25 | void log_write(const char *buffer, size_t length) 26 | { 27 | #ifndef RELEASE 28 | if ((log_buf_ptr + length) >= sizeof(log_buf)) 29 | return; 30 | 31 | memcpy(log_buf + log_buf_ptr, buffer, length); 32 | 33 | log_buf_ptr = log_buf_ptr + length; 34 | #endif 35 | } 36 | 37 | void log_flush() 38 | { 39 | #ifndef RELEASE 40 | ksceIoMkdir(LOG_PATH, 6); 41 | 42 | SceUID fd = ksceIoOpen(LOG_FILE, 43 | SCE_O_WRONLY | SCE_O_CREAT | SCE_O_APPEND, 6); 44 | if (fd < 0) 45 | return; 46 | 47 | ksceIoWrite(fd, log_buf, strlen(log_buf)); 48 | ksceIoClose(fd); 49 | #endif 50 | } 51 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H 2 | #define LOG_H 3 | 4 | #include 5 | #include 6 | 7 | #define LOG_PATH "ux0:dump/" 8 | #define LOG_FILE LOG_PATH "ds3vita_log.txt" 9 | 10 | void log_reset(); 11 | void log_write(const char *buffer, size_t length); 12 | void log_flush(); 13 | 14 | #ifndef RELEASE 15 | # define LOG(...) \ 16 | do { \ 17 | char buffer[256]; \ 18 | snprintf(buffer, sizeof(buffer), ##__VA_ARGS__); \ 19 | log_write(buffer, strlen(buffer)); \ 20 | } while (0) 21 | #else 22 | # define LOG(...) (void)0 23 | #endif 24 | 25 | #define TEST_CALL(f, ...) ({ \ 26 | int ret = f(__VA_ARGS__); \ 27 | LOG(# f " returned 0x%08X\n", ret); \ 28 | ret; \ 29 | }) 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "log.h" 11 | 12 | /* 13 | * Needed by newlib's libm. 14 | */ 15 | int __errno; 16 | 17 | #define DS3_VID 0x054C 18 | #define DS3_PID 0x0268 19 | 20 | #define DS3_JOYSTICK_THRESHOLD 5 21 | #define DS3_TRIGGER_THRESHOLD 1 22 | 23 | #define EVF_EXIT (1 << 0) 24 | 25 | #define abs(x) (((x) < 0) ? -(x) : (x)) 26 | 27 | #define DECL_FUNC_HOOK(name, ...) \ 28 | static tai_hook_ref_t name##_ref; \ 29 | static SceUID name##_hook_uid = -1; \ 30 | static int name##_hook_func(__VA_ARGS__) 31 | #define BIND_FUNC_OFFSET_HOOK(name, pid, modid, segidx, offset, thumb) \ 32 | name##_hook_uid = taiHookFunctionOffsetForKernel((pid), \ 33 | &name##_ref, (modid), (segidx), (offset), thumb, name##_hook_func) 34 | #define BIND_FUNC_EXPORT_HOOK(name, pid, module, lib_nid, func_nid) \ 35 | name##_hook_uid = taiHookFunctionExportForKernel((pid), \ 36 | &name##_ref, (module), (lib_nid), (func_nid), name##_hook_func) 37 | #define UNBIND_FUNC_HOOK(name) \ 38 | do { \ 39 | if (name##_hook_uid > 0) \ 40 | taiHookReleaseForKernel(name##_hook_uid, name##_ref); \ 41 | } while(0) 42 | 43 | struct ds3_input_report { 44 | unsigned char report_id; 45 | unsigned char unk0; 46 | 47 | unsigned char select : 1; 48 | unsigned char l3 : 1; 49 | unsigned char r3 : 1; 50 | unsigned char start : 1; 51 | unsigned char up : 1; 52 | unsigned char right : 1; 53 | unsigned char down : 1; 54 | unsigned char left : 1; 55 | 56 | unsigned char l2 : 1; 57 | unsigned char r2 : 1; 58 | unsigned char l1 : 1; 59 | unsigned char r1 : 1; 60 | unsigned char triangle : 1; 61 | unsigned char circle : 1; 62 | unsigned char cross : 1; 63 | unsigned char square : 1; 64 | 65 | unsigned char ps : 1; 66 | unsigned char not_used : 7; 67 | 68 | unsigned char unk1; 69 | 70 | unsigned char left_x; 71 | unsigned char left_y; 72 | unsigned char right_x; 73 | unsigned char right_y; 74 | 75 | unsigned int unk2; 76 | 77 | unsigned char up_sens; 78 | unsigned char right_sens; 79 | unsigned char down_sens; 80 | unsigned char left_sens; 81 | 82 | unsigned char L2_sens; 83 | unsigned char R2_sens; 84 | unsigned char L1_sens; 85 | unsigned char R1_sens; 86 | 87 | unsigned char triangle_sens; 88 | unsigned char circle_sens; 89 | unsigned char cross_sens; 90 | unsigned char square_sens; 91 | 92 | unsigned short unk3; 93 | unsigned char unk4; 94 | 95 | unsigned char status; 96 | unsigned char power_rating; 97 | unsigned char comm_status; 98 | unsigned int unk5; 99 | unsigned int unk6; 100 | unsigned char unk7; 101 | 102 | unsigned short accel_x; 103 | unsigned short accel_y; 104 | unsigned short accel_z; 105 | 106 | union { 107 | unsigned short gyro_z; 108 | unsigned short roll; 109 | }; 110 | } __attribute__((packed, aligned(32))); 111 | 112 | static SceUID bt_mempool_uid = -1; 113 | static SceUID bt_thread_evflag_uid = -1; 114 | static SceUID bt_thread_uid = -1; 115 | static SceUID bt_cb_uid = -1; 116 | static int bt_thread_run = 1; 117 | 118 | static int ds3_connected = 0; 119 | static unsigned int ds3_mac0 = 0; 120 | static unsigned int ds3_mac1 = 0; 121 | 122 | static struct ds3_input_report ds3_input; 123 | 124 | /*static SceUID SceBt_sub_2292CE4_0x2292D18_patch_uid = -1; 125 | static tai_hook_ref_t SceBt_sub_22999C8_ref;*/ 126 | static SceUID SceBt_sub_22999C8_hook_uid = -1; 127 | static tai_hook_ref_t SceBt_sub_22999C8_ref; 128 | static SceUID SceBt_sub_22947E4_hook_uid = -1; 129 | static tai_hook_ref_t SceBt_sub_22947E4_ref; 130 | 131 | static inline void ds3_input_reset(void) 132 | { 133 | memset(&ds3_input, 0, sizeof(ds3_input)); 134 | } 135 | 136 | static int is_ds3(const unsigned short vid_pid[2]) 137 | { 138 | return vid_pid[0] == DS3_VID && vid_pid[1] == DS3_PID; 139 | } 140 | 141 | static inline void *mempool_alloc(unsigned int size) 142 | { 143 | return ksceKernelAllocHeapMemory(bt_mempool_uid, size); 144 | } 145 | 146 | static inline void mempool_free(void *ptr) 147 | { 148 | ksceKernelFreeHeapMemory(bt_mempool_uid, ptr); 149 | } 150 | 151 | static int ds3_send_report(unsigned int mac0, unsigned int mac1, uint8_t flags, uint8_t report, 152 | size_t len, const void *data) 153 | { 154 | SceBtHidRequest *req; 155 | unsigned char *buf; 156 | 157 | req = mempool_alloc(sizeof(*req)); 158 | if (!req) { 159 | LOG("Error allocatin BT HID Request\n"); 160 | return -1; 161 | } 162 | 163 | if ((buf = mempool_alloc((len + 1) * sizeof(*buf))) == NULL) { 164 | LOG("Memory allocation error (mesg array)\n"); 165 | return -1; 166 | } 167 | 168 | buf[0] = report; 169 | memcpy(buf + 1, data, len); 170 | 171 | memset(req, 0, sizeof(*req)); 172 | req->type = 1; // 0xA2 -> type = 1 173 | req->buffer = buf; 174 | req->length = len + 1; 175 | req->next = req; 176 | 177 | TEST_CALL(ksceBtHidTransfer, mac0, mac1, req); 178 | 179 | mempool_free(buf); 180 | mempool_free(req); 181 | 182 | return 0; 183 | } 184 | 185 | static int ds3_send_feature_report(unsigned int mac0, unsigned int mac1, uint8_t flags, uint8_t report, 186 | size_t len, const void *data) 187 | { 188 | SceBtHidRequest *req; 189 | unsigned char *buf; 190 | 191 | req = mempool_alloc(sizeof(*req)); 192 | if (!req) { 193 | LOG("Error allocatin BT HID Request\n"); 194 | return -1; 195 | } 196 | 197 | if ((buf = mempool_alloc((len + 1) * sizeof(*buf))) == NULL) { 198 | LOG("Memory allocation error (mesg array)\n"); 199 | return -1; 200 | } 201 | 202 | buf[0] = report; 203 | memcpy(buf + 1, data, len); 204 | 205 | memset(req, 0, sizeof(*req)); 206 | req->type = 3; // 0x53 -> type = 3 207 | req->buffer = buf; 208 | req->length = len + 1; 209 | req->next = req; 210 | 211 | TEST_CALL(ksceBtHidTransfer, mac0, mac1, req); 212 | 213 | mempool_free(buf); 214 | mempool_free(req); 215 | 216 | return 0; 217 | } 218 | 219 | 220 | static int ds3_send_leds_rumble(unsigned int mac0, unsigned int mac1) 221 | { 222 | static const unsigned char led_pattern[] = { 223 | 0x0, 0x02, 0x04, 0x08, 0x10, 0x12, 0x14, 0x18, 0x1A, 0x1C, 0x1E 224 | }; 225 | 226 | unsigned char buf[] = { 227 | 0x01, 228 | 0x00, //Padding 229 | 0x00, 0x00, 0x00, 0x00, //Rumble (r, r, l, l) 230 | 0x00, 0x00, 0x00, 0x00, //Padding 231 | 0x00, /* LED_1 = 0x02, LED_2 = 0x04, ... */ 232 | 0xff, 0x27, 0x10, 0x00, 0x32, /* LED_4 */ 233 | 0xff, 0x27, 0x10, 0x00, 0x32, /* LED_3 */ 234 | 0xff, 0x27, 0x10, 0x00, 0x32, /* LED_2 */ 235 | 0xff, 0x27, 0x10, 0x00, 0x32, /* LED_1 */ 236 | 0x00, 0x00, 0x00, 0x00, 0x00 /* LED_5 (not soldered) */ 237 | }; 238 | 239 | buf[8] = led_pattern[1]; /* Turn on LED 1 */ 240 | 241 | if (ds3_send_report(mac0, mac1, 0, 0x01, sizeof(buf), buf)) { 242 | LOG("Send report error\n"); 243 | return -1; 244 | } 245 | 246 | return 0; 247 | } 248 | 249 | static int ds3_set_operational(unsigned int mac0, unsigned int mac1) 250 | { 251 | unsigned char data[] = { 252 | 0x42, 0x03, 0x00, 0x00 253 | }; 254 | 255 | if (ds3_send_feature_report(mac0, mac1, 0, 0xF4, sizeof(data), data)) { 256 | LOG("Set operational error\n"); 257 | return -1; 258 | } 259 | 260 | return 0; 261 | } 262 | 263 | 264 | DECL_FUNC_HOOK(SceCtrl_ksceCtrlGetControllerPortInfo, SceCtrlPortInfo *info) 265 | { 266 | int ret = TAI_CONTINUE(int, SceCtrl_ksceCtrlGetControllerPortInfo_ref, info); 267 | 268 | if (ret >= 0 && ds3_connected) { 269 | // info->port[0] |= SCE_CTRL_TYPE_VIRT; 270 | info->port[1] = SCE_CTRL_TYPE_DS3; 271 | } 272 | 273 | return ret; 274 | } 275 | 276 | static void patch_ctrl_data(const struct ds3_input_report *ds3, SceCtrlData *pad_data) 277 | { 278 | signed char ldx, ldy, rdx, rdy; 279 | unsigned int buttons = 0; 280 | int left_js_moved = 0; 281 | int right_js_moved = 0; 282 | 283 | if (ds3->cross) 284 | buttons |= SCE_CTRL_CROSS; 285 | if (ds3->circle) 286 | buttons |= SCE_CTRL_CIRCLE; 287 | if (ds3->triangle) 288 | buttons |= SCE_CTRL_TRIANGLE; 289 | if (ds3->square) 290 | buttons |= SCE_CTRL_SQUARE; 291 | 292 | if (ds3->up) 293 | buttons |= SCE_CTRL_UP; 294 | if (ds3->right) 295 | buttons |= SCE_CTRL_RIGHT; 296 | if (ds3->down) 297 | buttons |= SCE_CTRL_DOWN; 298 | if (ds3->left) 299 | buttons |= SCE_CTRL_LEFT; 300 | 301 | if (ds3->l1) 302 | buttons |= SCE_CTRL_LTRIGGER; 303 | if (ds3->r1) 304 | buttons |= SCE_CTRL_RTRIGGER; 305 | 306 | if (ds3->l2) 307 | buttons |= SCE_CTRL_L1; 308 | if (ds3->r2) 309 | buttons |= SCE_CTRL_R1; 310 | 311 | if (ds3->l3) 312 | buttons |= SCE_CTRL_L3; 313 | if (ds3->r3) 314 | buttons |= SCE_CTRL_R3; 315 | 316 | if (ds3->select) 317 | buttons |= SCE_CTRL_SELECT; 318 | if (ds3->start) 319 | buttons |= SCE_CTRL_START; 320 | if (ds3->ps) 321 | buttons |= SCE_CTRL_INTERCEPTED; 322 | 323 | ldx = ds3->left_x - 128; 324 | ldy = ds3->left_y - 128; 325 | rdx = ds3->right_x - 128; 326 | rdy = ds3->right_y - 128; 327 | 328 | if (sqrtf(ldx * ldx + ldy * ldy) > DS3_JOYSTICK_THRESHOLD) 329 | left_js_moved = 1; 330 | 331 | if (sqrtf(rdx * rdx + rdy * rdy) > DS3_JOYSTICK_THRESHOLD) 332 | right_js_moved = 1; 333 | 334 | if (left_js_moved) { 335 | pad_data->lx = ds3->left_x; 336 | pad_data->ly = ds3->left_y; 337 | } 338 | 339 | if (right_js_moved) { 340 | pad_data->rx = ds3->right_x; 341 | pad_data->ry = ds3->right_y; 342 | } 343 | 344 | if (ds3->L2_sens > DS3_TRIGGER_THRESHOLD) 345 | pad_data->lt = ds3->L2_sens; 346 | 347 | if (ds3->R2_sens > DS3_TRIGGER_THRESHOLD) 348 | pad_data->rt = ds3->R2_sens; 349 | 350 | if (ds3->ps) 351 | ksceCtrlSetButtonEmulation(0, 0, 0, SCE_CTRL_INTERCEPTED, 16); 352 | 353 | if (buttons != 0 || left_js_moved || right_js_moved || 354 | ds3->L2_sens > DS3_TRIGGER_THRESHOLD || 355 | ds3->R2_sens > DS3_TRIGGER_THRESHOLD) 356 | ksceKernelPowerTick(0); 357 | 358 | pad_data->buttons |= buttons; 359 | } 360 | 361 | static void patch_ctrl_data_all_user(const struct ds3_input_report *ds3, 362 | int port, SceCtrlData *pad_data, int count) 363 | { 364 | unsigned int i; 365 | 366 | for (i = 0; i < count; i++) { 367 | SceCtrlData k_data; 368 | 369 | ksceKernelMemcpyUserToKernel(&k_data, (uintptr_t)pad_data, sizeof(k_data)); 370 | patch_ctrl_data(ds3, &k_data); 371 | ksceKernelMemcpyKernelToUser((uintptr_t)pad_data, &k_data, sizeof(k_data)); 372 | 373 | pad_data++; 374 | } 375 | } 376 | 377 | static void patch_ctrl_data_all_kernel(const struct ds3_input_report *ds3, 378 | int port, SceCtrlData *pad_data, int count) 379 | { 380 | unsigned int i; 381 | 382 | for (i = 0; i < count; i++, pad_data++) 383 | patch_ctrl_data(ds3, pad_data); 384 | } 385 | 386 | #define DECL_FUNC_HOOK_PATCH_CTRL(type, name) \ 387 | DECL_FUNC_HOOK(SceCtrl_##name, int port, SceCtrlData *pad_data, int count) \ 388 | { \ 389 | int ret = TAI_CONTINUE(int, SceCtrl_ ##name##_ref, port, pad_data, count); \ 390 | if (ret >= 0 && ds3_connected) \ 391 | patch_ctrl_data_all_##type(&ds3_input, port, pad_data, count); \ 392 | return ret; \ 393 | } 394 | 395 | DECL_FUNC_HOOK_PATCH_CTRL(kernel, ksceCtrlPeekBufferNegative) 396 | DECL_FUNC_HOOK_PATCH_CTRL(user, sceCtrlPeekBufferNegative2) 397 | DECL_FUNC_HOOK_PATCH_CTRL(kernel, ksceCtrlPeekBufferPositive) 398 | DECL_FUNC_HOOK_PATCH_CTRL(user, sceCtrlPeekBufferPositive2) 399 | DECL_FUNC_HOOK_PATCH_CTRL(user, sceCtrlPeekBufferPositiveExt) 400 | DECL_FUNC_HOOK_PATCH_CTRL(user, sceCtrlPeekBufferPositiveExt2) 401 | DECL_FUNC_HOOK_PATCH_CTRL(kernel, ksceCtrlReadBufferNegative) 402 | DECL_FUNC_HOOK_PATCH_CTRL(user, sceCtrlReadBufferNegative2) 403 | DECL_FUNC_HOOK_PATCH_CTRL(kernel, ksceCtrlReadBufferPositive) 404 | DECL_FUNC_HOOK_PATCH_CTRL(user, sceCtrlReadBufferPositive2) 405 | DECL_FUNC_HOOK_PATCH_CTRL(user, sceCtrlReadBufferPositiveExt) 406 | DECL_FUNC_HOOK_PATCH_CTRL(user, sceCtrlReadBufferPositiveExt2) 407 | 408 | static void enqueue_read_request(unsigned int mac0, unsigned int mac1, 409 | SceBtHidRequest *request, unsigned char *buffer, 410 | unsigned int length) 411 | { 412 | memset(request, 0, sizeof(*request)); 413 | memset(buffer, 0, length); 414 | 415 | request->type = 0; 416 | request->buffer = buffer; 417 | request->length = length; 418 | request->next = request; 419 | 420 | ksceBtHidTransfer(mac0, mac1, request); 421 | } 422 | 423 | static int SceBt_sub_22999C8_hook_func(void *dev_base_ptr, int r1) 424 | { 425 | unsigned int flags = *(unsigned int *)(r1 + 4); 426 | 427 | if (dev_base_ptr && !(flags & 2)) { 428 | const void *dev_info = *(const void **)(dev_base_ptr + 0x14A4); 429 | const unsigned short *vid_pid = (const unsigned short *)(dev_info + 0x28); 430 | 431 | if (is_ds3(vid_pid)) { 432 | unsigned int *v8_ptr = (unsigned int *)(*(unsigned int *)dev_base_ptr + 8); 433 | 434 | /* 435 | * We need to enable the following bits in order to make the Vita 436 | * accept the new connection, otherwise it will refuse it. 437 | */ 438 | *v8_ptr |= 0x11000; 439 | } 440 | } 441 | 442 | return TAI_CONTINUE(int, SceBt_sub_22999C8_ref, dev_base_ptr, r1); 443 | } 444 | 445 | static void *SceBt_sub_22947E4_hook_func(unsigned int r0, unsigned int r1, unsigned long long r2) 446 | { 447 | void *ret = TAI_CONTINUE(void *, SceBt_sub_22947E4_ref, r0, r1, r2); 448 | 449 | if (ret) { 450 | /* 451 | * We have to enable this bit in order to make the Vita 452 | * accept the controller. 453 | */ 454 | *(unsigned int *)(ret + 0x24) |= 0x1000; 455 | } 456 | 457 | return ret; 458 | } 459 | 460 | static int bt_cb_func(int notifyId, int notifyCount, int notifyArg, void *common) 461 | { 462 | static SceBtHidRequest hid_request; 463 | static unsigned char recv_buff[0x100]; 464 | 465 | while (1) { 466 | int ret; 467 | SceBtEvent hid_event; 468 | 469 | memset(&hid_event, 0, sizeof(hid_event)); 470 | 471 | do { 472 | ret = ksceBtReadEvent(&hid_event, 1); 473 | } while (ret == SCE_BT_ERROR_CB_OVERFLOW); 474 | 475 | if (ret <= 0) { 476 | break; 477 | } 478 | 479 | LOG("->Event:"); 480 | for (int i = 0; i < 0x10; i++) 481 | LOG(" %02X", hid_event.data[i]); 482 | LOG("\n"); 483 | 484 | /* 485 | * If we get an event with a MAC, and the MAC is different 486 | * from the connected DS3, skip the event. 487 | */ 488 | if (ds3_connected) { 489 | if (hid_event.mac0 != ds3_mac0 || hid_event.mac1 != ds3_mac1) 490 | continue; 491 | } 492 | 493 | switch (hid_event.id) { 494 | case 0x01: /* Inquiry result event */ 495 | break; 496 | 497 | case 0x02: /* Inquiry stop event */ 498 | break; 499 | 500 | case 0x04: /* Link key request? event */ 501 | break; 502 | 503 | case 0x05: { /* Connection accepted event */ 504 | unsigned short vid_pid[2] = {0, 0}; 505 | char name[0x79]; 506 | unsigned int result1; 507 | unsigned int result2; 508 | 509 | /* 510 | * Getting the VID/PID or device name of the DS3 511 | * sometimes? returns an error. 512 | */ 513 | 514 | result1 = ksceBtGetVidPid(hid_event.mac0, hid_event.mac1, vid_pid); 515 | result2 = ksceBtGetDeviceName(hid_event.mac0, hid_event.mac1, name); 516 | 517 | if (is_ds3(vid_pid) || (result1 == 0x802F5001 && 518 | result2 == 0x802F0C01)) { 519 | ds3_input_reset(); 520 | ds3_mac0 = hid_event.mac0; 521 | ds3_mac1 = hid_event.mac1; 522 | ds3_connected = 1; 523 | ds3_set_operational(hid_event.mac0, hid_event.mac1); 524 | //ds3_send_leds_rumble(hid_event.mac0, hid_event.mac1); 525 | } 526 | break; 527 | } 528 | 529 | 530 | case 0x06: /* Device disconnect event*/ 531 | ds3_connected = 0; 532 | ds3_input_reset(); 533 | break; 534 | 535 | case 0x08: /* Connection requested event */ 536 | /* 537 | * Do nothing since we will get a 0x05 event afterwards. 538 | */ 539 | break; 540 | 541 | case 0x09: /* Connection request without being paired? event */ 542 | break; 543 | 544 | case 0x0A: /* HID reply to 0-type request */ 545 | 546 | LOG("DS3 0x0A event: 0x%02X\n", recv_buff[0]); 547 | 548 | switch (recv_buff[0]) { 549 | case 0x01: /* Full report */ 550 | /* 551 | * Save DS3 state to a global variable. 552 | */ 553 | memcpy(&ds3_input, recv_buff, sizeof(ds3_input)); 554 | 555 | enqueue_read_request(hid_event.mac0, hid_event.mac1, 556 | &hid_request, recv_buff, sizeof(recv_buff)); 557 | break; 558 | 559 | default: 560 | LOG("Unknown DS3 event: 0x%02X\n", recv_buff[0]); 561 | break; 562 | } 563 | 564 | break; 565 | 566 | case 0x0B: /* HID reply to 1-type request */ 567 | 568 | //LOG("DS3 0x0B event: 0x%02X\n", recv_buff[0]); 569 | 570 | enqueue_read_request(hid_event.mac0, hid_event.mac1, 571 | &hid_request, recv_buff, sizeof(recv_buff)); 572 | 573 | break; 574 | 575 | case 0x0C: /* HID reply to 3-type request? */ 576 | 577 | //LOG("DS3 0x0C event: 0x%02X\n", recv_buff[0]); 578 | 579 | enqueue_read_request(hid_event.mac0, hid_event.mac1, 580 | &hid_request, recv_buff, sizeof(recv_buff)); 581 | 582 | break; 583 | 584 | 585 | } 586 | } 587 | 588 | return 0; 589 | } 590 | 591 | static int ds3vita_bt_thread(SceSize args, void *argp) 592 | { 593 | bt_cb_uid = ksceKernelCreateCallback("ds3vita_bt_callback", 0, bt_cb_func, NULL); 594 | 595 | ksceBtRegisterCallback(bt_cb_uid, 0, 0xFFFFFFFF, 0xFFFFFFFF); 596 | 597 | /*#ifndef RELEASE 598 | ksceBtStartInquiry(); 599 | ksceKernelDelayThreadCB(4 * 1000 * 1000); 600 | ksceBtStopInquiry(); 601 | #endif*/ 602 | 603 | while (bt_thread_run) { 604 | int ret; 605 | unsigned int evf_out; 606 | 607 | ret = ksceKernelWaitEventFlagCB(bt_thread_evflag_uid, EVF_EXIT, 608 | SCE_EVENT_WAITOR | SCE_EVENT_WAITCLEAR_PAT, &evf_out, NULL); 609 | if (ret < 0) 610 | continue; 611 | 612 | if (evf_out & EVF_EXIT) 613 | break; 614 | } 615 | 616 | if (ds3_connected) 617 | ksceBtStartDisconnect(ds3_mac0, ds3_mac1); 618 | 619 | ksceBtUnregisterCallback(bt_cb_uid); 620 | 621 | ksceKernelDeleteCallback(bt_cb_uid); 622 | 623 | return 0; 624 | } 625 | 626 | void _start() __attribute__ ((weak, alias ("module_start"))); 627 | 628 | int module_start(SceSize argc, const void *args) 629 | { 630 | int ret; 631 | tai_module_info_t SceBt_modinfo; 632 | 633 | log_reset(); 634 | 635 | LOG("ds3vita by xerpi\n"); 636 | 637 | SceBt_modinfo.size = sizeof(SceBt_modinfo); 638 | ret = taiGetModuleInfoForKernel(KERNEL_PID, "SceBt", &SceBt_modinfo); 639 | if (ret < 0) { 640 | LOG("Error finding SceBt module\n"); 641 | goto error_find_scebt; 642 | } 643 | 644 | /* SceBt patch */ 645 | /*unsigned short thumb_nop[] = {0x00bf}; 646 | 647 | SceBt_sub_2292CE4_0x2292D18_patch_uid = taiInjectDataForKernel(KERNEL_PID, 648 | SceBt_modinfo.modid, 0, 0x2292D18 - 0x2280000, thumb_nop, sizeof(thumb_nop)); 649 | 650 | LOG("SceBt_sub_2292CE4_0x2292D18_patch_uid: 0x%08X\n", SceBt_sub_2292CE4_0x2292D18_patch_uid);*/ 651 | 652 | /* SceBt hooks */ 653 | SceBt_sub_22999C8_hook_uid = taiHookFunctionOffsetForKernel(KERNEL_PID, 654 | &SceBt_sub_22999C8_ref, SceBt_modinfo.modid, 0, 655 | 0x22999C8 - 0x2280000, 1, SceBt_sub_22999C8_hook_func); 656 | 657 | SceBt_sub_22947E4_hook_uid = taiHookFunctionOffsetForKernel(KERNEL_PID, 658 | &SceBt_sub_22947E4_ref, SceBt_modinfo.modid, 0, 659 | 0x22947E4 - 0x2280000, 1, SceBt_sub_22947E4_hook_func); 660 | 661 | /* Patch PAD Type */ 662 | BIND_FUNC_EXPORT_HOOK(SceCtrl_ksceCtrlGetControllerPortInfo, KERNEL_PID, 663 | "SceCtrl", TAI_ANY_LIBRARY, 0xF11D0D30); 664 | 665 | /* SceCtrl hooks: 666 | * sceCtrlPeekBufferNegative -> ksceCtrlPeekBufferNegative 667 | * sceCtrlPeekBufferNegative2 -> none 668 | * sceCtrlPeekBufferPositive -> ksceCtrlPeekBufferPositive 669 | * sceCtrlPeekBufferPositive2 -> none 670 | * sceCtrlPeekBufferPositiveExt -> none 671 | * sceCtrlPeekBufferPositiveExt2 -> none 672 | * sceCtrlReadBufferNegative -> ksceCtrlReadBufferNegative 673 | * sceCtrlReadBufferNegative2 -> none 674 | * sceCtrlReadBufferPositive -> ksceCtrlReadBufferPositive 675 | * sceCtrlReadBufferPositive2 -> none 676 | * sceCtrlReadBufferPositiveExt -> none 677 | * sceCtrlReadBufferPositiveExt2 -> none 678 | */ 679 | BIND_FUNC_EXPORT_HOOK(SceCtrl_ksceCtrlPeekBufferNegative, KERNEL_PID, 680 | "SceCtrl", TAI_ANY_LIBRARY, 0x19895843); 681 | 682 | BIND_FUNC_EXPORT_HOOK(SceCtrl_sceCtrlPeekBufferNegative2, KERNEL_PID, 683 | "SceCtrl", TAI_ANY_LIBRARY, 0x81A89660); 684 | 685 | BIND_FUNC_EXPORT_HOOK(SceCtrl_ksceCtrlPeekBufferPositive, KERNEL_PID, 686 | "SceCtrl", TAI_ANY_LIBRARY, 0xEA1D3A34); 687 | 688 | BIND_FUNC_EXPORT_HOOK(SceCtrl_sceCtrlPeekBufferPositive2, KERNEL_PID, 689 | "SceCtrl", TAI_ANY_LIBRARY, 0x15F81E8C); 690 | 691 | BIND_FUNC_EXPORT_HOOK(SceCtrl_sceCtrlPeekBufferPositiveExt, KERNEL_PID, 692 | "SceCtrl", TAI_ANY_LIBRARY, 0xA59454D3); 693 | 694 | BIND_FUNC_EXPORT_HOOK(SceCtrl_sceCtrlPeekBufferPositiveExt2, KERNEL_PID, 695 | "SceCtrl", TAI_ANY_LIBRARY, 0x860BF292); 696 | 697 | BIND_FUNC_EXPORT_HOOK(SceCtrl_ksceCtrlReadBufferNegative, KERNEL_PID, 698 | "SceCtrl", TAI_ANY_LIBRARY, 0x8D4E0DD1); 699 | 700 | BIND_FUNC_EXPORT_HOOK(SceCtrl_sceCtrlReadBufferNegative2, KERNEL_PID, 701 | "SceCtrl", TAI_ANY_LIBRARY, 0x27A0C5FB); 702 | 703 | BIND_FUNC_EXPORT_HOOK(SceCtrl_ksceCtrlReadBufferPositive, KERNEL_PID, 704 | "SceCtrl", TAI_ANY_LIBRARY, 0x9B96A1AA); 705 | 706 | BIND_FUNC_EXPORT_HOOK(SceCtrl_sceCtrlReadBufferPositive2, KERNEL_PID, 707 | "SceCtrl", TAI_ANY_LIBRARY, 0xC4226A3E); 708 | 709 | BIND_FUNC_EXPORT_HOOK(SceCtrl_sceCtrlReadBufferPositiveExt, KERNEL_PID, 710 | "SceCtrl", TAI_ANY_LIBRARY, 0xE2D99296); 711 | 712 | BIND_FUNC_EXPORT_HOOK(SceCtrl_sceCtrlReadBufferPositiveExt2, KERNEL_PID, 713 | "SceCtrl", TAI_ANY_LIBRARY, 0xA7178860); 714 | 715 | SceKernelHeapCreateOpt opt; 716 | opt.size = 0x1C; 717 | opt.uselock = 0x100; 718 | opt.field_8 = 0x10000; 719 | opt.field_C = 0; 720 | opt.field_10 = 0; 721 | opt.field_14 = 0; 722 | opt.field_18 = 0; 723 | 724 | bt_mempool_uid = ksceKernelCreateHeap("ds3vita_mempool", 0x100, &opt); 725 | LOG("Bluetooth mempool UID: 0x%08X\n", bt_mempool_uid); 726 | 727 | bt_thread_evflag_uid = ksceKernelCreateEventFlag("ds3vita_bt_thread_evflag", 728 | 0, 0, NULL); 729 | LOG("Bluetooth thread event flag UID: 0x%08X\n", bt_thread_evflag_uid); 730 | 731 | bt_thread_uid = ksceKernelCreateThread("ds3vita_bt_thread", ds3vita_bt_thread, 732 | 0x3C, 0x1000, 0, 0x10000, 0); 733 | LOG("Bluetooth thread UID: 0x%08X\n", bt_thread_uid); 734 | ksceKernelStartThread(bt_thread_uid, 0, NULL); 735 | 736 | LOG("module_start finished successfully!\n"); 737 | 738 | return SCE_KERNEL_START_SUCCESS; 739 | 740 | error_find_scebt: 741 | return SCE_KERNEL_START_FAILED; 742 | } 743 | 744 | int module_stop(SceSize argc, const void *args) 745 | { 746 | SceUInt timeout = 0xFFFFFFFF; 747 | 748 | bt_thread_run = 0; 749 | 750 | if (bt_thread_evflag_uid) 751 | ksceKernelSetEventFlag(bt_thread_evflag_uid, EVF_EXIT); 752 | 753 | if (bt_thread_uid > 0) { 754 | bt_thread_run = 0; 755 | ksceKernelWaitThreadEnd(bt_thread_uid, NULL, &timeout); 756 | ksceKernelDeleteThread(bt_thread_uid); 757 | } 758 | 759 | if (bt_thread_evflag_uid) 760 | ksceKernelDeleteEventFlag(bt_thread_evflag_uid); 761 | 762 | if (bt_mempool_uid > 0) { 763 | ksceKernelDeleteHeap(bt_mempool_uid); 764 | } 765 | 766 | if (SceBt_sub_22999C8_hook_uid > 0) { 767 | taiHookReleaseForKernel(SceBt_sub_22999C8_hook_uid, 768 | SceBt_sub_22999C8_ref); 769 | } 770 | 771 | if (SceBt_sub_22947E4_hook_uid > 0) { 772 | taiHookReleaseForKernel(SceBt_sub_22947E4_hook_uid, 773 | SceBt_sub_22947E4_ref); 774 | } 775 | 776 | UNBIND_FUNC_HOOK(SceCtrl_ksceCtrlGetControllerPortInfo); 777 | 778 | UNBIND_FUNC_HOOK(SceCtrl_ksceCtrlPeekBufferNegative); 779 | UNBIND_FUNC_HOOK(SceCtrl_sceCtrlPeekBufferNegative2); 780 | UNBIND_FUNC_HOOK(SceCtrl_ksceCtrlPeekBufferPositive); 781 | UNBIND_FUNC_HOOK(SceCtrl_sceCtrlPeekBufferPositive2); 782 | UNBIND_FUNC_HOOK(SceCtrl_sceCtrlPeekBufferPositiveExt); 783 | UNBIND_FUNC_HOOK(SceCtrl_sceCtrlPeekBufferPositiveExt2); 784 | UNBIND_FUNC_HOOK(SceCtrl_ksceCtrlReadBufferNegative); 785 | UNBIND_FUNC_HOOK(SceCtrl_sceCtrlReadBufferNegative2); 786 | UNBIND_FUNC_HOOK(SceCtrl_ksceCtrlReadBufferPositive); 787 | UNBIND_FUNC_HOOK(SceCtrl_sceCtrlReadBufferPositive2); 788 | UNBIND_FUNC_HOOK(SceCtrl_sceCtrlReadBufferPositiveExt); 789 | UNBIND_FUNC_HOOK(SceCtrl_sceCtrlReadBufferPositiveExt2); 790 | 791 | /*if (SceBt_sub_2292CE4_0x2292D18_patch_uid > 0) { 792 | taiInjectReleaseForKernel(SceBt_sub_2292CE4_0x2292D18_patch_uid); 793 | }*/ 794 | 795 | log_flush(); 796 | 797 | return SCE_KERNEL_STOP_SUCCESS; 798 | } 799 | --------------------------------------------------------------------------------