Merge "Unable to connect to a Motorola s705 until Bluetooth was toggled of and back on" into klp-dev
diff --git a/stack/btm/btm_acl.c b/stack/btm/btm_acl.c
index ef552a6..629c8b4 100644
--- a/stack/btm/btm_acl.c
+++ b/stack/btm/btm_acl.c
@@ -49,6 +49,52 @@
 
 /*******************************************************************************
 **
+** Function         btm_save_remote_device_role
+**
+** Description      This function is to save remote device role
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_save_remote_device_role(BD_ADDR bd_addr, UINT8 role)
+{
+    UINT8 i, j;
+    if (role == BTM_ROLE_UNDEFINED) return;
+
+    for (i = 0; i < BTM_ROLE_DEVICE_NUM; i++) {
+        if ((btm_cb.previous_connected_role[i] != BTM_ROLE_UNDEFINED) &&
+            (!bdcmp(bd_addr, btm_cb.previous_connected_remote_addr[i]))) {
+            break;
+        }
+    }
+
+    if (i < BTM_ROLE_DEVICE_NUM) {
+        UINT8 end;
+        if (i < btm_cb.front) {
+            for (j = i; j > 0; j--) {
+                bdcpy(btm_cb.previous_connected_remote_addr[j],
+                    btm_cb.previous_connected_remote_addr[j-1]);
+            }
+            bdcpy(btm_cb.previous_connected_remote_addr[0],
+                btm_cb.previous_connected_remote_addr[BTM_ROLE_DEVICE_NUM-1]);
+            end = BTM_ROLE_DEVICE_NUM-1;
+        } else {
+            end = i;
+        }
+
+        for (j = end; j > btm_cb.front; j--) {
+            bdcpy(btm_cb.previous_connected_remote_addr[j],
+                btm_cb.previous_connected_remote_addr[j-1]);
+        }
+    }
+
+    bdcpy(btm_cb.previous_connected_remote_addr[btm_cb.front], bd_addr);
+    btm_cb.previous_connected_role[btm_cb.front] = role;
+    btm_cb.front = (btm_cb.front + 1) % BTM_ROLE_DEVICE_NUM;
+}
+
+/*******************************************************************************
+**
 ** Function         btm_acl_init
 **
 ** Description      This function is called at BTM startup to initialize
@@ -158,6 +204,7 @@
     {
         p->hci_handle = hci_handle;
         p->link_role  = link_role;
+        btm_save_remote_device_role(bda, link_role);
 #if BLE_INCLUDED == TRUE
         p->is_le_link = is_le_link;
 #endif
@@ -175,6 +222,7 @@
             p->in_use            = TRUE;
             p->hci_handle        = hci_handle;
             p->link_role         = link_role;
+            btm_save_remote_device_role(bda, link_role);
             p->link_up_issued    = FALSE;
 
 #if BLE_INCLUDED == TRUE
@@ -2196,7 +2244,7 @@
 
         /* Update cached value */
         p->link_role = new_role;
-
+        btm_save_remote_device_role(p_bda, new_role);
         /* Reload LSTO: link supervision timeout is reset in the LM after a role switch */
         if (new_role == BTM_ROLE_MASTER)
         {
diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h
index 2f9b232..16a02e6 100644
--- a/stack/btm/btm_int.h
+++ b/stack/btm/btm_int.h
@@ -52,6 +52,10 @@
 */
 #define BTM_MAX_SCN      PORT_MAX_RFC_PORTS
 
+/* Definition for number of the remote device role saved
+*/
+#define BTM_ROLE_DEVICE_NUM      4
+
 /* Define masks for supported and exception 2.0 ACL packet types
 */
 #define BTM_ACL_SUPPORTED_PKTS_MASK      (HCI_PKT_TYPES_MASK_DM1        | \
@@ -895,6 +899,9 @@
     tBTM_PCM2_ACTION        pcm2_action;
 #endif
 
+    BD_ADDR previous_connected_remote_addr[BTM_ROLE_DEVICE_NUM];
+    UINT8   previous_connected_role[BTM_ROLE_DEVICE_NUM];
+    UINT8   front; /* front index of the role table */
 } tBTM_CB;
 
 
diff --git a/stack/btm/btm_main.c b/stack/btm/btm_main.c
index f3037f6..869899d 100644
--- a/stack/btm/btm_main.c
+++ b/stack/btm/btm_main.c
@@ -48,6 +48,7 @@
 *******************************************************************************/
 void btm_init (void)
 {
+    UINT8 i;
     /* All fields are cleared; nonzero fields are reinitialized in appropriate function */
     memset(&btm_cb, 0, sizeof(tBTM_CB));
 
@@ -56,6 +57,9 @@
 #else
     btm_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
 #endif
+    for (i = 0; i < BTM_ROLE_DEVICE_NUM; i++) {
+        btm_cb.previous_connected_role[i] = BTM_ROLE_UNDEFINED;
+    }
     /* Initialize BTM component structures */
     btm_inq_db_init();                  /* Inquiry Database and Structures */
     btm_acl_init();                     /* ACL Database and Structures */
diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h
index f4eb008..a17c583 100644
--- a/stack/l2cap/l2c_int.h
+++ b/stack/l2cap/l2c_int.h
@@ -585,7 +585,7 @@
 extern tL2C_LCB *l2cu_find_lcb_by_handle (UINT16 handle);
 extern void     l2cu_update_lcb_4_bonding (BD_ADDR p_bd_addr, BOOLEAN is_bonding);
 
-extern UINT8    l2cu_get_conn_role (tL2C_LCB *p_this_lcb);
+extern UINT8    l2cu_get_conn_role (BD_ADDR bd_addr);
 extern BOOLEAN  l2cu_set_acl_priority (BD_ADDR bd_addr, UINT8 priority, BOOLEAN reset_after_rs);
 
 extern void     l2cu_enqueue_ccb (tL2C_CCB *p_ccb);
diff --git a/stack/l2cap/l2c_link.c b/stack/l2cap/l2c_link.c
index 1974bb2..ca563d9 100644
--- a/stack/l2cap/l2c_link.c
+++ b/stack/l2cap/l2c_link.c
@@ -98,7 +98,7 @@
             if (!btm_dev_support_switch (bd_addr))
                 p_lcb->link_role = HCI_ROLE_SLAVE;
             else
-                p_lcb->link_role = l2cu_get_conn_role(p_lcb);
+                p_lcb->link_role = l2cu_get_conn_role(bd_addr);
         }
 
         /* Tell the other side we accept the connection */
@@ -119,7 +119,7 @@
         if (!btm_dev_support_switch (bd_addr))
             p_lcb->link_role = HCI_ROLE_SLAVE;
         else
-            p_lcb->link_role = l2cu_get_conn_role(p_lcb);
+            p_lcb->link_role = l2cu_get_conn_role(bd_addr);
 
         btsnd_hcic_accept_conn (bd_addr, p_lcb->link_role);
 
diff --git a/stack/l2cap/l2c_utils.c b/stack/l2cap/l2c_utils.c
index 457ea2d..1add2b6 100644
--- a/stack/l2cap/l2c_utils.c
+++ b/stack/l2cap/l2c_utils.c
@@ -252,6 +252,8 @@
 ** Function         l2cu_get_conn_role
 **
 ** Description      Determine the desired role (master or slave) of a link.
+**                  If it is the previous connected remote device, use the same
+**                  role as previous used role.
 **                  If already got a slave link, this one must be a master. If
 **                  already got at least 1 link where we are the master, make this
 **                  also a master.
@@ -259,8 +261,17 @@
 ** Returns          HCI_ROLE_MASTER or HCI_ROLE_SLAVE
 **
 *******************************************************************************/
-UINT8 l2cu_get_conn_role (tL2C_LCB *p_this_lcb)
+UINT8 l2cu_get_conn_role (BD_ADDR bd_addr)
 {
+    UINT8 i;
+    for (i = 0; i < BTM_ROLE_DEVICE_NUM; i++) {
+        if ((btm_cb.previous_connected_role[i] != BTM_ROLE_UNDEFINED) &&
+            (!bdcmp(bd_addr, btm_cb.previous_connected_remote_addr[i]))) {
+            L2CAP_TRACE_WARNING1 ("l2cu_get_conn_role %d",
+                                  btm_cb.previous_connected_role[i]);
+            return btm_cb.previous_connected_role[i];
+        }
+    }
     return l2cb.desire_role;
 }