diff options
-rw-r--r-- | include/net/bluetooth/hci.h | 3 | ||||
-rw-r--r-- | include/net/bluetooth/hci_core.h | 2 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 22 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 6 |
4 files changed, 26 insertions, 7 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index e756f82a29e5..6d4e11624fef 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h | |||
@@ -119,6 +119,7 @@ enum { | |||
119 | #define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */ | 119 | #define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */ |
120 | #define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */ | 120 | #define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */ |
121 | #define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ | 121 | #define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ |
122 | #define HCI_CMD_TIMEOUT (1000) /* 1 seconds */ | ||
122 | 123 | ||
123 | /* HCI data types */ | 124 | /* HCI data types */ |
124 | #define HCI_COMMAND_PKT 0x01 | 125 | #define HCI_COMMAND_PKT 0x01 |
@@ -244,6 +245,8 @@ enum { | |||
244 | #define HCI_AT_GENERAL_BONDING_MITM 0x05 | 245 | #define HCI_AT_GENERAL_BONDING_MITM 0x05 |
245 | 246 | ||
246 | /* ----- HCI Commands ---- */ | 247 | /* ----- HCI Commands ---- */ |
248 | #define HCI_OP_NOP 0x0000 | ||
249 | |||
247 | #define HCI_OP_INQUIRY 0x0401 | 250 | #define HCI_OP_INQUIRY 0x0401 |
248 | struct hci_cp_inquiry { | 251 | struct hci_cp_inquiry { |
249 | __u8 lap[3]; | 252 | __u8 lap[3]; |
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index d30b93c82fd4..ecd2acf24420 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -132,7 +132,6 @@ struct hci_dev { | |||
132 | unsigned int sco_pkts; | 132 | unsigned int sco_pkts; |
133 | unsigned int le_pkts; | 133 | unsigned int le_pkts; |
134 | 134 | ||
135 | unsigned long cmd_last_tx; | ||
136 | unsigned long acl_last_tx; | 135 | unsigned long acl_last_tx; |
137 | unsigned long sco_last_tx; | 136 | unsigned long sco_last_tx; |
138 | unsigned long le_last_tx; | 137 | unsigned long le_last_tx; |
@@ -143,6 +142,7 @@ struct hci_dev { | |||
143 | struct work_struct power_off; | 142 | struct work_struct power_off; |
144 | struct timer_list off_timer; | 143 | struct timer_list off_timer; |
145 | 144 | ||
145 | struct timer_list cmd_timer; | ||
146 | struct tasklet_struct cmd_task; | 146 | struct tasklet_struct cmd_task; |
147 | struct tasklet_struct rx_task; | 147 | struct tasklet_struct rx_task; |
148 | struct tasklet_struct tx_task; | 148 | struct tasklet_struct tx_task; |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c01415bc8946..702d5651c656 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/interrupt.h> | 41 | #include <linux/interrupt.h> |
42 | #include <linux/notifier.h> | 42 | #include <linux/notifier.h> |
43 | #include <linux/rfkill.h> | 43 | #include <linux/rfkill.h> |
44 | #include <linux/timer.h> | ||
44 | #include <net/sock.h> | 45 | #include <net/sock.h> |
45 | 46 | ||
46 | #include <asm/system.h> | 47 | #include <asm/system.h> |
@@ -623,6 +624,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) | |||
623 | 624 | ||
624 | /* Drop last sent command */ | 625 | /* Drop last sent command */ |
625 | if (hdev->sent_cmd) { | 626 | if (hdev->sent_cmd) { |
627 | del_timer_sync(&hdev->cmd_timer); | ||
626 | kfree_skb(hdev->sent_cmd); | 628 | kfree_skb(hdev->sent_cmd); |
627 | hdev->sent_cmd = NULL; | 629 | hdev->sent_cmd = NULL; |
628 | } | 630 | } |
@@ -1066,6 +1068,16 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) | |||
1066 | return 0; | 1068 | return 0; |
1067 | } | 1069 | } |
1068 | 1070 | ||
1071 | /* HCI command timer function */ | ||
1072 | static void hci_cmd_timer(unsigned long arg) | ||
1073 | { | ||
1074 | struct hci_dev *hdev = (void *) arg; | ||
1075 | |||
1076 | BT_ERR("%s command tx timeout", hdev->name); | ||
1077 | atomic_set(&hdev->cmd_cnt, 1); | ||
1078 | tasklet_schedule(&hdev->cmd_task); | ||
1079 | } | ||
1080 | |||
1069 | /* Register HCI device */ | 1081 | /* Register HCI device */ |
1070 | int hci_register_dev(struct hci_dev *hdev) | 1082 | int hci_register_dev(struct hci_dev *hdev) |
1071 | { | 1083 | { |
@@ -1112,6 +1124,8 @@ int hci_register_dev(struct hci_dev *hdev) | |||
1112 | skb_queue_head_init(&hdev->cmd_q); | 1124 | skb_queue_head_init(&hdev->cmd_q); |
1113 | skb_queue_head_init(&hdev->raw_q); | 1125 | skb_queue_head_init(&hdev->raw_q); |
1114 | 1126 | ||
1127 | setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev); | ||
1128 | |||
1115 | for (i = 0; i < NUM_REASSEMBLY; i++) | 1129 | for (i = 0; i < NUM_REASSEMBLY; i++) |
1116 | hdev->reassembly[i] = NULL; | 1130 | hdev->reassembly[i] = NULL; |
1117 | 1131 | ||
@@ -2004,11 +2018,6 @@ static void hci_cmd_task(unsigned long arg) | |||
2004 | 2018 | ||
2005 | BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); | 2019 | BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); |
2006 | 2020 | ||
2007 | if (!atomic_read(&hdev->cmd_cnt) && time_after(jiffies, hdev->cmd_last_tx + HZ)) { | ||
2008 | BT_ERR("%s command tx timeout", hdev->name); | ||
2009 | atomic_set(&hdev->cmd_cnt, 1); | ||
2010 | } | ||
2011 | |||
2012 | /* Send queued commands */ | 2021 | /* Send queued commands */ |
2013 | if (atomic_read(&hdev->cmd_cnt)) { | 2022 | if (atomic_read(&hdev->cmd_cnt)) { |
2014 | skb = skb_dequeue(&hdev->cmd_q); | 2023 | skb = skb_dequeue(&hdev->cmd_q); |
@@ -2021,7 +2030,8 @@ static void hci_cmd_task(unsigned long arg) | |||
2021 | if (hdev->sent_cmd) { | 2030 | if (hdev->sent_cmd) { |
2022 | atomic_dec(&hdev->cmd_cnt); | 2031 | atomic_dec(&hdev->cmd_cnt); |
2023 | hci_send_frame(skb); | 2032 | hci_send_frame(skb); |
2024 | hdev->cmd_last_tx = jiffies; | 2033 | mod_timer(&hdev->cmd_timer, |
2034 | jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT)); | ||
2025 | } else { | 2035 | } else { |
2026 | skb_queue_head(&hdev->cmd_q, skb); | 2036 | skb_queue_head(&hdev->cmd_q, skb); |
2027 | tasklet_schedule(&hdev->cmd_task); | 2037 | tasklet_schedule(&hdev->cmd_task); |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 74f04a27734d..09cb29e8713a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -1732,6 +1732,9 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
1732 | break; | 1732 | break; |
1733 | } | 1733 | } |
1734 | 1734 | ||
1735 | if (ev->opcode != HCI_OP_NOP) | ||
1736 | del_timer(&hdev->cmd_timer); | ||
1737 | |||
1735 | if (ev->ncmd) { | 1738 | if (ev->ncmd) { |
1736 | atomic_set(&hdev->cmd_cnt, 1); | 1739 | atomic_set(&hdev->cmd_cnt, 1); |
1737 | if (!skb_queue_empty(&hdev->cmd_q)) | 1740 | if (!skb_queue_empty(&hdev->cmd_q)) |
@@ -1807,6 +1810,9 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
1807 | break; | 1810 | break; |
1808 | } | 1811 | } |
1809 | 1812 | ||
1813 | if (ev->opcode != HCI_OP_NOP) | ||
1814 | del_timer(&hdev->cmd_timer); | ||
1815 | |||
1810 | if (ev->ncmd) { | 1816 | if (ev->ncmd) { |
1811 | atomic_set(&hdev->cmd_cnt, 1); | 1817 | atomic_set(&hdev->cmd_cnt, 1); |
1812 | if (!skb_queue_empty(&hdev->cmd_q)) | 1818 | if (!skb_queue_empty(&hdev->cmd_q)) |