Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
1da177e4 | 2 | * |
0372a662 MH |
3 | * Bluetooth HCI UART driver |
4 | * | |
5 | * Copyright (C) 2000-2001 Qualcomm Incorporated | |
6 | * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> | |
7 | * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org> | |
8 | * | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2 of the License, or | |
13 | * (at your option) any later version. | |
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 | * | |
1da177e4 | 24 | */ |
1da177e4 | 25 | |
1da177e4 LT |
26 | #include <linux/module.h> |
27 | ||
28 | #include <linux/kernel.h> | |
29 | #include <linux/init.h> | |
1da177e4 LT |
30 | #include <linux/types.h> |
31 | #include <linux/fcntl.h> | |
32 | #include <linux/interrupt.h> | |
33 | #include <linux/ptrace.h> | |
34 | #include <linux/poll.h> | |
35 | ||
36 | #include <linux/slab.h> | |
37 | #include <linux/tty.h> | |
38 | #include <linux/errno.h> | |
39 | #include <linux/string.h> | |
40 | #include <linux/signal.h> | |
41 | #include <linux/ioctl.h> | |
42 | #include <linux/skbuff.h> | |
43 | ||
44 | #include <net/bluetooth/bluetooth.h> | |
45 | #include <net/bluetooth/hci_core.h> | |
0372a662 | 46 | |
1da177e4 | 47 | #include "hci_uart.h" |
1da177e4 | 48 | |
0372a662 MH |
49 | #define VERSION "1.2" |
50 | ||
51 | struct h4_struct { | |
c27799f9 | 52 | struct sk_buff *rx_skb; |
0372a662 MH |
53 | struct sk_buff_head txq; |
54 | }; | |
55 | ||
1da177e4 LT |
56 | /* Initialize protocol */ |
57 | static int h4_open(struct hci_uart *hu) | |
58 | { | |
59 | struct h4_struct *h4; | |
0372a662 | 60 | |
1da177e4 | 61 | BT_DBG("hu %p", hu); |
0372a662 | 62 | |
fdcd1661 | 63 | h4 = kzalloc(sizeof(*h4), GFP_KERNEL); |
1da177e4 LT |
64 | if (!h4) |
65 | return -ENOMEM; | |
0372a662 | 66 | |
1da177e4 LT |
67 | skb_queue_head_init(&h4->txq); |
68 | ||
69 | hu->priv = h4; | |
70 | return 0; | |
71 | } | |
72 | ||
73 | /* Flush protocol data */ | |
74 | static int h4_flush(struct hci_uart *hu) | |
75 | { | |
76 | struct h4_struct *h4 = hu->priv; | |
77 | ||
78 | BT_DBG("hu %p", hu); | |
0372a662 | 79 | |
1da177e4 | 80 | skb_queue_purge(&h4->txq); |
0372a662 | 81 | |
1da177e4 LT |
82 | return 0; |
83 | } | |
84 | ||
85 | /* Close protocol */ | |
86 | static int h4_close(struct hci_uart *hu) | |
87 | { | |
88 | struct h4_struct *h4 = hu->priv; | |
0372a662 | 89 | |
1da177e4 LT |
90 | hu->priv = NULL; |
91 | ||
92 | BT_DBG("hu %p", hu); | |
93 | ||
94 | skb_queue_purge(&h4->txq); | |
0372a662 | 95 | |
c27799f9 MH |
96 | kfree_skb(h4->rx_skb); |
97 | ||
1da177e4 LT |
98 | hu->priv = NULL; |
99 | kfree(h4); | |
0372a662 | 100 | |
1da177e4 LT |
101 | return 0; |
102 | } | |
103 | ||
104 | /* Enqueue frame for transmittion (padding, crc, etc) */ | |
105 | static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) | |
106 | { | |
107 | struct h4_struct *h4 = hu->priv; | |
108 | ||
109 | BT_DBG("hu %p skb %p", hu, skb); | |
110 | ||
111 | /* Prepend skb with frame type */ | |
0d48d939 | 112 | memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); |
1da177e4 | 113 | skb_queue_tail(&h4->txq, skb); |
0372a662 | 114 | |
1da177e4 LT |
115 | return 0; |
116 | } | |
117 | ||
1da177e4 | 118 | /* Recv data */ |
9d1c40eb | 119 | static int h4_recv(struct hci_uart *hu, const void *data, int count) |
1da177e4 | 120 | { |
c27799f9 | 121 | struct h4_struct *h4 = hu->priv; |
b86ed368 | 122 | |
c2578202 CP |
123 | if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) |
124 | return -EUNATCH; | |
125 | ||
c27799f9 MH |
126 | h4->rx_skb = h4_recv_buf(hu->hdev, h4->rx_skb, data, count); |
127 | if (IS_ERR(h4->rx_skb)) { | |
128 | int err = PTR_ERR(h4->rx_skb); | |
129 | BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); | |
130 | return err; | |
b86ed368 | 131 | } |
0372a662 | 132 | |
1da177e4 LT |
133 | return count; |
134 | } | |
135 | ||
136 | static struct sk_buff *h4_dequeue(struct hci_uart *hu) | |
137 | { | |
138 | struct h4_struct *h4 = hu->priv; | |
139 | return skb_dequeue(&h4->txq); | |
140 | } | |
141 | ||
142 | static struct hci_uart_proto h4p = { | |
0372a662 MH |
143 | .id = HCI_UART_H4, |
144 | .open = h4_open, | |
145 | .close = h4_close, | |
146 | .recv = h4_recv, | |
147 | .enqueue = h4_enqueue, | |
148 | .dequeue = h4_dequeue, | |
149 | .flush = h4_flush, | |
1da177e4 | 150 | }; |
0372a662 | 151 | |
f2b94bb9 | 152 | int __init h4_init(void) |
1da177e4 LT |
153 | { |
154 | int err = hci_uart_register_proto(&h4p); | |
0372a662 | 155 | |
1da177e4 LT |
156 | if (!err) |
157 | BT_INFO("HCI H4 protocol initialized"); | |
158 | else | |
159 | BT_ERR("HCI H4 protocol registration failed"); | |
0372a662 | 160 | |
1da177e4 LT |
161 | return err; |
162 | } | |
163 | ||
f2b94bb9 | 164 | int __exit h4_deinit(void) |
1da177e4 LT |
165 | { |
166 | return hci_uart_unregister_proto(&h4p); | |
167 | } | |
e1a38d70 MH |
168 | |
169 | struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, | |
170 | const unsigned char *buffer, int count) | |
171 | { | |
172 | while (count) { | |
173 | int len; | |
174 | ||
175 | if (!skb) { | |
176 | switch (buffer[0]) { | |
177 | case HCI_ACLDATA_PKT: | |
178 | skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, | |
179 | GFP_ATOMIC); | |
180 | if (!skb) | |
181 | return ERR_PTR(-ENOMEM); | |
182 | ||
183 | bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; | |
184 | bt_cb(skb)->expect = HCI_ACL_HDR_SIZE; | |
185 | break; | |
186 | case HCI_SCODATA_PKT: | |
187 | skb = bt_skb_alloc(HCI_MAX_SCO_SIZE, | |
188 | GFP_ATOMIC); | |
189 | if (!skb) | |
190 | return ERR_PTR(-ENOMEM); | |
191 | ||
192 | bt_cb(skb)->pkt_type = HCI_SCODATA_PKT; | |
193 | bt_cb(skb)->expect = HCI_SCO_HDR_SIZE; | |
194 | break; | |
195 | case HCI_EVENT_PKT: | |
196 | skb = bt_skb_alloc(HCI_MAX_EVENT_SIZE, | |
197 | GFP_ATOMIC); | |
198 | if (!skb) | |
199 | return ERR_PTR(-ENOMEM); | |
200 | ||
201 | bt_cb(skb)->pkt_type = HCI_EVENT_PKT; | |
202 | bt_cb(skb)->expect = HCI_EVENT_HDR_SIZE; | |
203 | break; | |
204 | default: | |
205 | return ERR_PTR(-EILSEQ); | |
206 | } | |
207 | ||
208 | count -= 1; | |
209 | buffer += 1; | |
210 | } | |
211 | ||
212 | len = min_t(uint, bt_cb(skb)->expect, count); | |
213 | memcpy(skb_put(skb, len), buffer, len); | |
214 | ||
215 | count -= len; | |
216 | buffer += len; | |
217 | bt_cb(skb)->expect -= len; | |
218 | ||
219 | switch (bt_cb(skb)->pkt_type) { | |
220 | case HCI_ACLDATA_PKT: | |
221 | if (skb->len == HCI_ACL_HDR_SIZE) { | |
222 | __le16 dlen = hci_acl_hdr(skb)->dlen; | |
223 | ||
224 | /* Complete ACL header */ | |
225 | bt_cb(skb)->expect = __le16_to_cpu(dlen); | |
226 | ||
227 | if (skb_tailroom(skb) < bt_cb(skb)->expect) { | |
228 | kfree_skb(skb); | |
229 | return ERR_PTR(-EMSGSIZE); | |
230 | } | |
231 | } | |
232 | break; | |
233 | case HCI_SCODATA_PKT: | |
234 | if (skb->len == HCI_SCO_HDR_SIZE) { | |
235 | /* Complete SCO header */ | |
236 | bt_cb(skb)->expect = hci_sco_hdr(skb)->dlen; | |
237 | ||
238 | if (skb_tailroom(skb) < bt_cb(skb)->expect) { | |
239 | kfree_skb(skb); | |
240 | return ERR_PTR(-EMSGSIZE); | |
241 | } | |
242 | } | |
243 | break; | |
244 | case HCI_EVENT_PKT: | |
245 | if (skb->len == HCI_EVENT_HDR_SIZE) { | |
246 | /* Complete event header */ | |
247 | bt_cb(skb)->expect = hci_event_hdr(skb)->plen; | |
248 | ||
249 | if (skb_tailroom(skb) < bt_cb(skb)->expect) { | |
250 | kfree_skb(skb); | |
251 | return ERR_PTR(-EMSGSIZE); | |
252 | } | |
253 | } | |
254 | break; | |
255 | } | |
256 | ||
257 | if (bt_cb(skb)->expect == 0) { | |
258 | /* Complete frame */ | |
259 | hci_recv_frame(hdev, skb); | |
260 | skb = NULL; | |
261 | } | |
262 | } | |
263 | ||
264 | return skb; | |
265 | } |