From a6c511c636848f871f5b7aef38e25e5b894b3b48 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Wed, 23 May 2012 12:35:46 +0200 Subject: Bluetooth: Rename HCI_QUIRK_NO_RESET to HCI_QUIRK_RESET_ON_CLOSE HCI_QUIRK_NO_RESET name is misleading - purpose of this quirk is to reset device on close instead of init, not to not reset at all. Rename it to HCI_QUIRK_RESET_ON_CLOSE to avoid confusion. Signed-off-by: Szymon Janc Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bpa10x.c | 2 +- drivers/bluetooth/btusb.c | 6 +++--- drivers/bluetooth/hci_ldisc.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index 609861a..29caaed 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -470,7 +470,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id * hdev->flush = bpa10x_flush; hdev->send = bpa10x_send_frame; - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); err = hci_register_dev(hdev); if (err < 0) { diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c9463af..3a6cdc9 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1026,7 +1026,7 @@ static int btusb_probe(struct usb_interface *intf, data->isoc = usb_ifnum_to_if(data->udev, 1); if (!reset) - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) { if (!disable_scofix) @@ -1038,7 +1038,7 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_DIGIANSWER) { data->cmdreq_type = USB_TYPE_VENDOR; - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); } if (id->driver_info & BTUSB_CSR) { @@ -1046,7 +1046,7 @@ static int btusb_probe(struct usb_interface *intf, /* Old firmware would otherwise execute USB reset */ if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117) - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); } if (id->driver_info & BTUSB_SNIFFER) { diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index e564579..2f9b796 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -394,7 +394,7 @@ static int hci_uart_register_dev(struct hci_uart *hu) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags)) - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags)) hdev->dev_type = HCI_AMP; -- cgit v1.1 From fc5fef615a963c8b13abf0bbc2a8e8d7c3fd1ffb Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 23 May 2012 04:04:19 -0300 Subject: Bluetooth: Remove 'register' usage from the subsystem Let the compiler chooses what is best. Signed-off-by: Gustavo Padovan Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bluecard_cs.c | 10 +++++----- drivers/bluetooth/bt3c_cs.c | 4 ++-- drivers/bluetooth/btuart_cs.c | 4 ++-- drivers/bluetooth/dtl1_cs.c | 4 ++-- drivers/bluetooth/hci_bcsp.c | 2 +- drivers/bluetooth/hci_h4.c | 2 +- drivers/bluetooth/hci_ll.c | 6 +++--- 7 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 1fcd923..585c88e 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -231,12 +231,12 @@ static void bluecard_write_wakeup(bluecard_info_t *info) } do { - register unsigned int iobase = info->p_dev->resource[0]->start; - register unsigned int offset; - register unsigned char command; - register unsigned long ready_bit; + unsigned int iobase = info->p_dev->resource[0]->start; + unsigned int offset; + unsigned char command; + unsigned long ready_bit; register struct sk_buff *skb; - register int len; + int len; clear_bit(XMIT_WAKEUP, &(info->tx_state)); diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 308c859..b2b0fbb 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -186,9 +186,9 @@ static void bt3c_write_wakeup(bt3c_info_t *info) return; do { - register unsigned int iobase = info->p_dev->resource[0]->start; + unsigned int iobase = info->p_dev->resource[0]->start; register struct sk_buff *skb; - register int len; + int len; if (!pcmcia_dev_present(info->p_dev)) break; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index c4fc2f3..65b8d99 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -140,9 +140,9 @@ static void btuart_write_wakeup(btuart_info_t *info) } do { - register unsigned int iobase = info->p_dev->resource[0]->start; + unsigned int iobase = info->p_dev->resource[0]->start; register struct sk_buff *skb; - register int len; + int len; clear_bit(XMIT_WAKEUP, &(info->tx_state)); diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 6e8d961..b1b37cc 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -144,9 +144,9 @@ static void dtl1_write_wakeup(dtl1_info_t *info) } do { - register unsigned int iobase = info->p_dev->resource[0]->start; + unsigned int iobase = info->p_dev->resource[0]->start; register struct sk_buff *skb; - register int len; + int len; clear_bit(XMIT_WAKEUP, &(info->tx_state)); diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 661a8dc..57e502e 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -552,7 +552,7 @@ static u16 bscp_get_crc(struct bcsp_struct *bcsp) static int bcsp_recv(struct hci_uart *hu, void *data, int count) { struct bcsp_struct *bcsp = hu->priv; - register unsigned char *ptr; + unsigned char *ptr; BT_DBG("hu %p count %d rx_state %d rx_count %ld", hu, count, bcsp->rx_state, bcsp->rx_count); diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 7483294..c60623f 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -126,7 +126,7 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) static inline int h4_check_data_len(struct h4_struct *h4, int len) { - register int room = skb_tailroom(h4->rx_skb); + int room = skb_tailroom(h4->rx_skb); BT_DBG("len %d room %d", len, room); diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index b874c0e..ff6d589 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -348,7 +348,7 @@ static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb) static inline int ll_check_data_len(struct ll_struct *ll, int len) { - register int room = skb_tailroom(ll->rx_skb); + int room = skb_tailroom(ll->rx_skb); BT_DBG("len %d room %d", len, room); @@ -374,11 +374,11 @@ static inline int ll_check_data_len(struct ll_struct *ll, int len) static int ll_recv(struct hci_uart *hu, void *data, int count) { struct ll_struct *ll = hu->priv; - register char *ptr; + char *ptr; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; - register int len, type, dlen; + int len, type, dlen; BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count); -- cgit v1.1 From 8c520a59927a5600973782505dbb750d985057c4 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 23 May 2012 04:04:22 -0300 Subject: Bluetooth: Remove unnecessary headers include Most of the include were unnecessary or already included by some other header. Replace module.h by export.h where possible. Signed-off-by: Gustavo Padovan Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 3a6cdc9..a45e717 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -21,15 +21,7 @@ * */ -#include #include -#include -#include -#include -#include -#include -#include - #include #include -- cgit v1.1 From 37ed561e823f5f91ca87522d61a57974be583c0d Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Wed, 23 May 2012 18:50:04 -0700 Subject: Bluetooth: btmrvl: add SD8787 Bluetooth AMP device ID SD8787 SDIO function 3 (device ID 0x911B) is for Bluetooth AMP. Signed-off-by: Bing Zhao Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btmrvl_sdio.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index a853244..2867499 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -110,6 +110,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8787 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A), .driver_data = (unsigned long) &btmrvl_sdio_sd8787 }, + /* Marvell SD8787 Bluetooth AMP device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911B), + .driver_data = (unsigned long) &btmrvl_sdio_sd8787 }, /* Marvell SD8797 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A), .driver_data = (unsigned long) &btmrvl_sdio_sd8797 }, -- cgit v1.1 From 46afededca7d8b0117e05b23e5cbcfa0e2bbbd92 Mon Sep 17 00:00:00 2001 From: Devendra Naga Date: Tue, 19 Jun 2012 21:51:31 +0530 Subject: Bluetooth: cleanup dtl1_config Improve the error handling of dtl1_config() Signed-off-by: Devendra Naga Signed-off-by: Gustavo Padovan --- drivers/bluetooth/dtl1_cs.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index b1b37cc..97a7784 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -586,29 +586,31 @@ static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data) static int dtl1_config(struct pcmcia_device *link) { dtl1_info_t *info = link->priv; - int i; + int ret; /* Look for a generic full-sized window */ link->resource[0]->end = 8; - if (pcmcia_loop_config(link, dtl1_confcheck, NULL) < 0) + ret = pcmcia_loop_config(link, dtl1_confcheck, NULL); + if (ret) goto failed; - i = pcmcia_request_irq(link, dtl1_interrupt); - if (i != 0) + ret = pcmcia_request_irq(link, dtl1_interrupt); + if (ret) goto failed; - i = pcmcia_enable_device(link); - if (i != 0) + ret = pcmcia_enable_device(link); + if (ret) goto failed; - if (dtl1_open(info) != 0) + ret = dtl1_open(info); + if (ret) goto failed; return 0; failed: dtl1_detach(link); - return -ENODEV; + return ret; } static const struct pcmcia_device_id dtl1_ids[] = { -- cgit v1.1 From 510df2515f6b0afdd7604aee21b02b8f339e9344 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 20 Jun 2012 14:40:12 +0300 Subject: Bluetooth: Fix warning: using int as NULL pointer Fix for warnings below: ... drivers/bluetooth/bt3c_cs.c:667:20: warning: Using plain integer as NULL pointer drivers/bluetooth/btuart_cs.c:596:20: warning: Using plain integer as NULL pointer ... Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- drivers/bluetooth/bt3c_cs.c | 2 +- drivers/bluetooth/btuart_cs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index b2b0fbb..8925b6d 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -664,7 +664,7 @@ static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data) { int *try = priv_data; - if (try == 0) + if (!try) p_dev->io_lines = 16; if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0)) diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 65b8d99..21e803a 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -593,7 +593,7 @@ static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data) { int *try = priv_data; - if (try == 0) + if (!try) p_dev->io_lines = 16; if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0)) -- cgit v1.1 From 74ad8fdaefe6ccb8ef1918394a9d04a036658346 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 29 Jun 2012 14:58:07 +0300 Subject: Bluetooth: bluecard_cs: Shorten scope for iobase Shortening scope shall silence some warnings reported by Geert Uytterhoeven: ... drivers/bluetooth/bluecard_cs.c: warning: unused variable 'iobase' [-Wunused-variable] ... Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- drivers/bluetooth/bluecard_cs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 585c88e..66c3a67 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -621,7 +621,6 @@ static int bluecard_hci_flush(struct hci_dev *hdev) static int bluecard_hci_open(struct hci_dev *hdev) { bluecard_info_t *info = hci_get_drvdata(hdev); - unsigned int iobase = info->p_dev->resource[0]->start; if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); @@ -630,6 +629,8 @@ static int bluecard_hci_open(struct hci_dev *hdev) return 0; if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) { + unsigned int iobase = info->p_dev->resource[0]->start; + /* Enable LED */ outb(0x08 | 0x20, iobase + 0x30); } @@ -641,7 +642,6 @@ static int bluecard_hci_open(struct hci_dev *hdev) static int bluecard_hci_close(struct hci_dev *hdev) { bluecard_info_t *info = hci_get_drvdata(hdev); - unsigned int iobase = info->p_dev->resource[0]->start; if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) return 0; @@ -649,6 +649,8 @@ static int bluecard_hci_close(struct hci_dev *hdev) bluecard_hci_flush(hdev); if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) { + unsigned int iobase = info->p_dev->resource[0]->start; + /* Disable LED */ outb(0x00, iobase + 0x30); } -- cgit v1.1 From 2c2453f3e46139b86c1e5b0fbd821823b04e4ada Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 9 Jul 2012 13:57:18 +0300 Subject: Bluetooth: btmrvl: trivial style fixes Patch shortens locals scope and adds missing braces. This is a diff between v1 which was applied and v2 of patch "Bluetooth: btmrvl: Do not send vendor events to bluetooth stack". Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btmrvl_main.c | 8 +++++--- drivers/bluetooth/btmrvl_sdio.c | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index dc304de..3a4343b 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -47,10 +47,11 @@ EXPORT_SYMBOL_GPL(btmrvl_interrupt); bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) { struct hci_event_hdr *hdr = (void *) skb->data; - struct hci_ev_cmd_complete *ec; - u16 opcode, ocf, ogf; if (hdr->evt == HCI_EV_CMD_COMPLETE) { + struct hci_ev_cmd_complete *ec; + u16 opcode, ocf, ogf; + ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE); opcode = __le16_to_cpu(ec->opcode); ocf = hci_opcode_ocf(opcode); @@ -64,7 +65,8 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) } if (ogf == OGF) { - BT_DBG("vendor event skipped: ogf 0x%4.4x", ogf); + BT_DBG("vendor event skipped: ogf 0x%4.4x ocf 0x%4.4x", + ogf, ocf); kfree_skb(skb); return false; } diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index cf7588ed..6a9e971 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -568,8 +568,9 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) if (type == HCI_EVENT_PKT) { if (btmrvl_check_evtpkt(priv, skb)) hci_recv_frame(skb); - } else + } else { hci_recv_frame(skb); + } hdev->stat.byte_rx += buf_len; break; -- cgit v1.1 From 7dec65c8a7fdab87d23bcf3c7e7eff662d180853 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:02 +0300 Subject: Bluetooth: Initial skeleton for Three-wire UART (H5) support This patch adds the initial skeleton for Three-wire UART (H5) support and hooks it up to the HCI UART framework. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/Kconfig | 12 ++++++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_h5.c | 88 +++++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 +++ drivers/bluetooth/hci_uart.h | 5 +++ 5 files changed, 112 insertions(+) create mode 100644 drivers/bluetooth/hci_h5.c (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 5ccf142..e9f203e 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -81,6 +81,18 @@ config BT_HCIUART_LL Say Y here to compile support for HCILL protocol. +config BT_HCIUART_3WIRE + bool "Three-wire UART (H5) protocol support" + depends on BT_HCIUART + help + The HCI Three-wire UART Transport Layer makes it possible to + user the Bluetooth HCI over a serial port interface. The HCI + Three-wire UART Transport Layer assumes that the UART + communication may have bit errors, overrun errors or burst + errors and thereby making CTS/RTS lines unnecessary. + + Say Y here to compile support for Three-wire UART protocol. + config BT_HCIBCM203X tristate "HCI BCM203x USB driver" depends on USB diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index f4460f4..4afae20 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -28,4 +28,5 @@ hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o +hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o hci_uart-objs := $(hci_uart-y) diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c new file mode 100644 index 0000000..6353d00 --- /dev/null +++ b/drivers/bluetooth/hci_h5.c @@ -0,0 +1,88 @@ +/* + * + * Bluetooth HCI Three-wire UART driver + * + * Copyright (C) 2012 Intel Corporation + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include + +#include +#include + +#include "hci_uart.h" + +static int h5_open(struct hci_uart *hu) +{ + return -ENOSYS; +} + +static int h5_close(struct hci_uart *hu) +{ + return -ENOSYS; +} + +static int h5_recv(struct hci_uart *hu, void *data, int count) +{ + return -ENOSYS; +} + +static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb) +{ + return -ENOSYS; +} + +static struct sk_buff *h5_dequeue(struct hci_uart *hu) +{ + return NULL; +} + +static int h5_flush(struct hci_uart *hu) +{ + return -ENOSYS; +} + +static struct hci_uart_proto h5p = { + .id = HCI_UART_3WIRE, + .open = h5_open, + .close = h5_close, + .recv = h5_recv, + .enqueue = h5_enqueue, + .dequeue = h5_dequeue, + .flush = h5_flush, +}; + +int __init h5_init(void) +{ + int err = hci_uart_register_proto(&h5p); + + if (!err) + BT_INFO("HCI Three-wire UART (H5) protocol initialized"); + else + BT_ERR("HCI Three-wire UART (H5) protocol init failed"); + + return err; +} + +int __exit h5_deinit(void) +{ + return hci_uart_unregister_proto(&h5p); +} diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 2f9b796..142f49c 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -558,6 +558,9 @@ static int __init hci_uart_init(void) #ifdef CONFIG_BT_HCIUART_ATH3K ath_init(); #endif +#ifdef CONFIG_BT_HCIUART_3WIRE + h5_init(); +#endif return 0; } @@ -578,6 +581,9 @@ static void __exit hci_uart_exit(void) #ifdef CONFIG_BT_HCIUART_ATH3K ath_deinit(); #endif +#ifdef CONFIG_BT_HCIUART_3WIRE + h5_deinit(); +#endif /* Release tty registration of line discipline */ if ((err = tty_unregister_ldisc(N_HCI))) diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 6cf6ab22..aaf9d7d 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -104,3 +104,8 @@ int ll_deinit(void); int ath_init(void); int ath_deinit(void); #endif + +#ifdef CONFIG_BT_HCIUART_3WIRE +int h5_init(void); +int h5_deinit(void); +#endif -- cgit v1.1 From 7d664fbafaf992e501159c013b4264a03ee1efac Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:03 +0300 Subject: 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 Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 96 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 4 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 6353d00..6b7ec64 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -30,14 +30,48 @@ #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) { - 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) { - 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) @@ -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) { - 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) { + 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; } static int h5_flush(struct hci_uart *hu) { - return -ENOSYS; + BT_DBG("hu %p", hu); + return 0; } static struct hci_uart_proto h5p = { -- cgit v1.1 From 3f27e95b83d08a58aadef42f332b1d1d50101cb6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:04 +0300 Subject: Bluetooth: Add initial reliable packet support for Three-wire UART This patch adds initial support for reliable packets along with the necessary retransmission timer for the Three-wire UART HCI driver. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 6b7ec64..ae1bd32 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -30,6 +30,10 @@ #include "hci_uart.h" +#define H5_TXWINSIZE 4 + +#define H5_ACK_TIMEOUT msecs_to_jiffies(250) + struct h5 { struct sk_buff_head unack; /* Unack'ed packets queue */ struct sk_buff_head rel; /* Reliable packets queue */ @@ -37,11 +41,34 @@ struct h5 { struct sk_buff *rx_skb; + struct timer_list timer; /* Retransmission timer */ + bool txack_req; u8 msgq_txseq; }; +static void h5_timed_event(unsigned long arg) +{ + struct hci_uart *hu = (struct hci_uart *) arg; + struct h5 *h5 = hu->priv; + struct sk_buff *skb; + unsigned long flags; + + BT_DBG("hu %p retransmitting %u pkts", hu, h5->unack.qlen); + + spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); + + while ((skb = __skb_dequeue_tail(&h5->unack)) != NULL) { + h5->msgq_txseq = (h5->msgq_txseq - 1) & 0x07; + skb_queue_head(&h5->rel, skb); + } + + spin_unlock_irqrestore(&h5->unack.lock, flags); + + hci_uart_tx_wakeup(hu); +} + static int h5_open(struct hci_uart *hu) { struct h5 *h5; @@ -58,6 +85,10 @@ static int h5_open(struct hci_uart *hu) skb_queue_head_init(&h5->rel); skb_queue_head_init(&h5->unrel); + init_timer(&h5->timer); + h5->timer.function = h5_timed_event; + h5->timer.data = (unsigned long) hu; + return 0; } @@ -69,6 +100,8 @@ static int h5_close(struct hci_uart *hu) skb_queue_purge(&h5->rel); skb_queue_purge(&h5->unrel); + del_timer(&h5->timer); + kfree(h5); return 0; @@ -123,6 +156,7 @@ static struct sk_buff *h5_prepare_ack(struct h5 *h5) static struct sk_buff *h5_dequeue(struct hci_uart *hu) { struct h5 *h5 = hu->priv; + unsigned long flags; struct sk_buff *skb, *nskb; if ((skb = skb_dequeue(&h5->unrel)) != NULL) { @@ -136,6 +170,28 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu) BT_ERR("Could not dequeue pkt because alloc_skb failed"); } + spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); + + if (h5->unack.qlen >= H5_TXWINSIZE) + goto unlock; + + if ((skb = skb_dequeue(&h5->rel)) != NULL) { + nskb = h5_prepare_pkt(h5, skb); + + if (nskb) { + __skb_queue_tail(&h5->unack, skb); + mod_timer(&h5->timer, jiffies + H5_ACK_TIMEOUT); + spin_unlock_irqrestore(&h5->unack.lock, flags); + return nskb; + } + + skb_queue_head(&h5->rel, skb); + BT_ERR("Could not dequeue pkt because alloc_skb failed"); + } + +unlock: + spin_unlock_irqrestore(&h5->unack.lock, flags); + if (h5->txack_req) return h5_prepare_ack(h5); -- cgit v1.1 From bc1f35b9113275433021592954f54576ba587899 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:05 +0300 Subject: Bluetooth: Add basic packet parsing to Three-wire UART driver This patch adds basic packet parsing to the Three-wire UART HCI driver for packets received from the controller. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 230 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 222 insertions(+), 8 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index ae1bd32..ddf7ebb 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -34,20 +34,37 @@ #define H5_ACK_TIMEOUT msecs_to_jiffies(250) +/* + * Maximum Three-wire packet: + * 4 byte header + max value for 12-bit length + 2 bytes for CRC + */ +#define H5_MAX_LEN (4 + 0xfff + 2) + +#define SLIP_DELIMITER 0xc0 +#define SLIP_ESC 0xdb +#define SLIP_ESC_DELIM 0xdc +#define SLIP_ESC_ESC 0xdd + 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_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; + struct sk_buff *rx_skb; /* Receive buffer */ + size_t rx_pending; /* Expecting more bytes */ + bool rx_esc; /* SLIP escape mode */ - struct timer_list timer; /* Retransmission timer */ + int (*rx_func) (struct hci_uart *hu, u8 c); - bool txack_req; + struct timer_list timer; /* Retransmission timer */ - u8 msgq_txseq; + bool txack_req; + + u8 msgq_txseq; }; +static void h5_reset_rx(struct h5 *h5); + static void h5_timed_event(unsigned long arg) { struct hci_uart *hu = (struct hci_uart *) arg; @@ -85,6 +102,8 @@ static int h5_open(struct hci_uart *hu) skb_queue_head_init(&h5->rel); skb_queue_head_init(&h5->unrel); + h5_reset_rx(h5); + init_timer(&h5->timer); h5->timer.function = h5_timed_event; h5->timer.data = (unsigned long) hu; @@ -107,9 +126,204 @@ static int h5_close(struct hci_uart *hu) return 0; } +static void h5_handle_internal_rx(struct hci_uart *hu) +{ + BT_DBG("%s", hu->hdev->name); +} + +static void h5_complete_rx_pkt(struct hci_uart *hu) +{ + struct h5 *h5 = hu->priv; + u8 pkt_type; + + BT_DBG("%s", hu->hdev->name); + + pkt_type = h5->rx_skb->data[1] & 0x0f; + + switch (pkt_type) { + case HCI_EVENT_PKT: + case HCI_ACLDATA_PKT: + case HCI_SCODATA_PKT: + bt_cb(h5->rx_skb)->pkt_type = pkt_type; + + /* Remove Three-wire header */ + skb_pull(h5->rx_skb, 4); + + hci_recv_frame(h5->rx_skb); + h5->rx_skb = NULL; + + break; + + default: + h5_handle_internal_rx(hu); + break; + } + + h5_reset_rx(h5); +} + +static int h5_rx_crc(struct hci_uart *hu, unsigned char c) +{ + struct h5 *h5 = hu->priv; + + BT_DBG("%s 0x%02hhx", hu->hdev->name, c); + + h5_complete_rx_pkt(hu); + h5_reset_rx(h5); + + return 0; +} + +static int h5_rx_payload(struct hci_uart *hu, unsigned char c) +{ + struct h5 *h5 = hu->priv; + const unsigned char *hdr = h5->rx_skb->data; + + BT_DBG("%s 0x%02hhx", hu->hdev->name, c); + + if ((hdr[0] >> 4) & 0x01) { + h5->rx_func = h5_rx_crc; + h5->rx_pending = 2; + } else { + h5_complete_rx_pkt(hu); + h5_reset_rx(h5); + } + + return 0; +} + +static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c) +{ + struct h5 *h5 = hu->priv; + const unsigned char *hdr = h5->rx_skb->data; + + BT_DBG("%s 0x%02hhx", hu->hdev->name, c); + + if (((hdr[0] + hdr[1] + hdr[2] + hdr[3]) & 0xff) != 0xff) { + BT_ERR("Invalid header checksum"); + h5_reset_rx(h5); + return 0; + } + + h5->rx_func = h5_rx_payload; + h5->rx_pending = ((hdr[1] >> 4) & 0xff) + (hdr[2] << 4); + + return 0; +} + +static int h5_rx_pkt_start(struct hci_uart *hu, unsigned char c) +{ + struct h5 *h5 = hu->priv; + + BT_DBG("%s 0x%02hhx", hu->hdev->name, c); + + if (c == SLIP_DELIMITER) + return 1; + + h5->rx_func = h5_rx_3wire_hdr; + h5->rx_pending = 4; + + h5->rx_skb = bt_skb_alloc(H5_MAX_LEN, GFP_ATOMIC); + if (!h5->rx_skb) { + BT_ERR("Can't allocate mem for new packet"); + h5_reset_rx(h5); + return -ENOMEM; + } + + h5->rx_skb->dev = (void *) hu->hdev; + + return 0; +} + +static int h5_rx_delimiter(struct hci_uart *hu, unsigned char c) +{ + struct h5 *h5 = hu->priv; + + BT_DBG("%s 0x%02hhx", hu->hdev->name, c); + + if (c == SLIP_DELIMITER) + h5->rx_func = h5_rx_pkt_start; + + return 1; +} + +static void h5_unslip_one_byte(struct h5 *h5, unsigned char c) +{ + const u8 delim = SLIP_DELIMITER, esc = SLIP_ESC; + const u8 *byte = &c; + + if (!h5->rx_esc && c == SLIP_ESC) { + h5->rx_esc = true; + return; + } + + if (h5->rx_esc) { + switch (c) { + case SLIP_ESC_DELIM: + byte = &delim; + break; + case SLIP_ESC_ESC: + byte = &esc; + break; + default: + BT_ERR("Invalid esc byte 0x%02hhx", c); + h5_reset_rx(h5); + return; + } + + h5->rx_esc = false; + } + + memcpy(skb_put(h5->rx_skb, 1), byte, 1); + h5->rx_pending--; + + BT_DBG("unsliped 0x%02hhx", *byte); +} + +static void h5_reset_rx(struct h5 *h5) +{ + if (h5->rx_skb) { + kfree_skb(h5->rx_skb); + h5->rx_skb = NULL; + } + + h5->rx_func = h5_rx_delimiter; + h5->rx_pending = 0; + h5->rx_esc = false; +} + static int h5_recv(struct hci_uart *hu, void *data, int count) { - return -ENOSYS; + struct h5 *h5 = hu->priv; + unsigned char *ptr = data; + + BT_DBG("%s count %d", hu->hdev->name, count); + + while (count > 0) { + int processed; + + if (h5->rx_pending > 0) { + if (*ptr == SLIP_DELIMITER) { + BT_ERR("Too short H5 packet"); + h5_reset_rx(h5); + continue; + } + + h5_unslip_one_byte(h5, *ptr); + + ptr++; count--; + continue; + } + + processed = h5->rx_func(hu, *ptr); + if (processed < 0) + return processed; + + ptr += processed; + count -= processed; + } + + return 0; } static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb) -- cgit v1.1 From c0a1b73c3f7d0cf3a93b58507b411911659d1b6a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:06 +0300 Subject: Bluetooth: Add initial packet sending support to Three-wire UART This patch adds initial packed encoding and sending support to the Three-wire UART HCI transport driver. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 105 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 7 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index ddf7ebb..6df4c07 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -30,6 +30,9 @@ #include "hci_uart.h" +#define HCI_3WIRE_ACK_PKT 0 +#define HCI_3WIRE_LINK_PKT 15 + #define H5_TXWINSIZE 4 #define H5_ACK_TIMEOUT msecs_to_jiffies(250) @@ -60,7 +63,8 @@ struct h5 { bool txack_req; - u8 msgq_txseq; + u8 next_ack; + u8 next_seq; }; static void h5_reset_rx(struct h5 *h5); @@ -77,7 +81,7 @@ static void h5_timed_event(unsigned long arg) spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); while ((skb = __skb_dequeue_tail(&h5->unack)) != NULL) { - h5->msgq_txseq = (h5->msgq_txseq - 1) & 0x07; + h5->next_seq = (h5->next_seq - 1) & 0x07; skb_queue_head(&h5->rel, skb); } @@ -355,10 +359,96 @@ static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb) return 0; } -static struct sk_buff *h5_prepare_pkt(struct h5 *h5, struct sk_buff *skb) +static void h5_slip_delim(struct sk_buff *skb) +{ + const char delim = SLIP_DELIMITER; + + memcpy(skb_put(skb, 1), &delim, 1); +} + +static void h5_slip_one_byte(struct sk_buff *skb, u8 c) +{ + const char esc_delim[2] = { SLIP_ESC, SLIP_ESC_DELIM }; + const char esc_esc[2] = { SLIP_ESC, SLIP_ESC_ESC }; + + switch (c) { + case SLIP_DELIMITER: + memcpy(skb_put(skb, 2), &esc_delim, 2); + break; + case SLIP_ESC: + memcpy(skb_put(skb, 2), &esc_esc, 2); + break; + default: + memcpy(skb_put(skb, 1), &c, 1); + } +} + +static struct sk_buff *h5_build_pkt(struct h5 *h5, bool rel, u8 pkt_type, + const u8 *data, size_t len) { + struct sk_buff *nskb; + u8 hdr[4]; + int i; + + /* + * Max len of packet: (original len + 4 (H5 hdr) + 2 (crc)) * 2 + * (because bytes 0xc0 and 0xdb are escaped, worst case is when + * the packet is all made of 0xc0 and 0xdb) + 2 (0xc0 + * delimiters at start and end). + */ + nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC); + if (!nskb) + return NULL; + + bt_cb(nskb)->pkt_type = pkt_type; + + h5_slip_delim(nskb); + + hdr[0] = h5->next_ack << 3; h5->txack_req = false; - return NULL; + + if (rel) { + hdr[0] |= 1 << 7; + hdr[0] |= h5->next_seq; + h5->next_seq = (h5->next_seq + 1) % 8; + } + + hdr[1] = pkt_type | ((len & 0x0f) << 4); + hdr[2] = len >> 4; + hdr[3] = ~((hdr[0] + hdr[1] + hdr[2]) & 0xff); + + for (i = 0; i < 4; i++) + h5_slip_one_byte(nskb, hdr[i]); + + for (i = 0; i < len; i++) + h5_slip_one_byte(nskb, data[i]); + + h5_slip_delim(nskb); + + return nskb; +} + +static struct sk_buff *h5_prepare_pkt(struct h5 *h5, u8 pkt_type, + const u8 *data, size_t len) +{ + bool rel; + + switch (pkt_type) { + case HCI_ACLDATA_PKT: + case HCI_COMMAND_PKT: + rel = true; + break; + case HCI_SCODATA_PKT: + case HCI_3WIRE_LINK_PKT: + case HCI_3WIRE_ACK_PKT: + rel = false; + break; + default: + BT_ERR("Unknown packet type %u", pkt_type); + return NULL; + } + + return h5_build_pkt(h5, rel, pkt_type, data, len); } static struct sk_buff *h5_prepare_ack(struct h5 *h5) @@ -374,7 +464,8 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu) struct sk_buff *skb, *nskb; if ((skb = skb_dequeue(&h5->unrel)) != NULL) { - nskb = h5_prepare_pkt(h5, skb); + nskb = h5_prepare_pkt(h5, bt_cb(skb)->pkt_type, + skb->data, skb->len); if (nskb) { kfree_skb(skb); return nskb; @@ -390,8 +481,8 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu) goto unlock; if ((skb = skb_dequeue(&h5->rel)) != NULL) { - nskb = h5_prepare_pkt(h5, skb); - + nskb = h5_prepare_pkt(h5, bt_cb(skb)->pkt_type, + skb->data, skb->len); if (nskb) { __skb_queue_tail(&h5->unack, skb); mod_timer(&h5->timer, jiffies + H5_ACK_TIMEOUT); -- cgit v1.1 From 01977c0bbbc834e57436be0bab31c3df11d61710 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:07 +0300 Subject: Bluetooth: Add Three-wire header value convenience macros This patch adds convenience macros for reading Three-wire header values. This will help make the code more readable. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 6df4c07..f50afb2 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -43,6 +43,14 @@ */ #define H5_MAX_LEN (4 + 0xfff + 2) +/* Convenience macros for reading Three-wire header values */ +#define H5_HDR_SEQ(hdr) ((hdr)[0] & 0x07) +#define H5_HDR_ACK(hdr) (((hdr)[0] >> 3) & 0x07) +#define H5_HDR_CRC(hdr) (((hdr)[0] >> 6) & 0x01) +#define H5_HDR_RELIABLE(hdr) (((hdr)[0] >> 7) & 0x01) +#define H5_HDR_PKT_TYPE(hdr) ((hdr)[1] & 0x0f) +#define H5_HDR_LEN(hdr) ((((hdr)[1] >> 4) & 0xff) + ((hdr)[2] << 4)) + #define SLIP_DELIMITER 0xc0 #define SLIP_ESC 0xdb #define SLIP_ESC_DELIM 0xdc -- cgit v1.1 From 43eb12d7896063d06011baab7097944a70c7e45a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:08 +0300 Subject: Bluetooth: Fix/implement Three-wire reliable packet sending This patch should complete the necessary code for sending reliable Three-wire packets. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 87 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 17 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index f50afb2..6c7b27e 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -64,15 +64,15 @@ struct h5 { struct sk_buff *rx_skb; /* Receive buffer */ size_t rx_pending; /* Expecting more bytes */ bool rx_esc; /* SLIP escape mode */ + u8 rx_ack; /* Last ack number received */ + u8 rx_seq; /* Last seq number received */ int (*rx_func) (struct hci_uart *hu, u8 c); struct timer_list timer; /* Retransmission timer */ - bool txack_req; - - u8 next_ack; - u8 next_seq; + bool tx_ack_req; /* Pending ack to send */ + u8 tx_seq; /* Next seq number to send */ }; static void h5_reset_rx(struct h5 *h5); @@ -89,7 +89,7 @@ static void h5_timed_event(unsigned long arg) spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); while ((skb = __skb_dequeue_tail(&h5->unack)) != NULL) { - h5->next_seq = (h5->next_seq - 1) & 0x07; + h5->tx_seq = (h5->tx_seq - 1) & 0x07; skb_queue_head(&h5->rel, skb); } @@ -138,6 +138,45 @@ static int h5_close(struct hci_uart *hu) return 0; } +static void h5_pkt_cull(struct h5 *h5) +{ + struct sk_buff *skb, *tmp; + unsigned long flags; + int i, to_remove; + u8 seq; + + spin_lock_irqsave(&h5->unack.lock, flags); + + to_remove = skb_queue_len(&h5->unack); + + seq = h5->tx_seq; + + while (to_remove > 0) { + if (h5->rx_ack == seq) + break; + + to_remove--; + seq = (seq - 1) % 8; + } + + if (seq != h5->rx_ack) + BT_ERR("Controller acked invalid packet"); + + i = 0; + skb_queue_walk_safe(&h5->unack, skb, tmp) { + if (i++ >= to_remove) + break; + + __skb_unlink(skb, &h5->unack); + kfree_skb(skb); + } + + if (skb_queue_empty(&h5->unack)) + del_timer(&h5->timer); + + spin_unlock_irqrestore(&h5->unack.lock, flags); +} + static void h5_handle_internal_rx(struct hci_uart *hu) { BT_DBG("%s", hu->hdev->name); @@ -146,17 +185,24 @@ static void h5_handle_internal_rx(struct hci_uart *hu) static void h5_complete_rx_pkt(struct hci_uart *hu) { struct h5 *h5 = hu->priv; - u8 pkt_type; + const unsigned char *hdr = h5->rx_skb->data; BT_DBG("%s", hu->hdev->name); - pkt_type = h5->rx_skb->data[1] & 0x0f; + if (H5_HDR_RELIABLE(hdr)) { + h5->tx_seq = (h5->tx_seq + 1) % 8; + h5->tx_ack_req = true; + } - switch (pkt_type) { + h5->rx_ack = H5_HDR_ACK(hdr); + + h5_pkt_cull(h5); + + switch (H5_HDR_PKT_TYPE(hdr)) { case HCI_EVENT_PKT: case HCI_ACLDATA_PKT: case HCI_SCODATA_PKT: - bt_cb(h5->rx_skb)->pkt_type = pkt_type; + bt_cb(h5->rx_skb)->pkt_type = H5_HDR_PKT_TYPE(hdr); /* Remove Three-wire header */ skb_pull(h5->rx_skb, 4); @@ -193,7 +239,7 @@ static int h5_rx_payload(struct hci_uart *hu, unsigned char c) BT_DBG("%s 0x%02hhx", hu->hdev->name, c); - if ((hdr[0] >> 4) & 0x01) { + if (H5_HDR_CRC(hdr)) { h5->rx_func = h5_rx_crc; h5->rx_pending = 2; } else { @@ -217,8 +263,15 @@ static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c) return 0; } + if (H5_HDR_RELIABLE(hdr) && H5_HDR_SEQ(hdr) != h5->tx_seq) { + BT_ERR("Out-of-order packet arrived (%u != %u)", + H5_HDR_SEQ(hdr), h5->tx_seq); + h5_reset_rx(h5); + return 0; + } + h5->rx_func = h5_rx_payload; - h5->rx_pending = ((hdr[1] >> 4) & 0xff) + (hdr[2] << 4); + h5->rx_pending = H5_HDR_LEN(hdr); return 0; } @@ -412,13 +465,13 @@ static struct sk_buff *h5_build_pkt(struct h5 *h5, bool rel, u8 pkt_type, h5_slip_delim(nskb); - hdr[0] = h5->next_ack << 3; - h5->txack_req = false; + hdr[0] = h5->rx_seq << 3; + h5->tx_ack_req = false; if (rel) { hdr[0] |= 1 << 7; - hdr[0] |= h5->next_seq; - h5->next_seq = (h5->next_seq + 1) % 8; + hdr[0] |= h5->tx_seq; + h5->tx_seq = (h5->tx_seq + 1) % 8; } hdr[1] = pkt_type | ((len & 0x0f) << 4); @@ -461,7 +514,7 @@ static struct sk_buff *h5_prepare_pkt(struct h5 *h5, u8 pkt_type, static struct sk_buff *h5_prepare_ack(struct h5 *h5) { - h5->txack_req = false; + h5->tx_ack_req = false; return NULL; } @@ -505,7 +558,7 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu) unlock: spin_unlock_irqrestore(&h5->unack.lock, flags); - if (h5->txack_req) + if (h5->tx_ack_req) return h5_prepare_ack(h5); return NULL; -- cgit v1.1 From 40f10224df6f00b59ab342e3d9d9ac8b50c8eada Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:09 +0300 Subject: Bluetooth: Add support for Three-wire Link Control packets This patch adds basic support for parsing and sending Three-wire UART Link Control packets. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 96 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 17 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 6c7b27e..022a6bc 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -36,6 +36,7 @@ #define H5_TXWINSIZE 4 #define H5_ACK_TIMEOUT msecs_to_jiffies(250) +#define H5_SYNC_TIMEOUT msecs_to_jiffies(100) /* * Maximum Three-wire packet: @@ -65,7 +66,6 @@ struct h5 { size_t rx_pending; /* Expecting more bytes */ bool rx_esc; /* SLIP escape mode */ u8 rx_ack; /* Last ack number received */ - u8 rx_seq; /* Last seq number received */ int (*rx_func) (struct hci_uart *hu, u8 c); @@ -73,6 +73,7 @@ struct h5 { bool tx_ack_req; /* Pending ack to send */ u8 tx_seq; /* Next seq number to send */ + u8 tx_ack; /* Next ack number to send */ }; static void h5_reset_rx(struct h5 *h5); @@ -98,9 +99,26 @@ static void h5_timed_event(unsigned long arg) hci_uart_tx_wakeup(hu); } +static void h5_link_control(struct hci_uart *hu, const void *data, size_t len) +{ + struct h5 *h5 = hu->priv; + struct sk_buff *nskb; + + nskb = alloc_skb(3, GFP_ATOMIC); + if (!nskb) + return; + + bt_cb(nskb)->pkt_type = HCI_3WIRE_LINK_PKT; + + memcpy(skb_put(nskb, len), data, len); + + skb_queue_tail(&h5->unrel, nskb); +} + static int h5_open(struct hci_uart *hu) { struct h5 *h5; + const unsigned char sync[] = { 0x01, 0x7e }; BT_DBG("hu %p", hu); @@ -120,6 +138,10 @@ static int h5_open(struct hci_uart *hu) h5->timer.function = h5_timed_event; h5->timer.data = (unsigned long) hu; + /* Send initial sync request */ + h5_link_control(hu, sync, sizeof(sync)); + mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT); + return 0; } @@ -148,6 +170,8 @@ static void h5_pkt_cull(struct h5 *h5) spin_lock_irqsave(&h5->unack.lock, flags); to_remove = skb_queue_len(&h5->unack); + if (to_remove == 0) + goto unlock; seq = h5->tx_seq; @@ -174,12 +198,44 @@ static void h5_pkt_cull(struct h5 *h5) if (skb_queue_empty(&h5->unack)) del_timer(&h5->timer); +unlock: spin_unlock_irqrestore(&h5->unack.lock, flags); } static void h5_handle_internal_rx(struct hci_uart *hu) { + struct h5 *h5 = hu->priv; + const unsigned char sync_req[] = { 0x01, 0x7e }; + const unsigned char sync_rsp[] = { 0x02, 0x7d }; + const unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; + const unsigned char conf_rsp[] = { 0x04, 0x7b, 0x01 }; + const unsigned char *hdr = h5->rx_skb->data; + const unsigned char *data = &h5->rx_skb->data[4]; + BT_DBG("%s", hu->hdev->name); + + if (H5_HDR_PKT_TYPE(hdr) != HCI_3WIRE_LINK_PKT) + return; + + if (H5_HDR_LEN(hdr) < 2) + return; + + if (memcmp(data, sync_req, 2) == 0) { + h5_link_control(hu, sync_rsp, 2); + } else if (memcmp(data, sync_rsp, 2) == 0) { + h5_link_control(hu, conf_req, 3); + } else if (memcmp(data, conf_req, 2) == 0) { + h5_link_control(hu, conf_rsp, 2); + h5_link_control(hu, conf_req, 3); + } else if (memcmp(data, conf_rsp, 2) == 0) { + BT_DBG("Three-wire init sequence complete"); + return; + } else { + BT_DBG("Link Control: 0x%02hhx 0x%02hhx", data[0], data[1]); + return; + } + + hci_uart_tx_wakeup(hu); } static void h5_complete_rx_pkt(struct hci_uart *hu) @@ -190,8 +246,9 @@ static void h5_complete_rx_pkt(struct hci_uart *hu) BT_DBG("%s", hu->hdev->name); if (H5_HDR_RELIABLE(hdr)) { - h5->tx_seq = (h5->tx_seq + 1) % 8; + h5->tx_ack = (h5->tx_ack + 1) % 8; h5->tx_ack_req = true; + hci_uart_tx_wakeup(hu); } h5->rx_ack = H5_HDR_ACK(hdr); @@ -257,15 +314,20 @@ static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c) BT_DBG("%s 0x%02hhx", hu->hdev->name, c); + BT_DBG("%s rx: seq %u ack %u crc %u rel %u type %u len %u", + hu->hdev->name, H5_HDR_SEQ(hdr), H5_HDR_ACK(hdr), + H5_HDR_CRC(hdr), H5_HDR_RELIABLE(hdr), H5_HDR_PKT_TYPE(hdr), + H5_HDR_LEN(hdr)); + if (((hdr[0] + hdr[1] + hdr[2] + hdr[3]) & 0xff) != 0xff) { BT_ERR("Invalid header checksum"); h5_reset_rx(h5); return 0; } - if (H5_HDR_RELIABLE(hdr) && H5_HDR_SEQ(hdr) != h5->tx_seq) { + if (H5_HDR_RELIABLE(hdr) && H5_HDR_SEQ(hdr) != h5->tx_ack) { BT_ERR("Out-of-order packet arrived (%u != %u)", - H5_HDR_SEQ(hdr), h5->tx_seq); + H5_HDR_SEQ(hdr), h5->tx_ack); h5_reset_rx(h5); return 0; } @@ -444,9 +506,10 @@ static void h5_slip_one_byte(struct sk_buff *skb, u8 c) } } -static struct sk_buff *h5_build_pkt(struct h5 *h5, bool rel, u8 pkt_type, +static struct sk_buff *h5_build_pkt(struct hci_uart *hu, bool rel, u8 pkt_type, const u8 *data, size_t len) { + struct h5 *h5 = hu->priv; struct sk_buff *nskb; u8 hdr[4]; int i; @@ -465,7 +528,7 @@ static struct sk_buff *h5_build_pkt(struct h5 *h5, bool rel, u8 pkt_type, h5_slip_delim(nskb); - hdr[0] = h5->rx_seq << 3; + hdr[0] = h5->tx_ack << 3; h5->tx_ack_req = false; if (rel) { @@ -478,6 +541,11 @@ static struct sk_buff *h5_build_pkt(struct h5 *h5, bool rel, u8 pkt_type, hdr[2] = len >> 4; hdr[3] = ~((hdr[0] + hdr[1] + hdr[2]) & 0xff); + BT_DBG("%s tx: seq %u ack %u crc %u rel %u type %u len %u", + hu->hdev->name, H5_HDR_SEQ(hdr), H5_HDR_ACK(hdr), + H5_HDR_CRC(hdr), H5_HDR_RELIABLE(hdr), H5_HDR_PKT_TYPE(hdr), + H5_HDR_LEN(hdr)); + for (i = 0; i < 4; i++) h5_slip_one_byte(nskb, hdr[i]); @@ -489,7 +557,7 @@ static struct sk_buff *h5_build_pkt(struct h5 *h5, bool rel, u8 pkt_type, return nskb; } -static struct sk_buff *h5_prepare_pkt(struct h5 *h5, u8 pkt_type, +static struct sk_buff *h5_prepare_pkt(struct hci_uart *hu, u8 pkt_type, const u8 *data, size_t len) { bool rel; @@ -509,13 +577,7 @@ static struct sk_buff *h5_prepare_pkt(struct h5 *h5, u8 pkt_type, return NULL; } - return h5_build_pkt(h5, rel, pkt_type, data, len); -} - -static struct sk_buff *h5_prepare_ack(struct h5 *h5) -{ - h5->tx_ack_req = false; - return NULL; + return h5_build_pkt(hu, rel, pkt_type, data, len); } static struct sk_buff *h5_dequeue(struct hci_uart *hu) @@ -525,7 +587,7 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu) struct sk_buff *skb, *nskb; if ((skb = skb_dequeue(&h5->unrel)) != NULL) { - nskb = h5_prepare_pkt(h5, bt_cb(skb)->pkt_type, + nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type, skb->data, skb->len); if (nskb) { kfree_skb(skb); @@ -542,7 +604,7 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu) goto unlock; if ((skb = skb_dequeue(&h5->rel)) != NULL) { - nskb = h5_prepare_pkt(h5, bt_cb(skb)->pkt_type, + nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type, skb->data, skb->len); if (nskb) { __skb_queue_tail(&h5->unack, skb); @@ -559,7 +621,7 @@ unlock: spin_unlock_irqrestore(&h5->unack.lock, flags); if (h5->tx_ack_req) - return h5_prepare_ack(h5); + return h5_prepare_pkt(hu, HCI_3WIRE_ACK_PKT, NULL, 0); return NULL; } -- cgit v1.1 From dac670b97698f7c5584b224dd68d9d612b9ad4d7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:10 +0300 Subject: Bluetooth: Simplify hci_uart_tty_close logic This patch cleans up and reduces indentation in the hci_uart_tty_close function. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_ldisc.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 142f49c..b6d1f20 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -286,28 +286,29 @@ static int hci_uart_tty_open(struct tty_struct *tty) static void hci_uart_tty_close(struct tty_struct *tty) { struct hci_uart *hu = (void *)tty->disc_data; + struct hci_dev *hdev; BT_DBG("tty %p", tty); /* Detach from the tty */ tty->disc_data = NULL; - if (hu) { - struct hci_dev *hdev = hu->hdev; + if (!hu) + return; - if (hdev) - hci_uart_close(hdev); + hdev = hu->hdev; + if (hdev) + hci_uart_close(hdev); - if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { - if (hdev) { - hci_unregister_dev(hdev); - hci_free_dev(hdev); - } - hu->proto->close(hu); + if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { + if (hdev) { + hci_unregister_dev(hdev); + hci_free_dev(hdev); } - - kfree(hu); + hu->proto->close(hu); } + + kfree(hu); } /* hci_uart_tty_wakeup() -- cgit v1.1 From 9f2aee848fe60325b1984653833d2d1825ec730d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:11 +0300 Subject: Bluetooth: Add delayed init sequence support for UART controllers This patch makes it possible to have UART drivers perform an internal initialization before calling hci_register_dev. This allows moving a lot of init code from user space (hciattach) to the kernel side, thereby creating a more controlled/robust initialization process. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_ldisc.c | 39 ++++++++++++++++++++++++++++++++++++++- drivers/bluetooth/hci_uart.h | 5 +++++ 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index b6d1f20..74e0966 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -156,6 +156,35 @@ restart: return 0; } +static void hci_uart_init_work(struct work_struct *work) +{ + struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); + int err; + + if (!test_and_clear_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) + return; + + err = hci_register_dev(hu->hdev); + if (err < 0) { + BT_ERR("Can't register HCI device"); + hci_free_dev(hu->hdev); + hu->hdev = NULL; + hu->proto->close(hu); + } + + set_bit(HCI_UART_REGISTERED, &hu->flags); +} + +int hci_uart_init_ready(struct hci_uart *hu) +{ + if (!test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) + return -EALREADY; + + schedule_work(&hu->init_ready); + + return 0; +} + /* ------- Interface to HCI layer ------ */ /* Initialize device */ static int hci_uart_open(struct hci_dev *hdev) @@ -264,6 +293,8 @@ static int hci_uart_tty_open(struct tty_struct *tty) hu->tty = tty; tty->receive_room = 65536; + INIT_WORK(&hu->init_ready, hci_uart_init_work); + spin_lock_init(&hu->rx_lock); /* Flush any pending characters in the driver and line discipline. */ @@ -302,7 +333,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { if (hdev) { - hci_unregister_dev(hdev); + if (test_bit(HCI_UART_REGISTERED, &hu->flags)) + hci_unregister_dev(hdev); hci_free_dev(hdev); } hu->proto->close(hu); @@ -402,12 +434,17 @@ static int hci_uart_register_dev(struct hci_uart *hu) else hdev->dev_type = HCI_BREDR; + if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) + return 0; + if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); hci_free_dev(hdev); return -ENODEV; } + set_bit(HCI_UART_REGISTERED, &hu->flags); + return 0; } diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index aaf9d7d..fffa61f 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -47,6 +47,7 @@ #define HCI_UART_RAW_DEVICE 0 #define HCI_UART_RESET_ON_INIT 1 #define HCI_UART_CREATE_AMP 2 +#define HCI_UART_INIT_PENDING 3 struct hci_uart; @@ -66,6 +67,8 @@ struct hci_uart { unsigned long flags; unsigned long hdev_flags; + struct work_struct init_ready; + struct hci_uart_proto *proto; void *priv; @@ -76,6 +79,7 @@ struct hci_uart { /* HCI_UART proto flag bits */ #define HCI_UART_PROTO_SET 0 +#define HCI_UART_REGISTERED 1 /* TX states */ #define HCI_UART_SENDING 1 @@ -84,6 +88,7 @@ struct hci_uart { int hci_uart_register_proto(struct hci_uart_proto *p); int hci_uart_unregister_proto(struct hci_uart_proto *p); int hci_uart_tx_wakeup(struct hci_uart *hu); +int hci_uart_init_ready(struct hci_uart *hu); #ifdef CONFIG_BT_HCIUART_H4 int h4_init(void); -- cgit v1.1 From cd1b44255c498d122220f5280c6cdbf7749c764b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:12 +0300 Subject: Bluetooth: Use delayed init for Three-wire UART This patch takes into use the delayed initialization feature that the Bluetooth UART framework provides. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 022a6bc..3c0e17b 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -138,6 +138,8 @@ static int h5_open(struct hci_uart *hu) h5->timer.function = h5_timed_event; h5->timer.data = (unsigned long) hu; + set_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags); + /* Send initial sync request */ h5_link_control(hu, sync, sizeof(sync)); mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT); @@ -229,6 +231,7 @@ static void h5_handle_internal_rx(struct hci_uart *hu) h5_link_control(hu, conf_req, 3); } else if (memcmp(data, conf_rsp, 2) == 0) { BT_DBG("Three-wire init sequence complete"); + hci_uart_init_ready(hu); return; } else { BT_DBG("Link Control: 0x%02hhx 0x%02hhx", data[0], data[1]); -- cgit v1.1 From 255a68e0124082396d5e6a073ae80f2c41d9c886 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:13 +0300 Subject: Bluetooth: Improve rx debug logs for Three-wire UART Remove unnecessary debug logs and add some to more centralized places. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 3c0e17b..eb40b9a 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -246,8 +246,6 @@ static void h5_complete_rx_pkt(struct hci_uart *hu) struct h5 *h5 = hu->priv; const unsigned char *hdr = h5->rx_skb->data; - BT_DBG("%s", hu->hdev->name); - if (H5_HDR_RELIABLE(hdr)) { h5->tx_ack = (h5->tx_ack + 1) % 8; h5->tx_ack_req = true; @@ -284,8 +282,6 @@ static int h5_rx_crc(struct hci_uart *hu, unsigned char c) { struct h5 *h5 = hu->priv; - BT_DBG("%s 0x%02hhx", hu->hdev->name, c); - h5_complete_rx_pkt(hu); h5_reset_rx(h5); @@ -297,8 +293,6 @@ static int h5_rx_payload(struct hci_uart *hu, unsigned char c) struct h5 *h5 = hu->priv; const unsigned char *hdr = h5->rx_skb->data; - BT_DBG("%s 0x%02hhx", hu->hdev->name, c); - if (H5_HDR_CRC(hdr)) { h5->rx_func = h5_rx_crc; h5->rx_pending = 2; @@ -315,8 +309,6 @@ static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c) struct h5 *h5 = hu->priv; const unsigned char *hdr = h5->rx_skb->data; - BT_DBG("%s 0x%02hhx", hu->hdev->name, c); - BT_DBG("%s rx: seq %u ack %u crc %u rel %u type %u len %u", hu->hdev->name, H5_HDR_SEQ(hdr), H5_HDR_ACK(hdr), H5_HDR_CRC(hdr), H5_HDR_RELIABLE(hdr), H5_HDR_PKT_TYPE(hdr), @@ -345,8 +337,6 @@ static int h5_rx_pkt_start(struct hci_uart *hu, unsigned char c) { struct h5 *h5 = hu->priv; - BT_DBG("%s 0x%02hhx", hu->hdev->name, c); - if (c == SLIP_DELIMITER) return 1; @@ -369,8 +359,6 @@ static int h5_rx_delimiter(struct hci_uart *hu, unsigned char c) { struct h5 *h5 = hu->priv; - BT_DBG("%s 0x%02hhx", hu->hdev->name, c); - if (c == SLIP_DELIMITER) h5->rx_func = h5_rx_pkt_start; @@ -407,7 +395,7 @@ static void h5_unslip_one_byte(struct h5 *h5, unsigned char c) memcpy(skb_put(h5->rx_skb, 1), byte, 1); h5->rx_pending--; - BT_DBG("unsliped 0x%02hhx", *byte); + BT_DBG("unsliped 0x%02hhx, rx_pending %zu", *byte, h5->rx_pending); } static void h5_reset_rx(struct h5 *h5) @@ -427,7 +415,8 @@ static int h5_recv(struct hci_uart *hu, void *data, int count) struct h5 *h5 = hu->priv; unsigned char *ptr = data; - BT_DBG("%s count %d", hu->hdev->name, count); + BT_DBG("%s pending %zu count %d", hu->hdev->name, h5->rx_pending, + count); while (count > 0) { int processed; -- cgit v1.1 From 10122d07ced378ec9187f4b3110e110282beb192 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:14 +0300 Subject: Bluetooth: Add initial sleep support to Three-wire UART This patch adds very basic support for the sleep related messages. The only thing the code does right now is send a wakeup message as soon as receiving a sleep one, essentially preventing the controller from going to sleep. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index eb40b9a..d9d42f6 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -74,6 +74,8 @@ struct h5 { bool tx_ack_req; /* Pending ack to send */ u8 tx_seq; /* Next seq number to send */ u8 tx_ack; /* Next ack number to send */ + + bool sleeping; }; static void h5_reset_rx(struct h5 *h5); @@ -211,6 +213,9 @@ static void h5_handle_internal_rx(struct hci_uart *hu) const unsigned char sync_rsp[] = { 0x02, 0x7d }; const unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; const unsigned char conf_rsp[] = { 0x04, 0x7b, 0x01 }; + const unsigned char wakeup_req[] = { 0x05, 0xfa }; + const unsigned char woken_req[] = { 0x06, 0xf9 }; + const unsigned char sleep_req[] = { 0x07, 0x78 }; const unsigned char *hdr = h5->rx_skb->data; const unsigned char *data = &h5->rx_skb->data[4]; @@ -233,6 +238,14 @@ static void h5_handle_internal_rx(struct hci_uart *hu) BT_DBG("Three-wire init sequence complete"); hci_uart_init_ready(hu); return; + } else if (memcmp(data, sleep_req, 2) == 0) { + BT_DBG("Peer went to sleep"); + h5->sleeping = true; + h5_link_control(hu, wakeup_req, 2); + } else if (memcmp(data, woken_req, 2) == 0) { + BT_DBG("Peer woke up"); + h5->sleeping = false; + return; } else { BT_DBG("Link Control: 0x%02hhx 0x%02hhx", data[0], data[1]); return; -- cgit v1.1 From f674a057c1f6b0fedf7d989c6dac0b482fef1b55 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:15 +0300 Subject: Bluetooth: Add initialization tracking to HCI Three-wire driver This patch adds tracking for the uninitialized, initialized and active states for Three-wire UART. This is needed so we can handle periodic sending of the Link Establishment messages before reaching active state and so that we do not try to do any higher level HCI data transmission before reaching active state. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 66 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 16 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index d9d42f6..6fb8d4e 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -75,18 +75,53 @@ struct h5 { u8 tx_seq; /* Next seq number to send */ u8 tx_ack; /* Next ack number to send */ + enum { + H5_UNINITIALIZED, + H5_INITIALIZED, + H5_ACTIVE, + } state; + bool sleeping; }; static void h5_reset_rx(struct h5 *h5); +static void h5_link_control(struct hci_uart *hu, const void *data, size_t len) +{ + struct h5 *h5 = hu->priv; + struct sk_buff *nskb; + + nskb = alloc_skb(3, GFP_ATOMIC); + if (!nskb) + return; + + bt_cb(nskb)->pkt_type = HCI_3WIRE_LINK_PKT; + + memcpy(skb_put(nskb, len), data, len); + + skb_queue_tail(&h5->unrel, nskb); +} + static void h5_timed_event(unsigned long arg) { + const unsigned char sync_req[] = { 0x01, 0x7e }; + const unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; struct hci_uart *hu = (struct hci_uart *) arg; struct h5 *h5 = hu->priv; struct sk_buff *skb; unsigned long flags; + if (h5->state == H5_UNINITIALIZED) + h5_link_control(hu, sync_req, sizeof(sync_req)); + + if (h5->state == H5_INITIALIZED) + h5_link_control(hu, conf_req, sizeof(conf_req)); + + if (h5->state != H5_ACTIVE) { + mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT); + goto wakeup; + } + BT_DBG("hu %p retransmitting %u pkts", hu, h5->unack.qlen); spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); @@ -98,25 +133,10 @@ static void h5_timed_event(unsigned long arg) spin_unlock_irqrestore(&h5->unack.lock, flags); +wakeup: hci_uart_tx_wakeup(hu); } -static void h5_link_control(struct hci_uart *hu, const void *data, size_t len) -{ - struct h5 *h5 = hu->priv; - struct sk_buff *nskb; - - nskb = alloc_skb(3, GFP_ATOMIC); - if (!nskb) - return; - - bt_cb(nskb)->pkt_type = HCI_3WIRE_LINK_PKT; - - memcpy(skb_put(nskb, len), data, len); - - skb_queue_tail(&h5->unrel, nskb); -} - static int h5_open(struct hci_uart *hu) { struct h5 *h5; @@ -230,12 +250,14 @@ static void h5_handle_internal_rx(struct hci_uart *hu) if (memcmp(data, sync_req, 2) == 0) { h5_link_control(hu, sync_rsp, 2); } else if (memcmp(data, sync_rsp, 2) == 0) { + h5->state = H5_INITIALIZED; h5_link_control(hu, conf_req, 3); } else if (memcmp(data, conf_req, 2) == 0) { h5_link_control(hu, conf_rsp, 2); h5_link_control(hu, conf_req, 3); } else if (memcmp(data, conf_rsp, 2) == 0) { BT_DBG("Three-wire init sequence complete"); + h5->state = H5_ACTIVE; hci_uart_init_ready(hu); return; } else if (memcmp(data, sleep_req, 2) == 0) { @@ -340,6 +362,12 @@ static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c) return 0; } + if (h5->state != H5_ACTIVE && + H5_HDR_PKT_TYPE(hdr) != HCI_3WIRE_LINK_PKT) { + BT_ERR("Non-link packet received in non-active state"); + h5_reset_rx(h5); + } + h5->rx_func = h5_rx_payload; h5->rx_pending = H5_HDR_LEN(hdr); @@ -468,6 +496,12 @@ static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb) return 0; } + if (h5->state != H5_ACTIVE) { + BT_ERR("Ignoring HCI data in non-active state"); + kfree_skb(skb); + return 0; + } + switch (bt_cb(skb)->pkt_type) { case HCI_ACLDATA_PKT: case HCI_COMMAND_PKT: -- cgit v1.1 From 95c5c22097433711de93bc377af89918c6140f77 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:16 +0300 Subject: Bluetooth: Implement proper low-power support for Three-wire UART This patch adds on-demand wakeup request sending (and re-sendind) when we are in low-power state. When the controller enters this state it will send a sleep message after which the host is not allowed to send any other packets until a wakeup request has been sent and the woken message received as a response to it. The wakeup requests are re-sent periodically until a woken message is received. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 6fb8d4e..8819ce8 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -81,7 +81,11 @@ struct h5 { H5_ACTIVE, } state; - bool sleeping; + enum { + H5_AWAKE, + H5_SLEEPING, + H5_WAKING_UP, + } sleep; }; static void h5_reset_rx(struct h5 *h5); @@ -111,6 +115,8 @@ static void h5_timed_event(unsigned long arg) struct sk_buff *skb; unsigned long flags; + BT_DBG("%s", hu->hdev->name); + if (h5->state == H5_UNINITIALIZED) h5_link_control(hu, sync_req, sizeof(sync_req)); @@ -122,6 +128,11 @@ static void h5_timed_event(unsigned long arg) goto wakeup; } + if (h5->sleep != H5_AWAKE) { + h5->sleep = H5_SLEEPING; + goto wakeup; + } + BT_DBG("hu %p retransmitting %u pkts", hu, h5->unack.qlen); spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); @@ -262,12 +273,15 @@ static void h5_handle_internal_rx(struct hci_uart *hu) return; } else if (memcmp(data, sleep_req, 2) == 0) { BT_DBG("Peer went to sleep"); - h5->sleeping = true; - h5_link_control(hu, wakeup_req, 2); + h5->sleep = H5_SLEEPING; + return; } else if (memcmp(data, woken_req, 2) == 0) { BT_DBG("Peer woke up"); - h5->sleeping = false; - return; + h5->sleep = H5_AWAKE; + } else if (memcmp(data, wakeup_req, 2) == 0) { + BT_DBG("Peer requested wakeup"); + h5_link_control(hu, woken_req, 2); + h5->sleep = H5_AWAKE; } else { BT_DBG("Link Control: 0x%02hhx 0x%02hhx", data[0], data[1]); return; @@ -625,6 +639,19 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu) unsigned long flags; struct sk_buff *skb, *nskb; + if (h5->sleep != H5_AWAKE) { + const unsigned char wakeup_req[] = { 0x05, 0xfa }; + + if (h5->sleep == H5_WAKING_UP) + return NULL; + + h5->sleep = H5_WAKING_UP; + BT_DBG("Sending wakeup request"); + + mod_timer(&h5->timer, jiffies + HZ / 100); + return h5_prepare_pkt(hu, HCI_3WIRE_LINK_PKT, wakeup_req, 2); + } + if ((skb = skb_dequeue(&h5->unrel)) != NULL) { nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type, skb->data, skb->len); -- cgit v1.1 From c826ed095d431c91f1d18f9b83b365569fcd977b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:17 +0300 Subject: Bluetooth: Remove unnecessary h5_build_pkt function The implementation of h5_build_packet can be moved into h5_prepare_pkt since all h5_prepare_pkt does is determine whether the packet is reliable and then call h5_build_packet. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 49 ++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 26 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 8819ce8..f9067ce 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -559,14 +559,33 @@ static void h5_slip_one_byte(struct sk_buff *skb, u8 c) } } -static struct sk_buff *h5_build_pkt(struct hci_uart *hu, bool rel, u8 pkt_type, - const u8 *data, size_t len) +static bool valid_packet_type(u8 type) +{ + switch (type) { + case HCI_ACLDATA_PKT: + case HCI_COMMAND_PKT: + case HCI_SCODATA_PKT: + case HCI_3WIRE_LINK_PKT: + case HCI_3WIRE_ACK_PKT: + return true; + default: + return false; + } +} + +static struct sk_buff *h5_prepare_pkt(struct hci_uart *hu, u8 pkt_type, + const u8 *data, size_t len) { struct h5 *h5 = hu->priv; struct sk_buff *nskb; u8 hdr[4]; int i; + if (!valid_packet_type(pkt_type)) { + BT_ERR("Unknown packet type %u", pkt_type); + return NULL; + } + /* * Max len of packet: (original len + 4 (H5 hdr) + 2 (crc)) * 2 * (because bytes 0xc0 and 0xdb are escaped, worst case is when @@ -584,7 +603,8 @@ static struct sk_buff *h5_build_pkt(struct hci_uart *hu, bool rel, u8 pkt_type, hdr[0] = h5->tx_ack << 3; h5->tx_ack_req = false; - if (rel) { + /* Reliable packet? */ + if (pkt_type == HCI_ACLDATA_PKT || pkt_type == HCI_COMMAND_PKT) { hdr[0] |= 1 << 7; hdr[0] |= h5->tx_seq; h5->tx_seq = (h5->tx_seq + 1) % 8; @@ -610,29 +630,6 @@ static struct sk_buff *h5_build_pkt(struct hci_uart *hu, bool rel, u8 pkt_type, return nskb; } -static struct sk_buff *h5_prepare_pkt(struct hci_uart *hu, u8 pkt_type, - const u8 *data, size_t len) -{ - bool rel; - - switch (pkt_type) { - case HCI_ACLDATA_PKT: - case HCI_COMMAND_PKT: - rel = true; - break; - case HCI_SCODATA_PKT: - case HCI_3WIRE_LINK_PKT: - case HCI_3WIRE_ACK_PKT: - rel = false; - break; - default: - BT_ERR("Unknown packet type %u", pkt_type); - return NULL; - } - - return h5_build_pkt(hu, rel, pkt_type, data, len); -} - static struct sk_buff *h5_dequeue(struct hci_uart *hu) { struct h5 *h5 = hu->priv; -- cgit v1.1 From afdc944c1b9604fd0399d490e5bec5e632f731d0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:18 +0300 Subject: Bluetooth: Improve Three-wire UART configuration handling The configuration request/response messages contain a configuration field which contains the sliding window size (amount of unacked reliable packets that can be pending). This patch makes sure that we configure the correct size (minimum of local and remote values) and use it when determining whether to send new packets or not. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index f9067ce..831ccfe 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -33,7 +33,8 @@ #define HCI_3WIRE_ACK_PKT 0 #define HCI_3WIRE_LINK_PKT 15 -#define H5_TXWINSIZE 4 +/* Sliding window size */ +#define H5_TX_WIN_MAX 4 #define H5_ACK_TIMEOUT msecs_to_jiffies(250) #define H5_SYNC_TIMEOUT msecs_to_jiffies(100) @@ -74,6 +75,7 @@ struct h5 { bool tx_ack_req; /* Pending ack to send */ u8 tx_seq; /* Next seq number to send */ u8 tx_ack; /* Next ack number to send */ + u8 tx_win; /* Sliding window size */ enum { H5_UNINITIALIZED, @@ -106,10 +108,20 @@ static void h5_link_control(struct hci_uart *hu, const void *data, size_t len) skb_queue_tail(&h5->unrel, nskb); } +static u8 h5_cfg_field(struct h5 *h5) +{ + u8 field = 0; + + /* Sliding window size (first 3 bits) */ + field |= (h5->tx_win & 7); + + return field; +} + static void h5_timed_event(unsigned long arg) { const unsigned char sync_req[] = { 0x01, 0x7e }; - const unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; + unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; struct hci_uart *hu = (struct hci_uart *) arg; struct h5 *h5 = hu->priv; struct sk_buff *skb; @@ -120,8 +132,10 @@ static void h5_timed_event(unsigned long arg) if (h5->state == H5_UNINITIALIZED) h5_link_control(hu, sync_req, sizeof(sync_req)); - if (h5->state == H5_INITIALIZED) + if (h5->state == H5_INITIALIZED) { + conf_req[2] = h5_cfg_field(h5); h5_link_control(hu, conf_req, sizeof(conf_req)); + } if (h5->state != H5_ACTIVE) { mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT); @@ -171,6 +185,8 @@ static int h5_open(struct hci_uart *hu) h5->timer.function = h5_timed_event; h5->timer.data = (unsigned long) hu; + h5->tx_win = H5_TX_WIN_MAX; + set_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags); /* Send initial sync request */ @@ -242,8 +258,8 @@ static void h5_handle_internal_rx(struct hci_uart *hu) struct h5 *h5 = hu->priv; const unsigned char sync_req[] = { 0x01, 0x7e }; const unsigned char sync_rsp[] = { 0x02, 0x7d }; - const unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; - const unsigned char conf_rsp[] = { 0x04, 0x7b, 0x01 }; + unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; + const unsigned char conf_rsp[] = { 0x04, 0x7b }; const unsigned char wakeup_req[] = { 0x05, 0xfa }; const unsigned char woken_req[] = { 0x06, 0xf9 }; const unsigned char sleep_req[] = { 0x07, 0x78 }; @@ -258,6 +274,8 @@ static void h5_handle_internal_rx(struct hci_uart *hu) if (H5_HDR_LEN(hdr) < 2) return; + conf_req[2] = h5_cfg_field(h5); + if (memcmp(data, sync_req, 2) == 0) { h5_link_control(hu, sync_rsp, 2); } else if (memcmp(data, sync_rsp, 2) == 0) { @@ -267,7 +285,9 @@ static void h5_handle_internal_rx(struct hci_uart *hu) h5_link_control(hu, conf_rsp, 2); h5_link_control(hu, conf_req, 3); } else if (memcmp(data, conf_rsp, 2) == 0) { - BT_DBG("Three-wire init sequence complete"); + if (H5_HDR_LEN(hdr) > 2) + h5->tx_win = (data[2] & 7); + BT_DBG("Three-wire init complete. tx_win %u", h5->tx_win); h5->state = H5_ACTIVE; hci_uart_init_ready(hu); return; @@ -663,7 +683,7 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu) spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); - if (h5->unack.qlen >= H5_TXWINSIZE) + if (h5->unack.qlen >= h5->tx_win) goto unlock; if ((skb = skb_dequeue(&h5->rel)) != NULL) { -- cgit v1.1 From e0482103c22957b413db4c4ba35eca3b1e99751d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jul 2012 16:12:19 +0300 Subject: Bluetooth: Introduce a flags variable to Three-wire UART state This patch introduces a flags variable to the Three-wire UART state struct and converts the two existing bools in the struct into flags. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- drivers/bluetooth/hci_h5.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers/bluetooth') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 831ccfe..b6154d5 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -58,21 +58,27 @@ #define SLIP_ESC_DELIM 0xdc #define SLIP_ESC_ESC 0xdd +/* H5 state flags */ +enum { + H5_RX_ESC, /* SLIP escape mode */ + H5_TX_ACK_REQ, /* Pending ack to send */ +}; + 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 */ + unsigned long flags; + struct sk_buff *rx_skb; /* Receive buffer */ size_t rx_pending; /* Expecting more bytes */ - bool rx_esc; /* SLIP escape mode */ u8 rx_ack; /* Last ack number received */ int (*rx_func) (struct hci_uart *hu, u8 c); struct timer_list timer; /* Retransmission timer */ - bool tx_ack_req; /* Pending ack to send */ u8 tx_seq; /* Next seq number to send */ u8 tx_ack; /* Next ack number to send */ u8 tx_win; /* Sliding window size */ @@ -317,7 +323,7 @@ static void h5_complete_rx_pkt(struct hci_uart *hu) if (H5_HDR_RELIABLE(hdr)) { h5->tx_ack = (h5->tx_ack + 1) % 8; - h5->tx_ack_req = true; + set_bit(H5_TX_ACK_REQ, &h5->flags); hci_uart_tx_wakeup(hu); } @@ -445,12 +451,12 @@ static void h5_unslip_one_byte(struct h5 *h5, unsigned char c) const u8 delim = SLIP_DELIMITER, esc = SLIP_ESC; const u8 *byte = &c; - if (!h5->rx_esc && c == SLIP_ESC) { - h5->rx_esc = true; + if (!test_bit(H5_RX_ESC, &h5->flags) && c == SLIP_ESC) { + set_bit(H5_RX_ESC, &h5->flags); return; } - if (h5->rx_esc) { + if (test_and_clear_bit(H5_RX_ESC, &h5->flags)) { switch (c) { case SLIP_ESC_DELIM: byte = &delim; @@ -463,8 +469,6 @@ static void h5_unslip_one_byte(struct h5 *h5, unsigned char c) h5_reset_rx(h5); return; } - - h5->rx_esc = false; } memcpy(skb_put(h5->rx_skb, 1), byte, 1); @@ -482,7 +486,7 @@ static void h5_reset_rx(struct h5 *h5) h5->rx_func = h5_rx_delimiter; h5->rx_pending = 0; - h5->rx_esc = false; + clear_bit(H5_RX_ESC, &h5->flags); } static int h5_recv(struct hci_uart *hu, void *data, int count) @@ -621,7 +625,7 @@ static struct sk_buff *h5_prepare_pkt(struct hci_uart *hu, u8 pkt_type, h5_slip_delim(nskb); hdr[0] = h5->tx_ack << 3; - h5->tx_ack_req = false; + clear_bit(H5_TX_ACK_REQ, &h5->flags); /* Reliable packet? */ if (pkt_type == HCI_ACLDATA_PKT || pkt_type == HCI_COMMAND_PKT) { @@ -703,7 +707,7 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu) unlock: spin_unlock_irqrestore(&h5->unack.lock, flags); - if (h5->tx_ack_req) + if (test_bit(H5_TX_ACK_REQ, &h5->flags)) return h5_prepare_pkt(hu, HCI_3WIRE_ACK_PKT, NULL, 0); return NULL; -- cgit v1.1