Revert "CHROMIUM: Bluetooth: update stack to bluetooth-next"
This reverts commit 1e12643e9bec01a35da51dc7b1616333d2923189.
BUG=chrome-os-partner:48373
TEST=this caused 'hung task' reboots about ~120 seconds after boot when
loading bluetooth firmware fails, especially for marvell controllers
Change-Id: If61d1ea65271b705063664ee14f1fb0c0315ec3f
Reviewed-on: https://chromium-review.googlesource.com/317264
Commit-Ready: Jakub x Jakub Pawlowski <jpawlowski@chromium.org>
Tested-by: Jakub x Jakub Pawlowski <jpawlowski@chromium.org>
Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index ec6af15..3b099d5 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -4,20 +4,11 @@
config BT_INTEL
tristate
- select REGMAP
config BT_BCM
tristate
select FW_LOADER
-config BT_RTL
- tristate
- select FW_LOADER
-
-config BT_QCA
- tristate
- select FW_LOADER
-
config BT_HCIBTUSB
tristate "HCI USB driver"
depends on USB
@@ -41,17 +32,6 @@
Say Y here to compile support for Broadcom protocol.
-config BT_HCIBTUSB_RTL
- bool "Realtek protocol support"
- depends on BT_HCIBTUSB
- select BT_RTL
- default y
- help
- The Realtek protocol support enables firmware and configuration
- download support for Realtek Bluetooth controllers.
-
- Say Y here to compile support for Realtek protocol.
-
config BT_HCIBTSDIO
tristate "HCI SDIO driver"
depends on MMC
@@ -137,7 +117,6 @@
config BT_HCIUART_INTEL
bool "Intel protocol support"
depends on BT_HCIUART
- select BT_HCIUART_H4
select BT_INTEL
help
The Intel protocol support enables Bluetooth HCI over serial
@@ -156,19 +135,6 @@
Say Y here to compile support for Broadcom protocol.
-config BT_HCIUART_QCA
- bool "Qualcomm Atheros protocol support"
- depends on BT_HCIUART
- select BT_HCIUART_H4
- select BT_QCA
- help
- The Qualcomm Atheros protocol supports HCI In-Band Sleep feature
- over serial port interface(H4) between controller and host.
- This protocol is required for UART clock control for QCA Bluetooth
- devices.
-
- Say Y here to compile support for QCA protocol.
-
config BT_HCIBCM203X
tristate "HCI BCM203x USB driver"
depends on USB
@@ -183,8 +149,7 @@
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
@@ -277,7 +242,7 @@
The core driver to support Marvell Bluetooth devices.
This driver is required if you want to support
- Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897/8997.
+ Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897.
Say Y here to compile Marvell Bluetooth driver
into the kernel or say M to compile it as module.
@@ -291,7 +256,7 @@
The driver for Marvell Bluetooth chipsets with SDIO interface.
This driver is required if you want to use Marvell Bluetooth
- devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897/SD8997
+ devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897
chipsets are supported.
Say Y here to compile support for Marvell BT-over-SDIO driver
@@ -318,6 +283,5 @@
core driver to communicate with the BT core of the combo chip.
Say Y here to compile support for Texas Instrument's WiLink7 driver
- into the kernel or say M to compile it as module (btwilink).
-
+ into the kernel or say M to compile it as module.
endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 07c9cf3..dd0d9c4 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -21,8 +21,6 @@
obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
obj-$(CONFIG_BT_WILINK) += btwilink.o
obj-$(CONFIG_BT_BCM) += btbcm.o
-obj-$(CONFIG_BT_RTL) += btrtl.o
-obj-$(CONFIG_BT_QCA) += btqca.o
btmrvl-y := btmrvl_main.o
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
@@ -35,7 +33,6 @@
hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o
hci_uart-$(CONFIG_BT_HCIUART_INTEL) += hci_intel.o
hci_uart-$(CONFIG_BT_HCIUART_BCM) += hci_bcm.o
-hci_uart-$(CONFIG_BT_HCIUART_QCA) += hci_qca.o
hci_uart-objs := $(hci_uart-y)
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index fa893c3..c6848d3 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -80,7 +80,6 @@
{ USB_DEVICE(0x0489, 0xe057) },
{ USB_DEVICE(0x0489, 0xe056) },
{ USB_DEVICE(0x0489, 0xe05f) },
- { USB_DEVICE(0x0489, 0xe076) },
{ USB_DEVICE(0x0489, 0xe078) },
{ USB_DEVICE(0x04c5, 0x1330) },
{ USB_DEVICE(0x04CA, 0x3004) },
@@ -89,8 +88,6 @@
{ USB_DEVICE(0x04CA, 0x3007) },
{ USB_DEVICE(0x04CA, 0x3008) },
{ USB_DEVICE(0x04CA, 0x300b) },
- { USB_DEVICE(0x04CA, 0x300d) },
- { USB_DEVICE(0x04CA, 0x300f) },
{ USB_DEVICE(0x04CA, 0x3010) },
{ USB_DEVICE(0x0930, 0x0219) },
{ USB_DEVICE(0x0930, 0x021c) },
@@ -105,11 +102,9 @@
{ USB_DEVICE(0x0CF3, 0x311F) },
{ USB_DEVICE(0x0cf3, 0x3121) },
{ USB_DEVICE(0x0CF3, 0x817a) },
- { USB_DEVICE(0x0CF3, 0x817b) },
{ USB_DEVICE(0x0cf3, 0xe003) },
{ USB_DEVICE(0x0CF3, 0xE004) },
{ USB_DEVICE(0x0CF3, 0xE005) },
- { USB_DEVICE(0x0CF3, 0xE006) },
{ USB_DEVICE(0x13d3, 0x3362) },
{ USB_DEVICE(0x13d3, 0x3375) },
{ USB_DEVICE(0x13d3, 0x3393) },
@@ -117,7 +112,6 @@
{ USB_DEVICE(0x13d3, 0x3408) },
{ USB_DEVICE(0x13d3, 0x3423) },
{ USB_DEVICE(0x13d3, 0x3432) },
- { USB_DEVICE(0x13d3, 0x3474) },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
@@ -142,7 +136,6 @@
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
@@ -151,8 +144,6 @@
{ USB_DEVICE(0x04ca, 0x3007), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
@@ -167,10 +158,8 @@
{ USB_DEVICE(0x0cf3, 0x311F), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0CF3, 0x817b), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0xe006), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
@@ -179,7 +168,6 @@
{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 72d8bfa..fcfb72e 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -324,7 +324,7 @@
return -ENOMEM;
}
- hci_skb_pkt_type(skb) = pkt_type;
+ bt_cb(skb)->pkt_type = pkt_type;
data->reassembly = skb;
} else {
@@ -422,12 +422,17 @@
BT_DBG("hdev %p bfusb %p", hdev, data);
+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
write_lock_irqsave(&data->lock, flags);
err = bfusb_rx_submit(data, NULL);
if (!err) {
for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
bfusb_rx_submit(data, NULL);
+ } else {
+ clear_bit(HCI_RUNNING, &hdev->flags);
}
write_unlock_irqrestore(&data->lock, flags);
@@ -453,6 +458,9 @@
BT_DBG("hdev %p bfusb %p", hdev, data);
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
write_lock_irqsave(&data->lock, flags);
write_unlock_irqrestore(&data->lock, flags);
@@ -469,10 +477,12 @@
unsigned char buf[3];
int sent = 0, size, count;
- BT_DBG("hdev %p skb %p type %d len %d", hdev, skb,
- hci_skb_pkt_type(skb), skb->len);
+ BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, bt_cb(skb)->pkt_type, skb->len);
- switch (hci_skb_pkt_type(skb)) {
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+ switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;
break;
@@ -482,10 +492,10 @@
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);
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
count = skb->len;
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index c0b3b55..35e63aa 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -261,7 +261,7 @@
if (!skb)
break;
- if (hci_skb_pkt_type(skb) & 0x80) {
+ if (bt_cb(skb)->pkt_type & 0x80) {
/* Disable RTS */
info->ctrl_reg |= REG_CONTROL_RTS;
outb(info->ctrl_reg, iobase + REG_CONTROL);
@@ -279,13 +279,13 @@
/* Mark the buffer as dirty */
clear_bit(ready_bit, &(info->tx_state));
- if (hci_skb_pkt_type(skb) & 0x80) {
+ if (bt_cb(skb)->pkt_type & 0x80) {
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
DEFINE_WAIT(wait);
unsigned char baud_reg;
- switch (hci_skb_pkt_type(skb)) {
+ switch (bt_cb(skb)->pkt_type) {
case PKT_BAUD_RATE_460800:
baud_reg = REG_CONTROL_BAUD_RATE_460800;
break;
@@ -390,7 +390,7 @@
for (i = 0; i < len; i++) {
/* Allocate packet */
- if (!info->rx_skb) {
+ if (info->rx_skb == NULL) {
info->rx_state = RECV_WAIT_PACKET_TYPE;
info->rx_count = 0;
info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
@@ -402,9 +402,9 @@
if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
- hci_skb_pkt_type(info->rx_skb) = buf[i];
+ bt_cb(info->rx_skb)->pkt_type = buf[i];
- switch (hci_skb_pkt_type(info->rx_skb)) {
+ switch (bt_cb(info->rx_skb)->pkt_type) {
case 0x00:
/* init packet */
@@ -436,8 +436,7 @@
default:
/* unknown packet */
- BT_ERR("Unknown HCI packet with type 0x%02x received",
- hci_skb_pkt_type(info->rx_skb));
+ BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
info->hdev->stat.err_rx++;
kfree_skb(info->rx_skb);
@@ -579,21 +578,21 @@
switch (baud) {
case 460800:
cmd[4] = 0x00;
- hci_skb_pkt_type(skb) = PKT_BAUD_RATE_460800;
+ bt_cb(skb)->pkt_type = PKT_BAUD_RATE_460800;
break;
case 230400:
cmd[4] = 0x01;
- hci_skb_pkt_type(skb) = PKT_BAUD_RATE_230400;
+ bt_cb(skb)->pkt_type = PKT_BAUD_RATE_230400;
break;
case 115200:
cmd[4] = 0x02;
- hci_skb_pkt_type(skb) = PKT_BAUD_RATE_115200;
+ bt_cb(skb)->pkt_type = PKT_BAUD_RATE_115200;
break;
case 57600:
/* Fall through... */
default:
cmd[4] = 0x03;
- hci_skb_pkt_type(skb) = PKT_BAUD_RATE_57600;
+ bt_cb(skb)->pkt_type = PKT_BAUD_RATE_57600;
break;
}
@@ -629,6 +628,9 @@
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
+ if (test_and_set_bit(HCI_RUNNING, &(hdev->flags)))
+ return 0;
+
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) {
unsigned int iobase = info->p_dev->resource[0]->start;
@@ -644,6 +646,9 @@
{
struct bluecard_info *info = hci_get_drvdata(hdev);
+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
+ return 0;
+
bluecard_hci_flush(hdev);
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) {
@@ -661,7 +666,7 @@
{
struct bluecard_info *info = hci_get_drvdata(hdev);
- switch (hci_skb_pkt_type(skb)) {
+ switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;
break;
@@ -674,7 +679,7 @@
}
/* Prepend skb with frame type */
- memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
skb_queue_tail(&(info->txq), skb);
bluecard_write_wakeup(info);
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index fd6b53e..8a31991 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -35,9 +35,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
-#include "hci_uart.h"
-
-#define VERSION "0.11"
+#define VERSION "0.10"
static const struct usb_device_id bpa10x_table[] = {
/* Tektronix BPA 100/105 (Digianswer) */
@@ -58,6 +56,112 @@
struct sk_buff *rx_skb[2];
};
+#define HCI_VENDOR_HDR_SIZE 5
+
+struct hci_vendor_hdr {
+ __u8 type;
+ __le16 snum;
+ __le16 dlen;
+} __packed;
+
+static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
+{
+ struct bpa10x_data *data = hci_get_drvdata(hdev);
+
+ BT_DBG("%s queue %d buffer %p count %d", hdev->name,
+ queue, buf, count);
+
+ if (queue < 0 || queue > 1)
+ return -EILSEQ;
+
+ hdev->stat.byte_rx += count;
+
+ while (count) {
+ struct sk_buff *skb = data->rx_skb[queue];
+ struct { __u8 type; int expect; } *scb;
+ int type, len = 0;
+
+ if (!skb) {
+ /* Start of the frame */
+
+ type = *((__u8 *) buf);
+ count--; buf++;
+
+ switch (type) {
+ case HCI_EVENT_PKT:
+ if (count >= HCI_EVENT_HDR_SIZE) {
+ struct hci_event_hdr *h = buf;
+ len = HCI_EVENT_HDR_SIZE + h->plen;
+ } else
+ return -EILSEQ;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ if (count >= HCI_ACL_HDR_SIZE) {
+ struct hci_acl_hdr *h = buf;
+ len = HCI_ACL_HDR_SIZE +
+ __le16_to_cpu(h->dlen);
+ } else
+ return -EILSEQ;
+ break;
+
+ case HCI_SCODATA_PKT:
+ if (count >= HCI_SCO_HDR_SIZE) {
+ struct hci_sco_hdr *h = buf;
+ len = HCI_SCO_HDR_SIZE + h->dlen;
+ } else
+ return -EILSEQ;
+ break;
+
+ case HCI_VENDOR_PKT:
+ if (count >= HCI_VENDOR_HDR_SIZE) {
+ struct hci_vendor_hdr *h = buf;
+ len = HCI_VENDOR_HDR_SIZE +
+ __le16_to_cpu(h->dlen);
+ } else
+ return -EILSEQ;
+ break;
+ }
+
+ skb = bt_skb_alloc(len, GFP_ATOMIC);
+ if (!skb) {
+ BT_ERR("%s no memory for packet", hdev->name);
+ return -ENOMEM;
+ }
+
+ data->rx_skb[queue] = skb;
+
+ scb = (void *) skb->cb;
+ scb->type = type;
+ scb->expect = len;
+ } else {
+ /* Continuation */
+
+ scb = (void *) skb->cb;
+ len = scb->expect;
+ }
+
+ len = min(len, count);
+
+ memcpy(skb_put(skb, len), buf, len);
+
+ scb->expect -= len;
+
+ if (scb->expect == 0) {
+ /* Complete frame */
+
+ data->rx_skb[queue] = NULL;
+
+ bt_cb(skb)->pkt_type = scb->type;
+ hci_recv_frame(hdev, skb);
+ }
+
+ count -= len; buf += len;
+ }
+
+ return 0;
+}
+
static void bpa10x_tx_complete(struct urb *urb)
{
struct sk_buff *skb = urb->context;
@@ -80,22 +184,6 @@
kfree_skb(skb);
}
-#define HCI_VENDOR_HDR_SIZE 5
-
-#define HCI_RECV_VENDOR \
- .type = HCI_VENDOR_PKT, \
- .hlen = HCI_VENDOR_HDR_SIZE, \
- .loff = 3, \
- .lsize = 2, \
- .maxlen = HCI_MAX_FRAME_SIZE
-
-static const struct h4_recv_pkt bpa10x_recv_pkts[] = {
- { H4_RECV_ACL, .recv = hci_recv_frame },
- { H4_RECV_SCO, .recv = hci_recv_frame },
- { H4_RECV_EVENT, .recv = hci_recv_frame },
- { HCI_RECV_VENDOR, .recv = hci_recv_diag },
-};
-
static void bpa10x_rx_complete(struct urb *urb)
{
struct hci_dev *hdev = urb->context;
@@ -109,17 +197,11 @@
return;
if (urb->status == 0) {
- bool idx = usb_pipebulk(urb->pipe);
-
- data->rx_skb[idx] = h4_recv_buf(hdev, data->rx_skb[idx],
+ if (bpa10x_recv(hdev, usb_pipebulk(urb->pipe),
urb->transfer_buffer,
- urb->actual_length,
- bpa10x_recv_pkts,
- ARRAY_SIZE(bpa10x_recv_pkts));
- if (IS_ERR(data->rx_skb[idx])) {
+ urb->actual_length) < 0) {
BT_ERR("%s corrupted event packet", hdev->name);
hdev->stat.err_rx++;
- data->rx_skb[idx] = NULL;
}
}
@@ -222,6 +304,9 @@
BT_DBG("%s", hdev->name);
+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
err = bpa10x_submit_intr_urb(hdev);
if (err < 0)
goto error;
@@ -235,6 +320,8 @@
error:
usb_kill_anchored_urbs(&data->rx_anchor);
+ clear_bit(HCI_RUNNING, &hdev->flags);
+
return err;
}
@@ -244,6 +331,9 @@
BT_DBG("%s", hdev->name);
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
usb_kill_anchored_urbs(&data->rx_anchor);
return 0;
@@ -260,24 +350,6 @@
return 0;
}
-static int bpa10x_setup(struct hci_dev *hdev)
-{
- const u8 req[] = { 0x07 };
- struct sk_buff *skb;
-
- BT_DBG("%s", hdev->name);
-
- /* Read revision string */
- skb = __hci_cmd_sync(hdev, 0xfc0e, sizeof(req), req, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
-
- kfree_skb(skb);
- return 0;
-}
-
static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
struct bpa10x_data *data = hci_get_drvdata(hdev);
@@ -288,6 +360,9 @@
BT_DBG("%s", hdev->name);
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
skb->dev = (void *) hdev;
urb = usb_alloc_urb(0, GFP_ATOMIC);
@@ -295,9 +370,9 @@
return -ENOMEM;
/* Prepend skb with frame type */
- *skb_push(skb, 1) = hci_skb_pkt_type(skb);
+ *skb_push(skb, 1) = bt_cb(skb)->pkt_type;
- switch (hci_skb_pkt_type(skb)) {
+ switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
if (!dr) {
@@ -356,25 +431,6 @@
return 0;
}
-static int bpa10x_set_diag(struct hci_dev *hdev, bool enable)
-{
- const u8 req[] = { 0x00, enable };
- struct sk_buff *skb;
-
- BT_DBG("%s", hdev->name);
-
- if (!test_bit(HCI_RUNNING, &hdev->flags))
- return -ENETDOWN;
-
- /* Enable sniffer operation */
- skb = __hci_cmd_sync(hdev, 0xfc0e, sizeof(req), req, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- kfree_skb(skb);
- return 0;
-}
-
static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct bpa10x_data *data;
@@ -409,9 +465,7 @@
hdev->open = bpa10x_open;
hdev->close = bpa10x_close;
hdev->flush = bpa10x_flush;
- hdev->setup = bpa10x_setup;
hdev->send = bpa10x_send_frame;
- hdev->set_diag = bpa10x_set_diag;
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 8165ef2..6de97b3 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -202,8 +202,9 @@
/* Send frame */
len = bt3c_write(iobase, 256, skb->data, skb->len);
- if (len != skb->len)
+ if (len != skb->len) {
BT_ERR("Very strange");
+ }
kfree_skb(skb);
@@ -233,7 +234,7 @@
info->hdev->stat.byte_rx++;
/* Allocate packet */
- if (!info->rx_skb) {
+ if (info->rx_skb == NULL) {
info->rx_state = RECV_WAIT_PACKET_TYPE;
info->rx_count = 0;
info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
@@ -246,10 +247,10 @@
if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
- hci_skb_pkt_type(info->rx_skb) = inb(iobase + DATA_L);
+ bt_cb(info->rx_skb)->pkt_type = inb(iobase + DATA_L);
inb(iobase + DATA_H);
- switch (hci_skb_pkt_type(info->rx_skb)) {
+ switch (bt_cb(info->rx_skb)->pkt_type) {
case HCI_EVENT_PKT:
info->rx_state = RECV_WAIT_EVENT_HEADER;
@@ -268,9 +269,9 @@
default:
/* Unknown packet */
- BT_ERR("Unknown HCI packet with type 0x%02x received",
- hci_skb_pkt_type(info->rx_skb));
+ BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
info->hdev->stat.err_rx++;
+ clear_bit(HCI_RUNNING, &(info->hdev->flags));
kfree_skb(info->rx_skb);
info->rx_skb = NULL;
@@ -395,12 +396,17 @@
static int bt3c_hci_open(struct hci_dev *hdev)
{
+ set_bit(HCI_RUNNING, &(hdev->flags));
+
return 0;
}
static int bt3c_hci_close(struct hci_dev *hdev)
{
+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
+ return 0;
+
bt3c_hci_flush(hdev);
return 0;
@@ -412,7 +418,7 @@
struct bt3c_info *info = hci_get_drvdata(hdev);
unsigned long flags;
- switch (hci_skb_pkt_type(skb)) {
+ switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;
break;
@@ -422,10 +428,10 @@
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);
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
skb_queue_tail(&(info->txq), skb);
spin_lock_irqsave(&(info->lock), flags);
@@ -448,8 +454,7 @@
{
char *ptr = (char *) firmware;
char b[9];
- unsigned int iobase, tmp;
- unsigned long size, addr, fcs;
+ unsigned int iobase, size, addr, fcs, tmp;
int i, err = 0;
iobase = info->p_dev->resource[0]->start;
@@ -474,18 +479,15 @@
memset(b, 0, sizeof(b));
memcpy(b, ptr + 2, 2);
- if (kstrtoul(b, 16, &size) < 0)
- return -EINVAL;
+ size = simple_strtoul(b, NULL, 16);
memset(b, 0, sizeof(b));
memcpy(b, ptr + 4, 8);
- if (kstrtoul(b, 16, &addr) < 0)
- return -EINVAL;
+ addr = simple_strtoul(b, NULL, 16);
memset(b, 0, sizeof(b));
memcpy(b, ptr + (size * 2) + 2, 2);
- if (kstrtoul(b, 16, &fcs) < 0)
- return -EINVAL;
+ fcs = simple_strtoul(b, NULL, 16);
memset(b, 0, sizeof(b));
for (tmp = 0, i = 0; i < size; i++) {
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index 0b69794..4bba866 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -33,8 +33,6 @@
#define VERSION "0.1"
#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
-#define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}})
-#define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}})
int btbcm_check_bdaddr(struct hci_dev *hdev)
{
@@ -57,23 +55,17 @@
}
bda = (struct hci_rp_read_bd_addr *)skb->data;
+ if (bda->status) {
+ BT_ERR("%s: BCM: Device address result failed (%02x)",
+ hdev->name, bda->status);
+ kfree_skb(skb);
+ return -bt_to_errno(bda->status);
+ }
- /* Check if the address indicates a controller with either an
- * invalid or default address. In both cases the device needs
- * to be marked as not having a valid address.
- *
- * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller
+ /* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller
* with no configured address.
- *
- * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller
- * with waiting for configuration state.
- *
- * The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller
- * with waiting for configuration state.
*/
- if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) ||
- !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) ||
- !bacmp(&bda->bdaddr, BDADDR_BCM4330B1)) {
+ if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) {
BT_INFO("%s: BCM: Using default device address (%pMR)",
hdev->name, &bda->bdaddr);
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
@@ -103,14 +95,21 @@
}
EXPORT_SYMBOL_GPL(btbcm_set_bdaddr);
-int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw)
+int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
{
const struct hci_command_hdr *cmd;
+ const struct firmware *fw;
const u8 *fw_ptr;
size_t fw_size;
struct sk_buff *skb;
u16 opcode;
- int err = 0;
+ int err;
+
+ err = request_firmware(&fw, firmware, &hdev->dev);
+ if (err < 0) {
+ BT_INFO("%s: BCM: Patch %s not found", hdev->name, firmware);
+ return err;
+ }
/* Start Download */
skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
@@ -136,7 +135,8 @@
fw_size -= sizeof(*cmd);
if (fw_size < cmd->plen) {
- BT_ERR("%s: BCM: Patch is corrupted", hdev->name);
+ BT_ERR("%s: BCM: Patch %s is corrupted", hdev->name,
+ firmware);
err = -EINVAL;
goto done;
}
@@ -162,6 +162,7 @@
msleep(250);
done:
+ release_firmware(fw);
return err;
}
EXPORT_SYMBOL(btbcm_patchram);
@@ -181,27 +182,6 @@
return 0;
}
-static struct sk_buff *btbcm_read_local_name(struct hci_dev *hdev)
-{
- struct sk_buff *skb;
-
- skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- BT_ERR("%s: BCM: Reading local name failed (%ld)",
- hdev->name, PTR_ERR(skb));
- return skb;
- }
-
- if (skb->len != sizeof(struct hci_rp_read_local_name)) {
- BT_ERR("%s: BCM: Local name length mismatch", hdev->name);
- kfree_skb(skb);
- return ERR_PTR(-EIO);
- }
-
- return skb;
-}
-
static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev)
{
struct sk_buff *skb;
@@ -267,103 +247,10 @@
u16 subver;
const char *name;
} bcm_uart_subver_table[] = {
- { 0x4103, "BCM4330B1" }, /* 002.001.003 */
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */
- { 0x4406, "BCM4324B3" }, /* 002.004.006 */
- { 0x610c, "BCM4354" }, /* 003.001.012 */
{ }
};
-int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len)
-{
- u16 subver, rev;
- const char *hw_name = NULL;
- struct sk_buff *skb;
- struct hci_rp_read_local_version *ver;
- int i, err;
-
- /* Reset */
- err = btbcm_reset(hdev);
- if (err)
- return err;
-
- /* Read Local Version Info */
- skb = btbcm_read_local_version(hdev);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- ver = (struct hci_rp_read_local_version *)skb->data;
- rev = le16_to_cpu(ver->hci_rev);
- subver = le16_to_cpu(ver->lmp_subver);
- kfree_skb(skb);
-
- /* Read Verbose Config Version Info */
- skb = btbcm_read_verbose_config(hdev);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]);
- kfree_skb(skb);
-
- switch ((rev & 0xf000) >> 12) {
- case 0:
- case 1:
- case 3:
- for (i = 0; bcm_uart_subver_table[i].name; i++) {
- if (subver == bcm_uart_subver_table[i].subver) {
- hw_name = bcm_uart_subver_table[i].name;
- break;
- }
- }
-
- snprintf(fw_name, len, "brcm/%s.hcd", hw_name ? : "BCM");
- break;
- default:
- return 0;
- }
-
- BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
- hw_name ? : "BCM", (subver & 0xe000) >> 13,
- (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(btbcm_initialize);
-
-int btbcm_finalize(struct hci_dev *hdev)
-{
- struct sk_buff *skb;
- struct hci_rp_read_local_version *ver;
- u16 subver, rev;
- int err;
-
- /* Reset */
- err = btbcm_reset(hdev);
- if (err)
- return err;
-
- /* Read Local Version Info */
- skb = btbcm_read_local_version(hdev);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- ver = (struct hci_rp_read_local_version *)skb->data;
- rev = le16_to_cpu(ver->hci_rev);
- subver = le16_to_cpu(ver->lmp_subver);
- kfree_skb(skb);
-
- BT_INFO("%s: BCM (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
- (subver & 0xe000) >> 13, (subver & 0x1f00) >> 8,
- (subver & 0x00ff), rev & 0x0fff);
-
- btbcm_check_bdaddr(hdev);
-
- set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(btbcm_finalize);
-
static const struct {
u16 subver;
const char *name;
@@ -384,7 +271,6 @@
int btbcm_setup_patchram(struct hci_dev *hdev)
{
char fw_name[64];
- const struct firmware *fw;
u16 subver, rev, pid, vid;
const char *hw_name = NULL;
struct sk_buff *skb;
@@ -414,17 +300,8 @@
BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]);
kfree_skb(skb);
- /* Read Local Name */
- skb = btbcm_read_local_name(hdev);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
- kfree_skb(skb);
-
switch ((rev & 0xf000) >> 12) {
case 0:
- case 3:
for (i = 0; bcm_uart_subver_table[i].name; i++) {
if (subver == bcm_uart_subver_table[i].subver) {
hw_name = bcm_uart_subver_table[i].name;
@@ -461,18 +338,12 @@
}
BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
- hw_name ? : "BCM", (subver & 0xe000) >> 13,
+ hw_name ? : "BCM", (subver & 0x7000) >> 13,
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
- err = request_firmware(&fw, fw_name, &hdev->dev);
- if (err < 0) {
- BT_INFO("%s: BCM: Patch %s not found", hdev->name, fw_name);
+ err = btbcm_patchram(hdev, fw_name);
+ if (err == -ENOENT)
return 0;
- }
-
- btbcm_patchram(hdev, fw);
-
- release_firmware(fw);
/* Reset */
err = btbcm_reset(hdev);
@@ -490,17 +361,9 @@
kfree_skb(skb);
BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
- hw_name ? : "BCM", (subver & 0xe000) >> 13,
+ hw_name ? : "BCM", (subver & 0x7000) >> 13,
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
- /* Read Local Name */
- skb = btbcm_read_local_name(hdev);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
- kfree_skb(skb);
-
btbcm_check_bdaddr(hdev);
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
@@ -512,36 +375,15 @@
int btbcm_setup_apple(struct hci_dev *hdev)
{
struct sk_buff *skb;
- int err;
-
- /* Reset */
- err = btbcm_reset(hdev);
- if (err)
- return err;
/* Read Verbose Config Version Info */
skb = btbcm_read_verbose_config(hdev);
- if (!IS_ERR(skb)) {
- BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name,
- skb->data[1], get_unaligned_le16(skb->data + 5));
- kfree_skb(skb);
- }
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
- /* Read USB Product Info */
- skb = btbcm_read_usb_product(hdev);
- if (!IS_ERR(skb)) {
- BT_INFO("%s: BCM: product %4.4x:%4.4x", hdev->name,
- get_unaligned_le16(skb->data + 1),
- get_unaligned_le16(skb->data + 3));
- kfree_skb(skb);
- }
-
- /* Read Local Name */
- skb = btbcm_read_local_name(hdev);
- if (!IS_ERR(skb)) {
- BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
- kfree_skb(skb);
- }
+ BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1],
+ get_unaligned_le16(skb->data + 5));
+ kfree_skb(skb);
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h
index d9e6b41..eb6ab5f 100644
--- a/drivers/bluetooth/btbcm.h
+++ b/drivers/bluetooth/btbcm.h
@@ -21,61 +21,15 @@
*
*/
-#define BCM_UART_CLOCK_48MHZ 0x01
-#define BCM_UART_CLOCK_24MHZ 0x02
-
-struct bcm_update_uart_baud_rate {
- __le16 zero;
- __le32 baud_rate;
-} __packed;
-
-struct bcm_write_uart_clock_setting {
- __u8 type;
-} __packed;
-
-struct bcm_set_sleep_mode {
- __u8 sleep_mode;
- __u8 idle_host;
- __u8 idle_dev;
- __u8 bt_wake_active;
- __u8 host_wake_active;
- __u8 allow_host_sleep;
- __u8 combine_modes;
- __u8 tristate_control;
- __u8 usb_auto_sleep;
- __u8 usb_resume_timeout;
- __u8 pulsed_host_wake;
- __u8 break_to_host;
-} __packed;
-
-struct bcm_set_pcm_int_params {
- __u8 routing;
- __u8 rate;
- __u8 frame_sync;
- __u8 sync_mode;
- __u8 clock_mode;
-} __packed;
-
-struct bcm_set_pcm_format_params {
- __u8 lsb_first;
- __u8 fill_value;
- __u8 fill_method;
- __u8 fill_num;
- __u8 right_justify;
-} __packed;
-
#if IS_ENABLED(CONFIG_BT_BCM)
int btbcm_check_bdaddr(struct hci_dev *hdev);
int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
-int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw);
+int btbcm_patchram(struct hci_dev *hdev, const char *firmware);
int btbcm_setup_patchram(struct hci_dev *hdev);
int btbcm_setup_apple(struct hci_dev *hdev);
-int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len);
-int btbcm_finalize(struct hci_dev *hdev);
-
#else
static inline int btbcm_check_bdaddr(struct hci_dev *hdev)
@@ -88,7 +42,7 @@
return -EOPNOTSUPP;
}
-static inline int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw)
+static inline int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
{
return -EOPNOTSUPP;
}
@@ -103,15 +57,4 @@
return 0;
}
-static inline int btbcm_initialize(struct hci_dev *hdev, char *fw_name,
- size_t len)
-{
- return 0;
-}
-
-static inline int btbcm_finalize(struct hci_dev *hdev)
-{
- return 0;
-}
-
#endif
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 1f13e61..2d43d42 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -22,8 +22,6 @@
*/
#include <linux/module.h>
-#include <linux/firmware.h>
-#include <linux/regmap.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -55,6 +53,12 @@
}
bda = (struct hci_rp_read_bd_addr *)skb->data;
+ if (bda->status) {
+ BT_ERR("%s: Intel device address result failed (%02x)",
+ hdev->name, bda->status);
+ kfree_skb(skb);
+ return -bt_to_errno(bda->status);
+ }
/* For some Intel based controllers, the default Bluetooth device
* address 00:03:19:9E:8B:00 can be found. These controllers are
@@ -91,456 +95,7 @@
}
EXPORT_SYMBOL_GPL(btintel_set_bdaddr);
-int btintel_set_diag(struct hci_dev *hdev, bool enable)
-{
- struct sk_buff *skb;
- u8 param[3];
- int err;
-
- if (enable) {
- param[0] = 0x03;
- param[1] = 0x03;
- param[2] = 0x03;
- } else {
- param[0] = 0x00;
- param[1] = 0x00;
- param[2] = 0x00;
- }
-
- skb = __hci_cmd_sync(hdev, 0xfc43, 3, param, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- if (err == -ENODATA)
- goto done;
- BT_ERR("%s: Changing Intel diagnostic mode failed (%d)",
- hdev->name, err);
- return err;
- }
- kfree_skb(skb);
-
-done:
- btintel_set_event_mask(hdev, enable);
- return 0;
-}
-EXPORT_SYMBOL_GPL(btintel_set_diag);
-
-int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable)
-{
- struct sk_buff *skb;
- u8 param[2];
- int err;
-
- param[0] = 0x01;
- param[1] = 0x00;
-
- skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- BT_ERR("%s: Entering Intel manufacturer mode failed (%d)",
- hdev->name, err);
- return PTR_ERR(skb);
- }
- kfree_skb(skb);
-
- err = btintel_set_diag(hdev, enable);
-
- param[0] = 0x00;
- param[1] = 0x00;
-
- skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- BT_ERR("%s: Leaving Intel manufacturer mode failed (%d)",
- hdev->name, err);
- return PTR_ERR(skb);
- }
- kfree_skb(skb);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(btintel_set_diag_mfg);
-
-void btintel_hw_error(struct hci_dev *hdev, u8 code)
-{
- struct sk_buff *skb;
- u8 type = 0x00;
-
- BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code);
-
- skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- BT_ERR("%s: Reset after hardware error failed (%ld)",
- hdev->name, PTR_ERR(skb));
- return;
- }
- kfree_skb(skb);
-
- skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- BT_ERR("%s: Retrieving Intel exception info failed (%ld)",
- hdev->name, PTR_ERR(skb));
- return;
- }
-
- if (skb->len != 13) {
- BT_ERR("%s: Exception info size mismatch", hdev->name);
- kfree_skb(skb);
- return;
- }
-
- BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1));
-
- kfree_skb(skb);
-}
-EXPORT_SYMBOL_GPL(btintel_hw_error);
-
-void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
-{
- const char *variant;
-
- switch (ver->fw_variant) {
- case 0x06:
- variant = "Bootloader";
- break;
- case 0x23:
- variant = "Firmware";
- break;
- default:
- return;
- }
-
- BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name,
- variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,
- ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy);
-}
-EXPORT_SYMBOL_GPL(btintel_version_info);
-
-int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
- const void *param)
-{
- while (plen > 0) {
- struct sk_buff *skb;
- u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen;
-
- cmd_param[0] = fragment_type;
- memcpy(cmd_param + 1, param, fragment_len);
-
- skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1,
- cmd_param, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- kfree_skb(skb);
-
- plen -= fragment_len;
- param += fragment_len;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(btintel_secure_send);
-
-int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name)
-{
- const struct firmware *fw;
- struct sk_buff *skb;
- const u8 *fw_ptr;
- int err;
-
- err = request_firmware_direct(&fw, ddc_name, &hdev->dev);
- if (err < 0) {
- bt_dev_err(hdev, "Failed to load Intel DDC file %s (%d)",
- ddc_name, err);
- return err;
- }
-
- bt_dev_info(hdev, "Found Intel DDC parameters: %s", ddc_name);
-
- fw_ptr = fw->data;
-
- /* DDC file contains one or more DDC structure which has
- * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2).
- */
- while (fw->size > fw_ptr - fw->data) {
- u8 cmd_plen = fw_ptr[0] + sizeof(u8);
-
- skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- bt_dev_err(hdev, "Failed to send Intel_Write_DDC (%ld)",
- PTR_ERR(skb));
- release_firmware(fw);
- return PTR_ERR(skb);
- }
-
- fw_ptr += cmd_plen;
- kfree_skb(skb);
- }
-
- release_firmware(fw);
-
- bt_dev_info(hdev, "Applying Intel DDC parameters completed");
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(btintel_load_ddc_config);
-
-int btintel_set_event_mask(struct hci_dev *hdev, bool debug)
-{
- u8 mask[8] = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- struct sk_buff *skb;
- int err;
-
- if (debug)
- mask[1] |= 0x62;
-
- skb = __hci_cmd_sync(hdev, 0xfc52, 8, mask, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- BT_ERR("%s: Setting Intel event mask failed (%d)",
- hdev->name, err);
- return err;
- }
- kfree_skb(skb);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(btintel_set_event_mask);
-
-int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug)
-{
- struct sk_buff *skb;
- u8 param[2];
- int err;
-
- param[0] = 0x01;
- param[1] = 0x00;
-
- skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- BT_ERR("%s: Entering Intel manufacturer mode failed (%d)",
- hdev->name, err);
- return PTR_ERR(skb);
- }
- kfree_skb(skb);
-
- err = btintel_set_event_mask(hdev, debug);
-
- param[0] = 0x00;
- param[1] = 0x00;
-
- skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- BT_ERR("%s: Leaving Intel manufacturer mode failed (%d)",
- hdev->name, err);
- return PTR_ERR(skb);
- }
- kfree_skb(skb);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(btintel_set_event_mask_mfg);
-
-/* ------- REGMAP IBT SUPPORT ------- */
-
-#define IBT_REG_MODE_8BIT 0x00
-#define IBT_REG_MODE_16BIT 0x01
-#define IBT_REG_MODE_32BIT 0x02
-
-struct regmap_ibt_context {
- struct hci_dev *hdev;
- __u16 op_write;
- __u16 op_read;
-};
-
-struct ibt_cp_reg_access {
- __le32 addr;
- __u8 mode;
- __u8 len;
- __u8 data[0];
-} __packed;
-
-struct ibt_rp_reg_access {
- __u8 status;
- __le32 addr;
- __u8 data[0];
-} __packed;
-
-static int regmap_ibt_read(void *context, const void *addr, size_t reg_size,
- void *val, size_t val_size)
-{
- struct regmap_ibt_context *ctx = context;
- struct ibt_cp_reg_access cp;
- struct ibt_rp_reg_access *rp;
- struct sk_buff *skb;
- int err = 0;
-
- if (reg_size != sizeof(__le32))
- return -EINVAL;
-
- switch (val_size) {
- case 1:
- cp.mode = IBT_REG_MODE_8BIT;
- break;
- case 2:
- cp.mode = IBT_REG_MODE_16BIT;
- break;
- case 4:
- cp.mode = IBT_REG_MODE_32BIT;
- break;
- default:
- return -EINVAL;
- }
-
- /* regmap provides a little-endian formatted addr */
- cp.addr = *(__le32 *)addr;
- cp.len = val_size;
-
- bt_dev_dbg(ctx->hdev, "Register (0x%x) read", le32_to_cpu(cp.addr));
-
- skb = hci_cmd_sync(ctx->hdev, ctx->op_read, sizeof(cp), &cp,
- HCI_CMD_TIMEOUT);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error (%d)",
- le32_to_cpu(cp.addr), err);
- return err;
- }
-
- if (skb->len != sizeof(*rp) + val_size) {
- bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error, bad len",
- le32_to_cpu(cp.addr));
- err = -EINVAL;
- goto done;
- }
-
- rp = (struct ibt_rp_reg_access *)skb->data;
-
- if (rp->addr != cp.addr) {
- bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error, bad addr",
- le32_to_cpu(rp->addr));
- err = -EINVAL;
- goto done;
- }
-
- memcpy(val, rp->data, val_size);
-
-done:
- kfree_skb(skb);
- return err;
-}
-
-static int regmap_ibt_gather_write(void *context,
- const void *addr, size_t reg_size,
- const void *val, size_t val_size)
-{
- struct regmap_ibt_context *ctx = context;
- struct ibt_cp_reg_access *cp;
- struct sk_buff *skb;
- int plen = sizeof(*cp) + val_size;
- u8 mode;
- int err = 0;
-
- if (reg_size != sizeof(__le32))
- return -EINVAL;
-
- switch (val_size) {
- case 1:
- mode = IBT_REG_MODE_8BIT;
- break;
- case 2:
- mode = IBT_REG_MODE_16BIT;
- break;
- case 4:
- mode = IBT_REG_MODE_32BIT;
- break;
- default:
- return -EINVAL;
- }
-
- cp = kmalloc(plen, GFP_KERNEL);
- if (!cp)
- return -ENOMEM;
-
- /* regmap provides a little-endian formatted addr/value */
- cp->addr = *(__le32 *)addr;
- cp->mode = mode;
- cp->len = val_size;
- memcpy(&cp->data, val, val_size);
-
- bt_dev_dbg(ctx->hdev, "Register (0x%x) write", le32_to_cpu(cp->addr));
-
- skb = hci_cmd_sync(ctx->hdev, ctx->op_write, plen, cp, HCI_CMD_TIMEOUT);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- bt_dev_err(ctx->hdev, "regmap: Register (0x%x) write error (%d)",
- le32_to_cpu(cp->addr), err);
- goto done;
- }
- kfree_skb(skb);
-
-done:
- kfree(cp);
- return err;
-}
-
-static int regmap_ibt_write(void *context, const void *data, size_t count)
-{
- /* data contains register+value, since we only support 32bit addr,
- * minimum data size is 4 bytes.
- */
- if (WARN_ONCE(count < 4, "Invalid register access"))
- return -EINVAL;
-
- return regmap_ibt_gather_write(context, data, 4, data + 4, count - 4);
-}
-
-static void regmap_ibt_free_context(void *context)
-{
- kfree(context);
-}
-
-static struct regmap_bus regmap_ibt = {
- .read = regmap_ibt_read,
- .write = regmap_ibt_write,
- .gather_write = regmap_ibt_gather_write,
- .free_context = regmap_ibt_free_context,
- .reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
- .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
-};
-
-/* Config is the same for all register regions */
-static const struct regmap_config regmap_ibt_cfg = {
- .name = "btintel_regmap",
- .reg_bits = 32,
- .val_bits = 32,
-};
-
-struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
- u16 opcode_write)
-{
- struct regmap_ibt_context *ctx;
-
- bt_dev_info(hdev, "regmap: Init R%x-W%x region", opcode_read,
- opcode_write);
-
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return ERR_PTR(-ENOMEM);
-
- ctx->op_read = opcode_read;
- ctx->op_write = opcode_write;
- ctx->hdev = hdev;
-
- return regmap_init(&hdev->dev, ®map_ibt, ctx, ®map_ibt_cfg);
-}
-EXPORT_SYMBOL_GPL(btintel_regmap_init);
-
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("intel/ibt-11-5.sfi");
-MODULE_FIRMWARE("intel/ibt-11-5.ddc");
diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
index 07e58e0..4bda6ab 100644
--- a/drivers/bluetooth/btintel.h
+++ b/drivers/bluetooth/btintel.h
@@ -73,19 +73,6 @@
int btintel_check_bdaddr(struct hci_dev *hdev);
int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
-int btintel_set_diag(struct hci_dev *hdev, bool enable);
-int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable);
-void btintel_hw_error(struct hci_dev *hdev, u8 code);
-
-void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver);
-int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
- const void *param);
-int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name);
-int btintel_set_event_mask(struct hci_dev *hdev, bool debug);
-int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug);
-
-struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
- u16 opcode_write);
#else
@@ -99,51 +86,4 @@
return -EOPNOTSUPP;
}
-static inline int btintel_set_diag(struct hci_dev *hdev, bool enable)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable)
-{
- return -EOPNOTSUPP;
-}
-
-static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
-{
-}
-
-static inline void btintel_version_info(struct hci_dev *hdev,
- struct intel_version *ver)
-{
-}
-
-static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type,
- u32 plen, const void *param)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int btintel_load_ddc_config(struct hci_dev *hdev,
- const char *ddc_name)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int btintel_set_event_mask(struct hci_dev *hdev, bool debug)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug)
-{
- return -EOPNOTSUPP;
-}
-
-static inline struct regmap *btintel_regmap_init(struct hci_dev *hdev,
- u16 opcode_read,
- u16 opcode_write)
-{
- return ERR_PTR(-EINVAL);
-}
#endif
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index 27a9aac..a1167e4 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -89,16 +89,17 @@
wait_queue_head_t event_hs_wait_q;
u8 cmd_complete;
bool is_suspended;
+ bool is_suspending;
};
struct btmrvl_private {
struct btmrvl_device btmrvl_dev;
struct btmrvl_adapter *adapter;
struct btmrvl_thread main_thread;
- int (*hw_host_to_card)(struct btmrvl_private *priv,
+ int (*hw_host_to_card) (struct btmrvl_private *priv,
u8 *payload, u16 nb);
- int (*hw_wakeup_firmware)(struct btmrvl_private *priv);
- int (*hw_process_int_status)(struct btmrvl_private *priv);
+ int (*hw_wakeup_firmware) (struct btmrvl_private *priv);
+ int (*hw_process_int_status) (struct btmrvl_private *priv);
void (*firmware_dump)(struct btmrvl_private *priv);
spinlock_t driver_lock; /* spinlock used by driver */
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index f2b38c8..3423b113 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -184,7 +184,7 @@
}
skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_ATOMIC);
- if (!skb) {
+ if (skb == NULL) {
BT_ERR("No free skb");
return -ENOMEM;
}
@@ -196,7 +196,7 @@
if (len)
memcpy(skb_put(skb, len), param, len);
- hci_skb_pkt_type(skb) = MRVL_VENDOR_PKT;
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
skb_queue_head(&priv->adapter->tx_queue, skb);
@@ -377,6 +377,20 @@
return -EINVAL;
}
+ if (skb_headroom(skb) < BTM_HEADER_LEN) {
+ struct sk_buff *tmp = skb;
+
+ skb = skb_realloc_headroom(skb, BTM_HEADER_LEN);
+ if (!skb) {
+ BT_ERR("Tx Error: realloc_headroom failed %d",
+ BTM_HEADER_LEN);
+ skb = tmp;
+ return -EINVAL;
+ }
+
+ kfree_skb(tmp);
+ }
+
skb_push(skb, BTM_HEADER_LEN);
/* header type: byte[3]
@@ -387,7 +401,7 @@
skb->data[0] = (skb->len & 0x0000ff);
skb->data[1] = (skb->len & 0x00ff00) >> 8;
skb->data[2] = (skb->len & 0xff0000) >> 16;
- skb->data[3] = hci_skb_pkt_type(skb);
+ skb->data[3] = bt_cb(skb)->pkt_type;
if (priv->hw_host_to_card)
ret = priv->hw_host_to_card(priv, skb->data, skb->len);
@@ -434,9 +448,21 @@
{
struct btmrvl_private *priv = hci_get_drvdata(hdev);
- BT_DBG("type=%d, len=%d", hci_skb_pkt_type(skb), skb->len);
+ if (priv->adapter->is_suspending || priv->adapter->is_suspended) {
+ BT_ERR("%s: Device is suspending or suspended", __func__);
+ return -EBUSY;
+ }
- switch (hci_skb_pkt_type(skb)) {
+ BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len);
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags);
+ print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET,
+ skb->data, skb->len);
+ return -EBUSY;
+ }
+
+ switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;
break;
@@ -452,7 +478,8 @@
skb_queue_tail(&priv->adapter->tx_queue, skb);
- wake_up_interruptible(&priv->main_thread.wait_q);
+ if (!priv->adapter->is_suspended)
+ wake_up_interruptible(&priv->main_thread.wait_q);
return 0;
}
@@ -470,6 +497,9 @@
{
struct btmrvl_private *priv = hci_get_drvdata(hdev);
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
skb_queue_purge(&priv->adapter->tx_queue);
return 0;
@@ -477,6 +507,8 @@
static int btmrvl_open(struct hci_dev *hdev)
{
+ set_bit(HCI_RUNNING, &hdev->flags);
+
return 0;
}
@@ -516,17 +548,14 @@
ret = of_property_read_u8_array(dt_node, "btmrvl,cal-data",
cal_data + BT_CAL_HDR_LEN,
BT_CAL_DATA_SIZE);
- if (ret) {
- of_node_put(dt_node);
+ if (ret)
return ret;
- }
BT_DBG("Use cal data from device tree");
ret = btmrvl_download_cal_data(priv, cal_data,
BT_CAL_DATA_SIZE);
if (ret) {
BT_ERR("Fail to download calibrate data");
- of_node_put(dt_node);
return ret;
}
}
@@ -543,7 +572,7 @@
if (ret)
return ret;
- priv->btmrvl_dev.gpio_gap = 0xffff;
+ priv->btmrvl_dev.gpio_gap = 0xfffe;
btmrvl_check_device_tree(priv);
@@ -643,7 +672,8 @@
if (adapter->ps_state == PS_SLEEP)
continue;
- if (!priv->btmrvl_dev.tx_dnld_rdy)
+ if (!priv->btmrvl_dev.tx_dnld_rdy ||
+ priv->adapter->is_suspended)
continue;
skb = skb_dequeue(&adapter->tx_queue);
@@ -735,17 +765,12 @@
init_waitqueue_head(&priv->main_thread.wait_q);
priv->main_thread.task = kthread_run(btmrvl_service_main_thread,
&priv->main_thread, "btmrvl_main_service");
- if (IS_ERR(priv->main_thread.task))
- goto err_thread;
priv->btmrvl_dev.card = card;
priv->btmrvl_dev.tx_dnld_rdy = true;
return priv;
-err_thread:
- btmrvl_free_adapter(priv);
-
err_adapter:
kfree(priv);
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index d3a4acd..88d0199 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -146,29 +146,6 @@
.fw_dump_end = 0xea,
};
-static const struct btmrvl_sdio_card_reg btmrvl_reg_8997 = {
- .cfg = 0x00,
- .host_int_mask = 0x08,
- .host_intstatus = 0x0c,
- .card_status = 0x5c,
- .sq_read_base_addr_a0 = 0xf8,
- .sq_read_base_addr_a1 = 0xf9,
- .card_revision = 0xc8,
- .card_fw_status0 = 0xe8,
- .card_fw_status1 = 0xe9,
- .card_rx_len = 0xea,
- .card_rx_unit = 0xeb,
- .io_port_0 = 0xe4,
- .io_port_1 = 0xe5,
- .io_port_2 = 0xe6,
- .int_read_to_clear = true,
- .host_int_rsr = 0x04,
- .card_misc_cfg = 0xD8,
- .fw_dump_ctrl = 0xf0,
- .fw_dump_start = 0xf1,
- .fw_dump_end = 0xf8,
-};
-
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
.helper = "mrvl/sd8688_helper.bin",
.firmware = "mrvl/sd8688.bin",
@@ -214,37 +191,25 @@
.supports_fw_dump = true,
};
-static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = {
- .helper = NULL,
- .firmware = "mrvl/sd8997_uapsta.bin",
- .reg = &btmrvl_reg_8997,
- .support_pscan_win_report = true,
- .sd_blksz_fw_dl = 256,
- .supports_fw_dump = true,
-};
-
static const struct sdio_device_id btmrvl_sdio_ids[] = {
/* Marvell SD8688 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
- .driver_data = (unsigned long)&btmrvl_sdio_sd8688 },
+ .driver_data = (unsigned long) &btmrvl_sdio_sd8688 },
/* Marvell SD8787 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
- .driver_data = (unsigned long)&btmrvl_sdio_sd8787 },
+ .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 },
+ .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 },
+ .driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
/* Marvell SD8887 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9136),
.driver_data = (unsigned long)&btmrvl_sdio_sd8887 },
/* Marvell SD8897 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
- .driver_data = (unsigned long)&btmrvl_sdio_sd8897 },
- /* Marvell SD8997 Bluetooth device */
- { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9142),
- .driver_data = (unsigned long)&btmrvl_sdio_sd8997 },
+ .driver_data = (unsigned long) &btmrvl_sdio_sd8897 },
{ } /* Terminating entry */
};
@@ -654,7 +619,7 @@
/* Allocate buffer */
skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC);
- if (!skb) {
+ if (skb == NULL) {
BT_ERR("No free skb");
ret = -ENOMEM;
goto exit;
@@ -698,7 +663,7 @@
case HCI_ACLDATA_PKT:
case HCI_SCODATA_PKT:
case HCI_EVENT_PKT:
- hci_skb_pkt_type(skb) = type;
+ bt_cb(skb)->pkt_type = type;
skb_put(skb, buf_len);
skb_pull(skb, SDIO_HEADER_LEN);
@@ -713,7 +678,7 @@
break;
case MRVL_VENDOR_PKT:
- hci_skb_pkt_type(skb) = HCI_VENDOR_PKT;
+ bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
skb_put(skb, buf_len);
skb_pull(skb, SDIO_HEADER_LEN);
@@ -1106,6 +1071,8 @@
}
}
+ sdio_release_host(card->func);
+
/*
* winner or not, with this test the FW synchronizes when the
* module can continue its initialization
@@ -1115,8 +1082,6 @@
return -ETIMEDOUT;
}
- sdio_release_host(card->func);
-
return 0;
done:
@@ -1252,7 +1217,7 @@
unsigned int reg, reg_start, reg_end;
enum rdwr_status stat;
u8 *dbg_ptr, *end_ptr, *fw_dump_data, *fw_dump_ptr;
- u8 dump_num = 0, idx, i, read_reg, doneflag = 0;
+ u8 dump_num, idx, i, read_reg, doneflag = 0;
u32 memory_size, fw_dump_len = 0;
/* dump sdio register first */
@@ -1313,12 +1278,6 @@
if (memory_size == 0) {
BT_INFO("Firmware dump finished!");
- sdio_writeb(card->func, FW_DUMP_READ_DONE,
- card->reg->fw_dump_ctrl, &ret);
- if (ret) {
- BT_ERR("SDIO Write MEMDUMP_FINISH ERR");
- goto done;
- }
break;
}
@@ -1417,7 +1376,8 @@
/* fw_dump_data will be free in device coredump release function
after 5 min*/
- dev_coredumpv(&card->func->dev, fw_dump_data, fw_dump_len, GFP_KERNEL);
+ dev_coredumpv(&priv->btmrvl_dev.hcidev->dev, fw_dump_data,
+ fw_dump_len, GFP_KERNEL);
BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump end");
}
@@ -1544,6 +1504,7 @@
}
priv = card->priv;
+ priv->adapter->is_suspending = true;
hcidev = priv->btmrvl_dev.hcidev;
BT_DBG("%s: SDIO suspend", hcidev->name);
hci_suspend_dev(hcidev);
@@ -1556,6 +1517,7 @@
}
}
+ priv->adapter->is_suspending = false;
priv->adapter->is_suspended = true;
/* We will keep the power when hs enabled successfully */
@@ -1657,4 +1619,3 @@
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
-MODULE_FIRMWARE("mrvl/sd8997_uapsta.bin");
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
deleted file mode 100644
index 4a62081..0000000
--- a/drivers/bluetooth/btqca.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Bluetooth supports for Qualcomm Atheros chips
- *
- * Copyright (c) 2015 The Linux Foundation. All rights reserved.
- *
- * 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
- *
- * 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 <linux/module.h>
-#include <linux/firmware.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-#include "btqca.h"
-
-#define VERSION "0.1"
-
-static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version)
-{
- struct sk_buff *skb;
- struct edl_event_hdr *edl;
- struct rome_version *ver;
- char cmd;
- int err = 0;
-
- BT_DBG("%s: ROME Patch Version Request", hdev->name);
-
- cmd = EDL_PATCH_VER_REQ_CMD;
- skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN,
- &cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- BT_ERR("%s: Failed to read version of ROME (%d)", hdev->name,
- err);
- return err;
- }
-
- if (skb->len != sizeof(*edl) + sizeof(*ver)) {
- BT_ERR("%s: Version size mismatch len %d", hdev->name,
- skb->len);
- err = -EILSEQ;
- goto out;
- }
-
- edl = (struct edl_event_hdr *)(skb->data);
- if (!edl || !edl->data) {
- BT_ERR("%s: TLV with no header or no data", hdev->name);
- err = -EILSEQ;
- goto out;
- }
-
- if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
- edl->rtype != EDL_APP_VER_RES_EVT) {
- BT_ERR("%s: Wrong packet received %d %d", hdev->name,
- edl->cresp, edl->rtype);
- err = -EIO;
- goto out;
- }
-
- ver = (struct rome_version *)(edl->data);
-
- BT_DBG("%s: Product:0x%08x", hdev->name, le32_to_cpu(ver->product_id));
- BT_DBG("%s: Patch :0x%08x", hdev->name, le16_to_cpu(ver->patch_ver));
- BT_DBG("%s: ROM :0x%08x", hdev->name, le16_to_cpu(ver->rome_ver));
- BT_DBG("%s: SOC :0x%08x", hdev->name, le32_to_cpu(ver->soc_id));
-
- /* ROME chipset version can be decided by patch and SoC
- * version, combination with upper 2 bytes from SoC
- * and lower 2 bytes from patch will be used.
- */
- *rome_version = (le32_to_cpu(ver->soc_id) << 16) |
- (le16_to_cpu(ver->rome_ver) & 0x0000ffff);
-
-out:
- kfree_skb(skb);
-
- return err;
-}
-
-static int rome_reset(struct hci_dev *hdev)
-{
- struct sk_buff *skb;
- int err;
-
- BT_DBG("%s: ROME HCI_RESET", hdev->name);
-
- skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- BT_ERR("%s: Reset failed (%d)", hdev->name, err);
- return err;
- }
-
- kfree_skb(skb);
-
- return 0;
-}
-
-static void rome_tlv_check_data(struct rome_config *config,
- const struct firmware *fw)
-{
- const u8 *data;
- u32 type_len;
- u16 tag_id, tag_len;
- int idx, length;
- struct tlv_type_hdr *tlv;
- struct tlv_type_patch *tlv_patch;
- struct tlv_type_nvm *tlv_nvm;
-
- tlv = (struct tlv_type_hdr *)fw->data;
-
- type_len = le32_to_cpu(tlv->type_len);
- length = (type_len >> 8) & 0x00ffffff;
-
- BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
- BT_DBG("Length\t\t : %d bytes", length);
-
- switch (config->type) {
- case TLV_TYPE_PATCH:
- tlv_patch = (struct tlv_type_patch *)tlv->data;
- BT_DBG("Total Length\t\t : %d bytes",
- le32_to_cpu(tlv_patch->total_size));
- BT_DBG("Patch Data Length\t : %d bytes",
- le32_to_cpu(tlv_patch->data_length));
- BT_DBG("Signing Format Version : 0x%x",
- tlv_patch->format_version);
- BT_DBG("Signature Algorithm\t : 0x%x",
- tlv_patch->signature);
- BT_DBG("Reserved\t\t : 0x%x",
- le16_to_cpu(tlv_patch->reserved1));
- BT_DBG("Product ID\t\t : 0x%04x",
- le16_to_cpu(tlv_patch->product_id));
- BT_DBG("Rom Build Version\t : 0x%04x",
- le16_to_cpu(tlv_patch->rom_build));
- BT_DBG("Patch Version\t\t : 0x%04x",
- le16_to_cpu(tlv_patch->patch_version));
- BT_DBG("Reserved\t\t : 0x%x",
- le16_to_cpu(tlv_patch->reserved2));
- BT_DBG("Patch Entry Address\t : 0x%x",
- le32_to_cpu(tlv_patch->entry));
- break;
-
- case TLV_TYPE_NVM:
- idx = 0;
- data = tlv->data;
- while (idx < length) {
- tlv_nvm = (struct tlv_type_nvm *)(data + idx);
-
- tag_id = le16_to_cpu(tlv_nvm->tag_id);
- tag_len = le16_to_cpu(tlv_nvm->tag_len);
-
- /* Update NVM tags as needed */
- switch (tag_id) {
- case EDL_TAG_ID_HCI:
- /* HCI transport layer parameters
- * enabling software inband sleep
- * onto controller side.
- */
- tlv_nvm->data[0] |= 0x80;
-
- /* UART Baud Rate */
- tlv_nvm->data[2] = config->user_baud_rate;
-
- break;
-
- case EDL_TAG_ID_DEEP_SLEEP:
- /* Sleep enable mask
- * enabling deep sleep feature on controller.
- */
- tlv_nvm->data[0] |= 0x01;
-
- break;
- }
-
- idx += (sizeof(u16) + sizeof(u16) + 8 + tag_len);
- }
- break;
-
- default:
- BT_ERR("Unknown TLV type %d", config->type);
- break;
- }
-}
-
-static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int seg_size,
- const u8 *data)
-{
- struct sk_buff *skb;
- struct edl_event_hdr *edl;
- struct tlv_seg_resp *tlv_resp;
- u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2];
- int err = 0;
-
- BT_DBG("%s: Download segment #%d size %d", hdev->name, idx, seg_size);
-
- cmd[0] = EDL_PATCH_TLV_REQ_CMD;
- cmd[1] = seg_size;
- memcpy(cmd + 2, data, seg_size);
-
- skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, cmd,
- HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- BT_ERR("%s: Failed to send TLV segment (%d)", hdev->name, err);
- return err;
- }
-
- if (skb->len != sizeof(*edl) + sizeof(*tlv_resp)) {
- BT_ERR("%s: TLV response size mismatch", hdev->name);
- err = -EILSEQ;
- goto out;
- }
-
- edl = (struct edl_event_hdr *)(skb->data);
- if (!edl || !edl->data) {
- BT_ERR("%s: TLV with no header or no data", hdev->name);
- err = -EILSEQ;
- goto out;
- }
-
- tlv_resp = (struct tlv_seg_resp *)(edl->data);
-
- if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
- edl->rtype != EDL_TVL_DNLD_RES_EVT || tlv_resp->result != 0x00) {
- BT_ERR("%s: TLV with error stat 0x%x rtype 0x%x (0x%x)",
- hdev->name, edl->cresp, edl->rtype, tlv_resp->result);
- err = -EIO;
- }
-
-out:
- kfree_skb(skb);
-
- return err;
-}
-
-static int rome_tlv_download_request(struct hci_dev *hdev,
- const struct firmware *fw)
-{
- const u8 *buffer, *data;
- int total_segment, remain_size;
- int ret, i;
-
- if (!fw || !fw->data)
- return -EINVAL;
-
- total_segment = fw->size / MAX_SIZE_PER_TLV_SEGMENT;
- remain_size = fw->size % MAX_SIZE_PER_TLV_SEGMENT;
-
- BT_DBG("%s: Total segment num %d remain size %d total size %zu",
- hdev->name, total_segment, remain_size, fw->size);
-
- data = fw->data;
- for (i = 0; i < total_segment; i++) {
- buffer = data + i * MAX_SIZE_PER_TLV_SEGMENT;
- ret = rome_tlv_send_segment(hdev, i, MAX_SIZE_PER_TLV_SEGMENT,
- buffer);
- if (ret < 0)
- return -EIO;
- }
-
- if (remain_size) {
- buffer = data + total_segment * MAX_SIZE_PER_TLV_SEGMENT;
- ret = rome_tlv_send_segment(hdev, total_segment, remain_size,
- buffer);
- if (ret < 0)
- return -EIO;
- }
-
- return 0;
-}
-
-static int rome_download_firmware(struct hci_dev *hdev,
- struct rome_config *config)
-{
- const struct firmware *fw;
- int ret;
-
- BT_INFO("%s: ROME Downloading %s", hdev->name, config->fwname);
-
- ret = request_firmware(&fw, config->fwname, &hdev->dev);
- if (ret) {
- BT_ERR("%s: Failed to request file: %s (%d)", hdev->name,
- config->fwname, ret);
- return ret;
- }
-
- rome_tlv_check_data(config, fw);
-
- ret = rome_tlv_download_request(hdev, fw);
- if (ret) {
- BT_ERR("%s: Failed to download file: %s (%d)", hdev->name,
- config->fwname, ret);
- }
-
- release_firmware(fw);
-
- return ret;
-}
-
-int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
-{
- struct sk_buff *skb;
- u8 cmd[9];
- int err;
-
- cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD;
- cmd[1] = 0x02; /* TAG ID */
- cmd[2] = sizeof(bdaddr_t); /* size */
- memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t));
- skb = __hci_cmd_sync_ev(hdev, EDL_NVM_ACCESS_OPCODE, sizeof(cmd), cmd,
- HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- err = PTR_ERR(skb);
- BT_ERR("%s: Change address command failed (%d)",
- hdev->name, err);
- return err;
- }
-
- kfree_skb(skb);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
-
-int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
-{
- u32 rome_ver = 0;
- struct rome_config config;
- int err;
-
- BT_DBG("%s: ROME setup on UART", hdev->name);
-
- config.user_baud_rate = baudrate;
-
- /* Get ROME version information */
- err = rome_patch_ver_req(hdev, &rome_ver);
- if (err < 0 || rome_ver == 0) {
- BT_ERR("%s: Failed to get version 0x%x", hdev->name, err);
- return err;
- }
-
- BT_INFO("%s: ROME controller version 0x%08x", hdev->name, rome_ver);
-
- /* Download rampatch file */
- config.type = TLV_TYPE_PATCH;
- snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.bin",
- rome_ver);
- err = rome_download_firmware(hdev, &config);
- if (err < 0) {
- BT_ERR("%s: Failed to download patch (%d)", hdev->name, err);
- return err;
- }
-
- /* Download NVM configuration */
- config.type = TLV_TYPE_NVM;
- snprintf(config.fwname, sizeof(config.fwname), "qca/nvm_%08x.bin",
- rome_ver);
- err = rome_download_firmware(hdev, &config);
- if (err < 0) {
- BT_ERR("%s: Failed to download NVM (%d)", hdev->name, err);
- return err;
- }
-
- /* Perform HCI reset */
- err = rome_reset(hdev);
- if (err < 0) {
- BT_ERR("%s: Failed to run HCI_RESET (%d)", hdev->name, err);
- return err;
- }
-
- BT_INFO("%s: ROME setup on UART is completed", hdev->name);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(qca_uart_setup_rome);
-
-MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>");
-MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
deleted file mode 100644
index 65e994b..0000000
--- a/drivers/bluetooth/btqca.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Bluetooth supports for Qualcomm Atheros ROME chips
- *
- * Copyright (c) 2015 The Linux Foundation. All rights reserved.
- *
- * 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
- *
- * 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
- *
- */
-
-#define EDL_PATCH_CMD_OPCODE (0xFC00)
-#define EDL_NVM_ACCESS_OPCODE (0xFC0B)
-#define EDL_PATCH_CMD_LEN (1)
-#define EDL_PATCH_VER_REQ_CMD (0x19)
-#define EDL_PATCH_TLV_REQ_CMD (0x1E)
-#define EDL_NVM_ACCESS_SET_REQ_CMD (0x01)
-#define MAX_SIZE_PER_TLV_SEGMENT (243)
-
-#define EDL_CMD_REQ_RES_EVT (0x00)
-#define EDL_PATCH_VER_RES_EVT (0x19)
-#define EDL_APP_VER_RES_EVT (0x02)
-#define EDL_TVL_DNLD_RES_EVT (0x04)
-#define EDL_CMD_EXE_STATUS_EVT (0x00)
-#define EDL_SET_BAUDRATE_RSP_EVT (0x92)
-#define EDL_NVM_ACCESS_CODE_EVT (0x0B)
-
-#define EDL_TAG_ID_HCI (17)
-#define EDL_TAG_ID_DEEP_SLEEP (27)
-
-enum qca_bardrate {
- QCA_BAUDRATE_115200 = 0,
- QCA_BAUDRATE_57600,
- QCA_BAUDRATE_38400,
- QCA_BAUDRATE_19200,
- QCA_BAUDRATE_9600,
- QCA_BAUDRATE_230400,
- QCA_BAUDRATE_250000,
- QCA_BAUDRATE_460800,
- QCA_BAUDRATE_500000,
- QCA_BAUDRATE_720000,
- QCA_BAUDRATE_921600,
- QCA_BAUDRATE_1000000,
- QCA_BAUDRATE_1250000,
- QCA_BAUDRATE_2000000,
- QCA_BAUDRATE_3000000,
- QCA_BAUDRATE_4000000,
- QCA_BAUDRATE_1600000,
- QCA_BAUDRATE_3200000,
- QCA_BAUDRATE_3500000,
- QCA_BAUDRATE_AUTO = 0xFE,
- QCA_BAUDRATE_RESERVED
-};
-
-enum rome_tlv_type {
- TLV_TYPE_PATCH = 1,
- TLV_TYPE_NVM
-};
-
-struct rome_config {
- u8 type;
- char fwname[64];
- uint8_t user_baud_rate;
-};
-
-struct edl_event_hdr {
- __u8 cresp;
- __u8 rtype;
- __u8 data[0];
-} __packed;
-
-struct rome_version {
- __le32 product_id;
- __le16 patch_ver;
- __le16 rome_ver;
- __le32 soc_id;
-} __packed;
-
-struct tlv_seg_resp {
- __u8 result;
-} __packed;
-
-struct tlv_type_patch {
- __le32 total_size;
- __le32 data_length;
- __u8 format_version;
- __u8 signature;
- __le16 reserved1;
- __le16 product_id;
- __le16 rom_build;
- __le16 patch_version;
- __le16 reserved2;
- __le32 entry;
-} __packed;
-
-struct tlv_type_nvm {
- __le16 tag_id;
- __le16 tag_len;
- __le32 reserve1;
- __le32 reserve2;
- __u8 data[0];
-} __packed;
-
-struct tlv_type_hdr {
- __le32 type_len;
- __u8 data[0];
-} __packed;
-
-#if IS_ENABLED(CONFIG_BT_QCA)
-
-int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr);
-int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate);
-
-#else
-
-static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int qca_uart_setup_rome(struct hci_dev *hdev, int speed)
-{
- return -EOPNOTSUPP;
-}
-
-#endif
diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
deleted file mode 100644
index 8428893..0000000
--- a/drivers/bluetooth/btrtl.c
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Bluetooth support for Realtek devices
- *
- * Copyright (C) 2015 Endless Mobile, Inc.
- *
- * 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.
- *
- */
-
-#include <linux/module.h>
-#include <linux/firmware.h>
-#include <asm/unaligned.h>
-#include <linux/usb.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-#include "btrtl.h"
-
-#define VERSION "0.1"
-
-#define RTL_EPATCH_SIGNATURE "Realtech"
-#define RTL_ROM_LMP_3499 0x3499
-#define RTL_ROM_LMP_8723A 0x1200
-#define RTL_ROM_LMP_8723B 0x8723
-#define RTL_ROM_LMP_8821A 0x8821
-#define RTL_ROM_LMP_8761A 0x8761
-
-static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
-{
- struct rtl_rom_version_evt *rom_version;
- struct sk_buff *skb;
-
- /* Read RTL ROM version command */
- skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- BT_ERR("%s: Read ROM version failed (%ld)",
- hdev->name, PTR_ERR(skb));
- return PTR_ERR(skb);
- }
-
- if (skb->len != sizeof(*rom_version)) {
- BT_ERR("%s: RTL version event length mismatch", hdev->name);
- kfree_skb(skb);
- return -EIO;
- }
-
- rom_version = (struct rtl_rom_version_evt *)skb->data;
- BT_INFO("%s: rom_version status=%x version=%x",
- hdev->name, rom_version->status, rom_version->version);
-
- *version = rom_version->version;
-
- kfree_skb(skb);
- return 0;
-}
-
-static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
- const struct firmware *fw,
- unsigned char **_buf)
-{
- const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
- struct rtl_epatch_header *epatch_info;
- unsigned char *buf;
- int i, ret, len;
- size_t min_size;
- u8 opcode, length, data, rom_version = 0;
- int project_id = -1;
- const unsigned char *fwptr, *chip_id_base;
- const unsigned char *patch_length_base, *patch_offset_base;
- u32 patch_offset = 0;
- u16 patch_length, num_patches;
- const u16 project_id_to_lmp_subver[] = {
- RTL_ROM_LMP_8723A,
- RTL_ROM_LMP_8723B,
- RTL_ROM_LMP_8821A,
- RTL_ROM_LMP_8761A
- };
-
- ret = rtl_read_rom_version(hdev, &rom_version);
- if (ret)
- return ret;
-
- min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
- if (fw->size < min_size)
- return -EINVAL;
-
- fwptr = fw->data + fw->size - sizeof(extension_sig);
- if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) {
- BT_ERR("%s: extension section signature mismatch", hdev->name);
- return -EINVAL;
- }
-
- /* Loop from the end of the firmware parsing instructions, until
- * we find an instruction that identifies the "project ID" for the
- * hardware supported by this firwmare file.
- * Once we have that, we double-check that that project_id is suitable
- * for the hardware we are working with.
- */
- while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) {
- opcode = *--fwptr;
- length = *--fwptr;
- data = *--fwptr;
-
- BT_DBG("check op=%x len=%x data=%x", opcode, length, data);
-
- if (opcode == 0xff) /* EOF */
- break;
-
- if (length == 0) {
- BT_ERR("%s: found instruction with length 0",
- hdev->name);
- return -EINVAL;
- }
-
- if (opcode == 0 && length == 1) {
- project_id = data;
- break;
- }
-
- fwptr -= length;
- }
-
- if (project_id < 0) {
- BT_ERR("%s: failed to find version instruction", hdev->name);
- return -EINVAL;
- }
-
- if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) {
- BT_ERR("%s: unknown project id %d", hdev->name, project_id);
- return -EINVAL;
- }
-
- if (lmp_subver != project_id_to_lmp_subver[project_id]) {
- BT_ERR("%s: firmware is for %x but this is a %x", hdev->name,
- project_id_to_lmp_subver[project_id], lmp_subver);
- return -EINVAL;
- }
-
- epatch_info = (struct rtl_epatch_header *)fw->data;
- if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) {
- BT_ERR("%s: bad EPATCH signature", hdev->name);
- return -EINVAL;
- }
-
- num_patches = le16_to_cpu(epatch_info->num_patches);
- BT_DBG("fw_version=%x, num_patches=%d",
- le32_to_cpu(epatch_info->fw_version), num_patches);
-
- /* After the rtl_epatch_header there is a funky patch metadata section.
- * Assuming 2 patches, the layout is:
- * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2
- *
- * Find the right patch for this chip.
- */
- min_size += 8 * num_patches;
- if (fw->size < min_size)
- return -EINVAL;
-
- chip_id_base = fw->data + sizeof(struct rtl_epatch_header);
- patch_length_base = chip_id_base + (sizeof(u16) * num_patches);
- patch_offset_base = patch_length_base + (sizeof(u16) * num_patches);
- for (i = 0; i < num_patches; i++) {
- u16 chip_id = get_unaligned_le16(chip_id_base +
- (i * sizeof(u16)));
- if (chip_id == rom_version + 1) {
- patch_length = get_unaligned_le16(patch_length_base +
- (i * sizeof(u16)));
- patch_offset = get_unaligned_le32(patch_offset_base +
- (i * sizeof(u32)));
- break;
- }
- }
-
- if (!patch_offset) {
- BT_ERR("%s: didn't find patch for chip id %d",
- hdev->name, rom_version);
- return -EINVAL;
- }
-
- BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i);
- min_size = patch_offset + patch_length;
- if (fw->size < min_size)
- return -EINVAL;
-
- /* Copy the firmware into a new buffer and write the version at
- * the end.
- */
- len = patch_length;
- buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4);
-
- *_buf = buf;
- return len;
-}
-
-static int rtl_download_firmware(struct hci_dev *hdev,
- const unsigned char *data, int fw_len)
-{
- struct rtl_download_cmd *dl_cmd;
- int frag_num = fw_len / RTL_FRAG_LEN + 1;
- int frag_len = RTL_FRAG_LEN;
- int ret = 0;
- int i;
-
- dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL);
- if (!dl_cmd)
- return -ENOMEM;
-
- for (i = 0; i < frag_num; i++) {
- struct sk_buff *skb;
-
- BT_DBG("download fw (%d/%d)", i, frag_num);
-
- dl_cmd->index = i;
- if (i == (frag_num - 1)) {
- dl_cmd->index |= 0x80; /* data end */
- frag_len = fw_len % RTL_FRAG_LEN;
- }
- memcpy(dl_cmd->data, data, frag_len);
-
- /* Send download command */
- skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- BT_ERR("%s: download fw command failed (%ld)",
- hdev->name, PTR_ERR(skb));
- ret = -PTR_ERR(skb);
- goto out;
- }
-
- if (skb->len != sizeof(struct rtl_download_response)) {
- BT_ERR("%s: download fw event length mismatch",
- hdev->name);
- kfree_skb(skb);
- ret = -EIO;
- goto out;
- }
-
- kfree_skb(skb);
- data += RTL_FRAG_LEN;
- }
-
-out:
- kfree(dl_cmd);
- return ret;
-}
-
-static int btrtl_setup_rtl8723a(struct hci_dev *hdev)
-{
- const struct firmware *fw;
- int ret;
-
- BT_INFO("%s: rtl: loading rtl_bt/rtl8723a_fw.bin", hdev->name);
- ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &hdev->dev);
- if (ret < 0) {
- BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name);
- return ret;
- }
-
- if (fw->size < 8) {
- ret = -EINVAL;
- goto out;
- }
-
- /* Check that the firmware doesn't have the epatch signature
- * (which is only for RTL8723B and newer).
- */
- if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) {
- BT_ERR("%s: unexpected EPATCH signature!", hdev->name);
- ret = -EINVAL;
- goto out;
- }
-
- ret = rtl_download_firmware(hdev, fw->data, fw->size);
-
-out:
- release_firmware(fw);
- return ret;
-}
-
-static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
- const char *fw_name)
-{
- unsigned char *fw_data = NULL;
- const struct firmware *fw;
- int ret;
-
- BT_INFO("%s: rtl: loading %s", hdev->name, fw_name);
- ret = request_firmware(&fw, fw_name, &hdev->dev);
- if (ret < 0) {
- BT_ERR("%s: Failed to load %s", hdev->name, fw_name);
- return ret;
- }
-
- ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data);
- if (ret < 0)
- goto out;
-
- ret = rtl_download_firmware(hdev, fw_data, ret);
- kfree(fw_data);
- if (ret < 0)
- goto out;
-
-out:
- release_firmware(fw);
- return ret;
-}
-
-static struct sk_buff *btrtl_read_local_version(struct hci_dev *hdev)
-{
- struct sk_buff *skb;
-
- skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
- hdev->name, PTR_ERR(skb));
- return skb;
- }
-
- if (skb->len != sizeof(struct hci_rp_read_local_version)) {
- BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
- hdev->name);
- kfree_skb(skb);
- return ERR_PTR(-EIO);
- }
-
- return skb;
-}
-
-int btrtl_setup_realtek(struct hci_dev *hdev)
-{
- struct sk_buff *skb;
- struct hci_rp_read_local_version *resp;
- u16 lmp_subver;
-
- skb = btrtl_read_local_version(hdev);
- if (IS_ERR(skb))
- return -PTR_ERR(skb);
-
- resp = (struct hci_rp_read_local_version *)skb->data;
- BT_INFO("%s: rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
- "lmp_subver=%04x", hdev->name, resp->hci_ver, resp->hci_rev,
- resp->lmp_ver, resp->lmp_subver);
-
- lmp_subver = le16_to_cpu(resp->lmp_subver);
- kfree_skb(skb);
-
- /* Match a set of subver values that correspond to stock firmware,
- * which is not compatible with standard btusb.
- * If matched, upload an alternative firmware that does conform to
- * standard btusb. Once that firmware is uploaded, the subver changes
- * to a different value.
- */
- switch (lmp_subver) {
- case RTL_ROM_LMP_8723A:
- case RTL_ROM_LMP_3499:
- return btrtl_setup_rtl8723a(hdev);
- case RTL_ROM_LMP_8723B:
- return btrtl_setup_rtl8723b(hdev, lmp_subver,
- "rtl_bt/rtl8723b_fw.bin");
- case RTL_ROM_LMP_8821A:
- return btrtl_setup_rtl8723b(hdev, lmp_subver,
- "rtl_bt/rtl8821a_fw.bin");
- case RTL_ROM_LMP_8761A:
- return btrtl_setup_rtl8723b(hdev, lmp_subver,
- "rtl_bt/rtl8761a_fw.bin");
- default:
- BT_INFO("rtl: assuming no firmware upload needed.");
- return 0;
- }
-}
-EXPORT_SYMBOL_GPL(btrtl_setup_realtek);
-
-MODULE_AUTHOR("Daniel Drake <drake@endlessm.com>");
-MODULE_DESCRIPTION("Bluetooth support for Realtek devices ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h
deleted file mode 100644
index 38ffe48..0000000
--- a/drivers/bluetooth/btrtl.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Bluetooth support for Realtek devices
- *
- * Copyright (C) 2015 Endless Mobile, Inc.
- *
- * 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.
- *
- */
-
-#define RTL_FRAG_LEN 252
-
-struct rtl_download_cmd {
- __u8 index;
- __u8 data[RTL_FRAG_LEN];
-} __packed;
-
-struct rtl_download_response {
- __u8 status;
- __u8 index;
-} __packed;
-
-struct rtl_rom_version_evt {
- __u8 status;
- __u8 version;
-} __packed;
-
-struct rtl_epatch_header {
- __u8 signature[8];
- __le32 fw_version;
- __le16 num_patches;
-} __packed;
-
-#if IS_ENABLED(CONFIG_BT_RTL)
-
-int btrtl_setup_realtek(struct hci_dev *hdev);
-
-#else
-
-static inline int btrtl_setup_realtek(struct hci_dev *hdev)
-{
- return -EOPNOTSUPP;
-}
-
-#endif
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
index 2b05661..83f6437 100644
--- a/drivers/bluetooth/btsdio.c
+++ b/drivers/bluetooth/btsdio.c
@@ -86,7 +86,7 @@
skb->data[0] = (skb->len & 0x0000ff);
skb->data[1] = (skb->len & 0x00ff00) >> 8;
skb->data[2] = (skb->len & 0xff0000) >> 16;
- skb->data[3] = hci_skb_pkt_type(skb);
+ skb->data[3] = bt_cb(skb)->pkt_type;
err = sdio_writesb(data->func, REG_TDAT, skb->data, skb->len);
if (err < 0) {
@@ -158,7 +158,7 @@
data->hdev->stat.byte_rx += len;
- hci_skb_pkt_type(skb) = hdr[3];
+ bt_cb(skb)->pkt_type = hdr[3];
err = hci_recv_frame(data->hdev, skb);
if (err < 0)
@@ -194,15 +194,21 @@
BT_DBG("%s", hdev->name);
+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
sdio_claim_host(data->func);
err = sdio_enable_func(data->func);
- if (err < 0)
+ if (err < 0) {
+ clear_bit(HCI_RUNNING, &hdev->flags);
goto release;
+ }
err = sdio_claim_irq(data->func, btsdio_interrupt);
if (err < 0) {
sdio_disable_func(data->func);
+ clear_bit(HCI_RUNNING, &hdev->flags);
goto release;
}
@@ -223,6 +229,9 @@
BT_DBG("%s", hdev->name);
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
sdio_claim_host(data->func);
sdio_writeb(data->func, 0x00, REG_EN_INTRD, NULL);
@@ -252,7 +261,10 @@
BT_DBG("%s", hdev->name);
- switch (hci_skb_pkt_type(skb)) {
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+ switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;
break;
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index 9624b29..abb4d21 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -38,7 +38,7 @@
#include <linux/serial.h>
#include <linux/serial_reg.h>
#include <linux/bitops.h>
-#include <linux/io.h>
+#include <asm/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -188,7 +188,7 @@
info->hdev->stat.byte_rx++;
/* Allocate packet */
- if (!info->rx_skb) {
+ if (info->rx_skb == NULL) {
info->rx_state = RECV_WAIT_PACKET_TYPE;
info->rx_count = 0;
info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
@@ -200,9 +200,9 @@
if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
- hci_skb_pkt_type(info->rx_skb) = inb(iobase + UART_RX);
+ bt_cb(info->rx_skb)->pkt_type = inb(iobase + UART_RX);
- switch (hci_skb_pkt_type(info->rx_skb)) {
+ switch (bt_cb(info->rx_skb)->pkt_type) {
case HCI_EVENT_PKT:
info->rx_state = RECV_WAIT_EVENT_HEADER;
@@ -221,9 +221,9 @@
default:
/* Unknown packet */
- BT_ERR("Unknown HCI packet with type 0x%02x received",
- hci_skb_pkt_type(info->rx_skb));
+ BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
info->hdev->stat.err_rx++;
+ clear_bit(HCI_RUNNING, &(info->hdev->flags));
kfree_skb(info->rx_skb);
info->rx_skb = NULL;
@@ -409,12 +409,17 @@
static int btuart_hci_open(struct hci_dev *hdev)
{
+ set_bit(HCI_RUNNING, &(hdev->flags));
+
return 0;
}
static int btuart_hci_close(struct hci_dev *hdev)
{
+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
+ return 0;
+
btuart_hci_flush(hdev);
return 0;
@@ -425,7 +430,7 @@
{
struct btuart_info *info = hci_get_drvdata(hdev);
- switch (hci_skb_pkt_type(skb)) {
+ switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;
break;
@@ -438,7 +443,7 @@
}
/* Prepend skb with frame type */
- memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
skb_queue_tail(&(info->txq), skb);
btuart_write_wakeup(info);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 36360db..231f559 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -24,23 +24,27 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/firmware.h>
-#include <asm/unaligned.h>
+#include <linux/of.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "btintel.h"
#include "btbcm.h"
-#include "btrtl.h"
#define VERSION "0.8"
static bool disable_scofix;
static bool force_scofix;
-static bool reset = true;
+static int marvell_cmd_in_progress;
+static wait_queue_head_t marvell_wait_q;
+static bool marvell_led_support;
+
+static bool reset = 1;
static struct usb_driver btusb_driver;
+static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb);
#define BTUSB_IGNORE 0x01
#define BTUSB_DIGIANSWER 0x02
@@ -59,9 +63,8 @@
#define BTUSB_AMP 0x4000
#define BTUSB_QCA_ROME 0x8000
#define BTUSB_BCM_APPLE 0x10000
-#define BTUSB_REALTEK 0x20000
-#define BTUSB_BCM2045 0x40000
-#define BTUSB_IFNUM_2 0x80000
+
+#define BTUSB_MARVELL_LED_COMMAND 0xfc77
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
@@ -70,12 +73,9 @@
/* Generic Bluetooth AMP device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x04), .driver_info = BTUSB_AMP },
- /* Generic Bluetooth USB interface */
- { USB_INTERFACE_INFO(0xe0, 0x01, 0x01) },
-
/* Apple-specific (Broadcom) devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01),
- .driver_info = BTUSB_BCM_APPLE | BTUSB_IFNUM_2 },
+ .driver_info = BTUSB_BCM_APPLE },
/* MediaTek MT76x0E */
{ USB_DEVICE(0x0e8d, 0x763f) },
@@ -126,9 +126,6 @@
/* Broadcom BCM20702B0 (Dynex/Insignia) */
{ USB_DEVICE(0x19ff, 0x0239), .driver_info = BTUSB_BCM_PATCHRAM },
- /* Broadcom BCM43142A0 (Foxconn/Lenovo) */
- { USB_DEVICE(0x105b, 0xe065), .driver_info = BTUSB_BCM_PATCHRAM },
-
/* Foxconn - Hon Hai */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_PATCHRAM },
@@ -169,9 +166,6 @@
/* Broadcom BCM2033 without firmware */
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
- /* Broadcom BCM2045 devices */
- { USB_DEVICE(0x0a5c, 0x2045), .driver_info = BTUSB_BCM2045 },
-
/* Atheros 3011 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
@@ -190,7 +184,6 @@
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
@@ -199,8 +192,6 @@
{ USB_DEVICE(0x04ca, 0x3007), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
@@ -215,11 +206,9 @@
{ USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0x817b), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x0cf3, 0xe006), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
@@ -227,7 +216,6 @@
{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
- { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -237,7 +225,6 @@
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
/* QCA ROME chipset */
- { USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME },
@@ -282,7 +269,7 @@
{ USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC },
/* Roper Class 1 Bluetooth Dongle (Silicon Wave based) */
- { USB_DEVICE(0x1310, 0x0001), .driver_info = BTUSB_SWAVE },
+ { USB_DEVICE(0x1300, 0x0001), .driver_info = BTUSB_SWAVE },
/* Digianswer devices */
{ USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },
@@ -310,31 +297,6 @@
{ USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01),
.driver_info = BTUSB_IGNORE },
- /* Realtek Bluetooth devices */
- { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
- .driver_info = BTUSB_REALTEK },
-
- /* Additional Realtek 8723AE Bluetooth devices */
- { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
- { USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK },
-
- /* Additional Realtek 8723BE Bluetooth devices */
- { USB_DEVICE(0x0489, 0xe085), .driver_info = BTUSB_REALTEK },
- { USB_DEVICE(0x0489, 0xe08b), .driver_info = BTUSB_REALTEK },
- { USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_REALTEK },
- { USB_DEVICE(0x13d3, 0x3416), .driver_info = BTUSB_REALTEK },
- { USB_DEVICE(0x13d3, 0x3459), .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 },
- { USB_DEVICE(0x13d3, 0x3458), .driver_info = BTUSB_REALTEK },
- { USB_DEVICE(0x13d3, 0x3461), .driver_info = BTUSB_REALTEK },
- { USB_DEVICE(0x13d3, 0x3462), .driver_info = BTUSB_REALTEK },
-
- /* Silicon Wave based devices */
- { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE },
-
{ } /* Terminating entry */
};
@@ -350,15 +312,12 @@
#define BTUSB_FIRMWARE_LOADED 7
#define BTUSB_FIRMWARE_FAILED 8
#define BTUSB_BOOTING 9
-#define BTUSB_RESET_RESUME 10
-#define BTUSB_DIAG_RUNNING 11
struct btusb_data {
struct hci_dev *hdev;
struct usb_device *udev;
struct usb_interface *intf;
struct usb_interface *isoc;
- struct usb_interface *diag;
unsigned long flags;
@@ -373,7 +332,6 @@
struct usb_anchor intr_anchor;
struct usb_anchor bulk_anchor;
struct usb_anchor isoc_anchor;
- struct usb_anchor diag_anchor;
spinlock_t rxlock;
struct sk_buff *evt_skb;
@@ -385,8 +343,6 @@
struct usb_endpoint_descriptor *bulk_rx_ep;
struct usb_endpoint_descriptor *isoc_tx_ep;
struct usb_endpoint_descriptor *isoc_rx_ep;
- struct usb_endpoint_descriptor *diag_tx_ep;
- struct usb_endpoint_descriptor *diag_rx_ep;
__u8 cmdreq_type;
__u8 cmdreq;
@@ -394,6 +350,7 @@
unsigned int sco_num;
int isoc_altsetting;
int suspend_count;
+ bool is_marvell_device;
int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
@@ -447,22 +404,22 @@
break;
}
- hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
- hci_skb_expect(skb) = HCI_EVENT_HDR_SIZE;
+ bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
+ bt_cb(skb)->expect = HCI_EVENT_HDR_SIZE;
}
- len = min_t(uint, hci_skb_expect(skb), count);
+ len = min_t(uint, bt_cb(skb)->expect, count);
memcpy(skb_put(skb, len), buffer, len);
count -= len;
buffer += len;
- hci_skb_expect(skb) -= len;
+ bt_cb(skb)->expect -= len;
if (skb->len == HCI_EVENT_HDR_SIZE) {
/* Complete event header */
- hci_skb_expect(skb) = hci_event_hdr(skb)->plen;
+ bt_cb(skb)->expect = hci_event_hdr(skb)->plen;
- if (skb_tailroom(skb) < hci_skb_expect(skb)) {
+ if (skb_tailroom(skb) < bt_cb(skb)->expect) {
kfree_skb(skb);
skb = NULL;
@@ -471,7 +428,7 @@
}
}
- if (!hci_skb_expect(skb)) {
+ if (bt_cb(skb)->expect == 0) {
/* Complete frame */
data->recv_event(data->hdev, skb);
skb = NULL;
@@ -502,24 +459,24 @@
break;
}
- hci_skb_pkt_type(skb) = HCI_ACLDATA_PKT;
- hci_skb_expect(skb) = HCI_ACL_HDR_SIZE;
+ bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
+ bt_cb(skb)->expect = HCI_ACL_HDR_SIZE;
}
- len = min_t(uint, hci_skb_expect(skb), count);
+ len = min_t(uint, bt_cb(skb)->expect, count);
memcpy(skb_put(skb, len), buffer, len);
count -= len;
buffer += len;
- hci_skb_expect(skb) -= len;
+ bt_cb(skb)->expect -= len;
if (skb->len == HCI_ACL_HDR_SIZE) {
__le16 dlen = hci_acl_hdr(skb)->dlen;
/* Complete ACL header */
- hci_skb_expect(skb) = __le16_to_cpu(dlen);
+ bt_cb(skb)->expect = __le16_to_cpu(dlen);
- if (skb_tailroom(skb) < hci_skb_expect(skb)) {
+ if (skb_tailroom(skb) < bt_cb(skb)->expect) {
kfree_skb(skb);
skb = NULL;
@@ -528,7 +485,7 @@
}
}
- if (!hci_skb_expect(skb)) {
+ if (bt_cb(skb)->expect == 0) {
/* Complete frame */
hci_recv_frame(data->hdev, skb);
skb = NULL;
@@ -559,22 +516,22 @@
break;
}
- hci_skb_pkt_type(skb) = HCI_SCODATA_PKT;
- hci_skb_expect(skb) = HCI_SCO_HDR_SIZE;
+ bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
+ bt_cb(skb)->expect = HCI_SCO_HDR_SIZE;
}
- len = min_t(uint, hci_skb_expect(skb), count);
+ len = min_t(uint, bt_cb(skb)->expect, count);
memcpy(skb_put(skb, len), buffer, len);
count -= len;
buffer += len;
- hci_skb_expect(skb) -= len;
+ bt_cb(skb)->expect -= len;
if (skb->len == HCI_SCO_HDR_SIZE) {
/* Complete SCO header */
- hci_skb_expect(skb) = hci_sco_hdr(skb)->dlen;
+ bt_cb(skb)->expect = hci_sco_hdr(skb)->dlen;
- if (skb_tailroom(skb) < hci_skb_expect(skb)) {
+ if (skb_tailroom(skb) < bt_cb(skb)->expect) {
kfree_skb(skb);
skb = NULL;
@@ -583,7 +540,7 @@
}
}
- if (!hci_skb_expect(skb)) {
+ if (bt_cb(skb)->expect == 0) {
/* Complete frame */
hci_recv_frame(data->hdev, skb);
skb = NULL;
@@ -611,10 +568,34 @@
if (urb->status == 0) {
hdev->stat.byte_rx += urb->actual_length;
- if (btusb_recv_intr(data, urb->transfer_buffer,
- urb->actual_length) < 0) {
- BT_ERR("%s corrupted event packet", hdev->name);
- hdev->stat.err_rx++;
+ if (data->is_marvell_device && marvell_cmd_in_progress) {
+ struct hci_ev_cmd_complete *ev;
+ struct hci_event_hdr *hdr;
+ bool consume_ev = false;
+
+ hdr = urb->transfer_buffer;
+ if (hdr->evt == HCI_EV_CMD_COMPLETE) {
+ ev = (void *)((u8 *)hdr + HCI_EVENT_HDR_SIZE);
+ if (__le16_to_cpu(ev->opcode) ==
+ BTUSB_MARVELL_LED_COMMAND) {
+ consume_ev = true;
+ marvell_cmd_in_progress = false;
+ wake_up_interruptible(&marvell_wait_q);
+ }
+ }
+
+ if (!consume_ev &&
+ btusb_recv_intr(data, urb->transfer_buffer,
+ urb->actual_length) < 0) {
+ BT_ERR("%s corrupted event packet", hdev->name);
+ hdev->stat.err_rx++;
+ }
+ } else {
+ if (btusb_recv_intr(data, urb->transfer_buffer,
+ urb->actual_length) < 0) {
+ BT_ERR("%s corrupted event packet", hdev->name);
+ hdev->stat.err_rx++;
+ }
}
} else if (urb->status == -ENOENT) {
/* Avoid suspend failed when usb_kill_urb */
@@ -894,92 +875,6 @@
return err;
}
-static void btusb_diag_complete(struct urb *urb)
-{
- struct hci_dev *hdev = urb->context;
- struct btusb_data *data = hci_get_drvdata(hdev);
- int err;
-
- BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
- urb->actual_length);
-
- if (urb->status == 0) {
- struct sk_buff *skb;
-
- skb = bt_skb_alloc(urb->actual_length, GFP_ATOMIC);
- if (skb) {
- memcpy(skb_put(skb, urb->actual_length),
- urb->transfer_buffer, urb->actual_length);
- hci_recv_diag(hdev, skb);
- }
- } else if (urb->status == -ENOENT) {
- /* Avoid suspend failed when usb_kill_urb */
- return;
- }
-
- if (!test_bit(BTUSB_DIAG_RUNNING, &data->flags))
- return;
-
- usb_anchor_urb(urb, &data->diag_anchor);
- usb_mark_last_busy(data->udev);
-
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err < 0) {
- /* -EPERM: urb is being killed;
- * -ENODEV: device got disconnected */
- if (err != -EPERM && err != -ENODEV)
- BT_ERR("%s urb %p failed to resubmit (%d)",
- hdev->name, urb, -err);
- usb_unanchor_urb(urb);
- }
-}
-
-static int btusb_submit_diag_urb(struct hci_dev *hdev, gfp_t mem_flags)
-{
- struct btusb_data *data = hci_get_drvdata(hdev);
- struct urb *urb;
- unsigned char *buf;
- unsigned int pipe;
- int err, size = HCI_MAX_FRAME_SIZE;
-
- BT_DBG("%s", hdev->name);
-
- if (!data->diag_rx_ep)
- return -ENODEV;
-
- urb = usb_alloc_urb(0, mem_flags);
- if (!urb)
- return -ENOMEM;
-
- buf = kmalloc(size, mem_flags);
- if (!buf) {
- usb_free_urb(urb);
- return -ENOMEM;
- }
-
- pipe = usb_rcvbulkpipe(data->udev, data->diag_rx_ep->bEndpointAddress);
-
- usb_fill_bulk_urb(urb, data->udev, pipe, buf, size,
- btusb_diag_complete, hdev);
-
- urb->transfer_flags |= URB_FREE_BUFFER;
-
- usb_mark_last_busy(data->udev);
- usb_anchor_urb(urb, &data->diag_anchor);
-
- err = usb_submit_urb(urb, mem_flags);
- if (err < 0) {
- if (err != -EPERM && err != -ENODEV)
- BT_ERR("%s urb %p submission failed (%d)",
- hdev->name, urb, -err);
- usb_unanchor_urb(urb);
- }
-
- usb_free_urb(urb);
-
- return err;
-}
-
static void btusb_tx_complete(struct urb *urb)
{
struct sk_buff *skb = urb->context;
@@ -1029,6 +924,71 @@
kfree_skb(skb);
}
+static void btusb_marvell_config_led(struct hci_dev *hdev, bool status)
+{
+ u8 config_led[] = { 0x09, 0x00, 0x01, 0x01 };
+ int len = HCI_COMMAND_HDR_SIZE + sizeof(config_led);
+ struct hci_command_hdr *hdr;
+ struct sk_buff *skb;
+
+ if (marvell_cmd_in_progress)
+ return;
+
+ skb = bt_skb_alloc(len, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ hdr = (struct hci_command_hdr *)skb_put(skb, HCI_COMMAND_HDR_SIZE);
+ hdr->opcode = cpu_to_le16(BTUSB_MARVELL_LED_COMMAND);
+ hdr->plen = sizeof(config_led);
+
+ if (status)
+ config_led[1] = 0x01;
+
+ memcpy(skb_put(skb, sizeof(config_led)), config_led,
+ sizeof(config_led));
+ bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
+
+ marvell_cmd_in_progress = true;
+ btusb_send_frame(hdev, skb);
+ wait_event_interruptible_timeout(marvell_wait_q,
+ !marvell_cmd_in_progress, HZ);
+}
+
+static ssize_t
+btusb_marvell_sysfs_get_led_support(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, 10, "%d\n", marvell_led_support);
+}
+
+static ssize_t btusb_marvell_sysfs_set_led_support(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ bool res;
+ struct hci_dev *hdev = to_hci_dev(dev);
+
+ if (strtobool(buf, &res))
+ return -EINVAL;
+
+ marvell_led_support = !!res;
+
+ if (test_bit(HCI_UP, &hdev->flags)) {
+ if (marvell_led_support)
+ btusb_marvell_config_led(hdev, true);
+ else
+ btusb_marvell_config_led(hdev, false);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(led, S_IRUGO | S_IWUSR,
+ btusb_marvell_sysfs_get_led_support,
+ btusb_marvell_sysfs_set_led_support);
+
static int btusb_open(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
@@ -1041,7 +1001,7 @@
*/
if (data->setup_on_usb) {
err = data->setup_on_usb(hdev);
- if (err < 0)
+ if (err <0)
return err;
}
@@ -1051,6 +1011,9 @@
data->intf->needs_remote_wakeup = 1;
+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+ goto done;
+
if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
goto done;
@@ -1067,17 +1030,16 @@
set_bit(BTUSB_BULK_RUNNING, &data->flags);
btusb_submit_bulk_urb(hdev, GFP_KERNEL);
- if (data->diag) {
- if (!btusb_submit_diag_urb(hdev, GFP_KERNEL))
- set_bit(BTUSB_DIAG_RUNNING, &data->flags);
- }
-
done:
usb_autopm_put_interface(data->intf);
+
+ if (data->is_marvell_device && marvell_led_support)
+ btusb_marvell_config_led(hdev, true);
return 0;
failed:
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
+ clear_bit(HCI_RUNNING, &hdev->flags);
usb_autopm_put_interface(data->intf);
return err;
}
@@ -1087,7 +1049,6 @@
usb_kill_anchored_urbs(&data->intr_anchor);
usb_kill_anchored_urbs(&data->bulk_anchor);
usb_kill_anchored_urbs(&data->isoc_anchor);
- usb_kill_anchored_urbs(&data->diag_anchor);
}
static int btusb_close(struct hci_dev *hdev)
@@ -1097,13 +1058,24 @@
BT_DBG("%s", hdev->name);
+ if (data->is_marvell_device && marvell_led_support &&
+ usb_get_intfdata(data->intf))
+ btusb_marvell_config_led(hdev, false);
+
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ if (data->is_marvell_device) {
+ marvell_cmd_in_progress = false;
+ wake_up_interruptible(&marvell_wait_q);
+ }
+
cancel_work_sync(&data->work);
cancel_work_sync(&data->waker);
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
clear_bit(BTUSB_BULK_RUNNING, &data->flags);
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
- clear_bit(BTUSB_DIAG_RUNNING, &data->flags);
btusb_stop_traffic(data);
btusb_free_frags(data);
@@ -1267,7 +1239,10 @@
BT_DBG("%s", hdev->name);
- switch (hci_skb_pkt_type(skb)) {
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+ switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
urb = alloc_ctrl_urb(hdev, skb);
if (IS_ERR(urb))
@@ -1385,20 +1360,6 @@
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
usb_kill_anchored_urbs(&data->isoc_anchor);
- /* When isochronous alternate setting needs to be
- * changed, because SCO connection has been added
- * or removed, a packet fragment may be left in the
- * reassembling state. This could lead to wrongly
- * assembled fragments.
- *
- * Clear outstanding fragment when selecting a new
- * alternate setting.
- */
- spin_lock(&data->rxlock);
- kfree_skb(data->sco_skb);
- data->sco_skb = NULL;
- spin_unlock(&data->rxlock);
-
if (__set_isoc_interface(hdev, new_alts) < 0)
return;
}
@@ -1431,6 +1392,28 @@
usb_autopm_put_interface(data->intf);
}
+static struct sk_buff *btusb_read_local_version(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+
+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return skb;
+ }
+
+ if (skb->len != sizeof(struct hci_rp_read_local_version)) {
+ BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
+ hdev->name);
+ kfree_skb(skb);
+ return ERR_PTR(-EIO);
+ }
+
+ return skb;
+}
+
static int btusb_setup_bcm92035(struct hci_dev *hdev)
{
struct sk_buff *skb;
@@ -1451,42 +1434,36 @@
{
struct hci_rp_read_local_version *rp;
struct sk_buff *skb;
+ int ret;
BT_DBG("%s", hdev->name);
- skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- int err = PTR_ERR(skb);
- BT_ERR("%s: CSR: Local version failed (%d)", hdev->name, err);
- return err;
- }
-
- if (skb->len != sizeof(struct hci_rp_read_local_version)) {
- BT_ERR("%s: CSR: Local version length mismatch", hdev->name);
- kfree_skb(skb);
- return -EIO;
- }
+ skb = btusb_read_local_version(hdev);
+ if (IS_ERR(skb))
+ return -PTR_ERR(skb);
rp = (struct hci_rp_read_local_version *)skb->data;
- /* Detect controllers which aren't real CSR ones. */
- if (le16_to_cpu(rp->manufacturer) != 10 ||
- le16_to_cpu(rp->lmp_subver) == 0x0c5c) {
- /* Clear the reset quirk since this is not an actual
- * early Bluetooth 1.1 device from CSR.
- */
- clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+ if (!rp->status) {
+ if (le16_to_cpu(rp->manufacturer) != 10) {
+ /* Clear the reset quirk since this is not an actual
+ * early Bluetooth 1.1 device from CSR.
+ */
+ clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
- /* These fake CSR controllers have all a broken
- * stored link key handling and so just disable it.
- */
- set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
+ /* These fake CSR controllers have all a broken
+ * stored link key handling and so just disable it.
+ */
+ set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY,
+ &hdev->quirks);
+ }
}
+ ret = -bt_to_errno(rp->status);
+
kfree_skb(skb);
- return 0;
+ return ret;
}
static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev,
@@ -1696,6 +1673,12 @@
}
ver = (struct intel_version *)skb->data;
+ if (ver->status) {
+ BT_ERR("%s Intel fw version event failed (%02x)", hdev->name,
+ ver->status);
+ kfree_skb(skb);
+ return -bt_to_errno(ver->status);
+ }
BT_INFO("%s: read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x",
hdev->name, ver->hw_platform, ver->hw_variant,
@@ -1705,13 +1688,14 @@
/* fw_patch_num indicates the version of patch the device currently
* have. If there is no patch data in the device, it is always 0x00.
- * So, if it is other than 0x00, no need to patch the device again.
+ * So, if it is other than 0x00, no need to patch the deivce again.
*/
if (ver->fw_patch_num) {
BT_INFO("%s: Intel device is already patched. patch num: %02x",
hdev->name, ver->fw_patch_num);
kfree_skb(skb);
- goto complete;
+ btintel_check_bdaddr(hdev);
+ return 0;
}
/* Opens the firmware patch file based on the firmware version read
@@ -1723,12 +1707,11 @@
fw = btusb_setup_intel_get_fw(hdev, ver);
if (!fw) {
kfree_skb(skb);
- goto complete;
+ btintel_check_bdaddr(hdev);
+ return 0;
}
fw_ptr = fw->data;
- kfree_skb(skb);
-
/* This Intel specific command enables the manufacturer mode of the
* controller.
*
@@ -1743,6 +1726,15 @@
return PTR_ERR(skb);
}
+ if (skb->data[0]) {
+ u8 evt_status = skb->data[0];
+
+ BT_ERR("%s enable Intel manufacturer mode event failed (%02x)",
+ hdev->name, evt_status);
+ kfree_skb(skb);
+ release_firmware(fw);
+ return -bt_to_errno(evt_status);
+ }
kfree_skb(skb);
disable_patch = 1;
@@ -1796,7 +1788,8 @@
BT_INFO("%s: Intel Bluetooth firmware patch completed and activated",
hdev->name);
- goto complete;
+ btintel_check_bdaddr(hdev);
+ return 0;
exit_mfg_disable:
/* Disable the manufacturer mode without reset */
@@ -1811,7 +1804,8 @@
BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name);
- goto complete;
+ btintel_check_bdaddr(hdev);
+ return 0;
exit_mfg_deactivate:
release_firmware(fw);
@@ -1831,12 +1825,6 @@
BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated",
hdev->name);
-complete:
- /* Set the event mask for Intel specific vendor events. This enables
- * a few extra events that are useful during general operation.
- */
- btintel_set_event_mask_mfg(hdev, false);
-
btintel_check_bdaddr(hdev);
return 0;
}
@@ -1861,7 +1849,7 @@
*skb_put(skb, 1) = 0x00;
- hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
+ bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
return hci_recv_frame(hdev, skb);
}
@@ -1953,7 +1941,10 @@
BT_DBG("%s", hdev->name);
- switch (hci_skb_pkt_type(skb)) {
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+ switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
if (test_bit(BTUSB_BOOTLOADER, &data->flags)) {
struct hci_command_hdr *cmd = (void *)skb->data;
@@ -2007,6 +1998,51 @@
return -EILSEQ;
}
+static int btusb_intel_secure_send(struct hci_dev *hdev, u8 fragment_type,
+ u32 plen, const void *param)
+{
+ while (plen > 0) {
+ struct sk_buff *skb;
+ u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen;
+
+ cmd_param[0] = fragment_type;
+ memcpy(cmd_param + 1, param, fragment_len);
+
+ skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1,
+ cmd_param, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ kfree_skb(skb);
+
+ plen -= fragment_len;
+ param += fragment_len;
+ }
+
+ return 0;
+}
+
+static void btusb_intel_version_info(struct hci_dev *hdev,
+ struct intel_version *ver)
+{
+ const char *variant;
+
+ switch (ver->fw_variant) {
+ case 0x06:
+ variant = "Bootloader";
+ break;
+ case 0x23:
+ variant = "Firmware";
+ break;
+ default:
+ return;
+ }
+
+ BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name,
+ variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,
+ ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy);
+}
+
static int btusb_setup_intel_new(struct hci_dev *hdev)
{
static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01,
@@ -2017,7 +2053,6 @@
struct intel_boot_params *params;
const struct firmware *fw;
const u8 *fw_ptr;
- u32 frag_len;
char fwname[64];
ktime_t calltime, delta, rettime;
unsigned long long duration;
@@ -2045,6 +2080,13 @@
}
ver = (struct intel_version *)skb->data;
+ if (ver->status) {
+ BT_ERR("%s: Intel version command failure (%02x)",
+ hdev->name, ver->status);
+ err = -bt_to_errno(ver->status);
+ kfree_skb(skb);
+ return err;
+ }
/* The hardware platform number has a fixed value of 0x37 and
* for now only accept this single value.
@@ -2068,7 +2110,7 @@
return -EINVAL;
}
- btintel_version_info(hdev, ver);
+ btusb_intel_version_info(hdev, ver);
/* The firmware variant determines if the device is in bootloader
* mode or is running operational firmware. The value 0x06 identifies
@@ -2119,6 +2161,13 @@
}
params = (struct intel_boot_params *)skb->data;
+ if (params->status) {
+ BT_ERR("%s: Intel boot parameters command failure (%02x)",
+ hdev->name, params->status);
+ err = -bt_to_errno(params->status);
+ kfree_skb(skb);
+ return err;
+ }
BT_INFO("%s: Device revision is %u", hdev->name,
le16_to_cpu(params->dev_revid));
@@ -2126,15 +2175,6 @@
BT_INFO("%s: Secure boot is %s", hdev->name,
params->secure_boot ? "enabled" : "disabled");
- BT_INFO("%s: OTP lock is %s", hdev->name,
- params->otp_lock ? "enabled" : "disabled");
-
- BT_INFO("%s: API lock is %s", hdev->name,
- params->api_lock ? "enabled" : "disabled");
-
- BT_INFO("%s: Debug lock is %s", hdev->name,
- params->debug_lock ? "enabled" : "disabled");
-
BT_INFO("%s: Minimum firmware build %u week %u %u", hdev->name,
params->min_fw_build_nn, params->min_fw_build_cw,
2000 + params->min_fw_build_yy);
@@ -2177,12 +2217,6 @@
BT_INFO("%s: Found device firmware: %s", hdev->name, fwname);
- /* Save the DDC file name for later use to apply once the firmware
- * downloading is done.
- */
- snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.ddc",
- le16_to_cpu(params->dev_revid));
-
kfree_skb(skb);
if (fw->size < 644) {
@@ -2197,7 +2231,7 @@
/* Start the firmware download transaction with the Init fragment
* represented by the 128 bytes of CSS header.
*/
- err = btintel_secure_send(hdev, 0x00, 128, fw->data);
+ err = btusb_intel_secure_send(hdev, 0x00, 128, fw->data);
if (err < 0) {
BT_ERR("%s: Failed to send firmware header (%d)",
hdev->name, err);
@@ -2207,7 +2241,7 @@
/* Send the 256 bytes of public key information from the firmware
* as the PKey fragment.
*/
- err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128);
+ err = btusb_intel_secure_send(hdev, 0x03, 256, fw->data + 128);
if (err < 0) {
BT_ERR("%s: Failed to send firmware public key (%d)",
hdev->name, err);
@@ -2217,7 +2251,7 @@
/* Send the 256 bytes of signature information from the firmware
* as the Sign fragment.
*/
- err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388);
+ err = btusb_intel_secure_send(hdev, 0x02, 256, fw->data + 388);
if (err < 0) {
BT_ERR("%s: Failed to send firmware signature (%d)",
hdev->name, err);
@@ -2225,32 +2259,24 @@
}
fw_ptr = fw->data + 644;
- frag_len = 0;
while (fw_ptr - fw->data < fw->size) {
- struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
+ struct hci_command_hdr *cmd = (void *)fw_ptr;
+ u8 cmd_len;
- frag_len += sizeof(*cmd) + cmd->plen;
+ cmd_len = sizeof(*cmd) + cmd->plen;
- /* The parameter length of the secure send command requires
- * a 4 byte alignment. It happens so that the firmware file
- * contains proper Intel_NOP commands to align the fragments
- * as needed.
- *
- * Send set of commands with 4 byte alignment from the
- * firmware data buffer as a single Data fragement.
+ /* Send each command from the firmware data buffer as
+ * a single Data fragment.
*/
- if (!(frag_len % 4)) {
- err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
- if (err < 0) {
- BT_ERR("%s: Failed to send firmware data (%d)",
- hdev->name, err);
- goto done;
- }
-
- fw_ptr += frag_len;
- frag_len = 0;
+ err = btusb_intel_secure_send(hdev, 0x01, cmd_len, fw_ptr);
+ if (err < 0) {
+ BT_ERR("%s: Failed to send firmware data (%d)",
+ hdev->name, err);
+ goto done;
}
+
+ fw_ptr += cmd_len;
}
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
@@ -2269,8 +2295,8 @@
* of this device.
*/
err = btusb_wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING,
- TASK_INTERRUPTIBLE,
- msecs_to_jiffies(5000));
+ msecs_to_jiffies(5000),
+ TASK_INTERRUPTIBLE);
if (err == 1) {
BT_ERR("%s: Firmware loading interrupted", hdev->name);
err = -EINTR;
@@ -2322,8 +2348,8 @@
BT_INFO("%s: Waiting for device to boot", hdev->name);
err = btusb_wait_on_bit_timeout(&data->flags, BTUSB_BOOTING,
- TASK_INTERRUPTIBLE,
- msecs_to_jiffies(1000));
+ msecs_to_jiffies(1000),
+ TASK_INTERRUPTIBLE);
if (err == 1) {
BT_ERR("%s: Device boot interrupted", hdev->name);
@@ -2343,26 +2369,49 @@
clear_bit(BTUSB_BOOTLOADER, &data->flags);
- /* Once the device is running in operational mode, it needs to apply
- * the device configuration (DDC) parameters.
- *
- * The device can work without DDC parameters, so even if it fails
- * to load the file, no need to fail the setup.
- */
- btintel_load_ddc_config(hdev, fwname);
-
- /* Set the event mask for Intel specific vendor events. This enables
- * a few extra events that are useful during general operation. It
- * does not enable any debugging related events.
- *
- * The device will function correctly without these events enabled
- * and thus no need to fail the setup.
- */
- btintel_set_event_mask(hdev, false);
-
return 0;
}
+static void btusb_hw_error_intel(struct hci_dev *hdev, u8 code)
+{
+ struct sk_buff *skb;
+ u8 type = 0x00;
+
+ BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code);
+
+ skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Reset after hardware error failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return;
+ }
+ kfree_skb(skb);
+
+ skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Retrieving Intel exception info failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return;
+ }
+
+ if (skb->len != 13) {
+ BT_ERR("%s: Exception info size mismatch", hdev->name);
+ kfree_skb(skb);
+ return;
+ }
+
+ if (skb->data[0] != 0x00) {
+ BT_ERR("%s: Exception info command failure (%02x)",
+ hdev->name, skb->data[0]);
+ kfree_skb(skb);
+ return;
+ }
+
+ BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1));
+
+ kfree_skb(skb);
+}
+
static int btusb_shutdown_intel(struct hci_dev *hdev)
{
struct sk_buff *skb;
@@ -2465,7 +2514,6 @@
static const struct qca_device_info qca_devices_table[] = {
{ 0x00000100, 20, 4, 10 }, /* Rome 1.0 */
{ 0x00000101, 20, 4, 10 }, /* Rome 1.1 */
- { 0x00000200, 28, 4, 18 }, /* Rome 2.0 */
{ 0x00000201, 28, 4, 18 }, /* Rome 2.1 */
{ 0x00000300, 28, 4, 18 }, /* Rome 3.0 */
{ 0x00000302, 28, 4, 18 }, /* Rome 3.2 */
@@ -2650,7 +2698,7 @@
int i, err;
err = btusb_qca_send_vendor_req(hdev, QCA_GET_TARGET_VERSION, &ver,
- sizeof(ver));
+ sizeof(ver));
if (err < 0)
return err;
@@ -2685,115 +2733,19 @@
return 0;
}
-#ifdef CONFIG_BT_HCIBTUSB_BCM
-static inline int __set_diag_interface(struct hci_dev *hdev)
-{
- struct btusb_data *data = hci_get_drvdata(hdev);
- struct usb_interface *intf = data->diag;
- int i;
-
- if (!data->diag)
- return -ENODEV;
-
- data->diag_tx_ep = NULL;
- data->diag_rx_ep = NULL;
-
- for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
- struct usb_endpoint_descriptor *ep_desc;
-
- ep_desc = &intf->cur_altsetting->endpoint[i].desc;
-
- if (!data->diag_tx_ep && usb_endpoint_is_bulk_out(ep_desc)) {
- data->diag_tx_ep = ep_desc;
- continue;
- }
-
- if (!data->diag_rx_ep && usb_endpoint_is_bulk_in(ep_desc)) {
- data->diag_rx_ep = ep_desc;
- continue;
- }
- }
-
- if (!data->diag_tx_ep || !data->diag_rx_ep) {
- BT_ERR("%s invalid diagnostic descriptors", hdev->name);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static struct urb *alloc_diag_urb(struct hci_dev *hdev, bool enable)
-{
- struct btusb_data *data = hci_get_drvdata(hdev);
- struct sk_buff *skb;
- struct urb *urb;
- unsigned int pipe;
-
- if (!data->diag_tx_ep)
- return ERR_PTR(-ENODEV);
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb)
- return ERR_PTR(-ENOMEM);
-
- skb = bt_skb_alloc(2, GFP_KERNEL);
- if (!skb) {
- usb_free_urb(urb);
- return ERR_PTR(-ENOMEM);
- }
-
- *skb_put(skb, 1) = 0xf0;
- *skb_put(skb, 1) = enable;
-
- pipe = usb_sndbulkpipe(data->udev, data->diag_tx_ep->bEndpointAddress);
-
- usb_fill_bulk_urb(urb, data->udev, pipe,
- skb->data, skb->len, btusb_tx_complete, skb);
-
- skb->dev = (void *)hdev;
-
- return urb;
-}
-
-static int btusb_bcm_set_diag(struct hci_dev *hdev, bool enable)
-{
- struct btusb_data *data = hci_get_drvdata(hdev);
- struct urb *urb;
-
- if (!data->diag)
- return -ENODEV;
-
- if (!test_bit(HCI_RUNNING, &hdev->flags))
- return -ENETDOWN;
-
- urb = alloc_diag_urb(hdev, enable);
- if (IS_ERR(urb))
- return PTR_ERR(urb);
-
- return submit_or_queue_tx_urb(hdev, urb);
-}
-#endif
-
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_endpoint_descriptor *ep_desc;
struct btusb_data *data;
struct hci_dev *hdev;
- unsigned ifnum_base;
int i, err;
BT_DBG("intf %p id %p", intf, id);
/* interface numbers are hardcoded in the spec */
- if (intf->cur_altsetting->desc.bInterfaceNumber != 0) {
- if (!(id->driver_info & BTUSB_IFNUM_2))
- return -ENODEV;
- if (intf->cur_altsetting->desc.bInterfaceNumber != 2)
- return -ENODEV;
- }
-
- ifnum_base = intf->cur_altsetting->desc.bInterfaceNumber;
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+ return -ENODEV;
if (!id->driver_info) {
const struct usb_device_id *match;
@@ -2861,7 +2813,6 @@
init_usb_anchor(&data->intr_anchor);
init_usb_anchor(&data->bulk_anchor);
init_usb_anchor(&data->isoc_anchor);
- init_usb_anchor(&data->diag_anchor);
spin_lock_init(&data->rxlock);
if (id->driver_info & BTUSB_INTEL_NEW) {
@@ -2895,67 +2846,48 @@
hdev->send = btusb_send_frame;
hdev->notify = btusb_notify;
- if (id->driver_info & BTUSB_BCM2045)
- set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
-
if (id->driver_info & BTUSB_BCM92035)
hdev->setup = btusb_setup_bcm92035;
#ifdef CONFIG_BT_HCIBTUSB_BCM
if (id->driver_info & BTUSB_BCM_PATCHRAM) {
- hdev->manufacturer = 15;
hdev->setup = btbcm_setup_patchram;
- hdev->set_diag = btusb_bcm_set_diag;
hdev->set_bdaddr = btbcm_set_bdaddr;
-
- /* Broadcom LM_DIAG Interface numbers are hardcoded */
- data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
}
- if (id->driver_info & BTUSB_BCM_APPLE) {
- hdev->manufacturer = 15;
+ if (id->driver_info & BTUSB_BCM_APPLE)
hdev->setup = btbcm_setup_apple;
- hdev->set_diag = btusb_bcm_set_diag;
-
- /* Broadcom LM_DIAG Interface numbers are hardcoded */
- data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
- }
#endif
if (id->driver_info & BTUSB_INTEL) {
- hdev->manufacturer = 2;
hdev->setup = btusb_setup_intel;
hdev->shutdown = btusb_shutdown_intel;
- hdev->set_diag = btintel_set_diag_mfg;
hdev->set_bdaddr = btintel_set_bdaddr;
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
- set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
}
if (id->driver_info & BTUSB_INTEL_NEW) {
- hdev->manufacturer = 2;
hdev->send = btusb_send_frame_intel;
hdev->setup = btusb_setup_intel_new;
- hdev->hw_error = btintel_hw_error;
- hdev->set_diag = btintel_set_diag;
+ hdev->hw_error = btusb_hw_error_intel;
hdev->set_bdaddr = btintel_set_bdaddr;
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
- set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
}
- if (id->driver_info & BTUSB_MARVELL)
+ if (id->driver_info & BTUSB_MARVELL) {
hdev->set_bdaddr = btusb_set_bdaddr_marvell;
+ data->is_marvell_device = true;
+ init_waitqueue_head(&marvell_wait_q);
+ }
if (id->driver_info & BTUSB_SWAVE) {
set_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks);
set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks);
}
- if (id->driver_info & BTUSB_INTEL_BOOT) {
- hdev->manufacturer = 2;
+ if (id->driver_info & BTUSB_INTEL_BOOT)
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
- }
if (id->driver_info & BTUSB_ATH3012) {
hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
@@ -2968,24 +2900,12 @@
hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
}
-#ifdef CONFIG_BT_HCIBTUSB_RTL
- if (id->driver_info & BTUSB_REALTEK) {
- hdev->setup = btrtl_setup_realtek;
-
- /* Realtek devices lose their updated firmware over suspend,
- * but the USB hub doesn't notice any status change.
- * Explicitly request a device reset on resume.
- */
- set_bit(BTUSB_RESET_RESUME, &data->flags);
- }
-#endif
-
if (id->driver_info & BTUSB_AMP) {
/* AMP controllers do not support SCO packets */
data->isoc = NULL;
} else {
- /* Interface orders are hardcoded in the specification */
- data->isoc = usb_ifnum_to_if(data->udev, ifnum_base + 1);
+ /* Interface numbers are hardcoded in the specification */
+ data->isoc = usb_ifnum_to_if(data->udev, 1);
}
if (!reset)
@@ -3013,7 +2933,7 @@
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
/* Fake CSR devices with broken commands */
- if (bcdDevice <= 0x100 || bcdDevice == 0x134)
+ if (bcdDevice <= 0x100)
hdev->setup = btusb_setup_csr;
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
@@ -3048,16 +2968,6 @@
}
}
-#ifdef CONFIG_BT_HCIBTUSB_BCM
- if (data->diag) {
- if (!usb_driver_claim_interface(&btusb_driver,
- data->diag, data))
- __set_diag_interface(hdev);
- else
- data->diag = NULL;
- }
-#endif
-
err = hci_register_dev(hdev);
if (err < 0) {
hci_free_dev(hdev);
@@ -3066,6 +2976,12 @@
usb_set_intfdata(intf, data);
+ /* Create sysfs file to control Marvell LED feature */
+ if (id->driver_info & BTUSB_MARVELL) {
+ if (device_create_file(&hdev->dev, &dev_attr_led))
+ BT_ERR("failed to create sysfs file led\n");
+ }
+
return 0;
}
@@ -3082,28 +2998,18 @@
hdev = data->hdev;
usb_set_intfdata(data->intf, NULL);
+ if (data->is_marvell_device)
+ device_remove_file(&hdev->dev, &dev_attr_led);
+
if (data->isoc)
usb_set_intfdata(data->isoc, NULL);
- if (data->diag)
- usb_set_intfdata(data->diag, NULL);
-
hci_unregister_dev(hdev);
- if (intf == data->intf) {
- if (data->isoc)
- usb_driver_release_interface(&btusb_driver, data->isoc);
- if (data->diag)
- usb_driver_release_interface(&btusb_driver, data->diag);
- } else if (intf == data->isoc) {
- if (data->diag)
- usb_driver_release_interface(&btusb_driver, data->diag);
+ if (intf == data->isoc)
usb_driver_release_interface(&btusb_driver, data->intf);
- } else if (intf == data->diag) {
- usb_driver_release_interface(&btusb_driver, data->intf);
- if (data->isoc)
- usb_driver_release_interface(&btusb_driver, data->isoc);
- }
+ else if (data->isoc)
+ usb_driver_release_interface(&btusb_driver, data->isoc);
hci_free_dev(hdev);
}
@@ -3128,19 +3034,16 @@
return -EBUSY;
}
+ if (data->is_marvell_device) {
+ marvell_cmd_in_progress = 0;
+ wake_up_interruptible(&marvell_wait_q);
+ }
+
cancel_work_sync(&data->work);
btusb_stop_traffic(data);
usb_kill_anchored_urbs(&data->tx_anchor);
- /* Optionally request a device reset on resume, but only when
- * wakeups are disabled. If wakeups are enabled we assume the
- * device will stay powered up throughout suspend.
- */
- if (test_bit(BTUSB_RESET_RESUME, &data->flags) &&
- !device_may_wakeup(&data->udev->dev))
- data->udev->reset_resume = 1;
-
return 0;
}
diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c
index 24a652f..55c135b 100644
--- a/drivers/bluetooth/btwilink.c
+++ b/drivers/bluetooth/btwilink.c
@@ -22,7 +22,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-
+#define DEBUG
#include <linux/platform_device.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -155,6 +155,9 @@
BT_DBG("%s %p", hdev->name, hdev);
+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
/* provide contexts for callbacks from ST */
hst = hci_get_drvdata(hdev);
@@ -178,6 +181,7 @@
goto done;
if (err != -EINPROGRESS) {
+ clear_bit(HCI_RUNNING, &hdev->flags);
BT_ERR("st_register failed %d", err);
return err;
}
@@ -191,6 +195,7 @@
(&hst->wait_reg_completion,
msecs_to_jiffies(BT_REGISTER_TIMEOUT));
if (!timeleft) {
+ clear_bit(HCI_RUNNING, &hdev->flags);
BT_ERR("Timeout(%d sec),didn't get reg "
"completion signal from ST",
BT_REGISTER_TIMEOUT / 1000);
@@ -200,6 +205,7 @@
/* Is ST registration callback
* called with ERROR status? */
if (hst->reg_status != 0) {
+ clear_bit(HCI_RUNNING, &hdev->flags);
BT_ERR("ST registration completed with invalid "
"status %d", hst->reg_status);
return -EAGAIN;
@@ -209,6 +215,7 @@
hst->st_write = ti_st_proto[i].write;
if (!hst->st_write) {
BT_ERR("undefined ST write function");
+ clear_bit(HCI_RUNNING, &hdev->flags);
for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
/* Undo registration with ST */
err = st_unregister(&ti_st_proto[i]);
@@ -229,6 +236,9 @@
int err, i;
struct ti_st *hst = hci_get_drvdata(hdev);
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
for (i = MAX_BT_CHNL_IDS-1; i >= 0; i--) {
err = st_unregister(&ti_st_proto[i]);
if (err)
@@ -246,13 +256,16 @@
struct ti_st *hst;
long len;
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
hst = hci_get_drvdata(hdev);
/* Prepend skb with frame type */
- memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
- BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb),
- skb->len);
+ BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type,
+ skb->len);
/* Insert skb to shared transport layer's transmit queue.
* Freeing skb memory is taken care in shared transport layer,
@@ -268,7 +281,7 @@
/* ST accepted our skb. So, Go ahead and do rest */
hdev->stat.byte_tx += len;
- ti_st_tx_complete(hst, hci_skb_pkt_type(skb));
+ ti_st_tx_complete(hst, bt_cb(skb)->pkt_type);
return 0;
}
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 6317c6f3..78e10f0c 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -182,9 +182,9 @@
int i;
printk(KERN_INFO "Bluetooth: Nokia control data =");
- for (i = 0; i < skb->len; i++)
+ for (i = 0; i < skb->len; i++) {
printk(" %02x", skb->data[i]);
-
+ }
printk("\n");
/* transition to active state */
@@ -239,7 +239,7 @@
info->rx_count = nsh->len + (nsh->len & 0x0001);
break;
case RECV_WAIT_DATA:
- hci_skb_pkt_type(info->rx_skb) = nsh->type;
+ bt_cb(info->rx_skb)->pkt_type = nsh->type;
/* remove PAD byte if it exists */
if (nsh->len & 0x0001) {
@@ -250,7 +250,7 @@
/* remove NSH */
skb_pull(info->rx_skb, NSHL);
- switch (hci_skb_pkt_type(info->rx_skb)) {
+ switch (bt_cb(info->rx_skb)->pkt_type) {
case 0x80:
/* control data for the Nokia Card */
dtl1_control(info, info->rx_skb);
@@ -259,13 +259,12 @@
case 0x83:
case 0x84:
/* send frame to the HCI layer */
- hci_skb_pkt_type(info->rx_skb) &= 0x0f;
+ bt_cb(info->rx_skb)->pkt_type &= 0x0f;
hci_recv_frame(info->hdev, info->rx_skb);
break;
default:
/* unknown packet */
- BT_ERR("Unknown HCI packet with type 0x%02x received",
- hci_skb_pkt_type(info->rx_skb));
+ BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
kfree_skb(info->rx_skb);
break;
}
@@ -358,6 +357,8 @@
static int dtl1_hci_open(struct hci_dev *hdev)
{
+ set_bit(HCI_RUNNING, &(hdev->flags));
+
return 0;
}
@@ -375,6 +376,9 @@
static int dtl1_hci_close(struct hci_dev *hdev)
{
+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
+ return 0;
+
dtl1_hci_flush(hdev);
return 0;
@@ -387,7 +391,7 @@
struct sk_buff *s;
struct nsh nsh;
- switch (hci_skb_pkt_type(skb)) {
+ switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;
nsh.type = 0x81;
@@ -402,7 +406,7 @@
break;
default:
return -EILSEQ;
- }
+ };
nsh.zero = 0;
nsh.len = skb->len;
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 0ccf6bf..ec8fa0e 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -192,7 +192,6 @@
if (IS_ERR(ath->rx_skb)) {
int err = PTR_ERR(ath->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
- ath->rx_skb = NULL;
return err;
}
@@ -205,7 +204,7 @@
{
struct ath_struct *ath = hu->priv;
- if (hci_skb_pkt_type(skb) == HCI_SCODATA_PKT) {
+ if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
kfree_skb(skb);
return 0;
}
@@ -213,7 +212,7 @@
/* Update power management enable flag with parameters of
* HCI sleep enable vendor specific HCI command.
*/
- if (hci_skb_pkt_type(skb) == HCI_COMMAND_PKT) {
+ if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
struct hci_command_hdr *hdr = (void *)skb->data;
if (__le16_to_cpu(hdr->opcode) == HCI_OP_ATH_SLEEP)
@@ -223,7 +222,7 @@
BT_DBG("hu %p skb %p", hu, skb);
/* Prepend skb with frame type */
- memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
skb_queue_tail(&ath->txq, skb);
set_bit(HCI_UART_SENDING, &hu->tx_state);
@@ -243,7 +242,6 @@
static const struct hci_uart_proto athp = {
.id = HCI_UART_ATH3K,
.name = "ATH3K",
- .manufacturer = 69,
.open = ath_open,
.close = ath_close,
.flush = ath_flush,
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 3eed35e..1ec0b4a 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -24,16 +24,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-#include <linux/acpi.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/gpio/consumer.h>
-#include <linux/tty.h>
-#include <linux/interrupt.h>
-#include <linux/dmi.h>
-#include <linux/pm_runtime.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -41,243 +31,16 @@
#include "btbcm.h"
#include "hci_uart.h"
-#define BCM_LM_DIAG_PKT 0x07
-#define BCM_LM_DIAG_SIZE 63
-
-#define BCM_AUTOSUSPEND_DELAY 5000 /* default autosleep delay */
-
-struct bcm_device {
- struct list_head list;
-
- struct platform_device *pdev;
-
- const char *name;
- struct gpio_desc *device_wakeup;
- struct gpio_desc *shutdown;
-
- struct clk *clk;
- bool clk_enabled;
-
- u32 init_speed;
- int irq;
- u8 irq_polarity;
-
-#ifdef CONFIG_PM
- struct hci_uart *hu;
- bool is_suspended; /* suspend/resume flag */
-#endif
-};
-
struct bcm_data {
- struct sk_buff *rx_skb;
- struct sk_buff_head txq;
-
- struct bcm_device *dev;
+ struct sk_buff *rx_skb;
+ struct sk_buff_head txq;
};
-/* List of BCM BT UART devices */
-static DEFINE_MUTEX(bcm_device_lock);
-static LIST_HEAD(bcm_device_list);
-
-static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed)
-{
- struct hci_dev *hdev = hu->hdev;
- struct sk_buff *skb;
- struct bcm_update_uart_baud_rate param;
-
- if (speed > 3000000) {
- struct bcm_write_uart_clock_setting clock;
-
- clock.type = BCM_UART_CLOCK_48MHZ;
-
- bt_dev_dbg(hdev, "Set Controller clock (%d)", clock.type);
-
- /* This Broadcom specific command changes the UART's controller
- * clock for baud rate > 3000000.
- */
- skb = __hci_cmd_sync(hdev, 0xfc45, 1, &clock, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- int err = PTR_ERR(skb);
- bt_dev_err(hdev, "BCM: failed to write clock (%d)",
- err);
- return err;
- }
-
- kfree_skb(skb);
- }
-
- bt_dev_dbg(hdev, "Set Controller UART speed to %d bit/s", speed);
-
- param.zero = cpu_to_le16(0);
- param.baud_rate = cpu_to_le32(speed);
-
- /* This Broadcom specific command changes the UART's controller baud
- * rate.
- */
- skb = __hci_cmd_sync(hdev, 0xfc18, sizeof(param), ¶m,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- int err = PTR_ERR(skb);
- bt_dev_err(hdev, "BCM: failed to write update baudrate (%d)",
- err);
- return err;
- }
-
- kfree_skb(skb);
-
- return 0;
-}
-
-/* bcm_device_exists should be protected by bcm_device_lock */
-static bool bcm_device_exists(struct bcm_device *device)
-{
- struct list_head *p;
-
- list_for_each(p, &bcm_device_list) {
- struct bcm_device *dev = list_entry(p, struct bcm_device, list);
-
- if (device == dev)
- return true;
- }
-
- return false;
-}
-
-static int bcm_gpio_set_power(struct bcm_device *dev, bool powered)
-{
- if (powered && !IS_ERR(dev->clk) && !dev->clk_enabled)
- clk_enable(dev->clk);
-
- gpiod_set_value(dev->shutdown, powered);
- gpiod_set_value(dev->device_wakeup, powered);
-
- if (!powered && !IS_ERR(dev->clk) && dev->clk_enabled)
- clk_disable(dev->clk);
-
- dev->clk_enabled = powered;
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static irqreturn_t bcm_host_wake(int irq, void *data)
-{
- struct bcm_device *bdev = data;
-
- bt_dev_dbg(bdev, "Host wake IRQ");
-
- pm_runtime_get(&bdev->pdev->dev);
- pm_runtime_mark_last_busy(&bdev->pdev->dev);
- pm_runtime_put_autosuspend(&bdev->pdev->dev);
-
- return IRQ_HANDLED;
-}
-
-static int bcm_request_irq(struct bcm_data *bcm)
-{
- struct bcm_device *bdev = bcm->dev;
- int err = 0;
-
- /* If this is not a platform device, do not enable PM functionalities */
- mutex_lock(&bcm_device_lock);
- if (!bcm_device_exists(bdev)) {
- err = -ENODEV;
- goto unlock;
- }
-
- if (bdev->irq > 0) {
- err = devm_request_irq(&bdev->pdev->dev, bdev->irq,
- bcm_host_wake, IRQF_TRIGGER_RISING,
- "host_wake", bdev);
- if (err)
- goto unlock;
-
- device_init_wakeup(&bdev->pdev->dev, true);
-
- pm_runtime_set_autosuspend_delay(&bdev->pdev->dev,
- BCM_AUTOSUSPEND_DELAY);
- pm_runtime_use_autosuspend(&bdev->pdev->dev);
- pm_runtime_set_active(&bdev->pdev->dev);
- pm_runtime_enable(&bdev->pdev->dev);
- }
-
-unlock:
- mutex_unlock(&bcm_device_lock);
-
- return err;
-}
-
-static const struct bcm_set_sleep_mode default_sleep_params = {
- .sleep_mode = 1, /* 0=Disabled, 1=UART, 2=Reserved, 3=USB */
- .idle_host = 2, /* idle threshold HOST, in 300ms */
- .idle_dev = 2, /* idle threshold device, in 300ms */
- .bt_wake_active = 1, /* BT_WAKE active mode: 1 = high, 0 = low */
- .host_wake_active = 0, /* HOST_WAKE active mode: 1 = high, 0 = low */
- .allow_host_sleep = 1, /* Allow host sleep in SCO flag */
- .combine_modes = 1, /* Combine sleep and LPM flag */
- .tristate_control = 0, /* Allow tri-state control of UART tx flag */
- /* Irrelevant USB flags */
- .usb_auto_sleep = 0,
- .usb_resume_timeout = 0,
- .pulsed_host_wake = 0,
- .break_to_host = 0
-};
-
-static int bcm_setup_sleep(struct hci_uart *hu)
-{
- struct bcm_data *bcm = hu->priv;
- struct sk_buff *skb;
- struct bcm_set_sleep_mode sleep_params = default_sleep_params;
-
- sleep_params.host_wake_active = !bcm->dev->irq_polarity;
-
- skb = __hci_cmd_sync(hu->hdev, 0xfc27, sizeof(sleep_params),
- &sleep_params, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- int err = PTR_ERR(skb);
- bt_dev_err(hu->hdev, "Sleep VSC failed (%d)", err);
- return err;
- }
- kfree_skb(skb);
-
- bt_dev_dbg(hu->hdev, "Set Sleep Parameters VSC succeeded");
-
- return 0;
-}
-#else
-static inline int bcm_request_irq(struct bcm_data *bcm) { return 0; }
-static inline int bcm_setup_sleep(struct hci_uart *hu) { return 0; }
-#endif
-
-static int bcm_set_diag(struct hci_dev *hdev, bool enable)
-{
- struct hci_uart *hu = hci_get_drvdata(hdev);
- struct bcm_data *bcm = hu->priv;
- struct sk_buff *skb;
-
- if (!test_bit(HCI_RUNNING, &hdev->flags))
- return -ENETDOWN;
-
- skb = bt_skb_alloc(3, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
-
- *skb_put(skb, 1) = BCM_LM_DIAG_PKT;
- *skb_put(skb, 1) = 0xf0;
- *skb_put(skb, 1) = enable;
-
- skb_queue_tail(&bcm->txq, skb);
- hci_uart_tx_wakeup(hu);
-
- return 0;
-}
-
static int bcm_open(struct hci_uart *hu)
{
struct bcm_data *bcm;
- struct list_head *p;
- bt_dev_dbg(hu->hdev, "hu %p", hu);
+ BT_DBG("hu %p", hu);
bcm = kzalloc(sizeof(*bcm), GFP_KERNEL);
if (!bcm)
@@ -286,55 +49,14 @@
skb_queue_head_init(&bcm->txq);
hu->priv = bcm;
-
- mutex_lock(&bcm_device_lock);
- list_for_each(p, &bcm_device_list) {
- struct bcm_device *dev = list_entry(p, struct bcm_device, list);
-
- /* Retrieve saved bcm_device based on parent of the
- * platform device (saved during device probe) and
- * parent of tty device used by hci_uart
- */
- if (hu->tty->dev->parent == dev->pdev->dev.parent) {
- bcm->dev = dev;
- hu->init_speed = dev->init_speed;
-#ifdef CONFIG_PM
- dev->hu = hu;
-#endif
- bcm_gpio_set_power(bcm->dev, true);
- break;
- }
- }
-
- mutex_unlock(&bcm_device_lock);
-
return 0;
}
static int bcm_close(struct hci_uart *hu)
{
struct bcm_data *bcm = hu->priv;
- struct bcm_device *bdev = bcm->dev;
- bt_dev_dbg(hu->hdev, "hu %p", hu);
-
- /* Protect bcm->dev against removal of the device or driver */
- mutex_lock(&bcm_device_lock);
- if (bcm_device_exists(bdev)) {
- bcm_gpio_set_power(bdev, false);
-#ifdef CONFIG_PM
- pm_runtime_disable(&bdev->pdev->dev);
- pm_runtime_set_suspended(&bdev->pdev->dev);
-
- if (device_can_wakeup(&bdev->pdev->dev)) {
- devm_free_irq(&bdev->pdev->dev, bdev->irq, bdev);
- device_init_wakeup(&bdev->pdev->dev, false);
- }
-
- bdev->hu = NULL;
-#endif
- }
- mutex_unlock(&bcm_device_lock);
+ BT_DBG("hu %p", hu);
skb_queue_purge(&bcm->txq);
kfree_skb(bcm->rx_skb);
@@ -348,7 +70,7 @@
{
struct bcm_data *bcm = hu->priv;
- bt_dev_dbg(hu->hdev, "hu %p", hu);
+ BT_DBG("hu %p", hu);
skb_queue_purge(&bcm->txq);
@@ -357,84 +79,17 @@
static int bcm_setup(struct hci_uart *hu)
{
- struct bcm_data *bcm = hu->priv;
- char fw_name[64];
- const struct firmware *fw;
- unsigned int speed;
- int err;
+ BT_DBG("hu %p", hu);
- bt_dev_dbg(hu->hdev, "hu %p", hu);
-
- hu->hdev->set_diag = bcm_set_diag;
hu->hdev->set_bdaddr = btbcm_set_bdaddr;
- err = btbcm_initialize(hu->hdev, fw_name, sizeof(fw_name));
- if (err)
- return err;
-
- err = request_firmware(&fw, fw_name, &hu->hdev->dev);
- if (err < 0) {
- bt_dev_info(hu->hdev, "BCM: Patch %s not found", fw_name);
- return 0;
- }
-
- err = btbcm_patchram(hu->hdev, fw);
- if (err) {
- bt_dev_info(hu->hdev, "BCM: Patch failed (%d)", err);
- goto finalize;
- }
-
- /* Init speed if any */
- if (hu->init_speed)
- speed = hu->init_speed;
- else if (hu->proto->init_speed)
- speed = hu->proto->init_speed;
- else
- speed = 0;
-
- if (speed)
- hci_uart_set_baudrate(hu, speed);
-
- /* Operational speed if any */
- if (hu->oper_speed)
- speed = hu->oper_speed;
- else if (hu->proto->oper_speed)
- speed = hu->proto->oper_speed;
- else
- speed = 0;
-
- if (speed) {
- err = bcm_set_baudrate(hu, speed);
- if (!err)
- hci_uart_set_baudrate(hu, speed);
- }
-
-finalize:
- release_firmware(fw);
-
- err = btbcm_finalize(hu->hdev);
- if (err)
- return err;
-
- err = bcm_request_irq(bcm);
- if (!err)
- err = bcm_setup_sleep(hu);
-
- return err;
+ return btbcm_setup_patchram(hu->hdev);
}
-#define BCM_RECV_LM_DIAG \
- .type = BCM_LM_DIAG_PKT, \
- .hlen = BCM_LM_DIAG_SIZE, \
- .loff = 0, \
- .lsize = 0, \
- .maxlen = BCM_LM_DIAG_SIZE
-
static const struct h4_recv_pkt bcm_recv_pkts[] = {
- { H4_RECV_ACL, .recv = hci_recv_frame },
- { H4_RECV_SCO, .recv = hci_recv_frame },
- { H4_RECV_EVENT, .recv = hci_recv_frame },
- { BCM_RECV_LM_DIAG, .recv = hci_recv_diag },
+ { H4_RECV_ACL, .recv = hci_recv_frame },
+ { H4_RECV_SCO, .recv = hci_recv_frame },
+ { H4_RECV_EVENT, .recv = hci_recv_frame },
};
static int bcm_recv(struct hci_uart *hu, const void *data, int count)
@@ -448,18 +103,8 @@
bcm_recv_pkts, ARRAY_SIZE(bcm_recv_pkts));
if (IS_ERR(bcm->rx_skb)) {
int err = PTR_ERR(bcm->rx_skb);
- bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
- bcm->rx_skb = NULL;
+ BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
return err;
- } else if (!bcm->rx_skb) {
- /* Delay auto-suspend when receiving completed packet */
- mutex_lock(&bcm_device_lock);
- if (bcm->dev && bcm_device_exists(bcm->dev)) {
- pm_runtime_get(&bcm->dev->pdev->dev);
- pm_runtime_mark_last_busy(&bcm->dev->pdev->dev);
- pm_runtime_put_autosuspend(&bcm->dev->pdev->dev);
- }
- mutex_unlock(&bcm_device_lock);
}
return count;
@@ -469,10 +114,10 @@
{
struct bcm_data *bcm = hu->priv;
- bt_dev_dbg(hu->hdev, "hu %p skb %p", hu, skb);
+ BT_DBG("hu %p skb %p", hu, skb);
/* Prepend skb with frame type */
- memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
skb_queue_tail(&bcm->txq, skb);
return 0;
@@ -481,372 +126,28 @@
static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
{
struct bcm_data *bcm = hu->priv;
- struct sk_buff *skb = NULL;
- struct bcm_device *bdev = NULL;
- mutex_lock(&bcm_device_lock);
-
- if (bcm_device_exists(bcm->dev)) {
- bdev = bcm->dev;
- pm_runtime_get_sync(&bdev->pdev->dev);
- /* Shall be resumed here */
- }
-
- skb = skb_dequeue(&bcm->txq);
-
- if (bdev) {
- pm_runtime_mark_last_busy(&bdev->pdev->dev);
- pm_runtime_put_autosuspend(&bdev->pdev->dev);
- }
-
- mutex_unlock(&bcm_device_lock);
-
- return skb;
-}
-
-#ifdef CONFIG_PM
-static int bcm_suspend_device(struct device *dev)
-{
- struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
-
- bt_dev_dbg(bdev, "");
-
- if (!bdev->is_suspended && bdev->hu) {
- hci_uart_set_flow_control(bdev->hu, true);
-
- /* Once this returns, driver suspends BT via GPIO */
- bdev->is_suspended = true;
- }
-
- /* Suspend the device */
- if (bdev->device_wakeup) {
- gpiod_set_value(bdev->device_wakeup, false);
- bt_dev_dbg(bdev, "suspend, delaying 15 ms");
- mdelay(15);
- }
-
- return 0;
-}
-
-static int bcm_resume_device(struct device *dev)
-{
- struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
-
- bt_dev_dbg(bdev, "");
-
- if (bdev->device_wakeup) {
- gpiod_set_value(bdev->device_wakeup, true);
- bt_dev_dbg(bdev, "resume, delaying 15 ms");
- mdelay(15);
- }
-
- /* When this executes, the device has woken up already */
- if (bdev->is_suspended && bdev->hu) {
- bdev->is_suspended = false;
-
- hci_uart_set_flow_control(bdev->hu, false);
- }
-
- return 0;
-}
-#endif
-
-#ifdef CONFIG_PM_SLEEP
-/* Platform suspend callback */
-static int bcm_suspend(struct device *dev)
-{
- struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
- int error;
-
- bt_dev_dbg(bdev, "suspend: is_suspended %d", bdev->is_suspended);
-
- /* bcm_suspend can be called at any time as long as platform device is
- * bound, so it should use bcm_device_lock to protect access to hci_uart
- * and device_wake-up GPIO.
- */
- mutex_lock(&bcm_device_lock);
-
- if (!bdev->hu)
- goto unlock;
-
- if (pm_runtime_active(dev))
- bcm_suspend_device(dev);
-
- if (device_may_wakeup(&bdev->pdev->dev)) {
- error = enable_irq_wake(bdev->irq);
- if (!error)
- bt_dev_dbg(bdev, "BCM irq: enabled");
- }
-
-unlock:
- mutex_unlock(&bcm_device_lock);
-
- return 0;
-}
-
-/* Platform resume callback */
-static int bcm_resume(struct device *dev)
-{
- struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
-
- bt_dev_dbg(bdev, "resume: is_suspended %d", bdev->is_suspended);
-
- /* bcm_resume can be called at any time as long as platform device is
- * bound, so it should use bcm_device_lock to protect access to hci_uart
- * and device_wake-up GPIO.
- */
- mutex_lock(&bcm_device_lock);
-
- if (!bdev->hu)
- goto unlock;
-
- if (device_may_wakeup(&bdev->pdev->dev)) {
- disable_irq_wake(bdev->irq);
- bt_dev_dbg(bdev, "BCM irq: disabled");
- }
-
- bcm_resume_device(dev);
-
-unlock:
- mutex_unlock(&bcm_device_lock);
-
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
-
- return 0;
-}
-#endif
-
-static const struct acpi_gpio_params device_wakeup_gpios = { 0, 0, false };
-static const struct acpi_gpio_params shutdown_gpios = { 1, 0, false };
-static const struct acpi_gpio_params host_wakeup_gpios = { 2, 0, false };
-
-static const struct acpi_gpio_mapping acpi_bcm_default_gpios[] = {
- { "device-wakeup-gpios", &device_wakeup_gpios, 1 },
- { "shutdown-gpios", &shutdown_gpios, 1 },
- { "host-wakeup-gpios", &host_wakeup_gpios, 1 },
- { },
-};
-
-#ifdef CONFIG_ACPI
-static u8 acpi_active_low = ACPI_ACTIVE_LOW;
-
-/* IRQ polarity of some chipsets are not defined correctly in ACPI table. */
-static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = {
- {
- .ident = "Asus T100TA",
- .matches = {
- DMI_EXACT_MATCH(DMI_SYS_VENDOR,
- "ASUSTeK COMPUTER INC."),
- DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
- },
- .driver_data = &acpi_active_low,
- },
- { }
-};
-
-static int bcm_resource(struct acpi_resource *ares, void *data)
-{
- struct bcm_device *dev = data;
- struct acpi_resource_extended_irq *irq;
- struct acpi_resource_gpio *gpio;
- struct acpi_resource_uart_serialbus *sb;
-
- switch (ares->type) {
- case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- irq = &ares->data.extended_irq;
- dev->irq_polarity = irq->polarity;
- break;
-
- case ACPI_RESOURCE_TYPE_GPIO:
- gpio = &ares->data.gpio;
- if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT)
- dev->irq_polarity = gpio->polarity;
- break;
-
- case ACPI_RESOURCE_TYPE_SERIAL_BUS:
- sb = &ares->data.uart_serial_bus;
- if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_UART)
- dev->init_speed = sb->default_baud_rate;
- break;
-
- default:
- break;
- }
-
- /* Always tell the ACPI core to skip this resource */
- return 1;
-}
-
-static int bcm_acpi_probe(struct bcm_device *dev)
-{
- struct platform_device *pdev = dev->pdev;
- LIST_HEAD(resources);
- const struct dmi_system_id *dmi_id;
- int ret;
-
- /* Retrieve GPIO data */
- dev->name = dev_name(&pdev->dev);
- ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
- acpi_bcm_default_gpios);
- if (ret)
- return ret;
-
- dev->clk = devm_clk_get(&pdev->dev, NULL);
-
- dev->device_wakeup = devm_gpiod_get_optional(&pdev->dev,
- "device-wakeup",
- GPIOD_OUT_LOW);
- if (IS_ERR(dev->device_wakeup))
- return PTR_ERR(dev->device_wakeup);
-
- dev->shutdown = devm_gpiod_get_optional(&pdev->dev, "shutdown",
- GPIOD_OUT_LOW);
- if (IS_ERR(dev->shutdown))
- return PTR_ERR(dev->shutdown);
-
- /* IRQ can be declared in ACPI table as Interrupt or GpioInt */
- dev->irq = platform_get_irq(pdev, 0);
- if (dev->irq <= 0) {
- struct gpio_desc *gpio;
-
- gpio = devm_gpiod_get_optional(&pdev->dev, "host-wakeup",
- GPIOD_IN);
- if (IS_ERR(gpio))
- return PTR_ERR(gpio);
-
- dev->irq = gpiod_to_irq(gpio);
- }
-
- dev_info(&pdev->dev, "BCM irq: %d\n", dev->irq);
-
- /* Make sure at-least one of the GPIO is defined and that
- * a name is specified for this instance
- */
- if ((!dev->device_wakeup && !dev->shutdown) || !dev->name) {
- dev_err(&pdev->dev, "invalid platform data\n");
- return -EINVAL;
- }
-
- /* Retrieve UART ACPI info */
- ret = acpi_dev_get_resources(ACPI_COMPANION(&dev->pdev->dev),
- &resources, bcm_resource, dev);
- if (ret < 0)
- return ret;
- acpi_dev_free_resource_list(&resources);
-
- dmi_id = dmi_first_match(bcm_wrong_irq_dmi_table);
- if (dmi_id) {
- bt_dev_warn(dev, "%s: Overwriting IRQ polarity to active low",
- dmi_id->ident);
- dev->irq_polarity = *(u8 *)dmi_id->driver_data;
- }
-
- return 0;
-}
-#else
-static int bcm_acpi_probe(struct bcm_device *dev)
-{
- return -EINVAL;
-}
-#endif /* CONFIG_ACPI */
-
-static int bcm_probe(struct platform_device *pdev)
-{
- struct bcm_device *dev;
- int ret;
-
- dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
- dev->pdev = pdev;
-
- ret = bcm_acpi_probe(dev);
- if (ret)
- return ret;
-
- platform_set_drvdata(pdev, dev);
-
- dev_info(&pdev->dev, "%s device registered.\n", dev->name);
-
- /* Place this instance on the device list */
- mutex_lock(&bcm_device_lock);
- list_add_tail(&dev->list, &bcm_device_list);
- mutex_unlock(&bcm_device_lock);
-
- bcm_gpio_set_power(dev, false);
-
- return 0;
-}
-
-static int bcm_remove(struct platform_device *pdev)
-{
- struct bcm_device *dev = platform_get_drvdata(pdev);
-
- mutex_lock(&bcm_device_lock);
- list_del(&dev->list);
- mutex_unlock(&bcm_device_lock);
-
- acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pdev->dev));
-
- dev_info(&pdev->dev, "%s device unregistered.\n", dev->name);
-
- return 0;
+ return skb_dequeue(&bcm->txq);
}
static const struct hci_uart_proto bcm_proto = {
.id = HCI_UART_BCM,
.name = "BCM",
- .manufacturer = 15,
- .init_speed = 115200,
- .oper_speed = 4000000,
.open = bcm_open,
.close = bcm_close,
.flush = bcm_flush,
.setup = bcm_setup,
- .set_baudrate = bcm_set_baudrate,
.recv = bcm_recv,
.enqueue = bcm_enqueue,
.dequeue = bcm_dequeue,
};
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id bcm_acpi_match[] = {
- { "BCM2E39", 0 },
- { "BCM2E67", 0 },
- { },
-};
-MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
-#endif
-
-/* Platform suspend and resume callbacks */
-static const struct dev_pm_ops bcm_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(bcm_suspend, bcm_resume)
- SET_RUNTIME_PM_OPS(bcm_suspend_device, bcm_resume_device, NULL)
-};
-
-static struct platform_driver bcm_driver = {
- .probe = bcm_probe,
- .remove = bcm_remove,
- .driver = {
- .name = "hci_bcm",
- .acpi_match_table = ACPI_PTR(bcm_acpi_match),
- .pm = &bcm_pm_ops,
- },
-};
-
int __init bcm_init(void)
{
- platform_driver_register(&bcm_driver);
-
return hci_uart_register_proto(&bcm_proto);
}
int __exit bcm_deinit(void)
{
- platform_driver_unregister(&bcm_driver);
-
return hci_uart_unregister_proto(&bcm_proto);
}
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 064f2fe..dc8e3d4 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -47,8 +47,8 @@
#include "hci_uart.h"
-static bool txcrc = true;
-static bool hciextn = true;
+static bool txcrc = 1;
+static bool hciextn = 1;
#define BCSP_TXWINSIZE 4
@@ -155,7 +155,7 @@
return 0;
}
- switch (hci_skb_pkt_type(skb)) {
+ switch (bt_cb(skb)->pkt_type) {
case HCI_ACLDATA_PKT:
case HCI_COMMAND_PKT:
skb_queue_tail(&bcsp->rel, skb);
@@ -231,7 +231,7 @@
if (!nskb)
return NULL;
- hci_skb_pkt_type(nskb) = pkt_type;
+ bt_cb(nskb)->pkt_type = pkt_type;
bcsp_slip_msgdelim(nskb);
@@ -291,10 +291,7 @@
skb = skb_dequeue(&bcsp->unrel);
if (skb != NULL) {
- struct sk_buff *nskb;
-
- nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len,
- hci_skb_pkt_type(skb));
+ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, bt_cb(skb)->pkt_type);
if (nskb) {
kfree_skb(skb);
return nskb;
@@ -313,10 +310,8 @@
if (bcsp->unack.qlen < BCSP_TXWINSIZE) {
skb = skb_dequeue(&bcsp->rel);
if (skb != NULL) {
- struct sk_buff *nskb;
-
- nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len,
- hci_skb_pkt_type(skb));
+ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len,
+ bt_cb(skb)->pkt_type);
if (nskb) {
__skb_queue_tail(&bcsp->unack, skb);
mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
@@ -417,7 +412,7 @@
if (!nskb)
return;
memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4);
- hci_skb_pkt_type(nskb) = BCSP_LE_PKT;
+ bt_cb(nskb)->pkt_type = BCSP_LE_PKT;
skb_queue_head(&bcsp->unrel, nskb);
hci_uart_tx_wakeup(hu);
@@ -441,7 +436,7 @@
break;
default:
memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1);
- if ((bcsp->rx_skb->data[0] & 0x40) != 0 &&
+ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
bcsp->rx_state != BCSP_W4_CRC)
bcsp_crc_update(&bcsp->message_crc, byte);
bcsp->rx_count--;
@@ -452,24 +447,24 @@
switch (byte) {
case 0xdc:
memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1);
- if ((bcsp->rx_skb->data[0] & 0x40) != 0 &&
+ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
bcsp->rx_state != BCSP_W4_CRC)
- bcsp_crc_update(&bcsp->message_crc, 0xc0);
+ bcsp_crc_update(&bcsp-> message_crc, 0xc0);
bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
bcsp->rx_count--;
break;
case 0xdd:
memcpy(skb_put(bcsp->rx_skb, 1), &db, 1);
- if ((bcsp->rx_skb->data[0] & 0x40) != 0 &&
+ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
bcsp->rx_state != BCSP_W4_CRC)
- bcsp_crc_update(&bcsp->message_crc, 0xdb);
+ bcsp_crc_update(&bcsp-> message_crc, 0xdb);
bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
bcsp->rx_count--;
break;
default:
- BT_ERR("Invalid byte %02x after esc byte", byte);
+ BT_ERR ("Invalid byte %02x after esc byte", byte);
kfree_skb(bcsp->rx_skb);
bcsp->rx_skb = NULL;
bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
@@ -499,14 +494,14 @@
bcsp_pkt_cull(bcsp);
if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
bcsp->rx_skb->data[0] & 0x80) {
- hci_skb_pkt_type(bcsp->rx_skb) = HCI_ACLDATA_PKT;
+ bt_cb(bcsp->rx_skb)->pkt_type = HCI_ACLDATA_PKT;
pass_up = 1;
} else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
bcsp->rx_skb->data[0] & 0x80) {
- hci_skb_pkt_type(bcsp->rx_skb) = HCI_EVENT_PKT;
+ bt_cb(bcsp->rx_skb)->pkt_type = HCI_EVENT_PKT;
pass_up = 1;
} else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
- hci_skb_pkt_type(bcsp->rx_skb) = HCI_SCODATA_PKT;
+ bt_cb(bcsp->rx_skb)->pkt_type = HCI_SCODATA_PKT;
pass_up = 1;
} else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
!(bcsp->rx_skb->data[0] & 0x80)) {
@@ -528,11 +523,11 @@
hdr.evt = 0xff;
hdr.plen = bcsp->rx_skb->len;
memcpy(skb_push(bcsp->rx_skb, HCI_EVENT_HDR_SIZE), &hdr, HCI_EVENT_HDR_SIZE);
- hci_skb_pkt_type(bcsp->rx_skb) = HCI_EVENT_PKT;
+ bt_cb(bcsp->rx_skb)->pkt_type = HCI_EVENT_PKT;
hci_recv_frame(hu->hdev, bcsp->rx_skb);
} else {
- BT_ERR("Packet for unknown channel (%u %s)",
+ BT_ERR ("Packet for unknown channel (%u %s)",
bcsp->rx_skb->data[1] & 0x0f,
bcsp->rx_skb->data[0] & 0x80 ?
"reliable" : "unreliable");
@@ -592,7 +587,7 @@
}
if (bcsp->rx_skb->data[0] & 0x80 /* reliable pkt */
&& (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
- BT_ERR("Out-of-order packet arrived, got %u expected %u",
+ BT_ERR ("Out-of-order packet arrived, got %u expected %u",
bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
kfree_skb(bcsp->rx_skb);
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 635597b6..f7190f0 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -108,7 +108,7 @@
BT_DBG("hu %p skb %p", hu, skb);
/* Prepend skb with frame type */
- memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
skb_queue_tail(&h4->txq, skb);
return 0;
@@ -133,7 +133,6 @@
if (IS_ERR(h4->rx_skb)) {
int err = PTR_ERR(h4->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
- h4->rx_skb = NULL;
return err;
}
@@ -184,8 +183,8 @@
if (!skb)
return ERR_PTR(-ENOMEM);
- hci_skb_pkt_type(skb) = (&pkts[i])->type;
- hci_skb_expect(skb) = (&pkts[i])->hlen;
+ bt_cb(skb)->pkt_type = (&pkts[i])->type;
+ bt_cb(skb)->expect = (&pkts[i])->hlen;
break;
}
@@ -197,18 +196,18 @@
buffer += 1;
}
- len = min_t(uint, hci_skb_expect(skb) - skb->len, count);
+ len = min_t(uint, bt_cb(skb)->expect - skb->len, count);
memcpy(skb_put(skb, len), buffer, len);
count -= len;
buffer += len;
/* Check for partial packet */
- if (skb->len < hci_skb_expect(skb))
+ if (skb->len < bt_cb(skb)->expect)
continue;
for (i = 0; i < pkts_count; i++) {
- if (hci_skb_pkt_type(skb) == (&pkts[i])->type)
+ if (bt_cb(skb)->pkt_type == (&pkts[i])->type)
break;
}
@@ -223,12 +222,13 @@
switch ((&pkts[i])->lsize) {
case 0:
/* No variable data length */
- dlen = 0;
+ (&pkts[i])->recv(hdev, skb);
+ skb = NULL;
break;
case 1:
/* Single octet variable length */
dlen = skb->data[(&pkts[i])->loff];
- hci_skb_expect(skb) += dlen;
+ bt_cb(skb)->expect += dlen;
if (skb_tailroom(skb) < dlen) {
kfree_skb(skb);
@@ -239,7 +239,7 @@
/* Double octet variable length */
dlen = get_unaligned_le16(skb->data +
(&pkts[i])->loff);
- hci_skb_expect(skb) += dlen;
+ bt_cb(skb)->expect += dlen;
if (skb_tailroom(skb) < dlen) {
kfree_skb(skb);
@@ -251,12 +251,6 @@
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);
@@ -266,4 +260,3 @@
return skb;
}
-EXPORT_SYMBOL_GPL(h4_recv_buf);
diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c
index ebefe5e..3455cec 100644
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -75,7 +75,7 @@
size_t rx_pending; /* Expecting more bytes */
u8 rx_ack; /* Last ack number received */
- int (*rx_func)(struct hci_uart *hu, u8 c);
+ int (*rx_func) (struct hci_uart *hu, u8 c);
struct timer_list timer; /* Retransmission timer */
@@ -107,7 +107,7 @@
if (!nskb)
return;
- hci_skb_pkt_type(nskb) = HCI_3WIRE_LINK_PKT;
+ bt_cb(nskb)->pkt_type = HCI_3WIRE_LINK_PKT;
memcpy(skb_put(nskb, len), data, len);
@@ -128,7 +128,7 @@
{
const unsigned char sync_req[] = { 0x01, 0x7e };
unsigned char conf_req[] = { 0x03, 0xfc, 0x01 };
- struct hci_uart *hu = (struct hci_uart *)arg;
+ struct hci_uart *hu = (struct hci_uart *) arg;
struct h5 *h5 = hu->priv;
struct sk_buff *skb;
unsigned long flags;
@@ -210,7 +210,7 @@
init_timer(&h5->timer);
h5->timer.function = h5_timed_event;
- h5->timer.data = (unsigned long)hu;
+ h5->timer.data = (unsigned long) hu;
h5->tx_win = H5_TX_WIN_MAX;
@@ -360,7 +360,7 @@
case HCI_EVENT_PKT:
case HCI_ACLDATA_PKT:
case HCI_SCODATA_PKT:
- hci_skb_pkt_type(h5->rx_skb) = H5_HDR_PKT_TYPE(hdr);
+ bt_cb(h5->rx_skb)->pkt_type = H5_HDR_PKT_TYPE(hdr);
/* Remove Three-wire header */
skb_pull(h5->rx_skb, 4);
@@ -453,7 +453,7 @@
return -ENOMEM;
}
- h5->rx_skb->dev = (void *)hu->hdev;
+ h5->rx_skb->dev = (void *) hu->hdev;
return 0;
}
@@ -562,7 +562,7 @@
return 0;
}
- switch (hci_skb_pkt_type(skb)) {
+ switch (bt_cb(skb)->pkt_type) {
case HCI_ACLDATA_PKT:
case HCI_COMMAND_PKT:
skb_queue_tail(&h5->rel, skb);
@@ -573,7 +573,7 @@
break;
default:
- BT_ERR("Unknown packet type %u", hci_skb_pkt_type(skb));
+ BT_ERR("Unknown packet type %u", bt_cb(skb)->pkt_type);
kfree_skb(skb);
break;
}
@@ -642,7 +642,7 @@
if (!nskb)
return NULL;
- hci_skb_pkt_type(nskb) = pkt_type;
+ bt_cb(nskb)->pkt_type = pkt_type;
h5_slip_delim(nskb);
@@ -696,8 +696,8 @@
}
skb = skb_dequeue(&h5->unrel);
- if (skb) {
- nskb = h5_prepare_pkt(hu, hci_skb_pkt_type(skb),
+ if (skb != NULL) {
+ nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type,
skb->data, skb->len);
if (nskb) {
kfree_skb(skb);
@@ -714,8 +714,8 @@
goto unlock;
skb = skb_dequeue(&h5->rel);
- if (skb) {
- nskb = h5_prepare_pkt(hu, hci_skb_pkt_type(skb),
+ if (skb != NULL) {
+ nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type,
skb->data, skb->len);
if (nskb) {
__skb_queue_tail(&h5->unack, skb);
diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c
index 69760e2..5dd07bf 100644
--- a/drivers/bluetooth/hci_intel.c
+++ b/drivers/bluetooth/hci_intel.c
@@ -24,1296 +24,8 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-#include <linux/wait.h>
-#include <linux/tty.h>
-#include <linux/platform_device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/acpi.h>
-#include <linux/interrupt.h>
-#include <linux/pm_runtime.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "hci_uart.h"
-#include "btintel.h"
-
-#define STATE_BOOTLOADER 0
-#define STATE_DOWNLOADING 1
-#define STATE_FIRMWARE_LOADED 2
-#define STATE_FIRMWARE_FAILED 3
-#define STATE_BOOTING 4
-#define STATE_LPM_ENABLED 5
-#define STATE_TX_ACTIVE 6
-#define STATE_SUSPENDED 7
-#define STATE_LPM_TRANSACTION 8
-
-#define HCI_LPM_WAKE_PKT 0xf0
-#define HCI_LPM_PKT 0xf1
-#define HCI_LPM_MAX_SIZE 10
-#define HCI_LPM_HDR_SIZE HCI_EVENT_HDR_SIZE
-
-#define LPM_OP_TX_NOTIFY 0x00
-#define LPM_OP_SUSPEND_ACK 0x02
-#define LPM_OP_RESUME_ACK 0x03
-
-#define LPM_SUSPEND_DELAY_MS 1000
-
-struct hci_lpm_pkt {
- __u8 opcode;
- __u8 dlen;
- __u8 data[0];
-} __packed;
-
-struct intel_device {
- struct list_head list;
- struct platform_device *pdev;
- struct gpio_desc *reset;
- struct hci_uart *hu;
- struct mutex hu_lock;
- int irq;
-};
-
-static LIST_HEAD(intel_device_list);
-static DEFINE_MUTEX(intel_device_list_lock);
-
-struct intel_data {
- struct sk_buff *rx_skb;
- struct sk_buff_head txq;
- struct work_struct busy_work;
- struct hci_uart *hu;
- unsigned long flags;
-};
-
-static u8 intel_convert_speed(unsigned int speed)
-{
- switch (speed) {
- case 9600:
- return 0x00;
- case 19200:
- return 0x01;
- case 38400:
- return 0x02;
- case 57600:
- return 0x03;
- case 115200:
- return 0x04;
- case 230400:
- return 0x05;
- case 460800:
- return 0x06;
- case 921600:
- return 0x07;
- case 1843200:
- return 0x08;
- case 3250000:
- return 0x09;
- case 2000000:
- return 0x0a;
- case 3000000:
- return 0x0b;
- default:
- return 0xff;
- }
-}
-
-static int intel_wait_booting(struct hci_uart *hu)
-{
- struct intel_data *intel = hu->priv;
- int err;
-
- err = wait_on_bit_timeout(&intel->flags, STATE_BOOTING,
- TASK_INTERRUPTIBLE,
- msecs_to_jiffies(1000));
-
- if (err == 1) {
- bt_dev_err(hu->hdev, "Device boot interrupted");
- return -EINTR;
- }
-
- if (err) {
- bt_dev_err(hu->hdev, "Device boot timeout");
- return -ETIMEDOUT;
- }
-
- return err;
-}
-
-#ifdef CONFIG_PM
-static int intel_wait_lpm_transaction(struct hci_uart *hu)
-{
- struct intel_data *intel = hu->priv;
- int err;
-
- err = wait_on_bit_timeout(&intel->flags, STATE_LPM_TRANSACTION,
- TASK_INTERRUPTIBLE,
- msecs_to_jiffies(1000));
-
- if (err == 1) {
- bt_dev_err(hu->hdev, "LPM transaction interrupted");
- return -EINTR;
- }
-
- if (err) {
- bt_dev_err(hu->hdev, "LPM transaction timeout");
- return -ETIMEDOUT;
- }
-
- return err;
-}
-
-static int intel_lpm_suspend(struct hci_uart *hu)
-{
- static const u8 suspend[] = { 0x01, 0x01, 0x01 };
- struct intel_data *intel = hu->priv;
- struct sk_buff *skb;
-
- if (!test_bit(STATE_LPM_ENABLED, &intel->flags) ||
- test_bit(STATE_SUSPENDED, &intel->flags))
- return 0;
-
- if (test_bit(STATE_TX_ACTIVE, &intel->flags))
- return -EAGAIN;
-
- bt_dev_dbg(hu->hdev, "Suspending");
-
- skb = bt_skb_alloc(sizeof(suspend), GFP_KERNEL);
- if (!skb) {
- bt_dev_err(hu->hdev, "Failed to alloc memory for LPM packet");
- return -ENOMEM;
- }
-
- memcpy(skb_put(skb, sizeof(suspend)), suspend, sizeof(suspend));
- hci_skb_pkt_type(skb) = HCI_LPM_PKT;
-
- set_bit(STATE_LPM_TRANSACTION, &intel->flags);
-
- /* LPM flow is a priority, enqueue packet at list head */
- skb_queue_head(&intel->txq, skb);
- hci_uart_tx_wakeup(hu);
-
- intel_wait_lpm_transaction(hu);
- /* Even in case of failure, continue and test the suspended flag */
-
- clear_bit(STATE_LPM_TRANSACTION, &intel->flags);
-
- if (!test_bit(STATE_SUSPENDED, &intel->flags)) {
- bt_dev_err(hu->hdev, "Device suspend error");
- return -EINVAL;
- }
-
- bt_dev_dbg(hu->hdev, "Suspended");
-
- hci_uart_set_flow_control(hu, true);
-
- return 0;
-}
-
-static int intel_lpm_resume(struct hci_uart *hu)
-{
- struct intel_data *intel = hu->priv;
- struct sk_buff *skb;
-
- if (!test_bit(STATE_LPM_ENABLED, &intel->flags) ||
- !test_bit(STATE_SUSPENDED, &intel->flags))
- return 0;
-
- bt_dev_dbg(hu->hdev, "Resuming");
-
- hci_uart_set_flow_control(hu, false);
-
- skb = bt_skb_alloc(0, GFP_KERNEL);
- if (!skb) {
- bt_dev_err(hu->hdev, "Failed to alloc memory for LPM packet");
- return -ENOMEM;
- }
-
- hci_skb_pkt_type(skb) = HCI_LPM_WAKE_PKT;
-
- set_bit(STATE_LPM_TRANSACTION, &intel->flags);
-
- /* LPM flow is a priority, enqueue packet at list head */
- skb_queue_head(&intel->txq, skb);
- hci_uart_tx_wakeup(hu);
-
- intel_wait_lpm_transaction(hu);
- /* Even in case of failure, continue and test the suspended flag */
-
- clear_bit(STATE_LPM_TRANSACTION, &intel->flags);
-
- if (test_bit(STATE_SUSPENDED, &intel->flags)) {
- bt_dev_err(hu->hdev, "Device resume error");
- return -EINVAL;
- }
-
- bt_dev_dbg(hu->hdev, "Resumed");
-
- return 0;
-}
-#endif /* CONFIG_PM */
-
-static int intel_lpm_host_wake(struct hci_uart *hu)
-{
- static const u8 lpm_resume_ack[] = { LPM_OP_RESUME_ACK, 0x00 };
- struct intel_data *intel = hu->priv;
- struct sk_buff *skb;
-
- hci_uart_set_flow_control(hu, false);
-
- clear_bit(STATE_SUSPENDED, &intel->flags);
-
- skb = bt_skb_alloc(sizeof(lpm_resume_ack), GFP_KERNEL);
- if (!skb) {
- bt_dev_err(hu->hdev, "Failed to alloc memory for LPM packet");
- return -ENOMEM;
- }
-
- memcpy(skb_put(skb, sizeof(lpm_resume_ack)), lpm_resume_ack,
- sizeof(lpm_resume_ack));
- hci_skb_pkt_type(skb) = HCI_LPM_PKT;
-
- /* LPM flow is a priority, enqueue packet at list head */
- skb_queue_head(&intel->txq, skb);
- hci_uart_tx_wakeup(hu);
-
- bt_dev_dbg(hu->hdev, "Resumed by controller");
-
- return 0;
-}
-
-static irqreturn_t intel_irq(int irq, void *dev_id)
-{
- struct intel_device *idev = dev_id;
-
- dev_info(&idev->pdev->dev, "hci_intel irq\n");
-
- mutex_lock(&idev->hu_lock);
- if (idev->hu)
- intel_lpm_host_wake(idev->hu);
- mutex_unlock(&idev->hu_lock);
-
- /* Host/Controller are now LPM resumed, trigger a new delayed suspend */
- pm_runtime_get(&idev->pdev->dev);
- pm_runtime_mark_last_busy(&idev->pdev->dev);
- pm_runtime_put_autosuspend(&idev->pdev->dev);
-
- return IRQ_HANDLED;
-}
-
-static int intel_set_power(struct hci_uart *hu, bool powered)
-{
- struct list_head *p;
- int err = -ENODEV;
-
- mutex_lock(&intel_device_list_lock);
-
- list_for_each(p, &intel_device_list) {
- struct intel_device *idev = list_entry(p, struct intel_device,
- list);
-
- /* tty device and pdev device should share the same parent
- * which is the UART port.
- */
- if (hu->tty->dev->parent != idev->pdev->dev.parent)
- continue;
-
- if (!idev->reset) {
- err = -ENOTSUPP;
- break;
- }
-
- BT_INFO("hu %p, Switching compatible pm device (%s) to %u",
- hu, dev_name(&idev->pdev->dev), powered);
-
- gpiod_set_value(idev->reset, powered);
-
- /* Provide to idev a hu reference which is used to run LPM
- * transactions (lpm suspend/resume) from PM callbacks.
- * hu needs to be protected against concurrent removing during
- * these PM ops.
- */
- mutex_lock(&idev->hu_lock);
- idev->hu = powered ? hu : NULL;
- mutex_unlock(&idev->hu_lock);
-
- if (idev->irq < 0)
- break;
-
- if (powered && device_can_wakeup(&idev->pdev->dev)) {
- err = devm_request_threaded_irq(&idev->pdev->dev,
- idev->irq, NULL,
- intel_irq,
- IRQF_ONESHOT,
- "bt-host-wake", idev);
- if (err) {
- BT_ERR("hu %p, unable to allocate irq-%d",
- hu, idev->irq);
- break;
- }
-
- device_wakeup_enable(&idev->pdev->dev);
-
- pm_runtime_set_active(&idev->pdev->dev);
- pm_runtime_use_autosuspend(&idev->pdev->dev);
- pm_runtime_set_autosuspend_delay(&idev->pdev->dev,
- LPM_SUSPEND_DELAY_MS);
- pm_runtime_enable(&idev->pdev->dev);
- } else if (!powered && device_may_wakeup(&idev->pdev->dev)) {
- devm_free_irq(&idev->pdev->dev, idev->irq, idev);
- device_wakeup_disable(&idev->pdev->dev);
-
- pm_runtime_disable(&idev->pdev->dev);
- }
- }
-
- mutex_unlock(&intel_device_list_lock);
-
- return err;
-}
-
-static void intel_busy_work(struct work_struct *work)
-{
- struct list_head *p;
- struct intel_data *intel = container_of(work, struct intel_data,
- busy_work);
-
- /* Link is busy, delay the suspend */
- mutex_lock(&intel_device_list_lock);
- list_for_each(p, &intel_device_list) {
- struct intel_device *idev = list_entry(p, struct intel_device,
- list);
-
- if (intel->hu->tty->dev->parent == idev->pdev->dev.parent) {
- pm_runtime_get(&idev->pdev->dev);
- pm_runtime_mark_last_busy(&idev->pdev->dev);
- pm_runtime_put_autosuspend(&idev->pdev->dev);
- break;
- }
- }
- mutex_unlock(&intel_device_list_lock);
-}
-
-static int intel_open(struct hci_uart *hu)
-{
- struct intel_data *intel;
-
- BT_DBG("hu %p", hu);
-
- intel = kzalloc(sizeof(*intel), GFP_KERNEL);
- if (!intel)
- return -ENOMEM;
-
- skb_queue_head_init(&intel->txq);
- INIT_WORK(&intel->busy_work, intel_busy_work);
-
- intel->hu = hu;
-
- hu->priv = intel;
-
- if (!intel_set_power(hu, true))
- set_bit(STATE_BOOTING, &intel->flags);
-
- return 0;
-}
-
-static int intel_close(struct hci_uart *hu)
-{
- struct intel_data *intel = hu->priv;
-
- BT_DBG("hu %p", hu);
-
- cancel_work_sync(&intel->busy_work);
-
- intel_set_power(hu, false);
-
- skb_queue_purge(&intel->txq);
- kfree_skb(intel->rx_skb);
- kfree(intel);
-
- hu->priv = NULL;
- return 0;
-}
-
-static int intel_flush(struct hci_uart *hu)
-{
- struct intel_data *intel = hu->priv;
-
- BT_DBG("hu %p", hu);
-
- skb_queue_purge(&intel->txq);
-
- return 0;
-}
-
-static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode)
-{
- struct sk_buff *skb;
- struct hci_event_hdr *hdr;
- struct hci_ev_cmd_complete *evt;
-
- skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- hdr = (struct hci_event_hdr *)skb_put(skb, sizeof(*hdr));
- hdr->evt = HCI_EV_CMD_COMPLETE;
- hdr->plen = sizeof(*evt) + 1;
-
- evt = (struct hci_ev_cmd_complete *)skb_put(skb, sizeof(*evt));
- evt->ncmd = 0x01;
- evt->opcode = cpu_to_le16(opcode);
-
- *skb_put(skb, 1) = 0x00;
-
- hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
-
- return hci_recv_frame(hdev, skb);
-}
-
-static int intel_set_baudrate(struct hci_uart *hu, unsigned int speed)
-{
- struct intel_data *intel = hu->priv;
- struct hci_dev *hdev = hu->hdev;
- u8 speed_cmd[] = { 0x06, 0xfc, 0x01, 0x00 };
- struct sk_buff *skb;
- int err;
-
- /* This can be the first command sent to the chip, check
- * that the controller is ready.
- */
- err = intel_wait_booting(hu);
-
- clear_bit(STATE_BOOTING, &intel->flags);
-
- /* In case of timeout, try to continue anyway */
- if (err && err != ETIMEDOUT)
- return err;
-
- bt_dev_info(hdev, "Change controller speed to %d", speed);
-
- speed_cmd[3] = intel_convert_speed(speed);
- if (speed_cmd[3] == 0xff) {
- bt_dev_err(hdev, "Unsupported speed");
- return -EINVAL;
- }
-
- /* Device will not accept speed change if Intel version has not been
- * previously requested.
- */
- skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
- PTR_ERR(skb));
- return PTR_ERR(skb);
- }
- kfree_skb(skb);
-
- skb = bt_skb_alloc(sizeof(speed_cmd), GFP_KERNEL);
- if (!skb) {
- bt_dev_err(hdev, "Failed to alloc memory for baudrate packet");
- return -ENOMEM;
- }
-
- memcpy(skb_put(skb, sizeof(speed_cmd)), speed_cmd, sizeof(speed_cmd));
- hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
-
- hci_uart_set_flow_control(hu, true);
-
- skb_queue_tail(&intel->txq, skb);
- hci_uart_tx_wakeup(hu);
-
- /* wait 100ms to change baudrate on controller side */
- msleep(100);
-
- hci_uart_set_baudrate(hu, speed);
- hci_uart_set_flow_control(hu, false);
-
- return 0;
-}
-
-static int intel_setup(struct hci_uart *hu)
-{
- static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x08, 0x04, 0x00 };
- static const u8 lpm_param[] = { 0x03, 0x07, 0x01, 0x0b };
- struct intel_data *intel = hu->priv;
- struct intel_device *idev = NULL;
- struct hci_dev *hdev = hu->hdev;
- struct sk_buff *skb;
- struct intel_version *ver;
- struct intel_boot_params *params;
- struct list_head *p;
- const struct firmware *fw;
- const u8 *fw_ptr;
- char fwname[64];
- u32 frag_len;
- ktime_t calltime, delta, rettime;
- unsigned long long duration;
- unsigned int init_speed, oper_speed;
- int speed_change = 0;
- int err;
-
- bt_dev_dbg(hdev, "start intel_setup");
-
- hu->hdev->set_diag = btintel_set_diag;
- hu->hdev->set_bdaddr = btintel_set_bdaddr;
-
- calltime = ktime_get();
-
- if (hu->init_speed)
- init_speed = hu->init_speed;
- else
- init_speed = hu->proto->init_speed;
-
- if (hu->oper_speed)
- oper_speed = hu->oper_speed;
- else
- oper_speed = hu->proto->oper_speed;
-
- if (oper_speed && init_speed && oper_speed != init_speed)
- speed_change = 1;
-
- /* Check that the controller is ready */
- err = intel_wait_booting(hu);
-
- clear_bit(STATE_BOOTING, &intel->flags);
-
- /* In case of timeout, try to continue anyway */
- if (err && err != ETIMEDOUT)
- return err;
-
- set_bit(STATE_BOOTLOADER, &intel->flags);
-
- /* Read the Intel version information to determine if the device
- * is in bootloader mode or if it already has operational firmware
- * loaded.
- */
- skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
- PTR_ERR(skb));
- return PTR_ERR(skb);
- }
-
- if (skb->len != sizeof(*ver)) {
- bt_dev_err(hdev, "Intel version event size mismatch");
- kfree_skb(skb);
- return -EILSEQ;
- }
-
- ver = (struct intel_version *)skb->data;
- if (ver->status) {
- bt_dev_err(hdev, "Intel version command failure (%02x)",
- ver->status);
- err = -bt_to_errno(ver->status);
- kfree_skb(skb);
- return err;
- }
-
- /* The hardware platform number has a fixed value of 0x37 and
- * for now only accept this single value.
- */
- if (ver->hw_platform != 0x37) {
- bt_dev_err(hdev, "Unsupported Intel hardware platform (%u)",
- ver->hw_platform);
- kfree_skb(skb);
- return -EINVAL;
- }
-
- /* At the moment only the hardware variant iBT 3.0 (LnP/SfP) is
- * supported by this firmware loading method. This check has been
- * put in place to ensure correct forward compatibility options
- * when newer hardware variants come along.
- */
- if (ver->hw_variant != 0x0b) {
- bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
- ver->hw_variant);
- kfree_skb(skb);
- return -EINVAL;
- }
-
- btintel_version_info(hdev, ver);
-
- /* The firmware variant determines if the device is in bootloader
- * mode or is running operational firmware. The value 0x06 identifies
- * the bootloader and the value 0x23 identifies the operational
- * firmware.
- *
- * When the operational firmware is already present, then only
- * the check for valid Bluetooth device address is needed. This
- * determines if the device will be added as configured or
- * unconfigured controller.
- *
- * It is not possible to use the Secure Boot Parameters in this
- * case since that command is only available in bootloader mode.
- */
- if (ver->fw_variant == 0x23) {
- kfree_skb(skb);
- clear_bit(STATE_BOOTLOADER, &intel->flags);
- btintel_check_bdaddr(hdev);
- return 0;
- }
-
- /* If the device is not in bootloader mode, then the only possible
- * choice is to return an error and abort the device initialization.
- */
- if (ver->fw_variant != 0x06) {
- bt_dev_err(hdev, "Unsupported Intel firmware variant (%u)",
- ver->fw_variant);
- kfree_skb(skb);
- return -ENODEV;
- }
-
- kfree_skb(skb);
-
- /* Read the secure boot parameters to identify the operating
- * details of the bootloader.
- */
- skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- bt_dev_err(hdev, "Reading Intel boot parameters failed (%ld)",
- PTR_ERR(skb));
- return PTR_ERR(skb);
- }
-
- if (skb->len != sizeof(*params)) {
- bt_dev_err(hdev, "Intel boot parameters size mismatch");
- kfree_skb(skb);
- return -EILSEQ;
- }
-
- params = (struct intel_boot_params *)skb->data;
- if (params->status) {
- bt_dev_err(hdev, "Intel boot parameters command failure (%02x)",
- params->status);
- err = -bt_to_errno(params->status);
- kfree_skb(skb);
- return err;
- }
-
- bt_dev_info(hdev, "Device revision is %u",
- le16_to_cpu(params->dev_revid));
-
- bt_dev_info(hdev, "Secure boot is %s",
- params->secure_boot ? "enabled" : "disabled");
-
- bt_dev_info(hdev, "Minimum firmware build %u week %u %u",
- params->min_fw_build_nn, params->min_fw_build_cw,
- 2000 + params->min_fw_build_yy);
-
- /* It is required that every single firmware fragment is acknowledged
- * with a command complete event. If the boot parameters indicate
- * that this bootloader does not send them, then abort the setup.
- */
- if (params->limited_cce != 0x00) {
- bt_dev_err(hdev, "Unsupported Intel firmware loading method (%u)",
- params->limited_cce);
- kfree_skb(skb);
- return -EINVAL;
- }
-
- /* If the OTP has no valid Bluetooth device address, then there will
- * also be no valid address for the operational firmware.
- */
- if (!bacmp(¶ms->otp_bdaddr, BDADDR_ANY)) {
- bt_dev_info(hdev, "No device address configured");
- set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
- }
-
- /* With this Intel bootloader only the hardware variant and device
- * revision information are used to select the right firmware.
- *
- * Currently this bootloader support is limited to hardware variant
- * iBT 3.0 (LnP/SfP) which is identified by the value 11 (0x0b).
- */
- snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.sfi",
- le16_to_cpu(params->dev_revid));
-
- err = request_firmware(&fw, fwname, &hdev->dev);
- if (err < 0) {
- bt_dev_err(hdev, "Failed to load Intel firmware file (%d)",
- err);
- kfree_skb(skb);
- return err;
- }
-
- bt_dev_info(hdev, "Found device firmware: %s", fwname);
-
- /* Save the DDC file name for later */
- snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.ddc",
- le16_to_cpu(params->dev_revid));
-
- kfree_skb(skb);
-
- if (fw->size < 644) {
- bt_dev_err(hdev, "Invalid size of firmware file (%zu)",
- fw->size);
- err = -EBADF;
- goto done;
- }
-
- set_bit(STATE_DOWNLOADING, &intel->flags);
-
- /* Start the firmware download transaction with the Init fragment
- * represented by the 128 bytes of CSS header.
- */
- err = btintel_secure_send(hdev, 0x00, 128, fw->data);
- if (err < 0) {
- bt_dev_err(hdev, "Failed to send firmware header (%d)", err);
- goto done;
- }
-
- /* Send the 256 bytes of public key information from the firmware
- * as the PKey fragment.
- */
- err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128);
- if (err < 0) {
- bt_dev_err(hdev, "Failed to send firmware public key (%d)",
- err);
- goto done;
- }
-
- /* Send the 256 bytes of signature information from the firmware
- * as the Sign fragment.
- */
- err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388);
- if (err < 0) {
- bt_dev_err(hdev, "Failed to send firmware signature (%d)",
- err);
- goto done;
- }
-
- fw_ptr = fw->data + 644;
- frag_len = 0;
-
- while (fw_ptr - fw->data < fw->size) {
- struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
-
- frag_len += sizeof(*cmd) + cmd->plen;
-
- bt_dev_dbg(hdev, "Patching %td/%zu", (fw_ptr - fw->data),
- fw->size);
-
- /* The parameter length of the secure send command requires
- * a 4 byte alignment. It happens so that the firmware file
- * contains proper Intel_NOP commands to align the fragments
- * as needed.
- *
- * Send set of commands with 4 byte alignment from the
- * firmware data buffer as a single Data fragement.
- */
- if (frag_len % 4)
- continue;
-
- /* Send each command from the firmware data buffer as
- * a single Data fragment.
- */
- err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
- if (err < 0) {
- bt_dev_err(hdev, "Failed to send firmware data (%d)",
- err);
- goto done;
- }
-
- fw_ptr += frag_len;
- frag_len = 0;
- }
-
- set_bit(STATE_FIRMWARE_LOADED, &intel->flags);
-
- bt_dev_info(hdev, "Waiting for firmware download to complete");
-
- /* Before switching the device into operational mode and with that
- * booting the loaded firmware, wait for the bootloader notification
- * that all fragments have been successfully received.
- *
- * When the event processing receives the notification, then the
- * STATE_DOWNLOADING flag will be cleared.
- *
- * The firmware loading should not take longer than 5 seconds
- * and thus just timeout if that happens and fail the setup
- * of this device.
- */
- err = wait_on_bit_timeout(&intel->flags, STATE_DOWNLOADING,
- TASK_INTERRUPTIBLE,
- msecs_to_jiffies(5000));
- if (err == 1) {
- bt_dev_err(hdev, "Firmware loading interrupted");
- err = -EINTR;
- goto done;
- }
-
- if (err) {
- bt_dev_err(hdev, "Firmware loading timeout");
- err = -ETIMEDOUT;
- goto done;
- }
-
- if (test_bit(STATE_FIRMWARE_FAILED, &intel->flags)) {
- bt_dev_err(hdev, "Firmware loading failed");
- err = -ENOEXEC;
- goto done;
- }
-
- rettime = ktime_get();
- delta = ktime_sub(rettime, calltime);
- duration = (unsigned long long) ktime_to_ns(delta) >> 10;
-
- bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);
-
-done:
- release_firmware(fw);
-
- if (err < 0)
- return err;
-
- /* We need to restore the default speed before Intel reset */
- if (speed_change) {
- err = intel_set_baudrate(hu, init_speed);
- if (err)
- return err;
- }
-
- calltime = ktime_get();
-
- set_bit(STATE_BOOTING, &intel->flags);
-
- skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(reset_param), reset_param,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- kfree_skb(skb);
-
- /* The bootloader will not indicate when the device is ready. This
- * is done by the operational firmware sending bootup notification.
- *
- * Booting into operational firmware should not take longer than
- * 1 second. However if that happens, then just fail the setup
- * since something went wrong.
- */
- bt_dev_info(hdev, "Waiting for device to boot");
-
- err = intel_wait_booting(hu);
- if (err)
- return err;
-
- clear_bit(STATE_BOOTING, &intel->flags);
-
- rettime = ktime_get();
- delta = ktime_sub(rettime, calltime);
- duration = (unsigned long long) ktime_to_ns(delta) >> 10;
-
- bt_dev_info(hdev, "Device booted in %llu usecs", duration);
-
- /* Enable LPM if matching pdev with wakeup enabled */
- mutex_lock(&intel_device_list_lock);
- list_for_each(p, &intel_device_list) {
- struct intel_device *dev = list_entry(p, struct intel_device,
- list);
- if (hu->tty->dev->parent == dev->pdev->dev.parent) {
- if (device_may_wakeup(&dev->pdev->dev))
- idev = dev;
- break;
- }
- }
- mutex_unlock(&intel_device_list_lock);
-
- if (!idev)
- goto no_lpm;
-
- bt_dev_info(hdev, "Enabling LPM");
-
- skb = __hci_cmd_sync(hdev, 0xfc8b, sizeof(lpm_param), lpm_param,
- HCI_CMD_TIMEOUT);
- if (IS_ERR(skb)) {
- bt_dev_err(hdev, "Failed to enable LPM");
- goto no_lpm;
- }
- kfree_skb(skb);
-
- set_bit(STATE_LPM_ENABLED, &intel->flags);
-
-no_lpm:
- /* Ignore errors, device can work without DDC parameters */
- btintel_load_ddc_config(hdev, fwname);
-
- skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_CMD_TIMEOUT);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
- kfree_skb(skb);
-
- if (speed_change) {
- err = intel_set_baudrate(hu, oper_speed);
- if (err)
- return err;
- }
-
- bt_dev_info(hdev, "Setup complete");
-
- clear_bit(STATE_BOOTLOADER, &intel->flags);
-
- return 0;
-}
-
-static int intel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_uart *hu = hci_get_drvdata(hdev);
- struct intel_data *intel = hu->priv;
- struct hci_event_hdr *hdr;
-
- if (!test_bit(STATE_BOOTLOADER, &intel->flags) &&
- !test_bit(STATE_BOOTING, &intel->flags))
- goto recv;
-
- hdr = (void *)skb->data;
-
- /* When the firmware loading completes the device sends
- * out a vendor specific event indicating the result of
- * the firmware loading.
- */
- if (skb->len == 7 && hdr->evt == 0xff && hdr->plen == 0x05 &&
- skb->data[2] == 0x06) {
- if (skb->data[3] != 0x00)
- set_bit(STATE_FIRMWARE_FAILED, &intel->flags);
-
- if (test_and_clear_bit(STATE_DOWNLOADING, &intel->flags) &&
- test_bit(STATE_FIRMWARE_LOADED, &intel->flags)) {
- smp_mb__after_atomic();
- wake_up_bit(&intel->flags, STATE_DOWNLOADING);
- }
-
- /* When switching to the operational firmware the device
- * sends a vendor specific event indicating that the bootup
- * completed.
- */
- } else if (skb->len == 9 && hdr->evt == 0xff && hdr->plen == 0x07 &&
- skb->data[2] == 0x02) {
- if (test_and_clear_bit(STATE_BOOTING, &intel->flags)) {
- smp_mb__after_atomic();
- wake_up_bit(&intel->flags, STATE_BOOTING);
- }
- }
-recv:
- return hci_recv_frame(hdev, skb);
-}
-
-static void intel_recv_lpm_notify(struct hci_dev *hdev, int value)
-{
- struct hci_uart *hu = hci_get_drvdata(hdev);
- struct intel_data *intel = hu->priv;
-
- bt_dev_dbg(hdev, "TX idle notification (%d)", value);
-
- if (value) {
- set_bit(STATE_TX_ACTIVE, &intel->flags);
- schedule_work(&intel->busy_work);
- } else {
- clear_bit(STATE_TX_ACTIVE, &intel->flags);
- }
-}
-
-static int intel_recv_lpm(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_lpm_pkt *lpm = (void *)skb->data;
- struct hci_uart *hu = hci_get_drvdata(hdev);
- struct intel_data *intel = hu->priv;
-
- switch (lpm->opcode) {
- case LPM_OP_TX_NOTIFY:
- if (lpm->dlen < 1) {
- bt_dev_err(hu->hdev, "Invalid LPM notification packet");
- break;
- }
- intel_recv_lpm_notify(hdev, lpm->data[0]);
- break;
- case LPM_OP_SUSPEND_ACK:
- set_bit(STATE_SUSPENDED, &intel->flags);
- if (test_and_clear_bit(STATE_LPM_TRANSACTION, &intel->flags)) {
- smp_mb__after_atomic();
- wake_up_bit(&intel->flags, STATE_LPM_TRANSACTION);
- }
- break;
- case LPM_OP_RESUME_ACK:
- clear_bit(STATE_SUSPENDED, &intel->flags);
- if (test_and_clear_bit(STATE_LPM_TRANSACTION, &intel->flags)) {
- smp_mb__after_atomic();
- wake_up_bit(&intel->flags, STATE_LPM_TRANSACTION);
- }
- break;
- default:
- bt_dev_err(hdev, "Unknown LPM opcode (%02x)", lpm->opcode);
- break;
- }
-
- kfree_skb(skb);
-
- return 0;
-}
-
-#define INTEL_RECV_LPM \
- .type = HCI_LPM_PKT, \
- .hlen = HCI_LPM_HDR_SIZE, \
- .loff = 1, \
- .lsize = 1, \
- .maxlen = HCI_LPM_MAX_SIZE
-
-static const struct h4_recv_pkt intel_recv_pkts[] = {
- { H4_RECV_ACL, .recv = hci_recv_frame },
- { H4_RECV_SCO, .recv = hci_recv_frame },
- { H4_RECV_EVENT, .recv = intel_recv_event },
- { INTEL_RECV_LPM, .recv = intel_recv_lpm },
-};
-
-static int intel_recv(struct hci_uart *hu, const void *data, int count)
-{
- struct intel_data *intel = hu->priv;
-
- if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
- return -EUNATCH;
-
- intel->rx_skb = h4_recv_buf(hu->hdev, intel->rx_skb, data, count,
- intel_recv_pkts,
- ARRAY_SIZE(intel_recv_pkts));
- if (IS_ERR(intel->rx_skb)) {
- int err = PTR_ERR(intel->rx_skb);
- bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
- intel->rx_skb = NULL;
- return err;
- }
-
- return count;
-}
-
-static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb)
-{
- struct intel_data *intel = hu->priv;
- struct list_head *p;
-
- BT_DBG("hu %p skb %p", hu, skb);
-
- /* Be sure our controller is resumed and potential LPM transaction
- * completed before enqueuing any packet.
- */
- mutex_lock(&intel_device_list_lock);
- list_for_each(p, &intel_device_list) {
- struct intel_device *idev = list_entry(p, struct intel_device,
- list);
-
- if (hu->tty->dev->parent == idev->pdev->dev.parent) {
- pm_runtime_get_sync(&idev->pdev->dev);
- pm_runtime_mark_last_busy(&idev->pdev->dev);
- pm_runtime_put_autosuspend(&idev->pdev->dev);
- break;
- }
- }
- mutex_unlock(&intel_device_list_lock);
-
- skb_queue_tail(&intel->txq, skb);
-
- return 0;
-}
-
-static struct sk_buff *intel_dequeue(struct hci_uart *hu)
-{
- struct intel_data *intel = hu->priv;
- struct sk_buff *skb;
-
- skb = skb_dequeue(&intel->txq);
- if (!skb)
- return skb;
-
- if (test_bit(STATE_BOOTLOADER, &intel->flags) &&
- (hci_skb_pkt_type(skb) == HCI_COMMAND_PKT)) {
- struct hci_command_hdr *cmd = (void *)skb->data;
- __u16 opcode = le16_to_cpu(cmd->opcode);
-
- /* When the 0xfc01 command is issued to boot into
- * the operational firmware, it will actually not
- * send a command complete event. To keep the flow
- * control working inject that event here.
- */
- if (opcode == 0xfc01)
- inject_cmd_complete(hu->hdev, opcode);
- }
-
- /* Prepend skb with frame type */
- memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
-
- return skb;
-}
-
-static const struct hci_uart_proto intel_proto = {
- .id = HCI_UART_INTEL,
- .name = "Intel",
- .manufacturer = 2,
- .init_speed = 115200,
- .oper_speed = 3000000,
- .open = intel_open,
- .close = intel_close,
- .flush = intel_flush,
- .setup = intel_setup,
- .set_baudrate = intel_set_baudrate,
- .recv = intel_recv,
- .enqueue = intel_enqueue,
- .dequeue = intel_dequeue,
-};
-
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id intel_acpi_match[] = {
- { "INT33E1", 0 },
- { },
-};
-MODULE_DEVICE_TABLE(acpi, intel_acpi_match);
-#endif
-
-#ifdef CONFIG_PM
-static int intel_suspend_device(struct device *dev)
-{
- struct intel_device *idev = dev_get_drvdata(dev);
-
- mutex_lock(&idev->hu_lock);
- if (idev->hu)
- intel_lpm_suspend(idev->hu);
- mutex_unlock(&idev->hu_lock);
-
- return 0;
-}
-
-static int intel_resume_device(struct device *dev)
-{
- struct intel_device *idev = dev_get_drvdata(dev);
-
- mutex_lock(&idev->hu_lock);
- if (idev->hu)
- intel_lpm_resume(idev->hu);
- mutex_unlock(&idev->hu_lock);
-
- return 0;
-}
-#endif
-
-#ifdef CONFIG_PM_SLEEP
-static int intel_suspend(struct device *dev)
-{
- struct intel_device *idev = dev_get_drvdata(dev);
-
- if (device_may_wakeup(dev))
- enable_irq_wake(idev->irq);
-
- return intel_suspend_device(dev);
-}
-
-static int intel_resume(struct device *dev)
-{
- struct intel_device *idev = dev_get_drvdata(dev);
-
- if (device_may_wakeup(dev))
- disable_irq_wake(idev->irq);
-
- return intel_resume_device(dev);
-}
-#endif
-
-static const struct dev_pm_ops intel_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume)
- SET_RUNTIME_PM_OPS(intel_suspend_device, intel_resume_device, NULL)
-};
-
-static int intel_probe(struct platform_device *pdev)
-{
- struct intel_device *idev;
-
- idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL);
- if (!idev)
- return -ENOMEM;
-
- mutex_init(&idev->hu_lock);
-
- idev->pdev = pdev;
-
- idev->reset = devm_gpiod_get_optional(&pdev->dev, "reset",
- GPIOD_OUT_LOW);
- if (IS_ERR(idev->reset)) {
- dev_err(&pdev->dev, "Unable to retrieve gpio\n");
- return PTR_ERR(idev->reset);
- }
-
- idev->irq = platform_get_irq(pdev, 0);
- if (idev->irq < 0) {
- struct gpio_desc *host_wake;
-
- dev_err(&pdev->dev, "No IRQ, falling back to gpio-irq\n");
-
- host_wake = devm_gpiod_get_optional(&pdev->dev, "host-wake",
- GPIOD_IN);
- if (IS_ERR(host_wake)) {
- dev_err(&pdev->dev, "Unable to retrieve IRQ\n");
- goto no_irq;
- }
-
- idev->irq = gpiod_to_irq(host_wake);
- if (idev->irq < 0) {
- dev_err(&pdev->dev, "No corresponding irq for gpio\n");
- goto no_irq;
- }
- }
-
- /* Only enable wake-up/irq when controller is powered */
- device_set_wakeup_capable(&pdev->dev, true);
- device_wakeup_disable(&pdev->dev);
-
-no_irq:
- platform_set_drvdata(pdev, idev);
-
- /* Place this instance on the device list */
- mutex_lock(&intel_device_list_lock);
- list_add_tail(&idev->list, &intel_device_list);
- mutex_unlock(&intel_device_list_lock);
-
- dev_info(&pdev->dev, "registered, gpio(%d)/irq(%d).\n",
- desc_to_gpio(idev->reset), idev->irq);
-
- return 0;
-}
-
-static int intel_remove(struct platform_device *pdev)
-{
- struct intel_device *idev = platform_get_drvdata(pdev);
-
- device_wakeup_disable(&pdev->dev);
-
- mutex_lock(&intel_device_list_lock);
- list_del(&idev->list);
- mutex_unlock(&intel_device_list_lock);
-
- dev_info(&pdev->dev, "unregistered.\n");
-
- return 0;
-}
-
-static struct platform_driver intel_driver = {
- .probe = intel_probe,
- .remove = intel_remove,
- .driver = {
- .name = "hci_intel",
- .acpi_match_table = ACPI_PTR(intel_acpi_match),
- .pm = &intel_pm_ops,
- },
-};
-
-int __init intel_init(void)
-{
- platform_driver_register(&intel_driver);
-
- return hci_uart_register_proto(&intel_proto);
-}
-
-int __exit intel_deinit(void)
-{
- platform_driver_unregister(&intel_driver);
-
- return hci_uart_unregister_proto(&intel_proto);
-}
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 03146d7..5c9a73f 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -40,7 +40,6 @@
#include <linux/signal.h>
#include <linux/ioctl.h>
#include <linux/skbuff.h>
-#include <linux/firmware.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -162,7 +161,7 @@
break;
}
- hci_uart_tx_complete(hu, hci_skb_pkt_type(skb));
+ hci_uart_tx_complete(hu, bt_cb(skb)->pkt_type);
kfree_skb(skb);
}
@@ -208,6 +207,9 @@
BT_DBG("%s %p", hdev->name, hdev);
/* Nothing to do for UART driver */
+
+ set_bit(HCI_RUNNING, &hdev->flags);
+
return 0;
}
@@ -238,6 +240,9 @@
{
BT_DBG("hdev %p", hdev);
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
hci_uart_flush(hdev);
hdev->flush = NULL;
return 0;
@@ -248,8 +253,10 @@
{
struct hci_uart *hu = hci_get_drvdata(hdev);
- BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb),
- skb->len);
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+ BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
hu->proto->enqueue(hu, skb);
@@ -258,133 +265,11 @@
return 0;
}
-/* Flow control or un-flow control the device */
-void hci_uart_set_flow_control(struct hci_uart *hu, bool enable)
-{
- struct tty_struct *tty = hu->tty;
- struct ktermios ktermios;
- int status;
- unsigned int set = 0;
- unsigned int clear = 0;
-
- if (enable) {
- /* Disable hardware flow control */
- ktermios = tty->termios;
- ktermios.c_cflag &= ~CRTSCTS;
- status = tty_set_termios(tty, &ktermios);
- BT_DBG("Disabling hardware flow control: %s",
- status ? "failed" : "success");
-
- /* Clear RTS to prevent the device from sending */
- /* Most UARTs need OUT2 to enable interrupts */
- status = tty->driver->ops->tiocmget(tty);
- BT_DBG("Current tiocm 0x%x", status);
-
- set &= ~(TIOCM_OUT2 | TIOCM_RTS);
- clear = ~set;
- set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
- TIOCM_OUT2 | TIOCM_LOOP;
- clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
- TIOCM_OUT2 | TIOCM_LOOP;
- status = tty->driver->ops->tiocmset(tty, set, clear);
- BT_DBG("Clearing RTS: %s", status ? "failed" : "success");
- } else {
- /* Set RTS to allow the device to send again */
- status = tty->driver->ops->tiocmget(tty);
- BT_DBG("Current tiocm 0x%x", status);
-
- set |= (TIOCM_OUT2 | TIOCM_RTS);
- clear = ~set;
- set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
- TIOCM_OUT2 | TIOCM_LOOP;
- clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
- TIOCM_OUT2 | TIOCM_LOOP;
- status = tty->driver->ops->tiocmset(tty, set, clear);
- BT_DBG("Setting RTS: %s", status ? "failed" : "success");
-
- /* Re-enable hardware flow control */
- ktermios = tty->termios;
- ktermios.c_cflag |= CRTSCTS;
- status = tty_set_termios(tty, &ktermios);
- BT_DBG("Enabling hardware flow control: %s",
- status ? "failed" : "success");
- }
-}
-
-void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed,
- unsigned int oper_speed)
-{
- hu->init_speed = init_speed;
- hu->oper_speed = oper_speed;
-}
-
-void hci_uart_init_tty(struct hci_uart *hu)
-{
- struct tty_struct *tty = hu->tty;
- struct ktermios ktermios;
-
- /* Bring the UART into a known 8 bits no parity hw fc state */
- ktermios = tty->termios;
- ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP |
- INLCR | IGNCR | ICRNL | IXON);
- ktermios.c_oflag &= ~OPOST;
- ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
- ktermios.c_cflag &= ~(CSIZE | PARENB);
- ktermios.c_cflag |= CS8;
- ktermios.c_cflag |= CRTSCTS;
-
- /* tty_set_termios() return not checked as it is always 0 */
- tty_set_termios(tty, &ktermios);
-}
-
-void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed)
-{
- struct tty_struct *tty = hu->tty;
- struct ktermios ktermios;
-
- ktermios = tty->termios;
- ktermios.c_cflag &= ~CBAUD;
- tty_termios_encode_baud_rate(&ktermios, speed, speed);
-
- /* tty_set_termios() return not checked as it is always 0 */
- tty_set_termios(tty, &ktermios);
-
- BT_DBG("%s: New tty speeds: %d/%d", hu->hdev->name,
- tty->termios.c_ispeed, tty->termios.c_ospeed);
-}
-
static int hci_uart_setup(struct hci_dev *hdev)
{
struct hci_uart *hu = hci_get_drvdata(hdev);
struct hci_rp_read_local_version *ver;
struct sk_buff *skb;
- unsigned int speed;
- int err;
-
- /* Init speed if any */
- if (hu->init_speed)
- speed = hu->init_speed;
- else if (hu->proto->init_speed)
- speed = hu->proto->init_speed;
- else
- speed = 0;
-
- if (speed)
- hci_uart_set_baudrate(hu, speed);
-
- /* Operational speed if any */
- if (hu->oper_speed)
- speed = hu->oper_speed;
- else if (hu->proto->oper_speed)
- speed = hu->proto->oper_speed;
- else
- speed = 0;
-
- if (hu->proto->set_baudrate && speed) {
- err = hu->proto->set_baudrate(hu, speed);
- if (!err)
- hci_uart_set_baudrate(hu, speed);
- }
if (hu->proto->setup)
return hu->proto->setup(hu);
@@ -462,6 +347,8 @@
INIT_WORK(&hu->init_ready, hci_uart_init_work);
INIT_WORK(&hu->write_work, hci_uart_write_work);
+ spin_lock_init(&hu->rx_lock);
+
/* Flush any pending characters in the driver and line discipline. */
/* FIXME: why is this needed. Note don't use ldisc_ref here as the
@@ -559,14 +446,14 @@
if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
return;
- /* It does not need a lock here as it is already protected by a mutex in
- * tty caller
- */
+ spin_lock(&hu->rx_lock);
hu->proto->recv(hu, data, count);
if (hu->hdev)
hu->hdev->stat.byte_rx += count;
+ spin_unlock(&hu->rx_lock);
+
tty_unthrottle(tty);
}
@@ -588,13 +475,6 @@
hdev->bus = HCI_UART;
hci_set_drvdata(hdev, hu);
- /* Only when vendor specific setup callback is provided, consider
- * the manufacturer information valid. This avoids filling in the
- * value for Ericsson when nothing is specified.
- */
- if (hu->proto->setup)
- hdev->manufacturer = hu->proto->manufacturer;
-
hdev->open = hci_uart_open;
hdev->close = hci_uart_close;
hdev->flush = hci_uart_flush;
@@ -767,7 +647,7 @@
/* Register the tty discipline */
- memset(&hci_uart_ldisc, 0, sizeof(hci_uart_ldisc));
+ memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc));
hci_uart_ldisc.magic = TTY_LDISC_MAGIC;
hci_uart_ldisc.name = "n_hci";
hci_uart_ldisc.open = hci_uart_tty_open;
@@ -801,15 +681,9 @@
#ifdef CONFIG_BT_HCIUART_3WIRE
h5_init();
#endif
-#ifdef CONFIG_BT_HCIUART_INTEL
- intel_init();
-#endif
#ifdef CONFIG_BT_HCIUART_BCM
bcm_init();
#endif
-#ifdef CONFIG_BT_HCIUART_QCA
- qca_init();
-#endif
return 0;
}
@@ -833,15 +707,9 @@
#ifdef CONFIG_BT_HCIUART_3WIRE
h5_deinit();
#endif
-#ifdef CONFIG_BT_HCIUART_INTEL
- intel_deinit();
-#endif
#ifdef CONFIG_BT_HCIUART_BCM
bcm_deinit();
#endif
-#ifdef CONFIG_BT_HCIUART_QCA
- qca_deinit();
-#endif
/* Release tty registration of line discipline */
err = tty_unregister_ldisc(N_HCI);
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index 02692fe..9ee24b0 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -307,7 +307,7 @@
BT_DBG("hu %p skb %p", hu, skb);
/* Prepend skb with frame type */
- memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
/* lock hcill state */
spin_lock_irqsave(&ll->hcill_lock, flags);
@@ -493,7 +493,7 @@
return -ENOMEM;
}
- hci_skb_pkt_type(ll->rx_skb) = type;
+ bt_cb(ll->rx_skb)->pkt_type = type;
}
return count;
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
deleted file mode 100644
index 4d32a7c5..0000000
--- a/drivers/bluetooth/hci_qca.c
+++ /dev/null
@@ -1,970 +0,0 @@
-/*
- * Bluetooth Software UART Qualcomm protocol
- *
- * HCI_IBS (HCI In-Band Sleep) is Qualcomm's power management
- * protocol extension to H4.
- *
- * Copyright (C) 2007 Texas Instruments, Inc.
- * Copyright (c) 2010, 2012 The Linux Foundation. All rights reserved.
- *
- * Acknowledgements:
- * This file is based on hci_ll.c, which was...
- * Written by Ohad Ben-Cohen <ohad@bencohen.org>
- * which was in turn based on hci_h4.c, which was written
- * by Maxim Krasnyansky and Marcel Holtmann.
- *
- * 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
- *
- * 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 <linux/kernel.h>
-#include <linux/debugfs.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-#include "hci_uart.h"
-#include "btqca.h"
-
-/* HCI_IBS protocol messages */
-#define HCI_IBS_SLEEP_IND 0xFE
-#define HCI_IBS_WAKE_IND 0xFD
-#define HCI_IBS_WAKE_ACK 0xFC
-#define HCI_MAX_IBS_SIZE 10
-
-/* Controller states */
-#define STATE_IN_BAND_SLEEP_ENABLED 1
-
-#define IBS_WAKE_RETRANS_TIMEOUT_MS 100
-#define IBS_TX_IDLE_TIMEOUT_MS 2000
-#define BAUDRATE_SETTLE_TIMEOUT_MS 300
-
-/* HCI_IBS transmit side sleep protocol states */
-enum tx_ibs_states {
- HCI_IBS_TX_ASLEEP,
- HCI_IBS_TX_WAKING,
- HCI_IBS_TX_AWAKE,
-};
-
-/* HCI_IBS receive side sleep protocol states */
-enum rx_states {
- HCI_IBS_RX_ASLEEP,
- HCI_IBS_RX_AWAKE,
-};
-
-/* HCI_IBS transmit and receive side clock state vote */
-enum hci_ibs_clock_state_vote {
- HCI_IBS_VOTE_STATS_UPDATE,
- HCI_IBS_TX_VOTE_CLOCK_ON,
- HCI_IBS_TX_VOTE_CLOCK_OFF,
- HCI_IBS_RX_VOTE_CLOCK_ON,
- HCI_IBS_RX_VOTE_CLOCK_OFF,
-};
-
-struct qca_data {
- struct hci_uart *hu;
- struct sk_buff *rx_skb;
- struct sk_buff_head txq;
- struct sk_buff_head tx_wait_q; /* HCI_IBS wait queue */
- spinlock_t hci_ibs_lock; /* HCI_IBS state lock */
- u8 tx_ibs_state; /* HCI_IBS transmit side power state*/
- u8 rx_ibs_state; /* HCI_IBS receive side power state */
- u32 tx_vote; /* Clock must be on for TX */
- u32 rx_vote; /* Clock must be on for RX */
- struct timer_list tx_idle_timer;
- u32 tx_idle_delay;
- struct timer_list wake_retrans_timer;
- u32 wake_retrans;
- struct workqueue_struct *workqueue;
- struct work_struct ws_awake_rx;
- struct work_struct ws_awake_device;
- struct work_struct ws_rx_vote_off;
- struct work_struct ws_tx_vote_off;
- unsigned long flags;
-
- /* For debugging purpose */
- u64 ibs_sent_wacks;
- u64 ibs_sent_slps;
- u64 ibs_sent_wakes;
- u64 ibs_recv_wacks;
- u64 ibs_recv_slps;
- u64 ibs_recv_wakes;
- u64 vote_last_jif;
- u32 vote_on_ms;
- u32 vote_off_ms;
- u64 tx_votes_on;
- u64 rx_votes_on;
- u64 tx_votes_off;
- u64 rx_votes_off;
- u64 votes_on;
- u64 votes_off;
-};
-
-static void __serial_clock_on(struct tty_struct *tty)
-{
- /* TODO: Some chipset requires to enable UART clock on client
- * side to save power consumption or manual work is required.
- * Please put your code to control UART clock here if needed
- */
-}
-
-static void __serial_clock_off(struct tty_struct *tty)
-{
- /* TODO: Some chipset requires to disable UART clock on client
- * side to save power consumption or manual work is required.
- * Please put your code to control UART clock off here if needed
- */
-}
-
-/* serial_clock_vote needs to be called with the ibs lock held */
-static void serial_clock_vote(unsigned long vote, struct hci_uart *hu)
-{
- struct qca_data *qca = hu->priv;
- unsigned int diff;
-
- bool old_vote = (qca->tx_vote | qca->rx_vote);
- bool new_vote;
-
- switch (vote) {
- case HCI_IBS_VOTE_STATS_UPDATE:
- diff = jiffies_to_msecs(jiffies - qca->vote_last_jif);
-
- if (old_vote)
- qca->vote_off_ms += diff;
- else
- qca->vote_on_ms += diff;
- return;
-
- case HCI_IBS_TX_VOTE_CLOCK_ON:
- qca->tx_vote = true;
- qca->tx_votes_on++;
- new_vote = true;
- break;
-
- case HCI_IBS_RX_VOTE_CLOCK_ON:
- qca->rx_vote = true;
- qca->rx_votes_on++;
- new_vote = true;
- break;
-
- case HCI_IBS_TX_VOTE_CLOCK_OFF:
- qca->tx_vote = false;
- qca->tx_votes_off++;
- new_vote = qca->rx_vote | qca->tx_vote;
- break;
-
- case HCI_IBS_RX_VOTE_CLOCK_OFF:
- qca->rx_vote = false;
- qca->rx_votes_off++;
- new_vote = qca->rx_vote | qca->tx_vote;
- break;
-
- default:
- BT_ERR("Voting irregularity");
- return;
- }
-
- if (new_vote != old_vote) {
- if (new_vote)
- __serial_clock_on(hu->tty);
- else
- __serial_clock_off(hu->tty);
-
- BT_DBG("Vote serial clock %s(%s)", new_vote ? "true" : "false",
- vote ? "true" : "false");
-
- diff = jiffies_to_msecs(jiffies - qca->vote_last_jif);
-
- if (new_vote) {
- qca->votes_on++;
- qca->vote_off_ms += diff;
- } else {
- qca->votes_off++;
- qca->vote_on_ms += diff;
- }
- qca->vote_last_jif = jiffies;
- }
-}
-
-/* Builds and sends an HCI_IBS command packet.
- * These are very simple packets with only 1 cmd byte.
- */
-static int send_hci_ibs_cmd(u8 cmd, struct hci_uart *hu)
-{
- int err = 0;
- struct sk_buff *skb = NULL;
- struct qca_data *qca = hu->priv;
-
- BT_DBG("hu %p send hci ibs cmd 0x%x", hu, cmd);
-
- skb = bt_skb_alloc(1, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("Failed to allocate memory for HCI_IBS packet");
- return -ENOMEM;
- }
-
- /* Assign HCI_IBS type */
- *skb_put(skb, 1) = cmd;
-
- skb_queue_tail(&qca->txq, skb);
-
- return err;
-}
-
-static void qca_wq_awake_device(struct work_struct *work)
-{
- struct qca_data *qca = container_of(work, struct qca_data,
- ws_awake_device);
- struct hci_uart *hu = qca->hu;
- unsigned long retrans_delay;
-
- BT_DBG("hu %p wq awake device", hu);
-
- /* Vote for serial clock */
- serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
-
- spin_lock(&qca->hci_ibs_lock);
-
- /* Send wake indication to device */
- if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0)
- BT_ERR("Failed to send WAKE to device");
-
- qca->ibs_sent_wakes++;
-
- /* Start retransmit timer */
- retrans_delay = msecs_to_jiffies(qca->wake_retrans);
- mod_timer(&qca->wake_retrans_timer, jiffies + retrans_delay);
-
- spin_unlock(&qca->hci_ibs_lock);
-
- /* Actually send the packets */
- hci_uart_tx_wakeup(hu);
-}
-
-static void qca_wq_awake_rx(struct work_struct *work)
-{
- struct qca_data *qca = container_of(work, struct qca_data,
- ws_awake_rx);
- struct hci_uart *hu = qca->hu;
-
- BT_DBG("hu %p wq awake rx", hu);
-
- serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
-
- spin_lock(&qca->hci_ibs_lock);
- qca->rx_ibs_state = HCI_IBS_RX_AWAKE;
-
- /* Always acknowledge device wake up,
- * sending IBS message doesn't count as TX ON.
- */
- if (send_hci_ibs_cmd(HCI_IBS_WAKE_ACK, hu) < 0)
- BT_ERR("Failed to acknowledge device wake up");
-
- qca->ibs_sent_wacks++;
-
- spin_unlock(&qca->hci_ibs_lock);
-
- /* Actually send the packets */
- hci_uart_tx_wakeup(hu);
-}
-
-static void qca_wq_serial_rx_clock_vote_off(struct work_struct *work)
-{
- struct qca_data *qca = container_of(work, struct qca_data,
- ws_rx_vote_off);
- struct hci_uart *hu = qca->hu;
-
- BT_DBG("hu %p rx clock vote off", hu);
-
- serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_OFF, hu);
-}
-
-static void qca_wq_serial_tx_clock_vote_off(struct work_struct *work)
-{
- struct qca_data *qca = container_of(work, struct qca_data,
- ws_tx_vote_off);
- struct hci_uart *hu = qca->hu;
-
- BT_DBG("hu %p tx clock vote off", hu);
-
- /* Run HCI tx handling unlocked */
- hci_uart_tx_wakeup(hu);
-
- /* Now that message queued to tty driver, vote for tty clocks off.
- * It is up to the tty driver to pend the clocks off until tx done.
- */
- serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
-}
-
-static void hci_ibs_tx_idle_timeout(unsigned long arg)
-{
- struct hci_uart *hu = (struct hci_uart *)arg;
- struct qca_data *qca = hu->priv;
- unsigned long flags;
-
- BT_DBG("hu %p idle timeout in %d state", hu, qca->tx_ibs_state);
-
- spin_lock_irqsave_nested(&qca->hci_ibs_lock,
- flags, SINGLE_DEPTH_NESTING);
-
- switch (qca->tx_ibs_state) {
- case HCI_IBS_TX_AWAKE:
- /* TX_IDLE, go to SLEEP */
- if (send_hci_ibs_cmd(HCI_IBS_SLEEP_IND, hu) < 0) {
- BT_ERR("Failed to send SLEEP to device");
- break;
- }
- qca->tx_ibs_state = HCI_IBS_TX_ASLEEP;
- qca->ibs_sent_slps++;
- queue_work(qca->workqueue, &qca->ws_tx_vote_off);
- break;
-
- case HCI_IBS_TX_ASLEEP:
- case HCI_IBS_TX_WAKING:
- /* Fall through */
-
- default:
- BT_ERR("Spurrious timeout tx state %d", qca->tx_ibs_state);
- break;
- }
-
- spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
-}
-
-static void hci_ibs_wake_retrans_timeout(unsigned long arg)
-{
- struct hci_uart *hu = (struct hci_uart *)arg;
- struct qca_data *qca = hu->priv;
- unsigned long flags, retrans_delay;
- bool retransmit = false;
-
- BT_DBG("hu %p wake retransmit timeout in %d state",
- hu, qca->tx_ibs_state);
-
- spin_lock_irqsave_nested(&qca->hci_ibs_lock,
- flags, SINGLE_DEPTH_NESTING);
-
- switch (qca->tx_ibs_state) {
- case HCI_IBS_TX_WAKING:
- /* No WAKE_ACK, retransmit WAKE */
- retransmit = true;
- if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) {
- BT_ERR("Failed to acknowledge device wake up");
- break;
- }
- qca->ibs_sent_wakes++;
- retrans_delay = msecs_to_jiffies(qca->wake_retrans);
- mod_timer(&qca->wake_retrans_timer, jiffies + retrans_delay);
- break;
-
- case HCI_IBS_TX_ASLEEP:
- case HCI_IBS_TX_AWAKE:
- /* Fall through */
-
- default:
- BT_ERR("Spurrious timeout tx state %d", qca->tx_ibs_state);
- break;
- }
-
- spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
-
- if (retransmit)
- hci_uart_tx_wakeup(hu);
-}
-
-/* Initialize protocol */
-static int qca_open(struct hci_uart *hu)
-{
- struct qca_data *qca;
-
- BT_DBG("hu %p qca_open", hu);
-
- qca = kzalloc(sizeof(struct qca_data), GFP_ATOMIC);
- if (!qca)
- return -ENOMEM;
-
- skb_queue_head_init(&qca->txq);
- skb_queue_head_init(&qca->tx_wait_q);
- spin_lock_init(&qca->hci_ibs_lock);
- qca->workqueue = create_singlethread_workqueue("qca_wq");
- if (!qca->workqueue) {
- BT_ERR("QCA Workqueue not initialized properly");
- kfree(qca);
- return -ENOMEM;
- }
-
- INIT_WORK(&qca->ws_awake_rx, qca_wq_awake_rx);
- INIT_WORK(&qca->ws_awake_device, qca_wq_awake_device);
- INIT_WORK(&qca->ws_rx_vote_off, qca_wq_serial_rx_clock_vote_off);
- INIT_WORK(&qca->ws_tx_vote_off, qca_wq_serial_tx_clock_vote_off);
-
- qca->hu = hu;
-
- /* Assume we start with both sides asleep -- extra wakes OK */
- qca->tx_ibs_state = HCI_IBS_TX_ASLEEP;
- qca->rx_ibs_state = HCI_IBS_RX_ASLEEP;
-
- /* clocks actually on, but we start votes off */
- qca->tx_vote = false;
- qca->rx_vote = false;
- qca->flags = 0;
-
- qca->ibs_sent_wacks = 0;
- qca->ibs_sent_slps = 0;
- qca->ibs_sent_wakes = 0;
- qca->ibs_recv_wacks = 0;
- qca->ibs_recv_slps = 0;
- qca->ibs_recv_wakes = 0;
- qca->vote_last_jif = jiffies;
- qca->vote_on_ms = 0;
- qca->vote_off_ms = 0;
- qca->votes_on = 0;
- qca->votes_off = 0;
- qca->tx_votes_on = 0;
- qca->tx_votes_off = 0;
- qca->rx_votes_on = 0;
- qca->rx_votes_off = 0;
-
- hu->priv = qca;
-
- init_timer(&qca->wake_retrans_timer);
- qca->wake_retrans_timer.function = hci_ibs_wake_retrans_timeout;
- qca->wake_retrans_timer.data = (u_long)hu;
- qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
-
- init_timer(&qca->tx_idle_timer);
- qca->tx_idle_timer.function = hci_ibs_tx_idle_timeout;
- qca->tx_idle_timer.data = (u_long)hu;
- qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
-
- BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
- qca->tx_idle_delay, qca->wake_retrans);
-
- return 0;
-}
-
-static void qca_debugfs_init(struct hci_dev *hdev)
-{
- struct hci_uart *hu = hci_get_drvdata(hdev);
- struct qca_data *qca = hu->priv;
- struct dentry *ibs_dir;
- umode_t mode;
-
- if (!hdev->debugfs)
- return;
-
- ibs_dir = debugfs_create_dir("ibs", hdev->debugfs);
-
- /* read only */
- mode = S_IRUGO;
- debugfs_create_u8("tx_ibs_state", mode, ibs_dir, &qca->tx_ibs_state);
- debugfs_create_u8("rx_ibs_state", mode, ibs_dir, &qca->rx_ibs_state);
- debugfs_create_u64("ibs_sent_sleeps", mode, ibs_dir,
- &qca->ibs_sent_slps);
- debugfs_create_u64("ibs_sent_wakes", mode, ibs_dir,
- &qca->ibs_sent_wakes);
- debugfs_create_u64("ibs_sent_wake_acks", mode, ibs_dir,
- &qca->ibs_sent_wacks);
- debugfs_create_u64("ibs_recv_sleeps", mode, ibs_dir,
- &qca->ibs_recv_slps);
- debugfs_create_u64("ibs_recv_wakes", mode, ibs_dir,
- &qca->ibs_recv_wakes);
- debugfs_create_u64("ibs_recv_wake_acks", mode, ibs_dir,
- &qca->ibs_recv_wacks);
- debugfs_create_bool("tx_vote", mode, ibs_dir, &qca->tx_vote);
- debugfs_create_u64("tx_votes_on", mode, ibs_dir, &qca->tx_votes_on);
- debugfs_create_u64("tx_votes_off", mode, ibs_dir, &qca->tx_votes_off);
- debugfs_create_bool("rx_vote", mode, ibs_dir, &qca->rx_vote);
- debugfs_create_u64("rx_votes_on", mode, ibs_dir, &qca->rx_votes_on);
- debugfs_create_u64("rx_votes_off", mode, ibs_dir, &qca->rx_votes_off);
- debugfs_create_u64("votes_on", mode, ibs_dir, &qca->votes_on);
- debugfs_create_u64("votes_off", mode, ibs_dir, &qca->votes_off);
- debugfs_create_u32("vote_on_ms", mode, ibs_dir, &qca->vote_on_ms);
- debugfs_create_u32("vote_off_ms", mode, ibs_dir, &qca->vote_off_ms);
-
- /* read/write */
- mode = S_IRUGO | S_IWUSR;
- debugfs_create_u32("wake_retrans", mode, ibs_dir, &qca->wake_retrans);
- debugfs_create_u32("tx_idle_delay", mode, ibs_dir,
- &qca->tx_idle_delay);
-}
-
-/* Flush protocol data */
-static int qca_flush(struct hci_uart *hu)
-{
- struct qca_data *qca = hu->priv;
-
- BT_DBG("hu %p qca flush", hu);
-
- skb_queue_purge(&qca->tx_wait_q);
- skb_queue_purge(&qca->txq);
-
- return 0;
-}
-
-/* Close protocol */
-static int qca_close(struct hci_uart *hu)
-{
- struct qca_data *qca = hu->priv;
-
- BT_DBG("hu %p qca close", hu);
-
- serial_clock_vote(HCI_IBS_VOTE_STATS_UPDATE, hu);
-
- skb_queue_purge(&qca->tx_wait_q);
- skb_queue_purge(&qca->txq);
- del_timer(&qca->tx_idle_timer);
- del_timer(&qca->wake_retrans_timer);
- destroy_workqueue(qca->workqueue);
- qca->hu = NULL;
-
- kfree_skb(qca->rx_skb);
-
- hu->priv = NULL;
-
- kfree(qca);
-
- return 0;
-}
-
-/* Called upon a wake-up-indication from the device.
- */
-static void device_want_to_wakeup(struct hci_uart *hu)
-{
- unsigned long flags;
- struct qca_data *qca = hu->priv;
-
- BT_DBG("hu %p want to wake up", hu);
-
- spin_lock_irqsave(&qca->hci_ibs_lock, flags);
-
- qca->ibs_recv_wakes++;
-
- switch (qca->rx_ibs_state) {
- case HCI_IBS_RX_ASLEEP:
- /* Make sure clock is on - we may have turned clock off since
- * receiving the wake up indicator awake rx clock.
- */
- queue_work(qca->workqueue, &qca->ws_awake_rx);
- spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
- return;
-
- case HCI_IBS_RX_AWAKE:
- /* Always acknowledge device wake up,
- * sending IBS message doesn't count as TX ON.
- */
- if (send_hci_ibs_cmd(HCI_IBS_WAKE_ACK, hu) < 0) {
- BT_ERR("Failed to acknowledge device wake up");
- break;
- }
- qca->ibs_sent_wacks++;
- break;
-
- default:
- /* Any other state is illegal */
- BT_ERR("Received HCI_IBS_WAKE_IND in rx state %d",
- qca->rx_ibs_state);
- break;
- }
-
- spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
-
- /* Actually send the packets */
- hci_uart_tx_wakeup(hu);
-}
-
-/* Called upon a sleep-indication from the device.
- */
-static void device_want_to_sleep(struct hci_uart *hu)
-{
- unsigned long flags;
- struct qca_data *qca = hu->priv;
-
- BT_DBG("hu %p want to sleep", hu);
-
- spin_lock_irqsave(&qca->hci_ibs_lock, flags);
-
- qca->ibs_recv_slps++;
-
- switch (qca->rx_ibs_state) {
- case HCI_IBS_RX_AWAKE:
- /* Update state */
- qca->rx_ibs_state = HCI_IBS_RX_ASLEEP;
- /* Vote off rx clock under workqueue */
- queue_work(qca->workqueue, &qca->ws_rx_vote_off);
- break;
-
- case HCI_IBS_RX_ASLEEP:
- /* Fall through */
-
- default:
- /* Any other state is illegal */
- BT_ERR("Received HCI_IBS_SLEEP_IND in rx state %d",
- qca->rx_ibs_state);
- break;
- }
-
- spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
-}
-
-/* Called upon wake-up-acknowledgement from the device
- */
-static void device_woke_up(struct hci_uart *hu)
-{
- unsigned long flags, idle_delay;
- struct qca_data *qca = hu->priv;
- struct sk_buff *skb = NULL;
-
- BT_DBG("hu %p woke up", hu);
-
- spin_lock_irqsave(&qca->hci_ibs_lock, flags);
-
- qca->ibs_recv_wacks++;
-
- switch (qca->tx_ibs_state) {
- case HCI_IBS_TX_AWAKE:
- /* Expect one if we send 2 WAKEs */
- BT_DBG("Received HCI_IBS_WAKE_ACK in tx state %d",
- qca->tx_ibs_state);
- break;
-
- case HCI_IBS_TX_WAKING:
- /* Send pending packets */
- while ((skb = skb_dequeue(&qca->tx_wait_q)))
- skb_queue_tail(&qca->txq, skb);
-
- /* Switch timers and change state to HCI_IBS_TX_AWAKE */
- del_timer(&qca->wake_retrans_timer);
- idle_delay = msecs_to_jiffies(qca->tx_idle_delay);
- mod_timer(&qca->tx_idle_timer, jiffies + idle_delay);
- qca->tx_ibs_state = HCI_IBS_TX_AWAKE;
- break;
-
- case HCI_IBS_TX_ASLEEP:
- /* Fall through */
-
- default:
- BT_ERR("Received HCI_IBS_WAKE_ACK in tx state %d",
- qca->tx_ibs_state);
- break;
- }
-
- spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
-
- /* Actually send the packets */
- hci_uart_tx_wakeup(hu);
-}
-
-/* Enqueue frame for transmittion (padding, crc, etc) may be called from
- * two simultaneous tasklets.
- */
-static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb)
-{
- unsigned long flags = 0, idle_delay;
- struct qca_data *qca = hu->priv;
-
- BT_DBG("hu %p qca enq skb %p tx_ibs_state %d", hu, skb,
- qca->tx_ibs_state);
-
- /* Prepend skb with frame type */
- memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
-
- /* Don't go to sleep in middle of patch download or
- * Out-Of-Band(GPIOs control) sleep is selected.
- */
- if (!test_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags)) {
- skb_queue_tail(&qca->txq, skb);
- return 0;
- }
-
- spin_lock_irqsave(&qca->hci_ibs_lock, flags);
-
- /* Act according to current state */
- switch (qca->tx_ibs_state) {
- case HCI_IBS_TX_AWAKE:
- BT_DBG("Device awake, sending normally");
- skb_queue_tail(&qca->txq, skb);
- idle_delay = msecs_to_jiffies(qca->tx_idle_delay);
- mod_timer(&qca->tx_idle_timer, jiffies + idle_delay);
- break;
-
- case HCI_IBS_TX_ASLEEP:
- BT_DBG("Device asleep, waking up and queueing packet");
- /* Save packet for later */
- skb_queue_tail(&qca->tx_wait_q, skb);
-
- qca->tx_ibs_state = HCI_IBS_TX_WAKING;
- /* Schedule a work queue to wake up device */
- queue_work(qca->workqueue, &qca->ws_awake_device);
- break;
-
- case HCI_IBS_TX_WAKING:
- BT_DBG("Device waking up, queueing packet");
- /* Transient state; just keep packet for later */
- skb_queue_tail(&qca->tx_wait_q, skb);
- break;
-
- default:
- BT_ERR("Illegal tx state: %d (losing packet)",
- qca->tx_ibs_state);
- kfree_skb(skb);
- break;
- }
-
- spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
-
- return 0;
-}
-
-static int qca_ibs_sleep_ind(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_uart *hu = hci_get_drvdata(hdev);
-
- BT_DBG("hu %p recv hci ibs cmd 0x%x", hu, HCI_IBS_SLEEP_IND);
-
- device_want_to_sleep(hu);
-
- kfree_skb(skb);
- return 0;
-}
-
-static int qca_ibs_wake_ind(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_uart *hu = hci_get_drvdata(hdev);
-
- BT_DBG("hu %p recv hci ibs cmd 0x%x", hu, HCI_IBS_WAKE_IND);
-
- device_want_to_wakeup(hu);
-
- kfree_skb(skb);
- return 0;
-}
-
-static int qca_ibs_wake_ack(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_uart *hu = hci_get_drvdata(hdev);
-
- BT_DBG("hu %p recv hci ibs cmd 0x%x", hu, HCI_IBS_WAKE_ACK);
-
- device_woke_up(hu);
-
- kfree_skb(skb);
- return 0;
-}
-
-#define QCA_IBS_SLEEP_IND_EVENT \
- .type = HCI_IBS_SLEEP_IND, \
- .hlen = 0, \
- .loff = 0, \
- .lsize = 0, \
- .maxlen = HCI_MAX_IBS_SIZE
-
-#define QCA_IBS_WAKE_IND_EVENT \
- .type = HCI_IBS_WAKE_IND, \
- .hlen = 0, \
- .loff = 0, \
- .lsize = 0, \
- .maxlen = HCI_MAX_IBS_SIZE
-
-#define QCA_IBS_WAKE_ACK_EVENT \
- .type = HCI_IBS_WAKE_ACK, \
- .hlen = 0, \
- .loff = 0, \
- .lsize = 0, \
- .maxlen = HCI_MAX_IBS_SIZE
-
-static const struct h4_recv_pkt qca_recv_pkts[] = {
- { H4_RECV_ACL, .recv = hci_recv_frame },
- { H4_RECV_SCO, .recv = hci_recv_frame },
- { H4_RECV_EVENT, .recv = hci_recv_frame },
- { QCA_IBS_WAKE_IND_EVENT, .recv = qca_ibs_wake_ind },
- { QCA_IBS_WAKE_ACK_EVENT, .recv = qca_ibs_wake_ack },
- { QCA_IBS_SLEEP_IND_EVENT, .recv = qca_ibs_sleep_ind },
-};
-
-static int qca_recv(struct hci_uart *hu, const void *data, int count)
-{
- struct qca_data *qca = hu->priv;
-
- if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
- return -EUNATCH;
-
- qca->rx_skb = h4_recv_buf(hu->hdev, qca->rx_skb, data, count,
- qca_recv_pkts, ARRAY_SIZE(qca_recv_pkts));
- if (IS_ERR(qca->rx_skb)) {
- int err = PTR_ERR(qca->rx_skb);
- BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
- qca->rx_skb = NULL;
- return err;
- }
-
- return count;
-}
-
-static struct sk_buff *qca_dequeue(struct hci_uart *hu)
-{
- struct qca_data *qca = hu->priv;
-
- return skb_dequeue(&qca->txq);
-}
-
-static uint8_t qca_get_baudrate_value(int speed)
-{
- switch (speed) {
- case 9600:
- return QCA_BAUDRATE_9600;
- case 19200:
- return QCA_BAUDRATE_19200;
- case 38400:
- return QCA_BAUDRATE_38400;
- case 57600:
- return QCA_BAUDRATE_57600;
- case 115200:
- return QCA_BAUDRATE_115200;
- case 230400:
- return QCA_BAUDRATE_230400;
- case 460800:
- return QCA_BAUDRATE_460800;
- case 500000:
- return QCA_BAUDRATE_500000;
- case 921600:
- return QCA_BAUDRATE_921600;
- case 1000000:
- return QCA_BAUDRATE_1000000;
- case 2000000:
- return QCA_BAUDRATE_2000000;
- case 3000000:
- return QCA_BAUDRATE_3000000;
- case 3500000:
- return QCA_BAUDRATE_3500000;
- default:
- return QCA_BAUDRATE_115200;
- }
-}
-
-static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
-{
- struct hci_uart *hu = hci_get_drvdata(hdev);
- struct qca_data *qca = hu->priv;
- struct sk_buff *skb;
- u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
-
- if (baudrate > QCA_BAUDRATE_3000000)
- return -EINVAL;
-
- cmd[4] = baudrate;
-
- skb = bt_skb_alloc(sizeof(cmd), GFP_ATOMIC);
- if (!skb) {
- BT_ERR("Failed to allocate memory for baudrate packet");
- return -ENOMEM;
- }
-
- /* Assign commands to change baudrate and packet type. */
- memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
- hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
-
- skb_queue_tail(&qca->txq, skb);
- hci_uart_tx_wakeup(hu);
-
- /* wait 300ms to change new baudrate on controller side
- * controller will come back after they receive this HCI command
- * then host can communicate with new baudrate to controller
- */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
- set_current_state(TASK_INTERRUPTIBLE);
-
- return 0;
-}
-
-static int qca_setup(struct hci_uart *hu)
-{
- struct hci_dev *hdev = hu->hdev;
- struct qca_data *qca = hu->priv;
- unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
- int ret;
-
- BT_INFO("%s: ROME setup", hdev->name);
-
- /* Patch downloading has to be done without IBS mode */
- clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
-
- /* Setup initial baudrate */
- speed = 0;
- if (hu->init_speed)
- speed = hu->init_speed;
- else if (hu->proto->init_speed)
- speed = hu->proto->init_speed;
-
- if (speed)
- hci_uart_set_baudrate(hu, speed);
-
- /* Setup user speed if needed */
- speed = 0;
- if (hu->oper_speed)
- speed = hu->oper_speed;
- else if (hu->proto->oper_speed)
- speed = hu->proto->oper_speed;
-
- if (speed) {
- qca_baudrate = qca_get_baudrate_value(speed);
-
- BT_INFO("%s: Set UART speed to %d", hdev->name, speed);
- ret = qca_set_baudrate(hdev, qca_baudrate);
- if (ret) {
- BT_ERR("%s: Failed to change the baud rate (%d)",
- hdev->name, ret);
- return ret;
- }
- hci_uart_set_baudrate(hu, speed);
- }
-
- /* Setup patch / NVM configurations */
- ret = qca_uart_setup_rome(hdev, qca_baudrate);
- if (!ret) {
- set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
- qca_debugfs_init(hdev);
- }
-
- /* Setup bdaddr */
- hu->hdev->set_bdaddr = qca_set_bdaddr_rome;
-
- return ret;
-}
-
-static struct hci_uart_proto qca_proto = {
- .id = HCI_UART_QCA,
- .name = "QCA",
- .manufacturer = 29,
- .init_speed = 115200,
- .oper_speed = 3000000,
- .open = qca_open,
- .close = qca_close,
- .flush = qca_flush,
- .setup = qca_setup,
- .recv = qca_recv,
- .enqueue = qca_enqueue,
- .dequeue = qca_dequeue,
-};
-
-int __init qca_init(void)
-{
- return hci_uart_register_proto(&qca_proto);
-}
-
-int __exit qca_deinit(void)
-{
- return hci_uart_unregister_proto(&qca_proto);
-}
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 82c92f1..72120a5 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -35,7 +35,7 @@
#define HCIUARTGETFLAGS _IOR('U', 204, int)
/* UART protocols */
-#define HCI_UART_MAX_PROTO 9
+#define HCI_UART_MAX_PROTO 8
#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
@@ -45,7 +45,6 @@
#define HCI_UART_ATH3K 5
#define HCI_UART_INTEL 6
#define HCI_UART_BCM 7
-#define HCI_UART_QCA 8
#define HCI_UART_RAW_DEVICE 0
#define HCI_UART_RESET_ON_INIT 1
@@ -59,14 +58,10 @@
struct hci_uart_proto {
unsigned int id;
const char *name;
- unsigned int manufacturer;
- unsigned int init_speed;
- unsigned int oper_speed;
int (*open)(struct hci_uart *hu);
int (*close)(struct hci_uart *hu);
int (*flush)(struct hci_uart *hu);
int (*setup)(struct hci_uart *hu);
- int (*set_baudrate)(struct hci_uart *hu, unsigned int speed);
int (*recv)(struct hci_uart *hu, const void *data, int len);
int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
struct sk_buff *(*dequeue)(struct hci_uart *hu);
@@ -86,9 +81,7 @@
struct sk_buff *tx_skb;
unsigned long tx_state;
-
- unsigned int init_speed;
- unsigned int oper_speed;
+ spinlock_t rx_lock;
};
/* HCI_UART proto flag bits */
@@ -103,11 +96,6 @@
int hci_uart_unregister_proto(const struct hci_uart_proto *p);
int hci_uart_tx_wakeup(struct hci_uart *hu);
int hci_uart_init_ready(struct hci_uart *hu);
-void hci_uart_init_tty(struct hci_uart *hu);
-void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed);
-void hci_uart_set_flow_control(struct hci_uart *hu, bool enable);
-void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed,
- unsigned int oper_speed);
#ifdef CONFIG_BT_HCIUART_H4
int h4_init(void);
@@ -168,17 +156,7 @@
int h5_deinit(void);
#endif
-#ifdef CONFIG_BT_HCIUART_INTEL
-int intel_init(void);
-int intel_deinit(void);
-#endif
-
#ifdef CONFIG_BT_HCIUART_BCM
int bcm_init(void);
int bcm_deinit(void);
#endif
-
-#ifdef CONFIG_BT_HCIUART_QCA
-int qca_init(void);
-int qca_deinit(void);
-#endif
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index f712d05..5bb5872 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -55,6 +55,8 @@
static int vhci_open_dev(struct hci_dev *hdev)
{
+ set_bit(HCI_RUNNING, &hdev->flags);
+
return 0;
}
@@ -62,6 +64,9 @@
{
struct vhci_data *data = hci_get_drvdata(hdev);
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
skb_queue_purge(&data->readq);
return 0;
@@ -80,7 +85,10 @@
{
struct vhci_data *data = hci_get_drvdata(hdev);
- memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
skb_queue_tail(&data->readq, skb);
wake_up_interruptible(&data->read_wait);
@@ -140,7 +148,7 @@
return -EBUSY;
}
- hci_skb_pkt_type(skb) = HCI_VENDOR_PKT;
+ bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
*skb_put(skb, 1) = 0xff;
*skb_put(skb, 1) = opcode;
@@ -188,7 +196,7 @@
return -ENODEV;
}
- hci_skb_pkt_type(skb) = pkt_type;
+ bt_cb(skb)->pkt_type = pkt_type;
ret = hci_recv_frame(data->hdev, skb);
break;
@@ -239,7 +247,7 @@
data->hdev->stat.byte_tx += len;
- switch (hci_skb_pkt_type(skb)) {
+ switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
data->hdev->stat.cmd_tx++;
break;
@@ -364,7 +372,7 @@
.llseek = no_llseek,
};
-static struct miscdevice vhci_miscdev = {
+static struct miscdevice vhci_miscdev= {
.name = "vhci",
.fops = &vhci_fops,
.minor = VHCI_MINOR,
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index 4ebac1b..e4279fe 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -79,6 +79,4 @@
}
#endif
-#define request_firmware_direct request_firmware
-
#endif
diff --git a/include/linux/list.h b/include/linux/list.h
index 21ba7c2..b83e565 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -362,25 +362,6 @@
list_entry((ptr)->next, type, member)
/**
- * list_next_entry - get the next element in list
- * @pos: the type * to cursor
- * @member: the name of the list_struct within the struct.
- */
-#define list_next_entry(pos, member) \
- list_entry((pos)->member.next, typeof(*(pos)), member)
-
-/**
- * list_last_entry - get the last element from a list
- * @ptr: the list head to take the element from.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the list_struct within the struct.
- *
- * Note, that list is expected to be not empty.
- */
-#define list_last_entry(ptr, type, member) \
- list_entry((ptr)->prev, type, member)
-
-/**
* list_first_entry_or_null - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 4abec12..8ec93e5 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -29,8 +29,6 @@
#include <net/sock.h>
#include <linux/seq_file.h>
-#define BT_SUBSYS_VERSION "2.21"
-
#ifndef AF_BLUETOOTH
#define AF_BLUETOOTH 31
#define PF_BLUETOOTH AF_BLUETOOTH
@@ -124,28 +122,12 @@
__printf(1, 2)
void bt_info(const char *fmt, ...);
__printf(1, 2)
-void bt_warn(const char *fmt, ...);
-__printf(1, 2)
void bt_err(const char *fmt, ...);
-__printf(1, 2)
-void bt_err_ratelimited(const char *fmt, ...);
#define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__)
-#define BT_WARN(fmt, ...) bt_warn(fmt "\n", ##__VA_ARGS__)
#define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__)
#define BT_DBG(fmt, ...) pr_debug(fmt "\n", ##__VA_ARGS__)
-#define BT_ERR_RATELIMITED(fmt, ...) bt_err_ratelimited(fmt "\n", ##__VA_ARGS__)
-
-#define bt_dev_info(hdev, fmt, ...) \
- BT_INFO("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
-#define bt_dev_warn(hdev, fmt, ...) \
- BT_WARN("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
-#define bt_dev_err(hdev, fmt, ...) \
- BT_ERR("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
-#define bt_dev_dbg(hdev, fmt, ...) \
- BT_DBG("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
-
/* Connection and socket states */
enum {
BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
@@ -298,42 +280,35 @@
typedef void (*hci_req_complete_skb_t)(struct hci_dev *hdev, u8 status,
u16 opcode, struct sk_buff *skb);
-#define HCI_REQ_START BIT(0)
-#define HCI_REQ_SKB BIT(1)
-
-struct hci_ctrl {
- __u16 opcode;
- u8 req_flags;
- u8 req_event;
- union {
- hci_req_complete_t req_complete;
- hci_req_complete_skb_t req_complete_skb;
- };
+struct req_ctrl {
+ bool start;
+ u8 event;
+ hci_req_complete_t complete;
+ hci_req_complete_skb_t complete_skb;
};
struct bt_skb_cb {
__u8 pkt_type;
__u8 force_active;
+ __u16 opcode;
__u16 expect;
__u8 incoming:1;
union {
struct l2cap_ctrl l2cap;
- struct hci_ctrl hci;
+ struct req_ctrl req;
};
};
#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
-#define hci_skb_pkt_type(skb) bt_cb((skb))->pkt_type
-#define hci_skb_expect(skb) bt_cb((skb))->expect
-#define hci_skb_opcode(skb) bt_cb((skb))->hci.opcode
-
static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how)
{
struct sk_buff *skb;
skb = alloc_skb(len + BT_SKB_RESERVE, how);
- if (skb)
+ if (skb) {
skb_reserve(skb, BT_SKB_RESERVE);
+ bt_cb(skb)->incoming = 0;
+ }
return skb;
}
@@ -343,8 +318,10 @@
struct sk_buff *skb;
skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err);
- if (skb)
+ if (skb) {
skb_reserve(skb, BT_SKB_RESERVE);
+ bt_cb(skb)->incoming = 0;
+ }
if (!skb && *err)
return NULL;
@@ -388,19 +365,8 @@
int l2cap_init(void);
void l2cap_exit(void);
-#if IS_ENABLED(CONFIG_BT_BREDR)
int sco_init(void);
void sco_exit(void);
-#else
-static inline int sco_init(void)
-{
- return 0;
-}
-
-static inline void sco_exit(void)
-{
-}
-#endif
int mgmt_init(void);
void mgmt_exit(void);
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index cc22167..d95da83 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -44,9 +44,6 @@
#define HCI_DEV_DOWN 4
#define HCI_DEV_SUSPEND 5
#define HCI_DEV_RESUME 6
-#define HCI_DEV_OPEN 7
-#define HCI_DEV_CLOSE 8
-#define HCI_DEV_SETUP 9
/* HCI notify events */
#define HCI_NOTIFY_CONN_ADD 1
@@ -171,15 +168,6 @@
* during the hdev->setup vendor callback.
*/
HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
-
- /* When this quirk is set, the enabling of diagnostic mode is
- * not persistent over HCI Reset. Every time the controller
- * is brought up it needs to be reprogrammed.
- *
- * This quirk can be set before hci_register_dev is called or
- * during the hdev->setup vendor callback.
- */
- HCI_QUIRK_NON_PERSISTENT_DIAG,
};
/* HCI device flags */
@@ -250,7 +238,6 @@
HCI_LE_SCAN_INTERRUPTED,
HCI_DUT_MODE,
- HCI_VENDOR_DIAG,
HCI_FORCE_BREDR_SMP,
HCI_FORCE_STATIC_ADDR,
@@ -273,7 +260,6 @@
#define HCI_ACLDATA_PKT 0x02
#define HCI_SCODATA_PKT 0x03
#define HCI_EVENT_PKT 0x04
-#define HCI_DIAG_PKT 0xf0
#define HCI_VENDOR_PKT 0xff
/* HCI packet types */
@@ -452,8 +438,7 @@
#define HCI_ERROR_REMOTE_POWER_OFF 0x15
#define HCI_ERROR_LOCAL_HOST_TERM 0x16
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
-#define HCI_ERROR_INVALID_LL_PARAMS 0x1e
-#define HCI_ERROR_UNSPECIFIED 0x1f
+#define HCI_ERROR_INVALID_LL_PARAMS 0x1E
#define HCI_ERROR_ADVERTISING_TIMEOUT 0x3c
/* Flow control modes */
@@ -1217,16 +1202,6 @@
__le16 accuracy;
} __packed;
-#define HCI_OP_READ_ENC_KEY_SIZE 0x1408
-struct hci_cp_read_enc_key_size {
- __le16 handle;
-} __packed;
-struct hci_rp_read_enc_key_size {
- __u8 status;
- __le16 handle;
- __u8 key_size;
-} __packed;
-
#define HCI_OP_READ_LOCAL_AMP_INFO 0x1409
struct hci_rp_read_local_amp_info {
__u8 status;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 55ce209..1391af4 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -156,22 +156,16 @@
};
struct adv_info {
- struct list_head list;
- bool pending;
+ struct delayed_work timeout_exp;
__u8 instance;
__u32 flags;
__u16 timeout;
- __u16 remaining_time;
- __u16 duration;
__u16 adv_data_len;
__u8 adv_data[HCI_MAX_AD_LENGTH];
__u16 scan_rsp_len;
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
};
-#define HCI_MAX_ADV_INSTANCES 5
-#define HCI_DEFAULT_ADV_DURATION 2
-
#define HCI_MAX_SHORT_NAME_LENGTH 10
/* Default LE RPA expiry time, 15 minutes */
@@ -327,11 +321,6 @@
struct work_struct cmd_work;
struct work_struct tx_work;
- struct work_struct discov_update;
- struct work_struct bg_scan_update;
- struct delayed_work le_scan_disable;
- struct delayed_work le_scan_restart;
-
struct sk_buff_head rx_q;
struct sk_buff_head raw_q;
struct sk_buff_head cmd_q;
@@ -375,17 +364,16 @@
DECLARE_BITMAP(dev_flags, __HCI_NUM_FLAGS);
+ struct delayed_work le_scan_disable;
+ struct delayed_work le_scan_restart;
+
__s8 adv_tx_power;
__u8 adv_data[HCI_MAX_AD_LENGTH];
__u8 adv_data_len;
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
__u8 scan_rsp_data_len;
- struct list_head adv_instances;
- unsigned int adv_instance_cnt;
- __u8 cur_adv_instance;
- __u16 adv_instance_timeout;
- struct delayed_work adv_instance_expire;
+ struct adv_info adv_instance;
__u8 irk[16];
__u32 rpa_timeout;
@@ -400,8 +388,6 @@
int (*send)(struct hci_dev *hdev, struct sk_buff *skb);
void (*notify)(struct hci_dev *hdev, unsigned int evt);
void (*hw_error)(struct hci_dev *hdev, u8 code);
- int (*post_init)(struct hci_dev *hdev);
- int (*set_diag)(struct hci_dev *hdev, bool enable);
int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
};
@@ -547,22 +533,10 @@
/* ----- HCI interface to upper protocols ----- */
int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
int l2cap_disconn_ind(struct hci_conn *hcon);
-void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags);
+int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags);
-#if IS_ENABLED(CONFIG_BT_BREDR)
int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags);
-void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
-#else
-static inline int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
- __u8 *flags)
-{
- return 0;
-}
-
-static inline void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
-{
-}
-#endif
+int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
/* ----- Inquiry cache ----- */
#define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */
@@ -590,6 +564,11 @@
hdev->discovery.scan_duration = 0;
}
+static inline void adv_info_init(struct hci_dev *hdev)
+{
+ memset(&hdev->adv_instance, 0, sizeof(struct adv_info));
+}
+
bool hci_discovery_active(struct hci_dev *hdev);
void hci_discovery_set_state(struct hci_dev *hdev, int state);
@@ -796,30 +775,6 @@
return NULL;
}
-static inline struct hci_conn *hci_conn_hash_lookup_le(struct hci_dev *hdev,
- bdaddr_t *ba,
- __u8 ba_type)
-{
- struct hci_conn_hash *h = &hdev->conn_hash;
- struct hci_conn *c;
-
- rcu_read_lock();
-
- list_for_each_entry_rcu(c, &h->list, list) {
- if (c->type != LE_LINK)
- continue;
-
- if (ba_type == c->dst_type && !bacmp(&c->dst, ba)) {
- rcu_read_unlock();
- return c;
- }
- }
-
- rcu_read_unlock();
-
- return NULL;
-}
-
static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
__u8 type, __u16 state)
{
@@ -877,7 +832,7 @@
struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level,
- u16 conn_timeout);
+ u16 conn_timeout, u8 role);
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level, u16 conn_timeout,
u8 role);
@@ -1016,7 +971,6 @@
int hci_reset_dev(struct hci_dev *hdev);
int hci_dev_open(__u16 dev);
int hci_dev_close(__u16 dev);
-int hci_dev_do_close(struct hci_dev *hdev);
int hci_dev_reset(__u16 dev);
int hci_dev_reset_stat(__u16 dev);
int hci_dev_cmd(unsigned int cmd, void __user *arg);
@@ -1038,11 +992,15 @@
struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev,
bdaddr_t *addr, u8 addr_type);
void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
+void hci_conn_params_clear_all(struct hci_dev *hdev);
void hci_conn_params_clear_disabled(struct hci_dev *hdev);
struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list,
bdaddr_t *addr,
u8 addr_type);
+struct hci_conn_params *hci_explicit_connect_lookup(struct hci_dev *hdev,
+ bdaddr_t *addr,
+ u8 addr_type);
void hci_uuids_clear(struct hci_dev *hdev);
@@ -1079,19 +1037,9 @@
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 bdaddr_type);
-void hci_adv_instances_clear(struct hci_dev *hdev);
-struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
-struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance);
-int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
- u16 adv_data_len, u8 *adv_data,
- u16 scan_rsp_len, u8 *scan_rsp_data,
- u16 timeout, u16 duration);
-int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
-
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
-int hci_recv_diag(struct hci_dev *hdev, struct sk_buff *skb);
void hci_init_sysfs(struct hci_dev *hdev);
void hci_conn_init_sysfs(struct hci_conn *conn);
@@ -1353,7 +1301,7 @@
if (max >= to_multiplier * 8)
return -EINVAL;
- max_latency = (to_multiplier * 4 / max) - 1;
+ max_latency = (to_multiplier * 8 / max) - 1;
if (latency > 499 || latency > max_latency)
return -EINVAL;
@@ -1375,9 +1323,6 @@
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
-struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
- const void *param, u32 timeout);
-
/* ----- HCI Sockets ----- */
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
void hci_send_to_channel(unsigned short channel, struct sk_buff *skb,
@@ -1435,7 +1380,6 @@
int mgmt_powered(struct hci_dev *hdev, u8 powered);
int mgmt_update_adv_data(struct hci_dev *hdev);
void mgmt_discoverable_timeout(struct hci_dev *hdev);
-void mgmt_adv_timeout_expired(struct hci_dev *hdev);
void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
bool persistent);
void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
@@ -1474,8 +1418,6 @@
void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
u8 status);
void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
-void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status);
-void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status);
void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len);
@@ -1484,7 +1426,7 @@
void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
bool mgmt_powering_down(struct hci_dev *hdev);
void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent);
-void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent);
+void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk);
void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
bool persistent);
void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
@@ -1496,7 +1438,7 @@
u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
u16 to_multiplier);
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
- __u8 ltk[16], __u8 key_size);
+ __u8 ltk[16]);
void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 *bdaddr_type);
diff --git a/include/net/bluetooth/hci_mon.h b/include/net/bluetooth/hci_mon.h
index 587d013..77d1e57 100644
--- a/include/net/bluetooth/hci_mon.h
+++ b/include/net/bluetooth/hci_mon.h
@@ -39,12 +39,6 @@
#define HCI_MON_ACL_RX_PKT 5
#define HCI_MON_SCO_TX_PKT 6
#define HCI_MON_SCO_RX_PKT 7
-#define HCI_MON_OPEN_INDEX 8
-#define HCI_MON_CLOSE_INDEX 9
-#define HCI_MON_INDEX_INFO 10
-#define HCI_MON_VENDOR_DIAG 11
-#define HCI_MON_SYSTEM_NOTE 12
-#define HCI_MON_USER_LOGGING 13
struct hci_mon_new_index {
__u8 type;
@@ -54,10 +48,4 @@
} __packed;
#define HCI_MON_NEW_INDEX_SIZE 16
-struct hci_mon_index_info {
- bdaddr_t bdaddr;
- __le16 manufacturer;
-} __packed;
-#define HCI_MON_INDEX_INFO_SIZE 8
-
#endif /* __HCI_MON_H */
diff --git a/include/net/bluetooth/hci_sock.h b/include/net/bluetooth/hci_sock.h
index 8e9138a..9a46d66 100644
--- a/include/net/bluetooth/hci_sock.h
+++ b/include/net/bluetooth/hci_sock.h
@@ -45,7 +45,6 @@
#define HCI_CHANNEL_USER 1
#define HCI_CHANNEL_MONITOR 2
#define HCI_CHANNEL_CONTROL 3
-#define HCI_CHANNEL_LOGGING 4
struct hci_filter {
unsigned long type_mask;
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index e74f41d..bbc75ea 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -55,8 +55,6 @@
#define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000)
#define L2CAP_MOVE_TIMEOUT msecs_to_jiffies(4000)
#define L2CAP_MOVE_ERTX_TIMEOUT msecs_to_jiffies(60000)
-#define L2CAP_WAIT_ACK_POLL_PERIOD msecs_to_jiffies(200)
-#define L2CAP_WAIT_ACK_TIMEOUT msecs_to_jiffies(10000)
#define L2CAP_A2MP_DEFAULT_MTU 670
@@ -252,7 +250,7 @@
#define L2CAP_PSM_3DSP 0x0021
#define L2CAP_PSM_IPSP 0x0023 /* 6LoWPAN */
-/* channel identifier */
+/* channel indentifier */
#define L2CAP_CID_SIGNALING 0x0001
#define L2CAP_CID_CONN_LESS 0x0002
#define L2CAP_CID_A2MP 0x0003
@@ -275,8 +273,6 @@
#define L2CAP_CR_AUTHORIZATION 0x0006
#define L2CAP_CR_BAD_KEY_SIZE 0x0007
#define L2CAP_CR_ENCRYPTION 0x0008
-#define L2CAP_CR_INVALID_SCID 0x0009
-#define L2CAP_CR_SCID_IN_USE 0x0010
/* connect/create channel status */
#define L2CAP_CS_NO_INFO 0x0000
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 83c8055..e76e495 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2016,6 +2016,9 @@
perf_event_update_userpage(next_event);
}
+#define list_next_entry(pos, member) \
+ list_entry(pos->member.next, typeof(*pos), member)
+
static void perf_event_sync_stat(struct perf_event_context *ctx,
struct perf_event_context *next_ctx)
{
diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig
index 32b9294..81f837f 100644
--- a/net/bluetooth/Kconfig
+++ b/net/bluetooth/Kconfig
@@ -53,11 +53,6 @@
source "net/bluetooth/hidp/Kconfig"
-config BT_HS
- bool "Bluetooth High Speed (HS) features"
- depends on BT_BREDR
- default y
-
config BT_LE
bool "Bluetooth Low Energy (LE) features"
depends on BT
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index 6857bf7..c85a6af 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -9,11 +9,9 @@
obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
- hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
- ecc.o hci_request.o mgmt_util.o
+ hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
+ a2mp.o amp.o ecc.o hci_request.o mgmt_util.o
-bluetooth-$(CONFIG_BT_BREDR) += sco.o
-bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o
bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 8d68dfc..fe79321 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -16,7 +16,6 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
-#include "hci_request.h"
#include "a2mp.h"
#include "amp.h"
@@ -288,21 +287,11 @@
return 0;
}
-static void read_local_amp_info_complete(struct hci_dev *hdev, u8 status,
- u16 opcode)
-{
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- a2mp_send_getinfo_rsp(hdev);
-}
-
static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_cmd *hdr)
{
struct a2mp_info_req *req = (void *) skb->data;
struct hci_dev *hdev;
- struct hci_request hreq;
- int err = 0;
if (le16_to_cpu(hdr->len) < sizeof(*req))
return -EINVAL;
@@ -323,11 +312,7 @@
}
set_bit(READ_LOC_AMP_INFO, &mgr->state);
- hci_req_init(&hreq, hdev);
- hci_req_add(&hreq, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
- err = hci_req_run(&hreq, read_local_amp_info_complete);
- if (err < 0)
- a2mp_send_getinfo_rsp(hdev);
+ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
done:
if (hdev)
diff --git a/net/bluetooth/a2mp.h b/net/bluetooth/a2mp.h
index a4ff3ea..296f665 100644
--- a/net/bluetooth/a2mp.h
+++ b/net/bluetooth/a2mp.h
@@ -130,29 +130,10 @@
#define A2MP_STATUS_SECURITY_VIOLATION 0x06
struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr);
-
-#if IS_ENABLED(CONFIG_BT_HS)
int amp_mgr_put(struct amp_mgr *mgr);
struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
struct sk_buff *skb);
void a2mp_discover_amp(struct l2cap_chan *chan);
-#else
-static inline int amp_mgr_put(struct amp_mgr *mgr)
-{
- return 0;
-}
-
-static inline struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
- struct sk_buff *skb)
-{
- return NULL;
-}
-
-static inline void a2mp_discover_amp(struct l2cap_chan *chan)
-{
-}
-#endif
-
void a2mp_send_getinfo_rsp(struct hci_dev *hdev);
void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status);
void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status);
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 8b92dc9..7594511 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -33,6 +33,8 @@
#include "selftest.h"
+#define VERSION "2.20"
+
/* Bluetooth sockets */
#define BT_MAX_PROTO 8
static const struct net_proto_family *bt_proto[BT_MAX_PROTO];
@@ -219,14 +221,15 @@
BT_DBG("sock %p sk %p len %zu", sock, sk, len);
- if (flags & MSG_OOB)
+ if (flags & (MSG_OOB))
return -EOPNOTSUPP;
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (!skb) {
- if (sk->sk_shutdown & RCV_SHUTDOWN)
+ if (sk->sk_shutdown & RCV_SHUTDOWN) {
+ msg->msg_namelen = 0;
return 0;
-
+ }
return err;
}
@@ -244,6 +247,8 @@
if (bt_sk(sk)->skb_msg_name)
bt_sk(sk)->skb_msg_name(skb, msg->msg_name,
&msg->msg_namelen);
+ else
+ msg->msg_namelen = 0;
}
skb_free_datagram(sk, skb);
@@ -282,7 +287,7 @@
}
int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size, int flags)
+ struct msghdr *msg, size_t size, int flags)
{
struct sock *sk = sock->sk;
int err = 0;
@@ -714,7 +719,7 @@
BUILD_BUG_ON(sizeof(struct bt_skb_cb) > sizeof(skb->cb));
- BT_INFO("Core ver %s", BT_SUBSYS_VERSION);
+ BT_INFO("Core ver %s", VERSION);
err = bt_selftest();
if (err < 0)
@@ -788,7 +793,7 @@
module_exit(bt_exit);
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth Core ver " BT_SUBSYS_VERSION);
-MODULE_VERSION(BT_SUBSYS_VERSION);
+MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
+MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
MODULE_ALIAS_NETPROTO(PF_BLUETOOTH);
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index e32f341..ee016f0 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -16,7 +16,6 @@
#include <net/bluetooth/hci_core.h>
#include <crypto/hash.h>
-#include "hci_request.h"
#include "a2mp.h"
#include "amp.h"
@@ -221,49 +220,10 @@
return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data);
}
-static void read_local_amp_assoc_complete(struct hci_dev *hdev, u8 status,
- u16 opcode, struct sk_buff *skb)
-{
- struct hci_rp_read_local_amp_assoc *rp = (void *)skb->data;
- struct amp_assoc *assoc = &hdev->loc_assoc;
- size_t rem_len, frag_len;
-
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
-
- if (rp->status)
- goto send_rsp;
-
- frag_len = skb->len - sizeof(*rp);
- rem_len = __le16_to_cpu(rp->rem_len);
-
- if (rem_len > frag_len) {
- BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len);
-
- memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
- assoc->offset += frag_len;
-
- /* Read other fragments */
- amp_read_loc_assoc_frag(hdev, rp->phy_handle);
-
- return;
- }
-
- memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
- assoc->len = assoc->offset + rem_len;
- assoc->offset = 0;
-
-send_rsp:
- /* Send A2MP Rsp when all fragments are received */
- a2mp_send_getampassoc_rsp(hdev, rp->status);
- a2mp_send_create_phy_link_req(hdev, rp->status);
-}
-
void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
{
struct hci_cp_read_local_amp_assoc cp;
struct amp_assoc *loc_assoc = &hdev->loc_assoc;
- struct hci_request req;
- int err = 0;
BT_DBG("%s handle %d", hdev->name, phy_handle);
@@ -271,18 +231,12 @@
cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
cp.len_so_far = cpu_to_le16(loc_assoc->offset);
- hci_req_init(&req, hdev);
- hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
- err = hci_req_run_skb(&req, read_local_amp_assoc_complete);
- if (err < 0)
- a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
+ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
}
void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
{
struct hci_cp_read_local_amp_assoc cp;
- struct hci_request req;
- int err = 0;
memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc));
memset(&cp, 0, sizeof(cp));
@@ -290,11 +244,7 @@
cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
set_bit(READ_LOC_AMP_ASSOC, &mgr->state);
- hci_req_init(&req, hdev);
- hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
- hci_req_run_skb(&req, read_local_amp_assoc_complete);
- if (err < 0)
- a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
+ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
}
void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
@@ -302,8 +252,6 @@
{
struct hci_cp_read_local_amp_assoc cp;
struct amp_mgr *mgr = hcon->amp_mgr;
- struct hci_request req;
- int err = 0;
cp.phy_handle = hcon->handle;
cp.len_so_far = cpu_to_le16(0);
@@ -312,25 +260,7 @@
set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state);
/* Read Local AMP Assoc final link information data */
- hci_req_init(&req, hdev);
- hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
- hci_req_run_skb(&req, read_local_amp_assoc_complete);
- if (err < 0)
- a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
-}
-
-static void write_remote_amp_assoc_complete(struct hci_dev *hdev, u8 status,
- u16 opcode, struct sk_buff *skb)
-{
- struct hci_rp_write_remote_amp_assoc *rp = (void *)skb->data;
-
- BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
- hdev->name, rp->status, rp->phy_handle);
-
- if (rp->status)
- return;
-
- amp_write_rem_assoc_continue(hdev, rp->phy_handle);
+ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
}
/* Write AMP Assoc data fragments, returns true with last fragment written*/
@@ -340,7 +270,6 @@
struct hci_cp_write_remote_amp_assoc *cp;
struct amp_mgr *mgr = hcon->amp_mgr;
struct amp_ctrl *ctrl;
- struct hci_request req;
u16 frag_len, len;
ctrl = amp_ctrl_lookup(mgr, hcon->remote_id);
@@ -378,9 +307,7 @@
amp_ctrl_put(ctrl);
- hci_req_init(&req, hdev);
- hci_req_add(&req, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp);
- hci_req_run_skb(&req, write_remote_amp_assoc_complete);
+ hci_send_cmd(hdev, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp);
kfree(cp);
@@ -417,37 +344,10 @@
amp_write_rem_assoc_frag(hdev, hcon);
}
-static void create_phylink_complete(struct hci_dev *hdev, u8 status,
- u16 opcode)
-{
- struct hci_cp_create_phy_link *cp;
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- if (status) {
- struct hci_conn *hcon;
-
- hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle);
- if (hcon)
- hci_conn_del(hcon);
- } else {
- amp_write_remote_assoc(hdev, cp->phy_handle);
- }
-
- hci_dev_unlock(hdev);
-}
-
void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon)
{
struct hci_cp_create_phy_link cp;
- struct hci_request req;
cp.phy_handle = hcon->handle;
@@ -460,33 +360,13 @@
return;
}
- hci_req_init(&req, hdev);
- hci_req_add(&req, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp);
- hci_req_run(&req, create_phylink_complete);
-}
-
-static void accept_phylink_complete(struct hci_dev *hdev, u8 status,
- u16 opcode)
-{
- struct hci_cp_accept_phy_link *cp;
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- if (status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK);
- if (!cp)
- return;
-
- amp_write_remote_assoc(hdev, cp->phy_handle);
+ hci_send_cmd(hdev, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp);
}
void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon)
{
struct hci_cp_accept_phy_link cp;
- struct hci_request req;
cp.phy_handle = hcon->handle;
@@ -499,9 +379,7 @@
return;
}
- hci_req_init(&req, hdev);
- hci_req_add(&req, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
- hci_req_run(&req, accept_phylink_complete);
+ hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
}
void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon)
diff --git a/net/bluetooth/amp.h b/net/bluetooth/amp.h
index 8848f81..7ea3db7 100644
--- a/net/bluetooth/amp.h
+++ b/net/bluetooth/amp.h
@@ -44,20 +44,6 @@
struct hci_conn *hcon);
void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon);
-
-#if IS_ENABLED(CONFIG_BT_HS)
-void amp_create_logical_link(struct l2cap_chan *chan);
-void amp_disconnect_logical_link(struct hci_chan *hchan);
-#else
-static inline void amp_create_logical_link(struct l2cap_chan *chan)
-{
-}
-
-static inline void amp_disconnect_logical_link(struct hci_chan *hchan)
-{
-}
-#endif
-
void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon);
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h
index 40854c9..c91bda6 100644
--- a/net/bluetooth/bnep/bnep.h
+++ b/net/bluetooth/bnep/bnep.h
@@ -12,7 +12,8 @@
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, see <http://www.gnu.org/licenses/>.
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _BNEP_H
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index 1641367..d210577 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -577,9 +577,8 @@
/* session struct allocated as private part of net_device */
dev = alloc_netdev(sizeof(struct bnep_session),
- (*req->device) ? req->device : "bnep%d",
- NET_NAME_UNKNOWN,
- bnep_net_setup);
+ (*req->device) ? req->device : "bnep%d",
+ bnep_net_setup);
if (!dev)
return -ENOMEM;
diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c
index 9a503387..b0c6c6af 100644
--- a/net/bluetooth/cmtp/capi.c
+++ b/net/bluetooth/cmtp/capi.c
@@ -100,9 +100,9 @@
static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
{
struct cmtp_application *app;
- struct list_head *p;
+ struct list_head *p, *n;
- list_for_each(p, &session->applications) {
+ list_for_each_safe(p, n, &session->applications) {
app = list_entry(p, struct cmtp_application, list);
switch (pattern) {
case CMTP_MSGNUM:
@@ -511,13 +511,13 @@
struct capi_ctr *ctrl = m->private;
struct cmtp_session *session = ctrl->driverdata;
struct cmtp_application *app;
- struct list_head *p;
+ struct list_head *p, *n;
seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
seq_printf(m, "addr %s\n", session->name);
seq_printf(m, "ctrl %d\n", session->num);
- list_for_each(p, &session->applications) {
+ list_for_each_safe(p, n, &session->applications) {
app = list_entry(p, struct cmtp_application, list);
seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 2d334e0..8d9367e 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -59,11 +59,15 @@
{ EDR_ESCO_MASK | ESCO_EV3, 0x0008, 0x02 }, /* T1 */
};
+static void hci_le_create_connection_cancel(struct hci_conn *conn)
+{
+ hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
+}
+
/* This function requires the caller holds hdev->lock */
static void hci_connect_le_scan_cleanup(struct hci_conn *conn)
{
struct hci_conn_params *params;
- struct hci_dev *hdev = conn->hdev;
struct smp_irk *irk;
bdaddr_t *bdaddr;
u8 bdaddr_type;
@@ -72,15 +76,14 @@
bdaddr_type = conn->dst_type;
/* Check if we need to convert to identity address */
- irk = hci_get_irk(hdev, bdaddr, bdaddr_type);
+ irk = hci_get_irk(conn->hdev, bdaddr, bdaddr_type);
if (irk) {
bdaddr = &irk->bdaddr;
bdaddr_type = irk->addr_type;
}
- params = hci_pend_le_action_lookup(&hdev->pend_le_conns, bdaddr,
- bdaddr_type);
- if (!params || !params->explicit_connect)
+ params = hci_explicit_connect_lookup(conn->hdev, bdaddr, bdaddr_type);
+ if (!params)
return;
/* The connection attempt was doing scan for new RPA, and is
@@ -94,21 +97,21 @@
switch (params->auto_connect) {
case HCI_AUTO_CONN_EXPLICIT:
- hci_conn_params_del(hdev, bdaddr, bdaddr_type);
+ hci_conn_params_del(conn->hdev, bdaddr, bdaddr_type);
/* return instead of break to avoid duplicate scan update */
return;
case HCI_AUTO_CONN_DIRECT:
case HCI_AUTO_CONN_ALWAYS:
- list_add(¶ms->action, &hdev->pend_le_conns);
+ list_add(¶ms->action, &conn->hdev->pend_le_conns);
break;
case HCI_AUTO_CONN_REPORT:
- list_add(¶ms->action, &hdev->pend_le_reports);
+ list_add(¶ms->action, &conn->hdev->pend_le_reports);
break;
default:
break;
}
- hci_update_background_scan(hdev);
+ hci_update_background_scan(conn->hdev);
}
static void hci_conn_cleanup(struct hci_conn *conn)
@@ -178,10 +181,6 @@
hci_dev_hold(conn->hdev);
hci_conn_get(conn);
- /* Even though we hold a reference to the hdev, many other
- * things might get cleaned up meanwhile, including the hdev's
- * own workqueue, so we can't use that for scheduling.
- */
schedule_work(&conn->le_scan_cleanup);
}
@@ -228,8 +227,33 @@
hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
}
+static void hci_acl_create_connection_cancel(struct hci_conn *conn)
+{
+ struct hci_cp_create_conn_cancel cp;
+
+ BT_DBG("hcon %p", conn);
+
+ if (conn->hdev->hci_ver < BLUETOOTH_VER_1_2)
+ return;
+
+ bacpy(&cp.bdaddr, &conn->dst);
+ hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
+}
+
+static void hci_reject_sco(struct hci_conn *conn)
+{
+ struct hci_cp_reject_sync_conn_req cp;
+
+ cp.reason = HCI_ERROR_REJ_LIMITED_RESOURCES;
+ bacpy(&cp.bdaddr, &conn->dst);
+
+ hci_send_cmd(conn->hdev, HCI_OP_REJECT_SYNC_CONN_REQ, sizeof(cp), &cp);
+}
+
int hci_disconnect(struct hci_conn *conn, __u8 reason)
{
+ struct hci_cp_disconnect cp;
+
BT_DBG("hcon %p", conn);
/* When we are master of an established connection and it enters
@@ -237,8 +261,7 @@
* current clock offset. Processing of the result is done
* within the event handling and hci_clock_offset_evt function.
*/
- if (conn->type == ACL_LINK && conn->role == HCI_ROLE_MASTER &&
- (conn->state == BT_CONNECTED || conn->state == BT_CONFIG)) {
+ if (conn->type == ACL_LINK && conn->role == HCI_ROLE_MASTER) {
struct hci_dev *hdev = conn->hdev;
struct hci_cp_read_clock_offset clkoff_cp;
@@ -247,7 +270,25 @@
&clkoff_cp);
}
- return hci_abort_conn(conn, reason);
+ conn->state = BT_DISCONN;
+
+ cp.handle = cpu_to_le16(conn->handle);
+ cp.reason = reason;
+ return hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
+}
+
+static void hci_amp_disconn(struct hci_conn *conn)
+{
+ struct hci_cp_disconn_phy_link cp;
+
+ BT_DBG("hcon %p", conn);
+
+ conn->state = BT_DISCONN;
+
+ cp.phy_handle = HCI_PHY_HANDLE(conn->handle);
+ cp.reason = hci_proto_disconn_ind(conn);
+ hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHY_LINK,
+ sizeof(cp), &cp);
}
static void hci_add_sco(struct hci_conn *conn, __u16 handle)
@@ -355,7 +396,7 @@
}
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
- __u8 ltk[16], __u8 key_size)
+ __u8 ltk[16])
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_start_enc cp;
@@ -367,7 +408,7 @@
cp.handle = cpu_to_le16(conn->handle);
cp.rand = rand;
cp.ediv = ediv;
- memcpy(cp.ltk, ltk, key_size);
+ memcpy(cp.ltk, ltk, sizeof(cp.ltk));
hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
}
@@ -413,14 +454,35 @@
if (refcnt > 0)
return;
- /* LE connections in scanning state need special handling */
- if (conn->state == BT_CONNECT && conn->type == LE_LINK &&
- test_bit(HCI_CONN_SCANNING, &conn->flags)) {
- hci_connect_le_scan_remove(conn);
- return;
+ switch (conn->state) {
+ case BT_CONNECT:
+ case BT_CONNECT2:
+ if (conn->out) {
+ if (conn->type == ACL_LINK)
+ hci_acl_create_connection_cancel(conn);
+ else if (conn->type == LE_LINK) {
+ if (test_bit(HCI_CONN_SCANNING, &conn->flags))
+ hci_connect_le_scan_remove(conn);
+ else
+ hci_le_create_connection_cancel(conn);
+ }
+ } else if (conn->type == SCO_LINK || conn->type == ESCO_LINK) {
+ hci_reject_sco(conn);
+ }
+ break;
+ case BT_CONFIG:
+ case BT_CONNECTED:
+ if (conn->type == AMP_LINK) {
+ hci_amp_disconn(conn);
+ } else {
+ __u8 reason = hci_proto_disconn_ind(conn);
+ hci_disconnect(conn, reason);
+ }
+ break;
+ default:
+ conn->state = BT_CLOSED;
+ break;
}
-
- hci_abort_conn(conn, hci_proto_disconn_ind(conn));
}
/* Enter sniff mode */
@@ -488,7 +550,7 @@
return;
}
- hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
+ hci_le_create_connection_cancel(conn);
}
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
@@ -785,7 +847,7 @@
u8 role)
{
struct hci_conn_params *params;
- struct hci_conn *conn;
+ struct hci_conn *conn, *conn_unfinished;
struct smp_irk *irk;
struct hci_request req;
int err;
@@ -798,22 +860,35 @@
return ERR_PTR(-EOPNOTSUPP);
}
+ /* Some devices send ATT messages as soon as the physical link is
+ * established. To be able to handle these ATT messages, the user-
+ * space first establishes the connection and then starts the pairing
+ * process.
+ *
+ * So if a hci_conn object already exists for the following connection
+ * attempt, we simply update pending_sec_level and auth_type fields
+ * and return the object found.
+ */
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
+ conn_unfinished = NULL;
+ if (conn) {
+ if (conn->state == BT_CONNECT &&
+ test_bit(HCI_CONN_SCANNING, &conn->flags)) {
+ BT_DBG("will continue unfinished conn %pMR", dst);
+ conn_unfinished = conn;
+ } else {
+ if (conn->pending_sec_level < sec_level)
+ conn->pending_sec_level = sec_level;
+ goto done;
+ }
+ }
+
/* Since the controller supports only one LE connection attempt at a
* time, we return -EBUSY if there is any connection attempt running.
*/
if (hci_lookup_le_connect(hdev))
return ERR_PTR(-EBUSY);
- /* If there's already a connection object but it's not in
- * scanning state it means it must already be established, in
- * which case we can't do anything else except report a failure
- * to connect.
- */
- conn = hci_conn_hash_lookup_le(hdev, dst, dst_type);
- if (conn && !test_bit(HCI_CONN_SCANNING, &conn->flags)) {
- return ERR_PTR(-EBUSY);
- }
-
/* When given an identity address with existing identity
* resolving key, the connection needs to be established
* to a resolvable random address.
@@ -829,20 +904,23 @@
dst_type = ADDR_LE_DEV_RANDOM;
}
- if (conn) {
+ if (conn_unfinished) {
+ conn = conn_unfinished;
bacpy(&conn->dst, dst);
} else {
conn = hci_conn_add(hdev, LE_LINK, dst, role);
- if (!conn)
- return ERR_PTR(-ENOMEM);
- hci_conn_hold(conn);
- conn->pending_sec_level = sec_level;
}
+ if (!conn)
+ return ERR_PTR(-ENOMEM);
+
conn->dst_type = dst_type;
conn->sec_level = BT_SECURITY_LOW;
conn->conn_timeout = conn_timeout;
+ if (!conn_unfinished)
+ conn->pending_sec_level = sec_level;
+
hci_req_init(&req, hdev);
/* Disable advertising if we're active. For master role
@@ -906,17 +984,48 @@
return ERR_PTR(err);
}
+done:
+ /* If this is continuation of connect started by hci_connect_le_scan,
+ * it already called hci_conn_hold and calling it again would mess the
+ * counter.
+ */
+ if (!conn_unfinished)
+ hci_conn_hold(conn);
+
return conn;
}
+static void hci_connect_le_scan_complete(struct hci_dev *hdev, u8 status,
+ u16 opcode)
+{
+ struct hci_conn *conn;
+
+ if (!status)
+ return;
+
+ BT_ERR("Failed to add device to auto conn whitelist: status 0x%2.2x",
+ status);
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+ if (conn)
+ hci_le_conn_failed(conn, status);
+
+ hci_dev_unlock(hdev);
+}
+
static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
{
struct hci_conn *conn;
- conn = hci_conn_hash_lookup_le(hdev, addr, type);
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
if (!conn)
return false;
+ if (conn->dst_type != type)
+ return false;
+
if (conn->state != BT_CONNECTED)
return false;
@@ -924,9 +1033,10 @@
}
/* This function requires the caller holds hdev->lock */
-static int hci_explicit_conn_params_set(struct hci_dev *hdev,
+static int hci_explicit_conn_params_set(struct hci_request *req,
bdaddr_t *addr, u8 addr_type)
{
+ struct hci_dev *hdev = req->hdev;
struct hci_conn_params *params;
if (is_connected(hdev, addr, addr_type))
@@ -954,6 +1064,7 @@
}
params->explicit_connect = true;
+ __hci_update_background_scan(req);
BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
params->auto_connect);
@@ -964,9 +1075,11 @@
/* This function requires the caller holds hdev->lock */
struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level,
- u16 conn_timeout)
+ u16 conn_timeout, u8 role)
{
struct hci_conn *conn;
+ struct hci_request req;
+ int err;
/* Let's make sure that le is enabled.*/
if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
@@ -985,7 +1098,7 @@
* attempt, we simply update pending_sec_level and auth_type fields
* and return the object found.
*/
- conn = hci_conn_hash_lookup_le(hdev, dst, dst_type);
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
if (conn) {
if (conn->pending_sec_level < sec_level)
conn->pending_sec_level = sec_level;
@@ -994,22 +1107,29 @@
BT_DBG("requesting refresh of dst_addr");
- conn = hci_conn_add(hdev, LE_LINK, dst, HCI_ROLE_MASTER);
+ conn = hci_conn_add(hdev, LE_LINK, dst, role);
if (!conn)
return ERR_PTR(-ENOMEM);
- if (hci_explicit_conn_params_set(hdev, dst, dst_type) < 0)
+ hci_req_init(&req, hdev);
+
+ if (hci_explicit_conn_params_set(&req, dst, dst_type) < 0)
return ERR_PTR(-EBUSY);
conn->state = BT_CONNECT;
set_bit(HCI_CONN_SCANNING, &conn->flags);
+
+ err = hci_req_run(&req, hci_connect_le_scan_complete);
+ if (err && err != -ENODATA) {
+ hci_conn_del(conn);
+ return ERR_PTR(err);
+ }
+
conn->dst_type = dst_type;
conn->sec_level = BT_SECURITY_LOW;
conn->pending_sec_level = sec_level;
conn->conn_timeout = conn_timeout;
- hci_update_background_scan(hdev);
-
done:
hci_conn_hold(conn);
return conn;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0e2b409..7942b00 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -56,6 +56,22 @@
/* HCI ID Numbering */
static DEFINE_IDA(hci_index_ida);
+/* ----- HCI requests ----- */
+
+#define HCI_REQ_DONE 0
+#define HCI_REQ_PEND 1
+#define HCI_REQ_CANCELED 2
+
+#define hci_req_lock(d) mutex_lock(&d->req_lock)
+#define hci_req_unlock(d) mutex_unlock(&d->req_lock)
+
+/* ---- HCI notifications ---- */
+
+static void hci_notify(struct hci_dev *hdev, int event)
+{
+ hci_sock_dev_event(hdev, event);
+}
+
/* ---- HCI debugfs entries ---- */
static ssize_t dut_mode_read(struct file *file, char __user *user_buf,
@@ -78,6 +94,7 @@
char buf[32];
size_t buf_size = min(count, (sizeof(buf)-1));
bool enable;
+ int err;
if (!test_bit(HCI_UP, &hdev->flags))
return -ENETDOWN;
@@ -92,20 +109,24 @@
if (enable == hci_dev_test_flag(hdev, HCI_DUT_MODE))
return -EALREADY;
- hci_req_sync_lock(hdev);
+ hci_req_lock(hdev);
if (enable)
skb = __hci_cmd_sync(hdev, HCI_OP_ENABLE_DUT_MODE, 0, NULL,
HCI_CMD_TIMEOUT);
else
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL,
HCI_CMD_TIMEOUT);
- hci_req_sync_unlock(hdev);
+ hci_req_unlock(hdev);
if (IS_ERR(skb))
return PTR_ERR(skb);
+ err = -bt_to_errno(skb->data[0]);
kfree_skb(skb);
+ if (err < 0)
+ return err;
+
hci_dev_change_flag(hdev, HCI_DUT_MODE);
return count;
@@ -118,85 +139,197 @@
.llseek = default_llseek,
};
-static ssize_t vendor_diag_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct hci_dev *hdev = file->private_data;
- char buf[3];
+/* ---- HCI requests ---- */
- buf[0] = hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) ? 'Y': 'N';
- buf[1] = '\n';
- buf[2] = '\0';
- return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+static void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
+ struct sk_buff *skb)
+{
+ BT_DBG("%s result 0x%2.2x", hdev->name, result);
+
+ if (hdev->req_status == HCI_REQ_PEND) {
+ hdev->req_result = result;
+ hdev->req_status = HCI_REQ_DONE;
+ if (skb)
+ hdev->req_skb = skb_get(skb);
+ wake_up_interruptible(&hdev->req_wait_q);
+ }
}
-static ssize_t vendor_diag_write(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
+static void hci_req_cancel(struct hci_dev *hdev, int err)
{
- struct hci_dev *hdev = file->private_data;
- char buf[32];
- size_t buf_size = min(count, (sizeof(buf)-1));
- bool enable;
- int err;
+ BT_DBG("%s err 0x%2.2x", hdev->name, err);
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
+ if (hdev->req_status == HCI_REQ_PEND) {
+ hdev->req_result = err;
+ hdev->req_status = HCI_REQ_CANCELED;
+ wake_up_interruptible(&hdev->req_wait_q);
+ }
+}
- buf[buf_size] = '\0';
- if (strtobool(buf, &enable))
- return -EINVAL;
+struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
+ const void *param, u8 event, u32 timeout)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct hci_request req;
+ struct sk_buff *skb;
+ int err = 0;
- /* When the diagnostic flags are not persistent and the transport
- * is not active, then there is no need for the vendor callback.
- *
- * Instead just store the desired value. If needed the setting
- * will be programmed when the controller gets powered on.
- */
- if (test_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks) &&
- !test_bit(HCI_RUNNING, &hdev->flags))
- goto done;
+ BT_DBG("%s", hdev->name);
- hci_req_sync_lock(hdev);
- err = hdev->set_diag(hdev, enable);
- hci_req_sync_unlock(hdev);
+ hci_req_init(&req, hdev);
- if (err < 0)
+ hci_req_add_ev(&req, opcode, plen, param, event);
+
+ hdev->req_status = HCI_REQ_PEND;
+
+ add_wait_queue(&hdev->req_wait_q, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ err = hci_req_run_skb(&req, hci_req_sync_complete);
+ if (err < 0) {
+ remove_wait_queue(&hdev->req_wait_q, &wait);
+ set_current_state(TASK_RUNNING);
+ return ERR_PTR(err);
+ }
+
+ schedule_timeout(timeout);
+
+ remove_wait_queue(&hdev->req_wait_q, &wait);
+
+ if (signal_pending(current))
+ return ERR_PTR(-EINTR);
+
+ switch (hdev->req_status) {
+ case HCI_REQ_DONE:
+ err = -bt_to_errno(hdev->req_result);
+ break;
+
+ case HCI_REQ_CANCELED:
+ err = -hdev->req_result;
+ break;
+
+ default:
+ err = -ETIMEDOUT;
+ break;
+ }
+
+ hdev->req_status = hdev->req_result = 0;
+ skb = hdev->req_skb;
+ hdev->req_skb = NULL;
+
+ BT_DBG("%s end: err %d", hdev->name, err);
+
+ if (err < 0) {
+ kfree_skb(skb);
+ return ERR_PTR(err);
+ }
+
+ if (!skb)
+ return ERR_PTR(-ENODATA);
+
+ return skb;
+}
+EXPORT_SYMBOL(__hci_cmd_sync_ev);
+
+struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
+ const void *param, u32 timeout)
+{
+ return __hci_cmd_sync_ev(hdev, opcode, plen, param, 0, timeout);
+}
+EXPORT_SYMBOL(__hci_cmd_sync);
+
+/* Execute request and wait for completion. */
+static int __hci_req_sync(struct hci_dev *hdev,
+ void (*func)(struct hci_request *req,
+ unsigned long opt),
+ unsigned long opt, __u32 timeout)
+{
+ struct hci_request req;
+ DECLARE_WAITQUEUE(wait, current);
+ int err = 0;
+
+ BT_DBG("%s start", hdev->name);
+
+ hci_req_init(&req, hdev);
+
+ hdev->req_status = HCI_REQ_PEND;
+
+ func(&req, opt);
+
+ add_wait_queue(&hdev->req_wait_q, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ err = hci_req_run_skb(&req, hci_req_sync_complete);
+ if (err < 0) {
+ hdev->req_status = 0;
+
+ remove_wait_queue(&hdev->req_wait_q, &wait);
+ set_current_state(TASK_RUNNING);
+
+ /* ENODATA means the HCI request command queue is empty.
+ * This can happen when a request with conditionals doesn't
+ * trigger any commands to be sent. This is normal behavior
+ * and should not trigger an error return.
+ */
+ if (err == -ENODATA)
+ return 0;
+
return err;
+ }
-done:
- if (enable)
- hci_dev_set_flag(hdev, HCI_VENDOR_DIAG);
- else
- hci_dev_clear_flag(hdev, HCI_VENDOR_DIAG);
+ schedule_timeout(timeout);
- return count;
+ remove_wait_queue(&hdev->req_wait_q, &wait);
+
+ if (signal_pending(current))
+ return -EINTR;
+
+ switch (hdev->req_status) {
+ case HCI_REQ_DONE:
+ err = -bt_to_errno(hdev->req_result);
+ break;
+
+ case HCI_REQ_CANCELED:
+ err = -hdev->req_result;
+ break;
+
+ default:
+ err = -ETIMEDOUT;
+ break;
+ }
+
+ hdev->req_status = hdev->req_result = 0;
+
+ BT_DBG("%s end: err %d", hdev->name, err);
+
+ return err;
}
-static const struct file_operations vendor_diag_fops = {
- .open = simple_open,
- .read = vendor_diag_read,
- .write = vendor_diag_write,
- .llseek = default_llseek,
-};
-
-static void hci_debugfs_create_basic(struct hci_dev *hdev)
+static int hci_req_sync(struct hci_dev *hdev,
+ void (*req)(struct hci_request *req,
+ unsigned long opt),
+ unsigned long opt, __u32 timeout)
{
- debugfs_create_file("dut_mode", 0644, hdev->debugfs, hdev,
- &dut_mode_fops);
+ int ret;
- if (hdev->set_diag)
- debugfs_create_file("vendor_diag", 0644, hdev->debugfs, hdev,
- &vendor_diag_fops);
+ if (!test_bit(HCI_UP, &hdev->flags))
+ return -ENETDOWN;
+
+ /* Serialize all requests */
+ hci_req_lock(hdev);
+ ret = __hci_req_sync(hdev, req, opt, timeout);
+ hci_req_unlock(hdev);
+
+ return ret;
}
-static int hci_reset_req(struct hci_request *req, unsigned long opt)
+static void hci_reset_req(struct hci_request *req, unsigned long opt)
{
BT_DBG("%s %ld", req->hdev->name, opt);
/* Reset device */
set_bit(HCI_RESET, &req->hdev->flags);
hci_req_add(req, HCI_OP_RESET, 0, NULL);
- return 0;
}
static void bredr_init(struct hci_request *req)
@@ -236,7 +369,7 @@
hci_req_add(req, HCI_OP_READ_LOCATION_DATA, 0, NULL);
}
-static int amp_init2(struct hci_request *req)
+static void amp_init2(struct hci_request *req)
{
/* Read Local Supported Features. Not all AMP controllers
* support this so it's placed conditionally in the second
@@ -244,11 +377,9 @@
*/
if (req->hdev->commands[14] & 0x20)
hci_req_add(req, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
-
- return 0;
}
-static int hci_init1_req(struct hci_request *req, unsigned long opt)
+static void hci_init1_req(struct hci_request *req, unsigned long opt)
{
struct hci_dev *hdev = req->hdev;
@@ -271,8 +402,6 @@
BT_ERR("Unknown device type %d", hdev->dev_type);
break;
}
-
- return 0;
}
static void bredr_setup(struct hci_request *req)
@@ -349,30 +478,20 @@
if (lmp_bredr_capable(hdev)) {
events[4] |= 0x01; /* Flow Specification Complete */
+ events[4] |= 0x02; /* Inquiry Result with RSSI */
+ events[4] |= 0x04; /* Read Remote Extended Features Complete */
+ events[5] |= 0x08; /* Synchronous Connection Complete */
+ events[5] |= 0x10; /* Synchronous Connection Changed */
} else {
/* Use a different default for LE-only devices */
memset(events, 0, sizeof(events));
+ events[0] |= 0x10; /* Disconnection Complete */
+ events[1] |= 0x08; /* Read Remote Version Information Complete */
events[1] |= 0x20; /* Command Complete */
events[1] |= 0x40; /* Command Status */
events[1] |= 0x80; /* Hardware Error */
-
- /* If the controller supports the Disconnect command, enable
- * the corresponding event. In addition enable packet flow
- * control related events.
- */
- if (hdev->commands[0] & 0x20) {
- events[0] |= 0x10; /* Disconnection Complete */
- events[2] |= 0x04; /* Number of Completed Packets */
- events[3] |= 0x02; /* Data Buffer Overflow */
- }
-
- /* If the controller supports the Read Remote Version
- * Information command, enable the corresponding event.
- */
- if (hdev->commands[2] & 0x80)
- events[1] |= 0x08; /* Read Remote Version Information
- * Complete
- */
+ events[2] |= 0x04; /* Number of Completed Packets */
+ events[3] |= 0x02; /* Data Buffer Overflow */
if (hdev->le_features[0] & HCI_LE_ENCRYPTION) {
events[0] |= 0x80; /* Encryption Change */
@@ -380,18 +499,9 @@
}
}
- if (lmp_inq_rssi_capable(hdev) ||
- test_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks))
+ if (lmp_inq_rssi_capable(hdev))
events[4] |= 0x02; /* Inquiry Result with RSSI */
- if (lmp_ext_feat_capable(hdev))
- events[4] |= 0x04; /* Read Remote Extended Features Complete */
-
- if (lmp_esco_capable(hdev)) {
- events[5] |= 0x08; /* Synchronous Connection Complete */
- events[5] |= 0x10; /* Synchronous Connection Changed */
- }
-
if (lmp_sniffsubr_capable(hdev))
events[5] |= 0x20; /* Sniff Subrating */
@@ -427,7 +537,7 @@
hci_req_add(req, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
}
-static int hci_init2_req(struct hci_request *req, unsigned long opt)
+static void hci_init2_req(struct hci_request *req, unsigned long opt)
{
struct hci_dev *hdev = req->hdev;
@@ -507,8 +617,6 @@
hci_req_add(req, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
&enable);
}
-
- return 0;
}
static void hci_setup_link_policy(struct hci_request *req)
@@ -583,15 +691,14 @@
hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events);
}
-static int hci_init3_req(struct hci_request *req, unsigned long opt)
+static void hci_init3_req(struct hci_request *req, unsigned long opt)
{
struct hci_dev *hdev = req->hdev;
u8 p;
hci_setup_event_mask(req);
- if (hdev->commands[6] & 0x20 &&
- !test_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks)) {
+ if (hdev->commands[6] & 0x20) {
struct hci_cp_read_stored_link_key cp;
bacpy(&cp.bdaddr, BDADDR_ANY);
@@ -616,6 +723,7 @@
u8 events[8];
memset(events, 0, sizeof(events));
+ events[0] = 0x0f;
if (hdev->le_features[0] & HCI_LE_ENCRYPTION)
events[0] |= 0x10; /* LE Long Term Key Request */
@@ -642,34 +750,6 @@
* Report
*/
- /* If the controller supports the LE Set Scan Enable command,
- * enable the corresponding advertising report event.
- */
- if (hdev->commands[26] & 0x08)
- events[0] |= 0x02; /* LE Advertising Report */
-
- /* If the controller supports the LE Create Connection
- * command, enable the corresponding event.
- */
- if (hdev->commands[26] & 0x10)
- events[0] |= 0x01; /* LE Connection Complete */
-
- /* If the controller supports the LE Connection Update
- * command, enable the corresponding event.
- */
- if (hdev->commands[27] & 0x04)
- events[0] |= 0x04; /* LE Connection Update
- * Complete
- */
-
- /* If the controller supports the LE Read Remote Used Features
- * command, enable the corresponding event.
- */
- if (hdev->commands[27] & 0x20)
- events[0] |= 0x08; /* LE Read Remote Used
- * Features Complete
- */
-
/* If the controller supports the LE Read Local P-256
* Public Key command, enable the corresponding event.
*/
@@ -711,11 +791,9 @@
hci_req_add(req, HCI_OP_READ_LOCAL_EXT_FEATURES,
sizeof(cp), &cp);
}
-
- return 0;
}
-static int hci_init4_req(struct hci_request *req, unsigned long opt)
+static void hci_init4_req(struct hci_request *req, unsigned long opt)
{
struct hci_dev *hdev = req->hdev;
@@ -766,22 +844,25 @@
hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT,
sizeof(support), &support);
}
-
- return 0;
}
static int __hci_init(struct hci_dev *hdev)
{
int err;
- err = __hci_req_sync(hdev, hci_init1_req, 0, HCI_INIT_TIMEOUT, NULL);
+ err = __hci_req_sync(hdev, hci_init1_req, 0, HCI_INIT_TIMEOUT);
if (err < 0)
return err;
- if (hci_dev_test_flag(hdev, HCI_SETUP))
- hci_debugfs_create_basic(hdev);
+ /* The Device Under Test (DUT) mode is special and available for
+ * all controller types. So just create it early on.
+ */
+ if (hci_dev_test_flag(hdev, HCI_SETUP)) {
+ debugfs_create_file("dut_mode", 0644, hdev->debugfs, hdev,
+ &dut_mode_fops);
+ }
- err = __hci_req_sync(hdev, hci_init2_req, 0, HCI_INIT_TIMEOUT, NULL);
+ err = __hci_req_sync(hdev, hci_init2_req, 0, HCI_INIT_TIMEOUT);
if (err < 0)
return err;
@@ -792,11 +873,11 @@
if (hdev->dev_type != HCI_BREDR)
return 0;
- err = __hci_req_sync(hdev, hci_init3_req, 0, HCI_INIT_TIMEOUT, NULL);
+ err = __hci_req_sync(hdev, hci_init3_req, 0, HCI_INIT_TIMEOUT);
if (err < 0)
return err;
- err = __hci_req_sync(hdev, hci_init4_req, 0, HCI_INIT_TIMEOUT, NULL);
+ err = __hci_req_sync(hdev, hci_init4_req, 0, HCI_INIT_TIMEOUT);
if (err < 0)
return err;
@@ -827,7 +908,7 @@
return 0;
}
-static int hci_init0_req(struct hci_request *req, unsigned long opt)
+static void hci_init0_req(struct hci_request *req, unsigned long opt)
{
struct hci_dev *hdev = req->hdev;
@@ -843,8 +924,6 @@
/* Read BD Address */
if (hdev->set_bdaddr)
hci_req_add(req, HCI_OP_READ_BD_ADDR, 0, NULL);
-
- return 0;
}
static int __hci_unconf_init(struct hci_dev *hdev)
@@ -854,17 +933,14 @@
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
return 0;
- err = __hci_req_sync(hdev, hci_init0_req, 0, HCI_INIT_TIMEOUT, NULL);
+ err = __hci_req_sync(hdev, hci_init0_req, 0, HCI_INIT_TIMEOUT);
if (err < 0)
return err;
- if (hci_dev_test_flag(hdev, HCI_SETUP))
- hci_debugfs_create_basic(hdev);
-
return 0;
}
-static int hci_scan_req(struct hci_request *req, unsigned long opt)
+static void hci_scan_req(struct hci_request *req, unsigned long opt)
{
__u8 scan = opt;
@@ -872,10 +948,9 @@
/* Inquiry and Page scans */
hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
- return 0;
}
-static int hci_auth_req(struct hci_request *req, unsigned long opt)
+static void hci_auth_req(struct hci_request *req, unsigned long opt)
{
__u8 auth = opt;
@@ -883,10 +958,9 @@
/* Authentication */
hci_req_add(req, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth);
- return 0;
}
-static int hci_encrypt_req(struct hci_request *req, unsigned long opt)
+static void hci_encrypt_req(struct hci_request *req, unsigned long opt)
{
__u8 encrypt = opt;
@@ -894,10 +968,9 @@
/* Encryption */
hci_req_add(req, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
- return 0;
}
-static int hci_linkpol_req(struct hci_request *req, unsigned long opt)
+static void hci_linkpol_req(struct hci_request *req, unsigned long opt)
{
__le16 policy = cpu_to_le16(opt);
@@ -905,7 +978,6 @@
/* Default link policy */
hci_req_add(req, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
- return 0;
}
/* Get HCI device by index.
@@ -1150,7 +1222,7 @@
return copied;
}
-static int hci_inq_req(struct hci_request *req, unsigned long opt)
+static void hci_inq_req(struct hci_request *req, unsigned long opt)
{
struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
struct hci_dev *hdev = req->hdev;
@@ -1159,15 +1231,13 @@
BT_DBG("%s", hdev->name);
if (test_bit(HCI_INQUIRY, &hdev->flags))
- return 0;
+ return;
/* Start Inquiry */
memcpy(&cp.lap, &ir->lap, 3);
cp.length = ir->length;
cp.num_rsp = ir->num_rsp;
hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
-
- return 0;
}
static int wait_inquiry(void *word)
@@ -1224,7 +1294,7 @@
if (do_inquiry) {
err = hci_req_sync(hdev, hci_inq_req, (unsigned long) &ir,
- timeo, NULL);
+ timeo);
if (err < 0)
goto done;
@@ -1277,7 +1347,7 @@
BT_DBG("%s %p", hdev->name, hdev);
- hci_req_sync_lock(hdev);
+ hci_req_lock(hdev);
if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
ret = -ENODEV;
@@ -1325,15 +1395,10 @@
goto done;
}
- set_bit(HCI_RUNNING, &hdev->flags);
- hci_sock_dev_event(hdev, HCI_DEV_OPEN);
-
atomic_set(&hdev->cmd_cnt, 1);
set_bit(HCI_INIT, &hdev->flags);
if (hci_dev_test_flag(hdev, HCI_SETUP)) {
- hci_sock_dev_event(hdev, HCI_DEV_SETUP);
-
if (hdev->setup)
ret = hdev->setup(hdev);
@@ -1374,28 +1439,17 @@
if (!ret) {
if (!hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
- !hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
+ !hci_dev_test_flag(hdev, HCI_USER_CHANNEL))
ret = __hci_init(hdev);
- if (!ret && hdev->post_init)
- ret = hdev->post_init(hdev);
- }
}
- /* If the HCI Reset command is clearing all diagnostic settings,
- * then they need to be reprogrammed after the init procedure
- * completed.
- */
- if (test_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks) &&
- hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) && hdev->set_diag)
- ret = hdev->set_diag(hdev, true);
-
clear_bit(HCI_INIT, &hdev->flags);
if (!ret) {
hci_dev_hold(hdev);
hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
set_bit(HCI_UP, &hdev->flags);
- hci_sock_dev_event(hdev, HCI_DEV_UP);
+ hci_notify(hdev, HCI_DEV_UP);
if (!hci_dev_test_flag(hdev, HCI_SETUP) &&
!hci_dev_test_flag(hdev, HCI_CONFIG) &&
!hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
@@ -1422,15 +1476,12 @@
hdev->sent_cmd = NULL;
}
- clear_bit(HCI_RUNNING, &hdev->flags);
- hci_sock_dev_event(hdev, HCI_DEV_CLOSE);
-
hdev->close(hdev);
hdev->flags &= BIT(HCI_RAW);
}
done:
- hci_req_sync_unlock(hdev);
+ hci_req_unlock(hdev);
return ret;
}
@@ -1508,15 +1559,11 @@
BT_DBG("All LE pending actions cleared");
}
-int hci_dev_do_close(struct hci_dev *hdev)
+static int hci_dev_do_close(struct hci_dev *hdev)
{
- bool auto_off;
-
BT_DBG("%s %p", hdev->name, hdev);
- if (!hci_dev_test_flag(hdev, HCI_UNREGISTER) &&
- !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
- test_bit(HCI_UP, &hdev->flags)) {
+ if (!hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
/* Execute vendor specific shutdown routine */
if (hdev->shutdown)
hdev->shutdown(hdev);
@@ -1524,12 +1571,12 @@
cancel_delayed_work(&hdev->power_off);
- hci_req_sync_cancel(hdev, ENODEV);
- hci_req_sync_lock(hdev);
+ hci_req_cancel(hdev, ENODEV);
+ hci_req_lock(hdev);
if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
cancel_delayed_work_sync(&hdev->cmd_timer);
- hci_req_sync_unlock(hdev);
+ hci_req_unlock(hdev);
return 0;
}
@@ -1547,14 +1594,12 @@
if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
cancel_delayed_work(&hdev->service_cache);
+ cancel_delayed_work_sync(&hdev->le_scan_disable);
+ cancel_delayed_work_sync(&hdev->le_scan_restart);
+
if (hci_dev_test_flag(hdev, HCI_MGMT))
cancel_delayed_work_sync(&hdev->rpa_expired);
- if (hdev->adv_instance_timeout) {
- cancel_delayed_work_sync(&hdev->adv_instance_expire);
- hdev->adv_instance_timeout = 0;
- }
-
/* Avoid potential lockdep warnings from the *_flush() calls by
* ensuring the workqueue is empty up front.
*/
@@ -1564,10 +1609,10 @@
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- auto_off = hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF);
-
- if (!auto_off && hdev->dev_type == HCI_BREDR)
- mgmt_powered(hdev, 0);
+ if (!hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
+ if (hdev->dev_type == HCI_BREDR)
+ mgmt_powered(hdev, 0);
+ }
hci_inquiry_cache_flush(hdev);
hci_pend_le_actions_clear(hdev);
@@ -1576,7 +1621,7 @@
smp_unregister(hdev);
- hci_sock_dev_event(hdev, HCI_DEV_DOWN);
+ hci_notify(hdev, HCI_DEV_DOWN);
if (hdev->flush)
hdev->flush(hdev);
@@ -1584,10 +1629,11 @@
/* Reset device */
skb_queue_purge(&hdev->cmd_q);
atomic_set(&hdev->cmd_cnt, 1);
- if (test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks) &&
- !auto_off && !hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
+ if (!hci_dev_test_flag(hdev, HCI_AUTO_OFF) &&
+ !hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
+ test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
set_bit(HCI_INIT, &hdev->flags);
- __hci_req_sync(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT, NULL);
+ __hci_req_sync(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT);
clear_bit(HCI_INIT, &hdev->flags);
}
@@ -1606,9 +1652,6 @@
hdev->sent_cmd = NULL;
}
- clear_bit(HCI_RUNNING, &hdev->flags);
- hci_sock_dev_event(hdev, HCI_DEV_CLOSE);
-
/* After this point our queues are empty
* and no tasks are scheduled. */
hdev->close(hdev);
@@ -1624,9 +1667,7 @@
memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
bacpy(&hdev->random_addr, BDADDR_ANY);
- hci_req_sync_unlock(hdev);
-
- hci_request_cancel_all(hdev);
+ hci_req_unlock(hdev);
hci_dev_put(hdev);
return 0;
@@ -1662,7 +1703,7 @@
BT_DBG("%s %p", hdev->name, hdev);
- hci_req_sync_lock(hdev);
+ hci_req_lock(hdev);
/* Drop queues */
skb_queue_purge(&hdev->rx_q);
@@ -1684,9 +1725,9 @@
atomic_set(&hdev->cmd_cnt, 1);
hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
- ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT, NULL);
+ ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
- hci_req_sync_unlock(hdev);
+ hci_req_unlock(hdev);
return ret;
}
@@ -1819,7 +1860,7 @@
switch (cmd) {
case HCISETAUTH:
err = hci_req_sync(hdev, hci_auth_req, dr.dev_opt,
- HCI_INIT_TIMEOUT, NULL);
+ HCI_INIT_TIMEOUT);
break;
case HCISETENCRYPT:
@@ -1831,18 +1872,18 @@
if (!test_bit(HCI_AUTH, &hdev->flags)) {
/* Auth must be enabled first */
err = hci_req_sync(hdev, hci_auth_req, dr.dev_opt,
- HCI_INIT_TIMEOUT, NULL);
+ HCI_INIT_TIMEOUT);
if (err)
break;
}
err = hci_req_sync(hdev, hci_encrypt_req, dr.dev_opt,
- HCI_INIT_TIMEOUT, NULL);
+ HCI_INIT_TIMEOUT);
break;
case HCISETSCAN:
err = hci_req_sync(hdev, hci_scan_req, dr.dev_opt,
- HCI_INIT_TIMEOUT, NULL);
+ HCI_INIT_TIMEOUT);
/* Ensure that the connectable and discoverable states
* get correctly modified as this was a non-mgmt change.
@@ -1853,7 +1894,7 @@
case HCISETLINKPOL:
err = hci_req_sync(hdev, hci_linkpol_req, dr.dev_opt,
- HCI_INIT_TIMEOUT, NULL);
+ HCI_INIT_TIMEOUT);
break;
case HCISETLINKMODE:
@@ -2115,17 +2156,6 @@
mgmt_discoverable_timeout(hdev);
}
-static void hci_adv_timeout_expire(struct work_struct *work)
-{
- struct hci_dev *hdev;
-
- hdev = container_of(work, struct hci_dev, adv_instance_expire.work);
-
- BT_DBG("%s", hdev->name);
-
- mgmt_adv_timeout_expired(hdev);
-}
-
void hci_uuids_clear(struct hci_dev *hdev)
{
struct bt_uuid *uuid, *tmp;
@@ -2589,130 +2619,6 @@
return 0;
}
-/* This function requires the caller holds hdev->lock */
-struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
-{
- struct adv_info *adv_instance;
-
- list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
- if (adv_instance->instance == instance)
- return adv_instance;
- }
-
- return NULL;
-}
-
-/* This function requires the caller holds hdev->lock */
-struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance) {
- struct adv_info *cur_instance;
-
- cur_instance = hci_find_adv_instance(hdev, instance);
- if (!cur_instance)
- return NULL;
-
- if (cur_instance == list_last_entry(&hdev->adv_instances,
- struct adv_info, list))
- return list_first_entry(&hdev->adv_instances,
- struct adv_info, list);
- else
- return list_next_entry(cur_instance, list);
-}
-
-/* This function requires the caller holds hdev->lock */
-int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
-{
- struct adv_info *adv_instance;
-
- adv_instance = hci_find_adv_instance(hdev, instance);
- if (!adv_instance)
- return -ENOENT;
-
- BT_DBG("%s removing %dMR", hdev->name, instance);
-
- if (hdev->cur_adv_instance == instance && hdev->adv_instance_timeout) {
- cancel_delayed_work(&hdev->adv_instance_expire);
- hdev->adv_instance_timeout = 0;
- }
-
- list_del(&adv_instance->list);
- kfree(adv_instance);
-
- hdev->adv_instance_cnt--;
-
- return 0;
-}
-
-/* This function requires the caller holds hdev->lock */
-void hci_adv_instances_clear(struct hci_dev *hdev)
-{
- struct adv_info *adv_instance, *n;
-
- if (hdev->adv_instance_timeout) {
- cancel_delayed_work(&hdev->adv_instance_expire);
- hdev->adv_instance_timeout = 0;
- }
-
- list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
- list_del(&adv_instance->list);
- kfree(adv_instance);
- }
-
- hdev->adv_instance_cnt = 0;
-}
-
-/* This function requires the caller holds hdev->lock */
-int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
- u16 adv_data_len, u8 *adv_data,
- u16 scan_rsp_len, u8 *scan_rsp_data,
- u16 timeout, u16 duration)
-{
- struct adv_info *adv_instance;
-
- adv_instance = hci_find_adv_instance(hdev, instance);
- if (adv_instance) {
- memset(adv_instance->adv_data, 0,
- sizeof(adv_instance->adv_data));
- memset(adv_instance->scan_rsp_data, 0,
- sizeof(adv_instance->scan_rsp_data));
- } else {
- if (hdev->adv_instance_cnt >= HCI_MAX_ADV_INSTANCES ||
- instance < 1 || instance > HCI_MAX_ADV_INSTANCES)
- return -EOVERFLOW;
-
- adv_instance = kzalloc(sizeof(*adv_instance), GFP_KERNEL);
- if (!adv_instance)
- return -ENOMEM;
-
- adv_instance->pending = true;
- adv_instance->instance = instance;
- list_add(&adv_instance->list, &hdev->adv_instances);
- hdev->adv_instance_cnt++;
- }
-
- adv_instance->flags = flags;
- adv_instance->adv_data_len = adv_data_len;
- adv_instance->scan_rsp_len = scan_rsp_len;
-
- if (adv_data_len)
- memcpy(adv_instance->adv_data, adv_data, adv_data_len);
-
- if (scan_rsp_len)
- memcpy(adv_instance->scan_rsp_data,
- scan_rsp_data, scan_rsp_len);
-
- adv_instance->timeout = timeout;
- adv_instance->remaining_time = timeout;
-
- if (duration == 0)
- adv_instance->duration = HCI_DEFAULT_ADV_DURATION;
- else
- adv_instance->duration = duration;
-
- BT_DBG("%s for %dMR", hdev->name, instance);
-
- return 0;
-}
-
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
bdaddr_t *bdaddr, u8 type)
{
@@ -2811,6 +2717,23 @@
}
/* This function requires the caller holds hdev->lock */
+struct hci_conn_params *hci_explicit_connect_lookup(struct hci_dev *hdev,
+ bdaddr_t *addr,
+ u8 addr_type)
+{
+ struct hci_conn_params *param;
+
+ list_for_each_entry(param, &hdev->pend_le_conns, action) {
+ if (bacmp(¶m->addr, addr) == 0 &&
+ param->addr_type == addr_type &&
+ param->explicit_connect)
+ return param;
+ }
+
+ return NULL;
+}
+
+/* This function requires the caller holds hdev->lock */
struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev,
bdaddr_t *addr, u8 addr_type)
{
@@ -2896,16 +2819,181 @@
}
/* This function requires the caller holds hdev->lock */
-static void hci_conn_params_clear_all(struct hci_dev *hdev)
+void hci_conn_params_clear_all(struct hci_dev *hdev)
{
struct hci_conn_params *params, *tmp;
list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list)
hci_conn_params_free(params);
+ hci_update_background_scan(hdev);
+
BT_DBG("All LE connection parameters were removed");
}
+static void inquiry_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+{
+ if (status) {
+ BT_ERR("Failed to start inquiry: status %d", status);
+
+ hci_dev_lock(hdev);
+ hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+ hci_dev_unlock(hdev);
+ return;
+ }
+}
+
+static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status,
+ u16 opcode)
+{
+ /* General inquiry access code (GIAC) */
+ u8 lap[3] = { 0x33, 0x8b, 0x9e };
+ struct hci_cp_inquiry cp;
+ int err;
+
+ if (status) {
+ BT_ERR("Failed to disable LE scanning: status %d", status);
+ return;
+ }
+
+ hdev->discovery.scan_start = 0;
+
+ switch (hdev->discovery.type) {
+ case DISCOV_TYPE_LE:
+ hci_dev_lock(hdev);
+ hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+ hci_dev_unlock(hdev);
+ break;
+
+ case DISCOV_TYPE_INTERLEAVED:
+ hci_dev_lock(hdev);
+
+ if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
+ &hdev->quirks)) {
+ /* If we were running LE only scan, change discovery
+ * state. If we were running both LE and BR/EDR inquiry
+ * simultaneously, and BR/EDR inquiry is already
+ * finished, stop discovery, otherwise BR/EDR inquiry
+ * will stop discovery when finished. If we will resolve
+ * remote device name, do not change discovery state.
+ */
+ if (!test_bit(HCI_INQUIRY, &hdev->flags) &&
+ hdev->discovery.state != DISCOVERY_RESOLVING)
+ hci_discovery_set_state(hdev,
+ DISCOVERY_STOPPED);
+ } else {
+ struct hci_request req;
+
+ hci_inquiry_cache_flush(hdev);
+
+ hci_req_init(&req, hdev);
+
+ memset(&cp, 0, sizeof(cp));
+ memcpy(&cp.lap, lap, sizeof(cp.lap));
+ cp.length = DISCOV_INTERLEAVED_INQUIRY_LEN;
+ hci_req_add(&req, HCI_OP_INQUIRY, sizeof(cp), &cp);
+
+ err = hci_req_run(&req, inquiry_complete);
+ if (err) {
+ BT_ERR("Inquiry request failed: err %d", err);
+ hci_discovery_set_state(hdev,
+ DISCOVERY_STOPPED);
+ }
+ }
+
+ hci_dev_unlock(hdev);
+ break;
+ }
+}
+
+static void le_scan_disable_work(struct work_struct *work)
+{
+ struct hci_dev *hdev = container_of(work, struct hci_dev,
+ le_scan_disable.work);
+ struct hci_request req;
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ cancel_delayed_work_sync(&hdev->le_scan_restart);
+
+ hci_req_init(&req, hdev);
+
+ hci_req_add_le_scan_disable(&req);
+
+ err = hci_req_run(&req, le_scan_disable_work_complete);
+ if (err)
+ BT_ERR("Disable LE scanning request failed: err %d", err);
+}
+
+static void le_scan_restart_work_complete(struct hci_dev *hdev, u8 status,
+ u16 opcode)
+{
+ unsigned long timeout, duration, scan_start, now;
+
+ BT_DBG("%s", hdev->name);
+
+ if (status) {
+ BT_ERR("Failed to restart LE scan: status %d", status);
+ return;
+ }
+
+ if (!test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) ||
+ !hdev->discovery.scan_start)
+ return;
+
+ /* When the scan was started, hdev->le_scan_disable has been queued
+ * after duration from scan_start. During scan restart this job
+ * has been canceled, and we need to queue it again after proper
+ * timeout, to make sure that scan does not run indefinitely.
+ */
+ duration = hdev->discovery.scan_duration;
+ scan_start = hdev->discovery.scan_start;
+ now = jiffies;
+ if (now - scan_start <= duration) {
+ int elapsed;
+
+ if (now >= scan_start)
+ elapsed = now - scan_start;
+ else
+ elapsed = ULONG_MAX - scan_start + now;
+
+ timeout = duration - elapsed;
+ } else {
+ timeout = 0;
+ }
+ queue_delayed_work(hdev->workqueue,
+ &hdev->le_scan_disable, timeout);
+}
+
+static void le_scan_restart_work(struct work_struct *work)
+{
+ struct hci_dev *hdev = container_of(work, struct hci_dev,
+ le_scan_restart.work);
+ struct hci_request req;
+ struct hci_cp_le_set_scan_enable cp;
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ /* If controller is not scanning we are done. */
+ if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
+ return;
+
+ hci_req_init(&req, hdev);
+
+ hci_req_add_le_scan_disable(&req);
+
+ memset(&cp, 0, sizeof(cp));
+ cp.enable = LE_SCAN_ENABLE;
+ cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+
+ err = hci_req_run(&req, le_scan_restart_work_complete);
+ if (err)
+ BT_ERR("Restart LE scan request failed: err %d", err);
+}
+
/* Copy the Identity Address of the controller.
*
* If the controller has a public BD_ADDR, then by default use that one.
@@ -2951,9 +3039,6 @@
hdev->manufacturer = 0xffff; /* Default to internal use */
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
- hdev->adv_instance_cnt = 0;
- hdev->cur_adv_instance = 0x00;
- hdev->adv_instance_timeout = 0;
hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
@@ -2995,7 +3080,6 @@
INIT_LIST_HEAD(&hdev->pend_le_conns);
INIT_LIST_HEAD(&hdev->pend_le_reports);
INIT_LIST_HEAD(&hdev->conn_hash.list);
- INIT_LIST_HEAD(&hdev->adv_instances);
INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -3005,7 +3089,8 @@
INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
- INIT_DELAYED_WORK(&hdev->adv_instance_expire, hci_adv_timeout_expire);
+ INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
+ INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
skb_queue_head_init(&hdev->rx_q);
skb_queue_head_init(&hdev->cmd_q);
@@ -3015,10 +3100,9 @@
INIT_DELAYED_WORK(&hdev->cmd_timer, hci_cmd_timeout);
- hci_request_setup(hdev);
-
hci_init_sysfs(hdev);
discovery_init(hdev);
+ adv_info_init(hdev);
return hdev;
}
@@ -3062,15 +3146,16 @@
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
- hdev->workqueue = alloc_workqueue("%s", WQ_HIGHPRI | WQ_UNBOUND |
- WQ_MEM_RECLAIM, 1, hdev->name);
+ hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
+ WQ_MEM_RECLAIM, 1);
if (!hdev->workqueue) {
error = -ENOMEM;
goto err;
}
- hdev->req_workqueue = alloc_workqueue("%s", WQ_HIGHPRI | WQ_UNBOUND |
- WQ_MEM_RECLAIM, 1, hdev->name);
+ hdev->req_workqueue = alloc_workqueue(hdev->name,
+ WQ_HIGHPRI | WQ_UNBOUND |
+ WQ_MEM_RECLAIM, 1);
if (!hdev->req_workqueue) {
destroy_workqueue(hdev->workqueue);
error = -ENOMEM;
@@ -3119,7 +3204,7 @@
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
hci_dev_set_flag(hdev, HCI_UNCONFIGURED);
- hci_sock_dev_event(hdev, HCI_DEV_REG);
+ hci_notify(hdev, HCI_DEV_REG);
hci_dev_hold(hdev);
queue_work(hdev->req_workqueue, &hdev->power_on);
@@ -3167,7 +3252,7 @@
* pending list */
BUG_ON(!list_empty(&hdev->mgmt_pending));
- hci_sock_dev_event(hdev, HCI_DEV_UNREG);
+ hci_notify(hdev, HCI_DEV_UNREG);
if (hdev->rfkill) {
rfkill_unregister(hdev->rfkill);
@@ -3189,7 +3274,6 @@
hci_smp_ltks_clear(hdev);
hci_smp_irks_clear(hdev);
hci_remote_oob_data_clear(hdev);
- hci_adv_instances_clear(hdev);
hci_bdaddr_list_clear(&hdev->le_white_list);
hci_conn_params_clear_all(hdev);
hci_discovery_filter_clear(hdev);
@@ -3204,7 +3288,7 @@
/* Suspend HCI device */
int hci_suspend_dev(struct hci_dev *hdev)
{
- hci_sock_dev_event(hdev, HCI_DEV_SUSPEND);
+ hci_notify(hdev, HCI_DEV_SUSPEND);
return 0;
}
EXPORT_SYMBOL(hci_suspend_dev);
@@ -3212,7 +3296,7 @@
/* Resume HCI device */
int hci_resume_dev(struct hci_dev *hdev)
{
- hci_sock_dev_event(hdev, HCI_DEV_RESUME);
+ hci_notify(hdev, HCI_DEV_RESUME);
return 0;
}
EXPORT_SYMBOL(hci_resume_dev);
@@ -3227,7 +3311,7 @@
if (!skb)
return -ENOMEM;
- hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
+ bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
memcpy(skb_put(skb, 3), hw_err, 3);
/* Send Hardware Error to upper stack */
@@ -3244,13 +3328,6 @@
return -ENXIO;
}
- if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT &&
- hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
- hci_skb_pkt_type(skb) != HCI_SCODATA_PKT) {
- kfree_skb(skb);
- return -EINVAL;
- }
-
/* Incoming skb */
bt_cb(skb)->incoming = 1;
@@ -3264,22 +3341,6 @@
}
EXPORT_SYMBOL(hci_recv_frame);
-/* Receive diagnostic message from HCI drivers */
-int hci_recv_diag(struct hci_dev *hdev, struct sk_buff *skb)
-{
- /* Mark as diagnostic packet */
- hci_skb_pkt_type(skb) = HCI_DIAG_PKT;
-
- /* Time stamp */
- __net_timestamp(skb);
-
- skb_queue_tail(&hdev->rx_q, skb);
- queue_work(hdev->workqueue, &hdev->rx_work);
-
- return 0;
-}
-EXPORT_SYMBOL(hci_recv_diag);
-
/* ---- Interface to upper protocols ---- */
int hci_register_cb(struct hci_cb *cb)
@@ -3310,8 +3371,7 @@
{
int err;
- BT_DBG("%s type %d len %d", hdev->name, hci_skb_pkt_type(skb),
- skb->len);
+ BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
/* Time stamp */
__net_timestamp(skb);
@@ -3327,11 +3387,6 @@
/* Get rid of skb owner, prior to sending to the driver. */
skb_orphan(skb);
- if (!test_bit(HCI_RUNNING, &hdev->flags)) {
- kfree_skb(skb);
- return;
- }
-
err = hdev->send(hdev, skb);
if (err < 0) {
BT_ERR("%s sending frame failed (%d)", hdev->name, err);
@@ -3356,7 +3411,7 @@
/* Stand-alone HCI commands must be flagged as
* single-command requests.
*/
- bt_cb(skb)->hci.req_flags |= HCI_REQ_START;
+ bt_cb(skb)->req.start = true;
skb_queue_tail(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
@@ -3382,25 +3437,6 @@
return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
}
-/* Send HCI command and wait for command commplete event */
-struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
- const void *param, u32 timeout)
-{
- struct sk_buff *skb;
-
- if (!test_bit(HCI_UP, &hdev->flags))
- return ERR_PTR(-ENETDOWN);
-
- bt_dev_dbg(hdev, "opcode 0x%4.4x plen %d", opcode, plen);
-
- hci_req_sync_lock(hdev);
- skb = __hci_cmd_sync(hdev, opcode, plen, param, timeout);
- hci_req_sync_unlock(hdev);
-
- return skb;
-}
-EXPORT_SYMBOL(hci_cmd_sync);
-
/* Send ACL data */
static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
{
@@ -3424,7 +3460,7 @@
skb->len = skb_headlen(skb);
skb->data_len = 0;
- hci_skb_pkt_type(skb) = HCI_ACLDATA_PKT;
+ bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
switch (hdev->dev_type) {
case HCI_BREDR:
@@ -3464,7 +3500,7 @@
do {
skb = list; list = list->next;
- hci_skb_pkt_type(skb) = HCI_ACLDATA_PKT;
+ bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
hci_add_acl_hdr(skb, conn->handle, flags);
BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
@@ -3502,7 +3538,7 @@
skb_reset_transport_header(skb);
memcpy(skb_transport_header(skb), &hdr, HCI_SCO_HDR_SIZE);
- hci_skb_pkt_type(skb) = HCI_SCODATA_PKT;
+ bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
skb_queue_tail(&conn->data_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work);
@@ -4053,7 +4089,7 @@
if (!skb)
return true;
- return (bt_cb(skb)->hci.req_flags & HCI_REQ_START);
+ return bt_cb(skb)->req.start;
}
static void hci_resend_last(struct hci_dev *hdev)
@@ -4113,26 +4149,26 @@
* callback would be found in hdev->sent_cmd instead of the
* command queue (hdev->cmd_q).
*/
- if (bt_cb(hdev->sent_cmd)->hci.req_flags & HCI_REQ_SKB) {
- *req_complete_skb = bt_cb(hdev->sent_cmd)->hci.req_complete_skb;
+ if (bt_cb(hdev->sent_cmd)->req.complete) {
+ *req_complete = bt_cb(hdev->sent_cmd)->req.complete;
return;
}
- if (bt_cb(hdev->sent_cmd)->hci.req_complete) {
- *req_complete = bt_cb(hdev->sent_cmd)->hci.req_complete;
+ if (bt_cb(hdev->sent_cmd)->req.complete_skb) {
+ *req_complete_skb = bt_cb(hdev->sent_cmd)->req.complete_skb;
return;
}
/* Remove all pending commands belonging to this request */
spin_lock_irqsave(&hdev->cmd_q.lock, flags);
while ((skb = __skb_dequeue(&hdev->cmd_q))) {
- if (bt_cb(skb)->hci.req_flags & HCI_REQ_START) {
+ if (bt_cb(skb)->req.start) {
__skb_queue_head(&hdev->cmd_q, skb);
break;
}
- *req_complete = bt_cb(skb)->hci.req_complete;
- *req_complete_skb = bt_cb(skb)->hci.req_complete_skb;
+ *req_complete = bt_cb(skb)->req.complete;
+ *req_complete_skb = bt_cb(skb)->req.complete_skb;
kfree_skb(skb);
}
spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
@@ -4161,7 +4197,7 @@
if (test_bit(HCI_INIT, &hdev->flags)) {
/* Don't process data packets in this states. */
- switch (hci_skb_pkt_type(skb)) {
+ switch (bt_cb(skb)->pkt_type) {
case HCI_ACLDATA_PKT:
case HCI_SCODATA_PKT:
kfree_skb(skb);
@@ -4170,7 +4206,7 @@
}
/* Process frame */
- switch (hci_skb_pkt_type(skb)) {
+ switch (bt_cb(skb)->pkt_type) {
case HCI_EVENT_PKT:
BT_DBG("%s Event packet", hdev->name);
hci_event_packet(hdev, skb);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d92c6baf..d2d2694 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -828,7 +828,7 @@
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
- return;
+ goto a2mp_rsp;
hdev->amp_status = rp->amp_status;
hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
@@ -840,6 +840,46 @@
hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
+
+a2mp_rsp:
+ a2mp_send_getinfo_rsp(hdev);
+}
+
+static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_rp_read_local_amp_assoc *rp = (void *) skb->data;
+ struct amp_assoc *assoc = &hdev->loc_assoc;
+ size_t rem_len, frag_len;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
+ goto a2mp_rsp;
+
+ frag_len = skb->len - sizeof(*rp);
+ rem_len = __le16_to_cpu(rp->rem_len);
+
+ if (rem_len > frag_len) {
+ BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len);
+
+ memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
+ assoc->offset += frag_len;
+
+ /* Read other fragments */
+ amp_read_loc_assoc_frag(hdev, rp->phy_handle);
+
+ return;
+ }
+
+ memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
+ assoc->len = assoc->offset + rem_len;
+ assoc->offset = 0;
+
+a2mp_rsp:
+ /* Send A2MP Rsp when all fragments are received */
+ a2mp_send_getampassoc_rsp(hdev, rp->status);
+ a2mp_send_create_phy_link_req(hdev, rp->status);
}
static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
@@ -1374,6 +1414,20 @@
hci_dev_unlock(hdev);
}
+static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_rp_write_remote_amp_assoc *rp = (void *) skb->data;
+
+ BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
+ hdev->name, rp->status, rp->phy_handle);
+
+ if (rp->status)
+ return;
+
+ amp_write_rem_assoc_continue(hdev, rp->phy_handle);
+}
+
static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_read_rssi *rp = (void *) skb->data;
@@ -1895,6 +1949,47 @@
hci_dev_unlock(hdev);
}
+static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
+{
+ struct hci_cp_create_phy_link *cp;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+ cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
+ if (!cp)
+ return;
+
+ hci_dev_lock(hdev);
+
+ if (status) {
+ struct hci_conn *hcon;
+
+ hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle);
+ if (hcon)
+ hci_conn_del(hcon);
+ } else {
+ amp_write_remote_assoc(hdev, cp->phy_handle);
+ }
+
+ hci_dev_unlock(hdev);
+}
+
+static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
+{
+ struct hci_cp_accept_phy_link *cp;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+ if (status)
+ return;
+
+ cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK);
+ if (!cp)
+ return;
+
+ amp_write_remote_assoc(hdev, cp->phy_handle);
+}
+
static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
{
struct hci_cp_le_create_conn *cp;
@@ -1915,8 +2010,7 @@
hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_le(hdev, &cp->peer_addr,
- cp->peer_addr_type);
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
if (!conn)
goto unlock;
@@ -2514,63 +2608,6 @@
hci_dev_unlock(hdev);
}
-static void read_enc_key_size_complete(struct hci_dev *hdev, u8 status,
- u16 opcode, struct sk_buff *skb)
-{
- const struct hci_rp_read_enc_key_size *rp;
- struct hci_conn *conn;
- u16 handle;
-
- BT_DBG("%s status 0x%02x", hdev->name, status);
-
- if (!skb || skb->len < sizeof(*rp)) {
- BT_ERR("%s invalid HCI Read Encryption Key Size response",
- hdev->name);
- return;
- }
-
- rp = (void *)skb->data;
- handle = le16_to_cpu(rp->handle);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, handle);
- if (!conn)
- goto unlock;
-
- /* If we fail to read the encryption key size, assume maximum
- * (which is the same we do also when this HCI command isn't
- * supported.
- */
- if (rp->status) {
- BT_ERR("%s failed to read key size for handle %u", hdev->name,
- handle);
- conn->enc_key_size = HCI_LINK_KEY_SIZE;
- } else {
- conn->enc_key_size = rp->key_size;
- }
-
- if (conn->state == BT_CONFIG) {
- conn->state = BT_CONNECTED;
- hci_connect_cfm(conn, 0);
- hci_conn_drop(conn);
- } else {
- u8 encrypt;
-
- if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
- encrypt = 0x00;
- else if (test_bit(HCI_CONN_AES_CCM, &conn->flags))
- encrypt = 0x02;
- else
- encrypt = 0x01;
-
- hci_encrypt_cfm(conn, 0, encrypt);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_encrypt_change *ev = (void *) skb->data;
@@ -2618,51 +2655,22 @@
goto unlock;
}
- /* In Secure Connections Only mode, do not allow any connections
- * that are not encrypted with AES-CCM using a P-256 authenticated
- * combination key.
- */
- if (hci_dev_test_flag(hdev, HCI_SC_ONLY) &&
- (!test_bit(HCI_CONN_AES_CCM, &conn->flags) ||
- conn->key_type != HCI_LK_AUTH_COMBINATION_P256)) {
- hci_connect_cfm(conn, HCI_ERROR_AUTH_FAILURE);
- hci_conn_drop(conn);
- goto unlock;
- }
-
- /* Try reading the encryption key size for encrypted ACL links */
- if (!ev->status && ev->encrypt && conn->type == ACL_LINK) {
- struct hci_cp_read_enc_key_size cp;
- struct hci_request req;
-
- /* Only send HCI_Read_Encryption_Key_Size if the
- * controller really supports it. If it doesn't, assume
- * the default size (16).
- */
- if (!(hdev->commands[20] & 0x10)) {
- conn->enc_key_size = HCI_LINK_KEY_SIZE;
- goto notify;
- }
-
- hci_req_init(&req, hdev);
-
- cp.handle = cpu_to_le16(conn->handle);
- hci_req_add(&req, HCI_OP_READ_ENC_KEY_SIZE, sizeof(cp), &cp);
-
- if (hci_req_run_skb(&req, read_enc_key_size_complete)) {
- BT_ERR("Sending HCI Read Encryption Key Size failed");
- conn->enc_key_size = HCI_LINK_KEY_SIZE;
- goto notify;
- }
-
- goto unlock;
- }
-
-notify:
if (conn->state == BT_CONFIG) {
if (!ev->status)
conn->state = BT_CONNECTED;
+ /* In Secure Connections Only mode, do not allow any
+ * connections that are not encrypted with AES-CCM
+ * using a P-256 authenticated combination key.
+ */
+ if (hci_dev_test_flag(hdev, HCI_SC_ONLY) &&
+ (!test_bit(HCI_CONN_AES_CCM, &conn->flags) ||
+ conn->key_type != HCI_LK_AUTH_COMBINATION_P256)) {
+ hci_connect_cfm(conn, HCI_ERROR_AUTH_FAILURE);
+ hci_conn_drop(conn);
+ goto unlock;
+ }
+
hci_connect_cfm(conn, ev->status);
hci_conn_drop(conn);
} else
@@ -2909,6 +2917,10 @@
hci_cc_read_clock(hdev, skb);
break;
+ case HCI_OP_READ_LOCAL_AMP_ASSOC:
+ hci_cc_read_local_amp_assoc(hdev, skb);
+ break;
+
case HCI_OP_READ_INQ_RSP_TX_POWER:
hci_cc_read_inq_rsp_tx_power(hdev, skb);
break;
@@ -3013,6 +3025,10 @@
hci_cc_set_adv_param(hdev, skb);
break;
+ case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
+ hci_cc_write_remote_amp_assoc(hdev, skb);
+ break;
+
case HCI_OP_READ_RSSI:
hci_cc_read_rssi(hdev, skb);
break;
@@ -3096,6 +3112,14 @@
hci_cs_setup_sync_conn(hdev, ev->status);
break;
+ case HCI_OP_CREATE_PHY_LINK:
+ hci_cs_create_phylink(hdev, ev->status);
+ break;
+
+ case HCI_OP_ACCEPT_PHY_LINK:
+ hci_cs_accept_phylink(hdev, ev->status);
+ break;
+
case HCI_OP_SNIFF_MODE:
hci_cs_sniff_mode(hdev, ev->status);
break;
@@ -3138,7 +3162,7 @@
* complete event).
*/
if (ev->status ||
- (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->hci.req_event))
+ (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req.event))
hci_req_cmd_complete(hdev, *opcode, ev->status, req_complete,
req_complete_skb);
@@ -3732,25 +3756,17 @@
if (ev->link_type == ESCO_LINK)
goto unlock;
- /* When the link type in the event indicates SCO connection
- * and lookup of the connection object fails, then check
- * if an eSCO connection object exists.
- *
- * The core limits the synchronous connections to either
- * SCO or eSCO. The eSCO connection is preferred and tried
- * to be setup first and until successfully established,
- * the link type will be hinted as eSCO.
- */
conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr);
if (!conn)
goto unlock;
+
+ conn->type = SCO_LINK;
}
switch (ev->status) {
case 0x00:
conn->handle = __le16_to_cpu(ev->handle);
conn->state = BT_CONNECTED;
- conn->type = ev->link_type;
hci_debugfs_create_conn(conn);
hci_conn_add_sysfs(conn);
@@ -4302,23 +4318,6 @@
hci_dev_unlock(hdev);
}
-#if IS_ENABLED(CONFIG_BT_HS)
-static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_channel_selected *ev = (void *)skb->data;
- struct hci_conn *hcon;
-
- BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle);
-
- skb_pull(skb, sizeof(*ev));
-
- hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
- if (!hcon)
- return;
-
- amp_read_loc_assoc_final_data(hdev, hcon);
-}
-
static void hci_phy_link_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
@@ -4442,7 +4441,6 @@
hci_dev_unlock(hdev);
}
-#endif
static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
@@ -4725,27 +4723,6 @@
struct hci_conn *conn;
bool match;
u32 flags;
- u8 *ptr, real_len;
-
- /* Find the end of the data in case the report contains padded zero
- * bytes at the end causing an invalid length value.
- *
- * When data is NULL, len is 0 so there is no need for extra ptr
- * check as 'ptr < data + 0' is already false in such case.
- */
- for (ptr = data; ptr < data + len && *ptr; ptr += *ptr + 1) {
- if (ptr + 1 + *ptr > data + len)
- break;
- }
-
- real_len = ptr - data;
-
- /* Adjust for actual length */
- if (len != real_len) {
- BT_ERR_RATELIMITED("%s advertising data length corrected",
- hdev->name);
- len = real_len;
- }
/* If the direct address is present, then this report is from
* a LE Direct Advertising Report event. In that case it is
@@ -4990,8 +4967,7 @@
goto not_found;
}
- memcpy(cp.ltk, ltk->val, ltk->enc_size);
- memset(cp.ltk + ltk->enc_size, 0, sizeof(cp.ltk) - ltk->enc_size);
+ memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
cp.handle = cpu_to_le16(conn->handle);
conn->pending_sec_level = smp_ltk_sec_level(ltk);
@@ -5155,6 +5131,22 @@
}
}
+static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_ev_channel_selected *ev = (void *) skb->data;
+ struct hci_conn *hcon;
+
+ BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle);
+
+ skb_pull(skb, sizeof(*ev));
+
+ hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
+ if (!hcon)
+ return;
+
+ amp_read_loc_assoc_final_data(hdev, hcon);
+}
+
static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
u8 event, struct sk_buff *skb)
{
@@ -5209,7 +5201,7 @@
u8 status = 0, event = hdr->evt, req_evt = 0;
u16 opcode = HCI_OP_NOP;
- if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->hci.req_event == event) {
+ if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->req.event == event) {
struct hci_command_hdr *cmd_hdr = (void *) hdev->sent_cmd->data;
opcode = __le16_to_cpu(cmd_hdr->opcode);
hci_req_cmd_complete(hdev, opcode, status, &req_complete,
@@ -5375,15 +5367,14 @@
hci_le_meta_evt(hdev, skb);
break;
- case HCI_EV_REMOTE_OOB_DATA_REQUEST:
- hci_remote_oob_data_request_evt(hdev, skb);
- break;
-
-#if IS_ENABLED(CONFIG_BT_HS)
case HCI_EV_CHANNEL_SELECTED:
hci_chan_selected_evt(hdev, skb);
break;
+ case HCI_EV_REMOTE_OOB_DATA_REQUEST:
+ hci_remote_oob_data_request_evt(hdev, skb);
+ break;
+
case HCI_EV_PHY_LINK_COMPLETE:
hci_phy_link_complete_evt(hdev, skb);
break;
@@ -5399,7 +5390,6 @@
case HCI_EV_DISCONN_PHY_LINK_COMPLETE:
hci_disconn_phylink_complete_evt(hdev, skb);
break;
-#endif
case HCI_EV_NUM_COMP_BLOCKS:
hci_num_comp_blocks_evt(hdev, skb);
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index e8345d8..b736922 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -27,10 +27,6 @@
#include "smp.h"
#include "hci_request.h"
-#define HCI_REQ_DONE 0
-#define HCI_REQ_PEND 1
-#define HCI_REQ_CANCELED 2
-
void hci_req_init(struct hci_request *req, struct hci_dev *hdev)
{
skb_queue_head_init(&req->cmd_q);
@@ -60,12 +56,8 @@
return -ENODATA;
skb = skb_peek_tail(&req->cmd_q);
- if (complete) {
- bt_cb(skb)->hci.req_complete = complete;
- } else if (complete_skb) {
- bt_cb(skb)->hci.req_complete_skb = complete_skb;
- bt_cb(skb)->hci.req_flags |= HCI_REQ_SKB;
- }
+ bt_cb(skb)->req.complete = complete;
+ bt_cb(skb)->req.complete_skb = complete_skb;
spin_lock_irqsave(&hdev->cmd_q.lock, flags);
skb_queue_splice_tail(&req->cmd_q, &hdev->cmd_q);
@@ -86,197 +78,6 @@
return req_run(req, NULL, complete);
}
-static void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
- struct sk_buff *skb)
-{
- BT_DBG("%s result 0x%2.2x", hdev->name, result);
-
- if (hdev->req_status == HCI_REQ_PEND) {
- hdev->req_result = result;
- hdev->req_status = HCI_REQ_DONE;
- if (skb)
- hdev->req_skb = skb_get(skb);
- wake_up_interruptible(&hdev->req_wait_q);
- }
-}
-
-void hci_req_sync_cancel(struct hci_dev *hdev, int err)
-{
- BT_DBG("%s err 0x%2.2x", hdev->name, err);
-
- if (hdev->req_status == HCI_REQ_PEND) {
- hdev->req_result = err;
- hdev->req_status = HCI_REQ_CANCELED;
- wake_up_interruptible(&hdev->req_wait_q);
- }
-}
-
-struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
- const void *param, u8 event, u32 timeout)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct hci_request req;
- struct sk_buff *skb;
- int err = 0;
-
- BT_DBG("%s", hdev->name);
-
- hci_req_init(&req, hdev);
-
- hci_req_add_ev(&req, opcode, plen, param, event);
-
- hdev->req_status = HCI_REQ_PEND;
-
- add_wait_queue(&hdev->req_wait_q, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- err = hci_req_run_skb(&req, hci_req_sync_complete);
- if (err < 0) {
- remove_wait_queue(&hdev->req_wait_q, &wait);
- set_current_state(TASK_RUNNING);
- return ERR_PTR(err);
- }
-
- schedule_timeout(timeout);
-
- remove_wait_queue(&hdev->req_wait_q, &wait);
-
- if (signal_pending(current))
- return ERR_PTR(-EINTR);
-
- switch (hdev->req_status) {
- case HCI_REQ_DONE:
- err = -bt_to_errno(hdev->req_result);
- break;
-
- case HCI_REQ_CANCELED:
- err = -hdev->req_result;
- break;
-
- default:
- err = -ETIMEDOUT;
- break;
- }
-
- hdev->req_status = hdev->req_result = 0;
- skb = hdev->req_skb;
- hdev->req_skb = NULL;
-
- BT_DBG("%s end: err %d", hdev->name, err);
-
- if (err < 0) {
- kfree_skb(skb);
- return ERR_PTR(err);
- }
-
- if (!skb)
- return ERR_PTR(-ENODATA);
-
- return skb;
-}
-EXPORT_SYMBOL(__hci_cmd_sync_ev);
-
-struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
- const void *param, u32 timeout)
-{
- return __hci_cmd_sync_ev(hdev, opcode, plen, param, 0, timeout);
-}
-EXPORT_SYMBOL(__hci_cmd_sync);
-
-/* Execute request and wait for completion. */
-int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
- unsigned long opt),
- unsigned long opt, u32 timeout, u8 *hci_status)
-{
- struct hci_request req;
- DECLARE_WAITQUEUE(wait, current);
- int err = 0;
-
- BT_DBG("%s start", hdev->name);
-
- hci_req_init(&req, hdev);
-
- hdev->req_status = HCI_REQ_PEND;
-
- err = func(&req, opt);
- if (err) {
- if (hci_status)
- *hci_status = HCI_ERROR_UNSPECIFIED;
- return err;
- }
-
- add_wait_queue(&hdev->req_wait_q, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- err = hci_req_run_skb(&req, hci_req_sync_complete);
- if (err < 0) {
- hdev->req_status = 0;
-
- remove_wait_queue(&hdev->req_wait_q, &wait);
- set_current_state(TASK_RUNNING);
-
- /* ENODATA means the HCI request command queue is empty.
- * This can happen when a request with conditionals doesn't
- * trigger any commands to be sent. This is normal behavior
- * and should not trigger an error return.
- */
- if (err == -ENODATA)
- return 0;
-
- return err;
- }
-
- schedule_timeout(timeout);
-
- remove_wait_queue(&hdev->req_wait_q, &wait);
-
- if (signal_pending(current))
- return -EINTR;
-
- switch (hdev->req_status) {
- case HCI_REQ_DONE:
- err = -bt_to_errno(hdev->req_result);
- if (hci_status)
- *hci_status = hdev->req_result;
- break;
-
- case HCI_REQ_CANCELED:
- err = -hdev->req_result;
- if (hci_status)
- *hci_status = HCI_ERROR_UNSPECIFIED;
- break;
-
- default:
- err = -ETIMEDOUT;
- if (hci_status)
- *hci_status = HCI_ERROR_UNSPECIFIED;
- break;
- }
-
- hdev->req_status = hdev->req_result = 0;
-
- BT_DBG("%s end: err %d", hdev->name, err);
-
- return err;
-}
-
-int hci_req_sync(struct hci_dev *hdev, int (*req)(struct hci_request *req,
- unsigned long opt),
- unsigned long opt, u32 timeout, u8 *hci_status)
-{
- int ret;
-
- if (!test_bit(HCI_UP, &hdev->flags))
- return -ENETDOWN;
-
- /* Serialize all requests */
- hci_req_sync_lock(hdev);
- ret = __hci_req_sync(hdev, req, opt, timeout, hci_status);
- hci_req_sync_unlock(hdev);
-
- return ret;
-}
-
struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param)
{
@@ -297,8 +98,8 @@
BT_DBG("skb len %d", skb->len);
- hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
- hci_skb_opcode(skb) = opcode;
+ bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
+ bt_cb(skb)->opcode = opcode;
return skb;
}
@@ -327,9 +128,9 @@
}
if (skb_queue_empty(&req->cmd_q))
- bt_cb(skb)->hci.req_flags |= HCI_REQ_START;
+ bt_cb(skb)->req.start = true;
- bt_cb(skb)->hci.req_event = event;
+ bt_cb(skb)->req.event = event;
skb_queue_tail(&req->cmd_q, skb);
}
@@ -675,7 +476,7 @@
*
* This function requires the caller holds hdev->lock.
*/
-static void __hci_update_background_scan(struct hci_request *req)
+void __hci_update_background_scan(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
@@ -742,536 +543,24 @@
}
}
-void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
- u8 reason)
-{
- switch (conn->state) {
- case BT_CONNECTED:
- case BT_CONFIG:
- if (conn->type == AMP_LINK) {
- struct hci_cp_disconn_phy_link cp;
-
- cp.phy_handle = HCI_PHY_HANDLE(conn->handle);
- cp.reason = reason;
- hci_req_add(req, HCI_OP_DISCONN_PHY_LINK, sizeof(cp),
- &cp);
- } else {
- struct hci_cp_disconnect dc;
-
- dc.handle = cpu_to_le16(conn->handle);
- dc.reason = reason;
- hci_req_add(req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
- }
-
- conn->state = BT_DISCONN;
-
- break;
- case BT_CONNECT:
- if (conn->type == LE_LINK) {
- if (test_bit(HCI_CONN_SCANNING, &conn->flags))
- break;
- hci_req_add(req, HCI_OP_LE_CREATE_CONN_CANCEL,
- 0, NULL);
- } else if (conn->type == ACL_LINK) {
- if (req->hdev->hci_ver < BLUETOOTH_VER_1_2)
- break;
- hci_req_add(req, HCI_OP_CREATE_CONN_CANCEL,
- 6, &conn->dst);
- }
- break;
- case BT_CONNECT2:
- if (conn->type == ACL_LINK) {
- struct hci_cp_reject_conn_req rej;
-
- bacpy(&rej.bdaddr, &conn->dst);
- rej.reason = reason;
-
- hci_req_add(req, HCI_OP_REJECT_CONN_REQ,
- sizeof(rej), &rej);
- } else if (conn->type == SCO_LINK || conn->type == ESCO_LINK) {
- struct hci_cp_reject_sync_conn_req rej;
-
- bacpy(&rej.bdaddr, &conn->dst);
-
- /* SCO rejection has its own limited set of
- * allowed error values (0x0D-0x0F) which isn't
- * compatible with most values passed to this
- * function. To be safe hard-code one of the
- * values that's suitable for SCO.
- */
- rej.reason = HCI_ERROR_REMOTE_LOW_RESOURCES;
-
- hci_req_add(req, HCI_OP_REJECT_SYNC_CONN_REQ,
- sizeof(rej), &rej);
- }
- break;
- default:
- conn->state = BT_CLOSED;
- break;
- }
-}
-
-static void abort_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+static void update_background_scan_complete(struct hci_dev *hdev, u8 status,
+ u16 opcode)
{
if (status)
- BT_DBG("Failed to abort connection: status 0x%2.2x", status);
+ BT_DBG("HCI request failed to update background scanning: "
+ "status 0x%2.2x", status);
}
-int hci_abort_conn(struct hci_conn *conn, u8 reason)
+void hci_update_background_scan(struct hci_dev *hdev)
{
+ int err;
struct hci_request req;
- int err;
- hci_req_init(&req, conn->hdev);
+ hci_req_init(&req, hdev);
- __hci_abort_conn(&req, conn, reason);
+ __hci_update_background_scan(&req);
- err = hci_req_run(&req, abort_conn_complete);
- if (err && err != -ENODATA) {
+ err = hci_req_run(&req, update_background_scan_complete);
+ if (err && err != -ENODATA)
BT_ERR("Failed to run HCI request: err %d", err);
- return err;
- }
-
- return 0;
-}
-
-static int update_bg_scan(struct hci_request *req, unsigned long opt)
-{
- hci_dev_lock(req->hdev);
- __hci_update_background_scan(req);
- hci_dev_unlock(req->hdev);
- return 0;
-}
-
-static void bg_scan_update(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- bg_scan_update);
- struct hci_conn *conn;
- u8 status;
- int err;
-
- err = hci_req_sync(hdev, update_bg_scan, 0, HCI_CMD_TIMEOUT, &status);
- if (!err)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
- if (conn)
- hci_le_conn_failed(conn, status);
-
- hci_dev_unlock(hdev);
-}
-
-static int le_scan_disable(struct hci_request *req, unsigned long opt)
-{
- hci_req_add_le_scan_disable(req);
- return 0;
-}
-
-static int bredr_inquiry(struct hci_request *req, unsigned long opt)
-{
- u8 length = opt;
- /* General inquiry access code (GIAC) */
- u8 lap[3] = { 0x33, 0x8b, 0x9e };
- struct hci_cp_inquiry cp;
-
- BT_DBG("%s", req->hdev->name);
-
- hci_dev_lock(req->hdev);
- hci_inquiry_cache_flush(req->hdev);
- hci_dev_unlock(req->hdev);
-
- memset(&cp, 0, sizeof(cp));
- memcpy(&cp.lap, lap, sizeof(cp.lap));
- cp.length = length;
-
- hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
-
- return 0;
-}
-
-static void le_scan_disable_work(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- le_scan_disable.work);
- u8 status;
-
- BT_DBG("%s", hdev->name);
-
- if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
- return;
-
- cancel_delayed_work(&hdev->le_scan_restart);
-
- hci_req_sync(hdev, le_scan_disable, 0, HCI_CMD_TIMEOUT, &status);
- if (status) {
- BT_ERR("Failed to disable LE scan: status 0x%02x", status);
- return;
- }
-
- hdev->discovery.scan_start = 0;
-
- /* If we were running LE only scan, change discovery state. If
- * we were running both LE and BR/EDR inquiry simultaneously,
- * and BR/EDR inquiry is already finished, stop discovery,
- * otherwise BR/EDR inquiry will stop discovery when finished.
- * If we will resolve remote device name, do not change
- * discovery state.
- */
-
- if (hdev->discovery.type == DISCOV_TYPE_LE)
- goto discov_stopped;
-
- if (hdev->discovery.type != DISCOV_TYPE_INTERLEAVED)
- return;
-
- if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks)) {
- if (!test_bit(HCI_INQUIRY, &hdev->flags) &&
- hdev->discovery.state != DISCOVERY_RESOLVING)
- goto discov_stopped;
-
- return;
- }
-
- hci_req_sync(hdev, bredr_inquiry, DISCOV_INTERLEAVED_INQUIRY_LEN,
- HCI_CMD_TIMEOUT, &status);
- if (status) {
- BT_ERR("Inquiry failed: status 0x%02x", status);
- goto discov_stopped;
- }
-
- return;
-
-discov_stopped:
- hci_dev_lock(hdev);
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- hci_dev_unlock(hdev);
-}
-
-static int le_scan_restart(struct hci_request *req, unsigned long opt)
-{
- struct hci_dev *hdev = req->hdev;
- struct hci_cp_le_set_scan_enable cp;
-
- /* If controller is not scanning we are done. */
- if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
- return 0;
-
- hci_req_add_le_scan_disable(req);
-
- memset(&cp, 0, sizeof(cp));
- cp.enable = LE_SCAN_ENABLE;
- cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
- hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
-
- return 0;
-}
-
-static void le_scan_restart_work(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- le_scan_restart.work);
- unsigned long timeout, duration, scan_start, now;
- u8 status;
-
- BT_DBG("%s", hdev->name);
-
- hci_req_sync(hdev, le_scan_restart, 0, HCI_CMD_TIMEOUT, &status);
- if (status) {
- BT_ERR("Failed to restart LE scan: status %d", status);
- return;
- }
-
- hci_dev_lock(hdev);
-
- if (!test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) ||
- !hdev->discovery.scan_start)
- goto unlock;
-
- /* When the scan was started, hdev->le_scan_disable has been queued
- * after duration from scan_start. During scan restart this job
- * has been canceled, and we need to queue it again after proper
- * timeout, to make sure that scan does not run indefinitely.
- */
- duration = hdev->discovery.scan_duration;
- scan_start = hdev->discovery.scan_start;
- now = jiffies;
- if (now - scan_start <= duration) {
- int elapsed;
-
- if (now >= scan_start)
- elapsed = now - scan_start;
- else
- elapsed = ULONG_MAX - scan_start + now;
-
- timeout = duration - elapsed;
- } else {
- timeout = 0;
- }
-
- queue_delayed_work(hdev->req_workqueue,
- &hdev->le_scan_disable, timeout);
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static void cancel_adv_timeout(struct hci_dev *hdev)
-{
- if (hdev->adv_instance_timeout) {
- hdev->adv_instance_timeout = 0;
- cancel_delayed_work(&hdev->adv_instance_expire);
- }
-}
-
-static void disable_advertising(struct hci_request *req)
-{
- u8 enable = 0x00;
-
- hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
-}
-
-static int active_scan(struct hci_request *req, unsigned long opt)
-{
- uint16_t interval = opt;
- struct hci_dev *hdev = req->hdev;
- struct hci_cp_le_set_scan_param param_cp;
- struct hci_cp_le_set_scan_enable enable_cp;
- u8 own_addr_type;
- int err;
-
- BT_DBG("%s", hdev->name);
-
- if (hci_dev_test_flag(hdev, HCI_LE_ADV)) {
- hci_dev_lock(hdev);
-
- /* Don't let discovery abort an outgoing connection attempt
- * that's using directed advertising.
- */
- if (hci_lookup_le_connect(hdev)) {
- hci_dev_unlock(hdev);
- return -EBUSY;
- }
-
- cancel_adv_timeout(hdev);
- hci_dev_unlock(hdev);
-
- disable_advertising(req);
- }
-
- /* If controller is scanning, it means the background scanning is
- * running. Thus, we should temporarily stop it in order to set the
- * discovery scanning parameters.
- */
- if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
- hci_req_add_le_scan_disable(req);
-
- /* All active scans will be done with either a resolvable private
- * address (when privacy feature has been enabled) or non-resolvable
- * private address.
- */
- err = hci_update_random_address(req, true, &own_addr_type);
- if (err < 0)
- own_addr_type = ADDR_LE_DEV_PUBLIC;
-
- memset(¶m_cp, 0, sizeof(param_cp));
- param_cp.type = LE_SCAN_ACTIVE;
- param_cp.interval = cpu_to_le16(interval);
- param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
- param_cp.own_address_type = own_addr_type;
-
- hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
- ¶m_cp);
-
- memset(&enable_cp, 0, sizeof(enable_cp));
- enable_cp.enable = LE_SCAN_ENABLE;
- enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
-
- hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
- &enable_cp);
-
- return 0;
-}
-
-static int interleaved_discov(struct hci_request *req, unsigned long opt)
-{
- int err;
-
- BT_DBG("%s", req->hdev->name);
-
- err = active_scan(req, opt);
- if (err)
- return err;
-
- return bredr_inquiry(req, DISCOV_BREDR_INQUIRY_LEN);
-}
-
-static void start_discovery(struct hci_dev *hdev, u8 *status)
-{
- unsigned long timeout;
-
- BT_DBG("%s type %u", hdev->name, hdev->discovery.type);
-
- switch (hdev->discovery.type) {
- case DISCOV_TYPE_BREDR:
- if (!hci_dev_test_flag(hdev, HCI_INQUIRY))
- hci_req_sync(hdev, bredr_inquiry,
- DISCOV_BREDR_INQUIRY_LEN, HCI_CMD_TIMEOUT,
- status);
- return;
- case DISCOV_TYPE_INTERLEAVED:
- /* When running simultaneous discovery, the LE scanning time
- * should occupy the whole discovery time sine BR/EDR inquiry
- * and LE scanning are scheduled by the controller.
- *
- * For interleaving discovery in comparison, BR/EDR inquiry
- * and LE scanning are done sequentially with separate
- * timeouts.
- */
- if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
- &hdev->quirks)) {
- timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
- /* During simultaneous discovery, we double LE scan
- * interval. We must leave some time for the controller
- * to do BR/EDR inquiry.
- */
- hci_req_sync(hdev, interleaved_discov,
- DISCOV_LE_SCAN_INT * 2, HCI_CMD_TIMEOUT,
- status);
- break;
- }
-
- timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
- hci_req_sync(hdev, active_scan, DISCOV_LE_SCAN_INT,
- HCI_CMD_TIMEOUT, status);
- break;
- case DISCOV_TYPE_LE:
- timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
- hci_req_sync(hdev, active_scan, DISCOV_LE_SCAN_INT,
- HCI_CMD_TIMEOUT, status);
- break;
- default:
- *status = HCI_ERROR_UNSPECIFIED;
- return;
- }
-
- if (*status)
- return;
-
- BT_DBG("%s timeout %u ms", hdev->name, jiffies_to_msecs(timeout));
-
- /* When service discovery is used and the controller has a
- * strict duplicate filter, it is important to remember the
- * start and duration of the scan. This is required for
- * restarting scanning during the discovery phase.
- */
- if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) &&
- hdev->discovery.result_filtering) {
- hdev->discovery.scan_start = jiffies;
- hdev->discovery.scan_duration = timeout;
- }
-
- queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_disable,
- timeout);
-}
-
-bool hci_req_stop_discovery(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- struct discovery_state *d = &hdev->discovery;
- struct hci_cp_remote_name_req_cancel cp;
- struct inquiry_entry *e;
- bool ret = false;
-
- BT_DBG("%s state %u", hdev->name, hdev->discovery.state);
-
- if (d->state == DISCOVERY_FINDING || d->state == DISCOVERY_STOPPING) {
- if (test_bit(HCI_INQUIRY, &hdev->flags))
- hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
-
- if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
- cancel_delayed_work(&hdev->le_scan_disable);
- hci_req_add_le_scan_disable(req);
- }
-
- ret = true;
- } else {
- /* Passive scanning */
- if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
- hci_req_add_le_scan_disable(req);
- ret = true;
- }
- }
-
- /* No further actions needed for LE-only discovery */
- if (d->type == DISCOV_TYPE_LE)
- return ret;
-
- if (d->state == DISCOVERY_RESOLVING || d->state == DISCOVERY_STOPPING) {
- e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
- NAME_PENDING);
- if (!e)
- return ret;
-
- bacpy(&cp.bdaddr, &e->data.bdaddr);
- hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
- &cp);
- ret = true;
- }
-
- return ret;
-}
-
-static int stop_discovery(struct hci_request *req, unsigned long opt)
-{
- hci_dev_lock(req->hdev);
- hci_req_stop_discovery(req);
- hci_dev_unlock(req->hdev);
-
- return 0;
-}
-
-static void discov_update(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- discov_update);
- u8 status = 0;
-
- switch (hdev->discovery.state) {
- case DISCOVERY_STARTING:
- start_discovery(hdev, &status);
- mgmt_start_discovery_complete(hdev, status);
- if (status)
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- else
- hci_discovery_set_state(hdev, DISCOVERY_FINDING);
- break;
- case DISCOVERY_STOPPING:
- hci_req_sync(hdev, stop_discovery, 0, HCI_CMD_TIMEOUT, &status);
- mgmt_stop_discovery_complete(hdev, status);
- if (!status)
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- break;
- case DISCOVERY_STOPPED:
- default:
- return;
- }
-}
-
-void hci_request_setup(struct hci_dev *hdev)
-{
- INIT_WORK(&hdev->discov_update, discov_update);
- INIT_WORK(&hdev->bg_scan_update, bg_scan_update);
- INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
- INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
-}
-
-void hci_request_cancel_all(struct hci_dev *hdev)
-{
- cancel_work_sync(&hdev->discov_update);
- cancel_work_sync(&hdev->bg_scan_update);
- cancel_delayed_work_sync(&hdev->le_scan_disable);
- cancel_delayed_work_sync(&hdev->le_scan_restart);
}
diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h
index 6b9e59f..bf6df92 100644
--- a/net/bluetooth/hci_request.h
+++ b/net/bluetooth/hci_request.h
@@ -20,9 +20,6 @@
SOFTWARE IS DISCLAIMED.
*/
-#define hci_req_sync_lock(hdev) mutex_lock(&hdev->req_lock)
-#define hci_req_sync_unlock(hdev) mutex_unlock(&hdev->req_lock)
-
struct hci_request {
struct hci_dev *hdev;
struct sk_buff_head cmd_q;
@@ -44,37 +41,17 @@
hci_req_complete_t *req_complete,
hci_req_complete_skb_t *req_complete_skb);
-int hci_req_sync(struct hci_dev *hdev, int (*req)(struct hci_request *req,
- unsigned long opt),
- unsigned long opt, u32 timeout, u8 *hci_status);
-int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
- unsigned long opt),
- unsigned long opt, u32 timeout, u8 *hci_status);
-void hci_req_sync_cancel(struct hci_dev *hdev, int err);
-
struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param);
void hci_req_add_le_scan_disable(struct hci_request *req);
void hci_req_add_le_passive_scan(struct hci_request *req);
-/* Returns true if HCI commands were queued */
-bool hci_req_stop_discovery(struct hci_request *req);
-
void hci_update_page_scan(struct hci_dev *hdev);
void __hci_update_page_scan(struct hci_request *req);
int hci_update_random_address(struct hci_request *req, bool require_privacy,
u8 *own_addr_type);
-int hci_abort_conn(struct hci_conn *conn, u8 reason);
-void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
- u8 reason);
-
-static inline void hci_update_background_scan(struct hci_dev *hdev)
-{
- queue_work(hdev->req_workqueue, &hdev->bg_scan_update);
-}
-
-void hci_request_setup(struct hci_dev *hdev);
-void hci_request_cancel_all(struct hci_dev *hdev);
+void hci_update_background_scan(struct hci_dev *hdev);
+void __hci_update_background_scan(struct hci_request *req);
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index c0acd87..a5cf13b 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -26,8 +26,6 @@
#include <linux/export.h>
#include <asm/unaligned.h>
-#include <generated/compile.h>
-#include <generated/utsrelease.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -122,13 +120,16 @@
/* Apply filter */
flt = &hci_pi(sk)->filter;
- flt_type = hci_skb_pkt_type(skb) & HCI_FLT_TYPE_BITS;
+ if (bt_cb(skb)->pkt_type == HCI_VENDOR_PKT)
+ flt_type = 0;
+ else
+ flt_type = bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS;
if (!test_bit(flt_type, &flt->type_mask))
return true;
/* Extra filter for event packets only */
- if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT)
+ if (bt_cb(skb)->pkt_type != HCI_EVENT_PKT)
return false;
flt_event = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
@@ -172,19 +173,14 @@
continue;
if (hci_pi(sk)->channel == HCI_CHANNEL_RAW) {
- if (hci_skb_pkt_type(skb) != HCI_COMMAND_PKT &&
- hci_skb_pkt_type(skb) != HCI_EVENT_PKT &&
- hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
- hci_skb_pkt_type(skb) != HCI_SCODATA_PKT)
- continue;
if (is_filtered_packet(sk, skb))
continue;
} else if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
if (!bt_cb(skb)->incoming)
continue;
- if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT &&
- hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
- hci_skb_pkt_type(skb) != HCI_SCODATA_PKT)
+ if (bt_cb(skb)->pkt_type != HCI_EVENT_PKT &&
+ bt_cb(skb)->pkt_type != HCI_ACLDATA_PKT &&
+ bt_cb(skb)->pkt_type != HCI_SCODATA_PKT)
continue;
} else {
/* Don't send frame to other channel types */
@@ -198,7 +194,7 @@
continue;
/* Put type byte before the data */
- memcpy(skb_push(skb_copy, 1), &hci_skb_pkt_type(skb), 1);
+ memcpy(skb_push(skb_copy, 1), &bt_cb(skb)->pkt_type, 1);
}
nskb = skb_clone(skb_copy, GFP_ATOMIC);
@@ -264,7 +260,7 @@
BT_DBG("hdev %p len %d", hdev, skb->len);
- switch (hci_skb_pkt_type(skb)) {
+ switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
opcode = cpu_to_le16(HCI_MON_COMMAND_PKT);
break;
@@ -283,9 +279,6 @@
else
opcode = cpu_to_le16(HCI_MON_SCO_TX_PKT);
break;
- case HCI_DIAG_PKT:
- opcode = cpu_to_le16(HCI_MON_VENDOR_DIAG);
- break;
default:
return;
}
@@ -296,7 +289,7 @@
return;
/* Put header before the data */
- hdr = (void *)skb_push(skb_copy, HCI_MON_HDR_SIZE);
+ hdr = (void *) skb_push(skb_copy, HCI_MON_HDR_SIZE);
hdr->opcode = opcode;
hdr->index = cpu_to_le16(hdev->id);
hdr->len = cpu_to_le16(skb->len);
@@ -310,7 +303,6 @@
{
struct hci_mon_hdr *hdr;
struct hci_mon_new_index *ni;
- struct hci_mon_index_info *ii;
struct sk_buff *skb;
__le16 opcode;
@@ -320,7 +312,7 @@
if (!skb)
return NULL;
- ni = (void *)skb_put(skb, HCI_MON_NEW_INDEX_SIZE);
+ ni = (void *) skb_put(skb, HCI_MON_NEW_INDEX_SIZE);
ni->type = hdev->dev_type;
ni->bus = hdev->bus;
bacpy(&ni->bdaddr, &hdev->bdaddr);
@@ -337,47 +329,13 @@
opcode = cpu_to_le16(HCI_MON_DEL_INDEX);
break;
- case HCI_DEV_SETUP:
- if (hdev->manufacturer == 0xffff)
- return NULL;
-
- /* fall through */
-
- case HCI_DEV_UP:
- skb = bt_skb_alloc(HCI_MON_INDEX_INFO_SIZE, GFP_ATOMIC);
- if (!skb)
- return NULL;
-
- ii = (void *)skb_put(skb, HCI_MON_INDEX_INFO_SIZE);
- bacpy(&ii->bdaddr, &hdev->bdaddr);
- ii->manufacturer = cpu_to_le16(hdev->manufacturer);
-
- opcode = cpu_to_le16(HCI_MON_INDEX_INFO);
- break;
-
- case HCI_DEV_OPEN:
- skb = bt_skb_alloc(0, GFP_ATOMIC);
- if (!skb)
- return NULL;
-
- opcode = cpu_to_le16(HCI_MON_OPEN_INDEX);
- break;
-
- case HCI_DEV_CLOSE:
- skb = bt_skb_alloc(0, GFP_ATOMIC);
- if (!skb)
- return NULL;
-
- opcode = cpu_to_le16(HCI_MON_CLOSE_INDEX);
- break;
-
default:
return NULL;
}
__net_timestamp(skb);
- hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE);
+ hdr = (void *) skb_push(skb, HCI_MON_HDR_SIZE);
hdr->opcode = opcode;
hdr->index = cpu_to_le16(hdev->id);
hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
@@ -385,29 +343,6 @@
return skb;
}
-static void send_monitor_note(struct sock *sk, const char *text)
-{
- size_t len = strlen(text);
- struct hci_mon_hdr *hdr;
- struct sk_buff *skb;
-
- skb = bt_skb_alloc(len + 1, GFP_ATOMIC);
- if (!skb)
- return;
-
- strcpy(skb_put(skb, len + 1), text);
-
- __net_timestamp(skb);
-
- hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE);
- hdr->opcode = cpu_to_le16(HCI_MON_SYSTEM_NOTE);
- hdr->index = cpu_to_le16(HCI_DEV_NONE);
- hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
-
- if (sock_queue_rcv_skb(sk, skb))
- kfree_skb(skb);
-}
-
static void send_monitor_replay(struct sock *sk)
{
struct hci_dev *hdev;
@@ -423,28 +358,6 @@
if (sock_queue_rcv_skb(sk, skb))
kfree_skb(skb);
-
- if (!test_bit(HCI_RUNNING, &hdev->flags))
- continue;
-
- skb = create_monitor_event(hdev, HCI_DEV_OPEN);
- if (!skb)
- continue;
-
- if (sock_queue_rcv_skb(sk, skb))
- kfree_skb(skb);
-
- if (test_bit(HCI_UP, &hdev->flags))
- skb = create_monitor_event(hdev, HCI_DEV_UP);
- else if (hci_dev_test_flag(hdev, HCI_SETUP))
- skb = create_monitor_event(hdev, HCI_DEV_SETUP);
- else
- skb = NULL;
-
- if (skb) {
- if (sock_queue_rcv_skb(sk, skb))
- kfree_skb(skb);
- }
}
read_unlock(&hci_dev_list_lock);
@@ -461,30 +374,32 @@
if (!skb)
return;
- hdr = (void *)skb_put(skb, HCI_EVENT_HDR_SIZE);
+ hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE);
hdr->evt = HCI_EV_STACK_INTERNAL;
hdr->plen = sizeof(*ev) + dlen;
- ev = (void *)skb_put(skb, sizeof(*ev) + dlen);
+ ev = (void *) skb_put(skb, sizeof(*ev) + dlen);
ev->type = type;
memcpy(ev->data, data, dlen);
bt_cb(skb)->incoming = 1;
__net_timestamp(skb);
- hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
+ bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
hci_send_to_sock(hdev, skb);
kfree_skb(skb);
}
void hci_sock_dev_event(struct hci_dev *hdev, int event)
{
+ struct hci_ev_si_device ev;
+
BT_DBG("hdev %s event %d", hdev->name, event);
+ /* Send event to monitor */
if (atomic_read(&monitor_promisc)) {
struct sk_buff *skb;
- /* Send event to monitor */
skb = create_monitor_event(hdev, event);
if (skb) {
hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
@@ -493,14 +408,10 @@
}
}
- if (event <= HCI_DEV_DOWN) {
- struct hci_ev_si_device ev;
-
- /* Send event to sockets */
- ev.event = event;
- ev.dev_id = hdev->id;
- hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev);
- }
+ /* Send event to sockets */
+ ev.event = event;
+ ev.dev_id = hdev->id;
+ hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev);
if (event == HCI_DEV_UNREG) {
struct sock *sk;
@@ -592,18 +503,9 @@
if (hdev) {
if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
- /* When releasing an user channel exclusive access,
- * call hci_dev_do_close directly instead of calling
- * hci_dev_close to ensure the exclusive access will
- * be released and the controller brought back down.
- *
- * The checking of HCI_AUTO_OFF is not needed in this
- * case since it will have been cleared already when
- * opening the user channel.
- */
- hci_dev_do_close(hdev);
- hci_dev_clear_flag(hdev, HCI_USER_CHANNEL);
mgmt_index_added(hdev);
+ hci_dev_clear_flag(hdev, HCI_USER_CHANNEL);
+ hci_dev_close(hdev->id);
}
atomic_dec(&hdev->promisc);
@@ -678,20 +580,20 @@
return -EOPNOTSUPP;
case HCIGETCONNINFO:
- return hci_get_conn_info(hdev, (void __user *)arg);
+ return hci_get_conn_info(hdev, (void __user *) arg);
case HCIGETAUTHINFO:
- return hci_get_auth_info(hdev, (void __user *)arg);
+ return hci_get_auth_info(hdev, (void __user *) arg);
case HCIBLOCKADDR:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- return hci_sock_blacklist_add(hdev, (void __user *)arg);
+ return hci_sock_blacklist_add(hdev, (void __user *) arg);
case HCIUNBLOCKADDR:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- return hci_sock_blacklist_del(hdev, (void __user *)arg);
+ return hci_sock_blacklist_del(hdev, (void __user *) arg);
}
return -ENOIOCTLCMD;
@@ -700,7 +602,7 @@
static int hci_sock_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg)
{
- void __user *argp = (void __user *)arg;
+ void __user *argp = (void __user *) arg;
struct sock *sk = sock->sk;
int err;
@@ -839,11 +741,10 @@
goto done;
}
- if (test_bit(HCI_INIT, &hdev->flags) ||
+ if (test_bit(HCI_UP, &hdev->flags) ||
+ test_bit(HCI_INIT, &hdev->flags) ||
hci_dev_test_flag(hdev, HCI_SETUP) ||
- hci_dev_test_flag(hdev, HCI_CONFIG) ||
- (!hci_dev_test_flag(hdev, HCI_AUTO_OFF) &&
- test_bit(HCI_UP, &hdev->flags))) {
+ hci_dev_test_flag(hdev, HCI_CONFIG)) {
err = -EBUSY;
hci_dev_put(hdev);
goto done;
@@ -859,21 +760,10 @@
err = hci_dev_open(hdev->id);
if (err) {
- if (err == -EALREADY) {
- /* In case the transport is already up and
- * running, clear the error here.
- *
- * This can happen when opening an user
- * channel and HCI_AUTO_OFF grace period
- * is still active.
- */
- err = 0;
- } else {
- hci_dev_clear_flag(hdev, HCI_USER_CHANNEL);
- mgmt_index_added(hdev);
- hci_dev_put(hdev);
- goto done;
- }
+ hci_dev_clear_flag(hdev, HCI_USER_CHANNEL);
+ mgmt_index_added(hdev);
+ hci_dev_put(hdev);
+ goto done;
}
atomic_inc(&hdev->promisc);
@@ -897,27 +787,11 @@
*/
hci_sock_set_flag(sk, HCI_SOCK_TRUSTED);
- send_monitor_note(sk, "Linux version " UTS_RELEASE
- " (" UTS_MACHINE ")");
- send_monitor_note(sk, "Bluetooth subsystem version "
- BT_SUBSYS_VERSION);
send_monitor_replay(sk);
atomic_inc(&monitor_promisc);
break;
- case HCI_CHANNEL_LOGGING:
- if (haddr.hci_dev != HCI_DEV_NONE) {
- err = -EINVAL;
- goto done;
- }
-
- if (!capable(CAP_NET_ADMIN)) {
- err = -EPERM;
- goto done;
- }
- break;
-
default:
if (!hci_mgmt_chan_find(haddr.hci_channel)) {
err = -EINVAL;
@@ -967,7 +841,7 @@
static int hci_sock_getname(struct socket *sock, struct sockaddr *addr,
int *addr_len, int peer)
{
- struct sockaddr_hci *haddr = (struct sockaddr_hci *)addr;
+ struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
struct sock *sk = sock->sk;
struct hci_dev *hdev;
int err = 0;
@@ -1042,10 +916,7 @@
BT_DBG("sock %p, sk %p", sock, sk);
- if (flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- if (hci_pi(sk)->channel == HCI_CHANNEL_LOGGING)
+ if (flags & (MSG_OOB))
return -EOPNOTSUPP;
if (sk->sk_state == BT_CLOSED)
@@ -1194,90 +1065,6 @@
return err;
}
-static int hci_logging_frame(struct sock *sk, struct msghdr *msg, int len)
-{
- struct hci_mon_hdr *hdr;
- struct sk_buff *skb;
- struct hci_dev *hdev;
- u16 index;
- int err;
-
- /* The logging frame consists at minimum of the standard header,
- * the priority byte, the ident length byte and at least one string
- * terminator NUL byte. Anything shorter are invalid packets.
- */
- if (len < sizeof(*hdr) + 3)
- return -EINVAL;
-
- skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
- if (!skb)
- return err;
-
- if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
- err = -EFAULT;
- goto drop;
- }
-
- hdr = (void *)skb->data;
-
- if (__le16_to_cpu(hdr->len) != len - sizeof(*hdr)) {
- err = -EINVAL;
- goto drop;
- }
-
- if (__le16_to_cpu(hdr->opcode) == 0x0000) {
- __u8 priority = skb->data[sizeof(*hdr)];
- __u8 ident_len = skb->data[sizeof(*hdr) + 1];
-
- /* Only the priorities 0-7 are valid and with that any other
- * value results in an invalid packet.
- *
- * The priority byte is followed by an ident length byte and
- * the NUL terminated ident string. Check that the ident
- * length is not overflowing the packet and also that the
- * ident string itself is NUL terminated. In case the ident
- * length is zero, the length value actually doubles as NUL
- * terminator identifier.
- *
- * The message follows the ident string (if present) and
- * must be NUL terminated. Otherwise it is not a valid packet.
- */
- if (priority > 7 || skb->data[len - 1] != 0x00 ||
- ident_len > len - sizeof(*hdr) - 3 ||
- skb->data[sizeof(*hdr) + ident_len + 1] != 0x00) {
- err = -EINVAL;
- goto drop;
- }
- } else {
- err = -EINVAL;
- goto drop;
- }
-
- index = __le16_to_cpu(hdr->index);
-
- if (index != MGMT_INDEX_NONE) {
- hdev = hci_dev_get(index);
- if (!hdev) {
- err = -ENODEV;
- goto drop;
- }
- } else {
- hdev = NULL;
- }
-
- hdr->opcode = cpu_to_le16(HCI_MON_USER_LOGGING);
-
- hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, HCI_SOCK_TRUSTED, NULL);
- err = len;
-
- if (hdev)
- hci_dev_put(hdev);
-
-drop:
- kfree_skb(skb);
- return err;
-}
-
static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t len)
{
@@ -1307,9 +1094,6 @@
case HCI_CHANNEL_MONITOR:
err = -EOPNOTSUPP;
goto done;
- case HCI_CHANNEL_LOGGING:
- err = hci_logging_frame(sk, msg, len);
- goto done;
default:
mutex_lock(&mgmt_chan_list_lock);
chan = __hci_mgmt_chan_find(hci_pi(sk)->channel);
@@ -1342,7 +1126,7 @@
goto drop;
}
- hci_skb_pkt_type(skb) = skb->data[0];
+ bt_cb(skb)->pkt_type = *((unsigned char *) skb->data);
skb_pull(skb, 1);
if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
@@ -1351,16 +1135,16 @@
*
* However check that the packet type is valid.
*/
- if (hci_skb_pkt_type(skb) != HCI_COMMAND_PKT &&
- hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
- hci_skb_pkt_type(skb) != HCI_SCODATA_PKT) {
+ if (bt_cb(skb)->pkt_type != HCI_COMMAND_PKT &&
+ bt_cb(skb)->pkt_type != HCI_ACLDATA_PKT &&
+ bt_cb(skb)->pkt_type != HCI_SCODATA_PKT) {
err = -EINVAL;
goto drop;
}
skb_queue_tail(&hdev->raw_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work);
- } else if (hci_skb_pkt_type(skb) == HCI_COMMAND_PKT) {
+ } else if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
u16 opcode = get_unaligned_le16(skb->data);
u16 ogf = hci_opcode_ogf(opcode);
u16 ocf = hci_opcode_ocf(opcode);
@@ -1373,11 +1157,6 @@
goto drop;
}
- /* Since the opcode has already been extracted here, store
- * a copy of the value for later use by the drivers.
- */
- hci_skb_opcode(skb) = opcode;
-
if (ogf == 0x3f) {
skb_queue_tail(&hdev->raw_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work);
@@ -1385,7 +1164,7 @@
/* Stand-alone HCI commands must be flagged as
* single-command requests.
*/
- bt_cb(skb)->hci.req_flags |= HCI_REQ_START;
+ bt_cb(skb)->req.start = true;
skb_queue_tail(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
@@ -1396,12 +1175,6 @@
goto drop;
}
- if (hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
- hci_skb_pkt_type(skb) != HCI_SCODATA_PKT) {
- err = -EINVAL;
- goto drop;
- }
-
skb_queue_tail(&hdev->raw_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work);
}
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 341f51b..6fca135 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -5,6 +5,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
+static int acl_conn_index;
static struct class *bt_class;
static inline char *link_typetostr(int type)
@@ -99,7 +100,9 @@
BT_DBG("conn %p", conn);
- dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
+ acl_conn_index++;
+ dev_set_name(&conn->dev, "%s:%d:%d", hdev->name, conn->handle,
+ acl_conn_index);
if (device_add(&conn->dev) < 0) {
BT_ERR("Failed to register connection device");
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 4768321..a230aa2 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -416,20 +416,6 @@
{
struct hidp_session *session = (struct hidp_session *) arg;
- /* The HIDP user-space API only contains calls to add and remove
- * devices. There is no way to forward events of any kind. Therefore,
- * we have to forcefully disconnect a device on idle-timeouts. This is
- * unfortunate and weird API design, but it is spec-compliant and
- * required for backwards-compatibility. Hence, on idle-timeout, we
- * signal driver-detach events, so poll() will be woken up with an
- * error-condition on both sockets.
- */
-
- session->intr_sock->sk->sk_err = EUNATCH;
- session->ctrl_sock->sk->sk_err = EUNATCH;
- wake_up_interruptible(sk_sleep(session->intr_sock->sk));
- wake_up_interruptible(sk_sleep(session->ctrl_sock->sk));
-
hidp_session_terminate(session);
}
@@ -792,9 +778,6 @@
snprintf(hid->phys, sizeof(hid->phys), "%pMR",
&l2cap_pi(session->ctrl_sock->sk)->chan->src);
- /* NOTE: Some device modules depend on the dst address being stored in
- * uniq. Please be aware of this before making changes to this behavior.
- */
snprintf(hid->uniq, sizeof(hid->uniq), "%pMR",
&l2cap_pi(session->ctrl_sock->sk)->chan->dst);
@@ -946,7 +929,6 @@
session->conn = l2cap_conn_get(conn);
session->user.probe = hidp_session_probe;
session->user.remove = hidp_session_remove;
- INIT_LIST_HEAD(&session->user.list);
session->ctrl_sock = ctrl_sock;
session->intr_sock = intr_sock;
skb_queue_head_init(&session->ctrl_transmit);
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index 8798492..20d5ea4 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -186,7 +186,7 @@
};
/* HIDP init defines */
-int __init hidp_init_sockets(void);
-void __exit hidp_cleanup_sockets(void);
+extern int __init hidp_init_sockets(void);
+extern void __exit hidp_cleanup_sockets(void);
#endif /* __HIDP_H */
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 2947291..eda4304 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -213,7 +213,6 @@
write_unlock(&chan_list_lock);
return err;
}
-EXPORT_SYMBOL_GPL(l2cap_add_psm);
int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
{
@@ -239,7 +238,7 @@
else
dyn_end = L2CAP_CID_DYN_END;
- for (cid = L2CAP_CID_DYN_START; cid <= dyn_end; cid++) {
+ for (cid = L2CAP_CID_DYN_START; cid < dyn_end; cid++) {
if (!__l2cap_get_chan_by_scid(conn, cid))
return cid;
}
@@ -453,7 +452,6 @@
return chan;
}
-EXPORT_SYMBOL_GPL(l2cap_chan_create);
static void l2cap_chan_destroy(struct kref *kref)
{
@@ -481,7 +479,6 @@
kref_put(&c->kref, l2cap_chan_destroy);
}
-EXPORT_SYMBOL_GPL(l2cap_chan_put);
void l2cap_chan_set_defaults(struct l2cap_chan *chan)
{
@@ -500,7 +497,6 @@
set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
}
-EXPORT_SYMBOL_GPL(l2cap_chan_set_defaults);
static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
{
@@ -642,7 +638,6 @@
return;
}
-EXPORT_SYMBOL_GPL(l2cap_chan_del);
static void l2cap_conn_update_id_addr(struct work_struct *work)
{
@@ -748,7 +743,6 @@
break;
}
}
-EXPORT_SYMBOL(l2cap_chan_close);
static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
{
@@ -1601,7 +1595,7 @@
hci_dev_lock(hdev);
- if (!list_empty(&user->list)) {
+ if (user->list.next || user->list.prev) {
ret = -EINVAL;
goto out_unlock;
}
@@ -1631,10 +1625,12 @@
hci_dev_lock(hdev);
- if (list_empty(&user->list))
+ if (!user->list.next || !user->list.prev)
goto out_unlock;
- list_del_init(&user->list);
+ list_del(&user->list);
+ user->list.next = NULL;
+ user->list.prev = NULL;
user->remove(conn, user);
out_unlock:
@@ -1648,7 +1644,9 @@
while (!list_empty(&conn->users)) {
user = list_first_entry(&conn->users, struct l2cap_user, list);
- list_del_init(&user->list);
+ list_del(&user->list);
+ user->list.next = NULL;
+ user->list.prev = NULL;
user->remove(conn, user);
}
}
@@ -2546,7 +2544,6 @@
return err;
}
-EXPORT_SYMBOL_GPL(l2cap_chan_send);
static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq)
{
@@ -5251,9 +5248,7 @@
credits = __le16_to_cpu(rsp->credits);
result = __le16_to_cpu(rsp->result);
- if (result == L2CAP_CR_SUCCESS && (mtu < 23 || mps < 23 ||
- dcid < L2CAP_CID_DYN_START ||
- dcid > L2CAP_CID_LE_DYN_END))
+ if (result == L2CAP_CR_SUCCESS && (mtu < 23 || mps < 23))
return -EPROTO;
BT_DBG("dcid 0x%4.4x mtu %u mps %u credits %u result 0x%2.2x",
@@ -5273,11 +5268,6 @@
switch (result) {
case L2CAP_CR_SUCCESS:
- if (__l2cap_get_chan_by_dcid(conn, dcid)) {
- err = -EBADSLT;
- break;
- }
-
chan->ident = 0;
chan->dcid = dcid;
chan->omtu = mtu;
@@ -5445,16 +5435,9 @@
goto response_unlock;
}
- /* Check for valid dynamic CID range */
- if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) {
- result = L2CAP_CR_INVALID_SCID;
- chan = NULL;
- goto response_unlock;
- }
-
/* Check if we already have channel with that dcid */
if (__l2cap_get_chan_by_dcid(conn, scid)) {
- result = L2CAP_CR_SCID_IN_USE;
+ result = L2CAP_CR_NO_MEM;
chan = NULL;
goto response_unlock;
}
@@ -7114,6 +7097,8 @@
chan->dcid = cid;
if (bdaddr_type_is_le(dst_type)) {
+ u8 role;
+
/* Convert from L2CAP channel address type to HCI address type
*/
if (dst_type == BDADDR_LE_PUBLIC)
@@ -7122,15 +7107,14 @@
dst_type = ADDR_LE_DEV_RANDOM;
if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
- hcon = hci_connect_le(hdev, dst, dst_type,
- chan->sec_level,
- HCI_LE_CONN_TIMEOUT,
- HCI_ROLE_SLAVE);
+ role = HCI_ROLE_SLAVE;
else
- hcon = hci_connect_le_scan(hdev, dst, dst_type,
- chan->sec_level,
- HCI_LE_CONN_TIMEOUT);
+ role = HCI_ROLE_MASTER;
+ hcon = hci_connect_le_scan(hdev, dst, dst_type,
+ chan->sec_level,
+ HCI_LE_CONN_TIMEOUT,
+ role);
} else {
u8 auth_type = l2cap_get_auth_type(chan);
hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type);
@@ -7195,7 +7179,6 @@
hci_dev_put(hdev);
return err;
}
-EXPORT_SYMBOL_GPL(l2cap_chan_connect);
/* ---- L2CAP interface with lower layer (HCI) ---- */
@@ -7240,7 +7223,7 @@
read_lock(&chan_list_lock);
if (c)
- c = list_next_entry(c, global_l);
+ c = list_entry(c->global_l.next, typeof(*c), global_l);
else
c = list_entry(chan_list.next, typeof(*c), global_l);
@@ -7454,7 +7437,7 @@
mutex_unlock(&conn->chan_lock);
}
-void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
+int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_hdr *hdr;
@@ -7497,7 +7480,7 @@
if (len == skb->len) {
/* Complete frame received */
l2cap_recv_frame(conn, skb);
- return;
+ return 0;
}
BT_DBG("Start: total len %d, frag len %d", len, skb->len);
@@ -7556,6 +7539,7 @@
drop:
kfree_skb(skb);
+ return 0;
}
static struct hci_cb l2cap_cb = {
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 9f4f665..7399be6 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1054,23 +1054,18 @@
sock_put(sk);
}
-static int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan)
+static int __l2cap_wait_ack(struct sock *sk)
{
+ struct l2cap_chan *chan = l2cap_pi(sk)->chan;
DECLARE_WAITQUEUE(wait, current);
int err = 0;
- int timeo = L2CAP_WAIT_ACK_POLL_PERIOD;
- /* Timeout to prevent infinite loop */
- unsigned long timeout = jiffies + L2CAP_WAIT_ACK_TIMEOUT;
+ int timeo = HZ/5;
add_wait_queue(sk_sleep(sk), &wait);
set_current_state(TASK_INTERRUPTIBLE);
- do {
- BT_DBG("Waiting for %d ACKs, timeout %04d ms",
- chan->unacked_frames, time_after(jiffies, timeout) ? 0 :
- jiffies_to_msecs(timeout - jiffies));
-
+ while (chan->unacked_frames > 0 && chan->conn) {
if (!timeo)
- timeo = L2CAP_WAIT_ACK_POLL_PERIOD;
+ timeo = HZ/5;
if (signal_pending(current)) {
err = sock_intr_errno(timeo);
@@ -1085,15 +1080,7 @@
err = sock_error(sk);
if (err)
break;
-
- if (time_after(jiffies, timeout)) {
- err = -ENOLINK;
- break;
- }
-
- } while (chan->unacked_frames > 0 &&
- chan->state == BT_CONNECTED);
-
+ }
set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
return err;
@@ -1111,76 +1098,41 @@
if (!sk)
return 0;
- lock_sock(sk);
-
- if (sk->sk_shutdown)
- goto shutdown_already;
-
- BT_DBG("Handling sock shutdown");
-
- /* prevent sk structure from being freed whilst unlocked */
- sock_hold(sk);
-
chan = l2cap_pi(sk)->chan;
- /* prevent chan structure from being freed whilst unlocked */
- l2cap_chan_hold(chan);
+ conn = chan->conn;
BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
- if (chan->mode == L2CAP_MODE_ERTM &&
- chan->unacked_frames > 0 &&
- chan->state == BT_CONNECTED) {
- err = __l2cap_wait_ack(sk, chan);
-
- /* After waiting for ACKs, check whether shutdown
- * has already been actioned to close the L2CAP
- * link such as by l2cap_disconnection_req().
- */
- if (sk->sk_shutdown)
- goto has_shutdown;
- }
-
- sk->sk_shutdown = SHUTDOWN_MASK;
- release_sock(sk);
-
- l2cap_chan_lock(chan);
- conn = chan->conn;
if (conn)
- /* prevent conn structure from being freed */
- l2cap_conn_get(conn);
- l2cap_chan_unlock(chan);
-
- if (conn)
- /* mutex lock must be taken before l2cap_chan_lock() */
mutex_lock(&conn->chan_lock);
l2cap_chan_lock(chan);
- l2cap_chan_close(chan, 0);
- l2cap_chan_unlock(chan);
-
- if (conn) {
- mutex_unlock(&conn->chan_lock);
- l2cap_conn_put(conn);
- }
-
lock_sock(sk);
- if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
- !(current->flags & PF_EXITING))
- err = bt_sock_wait_state(sk, BT_CLOSED,
- sk->sk_lingertime);
+ if (!sk->sk_shutdown) {
+ if (chan->mode == L2CAP_MODE_ERTM)
+ err = __l2cap_wait_ack(sk);
-has_shutdown:
- l2cap_chan_put(chan);
- sock_put(sk);
+ sk->sk_shutdown = SHUTDOWN_MASK;
-shutdown_already:
+ release_sock(sk);
+ l2cap_chan_close(chan, 0);
+ lock_sock(sk);
+
+ if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
+ !(current->flags & PF_EXITING))
+ err = bt_sock_wait_state(sk, BT_CLOSED,
+ sk->sk_lingertime);
+ }
+
if (!err && sk->sk_err)
err = -sk->sk_err;
release_sock(sk);
+ l2cap_chan_unlock(chan);
- BT_DBG("Sock shutdown complete err: %d", err);
+ if (conn)
+ mutex_unlock(&conn->chan_lock);
return err;
}
@@ -1496,7 +1448,7 @@
static void l2cap_skb_msg_name(struct sk_buff *skb, void *msg_name,
int *msg_namelen)
{
- DECLARE_SOCKADDR(struct sockaddr_l2 *, la, msg_name);
+ struct sockaddr_l2 *la = (struct sockaddr_l2 *) msg_name;
memset(la, 0, sizeof(struct sockaddr_l2));
la->l2_family = AF_BLUETOOTH;
diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c
index aa4cf64..b36bc04 100644
--- a/net/bluetooth/lib.c
+++ b/net/bluetooth/lib.c
@@ -151,22 +151,6 @@
}
EXPORT_SYMBOL(bt_info);
-void bt_warn(const char *format, ...)
-{
- struct va_format vaf;
- va_list args;
-
- va_start(args, format);
-
- vaf.fmt = format;
- vaf.va = &args;
-
- pr_warn("%pV", &vaf);
-
- va_end(args);
-}
-EXPORT_SYMBOL(bt_warn);
-
void bt_err(const char *format, ...)
{
struct va_format vaf;
@@ -182,19 +166,3 @@
va_end(args);
}
EXPORT_SYMBOL(bt_err);
-
-void bt_err_ratelimited(const char *format, ...)
-{
- struct va_format vaf;
- va_list args;
-
- va_start(args, format);
-
- vaf.fmt = format;
- vaf.va = &args;
-
- pr_err_ratelimited("%pV", &vaf);
-
- va_end(args);
-}
-EXPORT_SYMBOL(bt_err_ratelimited);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index f024112..d19f163 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -40,7 +40,7 @@
#define U16_MAX ((u16)~0U)
#define MGMT_VERSION 1
-#define MGMT_REVISION 10
+#define MGMT_REVISION 9
static const u16 mgmt_commands[] = {
MGMT_OP_READ_INDEX_LIST,
@@ -270,14 +270,6 @@
HCI_SOCK_TRUSTED, skip_sk);
}
-static u8 le_addr_type(u8 mgmt_addr_type)
-{
- if (mgmt_addr_type == BDADDR_LE_PUBLIC)
- return ADDR_LE_DEV_PUBLIC;
- else
- return ADDR_LE_DEV_RANDOM;
-}
-
static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len)
{
@@ -842,20 +834,6 @@
return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
}
-static u8 get_current_adv_instance(struct hci_dev *hdev)
-{
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the advertising data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return hdev->cur_adv_instance;
-
- return 0x00;
-}
-
static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
{
u8 ad_len = 0;
@@ -882,25 +860,19 @@
return ad_len;
}
-static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
- u8 *ptr)
+static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
{
- struct adv_info *adv_instance;
-
- adv_instance = hci_find_adv_instance(hdev, instance);
- if (!adv_instance)
- return 0;
-
/* TODO: Set the appropriate entries based on advertising instance flags
* here once flags other than 0 are supported.
*/
- memcpy(ptr, adv_instance->scan_rsp_data,
- adv_instance->scan_rsp_len);
+ memcpy(ptr, hdev->adv_instance.scan_rsp_data,
+ hdev->adv_instance.scan_rsp_len);
- return adv_instance->scan_rsp_len;
+ return hdev->adv_instance.scan_rsp_len;
}
-static void update_inst_scan_rsp_data(struct hci_request *req, u8 instance)
+static void update_scan_rsp_data_for_instance(struct hci_request *req,
+ u8 instance)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_scan_rsp_data cp;
@@ -912,7 +884,7 @@
memset(&cp, 0, sizeof(cp));
if (instance)
- len = create_instance_scan_rsp_data(hdev, instance, cp.data);
+ len = create_instance_scan_rsp_data(hdev, cp.data);
else
len = create_default_scan_rsp_data(hdev, cp.data);
@@ -930,7 +902,21 @@
static void update_scan_rsp_data(struct hci_request *req)
{
- update_inst_scan_rsp_data(req, get_current_adv_instance(req->hdev));
+ struct hci_dev *hdev = req->hdev;
+ u8 instance;
+
+ /* The "Set Advertising" setting supersedes the "Add Advertising"
+ * setting. Here we set the scan response data based on which
+ * setting was set. When neither apply, default to the global settings,
+ * represented by instance "0".
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ instance = 0x01;
+ else
+ instance = 0x00;
+
+ update_scan_rsp_data_for_instance(req, instance);
}
static u8 get_adv_discov_flags(struct hci_dev *hdev)
@@ -957,6 +943,20 @@
return 0;
}
+static u8 get_current_adv_instance(struct hci_dev *hdev)
+{
+ /* The "Set Advertising" setting supersedes the "Add Advertising"
+ * setting. Here we set the advertising data based on which
+ * setting was set. When neither apply, default to the global settings,
+ * represented by instance "0".
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ return 0x01;
+
+ return 0x00;
+}
+
static bool get_connectable(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
@@ -977,65 +977,41 @@
static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
{
u32 flags;
- struct adv_info *adv_instance;
- if (instance == 0x00) {
- /* Instance 0 always manages the "Tx Power" and "Flags"
- * fields
- */
- flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
-
- /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting
- * corresponds to the "connectable" instance flag.
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
- flags |= MGMT_ADV_FLAG_CONNECTABLE;
-
- return flags;
- }
-
- adv_instance = hci_find_adv_instance(hdev, instance);
-
- /* Return 0 when we got an invalid instance identifier. */
- if (!adv_instance)
+ if (instance > 0x01)
return 0;
- return adv_instance->flags;
+ if (instance == 0x01)
+ return hdev->adv_instance.flags;
+
+ /* Instance 0 always manages the "Tx Power" and "Flags" fields */
+ flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
+
+ /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
+ * to the "connectable" instance flag.
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;
+
+ return flags;
}
-static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
+static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
{
- u8 instance = get_current_adv_instance(hdev);
- struct adv_info *adv_instance;
-
- /* Ignore instance 0 */
- if (instance == 0x00)
- return 0;
-
- adv_instance = hci_find_adv_instance(hdev, instance);
- if (!adv_instance)
+ /* Ignore instance 0 and other unsupported instances */
+ if (instance != 0x01)
return 0;
/* TODO: Take into account the "appearance" and "local-name" flags here.
* These are currently being ignored as they are not supported.
*/
- return adv_instance->scan_rsp_len;
+ return hdev->adv_instance.scan_rsp_len;
}
static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
{
- struct adv_info *adv_instance = NULL;
u8 ad_len = 0, flags = 0;
- u32 instance_flags;
-
- /* Return 0 when the current instance identifier is invalid. */
- if (instance) {
- adv_instance = hci_find_adv_instance(hdev, instance);
- if (!adv_instance)
- return 0;
- }
-
- instance_flags = get_adv_instance_flags(hdev, instance);
+ u32 instance_flags = get_adv_instance_flags(hdev, instance);
/* The Add Advertising command allows userspace to set both the general
* and limited discoverable flags.
@@ -1069,11 +1045,12 @@
}
}
- if (adv_instance) {
- memcpy(ptr, adv_instance->adv_data,
- adv_instance->adv_data_len);
- ad_len += adv_instance->adv_data_len;
- ptr += adv_instance->adv_data_len;
+ if (instance) {
+ memcpy(ptr, hdev->adv_instance.adv_data,
+ hdev->adv_instance.adv_data_len);
+
+ ad_len += hdev->adv_instance.adv_data_len;
+ ptr += hdev->adv_instance.adv_data_len;
}
/* Provide Tx Power only if we can provide a valid value for it */
@@ -1090,7 +1067,7 @@
return ad_len;
}
-static void update_inst_adv_data(struct hci_request *req, u8 instance)
+static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_data cp;
@@ -1118,7 +1095,10 @@
static void update_adv_data(struct hci_request *req)
{
- update_inst_adv_data(req, get_current_adv_instance(req->hdev));
+ struct hci_dev *hdev = req->hdev;
+ u8 instance = get_current_adv_instance(hdev);
+
+ update_adv_data_for_instance(req, instance);
}
int mgmt_update_adv_data(struct hci_dev *hdev)
@@ -1299,7 +1279,7 @@
if (connectable)
cp.type = LE_ADV_IND;
- else if (get_cur_adv_instance_scan_rsp_len(hdev))
+ else if (get_adv_instance_scan_rsp_len(hdev, instance))
cp.type = LE_ADV_SCAN_IND;
else
cp.type = LE_ADV_NONCONN_IND;
@@ -1418,6 +1398,49 @@
}
}
+static bool hci_stop_discovery(struct hci_request *req)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct hci_cp_remote_name_req_cancel cp;
+ struct inquiry_entry *e;
+
+ switch (hdev->discovery.state) {
+ case DISCOVERY_FINDING:
+ if (test_bit(HCI_INQUIRY, &hdev->flags))
+ hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+
+ if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
+ cancel_delayed_work(&hdev->le_scan_disable);
+ hci_req_add_le_scan_disable(req);
+ }
+
+ return true;
+
+ case DISCOVERY_RESOLVING:
+ e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
+ NAME_PENDING);
+ if (!e)
+ break;
+
+ bacpy(&cp.bdaddr, &e->data.bdaddr);
+ hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
+ &cp);
+
+ return true;
+
+ default:
+ /* Passive scanning */
+ if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
+ hci_req_add_le_scan_disable(req);
+ return true;
+ }
+
+ break;
+ }
+
+ return false;
+}
+
static void advertising_added(struct sock *sk, struct hci_dev *hdev,
u8 instance)
{
@@ -1438,141 +1461,27 @@
mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
}
-static int schedule_adv_instance(struct hci_request *req, u8 instance,
- bool force) {
- struct hci_dev *hdev = req->hdev;
- struct adv_info *adv_instance = NULL;
- u16 timeout;
-
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
- return -EPERM;
-
- if (hdev->adv_instance_timeout)
- return -EBUSY;
-
- adv_instance = hci_find_adv_instance(hdev, instance);
- if (!adv_instance)
- return -ENOENT;
-
- /* A zero timeout means unlimited advertising. As long as there is
- * only one instance, duration should be ignored. We still set a timeout
- * in case further instances are being added later on.
- *
- * If the remaining lifetime of the instance is more than the duration
- * then the timeout corresponds to the duration, otherwise it will be
- * reduced to the remaining instance lifetime.
- */
- if (adv_instance->timeout == 0 ||
- adv_instance->duration <= adv_instance->remaining_time)
- timeout = adv_instance->duration;
- else
- timeout = adv_instance->remaining_time;
-
- /* The remaining time is being reduced unless the instance is being
- * advertised without time limit.
- */
- if (adv_instance->timeout)
- adv_instance->remaining_time =
- adv_instance->remaining_time - timeout;
-
- hdev->adv_instance_timeout = timeout;
- queue_delayed_work(hdev->workqueue,
- &hdev->adv_instance_expire,
- msecs_to_jiffies(timeout * 1000));
-
- /* If we're just re-scheduling the same instance again then do not
- * execute any HCI commands. This happens when a single instance is
- * being advertised.
- */
- if (!force && hdev->cur_adv_instance == instance &&
- hci_dev_test_flag(hdev, HCI_LE_ADV))
- return 0;
-
- hdev->cur_adv_instance = instance;
- update_adv_data(req);
- update_scan_rsp_data(req);
- enable_advertising(req);
-
- return 0;
-}
-
-static void cancel_adv_timeout(struct hci_dev *hdev)
+static void clear_adv_instance(struct hci_dev *hdev)
{
- if (hdev->adv_instance_timeout) {
- hdev->adv_instance_timeout = 0;
- cancel_delayed_work(&hdev->adv_instance_expire);
- }
-}
+ struct hci_request req;
-/* For a single instance:
- * - force == true: The instance will be removed even when its remaining
- * lifetime is not zero.
- * - force == false: the instance will be deactivated but kept stored unless
- * the remaining lifetime is zero.
- *
- * For instance == 0x00:
- * - force == true: All instances will be removed regardless of their timeout
- * setting.
- * - force == false: Only instances that have a timeout will be removed.
- */
-static void clear_adv_instance(struct hci_dev *hdev, struct hci_request *req,
- u8 instance, bool force)
-{
- struct adv_info *adv_instance, *n, *next_instance = NULL;
- int err;
- u8 rem_inst;
+ if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ return;
- /* Cancel any timeout concerning the removed instance(s). */
- if (!instance || hdev->cur_adv_instance == instance)
- cancel_adv_timeout(hdev);
+ if (hdev->adv_instance.timeout)
+ cancel_delayed_work(&hdev->adv_instance.timeout_exp);
- /* Get the next instance to advertise BEFORE we remove
- * the current one. This can be the same instance again
- * if there is only one instance.
- */
- if (instance && hdev->cur_adv_instance == instance)
- next_instance = hci_get_next_instance(hdev, instance);
+ memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
+ advertising_removed(NULL, hdev, 1);
+ hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
- if (instance == 0x00) {
- list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances,
- list) {
- if (!(force || adv_instance->timeout))
- continue;
-
- rem_inst = adv_instance->instance;
- err = hci_remove_adv_instance(hdev, rem_inst);
- if (!err)
- advertising_removed(NULL, hdev, rem_inst);
- }
- hdev->cur_adv_instance = 0x00;
- } else {
- adv_instance = hci_find_adv_instance(hdev, instance);
-
- if (force || (adv_instance && adv_instance->timeout &&
- !adv_instance->remaining_time)) {
- /* Don't advertise a removed instance. */
- if (next_instance &&
- next_instance->instance == instance)
- next_instance = NULL;
-
- err = hci_remove_adv_instance(hdev, instance);
- if (!err)
- advertising_removed(NULL, hdev, instance);
- }
- }
-
- if (list_empty(&hdev->adv_instances)) {
- hdev->cur_adv_instance = 0x00;
- hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
- }
-
- if (!req || !hdev_is_powered(hdev) ||
+ if (!hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING))
return;
- if (next_instance)
- schedule_adv_instance(req, next_instance->instance, false);
+ hci_req_init(&req, hdev);
+ disable_advertising(&req);
+ hci_req_run(&req, NULL);
}
static int clean_up_hci_state(struct hci_dev *hdev)
@@ -1590,16 +1499,44 @@
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}
- clear_adv_instance(hdev, NULL, 0x00, false);
+ if (hdev->adv_instance.timeout)
+ clear_adv_instance(hdev);
if (hci_dev_test_flag(hdev, HCI_LE_ADV))
disable_advertising(&req);
- discov_stopped = hci_req_stop_discovery(&req);
+ discov_stopped = hci_stop_discovery(&req);
list_for_each_entry(conn, &hdev->conn_hash.list, list) {
- /* 0x15 == Terminated due to Power Off */
- __hci_abort_conn(&req, conn, 0x15);
+ struct hci_cp_disconnect dc;
+ struct hci_cp_reject_conn_req rej;
+
+ switch (conn->state) {
+ case BT_CONNECTED:
+ case BT_CONFIG:
+ dc.handle = cpu_to_le16(conn->handle);
+ dc.reason = 0x15; /* Terminated due to Power Off */
+ hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
+ break;
+ case BT_CONNECT:
+ if (conn->type == LE_LINK)
+ hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL,
+ 0, NULL);
+ else if (conn->type == ACL_LINK)
+ hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL,
+ 6, &conn->dst);
+ break;
+ case BT_CONNECT2:
+ bacpy(&rej.bdaddr, &conn->dst);
+ rej.reason = 0x15; /* Terminated due to Power Off */
+ if (conn->type == ACL_LINK)
+ hci_req_add(&req, HCI_OP_REJECT_CONN_REQ,
+ sizeof(rej), &rej);
+ else if (conn->type == SCO_LINK)
+ hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ,
+ sizeof(rej), &rej);
+ break;
+ }
}
err = hci_req_run(&req, clean_up_hci_complete);
@@ -2469,8 +2406,8 @@
hci_req_init(&req, hdev);
update_adv_data(&req);
update_scan_rsp_data(&req);
+ __hci_update_background_scan(&req);
hci_req_run(&req, NULL);
- hci_update_background_scan(hdev);
}
unlock:
@@ -2518,9 +2455,6 @@
val = !!cp->val;
enabled = lmp_host_le_capable(hdev);
- if (!val)
- clear_adv_instance(hdev, NULL, 0x00, true);
-
if (!hdev_is_powered(hdev) || val == enabled) {
bool changed = false;
@@ -2984,10 +2918,9 @@
{
struct mgmt_cp_unpair_device *cp = data;
struct mgmt_rp_unpair_device rp;
- struct hci_conn_params *params;
+ struct hci_cp_disconnect dc;
struct mgmt_pending_cmd *cmd;
struct hci_conn *conn;
- u8 addr_type;
int err;
memset(&rp, 0, sizeof(rp));
@@ -3028,23 +2961,36 @@
conn = NULL;
err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
- if (err < 0) {
- err = mgmt_cmd_complete(sk, hdev->id,
- MGMT_OP_UNPAIR_DEVICE,
- MGMT_STATUS_NOT_PAIRED, &rp,
- sizeof(rp));
- goto unlock;
+ } else {
+ u8 addr_type;
+
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
+ &cp->addr.bdaddr);
+ if (conn) {
+ /* Defer clearing up the connection parameters
+ * until closing to give a chance of keeping
+ * them if a repairing happens.
+ */
+ set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
+
+ /* If disconnection is not requested, then
+ * clear the connection variable so that the
+ * link is not terminated.
+ */
+ if (!cp->disconnect)
+ conn = NULL;
}
- goto done;
+ if (cp->addr.type == BDADDR_LE_PUBLIC)
+ addr_type = ADDR_LE_DEV_PUBLIC;
+ else
+ addr_type = ADDR_LE_DEV_RANDOM;
+
+ hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
+
+ err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
}
- /* LE address type */
- addr_type = le_addr_type(cp->addr.type);
-
- hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
-
- err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
if (err < 0) {
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
MGMT_STATUS_NOT_PAIRED, &rp,
@@ -3052,36 +2998,6 @@
goto unlock;
}
- conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
- if (!conn) {
- hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
- goto done;
- }
-
- /* Abort any ongoing SMP pairing */
- smp_cancel_pairing(conn);
-
- /* Defer clearing up the connection parameters until closing to
- * give a chance of keeping them if a repairing happens.
- */
- set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
-
- /* Disable auto-connection parameters if present */
- params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
- if (params) {
- if (params->explicit_connect)
- params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
- else
- params->auto_connect = HCI_AUTO_CONN_DISABLED;
- }
-
- /* If disconnection is not requested, then clear the connection
- * variable so that the link is not terminated.
- */
- if (!cp->disconnect)
- conn = NULL;
-
-done:
/* If the connection variable is set, then termination of the
* link is requested.
*/
@@ -3101,7 +3017,9 @@
cmd->cmd_complete = addr_cmd_complete;
- err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
+ dc.handle = cpu_to_le16(conn->handle);
+ dc.reason = 0x13; /* Remote User Terminated Connection */
+ err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
if (err < 0)
mgmt_pending_remove(cmd);
@@ -3149,8 +3067,7 @@
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
&cp->addr.bdaddr);
else
- conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
- le_addr_type(cp->addr.type));
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
@@ -3501,9 +3418,16 @@
conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
auth_type);
} else {
- u8 addr_type = le_addr_type(cp->addr.type);
+ u8 addr_type;
struct hci_conn_params *p;
+ /* Convert from L2CAP channel address type to HCI address type
+ */
+ if (cp->addr.type == BDADDR_LE_PUBLIC)
+ addr_type = ADDR_LE_DEV_PUBLIC;
+ else
+ addr_type = ADDR_LE_DEV_RANDOM;
+
/* When pairing a new device, it is expected to remember
* this device for future connections. Adding the connection
* parameter information ahead of time allows tracking
@@ -3520,7 +3444,8 @@
conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
addr_type, sec_level,
- HCI_LE_CONN_TIMEOUT);
+ HCI_LE_CONN_TIMEOUT,
+ HCI_ROLE_MASTER);
}
if (IS_ERR(conn)) {
@@ -3646,8 +3571,7 @@
if (addr->type == BDADDR_BREDR)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
else
- conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
- le_addr_type(addr->type));
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
if (!conn) {
err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
@@ -4122,9 +4046,144 @@
return err;
}
-void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
+static bool trigger_bredr_inquiry(struct hci_request *req, u8 *status)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct hci_cp_inquiry cp;
+ /* General inquiry access code (GIAC) */
+ u8 lap[3] = { 0x33, 0x8b, 0x9e };
+
+ *status = mgmt_bredr_support(hdev);
+ if (*status)
+ return false;
+
+ if (hci_dev_test_flag(hdev, HCI_INQUIRY)) {
+ *status = MGMT_STATUS_BUSY;
+ return false;
+ }
+
+ hci_inquiry_cache_flush(hdev);
+
+ memset(&cp, 0, sizeof(cp));
+ memcpy(&cp.lap, lap, sizeof(cp.lap));
+ cp.length = DISCOV_BREDR_INQUIRY_LEN;
+
+ hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
+
+ return true;
+}
+
+static bool trigger_le_scan(struct hci_request *req, u16 interval, u8 *status)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct hci_cp_le_set_scan_param param_cp;
+ struct hci_cp_le_set_scan_enable enable_cp;
+ u8 own_addr_type;
+ int err;
+
+ *status = mgmt_le_support(hdev);
+ if (*status)
+ return false;
+
+ if (hci_dev_test_flag(hdev, HCI_LE_ADV)) {
+ /* Don't let discovery abort an outgoing connection attempt
+ * that's using directed advertising.
+ */
+ if (hci_lookup_le_connect(hdev)) {
+ *status = MGMT_STATUS_REJECTED;
+ return false;
+ }
+
+ disable_advertising(req);
+ }
+
+ /* If controller is scanning, it means the background scanning is
+ * running. Thus, we should temporarily stop it in order to set the
+ * discovery scanning parameters.
+ */
+ if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
+ hci_req_add_le_scan_disable(req);
+
+ /* All active scans will be done with either a resolvable private
+ * address (when privacy feature has been enabled) or non-resolvable
+ * private address.
+ */
+ err = hci_update_random_address(req, true, &own_addr_type);
+ if (err < 0) {
+ *status = MGMT_STATUS_FAILED;
+ return false;
+ }
+
+ memset(¶m_cp, 0, sizeof(param_cp));
+ param_cp.type = LE_SCAN_ACTIVE;
+ param_cp.interval = cpu_to_le16(interval);
+ param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
+ param_cp.own_address_type = own_addr_type;
+
+ hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
+ ¶m_cp);
+
+ memset(&enable_cp, 0, sizeof(enable_cp));
+ enable_cp.enable = LE_SCAN_ENABLE;
+ enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
+
+ hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
+ &enable_cp);
+
+ return true;
+}
+
+static bool trigger_discovery(struct hci_request *req, u8 *status)
+{
+ struct hci_dev *hdev = req->hdev;
+
+ switch (hdev->discovery.type) {
+ case DISCOV_TYPE_BREDR:
+ if (!trigger_bredr_inquiry(req, status))
+ return false;
+ break;
+
+ case DISCOV_TYPE_INTERLEAVED:
+ if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
+ &hdev->quirks)) {
+ /* During simultaneous discovery, we double LE scan
+ * interval. We must leave some time for the controller
+ * to do BR/EDR inquiry.
+ */
+ if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT * 2,
+ status))
+ return false;
+
+ if (!trigger_bredr_inquiry(req, status))
+ return false;
+
+ return true;
+ }
+
+ if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
+ *status = MGMT_STATUS_NOT_SUPPORTED;
+ return false;
+ }
+ /* fall through */
+
+ case DISCOV_TYPE_LE:
+ if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT, status))
+ return false;
+ break;
+
+ default:
+ *status = MGMT_STATUS_INVALID_PARAMS;
+ return false;
+ }
+
+ return true;
+}
+
+static void start_discovery_complete(struct hci_dev *hdev, u8 status,
+ u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ unsigned long timeout;
BT_DBG("status %d", status);
@@ -4139,34 +4198,62 @@
mgmt_pending_remove(cmd);
}
- hci_dev_unlock(hdev);
-}
-
-static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
- uint8_t *mgmt_status)
-{
- switch (type) {
- case DISCOV_TYPE_LE:
- *mgmt_status = mgmt_le_support(hdev);
- if (*mgmt_status)
- return false;
- break;
- case DISCOV_TYPE_INTERLEAVED:
- *mgmt_status = mgmt_le_support(hdev);
- if (*mgmt_status)
- return false;
- /* Intentional fall-through */
- case DISCOV_TYPE_BREDR:
- *mgmt_status = mgmt_bredr_support(hdev);
- if (*mgmt_status)
- return false;
- break;
- default:
- *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
- return false;
+ if (status) {
+ hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+ goto unlock;
}
- return true;
+ hci_discovery_set_state(hdev, DISCOVERY_FINDING);
+
+ /* If the scan involves LE scan, pick proper timeout to schedule
+ * hdev->le_scan_disable that will stop it.
+ */
+ switch (hdev->discovery.type) {
+ case DISCOV_TYPE_LE:
+ timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
+ break;
+ case DISCOV_TYPE_INTERLEAVED:
+ /* When running simultaneous discovery, the LE scanning time
+ * should occupy the whole discovery time sine BR/EDR inquiry
+ * and LE scanning are scheduled by the controller.
+ *
+ * For interleaving discovery in comparison, BR/EDR inquiry
+ * and LE scanning are done sequentially with separate
+ * timeouts.
+ */
+ if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks))
+ timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
+ else
+ timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
+ break;
+ case DISCOV_TYPE_BREDR:
+ timeout = 0;
+ break;
+ default:
+ BT_ERR("Invalid discovery type %d", hdev->discovery.type);
+ timeout = 0;
+ break;
+ }
+
+ if (timeout) {
+ /* When service discovery is used and the controller has
+ * a strict duplicate filter, it is important to remember
+ * the start and duration of the scan. This is required
+ * for restarting scanning during the discovery phase.
+ */
+ if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER,
+ &hdev->quirks) &&
+ hdev->discovery.result_filtering) {
+ hdev->discovery.scan_start = jiffies;
+ hdev->discovery.scan_duration = timeout;
+ }
+
+ queue_delayed_work(hdev->workqueue,
+ &hdev->le_scan_disable, timeout);
+ }
+
+unlock:
+ hci_dev_unlock(hdev);
}
static int start_discovery(struct sock *sk, struct hci_dev *hdev,
@@ -4174,6 +4261,7 @@
{
struct mgmt_cp_start_discovery *cp = data;
struct mgmt_pending_cmd *cmd;
+ struct hci_request req;
u8 status;
int err;
@@ -4196,12 +4284,14 @@
goto failed;
}
- if (!discovery_type_is_valid(hdev, cp->type, &status)) {
- err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
- status, &cp->type, sizeof(cp->type));
+ cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
+ if (!cmd) {
+ err = -ENOMEM;
goto failed;
}
+ cmd->cmd_complete = generic_cmd_complete;
+
/* Clear the discovery filter first to free any previously
* allocated memory for the UUID list.
*/
@@ -4210,17 +4300,22 @@
hdev->discovery.type = cp->type;
hdev->discovery.report_invalid_rssi = false;
- cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
+ hci_req_init(&req, hdev);
+
+ if (!trigger_discovery(&req, &status)) {
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
+ status, &cp->type, sizeof(cp->type));
+ mgmt_pending_remove(cmd);
goto failed;
}
- cmd->cmd_complete = generic_cmd_complete;
+ err = hci_req_run(&req, start_discovery_complete);
+ if (err < 0) {
+ mgmt_pending_remove(cmd);
+ goto failed;
+ }
hci_discovery_set_state(hdev, DISCOVERY_STARTING);
- queue_work(hdev->req_workqueue, &hdev->discov_update);
- err = 0;
failed:
hci_dev_unlock(hdev);
@@ -4239,6 +4334,7 @@
{
struct mgmt_cp_start_service_discovery *cp = data;
struct mgmt_pending_cmd *cmd;
+ struct hci_request req;
const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
u16 uuid_count, expected_len;
u8 status;
@@ -4287,13 +4383,6 @@
goto failed;
}
- if (!discovery_type_is_valid(hdev, cp->type, &status)) {
- err = mgmt_cmd_complete(sk, hdev->id,
- MGMT_OP_START_SERVICE_DISCOVERY,
- status, &cp->type, sizeof(cp->type));
- goto failed;
- }
-
cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
hdev, data, len);
if (!cmd) {
@@ -4326,16 +4415,30 @@
}
}
+ hci_req_init(&req, hdev);
+
+ if (!trigger_discovery(&req, &status)) {
+ err = mgmt_cmd_complete(sk, hdev->id,
+ MGMT_OP_START_SERVICE_DISCOVERY,
+ status, &cp->type, sizeof(cp->type));
+ mgmt_pending_remove(cmd);
+ goto failed;
+ }
+
+ err = hci_req_run(&req, start_discovery_complete);
+ if (err < 0) {
+ mgmt_pending_remove(cmd);
+ goto failed;
+ }
+
hci_discovery_set_state(hdev, DISCOVERY_STARTING);
- queue_work(hdev->req_workqueue, &hdev->discov_update);
- err = 0;
failed:
hci_dev_unlock(hdev);
return err;
}
-void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
+static void stop_discovery_complete(struct hci_dev *hdev, u8 status, u16 opcode)
{
struct mgmt_pending_cmd *cmd;
@@ -4349,6 +4452,9 @@
mgmt_pending_remove(cmd);
}
+ if (!status)
+ hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+
hci_dev_unlock(hdev);
}
@@ -4357,6 +4463,7 @@
{
struct mgmt_cp_stop_discovery *mgmt_cp = data;
struct mgmt_pending_cmd *cmd;
+ struct hci_request req;
int err;
BT_DBG("%s", hdev->name);
@@ -4385,9 +4492,24 @@
cmd->cmd_complete = generic_cmd_complete;
- hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
- queue_work(hdev->req_workqueue, &hdev->discov_update);
- err = 0;
+ hci_req_init(&req, hdev);
+
+ hci_stop_discovery(&req);
+
+ err = hci_req_run(&req, stop_discovery_complete);
+ if (!err) {
+ hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
+ goto unlock;
+ }
+
+ mgmt_pending_remove(cmd);
+
+ /* If no HCI commands were sent we're done */
+ if (err == -ENODATA) {
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
+ &mgmt_cp->type, sizeof(mgmt_cp->type));
+ hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+ }
unlock:
hci_dev_unlock(hdev);
@@ -4554,9 +4676,6 @@
{
struct cmd_lookup match = { NULL, hdev };
struct hci_request req;
- u8 instance;
- struct adv_info *adv_instance;
- int err;
hci_dev_lock(hdev);
@@ -4582,31 +4701,18 @@
sock_put(match.sk);
/* If "Set Advertising" was just disabled and instance advertising was
- * set up earlier, then re-enable multi-instance advertising.
+ * set up earlier, then enable the advertising instance.
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
- list_empty(&hdev->adv_instances))
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
goto unlock;
- instance = hdev->cur_adv_instance;
- if (!instance) {
- adv_instance = list_first_entry_or_null(&hdev->adv_instances,
- struct adv_info, list);
- if (!adv_instance)
- goto unlock;
-
- instance = adv_instance->instance;
- }
-
hci_req_init(&req, hdev);
- err = schedule_adv_instance(&req, instance, true);
+ update_adv_data(&req);
+ enable_advertising(&req);
- if (!err)
- err = hci_req_run(&req, enable_advertising_instance);
-
- if (err)
+ if (hci_req_run(&req, enable_advertising_instance) < 0)
BT_ERR("Failed to re-configure advertising");
unlock:
@@ -4691,15 +4797,10 @@
else
hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
- cancel_adv_timeout(hdev);
-
if (val) {
- /* Switch to instance "0" for the Set Advertising setting.
- * We cannot use update_[adv|scan_rsp]_data() here as the
- * HCI_ADVERTISING flag is not yet set.
- */
- update_inst_adv_data(&req, 0x00);
- update_inst_scan_rsp_data(&req, 0x00);
+ /* Switch to instance "0" for the Set Advertising setting. */
+ update_adv_data_for_instance(&req, 0);
+ update_scan_rsp_data_for_instance(&req, 0);
enable_advertising(&req);
} else {
disable_advertising(&req);
@@ -5351,9 +5452,14 @@
for (i = 0; i < irk_count; i++) {
struct mgmt_irk_info *irk = &cp->irks[i];
+ u8 addr_type;
- hci_add_irk(hdev, &irk->addr.bdaddr,
- le_addr_type(irk->addr.type), irk->val,
+ if (irk->addr.type == BDADDR_LE_PUBLIC)
+ addr_type = ADDR_LE_DEV_PUBLIC;
+ else
+ addr_type = ADDR_LE_DEV_RANDOM;
+
+ hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
BDADDR_ANY);
}
@@ -5433,7 +5539,12 @@
for (i = 0; i < key_count; i++) {
struct mgmt_ltk_info *key = &cp->keys[i];
- u8 type, authenticated;
+ u8 type, addr_type, authenticated;
+
+ if (key->addr.type == BDADDR_LE_PUBLIC)
+ addr_type = ADDR_LE_DEV_PUBLIC;
+ else
+ addr_type = ADDR_LE_DEV_RANDOM;
switch (key->type) {
case MGMT_LTK_UNAUTHENTICATED:
@@ -5459,9 +5570,9 @@
continue;
}
- hci_add_ltk(hdev, &key->addr.bdaddr,
- le_addr_type(key->addr.type), type, authenticated,
- key->val, key->enc_size, key->ediv, key->rand);
+ hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
+ authenticated, key->val, key->enc_size, key->ediv,
+ key->rand);
}
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
@@ -5840,9 +5951,10 @@
}
/* This function requires the caller holds hdev->lock */
-static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
+static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr,
u8 addr_type, u8 auto_connect)
{
+ struct hci_dev *hdev = req->hdev;
struct hci_conn_params *params;
params = hci_conn_params_add(hdev, addr, addr_type);
@@ -5862,17 +5974,26 @@
*/
if (params->explicit_connect)
list_add(¶ms->action, &hdev->pend_le_conns);
+
+ __hci_update_background_scan(req);
break;
case HCI_AUTO_CONN_REPORT:
if (params->explicit_connect)
list_add(¶ms->action, &hdev->pend_le_conns);
else
list_add(¶ms->action, &hdev->pend_le_reports);
+ __hci_update_background_scan(req);
break;
case HCI_AUTO_CONN_DIRECT:
case HCI_AUTO_CONN_ALWAYS:
- if (!is_connected(hdev, addr, addr_type))
+ if (!is_connected(hdev, addr, addr_type)) {
list_add(¶ms->action, &hdev->pend_le_conns);
+ /* If we are in scan phase of connecting, we were
+ * already added to pend_le_conns and scanning.
+ */
+ if (params->auto_connect != HCI_AUTO_CONN_EXPLICIT)
+ __hci_update_background_scan(req);
+ }
break;
}
@@ -5896,10 +6017,31 @@
mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
}
+static void add_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+{
+ struct mgmt_pending_cmd *cmd;
+
+ BT_DBG("status 0x%02x", status);
+
+ hci_dev_lock(hdev);
+
+ cmd = pending_find(MGMT_OP_ADD_DEVICE, hdev);
+ if (!cmd)
+ goto unlock;
+
+ cmd->cmd_complete(cmd, mgmt_status(status));
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
static int add_device(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
struct mgmt_cp_add_device *cp = data;
+ struct mgmt_pending_cmd *cmd;
+ struct hci_request req;
u8 auto_conn, addr_type;
int err;
@@ -5916,15 +6058,24 @@
MGMT_STATUS_INVALID_PARAMS,
&cp->addr, sizeof(cp->addr));
+ hci_req_init(&req, hdev);
+
hci_dev_lock(hdev);
+ cmd = mgmt_pending_add(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto unlock;
+ }
+
+ cmd->cmd_complete = addr_cmd_complete;
+
if (cp->addr.type == BDADDR_BREDR) {
/* Only incoming connections action is supported for now */
if (cp->action != 0x01) {
- err = mgmt_cmd_complete(sk, hdev->id,
- MGMT_OP_ADD_DEVICE,
- MGMT_STATUS_INVALID_PARAMS,
- &cp->addr, sizeof(cp->addr));
+ err = cmd->cmd_complete(cmd,
+ MGMT_STATUS_INVALID_PARAMS);
+ mgmt_pending_remove(cmd);
goto unlock;
}
@@ -5933,12 +6084,15 @@
if (err)
goto unlock;
- hci_update_page_scan(hdev);
+ __hci_update_page_scan(&req);
goto added;
}
- addr_type = le_addr_type(cp->addr.type);
+ if (cp->addr.type == BDADDR_LE_PUBLIC)
+ addr_type = ADDR_LE_DEV_PUBLIC;
+ else
+ addr_type = ADDR_LE_DEV_RANDOM;
if (cp->action == 0x02)
auto_conn = HCI_AUTO_CONN_ALWAYS;
@@ -5953,31 +6107,33 @@
* hci_conn_params_lookup.
*/
if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
- err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
- MGMT_STATUS_INVALID_PARAMS,
- &cp->addr, sizeof(cp->addr));
+ err = cmd->cmd_complete(cmd, MGMT_STATUS_INVALID_PARAMS);
+ mgmt_pending_remove(cmd);
goto unlock;
}
/* If the connection parameters don't exist for this device,
* they will be created and configured with defaults.
*/
- if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
+ if (hci_conn_params_set(&req, &cp->addr.bdaddr, addr_type,
auto_conn) < 0) {
- err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
- MGMT_STATUS_FAILED, &cp->addr,
- sizeof(cp->addr));
+ err = cmd->cmd_complete(cmd, MGMT_STATUS_FAILED);
+ mgmt_pending_remove(cmd);
goto unlock;
}
- hci_update_background_scan(hdev);
-
added:
device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
- err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
- MGMT_STATUS_SUCCESS, &cp->addr,
- sizeof(cp->addr));
+ err = hci_req_run(&req, add_device_complete);
+ if (err < 0) {
+ /* ENODATA means no HCI commands were needed (e.g. if
+ * the adapter is powered off).
+ */
+ if (err == -ENODATA)
+ err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
+ mgmt_pending_remove(cmd);
+ }
unlock:
hci_dev_unlock(hdev);
@@ -5995,25 +6151,55 @@
mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
}
+static void remove_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+{
+ struct mgmt_pending_cmd *cmd;
+
+ BT_DBG("status 0x%02x", status);
+
+ hci_dev_lock(hdev);
+
+ cmd = pending_find(MGMT_OP_REMOVE_DEVICE, hdev);
+ if (!cmd)
+ goto unlock;
+
+ cmd->cmd_complete(cmd, mgmt_status(status));
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
static int remove_device(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
struct mgmt_cp_remove_device *cp = data;
+ struct mgmt_pending_cmd *cmd;
+ struct hci_request req;
int err;
BT_DBG("%s", hdev->name);
+ hci_req_init(&req, hdev);
+
hci_dev_lock(hdev);
+ cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_DEVICE, hdev, data, len);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto unlock;
+ }
+
+ cmd->cmd_complete = addr_cmd_complete;
+
if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
struct hci_conn_params *params;
u8 addr_type;
if (!bdaddr_type_is_valid(cp->addr.type)) {
- err = mgmt_cmd_complete(sk, hdev->id,
- MGMT_OP_REMOVE_DEVICE,
- MGMT_STATUS_INVALID_PARAMS,
- &cp->addr, sizeof(cp->addr));
+ err = cmd->cmd_complete(cmd,
+ MGMT_STATUS_INVALID_PARAMS);
+ mgmt_pending_remove(cmd);
goto unlock;
}
@@ -6022,22 +6208,23 @@
&cp->addr.bdaddr,
cp->addr.type);
if (err) {
- err = mgmt_cmd_complete(sk, hdev->id,
- MGMT_OP_REMOVE_DEVICE,
- MGMT_STATUS_INVALID_PARAMS,
- &cp->addr,
- sizeof(cp->addr));
+ err = cmd->cmd_complete(cmd,
+ MGMT_STATUS_INVALID_PARAMS);
+ mgmt_pending_remove(cmd);
goto unlock;
}
- hci_update_page_scan(hdev);
+ __hci_update_page_scan(&req);
device_removed(sk, hdev, &cp->addr.bdaddr,
cp->addr.type);
goto complete;
}
- addr_type = le_addr_type(cp->addr.type);
+ if (cp->addr.type == BDADDR_LE_PUBLIC)
+ addr_type = ADDR_LE_DEV_PUBLIC;
+ else
+ addr_type = ADDR_LE_DEV_RANDOM;
/* Kernel internally uses conn_params with resolvable private
* address, but Remove Device allows only identity addresses.
@@ -6045,36 +6232,33 @@
* hci_conn_params_lookup.
*/
if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
- err = mgmt_cmd_complete(sk, hdev->id,
- MGMT_OP_REMOVE_DEVICE,
- MGMT_STATUS_INVALID_PARAMS,
- &cp->addr, sizeof(cp->addr));
+ err = cmd->cmd_complete(cmd,
+ MGMT_STATUS_INVALID_PARAMS);
+ mgmt_pending_remove(cmd);
goto unlock;
}
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
addr_type);
if (!params) {
- err = mgmt_cmd_complete(sk, hdev->id,
- MGMT_OP_REMOVE_DEVICE,
- MGMT_STATUS_INVALID_PARAMS,
- &cp->addr, sizeof(cp->addr));
+ err = cmd->cmd_complete(cmd,
+ MGMT_STATUS_INVALID_PARAMS);
+ mgmt_pending_remove(cmd);
goto unlock;
}
if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
- err = mgmt_cmd_complete(sk, hdev->id,
- MGMT_OP_REMOVE_DEVICE,
- MGMT_STATUS_INVALID_PARAMS,
- &cp->addr, sizeof(cp->addr));
+ err = cmd->cmd_complete(cmd,
+ MGMT_STATUS_INVALID_PARAMS);
+ mgmt_pending_remove(cmd);
goto unlock;
}
list_del(¶ms->action);
list_del(¶ms->list);
kfree(params);
- hci_update_background_scan(hdev);
+ __hci_update_background_scan(&req);
device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
} else {
@@ -6082,10 +6266,9 @@
struct bdaddr_list *b, *btmp;
if (cp->addr.type) {
- err = mgmt_cmd_complete(sk, hdev->id,
- MGMT_OP_REMOVE_DEVICE,
- MGMT_STATUS_INVALID_PARAMS,
- &cp->addr, sizeof(cp->addr));
+ err = cmd->cmd_complete(cmd,
+ MGMT_STATUS_INVALID_PARAMS);
+ mgmt_pending_remove(cmd);
goto unlock;
}
@@ -6095,7 +6278,7 @@
kfree(b);
}
- hci_update_page_scan(hdev);
+ __hci_update_page_scan(&req);
list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
@@ -6112,13 +6295,20 @@
BT_DBG("All LE connection parameters were removed");
- hci_update_background_scan(hdev);
+ __hci_update_background_scan(&req);
}
complete:
- err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
- MGMT_STATUS_SUCCESS, &cp->addr,
- sizeof(cp->addr));
+ err = hci_req_run(&req, remove_device_complete);
+ if (err < 0) {
+ /* ENODATA means no HCI commands were needed (e.g. if
+ * the adapter is powered off).
+ */
+ if (err == -ENODATA)
+ err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
+ mgmt_pending_remove(cmd);
+ }
+
unlock:
hci_dev_unlock(hdev);
return err;
@@ -6644,9 +6834,8 @@
{
struct mgmt_rp_read_adv_features *rp;
size_t rp_len;
- int err, i;
+ int err;
bool instance;
- struct adv_info *adv_instance;
u32 supported_flags;
BT_DBG("%s", hdev->name);
@@ -6659,9 +6848,12 @@
rp_len = sizeof(*rp);
+ /* Currently only one instance is supported, so just add 1 to the
+ * response length.
+ */
instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
if (instance)
- rp_len += hdev->adv_instance_cnt;
+ rp_len++;
rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
@@ -6674,18 +6866,14 @@
rp->supported_flags = cpu_to_le32(supported_flags);
rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
- rp->max_instances = HCI_MAX_ADV_INSTANCES;
+ rp->max_instances = 1;
+ /* Currently only one instance is supported, so simply return the
+ * current instance number.
+ */
if (instance) {
- i = 0;
- list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
- if (i >= hdev->adv_instance_cnt)
- break;
-
- rp->instance[i] = adv_instance->instance;
- i++;
- }
- rp->num_instances = hdev->adv_instance_cnt;
+ rp->num_instances = 1;
+ rp->instance[0] = 1;
} else {
rp->num_instances = 0;
}
@@ -6747,10 +6935,7 @@
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
- struct mgmt_cp_add_advertising *cp;
struct mgmt_rp_add_advertising rp;
- struct adv_info *adv_instance, *n;
- u8 instance;
BT_DBG("status %d", status);
@@ -6758,32 +6943,16 @@
cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
- if (status)
+ if (status) {
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
-
- list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
- if (!adv_instance->pending)
- continue;
-
- if (!status) {
- adv_instance->pending = false;
- continue;
- }
-
- instance = adv_instance->instance;
-
- if (hdev->cur_adv_instance == instance)
- cancel_adv_timeout(hdev);
-
- hci_remove_adv_instance(hdev, instance);
- advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
+ memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
+ advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
}
if (!cmd)
goto unlock;
- cp = cmd->param;
- rp.instance = cp->instance;
+ rp.instance = 0x01;
if (status)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
@@ -6798,28 +6967,15 @@
hci_dev_unlock(hdev);
}
-void mgmt_adv_timeout_expired(struct hci_dev *hdev)
+static void adv_timeout_expired(struct work_struct *work)
{
- u8 instance;
- struct hci_request req;
+ struct hci_dev *hdev = container_of(work, struct hci_dev,
+ adv_instance.timeout_exp.work);
- hdev->adv_instance_timeout = 0;
-
- instance = get_current_adv_instance(hdev);
- if (instance == 0x00)
- return;
+ hdev->adv_instance.timeout = 0;
hci_dev_lock(hdev);
- hci_req_init(&req, hdev);
-
- clear_adv_instance(hdev, &req, instance, false);
-
- if (list_empty(&hdev->adv_instances))
- disable_advertising(&req);
-
- if (!skb_queue_empty(&req.cmd_q))
- hci_req_run(&req, NULL);
-
+ clear_adv_instance(hdev);
hci_dev_unlock(hdev);
}
@@ -6831,10 +6987,7 @@
u32 flags;
u32 supported_flags;
u8 status;
- u16 timeout, duration;
- unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
- u8 schedule_instance = 0;
- struct adv_info *next_instance;
+ u16 timeout;
int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;
@@ -6848,13 +7001,12 @@
flags = __le32_to_cpu(cp->flags);
timeout = __le16_to_cpu(cp->timeout);
- duration = __le16_to_cpu(cp->duration);
- /* The current implementation only supports a subset of the specified
- * flags.
+ /* The current implementation only supports adding one instance and only
+ * a subset of the specified flags.
*/
supported_flags = get_supported_adv_flags(hdev);
- if (flags & ~supported_flags)
+ if (cp->instance != 0x01 || (flags & ~supported_flags))
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_INVALID_PARAMS);
@@ -6882,51 +7034,38 @@
goto unlock;
}
- err = hci_add_adv_instance(hdev, cp->instance, flags,
- cp->adv_data_len, cp->data,
- cp->scan_rsp_len,
- cp->data + cp->adv_data_len,
- timeout, duration);
- if (err < 0) {
- err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
- MGMT_STATUS_FAILED);
- goto unlock;
- }
+ INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
- /* Only trigger an advertising added event if a new instance was
- * actually added.
- */
- if (hdev->adv_instance_cnt > prev_instance_cnt)
- advertising_added(sk, hdev, cp->instance);
+ hdev->adv_instance.flags = flags;
+ hdev->adv_instance.adv_data_len = cp->adv_data_len;
+ hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
- hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);
+ if (cp->adv_data_len)
+ memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
- if (hdev->cur_adv_instance == cp->instance) {
- /* If the currently advertised instance is being changed then
- * cancel the current advertising and schedule the next
- * instance. If there is only one instance then the overridden
- * advertising data will be visible right away.
- */
- cancel_adv_timeout(hdev);
+ if (cp->scan_rsp_len)
+ memcpy(hdev->adv_instance.scan_rsp_data,
+ cp->data + cp->adv_data_len, cp->scan_rsp_len);
- next_instance = hci_get_next_instance(hdev, cp->instance);
- if (next_instance)
- schedule_instance = next_instance->instance;
- } else if (!hdev->adv_instance_timeout) {
- /* Immediately advertise the new instance if no other
- * instance is currently being advertised.
- */
- schedule_instance = cp->instance;
- }
+ if (hdev->adv_instance.timeout)
+ cancel_delayed_work(&hdev->adv_instance.timeout_exp);
- /* If the HCI_ADVERTISING flag is set or the device isn't powered or
- * there is no instance to be advertised then we have no HCI
- * communication to make. Simply return.
+ hdev->adv_instance.timeout = timeout;
+
+ if (timeout)
+ queue_delayed_work(hdev->workqueue,
+ &hdev->adv_instance.timeout_exp,
+ msecs_to_jiffies(timeout * 1000));
+
+ if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ advertising_added(sk, hdev, 1);
+
+ /* If the HCI_ADVERTISING flag is set or the device isn't powered then
+ * we have no HCI communication to make. Simply return.
*/
if (!hdev_is_powered(hdev) ||
- hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- !schedule_instance) {
- rp.instance = cp->instance;
+ hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
+ rp.instance = 0x01;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
goto unlock;
@@ -6944,11 +7083,11 @@
hci_req_init(&req, hdev);
- err = schedule_adv_instance(&req, schedule_instance, true);
+ update_adv_data(&req);
+ update_scan_rsp_data(&req);
+ enable_advertising(&req);
- if (!err)
- err = hci_req_run(&req, add_advertising_complete);
-
+ err = hci_req_run(&req, add_advertising_complete);
if (err < 0)
mgmt_pending_remove(cmd);
@@ -6962,7 +7101,6 @@
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
- struct mgmt_cp_remove_advertising *cp;
struct mgmt_rp_remove_advertising rp;
BT_DBG("status %d", status);
@@ -6977,8 +7115,7 @@
if (!cmd)
goto unlock;
- cp = cmd->param;
- rp.instance = cp->instance;
+ rp.instance = 1;
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
&rp, sizeof(rp));
@@ -6993,20 +7130,20 @@
{
struct mgmt_cp_remove_advertising *cp = data;
struct mgmt_rp_remove_advertising rp;
+ int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;
- int err;
BT_DBG("%s", hdev->name);
- hci_dev_lock(hdev);
+ /* The current implementation only allows modifying instance no 1. A
+ * value of 0 indicates that all instances should be cleared.
+ */
+ if (cp->instance > 1)
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
+ MGMT_STATUS_INVALID_PARAMS);
- if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
- err = mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_REMOVE_ADVERTISING,
- MGMT_STATUS_INVALID_PARAMS);
- goto unlock;
- }
+ hci_dev_lock(hdev);
if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
@@ -7022,21 +7159,21 @@
goto unlock;
}
- hci_req_init(&req, hdev);
+ if (hdev->adv_instance.timeout)
+ cancel_delayed_work(&hdev->adv_instance.timeout_exp);
- clear_adv_instance(hdev, &req, cp->instance, true);
+ memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- if (list_empty(&hdev->adv_instances))
- disable_advertising(&req);
+ advertising_removed(sk, hdev, 1);
- /* If no HCI commands have been collected so far or the HCI_ADVERTISING
- * flag is set or the device isn't powered then we have no HCI
- * communication to make. Simply return.
+ hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
+
+ /* If the HCI_ADVERTISING flag is set or the device isn't powered then
+ * we have no HCI communication to make. Simply return.
*/
- if (skb_queue_empty(&req.cmd_q) ||
- !hdev_is_powered(hdev) ||
+ if (!hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = cp->instance;
+ rp.instance = 1;
err = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_REMOVE_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
@@ -7050,6 +7187,9 @@
goto unlock;
}
+ hci_req_init(&req, hdev);
+ disable_advertising(&req);
+
err = hci_req_run(&req, remove_advertising_complete);
if (err < 0)
mgmt_pending_remove(cmd);
@@ -7217,8 +7357,9 @@
}
/* This function requires the caller holds hdev->lock */
-static void restart_le_actions(struct hci_dev *hdev)
+static void restart_le_actions(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
struct hci_conn_params *p;
list_for_each_entry(p, &hdev->le_conn_params, list) {
@@ -7239,6 +7380,8 @@
break;
}
}
+
+ __hci_update_background_scan(req);
}
static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
@@ -7254,9 +7397,6 @@
* decide if the public address or static address is used.
*/
smp_register(hdev);
-
- restart_le_actions(hdev);
- hci_update_background_scan(hdev);
}
hci_dev_lock(hdev);
@@ -7274,7 +7414,6 @@
static int powered_update_hci(struct hci_dev *hdev)
{
struct hci_request req;
- struct adv_info *adv_instance;
u8 link_sec;
hci_req_init(&req, hdev);
@@ -7314,27 +7453,16 @@
* advertising data. This also applies to the case
* where BR/EDR was toggled during the AUTO_OFF phase.
*/
- if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
- (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))) {
+ if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
update_adv_data(&req);
update_scan_rsp_data(&req);
}
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- hdev->cur_adv_instance == 0x00 &&
- !list_empty(&hdev->adv_instances)) {
- adv_instance = list_first_entry(&hdev->adv_instances,
- struct adv_info, list);
- hdev->cur_adv_instance = adv_instance->instance;
- }
-
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+ hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
enable_advertising(&req);
- else if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- hdev->cur_adv_instance)
- schedule_adv_instance(&req, hdev->cur_adv_instance,
- true);
+
+ restart_le_actions(&req);
}
link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
@@ -7502,7 +7630,7 @@
memset(&ev, 0, sizeof(ev));
/* Devices using resolvable or non-resolvable random addresses
- * without providing an identity resolving key don't require
+ * without providing an indentity resolving key don't require
* to store long term keys. Their addresses will change the
* next time around.
*
@@ -7528,23 +7656,32 @@
if (key->type == SMP_LTK)
ev.key.master = 1;
- /* Make sure we copy only the significant bytes based on the
- * encryption key size, and set the rest of the value to zeroes.
- */
- memcpy(ev.key.val, key->val, key->enc_size);
- memset(ev.key.val + key->enc_size, 0,
- sizeof(ev.key.val) - key->enc_size);
+ memcpy(ev.key.val, key->val, sizeof(key->val));
mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
}
-void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
+void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
{
struct mgmt_ev_new_irk ev;
memset(&ev, 0, sizeof(ev));
- ev.store_hint = persistent;
+ /* For identity resolving keys from devices that are already
+ * using a public address or static random address, do not
+ * ask for storing this key. The identity resolving key really
+ * is only mandatory for devices using resovlable random
+ * addresses.
+ *
+ * Storing all identity resolving keys has the downside that
+ * they will be also loaded on next boot of they system. More
+ * identity resolving keys, means more time during scanning is
+ * needed to actually resolve these addresses.
+ */
+ if (bacmp(&irk->rpa, BDADDR_ANY))
+ ev.store_hint = 0x01;
+ else
+ ev.store_hint = 0x00;
bacpy(&ev.rpa, &irk->rpa);
bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
@@ -7562,7 +7699,7 @@
memset(&ev, 0, sizeof(ev));
/* Devices using resolvable or non-resolvable random addresses
- * without providing an identity resolving key don't require
+ * without providing an indentity resolving key don't require
* to store signature resolving keys. Their addresses will change
* the next time around.
*
@@ -8141,7 +8278,7 @@
hdev->discovery.scan_duration))
return;
- queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
+ queue_delayed_work(hdev->workqueue, &hdev->le_scan_restart,
DISCOV_LE_RESTART_DELAY);
}
@@ -8303,24 +8440,13 @@
void mgmt_reenable_advertising(struct hci_dev *hdev)
{
struct hci_request req;
- u8 instance;
if (!hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
return;
- instance = get_current_adv_instance(hdev);
-
hci_req_init(&req, hdev);
-
- if (instance) {
- schedule_adv_instance(&req, instance, true);
- } else {
- update_adv_data(&req);
- update_scan_rsp_data(&req);
- enable_advertising(&req);
- }
-
+ enable_advertising(&req);
hci_req_run(&req, adv_enable_complete);
}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 17150af..45f1e13 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -334,19 +334,16 @@
static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
{
- struct sockaddr_rc sa;
+ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
struct sock *sk = sock->sk;
- int len, err = 0;
+ int chan = sa->rc_channel;
+ int err = 0;
+
+ BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr);
if (!addr || addr->sa_family != AF_BLUETOOTH)
return -EINVAL;
- memset(&sa, 0, sizeof(sa));
- len = min_t(unsigned int, sizeof(sa), addr_len);
- memcpy(&sa, addr, len);
-
- BT_DBG("sk %p %pMR", sk, &sa.rc_bdaddr);
-
lock_sock(sk);
if (sk->sk_state != BT_OPEN) {
@@ -361,13 +358,12 @@
write_lock(&rfcomm_sk_list.lock);
- if (sa.rc_channel &&
- __rfcomm_get_listen_sock_by_addr(sa.rc_channel, &sa.rc_bdaddr)) {
+ if (chan && __rfcomm_get_listen_sock_by_addr(chan, &sa->rc_bdaddr)) {
err = -EADDRINUSE;
} else {
/* Save source address */
- bacpy(&rfcomm_pi(sk)->src, &sa.rc_bdaddr);
- rfcomm_pi(sk)->channel = sa.rc_channel;
+ bacpy(&rfcomm_pi(sk)->src, &sa->rc_bdaddr);
+ rfcomm_pi(sk)->channel = chan;
sk->sk_state = BT_BOUND;
}
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 45f6c28..4dd5c4d 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -74,7 +74,7 @@
static void sco_sock_timeout(unsigned long arg)
{
- struct sock *sk = (struct sock *)arg;
+ struct sock *sk = (struct sock *) arg;
BT_DBG("sock %p state %d", sk, sk->sk_state);
@@ -154,13 +154,13 @@
sock_set_flag(sk, SOCK_ZAPPED);
}
-static void sco_conn_del(struct hci_conn *hcon, int err)
+static int sco_conn_del(struct hci_conn *hcon, int err)
{
struct sco_conn *conn = hcon->sco_data;
struct sock *sk;
if (!conn)
- return;
+ return 0;
BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
@@ -170,21 +170,19 @@
sco_conn_unlock(conn);
if (sk) {
- sock_hold(sk);
bh_lock_sock(sk);
sco_sock_clear_timer(sk);
sco_chan_del(sk, err);
bh_unlock_sock(sk);
sco_sock_kill(sk);
- sock_put(sk);
}
hcon->sco_data = NULL;
kfree(conn);
+ return 0;
}
-static void __sco_chan_add(struct sco_conn *conn, struct sock *sk,
- struct sock *parent)
+static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
{
BT_DBG("conn %p", conn);
@@ -417,10 +415,8 @@
if (sco_pi(sk)->conn->hcon) {
sk->sk_state = BT_DISCONN;
sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
- sco_conn_lock(sco_pi(sk)->conn);
hci_conn_drop(sco_pi(sk)->conn->hcon);
sco_pi(sk)->conn->hcon = NULL;
- sco_conn_unlock(sco_pi(sk)->conn);
} else
sco_chan_del(sk, ECONNRESET);
break;
@@ -513,8 +509,7 @@
return 0;
}
-static int sco_sock_bind(struct socket *sock, struct sockaddr *addr,
- int addr_len)
+static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
{
struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
struct sock *sk = sock->sk;
@@ -621,8 +616,7 @@
return err;
}
-static int sco_sock_accept(struct socket *sock, struct socket *newsock,
- int flags)
+static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
{
DEFINE_WAIT_FUNC(wait, woken_wake_function);
struct sock *sk = sock->sk, *ch;
@@ -676,8 +670,7 @@
return err;
}
-static int sco_sock_getname(struct socket *sock, struct sockaddr *addr,
- int *len, int peer)
+static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
{
struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
struct sock *sk = sock->sk;
@@ -787,8 +780,7 @@
return bt_sock_recvmsg(iocb, sock, msg, len, flags);
}
-static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
- char __user *optval, unsigned int optlen)
+static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
int len, err = 0;
@@ -828,7 +820,7 @@
voice.setting = sco_pi(sk)->setting;
len = min_t(unsigned int, sizeof(voice), optlen);
- if (copy_from_user((char *)&voice, optval, len)) {
+ if (copy_from_user((char *) &voice, optval, len)) {
err = -EFAULT;
break;
}
@@ -852,8 +844,7 @@
return err;
}
-static int sco_sock_getsockopt_old(struct socket *sock, int optname,
- char __user *optval, int __user *optlen)
+static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
struct sco_options opts;
@@ -913,8 +904,7 @@
return err;
}
-static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
- char __user *optval, int __user *optlen)
+static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
int len, err = 0;
@@ -939,7 +929,7 @@
}
if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
- (u32 __user *)optval))
+ (u32 __user *) optval))
err = -EFAULT;
break;
@@ -972,9 +962,7 @@
if (!sk)
return 0;
- sock_hold(sk);
lock_sock(sk);
-
if (!sk->sk_shutdown) {
sk->sk_shutdown = SHUTDOWN_MASK;
sco_sock_clear_timer(sk);
@@ -985,10 +973,7 @@
err = bt_sock_wait_state(sk, BT_CLOSED,
sk->sk_lingertime);
}
-
release_sock(sk);
- sock_put(sk);
-
return err;
}
@@ -1032,11 +1017,6 @@
} else {
sco_conn_lock(conn);
- if (!conn->hcon) {
- sco_conn_unlock(conn);
- return;
- }
-
parent = sco_get_sock_listen(&conn->hcon->src);
if (!parent) {
sco_conn_unlock(conn);
@@ -1130,7 +1110,7 @@
sco_conn_del(hcon, bt_to_errno(reason));
}
-void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
+int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
{
struct sco_conn *conn = hcon->sco_data;
@@ -1141,11 +1121,12 @@
if (skb->len) {
sco_recv_frame(conn, skb);
- return;
+ return 0;
}
drop:
kfree_skb(skb);
+ return 0;
}
static struct hci_cb sco_cb = {
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 4661e1c..43b00e5 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -33,9 +33,6 @@
#include "ecc.h"
#include "smp.h"
-#define SMP_DEV(hdev) \
- ((struct smp_dev *)((struct l2cap_chan *)((hdev)->smp_data))->data)
-
/* Low-level debug macros to be used for stuff that we don't want
* accidentially in dmesg, i.e. the values of the various crypto keys
* and the inputs & outputs of crypto functions.
@@ -84,9 +81,6 @@
u8 local_rand[16];
bool debug_key;
- u8 min_key_size;
- u8 max_key_size;
-
struct crypto_blkcipher *tfm_aes;
struct crypto_hash *tfm_cmac;
};
@@ -377,8 +371,6 @@
uint8_t tmp[16], data[16];
int err;
- SMP_DBG("k %16phN r %16phN", k, r);
-
if (!tfm) {
BT_ERR("tfm %p", tfm);
return -EINVAL;
@@ -408,8 +400,6 @@
/* Most significant octet of encryptedData corresponds to data[0] */
swap_buf(data, r, 16);
- SMP_DBG("r %16phN", r);
-
return err;
}
@@ -420,10 +410,6 @@
u8 p1[16], p2[16];
int err;
- SMP_DBG("k %16phN r %16phN", k, r);
- SMP_DBG("iat %u ia %6phN rat %u ra %6phN", _iat, ia, _rat, ra);
- SMP_DBG("preq %7phN pres %7phN", preq, pres);
-
memset(p1, 0, 16);
/* p1 = pres || preq || _rat || _iat */
@@ -432,7 +418,10 @@
memcpy(p1 + 2, preq, 7);
memcpy(p1 + 9, pres, 7);
- SMP_DBG("p1 %16phN", p1);
+ /* p2 = padding || ia || ra */
+ memcpy(p2, ra, 6);
+ memcpy(p2 + 6, ia, 6);
+ memset(p2 + 12, 0, 4);
/* res = r XOR p1 */
u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
@@ -444,13 +433,6 @@
return err;
}
- /* p2 = padding || ia || ra */
- memcpy(p2, ra, 6);
- memcpy(p2 + 6, ia, 6);
- memset(p2 + 12, 0, 4);
-
- SMP_DBG("p2 %16phN", p2);
-
/* res = res XOR p2 */
u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
@@ -495,7 +477,7 @@
}
/* The output of the random address function ah is:
- * ah(k, r) = e(k, r') mod 2^24
+ * ah(h, r) = e(k, r') mod 2^24
* The output of the security function e is then truncated to 24 bits
* by taking the least significant 24 bits of the output of e as the
* result of ah.
@@ -715,7 +697,7 @@
if (rsp == NULL) {
req->io_capability = conn->hcon->io_capability;
req->oob_flag = oob_flag;
- req->max_key_size = SMP_DEV(hdev)->max_key_size;
+ req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
req->init_key_dist = local_dist;
req->resp_key_dist = remote_dist;
req->auth_req = (authreq & AUTH_REQ_MASK(hdev));
@@ -726,7 +708,7 @@
rsp->io_capability = conn->hcon->io_capability;
rsp->oob_flag = oob_flag;
- rsp->max_key_size = SMP_DEV(hdev)->max_key_size;
+ rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
rsp->init_key_dist = req->init_key_dist & remote_dist;
rsp->resp_key_dist = req->resp_key_dist & local_dist;
rsp->auth_req = (authreq & AUTH_REQ_MASK(hdev));
@@ -737,11 +719,10 @@
static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
{
struct l2cap_chan *chan = conn->smp;
- struct hci_dev *hdev = conn->hcon->hdev;
struct smp_chan *smp = chan->data;
- if (max_key_size > SMP_DEV(hdev)->max_key_size ||
- max_key_size < SMP_MIN_ENC_KEY_SIZE)
+ if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
+ (max_key_size < SMP_MIN_ENC_KEY_SIZE))
return SMP_ENC_KEY_SIZE;
smp->enc_key_size = max_key_size;
@@ -812,6 +793,7 @@
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
&reason);
+ clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags);
mgmt_auth_failed(hcon, HCI_ERROR_AUTH_FAILURE);
if (chan->data)
@@ -1004,10 +986,13 @@
smp_s1(smp->tfm_aes, smp->tk, smp->rrnd, smp->prnd, stk);
+ memset(stk + smp->enc_key_size, 0,
+ SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
+
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
return SMP_UNSPECIFIED;
- hci_le_start_enc(hcon, ediv, rand, stk, smp->enc_key_size);
+ hci_le_start_enc(hcon, ediv, rand, stk);
hcon->enc_key_size = smp->enc_key_size;
set_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags);
} else {
@@ -1020,6 +1005,9 @@
smp_s1(smp->tfm_aes, smp->tk, smp->prnd, smp->rrnd, stk);
+ memset(stk + smp->enc_key_size, 0,
+ SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
+
if (hcon->pending_sec_level == BT_SECURITY_HIGH)
auth = 1;
else
@@ -1046,24 +1034,8 @@
struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1];
bool persistent;
- if (hcon->type == ACL_LINK) {
- if (hcon->key_type == HCI_LK_DEBUG_COMBINATION)
- persistent = false;
- else
- persistent = !test_bit(HCI_CONN_FLUSH_KEY,
- &hcon->flags);
- } else {
- /* The LTKs, IRKs and CSRKs should be persistent only if
- * both sides had the bonding bit set in their
- * authentication requests.
- */
- persistent = !!((req->auth_req & rsp->auth_req) &
- SMP_AUTH_BONDING);
- }
-
if (smp->remote_irk) {
- mgmt_new_irk(hdev, smp->remote_irk, persistent);
-
+ mgmt_new_irk(hdev, smp->remote_irk);
/* Now that user space can be considered to know the
* identity address track the connection based on it
* from now on (assuming this is an LE link).
@@ -1091,6 +1063,21 @@
}
}
+ if (hcon->type == ACL_LINK) {
+ if (hcon->key_type == HCI_LK_DEBUG_COMBINATION)
+ persistent = false;
+ else
+ persistent = !test_bit(HCI_CONN_FLUSH_KEY,
+ &hcon->flags);
+ } else {
+ /* The LTKs and CSRKs should be persistent only if both sides
+ * had the bonding bit set in their authentication requests.
+ */
+ persistent = !!((req->auth_req & rsp->auth_req) &
+ SMP_AUTH_BONDING);
+ }
+
+
if (smp->csrk) {
smp->csrk->bdaddr_type = hcon->dst_type;
bacpy(&smp->csrk->bdaddr, &hcon->dst);
@@ -1158,6 +1145,9 @@
else
auth = 0;
+ memset(smp->tk + smp->enc_key_size, 0,
+ SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
+
smp->ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
key_type, auth, smp->tk, smp->enc_key_size,
0, 0);
@@ -1279,14 +1269,7 @@
__le16 ediv;
__le64 rand;
- /* Make sure we generate only the significant amount of
- * bytes based on the encryption key size, and set the rest
- * of the value to zeroes.
- */
- get_random_bytes(enc.ltk, smp->enc_key_size);
- memset(enc.ltk + smp->enc_key_size, 0,
- sizeof(enc.ltk) - smp->enc_key_size);
-
+ get_random_bytes(enc.ltk, sizeof(enc.ltk));
get_random_bytes(&ediv, sizeof(ediv));
get_random_bytes(&rand, sizeof(rand));
@@ -1706,7 +1689,7 @@
req->init_key_dist = local_dist;
req->resp_key_dist = remote_dist;
- req->max_key_size = conn->hcon->enc_key_size;
+ req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
smp->remote_key_dist = remote_dist;
@@ -1715,7 +1698,7 @@
memset(rsp, 0, sizeof(*rsp));
- rsp->max_key_size = conn->hcon->enc_key_size;
+ rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
rsp->init_key_dist = req->init_key_dist & remote_dist;
rsp->resp_key_dist = req->resp_key_dist & local_dist;
@@ -2208,7 +2191,7 @@
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
return true;
- hci_le_start_enc(hcon, key->ediv, key->rand, key->val, key->enc_size);
+ hci_le_start_enc(hcon, key->ediv, key->rand, key->val);
hcon->enc_key_size = key->enc_size;
/* We never store STKs for master role, so clear this flag */
@@ -2312,6 +2295,8 @@
if (!conn)
return 1;
+ chan = conn->smp;
+
if (!hci_dev_test_flag(hcon->hdev, HCI_LE_ENABLED))
return 1;
@@ -2325,12 +2310,6 @@
if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
return 0;
- chan = conn->smp;
- if (!chan) {
- BT_ERR("SMP security requested but not available");
- return 1;
- }
-
l2cap_chan_lock(chan);
/* If SMP is already in progress ignore this request */
@@ -2381,32 +2360,6 @@
return ret;
}
-void smp_cancel_pairing(struct hci_conn *hcon)
-{
- struct l2cap_conn *conn = hcon->l2cap_data;
- struct l2cap_chan *chan;
- struct smp_chan *smp;
-
- if (!conn)
- return;
-
- chan = conn->smp;
- if (!chan)
- return;
-
- l2cap_chan_lock(chan);
-
- smp = chan->data;
- if (smp) {
- if (test_bit(SMP_FLAG_COMPLETE, &smp->flags))
- smp_failure(conn, 0);
- else
- smp_failure(conn, SMP_UNSPECIFIED);
- }
-
- l2cap_chan_unlock(chan);
-}
-
static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_encrypt_info *rp = (void *) skb->data;
@@ -2786,7 +2739,7 @@
sc_add_ltk(smp);
if (hcon->out) {
- hci_le_start_enc(hcon, 0, 0, smp->tk, smp->enc_key_size);
+ hci_le_start_enc(hcon, 0, 0, smp->tk);
hcon->enc_key_size = smp->enc_key_size;
}
@@ -3134,7 +3087,7 @@
.resume = l2cap_chan_no_resume,
.set_shutdown = l2cap_chan_no_set_shutdown,
.get_sndtimeo = l2cap_chan_no_get_sndtimeo,
- .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec,
+ .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec,
};
static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
@@ -3170,8 +3123,6 @@
smp->tfm_aes = tfm_aes;
smp->tfm_cmac = tfm_cmac;
- smp->min_key_size = SMP_MIN_ENC_KEY_SIZE;
- smp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
create_chan:
chan = l2cap_chan_create();
@@ -3294,94 +3245,6 @@
.llseek = default_llseek,
};
-static ssize_t le_min_key_size_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct hci_dev *hdev = file->private_data;
- char buf[4];
-
- snprintf(buf, sizeof(buf), "%2u\n", SMP_DEV(hdev)->min_key_size);
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
-}
-
-static ssize_t le_min_key_size_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct hci_dev *hdev = file->private_data;
- char buf[32];
- size_t buf_size = min(count, (sizeof(buf) - 1));
- u8 key_size;
-
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
-
- buf[buf_size] = '\0';
-
- sscanf(buf, "%hhu", &key_size);
-
- if (key_size > SMP_DEV(hdev)->max_key_size ||
- key_size < SMP_MIN_ENC_KEY_SIZE)
- return -EINVAL;
-
- SMP_DEV(hdev)->min_key_size = key_size;
-
- return count;
-}
-
-static const struct file_operations le_min_key_size_fops = {
- .open = simple_open,
- .read = le_min_key_size_read,
- .write = le_min_key_size_write,
- .llseek = default_llseek,
-};
-
-static ssize_t le_max_key_size_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct hci_dev *hdev = file->private_data;
- char buf[4];
-
- snprintf(buf, sizeof(buf), "%2u\n", SMP_DEV(hdev)->max_key_size);
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
-}
-
-static ssize_t le_max_key_size_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct hci_dev *hdev = file->private_data;
- char buf[32];
- size_t buf_size = min(count, (sizeof(buf) - 1));
- u8 key_size;
-
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
-
- buf[buf_size] = '\0';
-
- sscanf(buf, "%hhu", &key_size);
-
- if (key_size > SMP_MAX_ENC_KEY_SIZE ||
- key_size < SMP_DEV(hdev)->min_key_size)
- return -EINVAL;
-
- SMP_DEV(hdev)->max_key_size = key_size;
-
- return count;
-}
-
-static const struct file_operations le_max_key_size_fops = {
- .open = simple_open,
- .read = le_max_key_size_read,
- .write = le_max_key_size_write,
- .llseek = default_llseek,
-};
-
int smp_register(struct hci_dev *hdev)
{
struct l2cap_chan *chan;
@@ -3406,11 +3269,6 @@
hdev->smp_data = chan;
- debugfs_create_file("le_min_key_size", 0644, hdev->debugfs, hdev,
- &le_min_key_size_fops);
- debugfs_create_file("le_max_key_size", 0644, hdev->debugfs, hdev,
- &le_max_key_size_fops);
-
/* If the controller does not support BR/EDR Secure Connections
* feature, then the BR/EDR SMP channel shall not be present.
*
diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h
index ffcc70b..6cf8725 100644
--- a/net/bluetooth/smp.h
+++ b/net/bluetooth/smp.h
@@ -180,7 +180,6 @@
};
/* SMP Commands */
-void smp_cancel_pairing(struct hci_conn *hcon);
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level,
enum smp_key_pref key_pref);
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);