diff options
author | Ohad Ben-Cohen <ohad@bencohen.org> | 2007-10-20 07:42:36 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-22 05:59:44 -0400 |
commit | 166d2f6a4332aad53cb0750a296f76c06102552d (patch) | |
tree | e4bb9cf9cae2948772b70cf90e8140bfebf75528 /drivers | |
parent | e24b21ec85afda6f51b6bc403e971ff2aa7eacee (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/Kconfig | 11 | ||||
-rw-r--r-- | drivers/bluetooth/Makefile | 1 | ||||
-rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 8 | ||||
-rw-r--r-- | drivers/bluetooth/hci_ll.c | 531 | ||||
-rw-r--r-- | drivers/bluetooth/hci_uart.h | 8 |
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 | ||
58 | config 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 | |||
58 | config BT_HCIBCM203X | 69 | config 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 | |||
16 | hci_uart-y := hci_ldisc.o | 16 | hci_uart-y := hci_ldisc.o |
17 | hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o | 17 | hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o |
18 | hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o | 18 | hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o |
19 | hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o | ||
19 | hci_uart-objs := $(hci_uart-y) | 20 | hci_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 */ | ||
68 | enum hcill_states_e { | ||
69 | HCILL_ASLEEP, | ||
70 | HCILL_ASLEEP_TO_AWAKE, | ||
71 | HCILL_AWAKE, | ||
72 | HCILL_AWAKE_TO_ASLEEP | ||
73 | }; | ||
74 | |||
75 | struct hcill_cmd { | ||
76 | u8 cmd; | ||
77 | } __attribute__((packed)); | ||
78 | |||
79 | struct 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 | */ | ||
93 | static 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); | ||
117 | out: | ||
118 | return err; | ||
119 | } | ||
120 | |||
121 | /* Initialize protocol */ | ||
122 | static 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 */ | ||
144 | static 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 */ | ||
157 | static 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 | */ | ||
183 | static 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 | */ | ||
196 | static 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 | |||
231 | out: | ||
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 | */ | ||
241 | static 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 | |||
264 | out: | ||
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 | */ | ||
274 | static 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 */ | ||
299 | static 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 | |||
345 | static 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 */ | ||
370 | static 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 | |||
500 | static 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 | |||
506 | static 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 | |||
516 | int 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 | |||
528 | int 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 | ||
43 | struct hci_uart; | 44 | struct hci_uart; |
44 | 45 | ||
@@ -85,3 +86,8 @@ int h4_deinit(void); | |||
85 | int bcsp_init(void); | 86 | int bcsp_init(void); |
86 | int bcsp_deinit(void); | 87 | int bcsp_deinit(void); |
87 | #endif | 88 | #endif |
89 | |||
90 | #ifdef CONFIG_BT_HCIUART_LL | ||
91 | int ll_init(void); | ||
92 | int ll_deinit(void); | ||
93 | #endif | ||