From d4595be82672b3a0f5453d5a04cba7df20e3b672 Mon Sep 17 00:00:00 2001 From: tytung Date: Fri, 29 Jun 2012 02:04:58 +0800 Subject: [PATCH] net: bluetooth: Hold wakelock until BT idle timer kicks in. Source: https://github.com/dorimanx/Dorimanx-HD2-2.6.32.X/commit/7e394e255119ad31a986e2d3f7cef3f134e10a79 --- include/net/bluetooth/hci_core.h | 7 +++++-- net/bluetooth/hci_conn.c | 30 ++++++++++++++++++++++++++++-- net/bluetooth/hci_event.c | 6 ++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2ac98852..748f853b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -26,7 +26,7 @@ #define __HCI_CORE_H #include - +#include /* HCI upper protocols */ #define HCI_PROTO_L2CAP 0 #define HCI_PROTO_SCO 1 @@ -183,10 +183,11 @@ struct hci_conn { struct timer_list disc_timer; struct timer_list idle_timer; + struct timer_list auto_accept_timer; struct work_struct work_add; struct work_struct work_del; - + struct wake_lock idle_lock; struct device dev; atomic_t devref; @@ -246,6 +247,7 @@ enum { HCI_CONN_ENCRYPT_PEND, HCI_CONN_RSWITCH_PEND, HCI_CONN_MODE_CHANGE_PEND, + HCI_CONN_SCO_SETUP_PEND, }; static inline void hci_conn_hash_init(struct hci_dev *hdev) @@ -326,6 +328,7 @@ void hci_acl_connect(struct hci_conn *conn); void hci_acl_disconn(struct hci_conn *conn, __u8 reason); void hci_add_sco(struct hci_conn *conn, __u16 handle); void hci_setup_sync(struct hci_conn *conn, __u16 handle); +void hci_sco_setup(struct hci_conn *conn, __u8 status); struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, __u16 pkt_type, bdaddr_t *dst); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 2f4d30fd..c22bc17c 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -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; @@ -216,6 +237,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, conn->power_save = 1; conn->disc_timeout = HCI_DISCONN_TIMEOUT; + wake_lock_init(&conn->idle_lock, WAKE_LOCK_SUSPEND, "bt_idle"); switch (type) { case ACL_LINK: @@ -271,9 +293,11 @@ int hci_conn_del(struct hci_conn *conn) BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); + /* Make sure no timers are running */ del_timer(&conn->idle_timer); - + wake_lock_destroy(&conn->idle_lock); del_timer(&conn->disc_timer); + del_timer(&conn->auto_accept_timer); if (conn->type == ACL_LINK) { struct hci_conn *sco = conn->link; @@ -521,9 +545,11 @@ void hci_conn_enter_active_mode(struct hci_conn *conn) } timer: - if (hdev->idle_timeout > 0) + if (hdev->idle_timeout > 0) { mod_timer(&conn->idle_timer, jiffies + msecs_to_jiffies(hdev->idle_timeout)); + wake_lock(&conn->idle_lock); + } } /* Enter sniff mode */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8c59afcc..6b0b59c4 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1482,6 +1482,12 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb else conn->power_save = 0; } + if (conn->mode == HCI_CM_SNIFF) + if (wake_lock_active(&conn->idle_lock)) + wake_unlock(&conn->idle_lock); + + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend)) + hci_sco_setup(conn, ev->status); } hci_dev_unlock(hdev);