diff --git a/ios/RetroArch/input/BTStack/btpad_ps3.c b/ios/RetroArch/input/BTStack/btpad_ps3.c new file mode 100644 index 0000000000..a6f444dcbd --- /dev/null +++ b/ios/RetroArch/input/BTStack/btpad_ps3.c @@ -0,0 +1,185 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2013 - Jason Fetters + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include + +#include "boolean.h" +#include "../../rarch_wrapper.h" + +#include "btdynamic.h" +#include "btpad.h" + +enum btpad_ps3_state { BTPAD_PS3_INITIALIZING, BTPAD_PS3_PENDING, BTPAD_PS3_WANT_NAME, BTPAD_PS3_CONNECTED }; + +struct btpad_ps3_data +{ + enum btpad_ps3_state state; + + uint8_t data[512]; + + bool have_address; + bd_addr_t address; + uint32_t handle; + uint32_t channels[2]; +}; + +static void* btpad_ps3_connect() +{ + struct btpad_ps3_data* device = malloc(sizeof(struct btpad_ps3_data)); + memset(device, 0, sizeof(*device)); + + ios_add_log_message("BTstack PS3: Registering HID INTERRUPT service"); + bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_INTERRUPT, 672); + device->state = BTPAD_PS3_INITIALIZING; + + return device; +} + +static void btpad_ps3_disconnect(struct btpad_ps3_data* device) +{ + ios_add_log_message("BTstack PS3: Disconnecting."); + + bt_send_cmd_ptr(hci_disconnect_ptr, device->handle, 0x15); + free(device); +} + +static void btpad_ps3_setleds(struct btpad_ps3_data* device, unsigned leds) +{ + static uint8_t report_buffer[] = { + 0x52, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + report_buffer[11] = (leds & 0xF) << 1; + bt_send_l2cap_ptr(device->channels[0], report_buffer, sizeof(report_buffer)); +} + +static uint32_t btpad_ps3_get_buttons(struct btpad_ps3_data* device) +{ + return (device->state == BTPAD_PS3_CONNECTED) ? device->data[3] | (device->data[4] << 8) : 0; +} + +static void btpad_ps3_packet_handler(struct btpad_ps3_data* device, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) +{ + if (packet_type == HCI_EVENT_PACKET) + { + if (device->state == BTPAD_PS3_INITIALIZING) + { + if (packet[0] == L2CAP_EVENT_SERVICE_REGISTERED) + { + uint32_t psm = READ_BT_16(packet, 3); + if (psm == PSM_HID_INTERRUPT) + { + ios_add_log_message("BTstack PS3: HID INTERRUPT service registered"); + ios_add_log_message("BTstack PS3: Registering HID CONTROL service"); + bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_CONTROL, 672); + } + else if(psm == PSM_HID_CONTROL) + { + ios_add_log_message("BTstack PS3: HID CONTROL service registered"); + ios_add_log_message("BTstack PS3: Waiting for connection"); + device->state = BTPAD_PS3_PENDING; + } + } + } + else if(device->state == BTPAD_PS3_PENDING) + { + if (packet[0] == L2CAP_EVENT_INCOMING_CONNECTION) + { + const uint32_t psm = READ_BT_16(packet, 10); + const unsigned interrupt = (psm == PSM_HID_INTERRUPT) ? 1 : 0; + + ios_add_log_message("BTstack PS3: Incoming L2CAP connection for PSM: %02X", psm); + + bd_addr_t address; + bt_flip_addr_ptr(address, &packet[2]); + + if (!device->have_address || BD_ADDR_CMP(device->address, address) == 0) + { + device->have_address = true; + + bt_flip_addr_ptr(device->address, &packet[2]); + device->handle = READ_BT_16(packet, 8); + device->channels[interrupt] = READ_BT_16(packet, 12); + + bt_send_cmd_ptr(l2cap_accept_connection_ptr, device->channels[interrupt]); + ios_add_log_message("BTstack PS3: Connection accepted"); + + if (device->channels[0] && device->channels[1]) + { + ios_add_log_message("BTstack PS3: Got both channels, requesting name"); + bt_send_cmd_ptr(hci_remote_name_request_ptr, device->address, 0, 0, 0); + device->state = BTPAD_PS3_WANT_NAME; + } + } + else + ios_add_log_message("BTstack PS3: Connection unexpected; ignoring"); + } + } + else if(device->state == BTPAD_PS3_WANT_NAME) + { + if (packet[0] == HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE) + { + bd_addr_t event_addr; + bt_flip_addr_ptr(event_addr, &packet[3]); + + if (BD_ADDR_CMP(event_addr, device->address) == 0) + { + if (strncmp((char*)&packet[9], "PLAYSTATION(R)3 Controller", 26) == 0) + { + ios_add_log_message("BTstack PS3: Got 'PLAYSTATION(R)3 Controller'; Sending startup packets"); + + // Special packet to tell PS3 controller to send reports + uint8_t data[] = {0x53, 0xF4, 0x42, 0x03, 0x00, 0x00}; + bt_send_l2cap_ptr(device->channels[0], data, 6); + + btpad_ps3_setleds(device, 1); + + device->state = BTPAD_PS3_CONNECTED; + } + else + { + ios_add_log_message("BTstack PS3: Got %200s; Will keep looking", (char*)&packet[9]); + device->have_address = 0; + device->handle = 0; + device->channels[0] = 0; + device->channels[1] = 0; + device->state = BTPAD_PS3_PENDING; + } + } + } + } + } + else if (packet_type == L2CAP_DATA_PACKET && packet[0] == 0xA1) + memcpy(device->data, packet, size); +} + +struct btpad_interface btpad_ps3 = +{ + (void*)&btpad_ps3_connect, + (void*)&btpad_ps3_disconnect, + (void*)&btpad_ps3_setleds, + (void*)&btpad_ps3_get_buttons, + (void*)&btpad_ps3_packet_handler +}; diff --git a/ios/RetroArch/input/BTStack/btpad_wii.c b/ios/RetroArch/input/BTStack/btpad_wii.c new file mode 100644 index 0000000000..38ad670445 --- /dev/null +++ b/ios/RetroArch/input/BTStack/btpad_wii.c @@ -0,0 +1,245 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2013 - Jason Fetters + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include + +#include "boolean.h" +#include "../../rarch_wrapper.h" + +#include "btdynamic.h" +#include "btpad.h" +#include "wiimote.h" + +enum btpad_wii_state { BTPAD_WII_WAITING, BTPAD_WII_PENDING, BTPAD_WII_WANT_NAME, BTPAD_WII_CONNECTING, BTPAD_WII_CONNECTED }; + +struct btpad_wii_data +{ + enum btpad_wii_state state; + struct wiimote_t wiimote; + + bd_addr_t address; + uint32_t page_scan_repetition_mode; + uint32_t class; + uint32_t clock_offset; + +}; + +static void* btpad_wii_connect() +{ + struct btpad_wii_data* device = malloc(sizeof(struct btpad_wii_data)); + memset(device, 0, sizeof(struct btpad_wii_data)); + + ios_add_log_message("BTstack Wii: Waiting for connection"); + bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 0); + + device->state = BTPAD_WII_WAITING; + + return device; +} + +static void btpad_wii_disconnect(struct btpad_wii_data* device) +{ + ios_add_log_message("BTstack Wii: Disconnecting."); + + bt_send_cmd_ptr(hci_disconnect_ptr, device->wiimote.wiiMoteConHandle, 0x15); + free(device); +} + +static void btpad_wii_setleds(struct btpad_wii_data* device, unsigned leds) +{ +} + +static uint32_t btpad_wii_get_buttons(struct btpad_wii_data* device) +{ + return (device->state == BTPAD_WII_CONNECTED) ? device->wiimote.btns | (device->wiimote.exp.classic.btns << 16) : 0; +} + +static void btpad_wii_packet_handler(struct btpad_wii_data* device, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) +{ + if (packet_type == HCI_EVENT_PACKET && packet[0] == HCI_EVENT_PIN_CODE_REQUEST) + { + ios_add_log_message("BTstack Wii: Sending PIN"); + + bd_addr_t event_addr; + bt_flip_addr_ptr(event_addr, &packet[2]); + bt_send_cmd_ptr(hci_pin_code_request_reply_ptr, event_addr, 6, &packet[2]); + } + + if (packet_type == HCI_EVENT_PACKET) + { + if (device->state == BTPAD_WII_WAITING) + { + switch (packet[0]) + { + case HCI_EVENT_INQUIRY_RESULT: + { + if (packet[2]) + { + ios_add_log_message("BTstack Wii: Inquiry found device"); + device->state = BTPAD_WII_PENDING; + + bt_flip_addr_ptr(device->address, &packet[3]); + device->page_scan_repetition_mode = packet [3 + packet[2] * (6)]; + device->class = READ_BT_24(packet, 3 + packet[2] * (6+1+1+1)); + device->clock_offset = READ_BT_16(packet, 3 + packet[2] * (6+1+1+1+3)) & 0x7fff; + } + + break; + } + + case HCI_EVENT_INQUIRY_COMPLETE: + { + bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 0); + break; + } + } + } + else if(device->state == BTPAD_WII_PENDING) + { + if (packet[0] == HCI_EVENT_INQUIRY_COMPLETE) + { + ios_add_log_message("BTstack Wii: Got inquiry complete; requesting name\n"); + device->state = BTPAD_WII_WANT_NAME; + + bt_send_cmd_ptr(hci_remote_name_request_ptr, device->address, device->page_scan_repetition_mode, + 0, device->clock_offset | 0x8000); + } + } + else if(device->state == BTPAD_WII_WANT_NAME) + { + if (packet[0] == HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE) + { + bd_addr_t event_addr; + bt_flip_addr_ptr(event_addr, &packet[3]); + + if (BD_ADDR_CMP(event_addr, device->address) == 0) + { + if (strncmp((char*)&packet[9], "Nintendo RVL-CNT-01", 19) == 0) + { + ios_add_log_message("BTstack Wii: Got Nintendo RVL-CNT-01; Connecting"); + device->state = BTPAD_WII_CONNECTING; + + bt_send_cmd_ptr(l2cap_create_channel_ptr, device->address, PSM_HID_CONTROL); + } + else + { + ios_add_log_message("BTstack Wii: Unrecognized device %s; Will keep looking", (char*)&packet[9]); + memset(device, 0, sizeof(*device)); + + device->state = BTPAD_WII_WAITING; + bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 0); + } + } + else + ios_add_log_message("BTstack Wii: Connection unexpected; ignoring"); + } + } + else if(device->state == BTPAD_WII_CONNECTING) + { + if (packet[0] == L2CAP_EVENT_CHANNEL_OPENED) + { + bd_addr_t event_addr; + bt_flip_addr_ptr(event_addr, &packet[3]); + if (BD_ADDR_CMP(device->address, event_addr) != 0) + { + ios_add_log_message("BTstack Wii: Incoming L2CAP connection not recognized; ignoring"); + return; + } + + const uint16_t psm = READ_BT_16(packet, 11); + + if (packet[2] == 0) + { + ios_add_log_message("BTstack: WiiMote L2CAP channel opened: %02X\n", psm); + + if (psm == PSM_HID_CONTROL) + { + ios_add_log_message("BTstack Wii: Got HID CONTROL channel; Opening INTERRUPT"); + bt_send_cmd_ptr(l2cap_create_channel_ptr, device->address, PSM_HID_INTERRUPT); + + memset(&device->wiimote, 0, sizeof(struct wiimote_t)); + device->wiimote.c_source_cid = READ_BT_16(packet, 13); + device->wiimote.wiiMoteConHandle = READ_BT_16(packet, 9); + memcpy(&device->wiimote.addr, &device->address, BD_ADDR_LEN); + device->wiimote.exp.type = EXP_NONE; + } + else if (psm == PSM_HID_INTERRUPT) + { + ios_add_log_message("BTstack Wii: Got HID INTERRUPT channel; Connected"); + device->state = BTPAD_WII_CONNECTED; + + device->wiimote.i_source_cid = READ_BT_16(packet, 13); + device->wiimote.state = WIIMOTE_STATE_CONNECTED; + wiimote_handshake(&device->wiimote, -1, NULL, -1); + } + } + else + { + ios_add_log_message("BTstack Wii: Failed to open WiiMote L2CAP channel for PSM: %02X", psm); + } + } + } + } + else if(packet_type == L2CAP_DATA_PACKET) + { + byte* msg = packet + 2; + + switch (packet[1]) + { + case WM_RPT_BTN: + { + wiimote_pressed_buttons(&device->wiimote, msg); + break; + } + + case WM_RPT_READ: + { + wiimote_pressed_buttons(&device->wiimote, msg); + + byte len = ((msg[2] & 0xF0) >> 4) + 1; + byte *data = (msg + 5); + + wiimote_handshake(&device->wiimote, WM_RPT_READ, data, len); + return; + } + + case WM_RPT_CTRL_STATUS: + { + wiimote_pressed_buttons(&device->wiimote, msg); + wiimote_handshake(&device->wiimote,WM_RPT_CTRL_STATUS,msg,-1); + + return; + } + + case WM_RPT_BTN_EXP: + { + wiimote_pressed_buttons(&device->wiimote, msg); + wiimote_handle_expansion(&device->wiimote, msg+2); + break; + } + } + } +} + +struct btpad_interface btpad_wii = +{ + (void*)&btpad_wii_connect, + (void*)&btpad_wii_disconnect, + (void*)&btpad_wii_setleds, + (void*)&btpad_wii_get_buttons, + (void*)&btpad_wii_packet_handler +}; diff --git a/ios/RetroArch/settings/RASettingsList.m b/ios/RetroArch/settings/RASettingsList.m index e62ab76449..c5148ce2cc 100644 --- a/ios/RetroArch/settings/RASettingsList.m +++ b/ios/RetroArch/settings/RASettingsList.m @@ -133,9 +133,9 @@ static RASettingData* custom_action(NSString* action) (void)[[RASettingsList alloc] init]; } -- (RASettingsList*)initWithModule:(RAModuleInfo*)module +- (id)init { - config_file_t* config = config_file_new([module.configPath UTF8String]); + config_file_t* config = config_file_new([[RetroArch_iOS get].moduleInfo.configPath UTF8String]); NSString* overlay_path = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/overlays/"]; NSString* shader_path = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/shaders/"];