aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth/btwilink.c
diff options
context:
space:
mode:
authorPavan Savoy <pavan_savoy@ti.com>2011-02-20 23:41:16 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-02-23 17:39:10 -0500
commit363907af85816adac5e60d48d3d84bba8f7201df (patch)
tree24f3033831cba9f67aeda39a8ab24a2334ebe85c /drivers/bluetooth/btwilink.c
parent6a3a81e7ca9b1ddaaf8d644b4102aff0fe2a7c40 (diff)
Bluetooth: btwilink driver
This is the bluetooth protocol driver for the TI WiLink7 chipsets. Texas Instrument's WiLink chipsets combine wireless technologies like BT, FM, GPS and WLAN onto a single chip. This Bluetooth driver works on top of the TI_ST shared transport line discipline driver which also allows other drivers like FM V4L2 and GPS character driver to make use of the same UART interface. Kconfig and Makefile modifications to enable the Bluetooth driver for Texas Instrument's WiLink 7 chipset. Signed-off-by: Pavan Savoy <pavan_savoy@ti.com> Acked-by: Gustavo F. Padovan <padovan@profusion.mobi> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/bluetooth/btwilink.c')
-rw-r--r--drivers/bluetooth/btwilink.c395
1 files changed, 395 insertions, 0 deletions
diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c
new file mode 100644
index 000000000000..65d27aff553a
--- /dev/null
+++ b/drivers/bluetooth/btwilink.c
@@ -0,0 +1,395 @@
1/*
2 * Texas Instrument's Bluetooth Driver For Shared Transport.
3 *
4 * Bluetooth Driver acts as interface between HCI core and
5 * TI Shared Transport Layer.
6 *
7 * Copyright (C) 2009-2010 Texas Instruments
8 * Author: Raja Mani <raja_mani@ti.com>
9 * Pavan Savoy <pavan_savoy@ti.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25#define DEBUG
26#include <linux/platform_device.h>
27#include <net/bluetooth/bluetooth.h>
28#include <net/bluetooth/hci_core.h>
29#include <net/bluetooth/hci.h>
30
31#include <linux/ti_wilink_st.h>
32
33/* Bluetooth Driver Version */
34#define VERSION "1.0"
35#define MAX_BT_CHNL_IDS 3
36
37/* Number of seconds to wait for registration completion
38 * when ST returns PENDING status.
39 */
40#define BT_REGISTER_TIMEOUT 6000 /* 6 sec */
41
42/**
43 * struct ti_st - driver operation structure
44 * @hdev: hci device pointer which binds to bt driver
45 * @reg_status: ST registration callback status
46 * @st_write: write function provided by the ST driver
47 * to be used by the driver during send_frame.
48 * @wait_reg_completion - completion sync between ti_st_open
49 * and st_reg_completion_cb.
50 */
51struct ti_st {
52 struct hci_dev *hdev;
53 char reg_status;
54 long (*st_write) (struct sk_buff *);
55 struct completion wait_reg_completion;
56};
57
58/* Increments HCI counters based on pocket ID (cmd,acl,sco) */
59static inline void ti_st_tx_complete(struct ti_st *hst, int pkt_type)
60{
61 struct hci_dev *hdev = hst->hdev;
62
63 /* Update HCI stat counters */
64 switch (pkt_type) {
65 case HCI_COMMAND_PKT:
66 hdev->stat.cmd_tx++;
67 break;
68
69 case HCI_ACLDATA_PKT:
70 hdev->stat.acl_tx++;
71 break;
72
73 case HCI_SCODATA_PKT:
74 hdev->stat.sco_tx++;
75 break;
76 }
77}
78
79/* ------- Interfaces to Shared Transport ------ */
80
81/* Called by ST layer to indicate protocol registration completion
82 * status.ti_st_open() function will wait for signal from this
83 * API when st_register() function returns ST_PENDING.
84 */
85static void st_reg_completion_cb(void *priv_data, char data)
86{
87 struct ti_st *lhst = priv_data;
88
89 /* Save registration status for use in ti_st_open() */
90 lhst->reg_status = data;
91 /* complete the wait in ti_st_open() */
92 complete(&lhst->wait_reg_completion);
93}
94
95/* Called by Shared Transport layer when receive data is
96 * available */
97static long st_receive(void *priv_data, struct sk_buff *skb)
98{
99 struct ti_st *lhst = priv_data;
100 int err;
101
102 if (!skb)
103 return -EFAULT;
104
105 if (!lhst) {
106 kfree_skb(skb);
107 return -EFAULT;
108 }
109
110 skb->dev = (void *) lhst->hdev;
111
112 /* Forward skb to HCI core layer */
113 err = hci_recv_frame(skb);
114 if (err < 0) {
115 BT_ERR("Unable to push skb to HCI core(%d)", err);
116 return err;
117 }
118
119 lhst->hdev->stat.byte_rx += skb->len;
120
121 return 0;
122}
123
124/* ------- Interfaces to HCI layer ------ */
125/* protocol structure registered with shared transport */
126static struct st_proto_s ti_st_proto[MAX_BT_CHNL_IDS] = {
127 {
128 .chnl_id = HCI_ACLDATA_PKT, /* ACL */
129 .hdr_len = sizeof(struct hci_acl_hdr),
130 .offset_len_in_hdr = offsetof(struct hci_acl_hdr, dlen),
131 .len_size = 2, /* sizeof(dlen) in struct hci_acl_hdr */
132 .reserve = 8,
133 },
134 {
135 .chnl_id = HCI_SCODATA_PKT, /* SCO */
136 .hdr_len = sizeof(struct hci_sco_hdr),
137 .offset_len_in_hdr = offsetof(struct hci_sco_hdr, dlen),
138 .len_size = 1, /* sizeof(dlen) in struct hci_sco_hdr */
139 .reserve = 8,
140 },
141 {
142 .chnl_id = HCI_EVENT_PKT, /* HCI Events */
143 .hdr_len = sizeof(struct hci_event_hdr),
144 .offset_len_in_hdr = offsetof(struct hci_event_hdr, plen),
145 .len_size = 1, /* sizeof(plen) in struct hci_event_hdr */
146 .reserve = 8,
147 },
148};
149
150/* Called from HCI core to initialize the device */
151static int ti_st_open(struct hci_dev *hdev)
152{
153 unsigned long timeleft;
154 struct ti_st *hst;
155 int err, i;
156
157 BT_DBG("%s %p", hdev->name, hdev);
158
159 if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
160 return -EBUSY;
161
162 /* provide contexts for callbacks from ST */
163 hst = hdev->driver_data;
164
165 for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
166 ti_st_proto[i].priv_data = hst;
167 ti_st_proto[i].max_frame_size = HCI_MAX_FRAME_SIZE;
168 ti_st_proto[i].recv = st_receive;
169 ti_st_proto[i].reg_complete_cb = st_reg_completion_cb;
170
171 /* Prepare wait-for-completion handler */
172 init_completion(&hst->wait_reg_completion);
173 /* Reset ST registration callback status flag,
174 * this value will be updated in
175 * st_reg_completion_cb()
176 * function whenever it called from ST driver.
177 */
178 hst->reg_status = -EINPROGRESS;
179
180 err = st_register(&ti_st_proto[i]);
181 if (!err)
182 goto done;
183
184 if (err != -EINPROGRESS) {
185 clear_bit(HCI_RUNNING, &hdev->flags);
186 BT_ERR("st_register failed %d", err);
187 return err;
188 }
189
190 /* ST is busy with either protocol
191 * registration or firmware download.
192 */
193 BT_DBG("waiting for registration "
194 "completion signal from ST");
195 timeleft = wait_for_completion_timeout
196 (&hst->wait_reg_completion,
197 msecs_to_jiffies(BT_REGISTER_TIMEOUT));
198 if (!timeleft) {
199 clear_bit(HCI_RUNNING, &hdev->flags);
200 BT_ERR("Timeout(%d sec),didn't get reg "
201 "completion signal from ST",
202 BT_REGISTER_TIMEOUT / 1000);
203 return -ETIMEDOUT;
204 }
205
206 /* Is ST registration callback
207 * called with ERROR status? */
208 if (hst->reg_status != 0) {
209 clear_bit(HCI_RUNNING, &hdev->flags);
210 BT_ERR("ST registration completed with invalid "
211 "status %d", hst->reg_status);
212 return -EAGAIN;
213 }
214
215done:
216 hst->st_write = ti_st_proto[i].write;
217 if (!hst->st_write) {
218 BT_ERR("undefined ST write function");
219 clear_bit(HCI_RUNNING, &hdev->flags);
220 for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
221 /* Undo registration with ST */
222 err = st_unregister(&ti_st_proto[i]);
223 if (err)
224 BT_ERR("st_unregister() failed with "
225 "error %d", err);
226 hst->st_write = NULL;
227 }
228 return -EIO;
229 }
230 }
231 return 0;
232}
233
234/* Close device */
235static int ti_st_close(struct hci_dev *hdev)
236{
237 int err, i;
238 struct ti_st *hst = hdev->driver_data;
239
240 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
241 return 0;
242
243 for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
244 err = st_unregister(&ti_st_proto[i]);
245 if (err)
246 BT_ERR("st_unregister(%d) failed with error %d",
247 ti_st_proto[i].chnl_id, err);
248 }
249
250 hst->st_write = NULL;
251
252 return err;
253}
254
255static int ti_st_send_frame(struct sk_buff *skb)
256{
257 struct hci_dev *hdev;
258 struct ti_st *hst;
259 long len;
260
261 hdev = (struct hci_dev *)skb->dev;
262
263 if (!test_bit(HCI_RUNNING, &hdev->flags))
264 return -EBUSY;
265
266 hst = hdev->driver_data;
267
268 /* Prepend skb with frame type */
269 memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
270
271 BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type,
272 skb->len);
273
274 /* Insert skb to shared transport layer's transmit queue.
275 * Freeing skb memory is taken care in shared transport layer,
276 * so don't free skb memory here.
277 */
278 len = hst->st_write(skb);
279 if (len < 0) {
280 kfree_skb(skb);
281 BT_ERR("ST write failed (%ld)", len);
282 /* Try Again, would only fail if UART has gone bad */
283 return -EAGAIN;
284 }
285
286 /* ST accepted our skb. So, Go ahead and do rest */
287 hdev->stat.byte_tx += len;
288 ti_st_tx_complete(hst, bt_cb(skb)->pkt_type);
289
290 return 0;
291}
292
293static void ti_st_destruct(struct hci_dev *hdev)
294{
295 BT_DBG("%s", hdev->name);
296 /* do nothing here, since platform remove
297 * would free the hdev->driver_data
298 */
299}
300
301static int bt_ti_probe(struct platform_device *pdev)
302{
303 static struct ti_st *hst;
304 struct hci_dev *hdev;
305 int err;
306
307 hst = kzalloc(sizeof(struct ti_st), GFP_KERNEL);
308 if (!hst)
309 return -ENOMEM;
310
311 /* Expose "hciX" device to user space */
312 hdev = hci_alloc_dev();
313 if (!hdev) {
314 kfree(hst);
315 return -ENOMEM;
316 }
317
318 BT_DBG("hdev %p", hdev);
319
320 hst->hdev = hdev;
321 hdev->bus = HCI_UART;
322 hdev->driver_data = hst;
323 hdev->open = ti_st_open;
324 hdev->close = ti_st_close;
325 hdev->flush = NULL;
326 hdev->send = ti_st_send_frame;
327 hdev->destruct = ti_st_destruct;
328 hdev->owner = THIS_MODULE;
329
330 err = hci_register_dev(hdev);
331 if (err < 0) {
332 BT_ERR("Can't register HCI device error %d", err);
333 kfree(hst);
334 hci_free_dev(hdev);
335 return err;
336 }
337
338 BT_DBG("HCI device registered (hdev %p)", hdev);
339
340 dev_set_drvdata(&pdev->dev, hst);
341 return err;
342}
343
344static int bt_ti_remove(struct platform_device *pdev)
345{
346 struct hci_dev *hdev;
347 struct ti_st *hst = dev_get_drvdata(&pdev->dev);
348
349 if (!hst)
350 return -EFAULT;
351
352 BT_DBG("%s", hst->hdev->name);
353
354 hdev = hst->hdev;
355 ti_st_close(hdev);
356 hci_unregister_dev(hdev);
357
358 hci_free_dev(hdev);
359 kfree(hst);
360
361 dev_set_drvdata(&pdev->dev, NULL);
362 return 0;
363}
364
365static struct platform_driver btwilink_driver = {
366 .probe = bt_ti_probe,
367 .remove = bt_ti_remove,
368 .driver = {
369 .name = "btwilink",
370 .owner = THIS_MODULE,
371 },
372};
373
374/* ------- Module Init/Exit interfaces ------ */
375static int __init btwilink_init(void)
376{
377 BT_INFO("Bluetooth Driver for TI WiLink - Version %s", VERSION);
378
379 return platform_driver_register(&btwilink_driver);
380}
381
382static void __exit btwilink_exit(void)
383{
384 platform_driver_unregister(&btwilink_driver);
385}
386
387module_init(btwilink_init);
388module_exit(btwilink_exit);
389
390/* ------ Module Info ------ */
391
392MODULE_AUTHOR("Raja Mani <raja_mani@ti.com>");
393MODULE_DESCRIPTION("Bluetooth Driver for TI Shared Transport" VERSION);
394MODULE_VERSION(VERSION);
395MODULE_LICENSE("GPL");