diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 18:19:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 18:19:35 -0400 |
commit | 6445ced8670f37cfc2c5e24a9de9b413dbfc788d (patch) | |
tree | 7c98481159008a4080cda929ea8c7bc7598a2c39 /drivers/bluetooth | |
parent | e6bee325e49f17c65c1fd66e9e8b348c85788341 (diff) | |
parent | 12bb12fac06d6212be9a5ed282c5670d4e90747f (diff) |
Merge branch 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
* 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6: (961 commits)
staging: hv: fix memory leaks
staging: hv: Remove NULL check before kfree
Staging: hv: Get rid of vmbus_child_dev_add()
Staging: hv: Change the signature for vmbus_child_device_register()
Staging: hv: Get rid of vmbus_cleanup() function
Staging: hv: Get rid of vmbus_dev_rm() function
Staging: hv: Change the signature for vmbus_on_isr()
Staging: hv: Eliminate vmbus_event_dpc()
Staging: hv: Get rid of the function vmbus_msg_dpc()
Staging: hv: Change the signature for vmbus_cleanup()
Staging: hv: Simplify root device management
staging: rtl8192e: Don't copy dev pointer to skb
staging: rtl8192e: Pass priv to cmdpkt functions
staging: rtl8192e: Pass priv to firmware download functions
staging: rtl8192e: Pass priv to rtl8192_interrupt
staging: rtl8192e: Pass rtl8192_priv to dm functions
staging: rtl8192e: Pass ieee80211_device to callbacks
staging: rtl8192e: Pass ieee80211_device to callbacks
staging: rtl8192e: Pass ieee80211_device to callbacks
staging: rtl8192e: Pass ieee80211_device to callbacks
...
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/Kconfig | 10 | ||||
-rw-r--r-- | drivers/bluetooth/Makefile | 1 | ||||
-rw-r--r-- | drivers/bluetooth/btwilink.c | 395 |
3 files changed, 406 insertions, 0 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 02deef424926..8e0de9a05867 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig | |||
@@ -219,4 +219,14 @@ config BT_ATH3K | |||
219 | Say Y here to compile support for "Atheros firmware download driver" | 219 | Say Y here to compile support for "Atheros firmware download driver" |
220 | into the kernel or say M to compile it as module (ath3k). | 220 | into the kernel or say M to compile it as module (ath3k). |
221 | 221 | ||
222 | config BT_WILINK | ||
223 | tristate "Texas Instruments WiLink7 driver" | ||
224 | depends on TI_ST | ||
225 | help | ||
226 | This enables the Bluetooth driver for Texas Instrument's BT/FM/GPS | ||
227 | combo devices. This makes use of shared transport line discipline | ||
228 | core driver to communicate with the BT core of the combo chip. | ||
229 | |||
230 | Say Y here to compile support for Texas Instrument's WiLink7 driver | ||
231 | into the kernel or say M to compile it as module. | ||
222 | endmenu | 232 | endmenu |
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 71bdf13287c4..f4460f4f4b78 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile | |||
@@ -18,6 +18,7 @@ obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o | |||
18 | obj-$(CONFIG_BT_ATH3K) += ath3k.o | 18 | obj-$(CONFIG_BT_ATH3K) += ath3k.o |
19 | obj-$(CONFIG_BT_MRVL) += btmrvl.o | 19 | obj-$(CONFIG_BT_MRVL) += btmrvl.o |
20 | obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o | 20 | obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o |
21 | obj-$(CONFIG_BT_WILINK) += btwilink.o | ||
21 | 22 | ||
22 | btmrvl-y := btmrvl_main.o | 23 | btmrvl-y := btmrvl_main.o |
23 | btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o | 24 | btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o |
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 | */ | ||
51 | struct 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) */ | ||
59 | static 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 | */ | ||
85 | static 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 */ | ||
97 | static 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 */ | ||
126 | static 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 */ | ||
151 | static 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 | |||
215 | done: | ||
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 */ | ||
235 | static 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 | |||
255 | static 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 | |||
293 | static 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 | |||
301 | static 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 | |||
344 | static 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 | |||
365 | static 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 ------ */ | ||
375 | static 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 | |||
382 | static void __exit btwilink_exit(void) | ||
383 | { | ||
384 | platform_driver_unregister(&btwilink_driver); | ||
385 | } | ||
386 | |||
387 | module_init(btwilink_init); | ||
388 | module_exit(btwilink_exit); | ||
389 | |||
390 | /* ------ Module Info ------ */ | ||
391 | |||
392 | MODULE_AUTHOR("Raja Mani <raja_mani@ti.com>"); | ||
393 | MODULE_DESCRIPTION("Bluetooth Driver for TI Shared Transport" VERSION); | ||
394 | MODULE_VERSION(VERSION); | ||
395 | MODULE_LICENSE("GPL"); | ||