summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/Kconfig20
-rw-r--r--drivers/bluetooth/Makefile1
-rw-r--r--drivers/bluetooth/bpa10x.c2
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c4
-rw-r--r--drivers/bluetooth/btrsi.c1
-rw-r--r--drivers/bluetooth/btuart_cs.c675
-rw-r--r--drivers/bluetooth/btusb.c4
-rw-r--r--drivers/bluetooth/h4_recv.h160
-rw-r--r--drivers/bluetooth/hci_bcm.c305
-rw-r--r--drivers/bluetooth/hci_ll.c222
10 files changed, 470 insertions, 924 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 149a38ee1fce..010f5f579e68 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -147,6 +147,7 @@ config BT_HCIUART_ATH3K
config BT_HCIUART_LL
bool "HCILL protocol support"
depends on BT_HCIUART_SERDEV
+ select BT_HCIUART_H4
help
HCILL (HCI Low Level) is a serial protocol for communication
between Bluetooth device and host. This protocol is required for
@@ -242,8 +243,7 @@ config BT_HCIBCM203X
config BT_HCIBPA10X
tristate "HCI BPA10x USB driver"
- depends on USB && BT_HCIUART
- select BT_HCIUART_H4
+ depends on USB
help
Bluetooth HCI BPA10x USB driver.
This driver provides support for the Digianswer BPA 100/105 Bluetooth
@@ -305,22 +305,6 @@ config BT_HCIBLUECARD
Say Y here to compile support for HCI BlueCard devices into the
kernel or say M to compile it as module (bluecard_cs).
-config BT_HCIBTUART
- tristate "HCI UART (PC Card) device driver"
- depends on PCMCIA
- help
- Bluetooth HCI UART (PC Card) driver.
- This driver provides support for Bluetooth PCMCIA devices with
- an UART interface:
- Xircom CreditCard Bluetooth Adapter
- Xircom RealPort2 Bluetooth Adapter
- Sphinx PICO Card
- H-Soft blue+Card
- Cyber-blue Compact Flash Card
-
- Say Y here to compile support for HCI UART devices into the
- kernel or say M to compile it as module (btuart_cs).
-
config BT_HCIVHCI
tristate "HCI VHCI (Virtual HCI device) driver"
help
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 03cfc1b20c4a..ec16c55eb6e9 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o
obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o
obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
-obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index 801ea4ca65e4..c6f7cc57db14 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -35,7 +35,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
-#include "hci_uart.h"
+#include "h4_recv.h"
#define VERSION "0.11"
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 7dbb4463b539..6f99b9f3d57f 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -689,7 +689,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
int ret, num_blocks, blksz;
struct sk_buff *skb = NULL;
u32 type;
- u8 *payload = NULL;
+ u8 *payload;
struct hci_dev *hdev = priv->btmrvl_dev.hcidev;
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
@@ -920,7 +920,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
{
struct sdio_func *func;
u8 reg;
- int ret = 0;
+ int ret;
if (!card || !card->func) {
BT_ERR("Error: card or function is NULL!");
diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c
index 5034325e417c..60d1419590ba 100644
--- a/drivers/bluetooth/btrsi.c
+++ b/drivers/bluetooth/btrsi.c
@@ -13,7 +13,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <net/bluetooth/bluetooth.h>
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
deleted file mode 100644
index 310e9c2e09b6..000000000000
--- a/drivers/bluetooth/btuart_cs.c
+++ /dev/null
@@ -1,675 +0,0 @@
-/*
- *
- * Driver for Bluetooth PCMCIA cards with HCI UART interface
- *
- * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
- * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
- *
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/moduleparam.h>
-
-#include <linux/skbuff.h>
-#include <linux/string.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/bitops.h>
-#include <linux/io.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-
-
-/* ======================== Module parameters ======================== */
-
-
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth driver for Bluetooth PCMCIA cards with HCI UART interface");
-MODULE_LICENSE("GPL");
-
-
-
-/* ======================== Local structures ======================== */
-
-
-struct btuart_info {
- struct pcmcia_device *p_dev;
-
- struct hci_dev *hdev;
-
- spinlock_t lock; /* For serializing operations */
-
- struct sk_buff_head txq;
- unsigned long tx_state;
-
- unsigned long rx_state;
- unsigned long rx_count;
- struct sk_buff *rx_skb;
-};
-
-
-static int btuart_config(struct pcmcia_device *link);
-static void btuart_release(struct pcmcia_device *link);
-
-static void btuart_detach(struct pcmcia_device *p_dev);
-
-
-/* Maximum baud rate */
-#define SPEED_MAX 115200
-
-/* Default baud rate: 57600, 115200, 230400 or 460800 */
-#define DEFAULT_BAUD_RATE 115200
-
-
-/* Transmit states */
-#define XMIT_SENDING 1
-#define XMIT_WAKEUP 2
-#define XMIT_WAITING 8
-
-/* Receiver states */
-#define RECV_WAIT_PACKET_TYPE 0
-#define RECV_WAIT_EVENT_HEADER 1
-#define RECV_WAIT_ACL_HEADER 2
-#define RECV_WAIT_SCO_HEADER 3
-#define RECV_WAIT_DATA 4
-
-
-
-/* ======================== Interrupt handling ======================== */
-
-
-static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
-{
- int actual = 0;
-
- /* Tx FIFO should be empty */
- if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
- return 0;
-
- /* Fill FIFO with current frame */
- while ((fifo_size-- > 0) && (actual < len)) {
- /* Transmit next byte */
- outb(buf[actual], iobase + UART_TX);
- actual++;
- }
-
- return actual;
-}
-
-
-static void btuart_write_wakeup(struct btuart_info *info)
-{
- if (!info) {
- BT_ERR("Unknown device");
- return;
- }
-
- if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
- set_bit(XMIT_WAKEUP, &(info->tx_state));
- return;
- }
-
- do {
- unsigned int iobase = info->p_dev->resource[0]->start;
- register struct sk_buff *skb;
- int len;
-
- clear_bit(XMIT_WAKEUP, &(info->tx_state));
-
- if (!pcmcia_dev_present(info->p_dev))
- return;
-
- skb = skb_dequeue(&(info->txq));
- if (!skb)
- break;
-
- /* Send frame */
- len = btuart_write(iobase, 16, skb->data, skb->len);
- set_bit(XMIT_WAKEUP, &(info->tx_state));
-
- if (len == skb->len) {
- kfree_skb(skb);
- } else {
- skb_pull(skb, len);
- skb_queue_head(&(info->txq), skb);
- }
-
- info->hdev->stat.byte_tx += len;
-
- } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
-
- clear_bit(XMIT_SENDING, &(info->tx_state));
-}
-
-
-static void btuart_receive(struct btuart_info *info)
-{
- unsigned int iobase;
- int boguscount = 0;
-
- if (!info) {
- BT_ERR("Unknown device");
- return;
- }
-
- iobase = info->p_dev->resource[0]->start;
-
- do {
- info->hdev->stat.byte_rx++;
-
- /* Allocate packet */
- if (!info->rx_skb) {
- info->rx_state = RECV_WAIT_PACKET_TYPE;
- info->rx_count = 0;
- info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
- if (!info->rx_skb) {
- BT_ERR("Can't allocate mem for new packet");
- return;
- }
- }
-
- if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
-
- hci_skb_pkt_type(info->rx_skb) = inb(iobase + UART_RX);
-
- switch (hci_skb_pkt_type(info->rx_skb)) {
-
- case HCI_EVENT_PKT:
- info->rx_state = RECV_WAIT_EVENT_HEADER;
- info->rx_count = HCI_EVENT_HDR_SIZE;
- break;
-
- case HCI_ACLDATA_PKT:
- info->rx_state = RECV_WAIT_ACL_HEADER;
- info->rx_count = HCI_ACL_HDR_SIZE;
- break;
-
- case HCI_SCODATA_PKT:
- info->rx_state = RECV_WAIT_SCO_HEADER;
- info->rx_count = HCI_SCO_HDR_SIZE;
- break;
-
- default:
- /* Unknown packet */
- BT_ERR("Unknown HCI packet with type 0x%02x received",
- hci_skb_pkt_type(info->rx_skb));
- info->hdev->stat.err_rx++;
-
- kfree_skb(info->rx_skb);
- info->rx_skb = NULL;
- break;
-
- }
-
- } else {
-
- skb_put_u8(info->rx_skb, inb(iobase + UART_RX));
- info->rx_count--;
-
- if (info->rx_count == 0) {
-
- int dlen;
- struct hci_event_hdr *eh;
- struct hci_acl_hdr *ah;
- struct hci_sco_hdr *sh;
-
-
- switch (info->rx_state) {
-
- case RECV_WAIT_EVENT_HEADER:
- eh = hci_event_hdr(info->rx_skb);
- info->rx_state = RECV_WAIT_DATA;
- info->rx_count = eh->plen;
- break;
-
- case RECV_WAIT_ACL_HEADER:
- ah = hci_acl_hdr(info->rx_skb);
- dlen = __le16_to_cpu(ah->dlen);
- info->rx_state = RECV_WAIT_DATA;
- info->rx_count = dlen;
- break;
-
- case RECV_WAIT_SCO_HEADER:
- sh = hci_sco_hdr(info->rx_skb);
- info->rx_state = RECV_WAIT_DATA;
- info->rx_count = sh->dlen;
- break;
-
- case RECV_WAIT_DATA:
- hci_recv_frame(info->hdev, info->rx_skb);
- info->rx_skb = NULL;
- break;
-
- }
-
- }
-
- }
-
- /* Make sure we don't stay here too long */
- if (boguscount++ > 16)
- break;
-
- } while (inb(iobase + UART_LSR) & UART_LSR_DR);
-}
-
-
-static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
-{
- struct btuart_info *info = dev_inst;
- unsigned int iobase;
- int boguscount = 0;
- int iir, lsr;
- irqreturn_t r = IRQ_NONE;
-
- if (!info || !info->hdev)
- /* our irq handler is shared */
- return IRQ_NONE;
-
- iobase = info->p_dev->resource[0]->start;
-
- spin_lock(&(info->lock));
-
- iir = inb(iobase + UART_IIR) & UART_IIR_ID;
- while (iir) {
- r = IRQ_HANDLED;
-
- /* Clear interrupt */
- lsr = inb(iobase + UART_LSR);
-
- switch (iir) {
- case UART_IIR_RLSI:
- BT_ERR("RLSI");
- break;
- case UART_IIR_RDI:
- /* Receive interrupt */
- btuart_receive(info);
- break;
- case UART_IIR_THRI:
- if (lsr & UART_LSR_THRE) {
- /* Transmitter ready for data */
- btuart_write_wakeup(info);
- }
- break;
- default:
- BT_ERR("Unhandled IIR=%#x", iir);
- break;
- }
-
- /* Make sure we don't stay here too long */
- if (boguscount++ > 100)
- break;
-
- iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-
- }
-
- spin_unlock(&(info->lock));
-
- return r;
-}
-
-
-static void btuart_change_speed(struct btuart_info *info,
- unsigned int speed)
-{
- unsigned long flags;
- unsigned int iobase;
- int fcr; /* FIFO control reg */
- int lcr; /* Line control reg */
- int divisor;
-
- if (!info) {
- BT_ERR("Unknown device");
- return;
- }
-
- iobase = info->p_dev->resource[0]->start;
-
- spin_lock_irqsave(&(info->lock), flags);
-
- /* Turn off interrupts */
- outb(0, iobase + UART_IER);
-
- divisor = SPEED_MAX / speed;
-
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
-
- /*
- * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
- * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
- * about this timeout since it will always be fast enough.
- */
-
- if (speed < 38400)
- fcr |= UART_FCR_TRIGGER_1;
- else
- fcr |= UART_FCR_TRIGGER_14;
-
- /* Bluetooth cards use 8N1 */
- lcr = UART_LCR_WLEN8;
-
- outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */
- outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */
- outb(divisor >> 8, iobase + UART_DLM);
- outb(lcr, iobase + UART_LCR); /* Set 8N1 */
- outb(fcr, iobase + UART_FCR); /* Enable FIFO's */
-
- /* Turn on interrupts */
- outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
-
- spin_unlock_irqrestore(&(info->lock), flags);
-}
-
-
-
-/* ======================== HCI interface ======================== */
-
-
-static int btuart_hci_flush(struct hci_dev *hdev)
-{
- struct btuart_info *info = hci_get_drvdata(hdev);
-
- /* Drop TX queue */
- skb_queue_purge(&(info->txq));
-
- return 0;
-}
-
-
-static int btuart_hci_open(struct hci_dev *hdev)
-{
- return 0;
-}
-
-
-static int btuart_hci_close(struct hci_dev *hdev)
-{
- btuart_hci_flush(hdev);
-
- return 0;
-}
-
-
-static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct btuart_info *info = hci_get_drvdata(hdev);
-
- switch (hci_skb_pkt_type(skb)) {
- case HCI_COMMAND_PKT:
- hdev->stat.cmd_tx++;
- break;
- case HCI_ACLDATA_PKT:
- hdev->stat.acl_tx++;
- break;
- case HCI_SCODATA_PKT:
- hdev->stat.sco_tx++;
- break;
- }
-
- /* Prepend skb with frame type */
- memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
- skb_queue_tail(&(info->txq), skb);
-
- btuart_write_wakeup(info);
-
- return 0;
-}
-
-
-
-/* ======================== Card services HCI interaction ======================== */
-
-
-static int btuart_open(struct btuart_info *info)
-{
- unsigned long flags;
- unsigned int iobase = info->p_dev->resource[0]->start;
- struct hci_dev *hdev;
-
- spin_lock_init(&(info->lock));
-
- skb_queue_head_init(&(info->txq));
-
- info->rx_state = RECV_WAIT_PACKET_TYPE;
- info->rx_count = 0;
- info->rx_skb = NULL;
-
- /* Initialize HCI device */
- hdev = hci_alloc_dev();
- if (!hdev) {
- BT_ERR("Can't allocate HCI device");
- return -ENOMEM;
- }
-
- info->hdev = hdev;
-
- hdev->bus = HCI_PCCARD;
- hci_set_drvdata(hdev, info);
- SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
-
- hdev->open = btuart_hci_open;
- hdev->close = btuart_hci_close;
- hdev->flush = btuart_hci_flush;
- hdev->send = btuart_hci_send_frame;
-
- spin_lock_irqsave(&(info->lock), flags);
-
- /* Reset UART */
- outb(0, iobase + UART_MCR);
-
- /* Turn off interrupts */
- outb(0, iobase + UART_IER);
-
- /* Initialize UART */
- outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */
- outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
-
- /* Turn on interrupts */
- // outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
-
- spin_unlock_irqrestore(&(info->lock), flags);
-
- btuart_change_speed(info, DEFAULT_BAUD_RATE);
-
- /* Timeout before it is safe to send the first HCI packet */
- msleep(1000);
-
- /* Register HCI device */
- if (hci_register_dev(hdev) < 0) {
- BT_ERR("Can't register HCI device");
- info->hdev = NULL;
- hci_free_dev(hdev);
- return -ENODEV;
- }
-
- return 0;
-}
-
-
-static int btuart_close(struct btuart_info *info)
-{
- unsigned long flags;
- unsigned int iobase = info->p_dev->resource[0]->start;
- struct hci_dev *hdev = info->hdev;
-
- if (!hdev)
- return -ENODEV;
-
- btuart_hci_close(hdev);
-
- spin_lock_irqsave(&(info->lock), flags);
-
- /* Reset UART */
- outb(0, iobase + UART_MCR);
-
- /* Turn off interrupts */
- outb(0, iobase + UART_IER);
-
- spin_unlock_irqrestore(&(info->lock), flags);
-
- hci_unregister_dev(hdev);
- hci_free_dev(hdev);
-
- return 0;
-}
-
-static int btuart_probe(struct pcmcia_device *link)
-{
- struct btuart_info *info;
-
- /* Create new info device */
- info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- info->p_dev = link;
- link->priv = info;
-
- link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
- CONF_AUTO_SET_IO;
-
- return btuart_config(link);
-}
-
-
-static void btuart_detach(struct pcmcia_device *link)
-{
- btuart_release(link);
-}
-
-static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data)
-{
- int *try = priv_data;
-
- if (!try)
- p_dev->io_lines = 16;
-
- if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0))
- return -EINVAL;
-
- p_dev->resource[0]->end = 8;
- p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
- p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-
- return pcmcia_request_io(p_dev);
-}
-
-static int btuart_check_config_notpicky(struct pcmcia_device *p_dev,
- void *priv_data)
-{
- static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
- int j;
-
- if (p_dev->io_lines > 3)
- return -ENODEV;
-
- p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
- p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
- p_dev->resource[0]->end = 8;
-
- for (j = 0; j < 5; j++) {
- p_dev->resource[0]->start = base[j];
- p_dev->io_lines = base[j] ? 16 : 3;
- if (!pcmcia_request_io(p_dev))
- return 0;
- }
- return -ENODEV;
-}
-
-static int btuart_config(struct pcmcia_device *link)
-{
- struct btuart_info *info = link->priv;
- int i;
- int try;
-
- /* First pass: look for a config entry that looks normal.
- * Two tries: without IO aliases, then with aliases
- */
- for (try = 0; try < 2; try++)
- if (!pcmcia_loop_config(link, btuart_check_config, &try))
- goto found_port;
-
- /* Second pass: try to find an entry that isn't picky about
- * its base address, then try to grab any standard serial port
- * address, and finally try to get any free port.
- */
- if (!pcmcia_loop_config(link, btuart_check_config_notpicky, NULL))
- goto found_port;
-
- BT_ERR("No usable port range found");
- goto failed;
-
-found_port:
- i = pcmcia_request_irq(link, btuart_interrupt);
- if (i != 0)
- goto failed;
-
- i = pcmcia_enable_device(link);
- if (i != 0)
- goto failed;
-
- if (btuart_open(info) != 0)
- goto failed;
-
- return 0;
-
-failed:
- btuart_release(link);
- return -ENODEV;
-}
-
-
-static void btuart_release(struct pcmcia_device *link)
-{
- struct btuart_info *info = link->priv;
-
- btuart_close(info);
-
- pcmcia_disable_device(link);
-}
-
-static const struct pcmcia_device_id btuart_ids[] = {
- /* don't use this driver. Use serial_cs + hci_uart instead */
- PCMCIA_DEVICE_NULL
-};
-MODULE_DEVICE_TABLE(pcmcia, btuart_ids);
-
-static struct pcmcia_driver btuart_driver = {
- .owner = THIS_MODULE,
- .name = "btuart_cs",
- .probe = btuart_probe,
- .remove = btuart_detach,
- .id_table = btuart_ids,
-};
-module_pcmcia_driver(btuart_driver);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 5cd868ea28ed..c8c8b0b8d333 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -368,6 +368,9 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x13d3, 0x3494), .driver_info = BTUSB_REALTEK },
+ /* Additional Realtek 8723BU Bluetooth devices */
+ { USB_DEVICE(0x7392, 0xa611), .driver_info = BTUSB_REALTEK },
+
/* Additional Realtek 8821AE Bluetooth devices */
{ USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK },
@@ -3060,6 +3063,7 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_QCA_ROME) {
data->setup_on_usb = btusb_setup_qca;
hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
+ set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
}
#ifdef CONFIG_BT_HCIBTUSB_RTL
diff --git a/drivers/bluetooth/h4_recv.h b/drivers/bluetooth/h4_recv.h
new file mode 100644
index 000000000000..b432651f8236
--- /dev/null
+++ b/drivers/bluetooth/h4_recv.h
@@ -0,0 +1,160 @@
+/*
+ *
+ * Generic Bluetooth HCI UART driver
+ *
+ * Copyright (C) 2015-2018 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 <asm/unaligned.h>
+
+struct h4_recv_pkt {
+ u8 type; /* Packet type */
+ u8 hlen; /* Header length */
+ u8 loff; /* Data length offset in header */
+ u8 lsize; /* Data length field size */
+ u16 maxlen; /* Max overall packet length */
+ int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);
+};
+
+#define H4_RECV_ACL \
+ .type = HCI_ACLDATA_PKT, \
+ .hlen = HCI_ACL_HDR_SIZE, \
+ .loff = 2, \
+ .lsize = 2, \
+ .maxlen = HCI_MAX_FRAME_SIZE \
+
+#define H4_RECV_SCO \
+ .type = HCI_SCODATA_PKT, \
+ .hlen = HCI_SCO_HDR_SIZE, \
+ .loff = 2, \
+ .lsize = 1, \
+ .maxlen = HCI_MAX_SCO_SIZE
+
+#define H4_RECV_EVENT \
+ .type = HCI_EVENT_PKT, \
+ .hlen = HCI_EVENT_HDR_SIZE, \
+ .loff = 1, \
+ .lsize = 1, \
+ .maxlen = HCI_MAX_EVENT_SIZE
+
+static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev,
+ struct sk_buff *skb,
+ const unsigned char *buffer,
+ int count,
+ const struct h4_recv_pkt *pkts,
+ int pkts_count)
+{
+ while (count) {
+ int i, len;
+
+ if (!count)
+ break;
+
+ if (!skb) {
+ for (i = 0; i < pkts_count; i++) {
+ if (buffer[0] != (&pkts[i])->type)
+ continue;
+
+ skb = bt_skb_alloc((&pkts[i])->maxlen,
+ GFP_ATOMIC);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ hci_skb_pkt_type(skb) = (&pkts[i])->type;
+ hci_skb_expect(skb) = (&pkts[i])->hlen;
+ break;
+ }
+
+ /* Check for invalid packet type */
+ if (!skb)
+ return ERR_PTR(-EILSEQ);
+
+ count -= 1;
+ buffer += 1;
+ }
+
+ len = min_t(uint, hci_skb_expect(skb) - skb->len, count);
+ skb_put_data(skb, buffer, len);
+
+ count -= len;
+ buffer += len;
+
+ /* Check for partial packet */
+ if (skb->len < hci_skb_expect(skb))
+ continue;
+
+ for (i = 0; i < pkts_count; i++) {
+ if (hci_skb_pkt_type(skb) == (&pkts[i])->type)
+ break;
+ }
+
+ if (i >= pkts_count) {
+ kfree_skb(skb);
+ return ERR_PTR(-EILSEQ);
+ }
+
+ if (skb->len == (&pkts[i])->hlen) {
+ u16 dlen;
+
+ switch ((&pkts[i])->lsize) {
+ case 0:
+ /* No variable data length */
+ dlen = 0;
+ break;
+ case 1:
+ /* Single octet variable length */
+ dlen = skb->data[(&pkts[i])->loff];
+ hci_skb_expect(skb) += dlen;
+
+ if (skb_tailroom(skb) < dlen) {
+ kfree_skb(skb);
+ return ERR_PTR(-EMSGSIZE);
+ }
+ break;
+ case 2:
+ /* Double octet variable length */
+ dlen = get_unaligned_le16(skb->data +
+ (&pkts[i])->loff);
+ hci_skb_expect(skb) += dlen;
+
+ if (skb_tailroom(skb) < dlen) {
+ kfree_skb(skb);
+ return ERR_PTR(-EMSGSIZE);
+ }
+ break;
+ default:
+ /* Unsupported variable length */
+ kfree_skb(skb);
+ return ERR_PTR(-EILSEQ);
+ }
+
+ if (!dlen) {
+ /* No more data, complete frame */
+ (&pkts[i])->recv(hdev, skb);
+ skb = NULL;
+ }
+ } else {
+ /* Complete frame */
+ (&pkts[i])->recv(hdev, skb);
+ skb = NULL;
+ }
+ }
+
+ return skb;
+}
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 40b9fb247010..441f5e1deb11 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -98,6 +98,8 @@ struct bcm_device {
int (*set_shutdown)(struct bcm_device *, bool);
#ifdef CONFIG_ACPI
acpi_handle btlp, btpu, btpd;
+ int gpio_count;
+ int gpio_int_idx;
#endif
struct clk *clk;
@@ -126,6 +128,10 @@ struct bcm_data {
static DEFINE_MUTEX(bcm_device_lock);
static LIST_HEAD(bcm_device_list);
+static int irq_polarity = -1;
+module_param(irq_polarity, int, 0444);
+MODULE_PARM_DESC(irq_polarity, "IRQ polarity 0: active-high 1: active-low");
+
static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed)
{
if (hu->serdev)
@@ -770,47 +776,27 @@ unlock:
}
#endif
-static const struct acpi_gpio_params int_last_device_wakeup_gpios = { 0, 0, false };
-static const struct acpi_gpio_params int_last_shutdown_gpios = { 1, 0, false };
-static const struct acpi_gpio_params int_last_host_wakeup_gpios = { 2, 0, false };
+static const struct acpi_gpio_params first_gpio = { 0, 0, false };
+static const struct acpi_gpio_params second_gpio = { 1, 0, false };
+static const struct acpi_gpio_params third_gpio = { 2, 0, false };
static const struct acpi_gpio_mapping acpi_bcm_int_last_gpios[] = {
- { "device-wakeup-gpios", &int_last_device_wakeup_gpios, 1 },
- { "shutdown-gpios", &int_last_shutdown_gpios, 1 },
- { "host-wakeup-gpios", &int_last_host_wakeup_gpios, 1 },
+ { "device-wakeup-gpios", &first_gpio, 1 },
+ { "shutdown-gpios", &second_gpio, 1 },
+ { "host-wakeup-gpios", &third_gpio, 1 },
{ },
};
-static const struct acpi_gpio_params int_first_host_wakeup_gpios = { 0, 0, false };
-static const struct acpi_gpio_params int_first_device_wakeup_gpios = { 1, 0, false };
-static const struct acpi_gpio_params int_first_shutdown_gpios = { 2, 0, false };
-
static const struct acpi_gpio_mapping acpi_bcm_int_first_gpios[] = {
- { "device-wakeup-gpios", &int_first_device_wakeup_gpios, 1 },
- { "shutdown-gpios", &int_first_shutdown_gpios, 1 },
- { "host-wakeup-gpios", &int_first_host_wakeup_gpios, 1 },
+ { "host-wakeup-gpios", &first_gpio, 1 },
+ { "device-wakeup-gpios", &second_gpio, 1 },
+ { "shutdown-gpios", &third_gpio, 1 },
{ },
};
#ifdef CONFIG_ACPI
/* IRQ polarity of some chipsets are not defined correctly in ACPI table. */
static const struct dmi_system_id bcm_active_low_irq_dmi_table[] = {
- {
- .ident = "Asus T100TA",
- .matches = {
- DMI_EXACT_MATCH(DMI_SYS_VENDOR,
- "ASUSTeK COMPUTER INC."),
- DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
- },
- },
- {
- .ident = "Asus T100CHI",
- .matches = {
- DMI_EXACT_MATCH(DMI_SYS_VENDOR,
- "ASUSTeK COMPUTER INC."),
- DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100CHI"),
- },
- },
{ /* Handle ThinkPad 8 tablets with BCM2E55 chipset ACPI ID */
.ident = "Lenovo ThinkPad 8",
.matches = {
@@ -818,13 +804,6 @@ static const struct dmi_system_id bcm_active_low_irq_dmi_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"),
},
},
- {
- .ident = "MINIX Z83-4",
- .matches = {
- DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MINIX"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
- },
- },
{ }
};
@@ -838,13 +817,18 @@ static int bcm_resource(struct acpi_resource *ares, void *data)
switch (ares->type) {
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
irq = &ares->data.extended_irq;
- dev->irq_active_low = irq->polarity == ACPI_ACTIVE_LOW;
+ if (irq->polarity != ACPI_ACTIVE_LOW)
+ dev_info(dev->dev, "ACPI Interrupt resource is active-high, this is usually wrong, treating the IRQ as active-low\n");
+ dev->irq_active_low = true;
break;
case ACPI_RESOURCE_TYPE_GPIO:
gpio = &ares->data.gpio;
- if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT)
+ if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) {
+ dev->gpio_int_idx = dev->gpio_count;
dev->irq_active_low = gpio->polarity == ACPI_ACTIVE_LOW;
+ }
+ dev->gpio_count++;
break;
case ACPI_RESOURCE_TYPE_SERIAL_BUS:
@@ -908,13 +892,13 @@ static inline int bcm_apple_get_resources(struct bcm_device *dev)
static int bcm_gpio_set_device_wakeup(struct bcm_device *dev, bool awake)
{
- gpiod_set_value(dev->device_wakeup, awake);
+ gpiod_set_value_cansleep(dev->device_wakeup, awake);
return 0;
}
static int bcm_gpio_set_shutdown(struct bcm_device *dev, bool powered)
{
- gpiod_set_value(dev->shutdown, powered);
+ gpiod_set_value_cansleep(dev->shutdown, powered);
return 0;
}
@@ -962,20 +946,11 @@ static int bcm_acpi_probe(struct bcm_device *dev)
LIST_HEAD(resources);
const struct dmi_system_id *dmi_id;
const struct acpi_gpio_mapping *gpio_mapping = acpi_bcm_int_last_gpios;
- const struct acpi_device_id *id;
struct resource_entry *entry;
int ret;
- /* Retrieve GPIO data */
- id = acpi_match_device(dev->dev->driver->acpi_match_table, dev->dev);
- if (id)
- gpio_mapping = (const struct acpi_gpio_mapping *) id->driver_data;
-
- ret = devm_acpi_dev_add_driver_gpios(dev->dev, gpio_mapping);
- if (ret)
- return ret;
-
/* Retrieve UART ACPI info */
+ dev->gpio_int_idx = -1;
ret = acpi_dev_get_resources(ACPI_COMPANION(dev->dev),
&resources, bcm_resource, dev);
if (ret < 0)
@@ -989,11 +964,40 @@ static int bcm_acpi_probe(struct bcm_device *dev)
}
acpi_dev_free_resource_list(&resources);
- dmi_id = dmi_first_match(bcm_active_low_irq_dmi_table);
- if (dmi_id) {
- dev_warn(dev->dev, "%s: Overwriting IRQ polarity to active low",
- dmi_id->ident);
- dev->irq_active_low = true;
+ /* If the DSDT uses an Interrupt resource for the IRQ, then there are
+ * only 2 GPIO resources, we use the irq-last mapping for this, since
+ * we already have an irq the 3th / last mapping will not be used.
+ */
+ if (dev->irq)
+ gpio_mapping = acpi_bcm_int_last_gpios;
+ else if (dev->gpio_int_idx == 0)
+ gpio_mapping = acpi_bcm_int_first_gpios;
+ else if (dev->gpio_int_idx == 2)
+ gpio_mapping = acpi_bcm_int_last_gpios;
+ else
+ dev_warn(dev->dev, "Unexpected ACPI gpio_int_idx: %d\n",
+ dev->gpio_int_idx);
+
+ /* Warn if our expectations are not met. */
+ if (dev->gpio_count != (dev->irq ? 2 : 3))
+ dev_warn(dev->dev, "Unexpected number of ACPI GPIOs: %d\n",
+ dev->gpio_count);
+
+ ret = devm_acpi_dev_add_driver_gpios(dev->dev, gpio_mapping);
+ if (ret)
+ return ret;
+
+ if (irq_polarity != -1) {
+ dev->irq_active_low = irq_polarity;
+ dev_warn(dev->dev, "Overwriting IRQ polarity to active %s by module-param\n",
+ dev->irq_active_low ? "low" : "high");
+ } else {
+ dmi_id = dmi_first_match(bcm_active_low_irq_dmi_table);
+ if (dmi_id) {
+ dev_warn(dev->dev, "%s: Overwriting IRQ polarity to active low",
+ dmi_id->ident);
+ dev->irq_active_low = true;
+ }
}
return 0;
@@ -1079,25 +1083,172 @@ static const struct hci_uart_proto bcm_proto = {
#ifdef CONFIG_ACPI
static const struct acpi_device_id bcm_acpi_match[] = {
- { "BCM2E1A", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E39", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E3A", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E3D", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E3F", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E40", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E54", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E55", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E64", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E65", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E67", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E71", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E72", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E7B", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E7C", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
- { "BCM2E7E", (kernel_ulong_t)&acpi_bcm_int_first_gpios },
- { "BCM2E95", (kernel_ulong_t)&acpi_bcm_int_first_gpios },
- { "BCM2E96", (kernel_ulong_t)&acpi_bcm_int_first_gpios },
- { "BCM2EA4", (kernel_ulong_t)&acpi_bcm_int_first_gpios },
+ { "BCM2E00" },
+ { "BCM2E01" },
+ { "BCM2E02" },
+ { "BCM2E03" },
+ { "BCM2E04" },
+ { "BCM2E05" },
+ { "BCM2E06" },
+ { "BCM2E07" },
+ { "BCM2E08" },
+ { "BCM2E09" },
+ { "BCM2E0A" },
+ { "BCM2E0B" },
+ { "BCM2E0C" },
+ { "BCM2E0D" },
+ { "BCM2E0E" },
+ { "BCM2E0F" },
+ { "BCM2E10" },
+ { "BCM2E11" },
+ { "BCM2E12" },
+ { "BCM2E13" },
+ { "BCM2E14" },
+ { "BCM2E15" },
+ { "BCM2E16" },
+ { "BCM2E17" },
+ { "BCM2E18" },
+ { "BCM2E19" },
+ { "BCM2E1A" },
+ { "BCM2E1B" },
+ { "BCM2E1C" },
+ { "BCM2E1D" },
+ { "BCM2E1F" },
+ { "BCM2E20" },
+ { "BCM2E21" },
+ { "BCM2E22" },
+ { "BCM2E23" },
+ { "BCM2E24" },
+ { "BCM2E25" },
+ { "BCM2E26" },
+ { "BCM2E27" },
+ { "BCM2E28" },
+ { "BCM2E29" },
+ { "BCM2E2A" },
+ { "BCM2E2B" },
+ { "BCM2E2C" },
+ { "BCM2E2D" },
+ { "BCM2E2E" },
+ { "BCM2E2F" },
+ { "BCM2E30" },
+ { "BCM2E31" },
+ { "BCM2E32" },
+ { "BCM2E33" },
+ { "BCM2E34" },
+ { "BCM2E35" },
+ { "BCM2E36" },
+ { "BCM2E37" },
+ { "BCM2E38" },
+ { "BCM2E39" },
+ { "BCM2E3A" },
+ { "BCM2E3B" },
+ { "BCM2E3C" },
+ { "BCM2E3D" },
+ { "BCM2E3E" },
+ { "BCM2E3F" },
+ { "BCM2E40" },
+ { "BCM2E41" },
+ { "BCM2E42" },
+ { "BCM2E43" },
+ { "BCM2E44" },
+ { "BCM2E45" },
+ { "BCM2E46" },
+ { "BCM2E47" },
+ { "BCM2E48" },
+ { "BCM2E49" },
+ { "BCM2E4A" },
+ { "BCM2E4B" },
+ { "BCM2E4C" },
+ { "BCM2E4D" },
+ { "BCM2E4E" },
+ { "BCM2E4F" },
+ { "BCM2E50" },
+ { "BCM2E51" },
+ { "BCM2E52" },
+ { "BCM2E53" },
+ { "BCM2E54" },
+ { "BCM2E55" },
+ { "BCM2E56" },
+ { "BCM2E57" },
+ { "BCM2E58" },
+ { "BCM2E59" },
+ { "BCM2E5A" },
+ { "BCM2E5B" },
+ { "BCM2E5C" },
+ { "BCM2E5D" },
+ { "BCM2E5E" },
+ { "BCM2E5F" },
+ { "BCM2E60" },
+ { "BCM2E61" },
+ { "BCM2E62" },
+ { "BCM2E63" },
+ { "BCM2E64" },
+ { "BCM2E65" },
+ { "BCM2E66" },
+ { "BCM2E67" },
+ { "BCM2E68" },
+ { "BCM2E69" },
+ { "BCM2E6B" },
+ { "BCM2E6D" },
+ { "BCM2E6E" },
+ { "BCM2E6F" },
+ { "BCM2E70" },
+ { "BCM2E71" },
+ { "BCM2E72" },
+ { "BCM2E73" },
+ { "BCM2E74" },
+ { "BCM2E75" },
+ { "BCM2E76" },
+ { "BCM2E77" },
+ { "BCM2E78" },
+ { "BCM2E79" },
+ { "BCM2E7A" },
+ { "BCM2E7B" },
+ { "BCM2E7C" },
+ { "BCM2E7D" },
+ { "BCM2E7E" },
+ { "BCM2E7F" },
+ { "BCM2E80" },
+ { "BCM2E81" },
+ { "BCM2E82" },
+ { "BCM2E83" },
+ { "BCM2E84" },
+ { "BCM2E85" },
+ { "BCM2E86" },
+ { "BCM2E87" },
+ { "BCM2E88" },
+ { "BCM2E89" },
+ { "BCM2E8A" },
+ { "BCM2E8B" },
+ { "BCM2E8C" },
+ { "BCM2E8D" },
+ { "BCM2E8E" },
+ { "BCM2E90" },
+ { "BCM2E92" },
+ { "BCM2E93" },
+ { "BCM2E94" },
+ { "BCM2E95" },
+ { "BCM2E96" },
+ { "BCM2E97" },
+ { "BCM2E98" },
+ { "BCM2E99" },
+ { "BCM2E9A" },
+ { "BCM2E9B" },
+ { "BCM2E9C" },
+ { "BCM2E9D" },
+ { "BCM2EA0" },
+ { "BCM2EA1" },
+ { "BCM2EA2" },
+ { "BCM2EA3" },
+ { "BCM2EA4" },
+ { "BCM2EA5" },
+ { "BCM2EA6" },
+ { "BCM2EA7" },
+ { "BCM2EA8" },
+ { "BCM2EA9" },
+ { "BCM2EAA" },
+ { "BCM2EAB" },
+ { "BCM2EAC" },
{ },
};
MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
@@ -1146,6 +1297,12 @@ static int bcm_serdev_probe(struct serdev_device *serdev)
if (err)
return err;
+ if (!bcmdev->shutdown) {
+ dev_warn(&serdev->dev,
+ "No reset resource, using default baud rate\n");
+ bcmdev->oper_speed = bcmdev->init_speed;
+ }
+
err = bcm_gpio_set_power(bcmdev, false);
if (err)
dev_err(&serdev->dev, "Failed to power down\n");
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index 2f30dcad96bd..27e414b4e3a2 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -67,13 +67,6 @@
#define HCILL_WAKE_UP_IND 0x32
#define HCILL_WAKE_UP_ACK 0x33
-/* HCILL receiver States */
-#define HCILL_W4_PACKET_TYPE 0
-#define HCILL_W4_EVENT_HDR 1
-#define HCILL_W4_ACL_HDR 2
-#define HCILL_W4_SCO_HDR 3
-#define HCILL_W4_DATA 4
-
/* HCILL states */
enum hcill_states_e {
HCILL_ASLEEP,
@@ -82,10 +75,6 @@ enum hcill_states_e {
HCILL_AWAKE_TO_ASLEEP
};
-struct hcill_cmd {
- u8 cmd;
-} __packed;
-
struct ll_device {
struct hci_uart hu;
struct serdev_device *serdev;
@@ -95,8 +84,6 @@ struct ll_device {
};
struct ll_struct {
- unsigned long rx_state;
- unsigned long rx_count;
struct sk_buff *rx_skb;
struct sk_buff_head txq;
spinlock_t hcill_lock; /* HCILL state lock */
@@ -113,7 +100,6 @@ static int send_hcill_cmd(u8 cmd, struct hci_uart *hu)
int err = 0;
struct sk_buff *skb = NULL;
struct ll_struct *ll = hu->priv;
- struct hcill_cmd *hcill_packet;
BT_DBG("hu %p cmd 0x%x", hu, cmd);
@@ -126,8 +112,7 @@ static int send_hcill_cmd(u8 cmd, struct hci_uart *hu)
}
/* prepare packet */
- hcill_packet = skb_put(skb, 1);
- hcill_packet->cmd = cmd;
+ skb_put_u8(skb, cmd);
/* send packet */
skb_queue_tail(&ll->txq, skb);
@@ -379,155 +364,88 @@ static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
return 0;
}
-static inline int ll_check_data_len(struct hci_dev *hdev, struct ll_struct *ll, int len)
+static int ll_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
- int room = skb_tailroom(ll->rx_skb);
-
- BT_DBG("len %d room %d", len, room);
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+ struct ll_struct *ll = hu->priv;
- if (!len) {
- hci_recv_frame(hdev, ll->rx_skb);
- } else if (len > room) {
- BT_ERR("Data length is too large");
- kfree_skb(ll->rx_skb);
- } else {
- ll->rx_state = HCILL_W4_DATA;
- ll->rx_count = len;
- return len;
+ switch (hci_skb_pkt_type(skb)) {
+ case HCILL_GO_TO_SLEEP_IND:
+ BT_DBG("HCILL_GO_TO_SLEEP_IND packet");
+ ll_device_want_to_sleep(hu);
+ break;
+ case HCILL_GO_TO_SLEEP_ACK:
+ /* shouldn't happen */
+ bt_dev_err(hdev, "received HCILL_GO_TO_SLEEP_ACK in state %ld",
+ ll->hcill_state);
+ break;
+ case HCILL_WAKE_UP_IND:
+ BT_DBG("HCILL_WAKE_UP_IND packet");
+ ll_device_want_to_wakeup(hu);
+ break;
+ case HCILL_WAKE_UP_ACK:
+ BT_DBG("HCILL_WAKE_UP_ACK packet");
+ ll_device_woke_up(hu);
+ break;
}
- ll->rx_state = HCILL_W4_PACKET_TYPE;
- ll->rx_skb = NULL;
- ll->rx_count = 0;
-
+ kfree_skb(skb);
return 0;
}
+#define LL_RECV_SLEEP_IND \
+ .type = HCILL_GO_TO_SLEEP_IND, \
+ .hlen = 0, \
+ .loff = 0, \
+ .lsize = 0, \
+ .maxlen = 0
+
+#define LL_RECV_SLEEP_ACK \
+ .type = HCILL_GO_TO_SLEEP_ACK, \
+ .hlen = 0, \
+ .loff = 0, \
+ .lsize = 0, \
+ .maxlen = 0
+
+#define LL_RECV_WAKE_IND \
+ .type = HCILL_WAKE_UP_IND, \
+ .hlen = 0, \
+ .loff = 0, \
+ .lsize = 0, \
+ .maxlen = 0
+
+#define LL_RECV_WAKE_ACK \
+ .type = HCILL_WAKE_UP_ACK, \
+ .hlen = 0, \
+ .loff = 0, \
+ .lsize = 0, \
+ .maxlen = 0
+
+static const struct h4_recv_pkt ll_recv_pkts[] = {
+ { H4_RECV_ACL, .recv = hci_recv_frame },
+ { H4_RECV_SCO, .recv = hci_recv_frame },
+ { H4_RECV_EVENT, .recv = hci_recv_frame },
+ { LL_RECV_SLEEP_IND, .recv = ll_recv_frame },
+ { LL_RECV_SLEEP_ACK, .recv = ll_recv_frame },
+ { LL_RECV_WAKE_IND, .recv = ll_recv_frame },
+ { LL_RECV_WAKE_ACK, .recv = ll_recv_frame },
+};
+
/* Recv data */
static int ll_recv(struct hci_uart *hu, const void *data, int count)
{
struct ll_struct *ll = hu->priv;
- const char *ptr;
- struct hci_event_hdr *eh;
- struct hci_acl_hdr *ah;
- struct hci_sco_hdr *sh;
- int len, type, dlen;
-
- BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count);
-
- ptr = data;
- while (count) {
- if (ll->rx_count) {
- len = min_t(unsigned int, ll->rx_count, count);
- skb_put_data(ll->rx_skb, ptr, len);
- ll->rx_count -= len; count -= len; ptr += len;
-
- if (ll->rx_count)
- continue;
-
- switch (ll->rx_state) {
- case HCILL_W4_DATA:
- BT_DBG("Complete data");
- hci_recv_frame(hu->hdev, ll->rx_skb);
-
- ll->rx_state = HCILL_W4_PACKET_TYPE;
- ll->rx_skb = NULL;
- continue;
-
- case HCILL_W4_EVENT_HDR:
- eh = hci_event_hdr(ll->rx_skb);
-
- BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
- ll_check_data_len(hu->hdev, ll, eh->plen);
- continue;
+ if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
+ return -EUNATCH;
- case HCILL_W4_ACL_HDR:
- ah = hci_acl_hdr(ll->rx_skb);
- dlen = __le16_to_cpu(ah->dlen);
-
- BT_DBG("ACL header: dlen %d", dlen);
-
- ll_check_data_len(hu->hdev, ll, dlen);
- continue;
-
- case HCILL_W4_SCO_HDR:
- sh = hci_sco_hdr(ll->rx_skb);
-
- BT_DBG("SCO header: dlen %d", sh->dlen);
-
- ll_check_data_len(hu->hdev, ll, sh->dlen);
- continue;
- }
- }
-
- /* HCILL_W4_PACKET_TYPE */
- switch (*ptr) {
- case HCI_EVENT_PKT:
- BT_DBG("Event packet");
- ll->rx_state = HCILL_W4_EVENT_HDR;
- ll->rx_count = HCI_EVENT_HDR_SIZE;
- type = HCI_EVENT_PKT;
- break;
-
- case HCI_ACLDATA_PKT:
- BT_DBG("ACL packet");
- ll->rx_state = HCILL_W4_ACL_HDR;
- ll->rx_count = HCI_ACL_HDR_SIZE;
- type = HCI_ACLDATA_PKT;
- break;
-
- case HCI_SCODATA_PKT:
- BT_DBG("SCO packet");
- ll->rx_state = HCILL_W4_SCO_HDR;
- ll->rx_count = HCI_SCO_HDR_SIZE;
- type = HCI_SCODATA_PKT;
- break;
-
- /* HCILL signals */
- case HCILL_GO_TO_SLEEP_IND:
- BT_DBG("HCILL_GO_TO_SLEEP_IND packet");
- ll_device_want_to_sleep(hu);
- ptr++; count--;
- continue;
-
- case HCILL_GO_TO_SLEEP_ACK:
- /* shouldn't happen */
- BT_ERR("received HCILL_GO_TO_SLEEP_ACK (in state %ld)", ll->hcill_state);
- ptr++; count--;
- continue;
-
- case HCILL_WAKE_UP_IND:
- BT_DBG("HCILL_WAKE_UP_IND packet");
- ll_device_want_to_wakeup(hu);
- ptr++; count--;
- continue;
-
- case HCILL_WAKE_UP_ACK:
- BT_DBG("HCILL_WAKE_UP_ACK packet");
- ll_device_woke_up(hu);
- ptr++; count--;
- continue;
-
- default:
- BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
- hu->hdev->stat.err_rx++;
- ptr++; count--;
- continue;
- }
-
- ptr++; count--;
-
- /* Allocate packet */
- ll->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
- if (!ll->rx_skb) {
- BT_ERR("Can't allocate mem for new packet");
- ll->rx_state = HCILL_W4_PACKET_TYPE;
- ll->rx_count = 0;
- return -ENOMEM;
- }
-
- hci_skb_pkt_type(ll->rx_skb) = type;
+ ll->rx_skb = h4_recv_buf(hu->hdev, ll->rx_skb, data, count,
+ ll_recv_pkts, ARRAY_SIZE(ll_recv_pkts));
+ if (IS_ERR(ll->rx_skb)) {
+ int err = PTR_ERR(ll->rx_skb);
+ bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
+ ll->rx_skb = NULL;
+ return err;
}
return count;