aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth
diff options
context:
space:
mode:
authorBing Zhao <bzhao@marvell.com>2009-06-02 17:29:35 -0400
committerMarcel Holtmann <marcel@holtmann.org>2009-08-22 17:25:32 -0400
commit132ff4e5fa8dfb71a7d99902f88043113947e972 (patch)
tree3fb4b236d8bfafd7c0a74f55a2d324189e0ccd91 /drivers/bluetooth
parentedad63886993d18ab800c49f6587a93432ef8b35 (diff)
Bluetooth: Add btmrvl driver for Marvell Bluetooth devices
This driver provides basic definitions and library functions to support Marvell Bluetooth enabled devices, such as 88W8688 WLAN/BT combo chip. This patch incorporates a lot of comments given by Nicolas Pitre <nico@marvell.com>. Many thanks to Nicolas Pitre. Signed-off-by: Rahul Tank <rahult@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r--drivers/bluetooth/Kconfig12
-rw-r--r--drivers/bluetooth/Makefile3
-rw-r--r--drivers/bluetooth/btmrvl_drv.h138
-rw-r--r--drivers/bluetooth/btmrvl_main.c714
4 files changed, 867 insertions, 0 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 1164837bb781..b049a79fcc02 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -170,5 +170,17 @@ config BT_HCIVHCI
170 Say Y here to compile support for virtual HCI devices into the 170 Say Y here to compile support for virtual HCI devices into the
171 kernel or say M to compile it as module (hci_vhci). 171 kernel or say M to compile it as module (hci_vhci).
172 172
173config BT_MRVL
174 tristate "Marvell Bluetooth driver support"
175 select FW_LOADER
176 help
177 The core driver to support Marvell Bluetooth devices.
178
179 This driver is required if you want to support
180 Marvell Bluetooth devices, such as 8688.
181
182 Say Y here to compile Marvell Bluetooth driver
183 into the kernel or say M to compile it as module.
184
173endmenu 185endmenu
174 186
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 16930f93d1ca..3eff1231812c 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -15,6 +15,9 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
15obj-$(CONFIG_BT_HCIBTUSB) += btusb.o 15obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
16obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o 16obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
17 17
18btmrvl-objs := btmrvl_main.o
19obj-$(CONFIG_BT_MRVL) += btmrvl.o
20
18hci_uart-y := hci_ldisc.o 21hci_uart-y := hci_ldisc.o
19hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o 22hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
20hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o 23hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
new file mode 100644
index 000000000000..9ad71f48110d
--- /dev/null
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -0,0 +1,138 @@
1/*
2 * Marvell Bluetooth driver: global definitions & declarations
3 *
4 * Copyright (C) 2009, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 *
15 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
18 * this warranty disclaimer.
19 *
20 */
21
22#ifndef _BTMRVL_DRV_H_
23#define _BTMRVL_DRV_H_
24
25#include <linux/kthread.h>
26#include <linux/bitops.h>
27#include <net/bluetooth/bluetooth.h>
28
29#define BTM_HEADER_LEN 4
30#define BTM_DEV_NAME_LEN 32
31#define BTM_UPLD_SIZE 2312
32
33/* Time to wait until Host Sleep state change in millisecond */
34#define WAIT_UNTIL_HS_STATE_CHANGED 5000
35/* Time to wait for command response in millisecond */
36#define WAIT_UNTIL_CMD_RESP 5000
37
38struct btmrvl_thread {
39 struct task_struct *task;
40 wait_queue_head_t wait_q;
41 void *priv;
42};
43
44struct btmrvl_device {
45 char name[BTM_DEV_NAME_LEN];
46 void *card;
47 struct hci_dev *hcidev;
48
49 u8 tx_dnld_rdy;
50
51 u8 psmode;
52 u8 pscmd;
53 u8 hsmode;
54 u8 hscmd;
55
56 /* Low byte is gap, high byte is GPIO */
57 u16 gpio_gap;
58
59 u8 hscfgcmd;
60 u8 sendcmdflag;
61};
62
63struct btmrvl_adapter {
64 u32 int_count;
65 struct sk_buff_head tx_queue;
66 u8 psmode;
67 u8 ps_state;
68 u8 hs_state;
69 u8 wakeup_tries;
70 wait_queue_head_t cmd_wait_q;
71 u8 cmd_complete;
72};
73
74struct btmrvl_private {
75 struct btmrvl_device btmrvl_dev;
76 struct btmrvl_adapter *adapter;
77 struct btmrvl_thread main_thread;
78 int (*hw_host_to_card) (struct btmrvl_private *priv,
79 u8 *payload, u16 nb);
80 int (*hw_wakeup_firmware) (struct btmrvl_private *priv);
81 spinlock_t driver_lock; /* spinlock used by driver */
82};
83
84#define MRVL_VENDOR_PKT 0xFE
85
86/* Bluetooth commands */
87#define BT_CMD_AUTO_SLEEP_MODE 0x23
88#define BT_CMD_HOST_SLEEP_CONFIG 0x59
89#define BT_CMD_HOST_SLEEP_ENABLE 0x5A
90#define BT_CMD_MODULE_CFG_REQ 0x5B
91
92/* Sub-commands: Module Bringup/Shutdown Request */
93#define MODULE_BRINGUP_REQ 0xF1
94#define MODULE_SHUTDOWN_REQ 0xF2
95
96#define BT_EVENT_POWER_STATE 0x20
97
98/* Bluetooth Power States */
99#define BT_PS_ENABLE 0x02
100#define BT_PS_DISABLE 0x03
101#define BT_PS_SLEEP 0x01
102
103#define OGF 0x3F
104
105/* Host Sleep states */
106#define HS_ACTIVATED 0x01
107#define HS_DEACTIVATED 0x00
108
109/* Power Save modes */
110#define PS_SLEEP 0x01
111#define PS_AWAKE 0x00
112
113struct btmrvl_cmd {
114 __le16 ocf_ogf;
115 u8 length;
116 u8 data[4];
117} __attribute__ ((packed));
118
119struct btmrvl_event {
120 u8 ec; /* event counter */
121 u8 length;
122 u8 data[4];
123} __attribute__ ((packed));
124
125/* Prototype of global function */
126
127struct btmrvl_private *btmrvl_add_card(void *card);
128int btmrvl_remove_card(struct btmrvl_private *priv);
129
130void btmrvl_interrupt(struct btmrvl_private *priv);
131
132void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
133int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
134
135int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
136int btmrvl_prepare_command(struct btmrvl_private *priv);
137
138#endif /* _BTMRVL_DRV_H_ */
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
new file mode 100644
index 000000000000..11c2f2cecf18
--- /dev/null
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -0,0 +1,714 @@
1/**
2 * Marvell Bluetooth driver
3 *
4 * Copyright (C) 2009, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 *
15 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
18 * this warranty disclaimer.
19 **/
20
21#include <net/bluetooth/bluetooth.h>
22#include <net/bluetooth/hci_core.h>
23
24#include "btmrvl_drv.h"
25
26#define VERSION "1.0"
27
28/*
29 * This function is called by interface specific interrupt handler.
30 * It updates Power Save & Host Sleep states, and wakes up the main
31 * thread.
32 */
33void btmrvl_interrupt(struct btmrvl_private *priv)
34{
35 BT_DBG("Enter");
36
37 priv->adapter->ps_state = PS_AWAKE;
38
39 priv->adapter->wakeup_tries = 0;
40
41 priv->adapter->int_count++;
42
43 wake_up_interruptible(&priv->main_thread.wait_q);
44
45 BT_DBG("Leave");
46}
47EXPORT_SYMBOL_GPL(btmrvl_interrupt);
48
49void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
50{
51 struct hci_event_hdr *hdr = (struct hci_event_hdr *)skb->data;
52 struct hci_ev_cmd_complete *ec;
53 u16 opcode, ocf;
54
55 BT_DBG("Enter");
56
57 if (hdr->evt == HCI_EV_CMD_COMPLETE) {
58 ec = (struct hci_ev_cmd_complete *)(skb->data +
59 HCI_EVENT_HDR_SIZE);
60 opcode = __le16_to_cpu(ec->opcode);
61 ocf = hci_opcode_ocf(opcode);
62 if ((ocf == BT_CMD_MODULE_CFG_REQ) &&
63 (priv->btmrvl_dev.sendcmdflag)) {
64 priv->btmrvl_dev.sendcmdflag = false;
65 priv->adapter->cmd_complete = true;
66 wake_up_interruptible(&priv->adapter->cmd_wait_q);
67 }
68 }
69
70 BT_DBG("Leave");
71}
72EXPORT_SYMBOL_GPL(btmrvl_check_evtpkt);
73
74int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
75{
76 struct btmrvl_adapter *adapter = priv->adapter;
77 u8 ret = 0;
78 struct btmrvl_event *event;
79
80 BT_DBG("Enter");
81
82 event = (struct btmrvl_event *) skb->data;
83 if (event->ec != 0xff) {
84 BT_DBG("Not Marvell Event=%x", event->ec);
85 ret = -EINVAL;
86 goto exit;
87 }
88
89 switch (event->data[0]) {
90 case BT_CMD_AUTO_SLEEP_MODE:
91 if (!event->data[2]) {
92 if (event->data[1] == BT_PS_ENABLE)
93 adapter->psmode = 1;
94 else
95 adapter->psmode = 0;
96 BT_DBG("PS Mode:%s",
97 (adapter->psmode) ? "Enable" : "Disable");
98 } else {
99 BT_DBG("PS Mode command failed");
100 }
101 break;
102
103 case BT_CMD_HOST_SLEEP_CONFIG:
104 if (!event->data[3])
105 BT_DBG("gpio=%x, gap=%x", event->data[1],
106 event->data[2]);
107 else
108 BT_DBG("HSCFG command failed");
109 break;
110
111 case BT_CMD_HOST_SLEEP_ENABLE:
112 if (!event->data[1]) {
113 adapter->hs_state = HS_ACTIVATED;
114 if (adapter->psmode)
115 adapter->ps_state = PS_SLEEP;
116 wake_up_interruptible(&adapter->cmd_wait_q);
117 BT_DBG("HS ACTIVATED!");
118 } else {
119 BT_DBG("HS Enable failed");
120 }
121 break;
122
123 case BT_CMD_MODULE_CFG_REQ:
124 if ((priv->btmrvl_dev.sendcmdflag) &&
125 (event->data[1] == MODULE_BRINGUP_REQ)) {
126 BT_DBG("EVENT:%s", (event->data[2]) ?
127 "Bring-up failed" : "Bring-up succeed");
128 } else if ((priv->btmrvl_dev.sendcmdflag) &&
129 (event->data[1] == MODULE_SHUTDOWN_REQ)) {
130 BT_DBG("EVENT:%s", (event->data[2]) ?
131 "Shutdown failed" : "Shutdown succeed");
132 } else {
133 BT_DBG("BT_CMD_MODULE_CFG_REQ resp for APP");
134 ret = -EINVAL;
135 }
136 break;
137
138 case BT_EVENT_POWER_STATE:
139 if (event->data[1] == BT_PS_SLEEP)
140 adapter->ps_state = PS_SLEEP;
141 BT_DBG("EVENT:%s",
142 (adapter->ps_state) ? "PS_SLEEP" : "PS_AWAKE");
143 break;
144
145 default:
146 BT_DBG("Unknown Event=%d", event->data[0]);
147 ret = -EINVAL;
148 break;
149 }
150
151exit:
152 if (!ret)
153 kfree_skb(skb);
154
155 BT_DBG("Leave");
156
157 return ret;
158}
159EXPORT_SYMBOL_GPL(btmrvl_process_event);
160
161int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
162{
163 struct sk_buff *skb = NULL;
164 u8 ret = 0;
165 struct btmrvl_cmd *cmd;
166
167 BT_DBG("Enter");
168
169 skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
170 if (skb == NULL) {
171 BT_ERR("No free skb");
172 ret = -ENOMEM;
173 goto exit;
174 }
175
176 cmd = (struct btmrvl_cmd *) skb->tail;
177 cmd->ocf_ogf = cpu_to_le16((OGF << 10) | BT_CMD_MODULE_CFG_REQ);
178 cmd->length = 1;
179 cmd->data[0] = subcmd;
180
181 bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
182
183 skb_put(skb, sizeof(*cmd));
184 skb->dev = (void *)priv->btmrvl_dev.hcidev;
185 skb_queue_head(&priv->adapter->tx_queue, skb);
186
187 priv->btmrvl_dev.sendcmdflag = true;
188
189 priv->adapter->cmd_complete = false;
190
191 BT_DBG("Queue module cfg Command");
192
193 wake_up_interruptible(&priv->main_thread.wait_q);
194
195 if (!wait_event_interruptible_timeout(
196 priv->adapter->cmd_wait_q,
197 priv->adapter->cmd_complete,
198 msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) {
199 ret = -ETIMEDOUT;
200 BT_ERR("module_cfg_cmd(%x): timeout: %d",
201 subcmd, priv->btmrvl_dev.sendcmdflag);
202 }
203
204 BT_DBG("module cfg Command done");
205
206exit:
207 BT_DBG("Leave");
208
209 return ret;
210}
211EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd);
212
213static int btmrvl_enable_hs(struct btmrvl_private *priv)
214{
215 struct sk_buff *skb = NULL;
216 u8 ret = 0;
217 struct btmrvl_cmd *cmd;
218
219 BT_DBG("Enter");
220
221 skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
222 if (skb == NULL) {
223 BT_ERR("No free skb");
224 ret = -ENOMEM;
225 goto exit;
226 }
227
228 cmd = (struct btmrvl_cmd *) skb->tail;
229 cmd->ocf_ogf = cpu_to_le16((OGF << 10) | BT_CMD_HOST_SLEEP_ENABLE);
230 cmd->length = 0;
231
232 bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
233
234 skb_put(skb, sizeof(*cmd));
235 skb->dev = (void *)priv->btmrvl_dev.hcidev;
236 skb_queue_head(&priv->adapter->tx_queue, skb);
237
238 BT_DBG("Queue hs enable Command");
239
240 wake_up_interruptible(&priv->main_thread.wait_q);
241
242 if (!wait_event_interruptible_timeout(
243 priv->adapter->cmd_wait_q,
244 priv->adapter->hs_state,
245 msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED))) {
246 ret = -ETIMEDOUT;
247 BT_ERR("timeout: %d, %d,%d",
248 priv->adapter->hs_state,
249 priv->adapter->ps_state,
250 priv->adapter->wakeup_tries);
251 }
252
253exit:
254 BT_DBG("Leave");
255
256 return ret;
257}
258
259int btmrvl_prepare_command(struct btmrvl_private *priv)
260{
261 struct sk_buff *skb = NULL;
262 u8 ret = 0;
263 struct btmrvl_cmd *cmd;
264
265 BT_DBG("Enter");
266
267 if (priv->btmrvl_dev.hscfgcmd) {
268 priv->btmrvl_dev.hscfgcmd = 0;
269
270 skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
271 if (skb == NULL) {
272 BT_ERR("No free skb");
273 ret = -ENOMEM;
274 goto exit;
275 }
276
277 cmd = (struct btmrvl_cmd *) skb->tail;
278 cmd->ocf_ogf = cpu_to_le16((OGF << 10) |
279 BT_CMD_HOST_SLEEP_CONFIG);
280 cmd->length = 2;
281 cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
282 cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff);
283
284 bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
285
286 skb_put(skb, sizeof(*cmd));
287 skb->dev = (void *)priv->btmrvl_dev.hcidev;
288 skb_queue_head(&priv->adapter->tx_queue, skb);
289
290 BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x",
291 cmd->data[0], cmd->data[1]);
292 }
293
294 if (priv->btmrvl_dev.pscmd) {
295 priv->btmrvl_dev.pscmd = 0;
296
297 skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
298 if (skb == NULL) {
299 BT_ERR("No free skb");
300 ret = -ENOMEM;
301 goto exit;
302 }
303
304 cmd = (struct btmrvl_cmd *) skb->tail;
305 cmd->ocf_ogf = cpu_to_le16((OGF << 10) |
306 BT_CMD_AUTO_SLEEP_MODE);
307 cmd->length = 1;
308
309 if (priv->btmrvl_dev.psmode)
310 cmd->data[0] = BT_PS_ENABLE;
311 else
312 cmd->data[0] = BT_PS_DISABLE;
313
314 bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
315
316 skb_put(skb, sizeof(*cmd));
317 skb->dev = (void *)priv->btmrvl_dev.hcidev;
318 skb_queue_head(&priv->adapter->tx_queue, skb);
319
320 BT_DBG("Queue PSMODE Command:%d", cmd->data[0]);
321 }
322
323 if (priv->btmrvl_dev.hscmd) {
324 priv->btmrvl_dev.hscmd = 0;
325
326 if (priv->btmrvl_dev.hsmode) {
327 ret = btmrvl_enable_hs(priv);
328 } else {
329 ret = priv->hw_wakeup_firmware(priv);
330 priv->adapter->hs_state = HS_DEACTIVATED;
331 }
332 }
333
334exit:
335 BT_DBG("Leave");
336
337 return ret;
338}
339
340static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb)
341{
342 u8 ret = 0;
343
344 BT_DBG("Enter");
345
346 if (!skb || !skb->data) {
347 BT_DBG("Leave");
348 return -EINVAL;
349 }
350
351 if (!skb->len || ((skb->len + BTM_HEADER_LEN) > BTM_UPLD_SIZE)) {
352 BT_ERR("Tx Error: Bad skb length %d : %d",
353 skb->len, BTM_UPLD_SIZE);
354 BT_DBG("Leave");
355 return -EINVAL;
356 }
357
358 if (skb_headroom(skb) < BTM_HEADER_LEN) {
359 struct sk_buff *tmp = skb;
360
361 skb = skb_realloc_headroom(skb, BTM_HEADER_LEN);
362 if (!skb) {
363 BT_ERR("Tx Error: realloc_headroom failed %d",
364 BTM_HEADER_LEN);
365 skb = tmp;
366 BT_DBG("Leave");
367 return -EINVAL;
368 }
369
370 kfree_skb(tmp);
371 }
372
373 skb_push(skb, BTM_HEADER_LEN);
374
375 /* header type: byte[3]
376 * HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor
377 * header length: byte[2][1][0]
378 */
379
380 skb->data[0] = (skb->len & 0x0000ff);
381 skb->data[1] = (skb->len & 0x00ff00) >> 8;
382 skb->data[2] = (skb->len & 0xff0000) >> 16;
383 skb->data[3] = bt_cb(skb)->pkt_type;
384
385 if (priv->hw_host_to_card)
386 ret = priv->hw_host_to_card(priv, skb->data, skb->len);
387
388 BT_DBG("Leave");
389
390 return ret;
391}
392
393static void btmrvl_init_adapter(struct btmrvl_private *priv)
394{
395 BT_DBG("Enter");
396
397 skb_queue_head_init(&priv->adapter->tx_queue);
398
399 priv->adapter->ps_state = PS_AWAKE;
400
401 init_waitqueue_head(&priv->adapter->cmd_wait_q);
402
403 BT_DBG("Leave");
404}
405
406static void btmrvl_free_adapter(struct btmrvl_private *priv)
407{
408 BT_DBG("Enter");
409
410 skb_queue_purge(&priv->adapter->tx_queue);
411
412 kfree(priv->adapter);
413
414 priv->adapter = NULL;
415
416 BT_DBG("Leave");
417}
418
419static int
420btmrvl_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
421{
422 BT_DBG("Enter");
423
424 BT_DBG("Leave");
425
426 return -ENOIOCTLCMD;
427}
428
429static void btmrvl_destruct(struct hci_dev *hdev)
430{
431 BT_DBG("Enter");
432
433 BT_DBG("Leave");
434}
435
436static int btmrvl_send_frame(struct sk_buff *skb)
437{
438 struct hci_dev *hdev = (struct hci_dev *)skb->dev;
439 struct btmrvl_private *priv = NULL;
440
441 BT_DBG("Enter: type=%d, len=%d", skb->pkt_type, skb->len);
442
443 if (!hdev || !hdev->driver_data) {
444 BT_ERR("Frame for unknown HCI device");
445 BT_DBG("Leave");
446 return -ENODEV;
447 }
448
449 priv = (struct btmrvl_private *)hdev->driver_data;
450 if (!test_bit(HCI_RUNNING, &hdev->flags)) {
451 BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags);
452 print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET,
453 skb->data, skb->len);
454 BT_DBG("Leave");
455 return -EBUSY;
456 }
457
458 switch (bt_cb(skb)->pkt_type) {
459 case HCI_COMMAND_PKT:
460 hdev->stat.cmd_tx++;
461 break;
462
463 case HCI_ACLDATA_PKT:
464 hdev->stat.acl_tx++;
465 break;
466
467 case HCI_SCODATA_PKT:
468 hdev->stat.sco_tx++;
469 break;
470 }
471
472 skb_queue_tail(&priv->adapter->tx_queue, skb);
473
474 wake_up_interruptible(&priv->main_thread.wait_q);
475
476 BT_DBG("Leave");
477
478 return 0;
479}
480
481static int btmrvl_flush(struct hci_dev *hdev)
482{
483 struct btmrvl_private *priv =
484 (struct btmrvl_private *) hdev->driver_data;
485
486 BT_DBG("Enter");
487
488 skb_queue_purge(&priv->adapter->tx_queue);
489
490 BT_DBG("Leave");
491
492 return 0;
493}
494
495static int btmrvl_close(struct hci_dev *hdev)
496{
497 struct btmrvl_private *priv =
498 (struct btmrvl_private *) hdev->driver_data;
499
500 BT_DBG("Enter");
501
502 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) {
503 BT_DBG("Leave");
504 return 0;
505 }
506
507 skb_queue_purge(&priv->adapter->tx_queue);
508
509 BT_DBG("Leave");
510
511 return 0;
512}
513
514static int btmrvl_open(struct hci_dev *hdev)
515{
516 BT_DBG("Enter");
517
518 set_bit(HCI_RUNNING, &hdev->flags);
519
520 BT_DBG("Leave");
521
522 return 0;
523}
524
525/*
526 * This function handles the event generated by firmware, rx data
527 * received from firmware, and tx data sent from kernel.
528 */
529static int btmrvl_service_main_thread(void *data)
530{
531 struct btmrvl_thread *thread = data;
532 struct btmrvl_private *priv = thread->priv;
533 struct btmrvl_adapter *adapter = priv->adapter;
534 wait_queue_t wait;
535 struct sk_buff *skb;
536 ulong flags;
537
538 BT_DBG("Enter");
539
540 init_waitqueue_entry(&wait, current);
541
542 current->flags |= PF_NOFREEZE;
543
544 for (;;) {
545 add_wait_queue(&thread->wait_q, &wait);
546
547 set_current_state(TASK_INTERRUPTIBLE);
548
549 if (adapter->wakeup_tries ||
550 ((!adapter->int_count) &&
551 (!priv->btmrvl_dev.tx_dnld_rdy ||
552 skb_queue_empty(&adapter->tx_queue)))) {
553 BT_DBG("main_thread is sleeping...");
554 schedule();
555 }
556
557 set_current_state(TASK_RUNNING);
558
559 remove_wait_queue(&thread->wait_q, &wait);
560
561 BT_DBG("main_thread woke up");
562
563 if (kthread_should_stop()) {
564 BT_DBG("main_thread: break from main thread");
565 break;
566 }
567
568 spin_lock_irqsave(&priv->driver_lock, flags);
569 if (adapter->int_count) {
570 adapter->int_count = 0;
571 } else if ((adapter->ps_state == PS_SLEEP) &&
572 !skb_queue_empty(&adapter->tx_queue)) {
573 spin_unlock_irqrestore(&priv->driver_lock, flags);
574 adapter->wakeup_tries++;
575 priv->hw_wakeup_firmware(priv);
576 continue;
577 }
578 spin_unlock_irqrestore(&priv->driver_lock, flags);
579
580 if (adapter->ps_state == PS_SLEEP)
581 continue;
582
583 if (!priv->btmrvl_dev.tx_dnld_rdy)
584 continue;
585
586 skb = skb_dequeue(&adapter->tx_queue);
587 if (skb) {
588 if (btmrvl_tx_pkt(priv, skb))
589 priv->btmrvl_dev.hcidev->stat.err_tx++;
590 else
591 priv->btmrvl_dev.hcidev->stat.byte_tx
592 += skb->len;
593
594 kfree_skb(skb);
595 }
596 }
597
598 BT_DBG("Leave");
599
600 return 0;
601}
602
603struct btmrvl_private *btmrvl_add_card(void *card)
604{
605 struct hci_dev *hdev = NULL;
606 struct btmrvl_private *priv = NULL;
607 int ret;
608
609 BT_DBG("Enter");
610
611 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
612 if (!priv) {
613 BT_ERR("Can not allocate priv");
614 goto err_priv;
615 }
616
617 priv->adapter = kzalloc(sizeof(*priv->adapter), GFP_KERNEL);
618 if (!priv->adapter) {
619 BT_ERR("Allocate buffer for btmrvl_adapter failed!");
620 goto err_adapter;
621 }
622
623 btmrvl_init_adapter(priv);
624
625 hdev = hci_alloc_dev();
626 if (!hdev) {
627 BT_ERR("Can not allocate HCI device");
628 goto err_hdev;
629 }
630
631 BT_DBG("Starting kthread...");
632 priv->main_thread.priv = priv;
633 spin_lock_init(&priv->driver_lock);
634
635 init_waitqueue_head(&priv->main_thread.wait_q);
636 priv->main_thread.task = kthread_run(btmrvl_service_main_thread,
637 &priv->main_thread, "btmrvl_main_service");
638
639 priv->btmrvl_dev.hcidev = hdev;
640 priv->btmrvl_dev.card = card;
641
642 hdev->driver_data = priv;
643
644 priv->btmrvl_dev.tx_dnld_rdy = true;
645
646 hdev->type = HCI_SDIO;
647 hdev->open = btmrvl_open;
648 hdev->close = btmrvl_close;
649 hdev->flush = btmrvl_flush;
650 hdev->send = btmrvl_send_frame;
651 hdev->destruct = btmrvl_destruct;
652 hdev->ioctl = btmrvl_ioctl;
653 hdev->owner = THIS_MODULE;
654
655 ret = hci_register_dev(hdev);
656 if (ret < 0) {
657 BT_ERR("Can not register HCI device");
658 goto err_hci_register_dev;
659 }
660
661 BT_DBG("Leave");
662 return priv;
663
664err_hci_register_dev:
665 /* Stop the thread servicing the interrupts */
666 kthread_stop(priv->main_thread.task);
667
668 hci_free_dev(hdev);
669
670err_hdev:
671 btmrvl_free_adapter(priv);
672
673err_adapter:
674 kfree(priv);
675
676err_priv:
677 BT_DBG("Leave");
678
679 return NULL;
680}
681EXPORT_SYMBOL_GPL(btmrvl_add_card);
682
683int btmrvl_remove_card(struct btmrvl_private *priv)
684{
685 struct hci_dev *hdev;
686
687 BT_DBG("Enter");
688
689 hdev = priv->btmrvl_dev.hcidev;
690
691 wake_up_interruptible(&priv->adapter->cmd_wait_q);
692
693 kthread_stop(priv->main_thread.task);
694
695 hci_unregister_dev(hdev);
696
697 hci_free_dev(hdev);
698
699 priv->btmrvl_dev.hcidev = NULL;
700
701 btmrvl_free_adapter(priv);
702
703 kfree(priv);
704
705 BT_DBG("Leave");
706
707 return 0;
708}
709EXPORT_SYMBOL_GPL(btmrvl_remove_card);
710
711MODULE_AUTHOR("Marvell International Ltd.");
712MODULE_DESCRIPTION("Marvell Bluetooth Driver v" VERSION);
713MODULE_VERSION(VERSION);
714MODULE_LICENSE("GPL v2");