Bluetooth: Defer SCO setup if mode change is pending
[pandora-kernel.git] / net / bluetooth / hci_conn.c
index b10e3cd..0b1e460 100644 (file)
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
+   Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -155,6 +155,27 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
        hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
 }
 
+/* Device _must_ be locked */
+void hci_sco_setup(struct hci_conn *conn, __u8 status)
+{
+       struct hci_conn *sco = conn->link;
+
+       BT_DBG("%p", conn);
+
+       if (!sco)
+               return;
+
+       if (!status) {
+               if (lmp_esco_capable(conn->hdev))
+                       hci_setup_sync(sco, conn->handle);
+               else
+                       hci_add_sco(sco, conn->handle);
+       } else {
+               hci_proto_connect_cfm(sco, status);
+               hci_conn_del(sco);
+       }
+}
+
 static void hci_conn_timeout(unsigned long arg)
 {
        struct hci_conn *conn = (void *) arg;
@@ -358,6 +379,11 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
                acl->sec_level = sec_level;
                acl->auth_type = auth_type;
                hci_acl_connect(acl);
+       } else {
+               if (acl->sec_level < sec_level)
+                       acl->sec_level = sec_level;
+               if (acl->auth_type < auth_type)
+                       acl->auth_type = auth_type;
        }
 
        if (type == ACL_LINK)
@@ -380,10 +406,13 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
                acl->power_save = 1;
                hci_conn_enter_active_mode(acl);
 
-               if (lmp_esco_capable(hdev))
-                       hci_setup_sync(sco, acl->handle);
-               else
-                       hci_add_sco(sco, acl->handle);
+               if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
+                       /* defer SCO setup until mode change completed */
+                       set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend);
+                       return sco;
+               }
+
+               hci_sco_setup(acl, 0x00);
        }
 
        return sco;