From bb4b254be714c6567f579dd684b29b45a9eff992 Mon Sep 17 00:00:00 2001
From: meancoot <nowhere>
Date: Mon, 25 Mar 2013 18:25:21 -0400
Subject: [PATCH] (iOS, BTstack) More refactoring; Now have to choose the type
 of pad to connect (annoying, but there's no other way the code gets stable)

---
 griffin/griffin.c                       |   2 +
 ios/RetroArch.xcodeproj/project.pbxproj |   4 +
 ios/RetroArch/RetroArch_iOS.h           |   2 +-
 ios/RetroArch/RetroArch_iOS.m           |  18 +-
 ios/RetroArch/input/BTStack/btdynamic.c |  11 +-
 ios/RetroArch/input/BTStack/btdynamic.h |   1 +
 ios/RetroArch/input/BTStack/btpad.c     | 444 +++---------------------
 ios/RetroArch/input/BTStack/btpad.h     |  19 +-
 8 files changed, 104 insertions(+), 397 deletions(-)

diff --git a/griffin/griffin.c b/griffin/griffin.c
index bf3b36191d..e60a9241d0 100644
--- a/griffin/griffin.c
+++ b/griffin/griffin.c
@@ -247,6 +247,8 @@ INPUT
 #include "../ios/RetroArch/input/BTStack/btdynamic.c"
 #include "../ios/RetroArch/input/BTStack/wiimote.c"
 #include "../ios/RetroArch/input/BTStack/btpad.c"
+#include "../ios/RetroArch/input/BTStack/btpad_ps3.c"
+#include "../ios/RetroArch/input/BTStack/btpad_wii.c"
 #elif defined(__BLACKBERRY_QNX__)
 #include "../playbook/qnx_input.c"
 #endif
diff --git a/ios/RetroArch.xcodeproj/project.pbxproj b/ios/RetroArch.xcodeproj/project.pbxproj
index 6288e261ad..25fc340bfc 100644
--- a/ios/RetroArch.xcodeproj/project.pbxproj
+++ b/ios/RetroArch.xcodeproj/project.pbxproj
@@ -44,6 +44,8 @@
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
+		960356BC1700652C008F55DA /* btpad_ps3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = btpad_ps3.c; sourceTree = "<group>"; };
+		960356BD1700652C008F55DA /* btpad_wii.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = btpad_wii.c; sourceTree = "<group>"; };
 		96096DD716D1ABAF00BF4499 /* RAModuleInfoList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAModuleInfoList.m; sourceTree = "<group>"; };
 		9614C71F16DDC018000B36EF /* RetroArch copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "RetroArch copy-Info.plist"; path = "/Users/jason/Documents/Projects/ios/RetroArch/ios/RetroArch copy-Info.plist"; sourceTree = "<absolute>"; };
 		962979F416C43B9500E6DCE0 /* ic_dir.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_dir.png; path = "../../android/phoenix/res/drawable-xhdpi/ic_dir.png"; sourceTree = "<group>"; };
@@ -156,6 +158,8 @@
 			children = (
 				966B9C9416E418B7005B61E1 /* btstack */,
 				966B9CA116E418B7005B61E1 /* btpad.c */,
+				960356BC1700652C008F55DA /* btpad_ps3.c */,
+				960356BD1700652C008F55DA /* btpad_wii.c */,
 				96F9C27B16FF66BC002455B3 /* btpad.h */,
 				96F9C27516FF5E97002455B3 /* btdynamic.c */,
 				96F9C27616FF5E97002455B3 /* btdynamic.h */,
diff --git a/ios/RetroArch/RetroArch_iOS.h b/ios/RetroArch/RetroArch_iOS.h
index 08bae16b3d..d5a406bc52 100644
--- a/ios/RetroArch/RetroArch_iOS.h
+++ b/ios/RetroArch/RetroArch_iOS.h
@@ -15,7 +15,7 @@
 
 #import <UIKit/UIKit.h>
 
-@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate>
+@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate, UIAlertViewDelegate>
 
 + (void)displayErrorMessage:(NSString*)message;
 
diff --git a/ios/RetroArch/RetroArch_iOS.m b/ios/RetroArch/RetroArch_iOS.m
index 7ab8d94a4b..cbda74950e 100644
--- a/ios/RetroArch/RetroArch_iOS.m
+++ b/ios/RetroArch/RetroArch_iOS.m
@@ -19,7 +19,8 @@
 #import "browser/browser.h"
 #import "settings/settings.h"
 
-#include "input/BTstack/btdynamic.h"
+#include "input/BTStack/btdynamic.h"
+#include "input/BTStack/btpad.h"
 
 #define kDOCSFOLDER [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]
 
@@ -291,6 +292,21 @@
 {
    if (btstack_is_loaded())
    {
+      UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"RetroArch"
+                                                message:@"Choose Pad Type"
+                                                delegate:self
+                                                cancelButtonTitle:nil
+                                                otherButtonTitles:@"Wii", @"PS3", nil];
+      [alert show];
+   }
+}
+
+- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
+{
+   if (btstack_is_loaded())
+   {
+      btpad_set_pad_type(buttonIndex == 0);
+
       btstack_start();
       [self.topViewController.navigationItem setRightBarButtonItem:[self createBluetoothButton] animated:YES];
    }
diff --git a/ios/RetroArch/input/BTStack/btdynamic.c b/ios/RetroArch/input/BTStack/btdynamic.c
index 7a7d1365ff..b82c6631c5 100644
--- a/ios/RetroArch/input/BTStack/btdynamic.c
+++ b/ios/RetroArch/input/BTStack/btdynamic.c
@@ -41,6 +41,7 @@ static struct
    GRAB(btstack_set_power_mode),
    GRAB(btstack_set_system_bluetooth_enabled),
    GRAB(hci_delete_stored_link_key),
+   GRAB(hci_disconnect),
    GRAB(hci_inquiry),
    GRAB(hci_inquiry_cancel),
    GRAB(hci_pin_code_request_reply),
@@ -56,7 +57,7 @@ static struct
    {0, 0}
 };
 
-extern void btstack_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
+extern void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
 
 static pthread_t btstack_thread;
 static bool btstack_tested;
@@ -70,7 +71,7 @@ static void* btstack_thread_function(void* data)
    ios_add_log_message("BTstack: Thread Initializing");
 
    run_loop_init_ptr(RUN_LOOP_COCOA);
-   bt_register_packet_handler_ptr(btstack_packet_handler);
+   bt_register_packet_handler_ptr(btpad_packet_handler);
 
    if (bt_open_ptr())
    {
@@ -140,6 +141,9 @@ bool btstack_load()
 
 void btstack_start()
 {
+   if (!btstack_load())
+      return;
+
    static bool thread_started = false;
    if (!thread_started)
    {
@@ -157,6 +161,9 @@ void btstack_start()
 
 void btstack_stop()
 {
+   if (!btstack_load())
+      return;
+
    if (btstack_poweron)
    {
       ios_add_log_message("BTstack: Clearing poweron flag");
diff --git a/ios/RetroArch/input/BTStack/btdynamic.h b/ios/RetroArch/input/BTStack/btdynamic.h
index 446bb0f3ef..cd76988ba6 100644
--- a/ios/RetroArch/input/BTStack/btdynamic.h
+++ b/ios/RetroArch/input/BTStack/btdynamic.h
@@ -44,6 +44,7 @@ BTDIMPORT const hci_cmd_t* btstack_get_system_bluetooth_enabled_ptr;
 BTDIMPORT const hci_cmd_t* btstack_set_power_mode_ptr;
 BTDIMPORT const hci_cmd_t* btstack_set_system_bluetooth_enabled_ptr;
 BTDIMPORT const hci_cmd_t* hci_delete_stored_link_key_ptr;
+BTDIMPORT const hci_cmd_t* hci_disconnect_ptr;
 BTDIMPORT const hci_cmd_t* hci_inquiry_ptr;
 BTDIMPORT const hci_cmd_t* hci_inquiry_cancel_ptr;
 BTDIMPORT const hci_cmd_t* hci_pin_code_request_reply_ptr;
diff --git a/ios/RetroArch/input/BTStack/btpad.c b/ios/RetroArch/input/BTStack/btpad.c
index 96370daa69..dd9d5dec41 100644
--- a/ios/RetroArch/input/BTStack/btpad.c
+++ b/ios/RetroArch/input/BTStack/btpad.c
@@ -1,31 +1,16 @@
-/*
- * This file is part of MAME4iOS.
+/*  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.
  *
- * Copyright (C) 2012 David Valdeita (Seleuco)
+ *  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.
  *
- * This program 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 Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * In addition, as a special exception, Seleuco
- * gives permission to link the code of this program with
- * the MAME library (or with modified versions of MAME that use the
- * same license as MAME), and distribute linked combinations including
- * the two.  You must obey the GNU General Public License in all
- * respects for all of the code used other than MAME.  If you modify
- * this file, you may extend this exception to your version of the
- * file, but you are not obligated to do so.  If you do not wish to
- * do so, delete this exception statement from your version.
+ *  You should have received a copy of the GNU General Public License along with RetroArch.
+ *  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <sys/types.h>
@@ -38,392 +23,71 @@
 #include "btpad.h"
 #include "wiimote.h"
 
-enum btpad_state_t { BTPAD_NOT_INITIALIZED, BTPAD_NO_CONNECTION, BTPAD_INQUIRY_CONNECTION, BTPAD_CONNECTION, BTPAD_WANT_NAME, BTPAD_CONNECTED };
-static enum btpad_state_t btpad_state = BTPAD_NOT_INITIALIZED;
-
-static enum btpad_device_type_t device_type;
-static bd_addr_t device_address;
-static char device_name[256];
-
-// Connection data
-static uint32_t device_handle[2];
-static uint32_t device_remote_cid[2];
-static uint32_t device_local_cid[2];
-
-// Inquiry data
-static uint32_t device_page_scan_repetition_mode;
-static uint32_t device_class;
-static uint32_t device_clock_offset;
-
-// Buffers
-static struct wiimote_t wiimote_buffer;
-static uint8_t psdata_buffer[512];
+static struct btpad_interface* btpad_iface;
+static void* btpad_device;
+static bool btpad_want_wiimote;
+static pthread_mutex_t btpad_lock = PTHREAD_MUTEX_INITIALIZER;
 
 // MAIN THREAD ONLY
-enum btpad_device_type_t btpad_get_connected_type()
-{
-   return device_type;
-}
-
 uint32_t btpad_get_buttons()
 {
-   switch (device_type)
-   {
-      case BTPAD_WIIMOTE:
-         return wiimote_buffer.btns | (wiimote_buffer.exp.classic.btns << 16);
-      case BTPAD_PS3:
-         return psdata_buffer[3] | (psdata_buffer[4] << 8);
-      default:
-         return 0;
-   }
+   pthread_mutex_lock(&btpad_lock);
+   uint32_t result = (btpad_device && btpad_iface) ? btpad_iface->get_buttons(btpad_device) : 0;
+   pthread_mutex_unlock(&btpad_lock);
+
+   return result;
+}
+
+void btpad_set_pad_type(bool wiimote)
+{
+   pthread_mutex_lock(&btpad_lock);
+   btpad_want_wiimote = wiimote;
+   pthread_mutex_unlock(&btpad_lock);
 }
 
 // BT THREAD ONLY
-static void set_ps3_data(unsigned leds)
+static void btpad_connect_pad(bool wiimote)
 {
-   // TODO: LEDS
+   pthread_mutex_lock(&btpad_lock);
 
-   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
-   };
+   ios_add_log_message("BTpad: Connecting to %s", wiimote ? "WiiMote" : "PS3");
+
+   btpad_iface = (wiimote) ? &btpad_wii : &btpad_ps3;
+   btpad_device = btpad_iface->connect();
    
-   bt_send_l2cap_ptr(device_local_cid[0], report_buffer, sizeof(report_buffer));
+   pthread_mutex_unlock(&btpad_lock);
 }
 
-static bool btstack_read_incoming_connection_packet(uint8_t* packet, uint16_t size)
+static void btpad_disconnect_pad()
 {
-   const uint32_t psm = READ_BT_16(packet, 10);
-   const unsigned interrupt = (psm == PSM_HID_INTERRUPT) ? 1 : 0;
+   pthread_mutex_lock(&btpad_lock);
 
-   bt_flip_addr_ptr(device_address, &packet[2]);
-   device_handle[interrupt] = READ_BT_16(packet, 8);
-   device_local_cid[interrupt] = READ_BT_16(packet, 12);
-   device_remote_cid[interrupt] = READ_BT_16(packet, 14);
+   if (btpad_iface && btpad_device)
+   {
+      ios_add_log_message("BTpad: Disconnecting");
    
-   return interrupt;
-}
-
-static void btstack_not_initialized_handler(uint8_t* packet, uint16_t size)
-{
-   switch (packet[0])
-   {
-      case BTSTACK_EVENT_STATE:
-      {
-         if (packet[2] == HCI_STATE_WORKING)
-         {
-            ios_add_log_message("BTstack: Power state now HCI_STATE_WORKING");
-            ios_add_log_message("BTstack: Registering HID INTERRUPT service");
-            bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_INTERRUPT, 672);
-         }
-         else
-            ios_add_log_message("BTstack: State is now %d", packet[2]);
-         break;
-      }
-
-      case L2CAP_EVENT_SERVICE_REGISTERED:
-      {
-         if (READ_BT_16(packet, 3) == PSM_HID_INTERRUPT)
-         {
-            ios_add_log_message("BTstack: HID INTERRUPT service registered");
-            ios_add_log_message("BTstack: Registering HID CONTROL service");
-            bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_CONTROL, 672);
-         }
-         else if(READ_BT_16(packet, 3) == PSM_HID_CONTROL)
-         {
-            ios_add_log_message("BTstack: HID CONTROL service registered");
-
-            ios_add_log_message("BTstack: Waiting for connection");
-            bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 0);
-            btpad_state = BTPAD_NO_CONNECTION;
-         }
-         break;
-      }
+      btpad_iface->disconnect(btpad_device);
+      btpad_device = 0;
+      btpad_iface = 0;
    }
-}
-
-static void btstack_no_connection_handler(uint8_t* packet, uint16_t size)
-{
-   switch (packet[0])
-   {
-      // Device is connecting to iOS
-      case L2CAP_EVENT_INCOMING_CONNECTION:
-      {
-         ios_add_log_message("BTstack: Incoming L2CAP connection (PS3 Pad?)");
-      
-         btpad_state = BTPAD_CONNECTION;
-               
-         bool ch = btstack_read_incoming_connection_packet(packet, size);
-         bt_send_cmd_ptr(l2cap_accept_connection_ptr, device_local_cid[ch ? 1 : 0]);
-
-         break;
-      }
-
-      // iOS is connecting to device
-      // Here we just copy the details of the first device found
-      case HCI_EVENT_INQUIRY_RESULT:
-      {
-         ios_add_log_message("BTstack: Inquiry found device (WiiMote?)");
-      
-         if (packet[2])
-         {
-            btpad_state = BTPAD_INQUIRY_CONNECTION;
-               
-            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;
-      }
-   }
-}
-
-static void btstack_connection_handler(uint8_t* packet, uint16_t size)
-{
-   switch (packet[0])
-   {
-      case L2CAP_EVENT_INCOMING_CONNECTION:
-      {
-         ios_add_log_message("BTstack: Got other half L2CAP connection; requesting name\n");
-      
-         btpad_state = BTPAD_WANT_NAME;
-
-         bool ch = btstack_read_incoming_connection_packet(packet, size);
-         bt_send_cmd_ptr(l2cap_accept_connection_ptr, device_local_cid[ch ? 1 : 0]);
-         bt_send_cmd_ptr(hci_remote_name_request_ptr, device_address, 0, 0, 0);
-
-         break;
-      }
-   }
-}
-
-static void btstack_inquiry_connection_handler(uint8_t* packet, uint16_t size)
-{
-   switch (packet[0])
-   {
-      case HCI_EVENT_INQUIRY_COMPLETE:
-      {
-         ios_add_log_message("BTstack: Got inquiry complete; requesting name\n");
-      
-         btpad_state = BTPAD_WANT_NAME;
-         bt_send_cmd_ptr(hci_remote_name_request_ptr, device_address, device_page_scan_repetition_mode,
-                         0, device_clock_offset | 0x8000);
-         break;
-      }
-   }
-}
-
-static void btstack_want_name_handler(uint8_t* packet, uint16_t size)
-{
-   bd_addr_t event_addr;
-
-   switch (packet[0])
-   {
-      case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
-      {
-         bt_flip_addr_ptr(event_addr, &packet[3]);
-               
-         if (BD_ADDR_CMP(event_addr, device_address) == 0)
-         {
-            strncpy(device_name, (const char*)&packet[9], 248);
-            device_name[248] = 0;
-
-            ios_add_log_message("BTstack: Got device name: %s\n", device_name);
-
-            if (strncmp(device_name, "Nintendo RVL-CNT-01", 19) == 0)
-            {
-               ios_add_log_message("BTstack: Got WiiMote\n");
-               btpad_state = BTPAD_CONNECTED;
-               device_type = BTPAD_WIIMOTE;
-               bt_send_cmd_ptr(l2cap_create_channel_ptr, device_address, PSM_HID_CONTROL);
-            }
-            else if(strncmp(device_name, "PLAYSTATION(R)3 Controller", 26) == 0)
-            {
-               ios_add_log_message("BTstack: Got PS3 Pad; Sending startup packets\n");
-            
-               btpad_state = BTPAD_CONNECTED;
-               device_type = BTPAD_PS3;
-
-               // Special packet to tell PS3 controller to send reports
-               uint8_t data[] = {0x53, 0xF4, 0x42, 0x03, 0x00, 0x00};
-               bt_send_l2cap_ptr(device_local_cid[0], data, 6);
-               set_ps3_data(0);
-            }
-            else
-            {
-               ios_add_log_message("BTstack: Unrecognized device; Will keep looking");
-               btpad_state = BTPAD_NO_CONNECTION;
-            }
-         }
-               
-         break;
-      }
-   }
-}
-
-static void btstack_ps3_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
-{
-   if (packet_type == L2CAP_DATA_PACKET && packet[0] == 0xA1)
-   {
-      static bool tag = false;
-      if(!tag) ios_add_log_message("BTstack: Got PS3 Data Packet (Will only show once)\n");
-      tag = true;
    
-      memcpy(psdata_buffer, packet, size);
-   }
+   pthread_mutex_unlock(&btpad_lock);
 }
 
-static void btstack_wiimote_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
 {
-   bd_addr_t event_addr;
-
-   if (packet_type == HCI_EVENT_PACKET && packet[0] == L2CAP_EVENT_CHANNEL_OPENED)
+   if (packet_type == HCI_EVENT_PACKET && packet[0] == BTSTACK_EVENT_STATE)
    {
-      bt_flip_addr_ptr(event_addr, &packet[3]);
-      const uint16_t psm = READ_BT_16(packet, 11);
-            
-      if (packet[2] == 0 && BD_ADDR_CMP(event_addr, device_address) == 0)
-      {
-         ios_add_log_message("BTstack: WiiMote L2CAP channel openend: %02X\n", psm);
-            
-         const unsigned interrupt = (psm == PSM_HID_INTERRUPT) ? 1 : 0;
-                  
-         device_local_cid[interrupt] = READ_BT_16(packet, 13);
-         device_remote_cid[interrupt] = READ_BT_16(packet, 15);
-         device_handle[interrupt] = READ_BT_16(packet, 9);
-
-         if (psm == PSM_HID_CONTROL)
-         {
-            bt_send_cmd_ptr(l2cap_create_channel_ptr, device_address, PSM_HID_INTERRUPT);
-
-            memset(&wiimote_buffer, 0, sizeof(struct wiimote_t));
-            wiimote_buffer.unid = 0;
-            wiimote_buffer.c_source_cid = device_local_cid[0];
-            wiimote_buffer.exp.type = EXP_NONE;
-            wiimote_buffer.wiiMoteConHandle = device_handle[0];
-            memcpy(&wiimote_buffer.addr, &device_address, BD_ADDR_LEN);
-         }
-         else if (psm == PSM_HID_INTERRUPT)
-         {
-            wiimote_buffer.i_source_cid = device_local_cid[1];
-            wiimote_buffer.state = WIIMOTE_STATE_CONNECTED;
-            wiimote_handshake(&wiimote_buffer, -1, NULL, -1);
-         }
-      }
-      else
-      {
-         ios_add_log_message("BTstack: Failed to open WiiMote L2CAP channel: %d", psm);
-         ios_add_log_message("BTstack: Won't recover, please exit RetroArch from the task switcher");
-      }
+      if (packet[2] == HCI_STATE_WORKING)
+         btpad_connect_pad(btpad_want_wiimote);
+      else if(packet[2] > HCI_STATE_WORKING && btpad_iface && btpad_device)
+         btpad_disconnect_pad();
    }
-   else if(packet_type == L2CAP_DATA_PACKET)
+
+   if (btpad_device && btpad_iface)
    {
-      static bool tag = false;
-      if(!tag) ios_add_log_message("BTstack: Got Wii Data Packet (Will only show once)\n");
-      tag = true;
-   
-      byte* msg = packet + 2;
-         
-      switch (packet[1])
-      {
-         case WM_RPT_BTN:
-         {
-            wiimote_pressed_buttons(&wiimote_buffer, msg);
-            break;
-         }
-
-         case WM_RPT_READ:
-         {
-            wiimote_pressed_buttons(&wiimote_buffer, msg);
-
-            byte len = ((msg[2] & 0xF0) >> 4) + 1;
-            byte *data = (msg + 5);
-
-            wiimote_handshake(&wiimote_buffer, WM_RPT_READ, data, len);
-            return;
-         }
-
-         case WM_RPT_CTRL_STATUS:
-         {
-            wiimote_pressed_buttons(&wiimote_buffer, msg);
-            wiimote_handshake(&wiimote_buffer,WM_RPT_CTRL_STATUS,msg,-1);
-
-            return;
-         }
-
-         case WM_RPT_BTN_EXP:
-         {
-            wiimote_pressed_buttons(&wiimote_buffer, msg);
-            wiimote_handle_expansion(&wiimote_buffer, msg+2);
-            break;
-         }
-      }
-   }
-}
-
-
-void btstack_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
-{
-   typedef void (*handler_t)(uint8_t*, uint16_t);
-   static handler_t const handlers[] =
-   {
-      &btstack_not_initialized_handler,
-      &btstack_no_connection_handler,
-      &btstack_inquiry_connection_handler,
-      &btstack_connection_handler,
-      &btstack_want_name_handler
-   };
-
-   if (packet_type == HCI_EVENT_PACKET && btpad_state <= BTPAD_WANT_NAME)
-   {
-      handlers[(unsigned)btpad_state](packet, size);
-   }
-   else if (btpad_state == BTPAD_CONNECTED)
-   {
-      if (device_type == BTPAD_PS3)
-         btstack_ps3_handler(packet_type, channel, packet, size);
-      else if(device_type == BTPAD_WIIMOTE)
-         btstack_wiimote_handler(packet_type, channel, packet, size);
-   }
-
-   if (packet_type == HCI_EVENT_PACKET)
-   {
-      bd_addr_t event_addr;
-   
-      switch (packet[0])
-      {
-         // This PIN will work for Wiimotes, other devices with PINs aren't supported
-         case HCI_EVENT_PIN_CODE_REQUEST:
-            ios_add_log_message("BTstack: Sending PIN (will fail if device isn't WiiMote");
-         
-            bt_flip_addr_ptr(event_addr, &packet[2]);
-            bt_send_cmd_ptr(hci_pin_code_request_reply_ptr, device_address, 6, &packet[2]);
-            break;
-      
-         case L2CAP_EVENT_CHANNEL_CLOSED:
-            ios_add_log_message("BTstack: Lost L2CAP connection; will start searching for new device");
-   
-            btpad_state = BTPAD_NO_CONNECTION;
-            device_type = BTPAD_NONE;
-            
-            bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 0);
-
-            break;
-      }
+      pthread_mutex_lock(&btpad_lock);
+      btpad_iface->packet_handler(btpad_device, packet_type, channel, packet, size);
+      pthread_mutex_unlock(&btpad_lock);
    }
 }
diff --git a/ios/RetroArch/input/BTStack/btpad.h b/ios/RetroArch/input/BTStack/btpad.h
index 8a1245e362..7b05970e31 100644
--- a/ios/RetroArch/input/BTStack/btpad.h
+++ b/ios/RetroArch/input/BTStack/btpad.h
@@ -16,9 +16,22 @@
 #ifndef __IOS_RARCH_BTPAD_H__
 #define __IOS_RARCH_BTPAD_H__
 
-enum btpad_device_type_t { BTPAD_NONE, BTPAD_PENDING, BTPAD_WIIMOTE, BTPAD_PS3 };
-
-enum btpad_device_type_t btpad_get_connected_type();
 uint32_t btpad_get_buttons();
+void btpad_set_pad_type(bool wiimote);
+
+// Private interface
+struct btpad_interface
+{
+   void* (*connect)();
+   void (*disconnect)(void* device);
+   void (*set_leds)(void* device, unsigned leds);
+
+   uint32_t (*get_buttons)(void* device);
+
+   void (*packet_handler)(void* device, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
+};
+
+extern struct btpad_interface btpad_ps3;
+extern struct btpad_interface btpad_wii;
 
 #endif