aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2007-10-20 08:02:04 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-22 05:59:45 -0400
commitddbaf13e3609442b64abb931ac21527772d87980 (patch)
treeba9b1bb2c6b90eb3a33093604000310730b5431e /drivers
parentac019360fe311dd6aa11b358a02eb3a61675882e (diff)
[Bluetooth] Add generic driver for Bluetooth SDIO devices
This patch adds a generic driver for Bluetooth SDIO devices. It supports Type-A and Type-B devices. Signed-off-by: David Vrabel <david.vrabel@csr.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/Kconfig11
-rw-r--r--drivers/bluetooth/Makefile2
-rw-r--r--drivers/bluetooth/btsdio.c406
3 files changed, 419 insertions, 0 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 62b89b95ace2..77bded441cf1 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -22,6 +22,17 @@ config BT_HCIUSB_SCO
22 22
23 Say Y here to compile support for SCO over HCI USB. 23 Say Y here to compile support for SCO over HCI USB.
24 24
25config BT_HCIBTSDIO
26 tristate "HCI SDIO driver"
27 depends on MMC
28 help
29 Bluetooth HCI SDIO driver.
30 This driver is required if you want to use Bluetooth device with
31 SDIO interface.
32
33 Say Y here to compile support for Bluetooth SDIO devices into the
34 kernel or say M to compile it as module (btsdio).
35
25config BT_HCIUART 36config BT_HCIUART
26 tristate "HCI UART driver" 37 tristate "HCI UART driver"
27 help 38 help
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index a543dfc2d6f5..aee12797aa1c 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -13,6 +13,8 @@ obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
13obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o 13obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
14obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o 14obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
15 15
16obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
17
16hci_uart-y := hci_ldisc.o 18hci_uart-y := hci_ldisc.o
17hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o 19hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
18hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o 20hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
new file mode 100644
index 000000000000..b786f6187902
--- /dev/null
+++ b/drivers/bluetooth/btsdio.c
@@ -0,0 +1,406 @@
1/*
2 *
3 * Generic Bluetooth SDIO driver
4 *
5 * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
6 * Copyright (C) 2007 Marcel Holtmann <marcel@holtmann.org>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/init.h>
28#include <linux/slab.h>
29#include <linux/types.h>
30#include <linux/sched.h>
31#include <linux/errno.h>
32#include <linux/skbuff.h>
33
34#include <linux/mmc/sdio_ids.h>
35#include <linux/mmc/sdio_func.h>
36
37#include <net/bluetooth/bluetooth.h>
38#include <net/bluetooth/hci_core.h>
39
40#ifndef CONFIG_BT_HCIBTSDIO_DEBUG
41#undef BT_DBG
42#define BT_DBG(D...)
43#endif
44
45#define VERSION "0.1"
46
47static const struct sdio_device_id btsdio_table[] = {
48 /* Generic Bluetooth Type-A SDIO device */
49 { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_A) },
50
51 /* Generic Bluetooth Type-B SDIO device */
52 { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
53
54 { } /* Terminating entry */
55};
56
57MODULE_DEVICE_TABLE(sdio, btsdio_table);
58
59struct btsdio_data {
60 struct hci_dev *hdev;
61 struct sdio_func *func;
62
63 struct work_struct work;
64
65 struct sk_buff_head txq;
66};
67
68#define REG_RDAT 0x00 /* Receiver Data */
69#define REG_TDAT 0x00 /* Transmitter Data */
70#define REG_PC_RRT 0x10 /* Read Packet Control */
71#define REG_PC_WRT 0x11 /* Write Packet Control */
72#define REG_RTC_STAT 0x12 /* Retry Control Status */
73#define REG_RTC_SET 0x12 /* Retry Control Set */
74#define REG_INTRD 0x13 /* Interrupt Indication */
75#define REG_CL_INTRD 0x13 /* Interrupt Clear */
76#define REG_EN_INTRD 0x14 /* Interrupt Enable */
77#define REG_MD_STAT 0x20 /* Bluetooth Mode Status */
78
79static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb)
80{
81 int err;
82
83 BT_DBG("%s", data->hdev->name);
84
85 /* Prepend Type-A header */
86 skb_push(skb, 4);
87 skb->data[0] = (skb->len & 0x0000ff);
88 skb->data[1] = (skb->len & 0x00ff00) >> 8;
89 skb->data[2] = (skb->len & 0xff0000) >> 16;
90 skb->data[3] = bt_cb(skb)->pkt_type;
91
92 err = sdio_writesb(data->func, REG_TDAT, skb->data, skb->len);
93 if (err < 0) {
94 sdio_writeb(data->func, 0x01, REG_PC_WRT, NULL);
95 return err;
96 }
97
98 data->hdev->stat.byte_tx += skb->len;
99
100 kfree_skb(skb);
101
102 return 0;
103}
104
105static void btsdio_work(struct work_struct *work)
106{
107 struct btsdio_data *data = container_of(work, struct btsdio_data, work);
108 struct sk_buff *skb;
109 int err;
110
111 BT_DBG("%s", data->hdev->name);
112
113 sdio_claim_host(data->func);
114
115 while ((skb = skb_dequeue(&data->txq))) {
116 err = btsdio_tx_packet(data, skb);
117 if (err < 0) {
118 data->hdev->stat.err_tx++;
119 skb_queue_head(&data->txq, skb);
120 break;
121 }
122 }
123
124 sdio_release_host(data->func);
125}
126
127static int btsdio_rx_packet(struct btsdio_data *data)
128{
129 u8 hdr[4] __attribute__ ((aligned(4)));
130 struct sk_buff *skb;
131 int err, len;
132
133 BT_DBG("%s", data->hdev->name);
134
135 err = sdio_readsb(data->func, hdr, REG_RDAT, 4);
136 if (err < 0)
137 return err;
138
139 len = hdr[0] | (hdr[1] << 8) | (hdr[2] << 16);
140 if (len < 4 || len > 65543)
141 return -EILSEQ;
142
143 skb = bt_skb_alloc(len - 4, GFP_KERNEL);
144 if (!skb) {
145 /* Out of memory. Prepare a read retry and just
146 * return with the expectation that the next time
147 * we're called we'll have more memory. */
148 return -ENOMEM;
149 }
150
151 skb_put(skb, len - 4);
152
153 err = sdio_readsb(data->func, skb->data, REG_RDAT, len - 4);
154 if (err < 0) {
155 kfree(skb);
156 return err;
157 }
158
159 data->hdev->stat.byte_rx += len;
160
161 skb->dev = (void *) data->hdev;
162 bt_cb(skb)->pkt_type = hdr[3];
163
164 err = hci_recv_frame(skb);
165 if (err < 0) {
166 kfree(skb);
167 return err;
168 }
169
170 sdio_writeb(data->func, 0x00, REG_PC_RRT, NULL);
171
172 return 0;
173}
174
175static void btsdio_interrupt(struct sdio_func *func)
176{
177 struct btsdio_data *data = sdio_get_drvdata(func);
178 int intrd;
179
180 BT_DBG("%s", data->hdev->name);
181
182 intrd = sdio_readb(func, REG_INTRD, NULL);
183 if (intrd & 0x01) {
184 sdio_writeb(func, 0x01, REG_CL_INTRD, NULL);
185
186 if (btsdio_rx_packet(data) < 0) {
187 data->hdev->stat.err_rx++;
188 sdio_writeb(data->func, 0x01, REG_PC_RRT, NULL);
189 }
190 }
191}
192
193static int btsdio_open(struct hci_dev *hdev)
194{
195 struct btsdio_data *data = hdev->driver_data;
196 int err;
197
198 BT_DBG("%s", hdev->name);
199
200 if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
201 return 0;
202
203 sdio_claim_host(data->func);
204
205 err = sdio_enable_func(data->func);
206 if (err < 0) {
207 clear_bit(HCI_RUNNING, &hdev->flags);
208 goto release;
209 }
210
211 err = sdio_claim_irq(data->func, btsdio_interrupt);
212 if (err < 0) {
213 sdio_disable_func(data->func);
214 clear_bit(HCI_RUNNING, &hdev->flags);
215 goto release;
216 }
217
218 if (data->func->class == SDIO_CLASS_BT_B)
219 sdio_writeb(data->func, 0x00, REG_MD_STAT, NULL);
220
221 sdio_writeb(data->func, 0x01, REG_EN_INTRD, NULL);
222
223release:
224 sdio_release_host(data->func);
225
226 return err;
227}
228
229static int btsdio_close(struct hci_dev *hdev)
230{
231 struct btsdio_data *data = hdev->driver_data;
232
233 BT_DBG("%s", hdev->name);
234
235 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
236 return 0;
237
238 sdio_claim_host(data->func);
239
240 sdio_writeb(data->func, 0x00, REG_EN_INTRD, NULL);
241
242 sdio_release_irq(data->func);
243 sdio_disable_func(data->func);
244
245 sdio_release_host(data->func);
246
247 return 0;
248}
249
250static int btsdio_flush(struct hci_dev *hdev)
251{
252 struct btsdio_data *data = hdev->driver_data;
253
254 BT_DBG("%s", hdev->name);
255
256 skb_queue_purge(&data->txq);
257
258 return 0;
259}
260
261static int btsdio_send_frame(struct sk_buff *skb)
262{
263 struct hci_dev *hdev = (struct hci_dev *) skb->dev;
264 struct btsdio_data *data = hdev->driver_data;
265
266 BT_DBG("%s", hdev->name);
267
268 if (!test_bit(HCI_RUNNING, &hdev->flags))
269 return -EBUSY;
270
271 switch (bt_cb(skb)->pkt_type) {
272 case HCI_COMMAND_PKT:
273 hdev->stat.cmd_tx++;
274 break;
275
276 case HCI_ACLDATA_PKT:
277 hdev->stat.acl_tx++;
278 break;
279
280 case HCI_SCODATA_PKT:
281 hdev->stat.sco_tx++;
282 break;
283
284 default:
285 return -EILSEQ;
286 }
287
288 skb_queue_tail(&data->txq, skb);
289
290 schedule_work(&data->work);
291
292 return 0;
293}
294
295static void btsdio_destruct(struct hci_dev *hdev)
296{
297 struct btsdio_data *data = hdev->driver_data;
298
299 BT_DBG("%s", hdev->name);
300
301 kfree(data);
302}
303
304static int btsdio_probe(struct sdio_func *func,
305 const struct sdio_device_id *id)
306{
307 struct btsdio_data *data;
308 struct hci_dev *hdev;
309 struct sdio_func_tuple *tuple = func->tuples;
310 int err;
311
312 BT_DBG("func %p id %p class 0x%04x", func, id, func->class);
313
314 while (tuple) {
315 BT_DBG("code 0x%x size %d", tuple->code, tuple->size);
316 tuple = tuple->next;
317 }
318
319 data = kzalloc(sizeof(*data), GFP_KERNEL);
320 if (!data)
321 return -ENOMEM;
322
323 data->func = func;
324
325 INIT_WORK(&data->work, btsdio_work);
326
327 skb_queue_head_init(&data->txq);
328
329 hdev = hci_alloc_dev();
330 if (!hdev) {
331 kfree(data);
332 return -ENOMEM;
333 }
334
335 hdev->type = HCI_SDIO;
336 hdev->driver_data = data;
337
338 data->hdev = hdev;
339
340 SET_HCIDEV_DEV(hdev, &func->dev);
341
342 hdev->open = btsdio_open;
343 hdev->close = btsdio_close;
344 hdev->flush = btsdio_flush;
345 hdev->send = btsdio_send_frame;
346 hdev->destruct = btsdio_destruct;
347
348 hdev->owner = THIS_MODULE;
349
350 err = hci_register_dev(hdev);
351 if (err < 0) {
352 hci_free_dev(hdev);
353 kfree(data);
354 return err;
355 }
356
357 sdio_set_drvdata(func, data);
358
359 return 0;
360}
361
362static void btsdio_remove(struct sdio_func *func)
363{
364 struct btsdio_data *data = sdio_get_drvdata(func);
365 struct hci_dev *hdev;
366
367 BT_DBG("func %p", func);
368
369 if (!data)
370 return;
371
372 hdev = data->hdev;
373
374 sdio_set_drvdata(func, NULL);
375
376 hci_unregister_dev(hdev);
377
378 hci_free_dev(hdev);
379}
380
381static struct sdio_driver btsdio_driver = {
382 .name = "btsdio",
383 .probe = btsdio_probe,
384 .remove = btsdio_remove,
385 .id_table = btsdio_table,
386};
387
388static int __init btsdio_init(void)
389{
390 BT_INFO("Generic Bluetooth SDIO driver ver %s", VERSION);
391
392 return sdio_register_driver(&btsdio_driver);
393}
394
395static void __exit btsdio_exit(void)
396{
397 sdio_unregister_driver(&btsdio_driver);
398}
399
400module_init(btsdio_init);
401module_exit(btsdio_exit);
402
403MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
404MODULE_DESCRIPTION("Generic Bluetooth SDIO driver ver " VERSION);
405MODULE_VERSION(VERSION);
406MODULE_LICENSE("GPL");