diff options
Diffstat (limited to 'drivers/bluetooth/btmrvl_main.c')
-rw-r--r-- | drivers/bluetooth/btmrvl_main.c | 129 |
1 files changed, 41 insertions, 88 deletions
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 9a9f51875df5..d9d42295e533 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c | |||
@@ -57,8 +57,7 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) | |||
57 | ocf = hci_opcode_ocf(opcode); | 57 | ocf = hci_opcode_ocf(opcode); |
58 | ogf = hci_opcode_ogf(opcode); | 58 | ogf = hci_opcode_ogf(opcode); |
59 | 59 | ||
60 | if (ocf == BT_CMD_MODULE_CFG_REQ && | 60 | if (priv->btmrvl_dev.sendcmdflag) { |
61 | priv->btmrvl_dev.sendcmdflag) { | ||
62 | priv->btmrvl_dev.sendcmdflag = false; | 61 | priv->btmrvl_dev.sendcmdflag = false; |
63 | priv->adapter->cmd_complete = true; | 62 | priv->adapter->cmd_complete = true; |
64 | wake_up_interruptible(&priv->adapter->cmd_wait_q); | 63 | wake_up_interruptible(&priv->adapter->cmd_wait_q); |
@@ -116,7 +115,6 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) | |||
116 | adapter->hs_state = HS_ACTIVATED; | 115 | adapter->hs_state = HS_ACTIVATED; |
117 | if (adapter->psmode) | 116 | if (adapter->psmode) |
118 | adapter->ps_state = PS_SLEEP; | 117 | adapter->ps_state = PS_SLEEP; |
119 | wake_up_interruptible(&adapter->cmd_wait_q); | ||
120 | BT_DBG("HS ACTIVATED!"); | 118 | BT_DBG("HS ACTIVATED!"); |
121 | } else { | 119 | } else { |
122 | BT_DBG("HS Enable failed"); | 120 | BT_DBG("HS Enable failed"); |
@@ -168,11 +166,11 @@ exit: | |||
168 | } | 166 | } |
169 | EXPORT_SYMBOL_GPL(btmrvl_process_event); | 167 | EXPORT_SYMBOL_GPL(btmrvl_process_event); |
170 | 168 | ||
171 | int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) | 169 | static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 cmd_no, |
170 | const void *param, u8 len) | ||
172 | { | 171 | { |
173 | struct sk_buff *skb; | 172 | struct sk_buff *skb; |
174 | struct btmrvl_cmd *cmd; | 173 | struct btmrvl_cmd *cmd; |
175 | int ret = 0; | ||
176 | 174 | ||
177 | skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); | 175 | skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); |
178 | if (skb == NULL) { | 176 | if (skb == NULL) { |
@@ -181,9 +179,11 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) | |||
181 | } | 179 | } |
182 | 180 | ||
183 | cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); | 181 | cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); |
184 | cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_MODULE_CFG_REQ)); | 182 | cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, cmd_no)); |
185 | cmd->length = 1; | 183 | cmd->length = len; |
186 | cmd->data[0] = subcmd; | 184 | |
185 | if (len) | ||
186 | memcpy(cmd->data, param, len); | ||
187 | 187 | ||
188 | bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; | 188 | bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; |
189 | 189 | ||
@@ -194,19 +194,23 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) | |||
194 | 194 | ||
195 | priv->adapter->cmd_complete = false; | 195 | priv->adapter->cmd_complete = false; |
196 | 196 | ||
197 | BT_DBG("Queue module cfg Command"); | ||
198 | |||
199 | wake_up_interruptible(&priv->main_thread.wait_q); | 197 | wake_up_interruptible(&priv->main_thread.wait_q); |
200 | 198 | ||
201 | if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q, | 199 | if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q, |
202 | priv->adapter->cmd_complete, | 200 | priv->adapter->cmd_complete, |
203 | msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) { | 201 | msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) |
204 | ret = -ETIMEDOUT; | 202 | return -ETIMEDOUT; |
205 | BT_ERR("module_cfg_cmd(%x): timeout: %d", | ||
206 | subcmd, priv->btmrvl_dev.sendcmdflag); | ||
207 | } | ||
208 | 203 | ||
209 | BT_DBG("module cfg Command done"); | 204 | return 0; |
205 | } | ||
206 | |||
207 | int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) | ||
208 | { | ||
209 | int ret; | ||
210 | |||
211 | ret = btmrvl_send_sync_cmd(priv, BT_CMD_MODULE_CFG_REQ, &subcmd, 1); | ||
212 | if (ret) | ||
213 | BT_ERR("module_cfg_cmd(%x) failed\n", subcmd); | ||
210 | 214 | ||
211 | return ret; | 215 | return ret; |
212 | } | 216 | } |
@@ -214,61 +218,36 @@ EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); | |||
214 | 218 | ||
215 | int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv) | 219 | int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv) |
216 | { | 220 | { |
217 | struct sk_buff *skb; | 221 | int ret; |
218 | struct btmrvl_cmd *cmd; | 222 | u8 param[2]; |
219 | |||
220 | skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); | ||
221 | if (!skb) { | ||
222 | BT_ERR("No free skb"); | ||
223 | return -ENOMEM; | ||
224 | } | ||
225 | |||
226 | cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); | ||
227 | cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, | ||
228 | BT_CMD_HOST_SLEEP_CONFIG)); | ||
229 | cmd->length = 2; | ||
230 | cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8; | ||
231 | cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff); | ||
232 | 223 | ||
233 | bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; | 224 | param[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8; |
225 | param[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff); | ||
234 | 226 | ||
235 | skb->dev = (void *) priv->btmrvl_dev.hcidev; | 227 | BT_DBG("Sending HSCFG Command, gpio=0x%x, gap=0x%x", |
236 | skb_queue_head(&priv->adapter->tx_queue, skb); | 228 | param[0], param[1]); |
237 | 229 | ||
238 | BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x", cmd->data[0], | 230 | ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_CONFIG, param, 2); |
239 | cmd->data[1]); | 231 | if (ret) |
232 | BT_ERR("HSCFG command failed\n"); | ||
240 | 233 | ||
241 | return 0; | 234 | return ret; |
242 | } | 235 | } |
243 | EXPORT_SYMBOL_GPL(btmrvl_send_hscfg_cmd); | 236 | EXPORT_SYMBOL_GPL(btmrvl_send_hscfg_cmd); |
244 | 237 | ||
245 | int btmrvl_enable_ps(struct btmrvl_private *priv) | 238 | int btmrvl_enable_ps(struct btmrvl_private *priv) |
246 | { | 239 | { |
247 | struct sk_buff *skb; | 240 | int ret; |
248 | struct btmrvl_cmd *cmd; | 241 | u8 param; |
249 | |||
250 | skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); | ||
251 | if (skb == NULL) { | ||
252 | BT_ERR("No free skb"); | ||
253 | return -ENOMEM; | ||
254 | } | ||
255 | |||
256 | cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); | ||
257 | cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, | ||
258 | BT_CMD_AUTO_SLEEP_MODE)); | ||
259 | cmd->length = 1; | ||
260 | 242 | ||
261 | if (priv->btmrvl_dev.psmode) | 243 | if (priv->btmrvl_dev.psmode) |
262 | cmd->data[0] = BT_PS_ENABLE; | 244 | param = BT_PS_ENABLE; |
263 | else | 245 | else |
264 | cmd->data[0] = BT_PS_DISABLE; | 246 | param = BT_PS_DISABLE; |
265 | |||
266 | bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; | ||
267 | |||
268 | skb->dev = (void *) priv->btmrvl_dev.hcidev; | ||
269 | skb_queue_head(&priv->adapter->tx_queue, skb); | ||
270 | 247 | ||
271 | BT_DBG("Queue PSMODE Command:%d", cmd->data[0]); | 248 | ret = btmrvl_send_sync_cmd(priv, BT_CMD_AUTO_SLEEP_MODE, ¶m, 1); |
249 | if (ret) | ||
250 | BT_ERR("PSMODE command failed\n"); | ||
272 | 251 | ||
273 | return 0; | 252 | return 0; |
274 | } | 253 | } |
@@ -276,37 +255,11 @@ EXPORT_SYMBOL_GPL(btmrvl_enable_ps); | |||
276 | 255 | ||
277 | int btmrvl_enable_hs(struct btmrvl_private *priv) | 256 | int btmrvl_enable_hs(struct btmrvl_private *priv) |
278 | { | 257 | { |
279 | struct sk_buff *skb; | 258 | int ret; |
280 | struct btmrvl_cmd *cmd; | ||
281 | int ret = 0; | ||
282 | |||
283 | skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); | ||
284 | if (skb == NULL) { | ||
285 | BT_ERR("No free skb"); | ||
286 | return -ENOMEM; | ||
287 | } | ||
288 | |||
289 | cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); | ||
290 | cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_ENABLE)); | ||
291 | cmd->length = 0; | ||
292 | |||
293 | bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; | ||
294 | |||
295 | skb->dev = (void *) priv->btmrvl_dev.hcidev; | ||
296 | skb_queue_head(&priv->adapter->tx_queue, skb); | ||
297 | |||
298 | BT_DBG("Queue hs enable Command"); | ||
299 | |||
300 | wake_up_interruptible(&priv->main_thread.wait_q); | ||
301 | 259 | ||
302 | if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q, | 260 | ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_ENABLE, NULL, 0); |
303 | priv->adapter->hs_state, | 261 | if (ret) |
304 | msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED))) { | 262 | BT_ERR("Host sleep enable command failed\n"); |
305 | ret = -ETIMEDOUT; | ||
306 | BT_ERR("timeout: %d, %d,%d", priv->adapter->hs_state, | ||
307 | priv->adapter->ps_state, | ||
308 | priv->adapter->wakeup_tries); | ||
309 | } | ||
310 | 263 | ||
311 | return ret; | 264 | return ret; |
312 | } | 265 | } |