Bluetooth: Add basic state tracking to Three-wire UART driver
[deliverable/linux.git] / drivers / bluetooth / hci_h5.c
CommitLineData
7dec65c8
JH
1/*
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
7d664fba
JH
33struct h5 {
34 struct sk_buff_head unack; /* Unack'ed packets queue */
35 struct sk_buff_head rel; /* Reliable packets queue */
36 struct sk_buff_head unrel; /* Unreliable packets queue */
37
38 struct sk_buff *rx_skb;
39
40 bool txack_req;
41
42 u8 msgq_txseq;
43};
44
7dec65c8
JH
45static int h5_open(struct hci_uart *hu)
46{
7d664fba
JH
47 struct h5 *h5;
48
49 BT_DBG("hu %p", hu);
50
51 h5 = kzalloc(sizeof(*h5), GFP_KERNEL);
52 if (!h5)
53 return -ENOMEM;
54
55 hu->priv = h5;
56
57 skb_queue_head_init(&h5->unack);
58 skb_queue_head_init(&h5->rel);
59 skb_queue_head_init(&h5->unrel);
60
61 return 0;
7dec65c8
JH
62}
63
64static int h5_close(struct hci_uart *hu)
65{
7d664fba
JH
66 struct h5 *h5 = hu->priv;
67
68 skb_queue_purge(&h5->unack);
69 skb_queue_purge(&h5->rel);
70 skb_queue_purge(&h5->unrel);
71
72 kfree(h5);
73
74 return 0;
7dec65c8
JH
75}
76
77static int h5_recv(struct hci_uart *hu, void *data, int count)
78{
79 return -ENOSYS;
80}
81
82static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb)
83{
7d664fba
JH
84 struct h5 *h5 = hu->priv;
85
86 if (skb->len > 0xfff) {
87 BT_ERR("Packet too long (%u bytes)", skb->len);
88 kfree_skb(skb);
89 return 0;
90 }
91
92 switch (bt_cb(skb)->pkt_type) {
93 case HCI_ACLDATA_PKT:
94 case HCI_COMMAND_PKT:
95 skb_queue_tail(&h5->rel, skb);
96 break;
97
98 case HCI_SCODATA_PKT:
99 skb_queue_tail(&h5->unrel, skb);
100 break;
101
102 default:
103 BT_ERR("Unknown packet type %u", bt_cb(skb)->pkt_type);
104 kfree_skb(skb);
105 break;
106 }
107
108 return 0;
109}
110
111static struct sk_buff *h5_prepare_pkt(struct h5 *h5, struct sk_buff *skb)
112{
113 h5->txack_req = false;
114 return NULL;
115}
116
117static struct sk_buff *h5_prepare_ack(struct h5 *h5)
118{
119 h5->txack_req = false;
120 return NULL;
7dec65c8
JH
121}
122
123static struct sk_buff *h5_dequeue(struct hci_uart *hu)
124{
7d664fba
JH
125 struct h5 *h5 = hu->priv;
126 struct sk_buff *skb, *nskb;
127
128 if ((skb = skb_dequeue(&h5->unrel)) != NULL) {
129 nskb = h5_prepare_pkt(h5, skb);
130 if (nskb) {
131 kfree_skb(skb);
132 return nskb;
133 }
134
135 skb_queue_head(&h5->unrel, skb);
136 BT_ERR("Could not dequeue pkt because alloc_skb failed");
137 }
138
139 if (h5->txack_req)
140 return h5_prepare_ack(h5);
141
7dec65c8
JH
142 return NULL;
143}
144
145static int h5_flush(struct hci_uart *hu)
146{
7d664fba
JH
147 BT_DBG("hu %p", hu);
148 return 0;
7dec65c8
JH
149}
150
151static struct hci_uart_proto h5p = {
152 .id = HCI_UART_3WIRE,
153 .open = h5_open,
154 .close = h5_close,
155 .recv = h5_recv,
156 .enqueue = h5_enqueue,
157 .dequeue = h5_dequeue,
158 .flush = h5_flush,
159};
160
161int __init h5_init(void)
162{
163 int err = hci_uart_register_proto(&h5p);
164
165 if (!err)
166 BT_INFO("HCI Three-wire UART (H5) protocol initialized");
167 else
168 BT_ERR("HCI Three-wire UART (H5) protocol init failed");
169
170 return err;
171}
172
173int __exit h5_deinit(void)
174{
175 return hci_uart_unregister_proto(&h5p);
176}
This page took 0.044716 seconds and 5 git commands to generate.