aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorOhad Ben-Cohen <ohad@bencohen.org>2007-10-20 07:42:36 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-22 05:59:44 -0400
commit166d2f6a4332aad53cb0750a296f76c06102552d (patch)
treee4bb9cf9cae2948772b70cf90e8140bfebf75528 /drivers
parente24b21ec85afda6f51b6bc403e971ff2aa7eacee (diff)
[Bluetooth] Add UART driver for Texas Instruments' BRF63xx chips
Add support for Texas Instruments' HCI Low Level (HCILL) Bluetooth protocol, which is a power management extension to H4. The HCILL is widely used by TI's BRF63xx Bluetooth chips. Signed-off-by: Ohad Ben-Cohen <ohad@bencohen.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/Kconfig11
-rw-r--r--drivers/bluetooth/Makefile1
-rw-r--r--drivers/bluetooth/hci_ldisc.c8
-rw-r--r--drivers/bluetooth/hci_ll.c531
-rw-r--r--drivers/bluetooth/hci_uart.h8
5 files changed, 557 insertions, 2 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index b9fbe6e7f9ae..62b89b95ace2 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -55,6 +55,17 @@ config BT_HCIUART_BCSP
55 55
56 Say Y here to compile support for HCI BCSP protocol. 56 Say Y here to compile support for HCI BCSP protocol.
57 57
58config BT_HCIUART_LL
59 bool "HCILL protocol support"
60 depends on BT_HCIUART
61 help
62 HCILL (HCI Low Level) is a serial protocol for communication
63 between Bluetooth device and host. This protocol is required for
64 serial Bluetooth devices that are based on Texas Instruments'
65 BRF chips.
66
67 Say Y here to compile support for HCILL protocol.
68
58config BT_HCIBCM203X 69config BT_HCIBCM203X
59 tristate "HCI BCM203x USB driver" 70 tristate "HCI BCM203x USB driver"
60 depends on USB 71 depends on USB
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 08c10e178e02..a543dfc2d6f5 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -16,4 +16,5 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
16hci_uart-y := hci_ldisc.o 16hci_uart-y := hci_ldisc.o
17hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o 17hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
18hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o 18hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
19hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
19hci_uart-objs := $(hci_uart-y) 20hci_uart-objs := $(hci_uart-y)
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 6055b9c0ac0f..e68821d074b0 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -549,7 +549,10 @@ static int __init hci_uart_init(void)
549#ifdef CONFIG_BT_HCIUART_BCSP 549#ifdef CONFIG_BT_HCIUART_BCSP
550 bcsp_init(); 550 bcsp_init();
551#endif 551#endif
552 552#ifdef CONFIG_BT_HCIUART_LL
553 ll_init();
554#endif
555
553 return 0; 556 return 0;
554} 557}
555 558
@@ -563,6 +566,9 @@ static void __exit hci_uart_exit(void)
563#ifdef CONFIG_BT_HCIUART_BCSP 566#ifdef CONFIG_BT_HCIUART_BCSP
564 bcsp_deinit(); 567 bcsp_deinit();
565#endif 568#endif
569#ifdef CONFIG_BT_HCIUART_LL
570 ll_deinit();
571#endif
566 572
567 /* Release tty registration of line discipline */ 573 /* Release tty registration of line discipline */
568 if ((err = tty_unregister_ldisc(N_HCI))) 574 if ((err = tty_unregister_ldisc(N_HCI)))
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
new file mode 100644
index 000000000000..8c3e62a17b4a
--- /dev/null
+++ b/drivers/bluetooth/hci_ll.c
@@ -0,0 +1,531 @@
1/*
2 * Texas Instruments' Bluetooth HCILL UART protocol
3 *
4 * HCILL (HCI Low Level) is a Texas Instruments' power management
5 * protocol extension to H4.
6 *
7 * Copyright (C) 2007 Texas Instruments, Inc.
8 *
9 * Written by Ohad Ben-Cohen <ohad@bencohen.org>
10 *
11 * Acknowledgements:
12 * This file is based on hci_h4.c, which was written
13 * by Maxim Krasnyansky and Marcel Holtmann.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License version 2
17 * as published by the Free Software Foundation
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30#include <linux/module.h>
31#include <linux/kernel.h>
32
33#include <linux/init.h>
34#include <linux/sched.h>
35#include <linux/types.h>
36#include <linux/fcntl.h>
37#include <linux/interrupt.h>
38#include <linux/ptrace.h>
39#include <linux/poll.h>
40
41#include <linux/slab.h>
42#include <linux/tty.h>
43#include <linux/errno.h>
44#include <linux/string.h>
45#include <linux/signal.h>
46#include <linux/ioctl.h>
47#include <linux/skbuff.h>
48
49#include <net/bluetooth/bluetooth.h>
50#include <net/bluetooth/hci_core.h>
51
52#include "hci_uart.h"
53
54/* HCILL commands */
55#define HCILL_GO_TO_SLEEP_IND 0x30
56#define HCILL_GO_TO_SLEEP_ACK 0x31
57#define HCILL_WAKE_UP_IND 0x32
58#define HCILL_WAKE_UP_ACK 0x33
59
60/* HCILL receiver States */
61#define HCILL_W4_PACKET_TYPE 0
62#define HCILL_W4_EVENT_HDR 1
63#define HCILL_W4_ACL_HDR 2
64#define HCILL_W4_SCO_HDR 3
65#define HCILL_W4_DATA 4
66
67/* HCILL states */
68enum hcill_states_e {
69 HCILL_ASLEEP,
70 HCILL_ASLEEP_TO_AWAKE,
71 HCILL_AWAKE,
72 HCILL_AWAKE_TO_ASLEEP
73};
74
75struct hcill_cmd {
76 u8 cmd;
77} __attribute__((packed));
78
79struct ll_struct {
80 unsigned long rx_state;
81 unsigned long rx_count;
82 struct sk_buff *rx_skb;
83 struct sk_buff_head txq;
84 spinlock_t hcill_lock; /* HCILL state lock */
85 unsigned long hcill_state; /* HCILL power state */
86 struct sk_buff_head tx_wait_q; /* HCILL wait queue */
87};
88
89/*
90 * Builds and sends an HCILL command packet.
91 * These are very simple packets with only 1 cmd byte
92 */
93static int send_hcill_cmd(u8 cmd, struct hci_uart *hu)
94{
95 int err = 0;
96 struct sk_buff *skb = NULL;
97 struct ll_struct *ll = hu->priv;
98 struct hcill_cmd *hcill_packet;
99
100 BT_DBG("hu %p cmd 0x%x", hu, cmd);
101
102 /* allocate packet */
103 skb = bt_skb_alloc(1, GFP_ATOMIC);
104 if (!skb) {
105 BT_ERR("cannot allocate memory for HCILL packet");
106 err = -ENOMEM;
107 goto out;
108 }
109
110 /* prepare packet */
111 hcill_packet = (struct hcill_cmd *) skb_put(skb, 1);
112 hcill_packet->cmd = cmd;
113 skb->dev = (void *) hu->hdev;
114
115 /* send packet */
116 skb_queue_tail(&ll->txq, skb);
117out:
118 return err;
119}
120
121/* Initialize protocol */
122static int ll_open(struct hci_uart *hu)
123{
124 struct ll_struct *ll;
125
126 BT_DBG("hu %p", hu);
127
128 ll = kzalloc(sizeof(*ll), GFP_ATOMIC);
129 if (!ll)
130 return -ENOMEM;
131
132 skb_queue_head_init(&ll->txq);
133 skb_queue_head_init(&ll->tx_wait_q);
134 spin_lock_init(&ll->hcill_lock);
135
136 ll->hcill_state = HCILL_AWAKE;
137
138 hu->priv = ll;
139
140 return 0;
141}
142
143/* Flush protocol data */
144static int ll_flush(struct hci_uart *hu)
145{
146 struct ll_struct *ll = hu->priv;
147
148 BT_DBG("hu %p", hu);
149
150 skb_queue_purge(&ll->tx_wait_q);
151 skb_queue_purge(&ll->txq);
152
153 return 0;
154}
155
156/* Close protocol */
157static int ll_close(struct hci_uart *hu)
158{
159 struct ll_struct *ll = hu->priv;
160
161 BT_DBG("hu %p", hu);
162
163 skb_queue_purge(&ll->tx_wait_q);
164 skb_queue_purge(&ll->txq);
165
166 if (ll->rx_skb)
167 kfree_skb(ll->rx_skb);
168
169 hu->priv = NULL;
170
171 kfree(ll);
172
173 return 0;
174}
175
176/*
177 * internal function, which does common work of the device wake up process:
178 * 1. places all pending packets (waiting in tx_wait_q list) in txq list.
179 * 2. changes internal state to HCILL_AWAKE.
180 * Note: assumes that hcill_lock spinlock is taken,
181 * shouldn't be called otherwise!
182 */
183static void __ll_do_awake(struct ll_struct *ll)
184{
185 struct sk_buff *skb = NULL;
186
187 while ((skb = skb_dequeue(&ll->tx_wait_q)))
188 skb_queue_tail(&ll->txq, skb);
189
190 ll->hcill_state = HCILL_AWAKE;
191}
192
193/*
194 * Called upon a wake-up-indication from the device
195 */
196static void ll_device_want_to_wakeup(struct hci_uart *hu)
197{
198 unsigned long flags;
199 struct ll_struct *ll = hu->priv;
200
201 BT_DBG("hu %p", hu);
202
203 /* lock hcill state */
204 spin_lock_irqsave(&ll->hcill_lock, flags);
205
206 switch (ll->hcill_state) {
207 case HCILL_ASLEEP:
208 /* acknowledge device wake up */
209 if (send_hcill_cmd(HCILL_WAKE_UP_ACK, hu) < 0) {
210 BT_ERR("cannot acknowledge device wake up");
211 goto out;
212 }
213 break;
214 case HCILL_ASLEEP_TO_AWAKE:
215 /*
216 * this state means that a wake-up-indication
217 * is already on its way to the device,
218 * and will serve as the required wake-up-ack
219 */
220 BT_DBG("dual wake-up-indication");
221 break;
222 default:
223 /* any other state are illegal */
224 BT_ERR("received HCILL_WAKE_UP_IND in state %ld", ll->hcill_state);
225 break;
226 }
227
228 /* send pending packets and change state to HCILL_AWAKE */
229 __ll_do_awake(ll);
230
231out:
232 spin_unlock_irqrestore(&ll->hcill_lock, flags);
233
234 /* actually send the packets */
235 hci_uart_tx_wakeup(hu);
236}
237
238/*
239 * Called upon a sleep-indication from the device
240 */
241static void ll_device_want_to_sleep(struct hci_uart *hu)
242{
243 unsigned long flags;
244 struct ll_struct *ll = hu->priv;
245
246 BT_DBG("hu %p", hu);
247
248 /* lock hcill state */
249 spin_lock_irqsave(&ll->hcill_lock, flags);
250
251 /* sanity check */
252 if (ll->hcill_state != HCILL_AWAKE)
253 BT_ERR("ERR: HCILL_GO_TO_SLEEP_IND in state %ld", ll->hcill_state);
254
255 /* acknowledge device sleep */
256 if (send_hcill_cmd(HCILL_GO_TO_SLEEP_ACK, hu) < 0) {
257 BT_ERR("cannot acknowledge device sleep");
258 goto out;
259 }
260
261 /* update state */
262 ll->hcill_state = HCILL_ASLEEP;
263
264out:
265 spin_unlock_irqrestore(&ll->hcill_lock, flags);
266
267 /* actually send the sleep ack packet */
268 hci_uart_tx_wakeup(hu);
269}
270
271/*
272 * Called upon wake-up-acknowledgement from the device
273 */
274static void ll_device_woke_up(struct hci_uart *hu)
275{
276 unsigned long flags;
277 struct ll_struct *ll = hu->priv;
278
279 BT_DBG("hu %p", hu);
280
281 /* lock hcill state */
282 spin_lock_irqsave(&ll->hcill_lock, flags);
283
284 /* sanity check */
285 if (ll->hcill_state != HCILL_ASLEEP_TO_AWAKE)
286 BT_ERR("received HCILL_WAKE_UP_ACK in state %ld", ll->hcill_state);
287
288 /* send pending packets and change state to HCILL_AWAKE */
289 __ll_do_awake(ll);
290
291 spin_unlock_irqrestore(&ll->hcill_lock, flags);
292
293 /* actually send the packets */
294 hci_uart_tx_wakeup(hu);
295}
296
297/* Enqueue frame for transmittion (padding, crc, etc) */
298/* may be called from two simultaneous tasklets */
299static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
300{
301 unsigned long flags = 0;
302 struct ll_struct *ll = hu->priv;
303
304 BT_DBG("hu %p skb %p", hu, skb);
305
306 /* Prepend skb with frame type */
307 memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
308
309 /* lock hcill state */
310 spin_lock_irqsave(&ll->hcill_lock, flags);
311
312 /* act according to current state */
313 switch (ll->hcill_state) {
314 case HCILL_AWAKE:
315 BT_DBG("device awake, sending normally");
316 skb_queue_tail(&ll->txq, skb);
317 break;
318 case HCILL_ASLEEP:
319 BT_DBG("device asleep, waking up and queueing packet");
320 /* save packet for later */
321 skb_queue_tail(&ll->tx_wait_q, skb);
322 /* awake device */
323 if (send_hcill_cmd(HCILL_WAKE_UP_IND, hu) < 0) {
324 BT_ERR("cannot wake up device");
325 break;
326 }
327 ll->hcill_state = HCILL_ASLEEP_TO_AWAKE;
328 break;
329 case HCILL_ASLEEP_TO_AWAKE:
330 BT_DBG("device waking up, queueing packet");
331 /* transient state; just keep packet for later */
332 skb_queue_tail(&ll->tx_wait_q, skb);
333 break;
334 default:
335 BT_ERR("illegal hcill state: %ld (losing packet)", ll->hcill_state);
336 kfree_skb(skb);
337 break;
338 }
339
340 spin_unlock_irqrestore(&ll->hcill_lock, flags);
341
342 return 0;
343}
344
345static inline int ll_check_data_len(struct ll_struct *ll, int len)
346{
347 register int room = skb_tailroom(ll->rx_skb);
348
349 BT_DBG("len %d room %d", len, room);
350
351 if (!len) {
352 hci_recv_frame(ll->rx_skb);
353 } else if (len > room) {
354 BT_ERR("Data length is too large");
355 kfree_skb(ll->rx_skb);
356 } else {
357 ll->rx_state = HCILL_W4_DATA;
358 ll->rx_count = len;
359 return len;
360 }
361
362 ll->rx_state = HCILL_W4_PACKET_TYPE;
363 ll->rx_skb = NULL;
364 ll->rx_count = 0;
365
366 return 0;
367}
368
369/* Recv data */
370static int ll_recv(struct hci_uart *hu, void *data, int count)
371{
372 struct ll_struct *ll = hu->priv;
373 register char *ptr;
374 struct hci_event_hdr *eh;
375 struct hci_acl_hdr *ah;
376 struct hci_sco_hdr *sh;
377 register int len, type, dlen;
378
379 BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count);
380
381 ptr = data;
382 while (count) {
383 if (ll->rx_count) {
384 len = min_t(unsigned int, ll->rx_count, count);
385 memcpy(skb_put(ll->rx_skb, len), ptr, len);
386 ll->rx_count -= len; count -= len; ptr += len;
387
388 if (ll->rx_count)
389 continue;
390
391 switch (ll->rx_state) {
392 case HCILL_W4_DATA:
393 BT_DBG("Complete data");
394 hci_recv_frame(ll->rx_skb);
395
396 ll->rx_state = HCILL_W4_PACKET_TYPE;
397 ll->rx_skb = NULL;
398 continue;
399
400 case HCILL_W4_EVENT_HDR:
401 eh = (struct hci_event_hdr *) ll->rx_skb->data;
402
403 BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
404
405 ll_check_data_len(ll, eh->plen);
406 continue;
407
408 case HCILL_W4_ACL_HDR:
409 ah = (struct hci_acl_hdr *) ll->rx_skb->data;
410 dlen = __le16_to_cpu(ah->dlen);
411
412 BT_DBG("ACL header: dlen %d", dlen);
413
414 ll_check_data_len(ll, dlen);
415 continue;
416
417 case HCILL_W4_SCO_HDR:
418 sh = (struct hci_sco_hdr *) ll->rx_skb->data;
419
420 BT_DBG("SCO header: dlen %d", sh->dlen);
421
422 ll_check_data_len(ll, sh->dlen);
423 continue;
424 }
425 }
426
427 /* HCILL_W4_PACKET_TYPE */
428 switch (*ptr) {
429 case HCI_EVENT_PKT:
430 BT_DBG("Event packet");
431 ll->rx_state = HCILL_W4_EVENT_HDR;
432 ll->rx_count = HCI_EVENT_HDR_SIZE;
433 type = HCI_EVENT_PKT;
434 break;
435
436 case HCI_ACLDATA_PKT:
437 BT_DBG("ACL packet");
438 ll->rx_state = HCILL_W4_ACL_HDR;
439 ll->rx_count = HCI_ACL_HDR_SIZE;
440 type = HCI_ACLDATA_PKT;
441 break;
442
443 case HCI_SCODATA_PKT:
444 BT_DBG("SCO packet");
445 ll->rx_state = HCILL_W4_SCO_HDR;
446 ll->rx_count = HCI_SCO_HDR_SIZE;
447 type = HCI_SCODATA_PKT;
448 break;
449
450 /* HCILL signals */
451 case HCILL_GO_TO_SLEEP_IND:
452 BT_DBG("HCILL_GO_TO_SLEEP_IND packet");
453 ll_device_want_to_sleep(hu);
454 ptr++; count--;
455 continue;
456
457 case HCILL_GO_TO_SLEEP_ACK:
458 /* shouldn't happen */
459 BT_ERR("received HCILL_GO_TO_SLEEP_ACK (in state %ld)", ll->hcill_state);
460 ptr++; count--;
461 continue;
462
463 case HCILL_WAKE_UP_IND:
464 BT_DBG("HCILL_WAKE_UP_IND packet");
465 ll_device_want_to_wakeup(hu);
466 ptr++; count--;
467 continue;
468
469 case HCILL_WAKE_UP_ACK:
470 BT_DBG("HCILL_WAKE_UP_ACK packet");
471 ll_device_woke_up(hu);
472 ptr++; count--;
473 continue;
474
475 default:
476 BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
477 hu->hdev->stat.err_rx++;
478 ptr++; count--;
479 continue;
480 };
481
482 ptr++; count--;
483
484 /* Allocate packet */
485 ll->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
486 if (!ll->rx_skb) {
487 BT_ERR("Can't allocate mem for new packet");
488 ll->rx_state = HCILL_W4_PACKET_TYPE;
489 ll->rx_count = 0;
490 return 0;
491 }
492
493 ll->rx_skb->dev = (void *) hu->hdev;
494 bt_cb(ll->rx_skb)->pkt_type = type;
495 }
496
497 return count;
498}
499
500static struct sk_buff *ll_dequeue(struct hci_uart *hu)
501{
502 struct ll_struct *ll = hu->priv;
503 return skb_dequeue(&ll->txq);
504}
505
506static struct hci_uart_proto llp = {
507 .id = HCI_UART_LL,
508 .open = ll_open,
509 .close = ll_close,
510 .recv = ll_recv,
511 .enqueue = ll_enqueue,
512 .dequeue = ll_dequeue,
513 .flush = ll_flush,
514};
515
516int ll_init(void)
517{
518 int err = hci_uart_register_proto(&llp);
519
520 if (!err)
521 BT_INFO("HCILL protocol initialized");
522 else
523 BT_ERR("HCILL protocol registration failed");
524
525 return err;
526}
527
528int ll_deinit(void)
529{
530 return hci_uart_unregister_proto(&llp);
531}
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 1097ce72393f..50113db06b9f 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -33,12 +33,13 @@
33#define HCIUARTGETDEVICE _IOR('U', 202, int) 33#define HCIUARTGETDEVICE _IOR('U', 202, int)
34 34
35/* UART protocols */ 35/* UART protocols */
36#define HCI_UART_MAX_PROTO 4 36#define HCI_UART_MAX_PROTO 5
37 37
38#define HCI_UART_H4 0 38#define HCI_UART_H4 0
39#define HCI_UART_BCSP 1 39#define HCI_UART_BCSP 1
40#define HCI_UART_3WIRE 2 40#define HCI_UART_3WIRE 2
41#define HCI_UART_H4DS 3 41#define HCI_UART_H4DS 3
42#define HCI_UART_LL 4
42 43
43struct hci_uart; 44struct hci_uart;
44 45
@@ -85,3 +86,8 @@ int h4_deinit(void);
85int bcsp_init(void); 86int bcsp_init(void);
86int bcsp_deinit(void); 87int bcsp_deinit(void);
87#endif 88#endif
89
90#ifdef CONFIG_BT_HCIUART_LL
91int ll_init(void);
92int ll_deinit(void);
93#endif