diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/bluetooth/hci_bcsp.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/bluetooth/hci_bcsp.c')
-rw-r--r-- | drivers/bluetooth/hci_bcsp.c | 749 |
1 files changed, 749 insertions, 0 deletions
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c new file mode 100644 index 000000000000..c0ed213fc857 --- /dev/null +++ b/drivers/bluetooth/hci_bcsp.c | |||
@@ -0,0 +1,749 @@ | |||
1 | /* | ||
2 | BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). | ||
3 | Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com> | ||
4 | |||
5 | Based on | ||
6 | hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com> | ||
7 | ABCSP by Carl Orsborn <cjo@csr.com> | ||
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 version 2 as | ||
11 | published by the Free Software Foundation; | ||
12 | |||
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
14 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
16 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
17 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
18 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
19 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
20 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
21 | |||
22 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
23 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
24 | SOFTWARE IS DISCLAIMED. | ||
25 | */ | ||
26 | |||
27 | /* | ||
28 | * $Id: hci_bcsp.c,v 1.2 2002/09/26 05:05:14 maxk Exp $ | ||
29 | */ | ||
30 | |||
31 | #define VERSION "0.2" | ||
32 | |||
33 | #include <linux/config.h> | ||
34 | #include <linux/module.h> | ||
35 | |||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/sched.h> | ||
39 | #include <linux/types.h> | ||
40 | #include <linux/fcntl.h> | ||
41 | #include <linux/interrupt.h> | ||
42 | #include <linux/ptrace.h> | ||
43 | #include <linux/poll.h> | ||
44 | |||
45 | #include <linux/slab.h> | ||
46 | #include <linux/tty.h> | ||
47 | #include <linux/errno.h> | ||
48 | #include <linux/string.h> | ||
49 | #include <linux/signal.h> | ||
50 | #include <linux/ioctl.h> | ||
51 | #include <linux/skbuff.h> | ||
52 | |||
53 | #include <net/bluetooth/bluetooth.h> | ||
54 | #include <net/bluetooth/hci_core.h> | ||
55 | #include "hci_uart.h" | ||
56 | #include "hci_bcsp.h" | ||
57 | |||
58 | #ifndef CONFIG_BT_HCIUART_DEBUG | ||
59 | #undef BT_DBG | ||
60 | #define BT_DBG( A... ) | ||
61 | #undef BT_DMP | ||
62 | #define BT_DMP( A... ) | ||
63 | #endif | ||
64 | |||
65 | static int hciextn = 1; | ||
66 | |||
67 | /* ---- BCSP CRC calculation ---- */ | ||
68 | |||
69 | /* Table for calculating CRC for polynomial 0x1021, LSB processed first, | ||
70 | initial value 0xffff, bits shifted in reverse order. */ | ||
71 | |||
72 | static const u16 crc_table[] = { | ||
73 | 0x0000, 0x1081, 0x2102, 0x3183, | ||
74 | 0x4204, 0x5285, 0x6306, 0x7387, | ||
75 | 0x8408, 0x9489, 0xa50a, 0xb58b, | ||
76 | 0xc60c, 0xd68d, 0xe70e, 0xf78f | ||
77 | }; | ||
78 | |||
79 | /* Initialise the crc calculator */ | ||
80 | #define BCSP_CRC_INIT(x) x = 0xffff | ||
81 | |||
82 | /* | ||
83 | Update crc with next data byte | ||
84 | |||
85 | Implementation note | ||
86 | The data byte is treated as two nibbles. The crc is generated | ||
87 | in reverse, i.e., bits are fed into the register from the top. | ||
88 | */ | ||
89 | static void bcsp_crc_update(u16 *crc, u8 d) | ||
90 | { | ||
91 | u16 reg = *crc; | ||
92 | |||
93 | reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f]; | ||
94 | reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f]; | ||
95 | |||
96 | *crc = reg; | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | Get reverse of generated crc | ||
101 | |||
102 | Implementation note | ||
103 | The crc generator (bcsp_crc_init() and bcsp_crc_update()) | ||
104 | creates a reversed crc, so it needs to be swapped back before | ||
105 | being passed on. | ||
106 | */ | ||
107 | static u16 bcsp_crc_reverse(u16 crc) | ||
108 | { | ||
109 | u16 b, rev; | ||
110 | |||
111 | for (b = 0, rev = 0; b < 16; b++) { | ||
112 | rev = rev << 1; | ||
113 | rev |= (crc & 1); | ||
114 | crc = crc >> 1; | ||
115 | } | ||
116 | return (rev); | ||
117 | } | ||
118 | |||
119 | /* ---- BCSP core ---- */ | ||
120 | |||
121 | static void bcsp_slip_msgdelim(struct sk_buff *skb) | ||
122 | { | ||
123 | const char pkt_delim = 0xc0; | ||
124 | memcpy(skb_put(skb, 1), &pkt_delim, 1); | ||
125 | } | ||
126 | |||
127 | static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c) | ||
128 | { | ||
129 | const char esc_c0[2] = { 0xdb, 0xdc }; | ||
130 | const char esc_db[2] = { 0xdb, 0xdd }; | ||
131 | |||
132 | switch (c) { | ||
133 | case 0xc0: | ||
134 | memcpy(skb_put(skb, 2), &esc_c0, 2); | ||
135 | break; | ||
136 | case 0xdb: | ||
137 | memcpy(skb_put(skb, 2), &esc_db, 2); | ||
138 | break; | ||
139 | default: | ||
140 | memcpy(skb_put(skb, 1), &c, 1); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb) | ||
145 | { | ||
146 | struct bcsp_struct *bcsp = hu->priv; | ||
147 | |||
148 | if (skb->len > 0xFFF) { | ||
149 | BT_ERR("Packet too long"); | ||
150 | kfree_skb(skb); | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | switch (skb->pkt_type) { | ||
155 | case HCI_ACLDATA_PKT: | ||
156 | case HCI_COMMAND_PKT: | ||
157 | skb_queue_tail(&bcsp->rel, skb); | ||
158 | break; | ||
159 | |||
160 | case HCI_SCODATA_PKT: | ||
161 | skb_queue_tail(&bcsp->unrel, skb); | ||
162 | break; | ||
163 | |||
164 | default: | ||
165 | BT_ERR("Unknown packet type"); | ||
166 | kfree_skb(skb); | ||
167 | break; | ||
168 | } | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, | ||
174 | int len, int pkt_type) | ||
175 | { | ||
176 | struct sk_buff *nskb; | ||
177 | u8 hdr[4], chan; | ||
178 | int rel, i; | ||
179 | |||
180 | #ifdef CONFIG_BT_HCIUART_BCSP_TXCRC | ||
181 | u16 BCSP_CRC_INIT(bcsp_txmsg_crc); | ||
182 | #endif | ||
183 | |||
184 | switch (pkt_type) { | ||
185 | case HCI_ACLDATA_PKT: | ||
186 | chan = 6; /* BCSP ACL channel */ | ||
187 | rel = 1; /* reliable channel */ | ||
188 | break; | ||
189 | case HCI_COMMAND_PKT: | ||
190 | chan = 5; /* BCSP cmd/evt channel */ | ||
191 | rel = 1; /* reliable channel */ | ||
192 | break; | ||
193 | case HCI_SCODATA_PKT: | ||
194 | chan = 7; /* BCSP SCO channel */ | ||
195 | rel = 0; /* unreliable channel */ | ||
196 | break; | ||
197 | case BCSP_LE_PKT: | ||
198 | chan = 1; /* BCSP LE channel */ | ||
199 | rel = 0; /* unreliable channel */ | ||
200 | break; | ||
201 | case BCSP_ACK_PKT: | ||
202 | chan = 0; /* BCSP internal channel */ | ||
203 | rel = 0; /* unreliable channel */ | ||
204 | break; | ||
205 | default: | ||
206 | BT_ERR("Unknown packet type"); | ||
207 | return NULL; | ||
208 | } | ||
209 | |||
210 | if (hciextn && chan == 5) { | ||
211 | struct hci_command_hdr *hdr = (struct hci_command_hdr *) data; | ||
212 | |||
213 | if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == OGF_VENDOR_CMD) { | ||
214 | u8 desc = *(data + HCI_COMMAND_HDR_SIZE); | ||
215 | if ((desc & 0xf0) == 0xc0) { | ||
216 | data += HCI_COMMAND_HDR_SIZE + 1; | ||
217 | len -= HCI_COMMAND_HDR_SIZE + 1; | ||
218 | chan = desc & 0x0f; | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | /* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2 | ||
224 | (because bytes 0xc0 and 0xdb are escaped, worst case is | ||
225 | when the packet is all made of 0xc0 and 0xdb :) ) | ||
226 | + 2 (0xc0 delimiters at start and end). */ | ||
227 | |||
228 | nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC); | ||
229 | if (!nskb) | ||
230 | return NULL; | ||
231 | |||
232 | nskb->pkt_type = pkt_type; | ||
233 | |||
234 | bcsp_slip_msgdelim(nskb); | ||
235 | |||
236 | hdr[0] = bcsp->rxseq_txack << 3; | ||
237 | bcsp->txack_req = 0; | ||
238 | BT_DBG("We request packet no %u to card", bcsp->rxseq_txack); | ||
239 | |||
240 | if (rel) { | ||
241 | hdr[0] |= 0x80 + bcsp->msgq_txseq; | ||
242 | BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); | ||
243 | bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; | ||
244 | } | ||
245 | #ifdef CONFIG_BT_HCIUART_BCSP_TXCRC | ||
246 | hdr[0] |= 0x40; | ||
247 | #endif | ||
248 | |||
249 | hdr[1] = ((len << 4) & 0xff) | chan; | ||
250 | hdr[2] = len >> 4; | ||
251 | hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]); | ||
252 | |||
253 | /* Put BCSP header */ | ||
254 | for (i = 0; i < 4; i++) { | ||
255 | bcsp_slip_one_byte(nskb, hdr[i]); | ||
256 | #ifdef CONFIG_BT_HCIUART_BCSP_TXCRC | ||
257 | bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]); | ||
258 | #endif | ||
259 | } | ||
260 | |||
261 | /* Put payload */ | ||
262 | for (i = 0; i < len; i++) { | ||
263 | bcsp_slip_one_byte(nskb, data[i]); | ||
264 | #ifdef CONFIG_BT_HCIUART_BCSP_TXCRC | ||
265 | bcsp_crc_update(&bcsp_txmsg_crc, data[i]); | ||
266 | #endif | ||
267 | } | ||
268 | |||
269 | #ifdef CONFIG_BT_HCIUART_BCSP_TXCRC | ||
270 | /* Put CRC */ | ||
271 | bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc); | ||
272 | bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff)); | ||
273 | bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff)); | ||
274 | #endif | ||
275 | |||
276 | bcsp_slip_msgdelim(nskb); | ||
277 | return nskb; | ||
278 | } | ||
279 | |||
280 | /* This is a rewrite of pkt_avail in ABCSP */ | ||
281 | static struct sk_buff *bcsp_dequeue(struct hci_uart *hu) | ||
282 | { | ||
283 | struct bcsp_struct *bcsp = hu->priv; | ||
284 | unsigned long flags; | ||
285 | struct sk_buff *skb; | ||
286 | |||
287 | /* First of all, check for unreliable messages in the queue, | ||
288 | since they have priority */ | ||
289 | |||
290 | if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) { | ||
291 | struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type); | ||
292 | if (nskb) { | ||
293 | kfree_skb(skb); | ||
294 | return nskb; | ||
295 | } else { | ||
296 | skb_queue_head(&bcsp->unrel, skb); | ||
297 | BT_ERR("Could not dequeue pkt because alloc_skb failed"); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | /* Now, try to send a reliable pkt. We can only send a | ||
302 | reliable packet if the number of packets sent but not yet ack'ed | ||
303 | is < than the winsize */ | ||
304 | |||
305 | spin_lock_irqsave(&bcsp->unack.lock, flags); | ||
306 | |||
307 | if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) { | ||
308 | struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type); | ||
309 | if (nskb) { | ||
310 | __skb_queue_tail(&bcsp->unack, skb); | ||
311 | mod_timer(&bcsp->tbcsp, jiffies + HZ / 4); | ||
312 | spin_unlock_irqrestore(&bcsp->unack.lock, flags); | ||
313 | return nskb; | ||
314 | } else { | ||
315 | skb_queue_head(&bcsp->rel, skb); | ||
316 | BT_ERR("Could not dequeue pkt because alloc_skb failed"); | ||
317 | } | ||
318 | } | ||
319 | |||
320 | spin_unlock_irqrestore(&bcsp->unack.lock, flags); | ||
321 | |||
322 | |||
323 | /* We could not send a reliable packet, either because there are | ||
324 | none or because there are too many unack'ed pkts. Did we receive | ||
325 | any packets we have not acknowledged yet ? */ | ||
326 | |||
327 | if (bcsp->txack_req) { | ||
328 | /* if so, craft an empty ACK pkt and send it on BCSP unreliable | ||
329 | channel 0 */ | ||
330 | struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT); | ||
331 | return nskb; | ||
332 | } | ||
333 | |||
334 | /* We have nothing to send */ | ||
335 | return NULL; | ||
336 | } | ||
337 | |||
338 | static int bcsp_flush(struct hci_uart *hu) | ||
339 | { | ||
340 | BT_DBG("hu %p", hu); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | /* Remove ack'ed packets */ | ||
345 | static void bcsp_pkt_cull(struct bcsp_struct *bcsp) | ||
346 | { | ||
347 | unsigned long flags; | ||
348 | struct sk_buff *skb; | ||
349 | int i, pkts_to_be_removed; | ||
350 | u8 seqno; | ||
351 | |||
352 | spin_lock_irqsave(&bcsp->unack.lock, flags); | ||
353 | |||
354 | pkts_to_be_removed = bcsp->unack.qlen; | ||
355 | seqno = bcsp->msgq_txseq; | ||
356 | |||
357 | while (pkts_to_be_removed) { | ||
358 | if (bcsp->rxack == seqno) | ||
359 | break; | ||
360 | pkts_to_be_removed--; | ||
361 | seqno = (seqno - 1) & 0x07; | ||
362 | } | ||
363 | |||
364 | if (bcsp->rxack != seqno) | ||
365 | BT_ERR("Peer acked invalid packet"); | ||
366 | |||
367 | BT_DBG("Removing %u pkts out of %u, up to seqno %u", | ||
368 | pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07); | ||
369 | |||
370 | for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed | ||
371 | && skb != (struct sk_buff *) &bcsp->unack; i++) { | ||
372 | struct sk_buff *nskb; | ||
373 | |||
374 | nskb = skb->next; | ||
375 | __skb_unlink(skb, &bcsp->unack); | ||
376 | kfree_skb(skb); | ||
377 | skb = nskb; | ||
378 | } | ||
379 | if (bcsp->unack.qlen == 0) | ||
380 | del_timer(&bcsp->tbcsp); | ||
381 | spin_unlock_irqrestore(&bcsp->unack.lock, flags); | ||
382 | |||
383 | if (i != pkts_to_be_removed) | ||
384 | BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed); | ||
385 | } | ||
386 | |||
387 | /* Handle BCSP link-establishment packets. When we | ||
388 | detect a "sync" packet, symptom that the BT module has reset, | ||
389 | we do nothing :) (yet) */ | ||
390 | static void bcsp_handle_le_pkt(struct hci_uart *hu) | ||
391 | { | ||
392 | struct bcsp_struct *bcsp = hu->priv; | ||
393 | u8 conf_pkt[4] = { 0xad, 0xef, 0xac, 0xed }; | ||
394 | u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 }; | ||
395 | u8 sync_pkt[4] = { 0xda, 0xdc, 0xed, 0xed }; | ||
396 | |||
397 | /* spot "conf" pkts and reply with a "conf rsp" pkt */ | ||
398 | if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 && | ||
399 | !memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) { | ||
400 | struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC); | ||
401 | |||
402 | BT_DBG("Found a LE conf pkt"); | ||
403 | if (!nskb) | ||
404 | return; | ||
405 | memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4); | ||
406 | nskb->pkt_type = BCSP_LE_PKT; | ||
407 | |||
408 | skb_queue_head(&bcsp->unrel, nskb); | ||
409 | hci_uart_tx_wakeup(hu); | ||
410 | } | ||
411 | /* Spot "sync" pkts. If we find one...disaster! */ | ||
412 | else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 && | ||
413 | !memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) { | ||
414 | BT_ERR("Found a LE sync pkt, card has reset"); | ||
415 | } | ||
416 | } | ||
417 | |||
418 | static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte) | ||
419 | { | ||
420 | const u8 c0 = 0xc0, db = 0xdb; | ||
421 | |||
422 | switch (bcsp->rx_esc_state) { | ||
423 | case BCSP_ESCSTATE_NOESC: | ||
424 | switch (byte) { | ||
425 | case 0xdb: | ||
426 | bcsp->rx_esc_state = BCSP_ESCSTATE_ESC; | ||
427 | break; | ||
428 | default: | ||
429 | memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1); | ||
430 | if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && | ||
431 | bcsp->rx_state != BCSP_W4_CRC) | ||
432 | bcsp_crc_update(&bcsp->message_crc, byte); | ||
433 | bcsp->rx_count--; | ||
434 | } | ||
435 | break; | ||
436 | |||
437 | case BCSP_ESCSTATE_ESC: | ||
438 | switch (byte) { | ||
439 | case 0xdc: | ||
440 | memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1); | ||
441 | if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && | ||
442 | bcsp->rx_state != BCSP_W4_CRC) | ||
443 | bcsp_crc_update(&bcsp-> message_crc, 0xc0); | ||
444 | bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; | ||
445 | bcsp->rx_count--; | ||
446 | break; | ||
447 | |||
448 | case 0xdd: | ||
449 | memcpy(skb_put(bcsp->rx_skb, 1), &db, 1); | ||
450 | if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && | ||
451 | bcsp->rx_state != BCSP_W4_CRC) | ||
452 | bcsp_crc_update(&bcsp-> message_crc, 0xdb); | ||
453 | bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; | ||
454 | bcsp->rx_count--; | ||
455 | break; | ||
456 | |||
457 | default: | ||
458 | BT_ERR ("Invalid byte %02x after esc byte", byte); | ||
459 | kfree_skb(bcsp->rx_skb); | ||
460 | bcsp->rx_skb = NULL; | ||
461 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
462 | bcsp->rx_count = 0; | ||
463 | } | ||
464 | } | ||
465 | } | ||
466 | |||
467 | static inline void bcsp_complete_rx_pkt(struct hci_uart *hu) | ||
468 | { | ||
469 | struct bcsp_struct *bcsp = hu->priv; | ||
470 | int pass_up; | ||
471 | |||
472 | if (bcsp->rx_skb->data[0] & 0x80) { /* reliable pkt */ | ||
473 | BT_DBG("Received seqno %u from card", bcsp->rxseq_txack); | ||
474 | bcsp->rxseq_txack++; | ||
475 | bcsp->rxseq_txack %= 0x8; | ||
476 | bcsp->txack_req = 1; | ||
477 | |||
478 | /* If needed, transmit an ack pkt */ | ||
479 | hci_uart_tx_wakeup(hu); | ||
480 | } | ||
481 | |||
482 | bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07; | ||
483 | BT_DBG("Request for pkt %u from card", bcsp->rxack); | ||
484 | |||
485 | bcsp_pkt_cull(bcsp); | ||
486 | if ((bcsp->rx_skb->data[1] & 0x0f) == 6 && | ||
487 | bcsp->rx_skb->data[0] & 0x80) { | ||
488 | bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT; | ||
489 | pass_up = 1; | ||
490 | } else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 && | ||
491 | bcsp->rx_skb->data[0] & 0x80) { | ||
492 | bcsp->rx_skb->pkt_type = HCI_EVENT_PKT; | ||
493 | pass_up = 1; | ||
494 | } else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) { | ||
495 | bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT; | ||
496 | pass_up = 1; | ||
497 | } else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 && | ||
498 | !(bcsp->rx_skb->data[0] & 0x80)) { | ||
499 | bcsp_handle_le_pkt(hu); | ||
500 | pass_up = 0; | ||
501 | } else | ||
502 | pass_up = 0; | ||
503 | |||
504 | if (!pass_up) { | ||
505 | struct hci_event_hdr hdr; | ||
506 | u8 desc = (bcsp->rx_skb->data[1] & 0x0f); | ||
507 | |||
508 | if (desc != 0 && desc != 1) { | ||
509 | if (hciextn) { | ||
510 | desc |= 0xc0; | ||
511 | skb_pull(bcsp->rx_skb, 4); | ||
512 | memcpy(skb_push(bcsp->rx_skb, 1), &desc, 1); | ||
513 | |||
514 | hdr.evt = 0xff; | ||
515 | hdr.plen = bcsp->rx_skb->len; | ||
516 | memcpy(skb_push(bcsp->rx_skb, HCI_EVENT_HDR_SIZE), &hdr, HCI_EVENT_HDR_SIZE); | ||
517 | bcsp->rx_skb->pkt_type = HCI_EVENT_PKT; | ||
518 | |||
519 | hci_recv_frame(bcsp->rx_skb); | ||
520 | } else { | ||
521 | BT_ERR ("Packet for unknown channel (%u %s)", | ||
522 | bcsp->rx_skb->data[1] & 0x0f, | ||
523 | bcsp->rx_skb->data[0] & 0x80 ? | ||
524 | "reliable" : "unreliable"); | ||
525 | kfree_skb(bcsp->rx_skb); | ||
526 | } | ||
527 | } else | ||
528 | kfree_skb(bcsp->rx_skb); | ||
529 | } else { | ||
530 | /* Pull out BCSP hdr */ | ||
531 | skb_pull(bcsp->rx_skb, 4); | ||
532 | |||
533 | hci_recv_frame(bcsp->rx_skb); | ||
534 | } | ||
535 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
536 | bcsp->rx_skb = NULL; | ||
537 | } | ||
538 | |||
539 | /* Recv data */ | ||
540 | static int bcsp_recv(struct hci_uart *hu, void *data, int count) | ||
541 | { | ||
542 | struct bcsp_struct *bcsp = hu->priv; | ||
543 | register unsigned char *ptr; | ||
544 | |||
545 | BT_DBG("hu %p count %d rx_state %d rx_count %ld", | ||
546 | hu, count, bcsp->rx_state, bcsp->rx_count); | ||
547 | |||
548 | ptr = data; | ||
549 | while (count) { | ||
550 | if (bcsp->rx_count) { | ||
551 | if (*ptr == 0xc0) { | ||
552 | BT_ERR("Short BCSP packet"); | ||
553 | kfree_skb(bcsp->rx_skb); | ||
554 | bcsp->rx_state = BCSP_W4_PKT_START; | ||
555 | bcsp->rx_count = 0; | ||
556 | } else | ||
557 | bcsp_unslip_one_byte(bcsp, *ptr); | ||
558 | |||
559 | ptr++; count--; | ||
560 | continue; | ||
561 | } | ||
562 | |||
563 | switch (bcsp->rx_state) { | ||
564 | case BCSP_W4_BCSP_HDR: | ||
565 | if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] + | ||
566 | bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) { | ||
567 | BT_ERR("Error in BCSP hdr checksum"); | ||
568 | kfree_skb(bcsp->rx_skb); | ||
569 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
570 | bcsp->rx_count = 0; | ||
571 | continue; | ||
572 | } | ||
573 | if (bcsp->rx_skb->data[0] & 0x80 /* reliable pkt */ | ||
574 | && (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) { | ||
575 | BT_ERR ("Out-of-order packet arrived, got %u expected %u", | ||
576 | bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack); | ||
577 | |||
578 | kfree_skb(bcsp->rx_skb); | ||
579 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
580 | bcsp->rx_count = 0; | ||
581 | continue; | ||
582 | } | ||
583 | bcsp->rx_state = BCSP_W4_DATA; | ||
584 | bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) + | ||
585 | (bcsp->rx_skb->data[2] << 4); /* May be 0 */ | ||
586 | continue; | ||
587 | |||
588 | case BCSP_W4_DATA: | ||
589 | if (bcsp->rx_skb->data[0] & 0x40) { /* pkt with crc */ | ||
590 | bcsp->rx_state = BCSP_W4_CRC; | ||
591 | bcsp->rx_count = 2; | ||
592 | } else | ||
593 | bcsp_complete_rx_pkt(hu); | ||
594 | continue; | ||
595 | |||
596 | case BCSP_W4_CRC: | ||
597 | if (bcsp_crc_reverse(bcsp->message_crc) != | ||
598 | (bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) + | ||
599 | bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) { | ||
600 | |||
601 | BT_ERR ("Checksum failed: computed %04x received %04x", | ||
602 | bcsp_crc_reverse(bcsp->message_crc), | ||
603 | (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) + | ||
604 | bcsp->rx_skb->data[bcsp->rx_skb->len - 1]); | ||
605 | |||
606 | kfree_skb(bcsp->rx_skb); | ||
607 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
608 | bcsp->rx_count = 0; | ||
609 | continue; | ||
610 | } | ||
611 | skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2); | ||
612 | bcsp_complete_rx_pkt(hu); | ||
613 | continue; | ||
614 | |||
615 | case BCSP_W4_PKT_DELIMITER: | ||
616 | switch (*ptr) { | ||
617 | case 0xc0: | ||
618 | bcsp->rx_state = BCSP_W4_PKT_START; | ||
619 | break; | ||
620 | default: | ||
621 | /*BT_ERR("Ignoring byte %02x", *ptr);*/ | ||
622 | break; | ||
623 | } | ||
624 | ptr++; count--; | ||
625 | break; | ||
626 | |||
627 | case BCSP_W4_PKT_START: | ||
628 | switch (*ptr) { | ||
629 | case 0xc0: | ||
630 | ptr++; count--; | ||
631 | break; | ||
632 | |||
633 | default: | ||
634 | bcsp->rx_state = BCSP_W4_BCSP_HDR; | ||
635 | bcsp->rx_count = 4; | ||
636 | bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; | ||
637 | BCSP_CRC_INIT(bcsp->message_crc); | ||
638 | |||
639 | /* Do not increment ptr or decrement count | ||
640 | * Allocate packet. Max len of a BCSP pkt= | ||
641 | * 0xFFF (payload) +4 (header) +2 (crc) */ | ||
642 | |||
643 | bcsp->rx_skb = bt_skb_alloc(0x1005, GFP_ATOMIC); | ||
644 | if (!bcsp->rx_skb) { | ||
645 | BT_ERR("Can't allocate mem for new packet"); | ||
646 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
647 | bcsp->rx_count = 0; | ||
648 | return 0; | ||
649 | } | ||
650 | bcsp->rx_skb->dev = (void *) hu->hdev; | ||
651 | break; | ||
652 | } | ||
653 | break; | ||
654 | } | ||
655 | } | ||
656 | return count; | ||
657 | } | ||
658 | |||
659 | /* Arrange to retransmit all messages in the relq. */ | ||
660 | static void bcsp_timed_event(unsigned long arg) | ||
661 | { | ||
662 | struct hci_uart *hu = (struct hci_uart *) arg; | ||
663 | struct bcsp_struct *bcsp = hu->priv; | ||
664 | struct sk_buff *skb; | ||
665 | unsigned long flags; | ||
666 | |||
667 | BT_DBG("hu %p retransmitting %u pkts", hu, bcsp->unack.qlen); | ||
668 | |||
669 | spin_lock_irqsave(&bcsp->unack.lock, flags); | ||
670 | |||
671 | while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) { | ||
672 | bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07; | ||
673 | skb_queue_head(&bcsp->rel, skb); | ||
674 | } | ||
675 | |||
676 | spin_unlock_irqrestore(&bcsp->unack.lock, flags); | ||
677 | |||
678 | hci_uart_tx_wakeup(hu); | ||
679 | } | ||
680 | |||
681 | static int bcsp_open(struct hci_uart *hu) | ||
682 | { | ||
683 | struct bcsp_struct *bcsp; | ||
684 | |||
685 | BT_DBG("hu %p", hu); | ||
686 | |||
687 | bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC); | ||
688 | if (!bcsp) | ||
689 | return -ENOMEM; | ||
690 | memset(bcsp, 0, sizeof(*bcsp)); | ||
691 | |||
692 | hu->priv = bcsp; | ||
693 | skb_queue_head_init(&bcsp->unack); | ||
694 | skb_queue_head_init(&bcsp->rel); | ||
695 | skb_queue_head_init(&bcsp->unrel); | ||
696 | |||
697 | init_timer(&bcsp->tbcsp); | ||
698 | bcsp->tbcsp.function = bcsp_timed_event; | ||
699 | bcsp->tbcsp.data = (u_long) hu; | ||
700 | |||
701 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
702 | |||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | static int bcsp_close(struct hci_uart *hu) | ||
707 | { | ||
708 | struct bcsp_struct *bcsp = hu->priv; | ||
709 | hu->priv = NULL; | ||
710 | |||
711 | BT_DBG("hu %p", hu); | ||
712 | |||
713 | skb_queue_purge(&bcsp->unack); | ||
714 | skb_queue_purge(&bcsp->rel); | ||
715 | skb_queue_purge(&bcsp->unrel); | ||
716 | del_timer(&bcsp->tbcsp); | ||
717 | |||
718 | kfree(bcsp); | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | static struct hci_uart_proto bcsp = { | ||
723 | .id = HCI_UART_BCSP, | ||
724 | .open = bcsp_open, | ||
725 | .close = bcsp_close, | ||
726 | .enqueue = bcsp_enqueue, | ||
727 | .dequeue = bcsp_dequeue, | ||
728 | .recv = bcsp_recv, | ||
729 | .flush = bcsp_flush | ||
730 | }; | ||
731 | |||
732 | int bcsp_init(void) | ||
733 | { | ||
734 | int err = hci_uart_register_proto(&bcsp); | ||
735 | if (!err) | ||
736 | BT_INFO("HCI BCSP protocol initialized"); | ||
737 | else | ||
738 | BT_ERR("HCI BCSP protocol registration failed"); | ||
739 | |||
740 | return err; | ||
741 | } | ||
742 | |||
743 | int bcsp_deinit(void) | ||
744 | { | ||
745 | return hci_uart_unregister_proto(&bcsp); | ||
746 | } | ||
747 | |||
748 | module_param(hciextn, bool, 0644); | ||
749 | MODULE_PARM_DESC(hciextn, "Convert HCI Extensions into BCSP packets"); | ||