blob: ae1bd32d8ef947dccac26c8db5ead28c300eea06 [file] [log] [blame]
Johan Hedberg7dec65c2012-07-16 16:12:02 +03001/*
2 *
3 * Bluetooth HCI Three-wire UART driver
4 *
5 * Copyright (C) 2012 Intel Corporation
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <linux/kernel.h>
25#include <linux/errno.h>
26#include <linux/skbuff.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30
31#include "hci_uart.h"
32
Johan Hedberg3f27e952012-07-16 16:12:04 +030033#define H5_TXWINSIZE 4
34
35#define H5_ACK_TIMEOUT msecs_to_jiffies(250)
36
Johan Hedberg7d664fb2012-07-16 16:12:03 +030037struct h5 {
38 struct sk_buff_head unack; /* Unack'ed packets queue */
39 struct sk_buff_head rel; /* Reliable packets queue */
40 struct sk_buff_head unrel; /* Unreliable packets queue */
41
42 struct sk_buff *rx_skb;
43
Johan Hedberg3f27e952012-07-16 16:12:04 +030044 struct timer_list timer; /* Retransmission timer */
45
Johan Hedberg7d664fb2012-07-16 16:12:03 +030046 bool txack_req;
47
48 u8 msgq_txseq;
49};
50
Johan Hedberg3f27e952012-07-16 16:12:04 +030051static void h5_timed_event(unsigned long arg)
52{
53 struct hci_uart *hu = (struct hci_uart *) arg;
54 struct h5 *h5 = hu->priv;
55 struct sk_buff *skb;
56 unsigned long flags;
57
58 BT_DBG("hu %p retransmitting %u pkts", hu, h5->unack.qlen);
59
60 spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING);
61
62 while ((skb = __skb_dequeue_tail(&h5->unack)) != NULL) {
63 h5->msgq_txseq = (h5->msgq_txseq - 1) & 0x07;
64 skb_queue_head(&h5->rel, skb);
65 }
66
67 spin_unlock_irqrestore(&h5->unack.lock, flags);
68
69 hci_uart_tx_wakeup(hu);
70}
71
Johan Hedberg7dec65c2012-07-16 16:12:02 +030072static int h5_open(struct hci_uart *hu)
73{
Johan Hedberg7d664fb2012-07-16 16:12:03 +030074 struct h5 *h5;
75
76 BT_DBG("hu %p", hu);
77
78 h5 = kzalloc(sizeof(*h5), GFP_KERNEL);
79 if (!h5)
80 return -ENOMEM;
81
82 hu->priv = h5;
83
84 skb_queue_head_init(&h5->unack);
85 skb_queue_head_init(&h5->rel);
86 skb_queue_head_init(&h5->unrel);
87
Johan Hedberg3f27e952012-07-16 16:12:04 +030088 init_timer(&h5->timer);
89 h5->timer.function = h5_timed_event;
90 h5->timer.data = (unsigned long) hu;
91
Johan Hedberg7d664fb2012-07-16 16:12:03 +030092 return 0;
Johan Hedberg7dec65c2012-07-16 16:12:02 +030093}
94
95static int h5_close(struct hci_uart *hu)
96{
Johan Hedberg7d664fb2012-07-16 16:12:03 +030097 struct h5 *h5 = hu->priv;
98
99 skb_queue_purge(&h5->unack);
100 skb_queue_purge(&h5->rel);
101 skb_queue_purge(&h5->unrel);
102
Johan Hedberg3f27e952012-07-16 16:12:04 +0300103 del_timer(&h5->timer);
104
Johan Hedberg7d664fb2012-07-16 16:12:03 +0300105 kfree(h5);
106
107 return 0;
Johan Hedberg7dec65c2012-07-16 16:12:02 +0300108}
109
110static int h5_recv(struct hci_uart *hu, void *data, int count)
111{
112 return -ENOSYS;
113}
114
115static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb)
116{
Johan Hedberg7d664fb2012-07-16 16:12:03 +0300117 struct h5 *h5 = hu->priv;
118
119 if (skb->len > 0xfff) {
120 BT_ERR("Packet too long (%u bytes)", skb->len);
121 kfree_skb(skb);
122 return 0;
123 }
124
125 switch (bt_cb(skb)->pkt_type) {
126 case HCI_ACLDATA_PKT:
127 case HCI_COMMAND_PKT:
128 skb_queue_tail(&h5->rel, skb);
129 break;
130
131 case HCI_SCODATA_PKT:
132 skb_queue_tail(&h5->unrel, skb);
133 break;
134
135 default:
136 BT_ERR("Unknown packet type %u", bt_cb(skb)->pkt_type);
137 kfree_skb(skb);
138 break;
139 }
140
141 return 0;
142}
143
144static struct sk_buff *h5_prepare_pkt(struct h5 *h5, struct sk_buff *skb)
145{
146 h5->txack_req = false;
147 return NULL;
148}
149
150static struct sk_buff *h5_prepare_ack(struct h5 *h5)
151{
152 h5->txack_req = false;
153 return NULL;
Johan Hedberg7dec65c2012-07-16 16:12:02 +0300154}
155
156static struct sk_buff *h5_dequeue(struct hci_uart *hu)
157{
Johan Hedberg7d664fb2012-07-16 16:12:03 +0300158 struct h5 *h5 = hu->priv;
Johan Hedberg3f27e952012-07-16 16:12:04 +0300159 unsigned long flags;
Johan Hedberg7d664fb2012-07-16 16:12:03 +0300160 struct sk_buff *skb, *nskb;
161
162 if ((skb = skb_dequeue(&h5->unrel)) != NULL) {
163 nskb = h5_prepare_pkt(h5, skb);
164 if (nskb) {
165 kfree_skb(skb);
166 return nskb;
167 }
168
169 skb_queue_head(&h5->unrel, skb);
170 BT_ERR("Could not dequeue pkt because alloc_skb failed");
171 }
172
Johan Hedberg3f27e952012-07-16 16:12:04 +0300173 spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING);
174
175 if (h5->unack.qlen >= H5_TXWINSIZE)
176 goto unlock;
177
178 if ((skb = skb_dequeue(&h5->rel)) != NULL) {
179 nskb = h5_prepare_pkt(h5, skb);
180
181 if (nskb) {
182 __skb_queue_tail(&h5->unack, skb);
183 mod_timer(&h5->timer, jiffies + H5_ACK_TIMEOUT);
184 spin_unlock_irqrestore(&h5->unack.lock, flags);
185 return nskb;
186 }
187
188 skb_queue_head(&h5->rel, skb);
189 BT_ERR("Could not dequeue pkt because alloc_skb failed");
190 }
191
192unlock:
193 spin_unlock_irqrestore(&h5->unack.lock, flags);
194
Johan Hedberg7d664fb2012-07-16 16:12:03 +0300195 if (h5->txack_req)
196 return h5_prepare_ack(h5);
197
Johan Hedberg7dec65c2012-07-16 16:12:02 +0300198 return NULL;
199}
200
201static int h5_flush(struct hci_uart *hu)
202{
Johan Hedberg7d664fb2012-07-16 16:12:03 +0300203 BT_DBG("hu %p", hu);
204 return 0;
Johan Hedberg7dec65c2012-07-16 16:12:02 +0300205}
206
207static struct hci_uart_proto h5p = {
208 .id = HCI_UART_3WIRE,
209 .open = h5_open,
210 .close = h5_close,
211 .recv = h5_recv,
212 .enqueue = h5_enqueue,
213 .dequeue = h5_dequeue,
214 .flush = h5_flush,
215};
216
217int __init h5_init(void)
218{
219 int err = hci_uart_register_proto(&h5p);
220
221 if (!err)
222 BT_INFO("HCI Three-wire UART (H5) protocol initialized");
223 else
224 BT_ERR("HCI Three-wire UART (H5) protocol init failed");
225
226 return err;
227}
228
229int __exit h5_deinit(void)
230{
231 return hci_uart_unregister_proto(&h5p);
232}