Bluetooth: Add basic state tracking to Three-wire UART driver

This patch adds basic state tracking and socket buffer handling to the
Three-wire UART (H5) HCI driver.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
This commit is contained in:
Johan Hedberg 2012-07-16 16:12:03 +03:00 committed by Gustavo Padovan
parent 7dec65c8a7
commit 7d664fbafa
1 changed files with 92 additions and 4 deletions

View File

@ -30,14 +30,48 @@
#include "hci_uart.h" #include "hci_uart.h"
struct h5 {
struct sk_buff_head unack; /* Unack'ed packets queue */
struct sk_buff_head rel; /* Reliable packets queue */
struct sk_buff_head unrel; /* Unreliable packets queue */
struct sk_buff *rx_skb;
bool txack_req;
u8 msgq_txseq;
};
static int h5_open(struct hci_uart *hu) static int h5_open(struct hci_uart *hu)
{ {
return -ENOSYS; struct h5 *h5;
BT_DBG("hu %p", hu);
h5 = kzalloc(sizeof(*h5), GFP_KERNEL);
if (!h5)
return -ENOMEM;
hu->priv = h5;
skb_queue_head_init(&h5->unack);
skb_queue_head_init(&h5->rel);
skb_queue_head_init(&h5->unrel);
return 0;
} }
static int h5_close(struct hci_uart *hu) static int h5_close(struct hci_uart *hu)
{ {
return -ENOSYS; struct h5 *h5 = hu->priv;
skb_queue_purge(&h5->unack);
skb_queue_purge(&h5->rel);
skb_queue_purge(&h5->unrel);
kfree(h5);
return 0;
} }
static int h5_recv(struct hci_uart *hu, void *data, int count) static int h5_recv(struct hci_uart *hu, void *data, int count)
@ -47,17 +81,71 @@ static int h5_recv(struct hci_uart *hu, void *data, int count)
static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb) static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb)
{ {
return -ENOSYS; struct h5 *h5 = hu->priv;
if (skb->len > 0xfff) {
BT_ERR("Packet too long (%u bytes)", skb->len);
kfree_skb(skb);
return 0;
}
switch (bt_cb(skb)->pkt_type) {
case HCI_ACLDATA_PKT:
case HCI_COMMAND_PKT:
skb_queue_tail(&h5->rel, skb);
break;
case HCI_SCODATA_PKT:
skb_queue_tail(&h5->unrel, skb);
break;
default:
BT_ERR("Unknown packet type %u", bt_cb(skb)->pkt_type);
kfree_skb(skb);
break;
}
return 0;
}
static struct sk_buff *h5_prepare_pkt(struct h5 *h5, struct sk_buff *skb)
{
h5->txack_req = false;
return NULL;
}
static struct sk_buff *h5_prepare_ack(struct h5 *h5)
{
h5->txack_req = false;
return NULL;
} }
static struct sk_buff *h5_dequeue(struct hci_uart *hu) static struct sk_buff *h5_dequeue(struct hci_uart *hu)
{ {
struct h5 *h5 = hu->priv;
struct sk_buff *skb, *nskb;
if ((skb = skb_dequeue(&h5->unrel)) != NULL) {
nskb = h5_prepare_pkt(h5, skb);
if (nskb) {
kfree_skb(skb);
return nskb;
}
skb_queue_head(&h5->unrel, skb);
BT_ERR("Could not dequeue pkt because alloc_skb failed");
}
if (h5->txack_req)
return h5_prepare_ack(h5);
return NULL; return NULL;
} }
static int h5_flush(struct hci_uart *hu) static int h5_flush(struct hci_uart *hu)
{ {
return -ENOSYS; BT_DBG("hu %p", hu);
return 0;
} }
static struct hci_uart_proto h5p = { static struct hci_uart_proto h5p = {