Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: drivers/bluetooth/hci_ath.c

Issue 2649001: Atheros patch to support ath3k BT device. (Closed) Base URL: ssh://git@chromiumos-git/kernel.git
Patch Set: Modified to address review comments. Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « drivers/bluetooth/Makefile ('k') | drivers/bluetooth/hci_ldisc.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2009-2010 Atheros Communications Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22
23 #include <linux/init.h>
24 #include <linux/slab.h>
25 #include <linux/tty.h>
26 #include <linux/errno.h>
27 #include <linux/ioctl.h>
28 #include <linux/skbuff.h>
29
30 #include <net/bluetooth/bluetooth.h>
31 #include <net/bluetooth/hci_core.h>
32
33 #include "hci_uart.h"
34
35
36 /* HCIATH receiver States */
37 #define HCIATH_W4_PACKET_TYPE 0
38 #define HCIATH_W4_EVENT_HDR 1
39 #define HCIATH_W4_ACL_HDR 2
40 #define HCIATH_W4_SCO_HDR 3
41 #define HCIATH_W4_DATA 4
42
43 struct ath_struct {
44 struct hci_uart *hu;
45 unsigned int rx_state;
46 unsigned int rx_count;
47 unsigned int cur_sleep;
48
49 spinlock_t hciath_lock;
50 struct sk_buff *rx_skb;
51 struct sk_buff_head txq;
52 wait_queue_head_t wqevt;
53 struct work_struct ctxtsw;
54 };
55
56 int ath_wakeup_ar3001(struct tty_struct *tty)
57 {
58 struct termios settings;
59 int status = 0x00;
60 mm_segment_t oldfs;
61 status = tty->driver->ops->tiocmget(tty, NULL);
62
63 if ((status & TIOCM_CTS))
64 return status;
65
66 oldfs = get_fs();
67 set_fs(KERNEL_DS);
68 n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
69
70 settings.c_cflag &= ~CRTSCTS;
71 n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
72 set_fs(oldfs);
73 status = tty->driver->ops->tiocmget(tty, NULL);
74
75 /* Wake up board */
76 tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
77 mdelay(20);
78
79 status = tty->driver->ops->tiocmget(tty, NULL);
80
81 tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
82 mdelay(20);
83
84 status = tty->driver->ops->tiocmget(tty, NULL);
85 oldfs = get_fs();
86 set_fs(KERNEL_DS);
87 n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
88
89 settings.c_cflag |= CRTSCTS;
90 n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
91 set_fs(oldfs);
92 return status;
93 }
94
95 static void ath_context_switch(struct work_struct *work)
96 {
97 int status;
98 struct ath_struct *ath;
99 struct hci_uart *hu;
100 struct tty_struct *tty;
101
102 ath = container_of(work, struct ath_struct, ctxtsw);
103
104 hu = ath->hu;
105 tty = hu->tty;
106
107 /* verify and wake up controller */
108 if (ath->cur_sleep) {
109
110 status = ath_wakeup_ar3001(tty);
111 if (!(status & TIOCM_CTS))
112 return;
113 }
114
115 /* Ready to send Data */
116 clear_bit(HCI_UART_SENDING, &hu->tx_state);
117 hci_uart_tx_wakeup(hu);
118 }
119
120 int ath_check_sleep_cmd(struct ath_struct *ath, unsigned char *packet)
121 {
122 if (packet[0] == 0x04 && packet[1] == 0xFC)
123 ath->cur_sleep = packet[3];
124
125 return 0;
126 }
127
128
129 /* Initialize protocol */
130 static int ath_open(struct hci_uart *hu)
131 {
132 struct ath_struct *ath;
133 BT_DBG("hu %p", hu);
134
135 ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
136 if (!ath)
137 return -ENOMEM;
138
139 skb_queue_head_init(&ath->txq);
140 spin_lock_init(&ath->hciath_lock);
141
142 ath->cur_sleep = 0;
143 hu->priv = ath;
144 ath->hu = hu;
145
146 init_waitqueue_head(&ath->wqevt);
147 INIT_WORK(&ath->ctxtsw, ath_context_switch);
148 return 0;
149 }
150
151 /* Flush protocol data */
152 static int ath_flush(struct hci_uart *hu)
153 {
154 struct ath_struct *ath = hu->priv;
155 BT_DBG("hu %p", hu);
156 skb_queue_purge(&ath->txq);
157
158 return 0;
159 }
160
161 /* Close protocol */
162 static int ath_close(struct hci_uart *hu)
163 {
164 struct ath_struct *ath = hu->priv;
165 BT_DBG("hu %p", hu);
166
167 skb_queue_purge(&ath->txq);
168
169 if (ath->rx_skb)
170 kfree_skb(ath->rx_skb);
171
172 wake_up_interruptible(&ath->wqevt);
173 hu->priv = NULL;
174 kfree(ath);
175 return 0;
176 }
177
178 /* Enqueue frame for transmittion */
179 static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
180 {
181 struct ath_struct *ath = hu->priv;
182 if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
183
184 /* Discard SCO packet.AR3001 does not support SCO over HCI */
185 BT_DBG("SCO Packet over HCI received Dropping\n");
186 kfree(skb);
187 return 0;
188 }
189 BT_DBG("hu %p skb %p", hu, skb);
190
191 /* Prepend skb with frame type */
192 memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
193
194 skb_queue_tail(&ath->txq, skb);
195 set_bit(HCI_UART_SENDING, &hu->tx_state);
196
197 schedule_work(&ath->ctxtsw);
198 return 0;
199 }
200
201 static struct sk_buff *ath_dequeue(struct hci_uart *hu)
202 {
203 struct ath_struct *ath = hu->priv;
204 struct sk_buff *skbuf;
205
206 skbuf = skb_dequeue(&ath->txq);
207 if (skbuf != NULL)
208 ath_check_sleep_cmd(ath, &skbuf->data[1]);
209
210 return skbuf;
211 }
212
213 static inline int ath_check_data_len(struct ath_struct *ath, int len)
214 {
215 register int room = skb_tailroom(ath->rx_skb);
216 BT_DBG("len %d room %d", len, room);
217
218 if (len > room) {
219 BT_ERR("Data length is too large");
220 kfree_skb(ath->rx_skb);
221 ath->rx_state = HCIATH_W4_PACKET_TYPE;
222 ath->rx_skb = NULL;
223 ath->rx_count = 0;
224 } else {
225 ath->rx_state = HCIATH_W4_DATA;
226 ath->rx_count = len;
227 return len;
228 }
229
230 return 0;
231 }
232
233 /* Recv data */
234 static int ath_recv(struct hci_uart *hu, void *data, int count)
235 {
236 struct ath_struct *ath = hu->priv;
237 register char *ptr;
238 struct hci_event_hdr *eh;
239 struct hci_acl_hdr *ah;
240 struct hci_sco_hdr *sh;
241 struct sk_buff *skbuf;
242 register int len, type, dlen;
243
244 skbuf = NULL;
245 BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
246 ath->rx_state, ath->rx_count);
247 ptr = data;
248 while (count) {
249 if (ath->rx_count) {
250
251 len = min_t(unsigned int, ath->rx_count, count);
252 memcpy(skb_put(ath->rx_skb, len), ptr, len);
253 ath->rx_count -= len;
254 count -= len;
255 ptr += len;
256
257 if (ath->rx_count)
258 continue;
259 switch (ath->rx_state) {
260 case HCIATH_W4_DATA:
261 hci_recv_frame(ath->rx_skb);
262 ath->rx_state = HCIATH_W4_PACKET_TYPE;
263 ath->rx_skb = NULL;
264 ath->rx_count = 0;
265 continue;
266 case HCIATH_W4_EVENT_HDR:
267 eh = (struct hci_event_hdr *)ath->rx_skb->data;
268 BT_DBG("Event header: evt 0x%2.2x plen %d",
269 eh->evt, eh->plen);
270 ath_check_data_len(ath, eh->plen);
271 continue;
272 case HCIATH_W4_ACL_HDR:
273 ah = (struct hci_acl_hdr *)ath->rx_skb->data;
274 dlen = __le16_to_cpu(ah->dlen);
275 BT_DBG("ACL header: dlen %d", dlen);
276 ath_check_data_len(ath, dlen);
277 continue;
278 case HCIATH_W4_SCO_HDR:
279 sh = (struct hci_sco_hdr *)ath->rx_skb->data;
280 BT_DBG("SCO header: dlen %d", sh->dlen);
281 ath_check_data_len(ath, sh->dlen);
282 continue;
283 }
284 }
285
286 /* HCIATH_W4_PACKET_TYPE */
287 switch (*ptr) {
288 case HCI_EVENT_PKT:
289 BT_DBG("Event packet");
290 ath->rx_state = HCIATH_W4_EVENT_HDR;
291 ath->rx_count = HCI_EVENT_HDR_SIZE;
292 type = HCI_EVENT_PKT;
293 break;
294 case HCI_ACLDATA_PKT:
295 BT_DBG("ACL packet");
296 ath->rx_state = HCIATH_W4_ACL_HDR;
297 ath->rx_count = HCI_ACL_HDR_SIZE;
298 type = HCI_ACLDATA_PKT;
299 break;
300 case HCI_SCODATA_PKT:
301 BT_DBG("SCO packet");
302 ath->rx_state = HCIATH_W4_SCO_HDR;
303 ath->rx_count = HCI_SCO_HDR_SIZE;
304 type = HCI_SCODATA_PKT;
305 break;
306 default:
307 BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
308 hu->hdev->stat.err_rx++;
309 ptr++;
310 count--;
311 continue;
312 };
313 ptr++;
314 count--;
315
316 /* Allocate packet */
317 ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
318 if (!ath->rx_skb) {
319 BT_ERR("Can't allocate mem for new packet");
320 ath->rx_state = HCIATH_W4_PACKET_TYPE;
321 ath->rx_count = 0;
322 return -ENOMEM;
323 }
324 ath->rx_skb->dev = (void *)hu->hdev;
325 bt_cb(ath->rx_skb)->pkt_type = type;
326 } return count;
327 }
328
329 static struct hci_uart_proto athp = {
330 .id = HCI_UART_ATH,
331 .open = ath_open,
332 .close = ath_close,
333 .recv = ath_recv,
334 .enqueue = ath_enqueue,
335 .dequeue = ath_dequeue,
336 .flush = ath_flush,
337 };
338
339 int ath_init(void)
340 {
341 int err = hci_uart_register_proto(&athp);
342 if (!err)
343 BT_INFO("HCIATH protocol initialized");
344
345 else
346 BT_ERR("HCIATH protocol registration failed with err %d", err);
347 return err;
348 }
349
350 int ath_deinit(void)
351 {
352 return hci_uart_unregister_proto(&athp);
353 }
OLDNEW
« no previous file with comments | « drivers/bluetooth/Makefile ('k') | drivers/bluetooth/hci_ldisc.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698