Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Johan Hedberg says:

====================
pull request: bluetooth-next 2018-05-18

Here's the first bluetooth-next pull request for the 4.18 kernel:

 - Refactoring of the btbcm driver
 - New USB IDs for QCA_ROME and LiteOn controllers
 - Buffer overflow fix if the controller sends invalid advertising data length
 - Various cleanups & fixes for Qualcomm controllers

Please let me know if there are any issues pulling. Thanks.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2018-05-20 18:24:22 -04:00
commit 2c71ab4bb4
19 changed files with 485 additions and 246 deletions

View File

@ -0,0 +1,30 @@
Qualcomm Bluetooth Chips
---------------------
This documents the binding structure and common properties for serial
attached Qualcomm devices.
Serial attached Qualcomm devices shall be a child node of the host UART
device the slave device is attached to.
Required properties:
- compatible: should contain one of the following:
* "qcom,qca6174-bt"
Optional properties:
- enable-gpios: gpio specifier used to enable chip
- clocks: clock provided to the controller (SUSCLK_32KHZ)
Example:
serial@7570000 {
label = "BT-UART";
status = "okay";
bluetooth {
compatible = "qcom,qca6174-bt";
enable-gpios = <&pm8994_gpios 19 GPIO_ACTIVE_HIGH>;
clocks = <&divclk4>;
};
};

View File

@ -36,4 +36,30 @@ config {
drive-strength = <2>; /* 2 MA */ drive-strength = <2>; /* 2 MA */
}; };
}; };
blsp1_uart1_default: blsp1_uart1_default {
mux {
pins = "gpio41", "gpio42", "gpio43", "gpio44";
function = "blsp_uart2";
};
config {
pins = "gpio41", "gpio42", "gpio43", "gpio44";
drive-strength = <16>;
bias-disable;
};
};
blsp1_uart1_sleep: blsp1_uart1_sleep {
mux {
pins = "gpio41", "gpio42", "gpio43", "gpio44";
function = "gpio";
};
config {
pins = "gpio41", "gpio42", "gpio43", "gpio44";
drive-strength = <2>;
bias-disable;
};
};
}; };

View File

@ -14,6 +14,28 @@ pinconf {
}; };
}; };
bt_en_gpios: bt_en_gpios {
pinconf {
pins = "gpio19";
function = PMIC_GPIO_FUNC_NORMAL;
output-low;
power-source = <PM8994_GPIO_S4>; // 1.8V
qcom,drive-strength = <PMIC_GPIO_STRENGTH_LOW>;
bias-pull-down;
};
};
wlan_en_gpios: wlan_en_gpios {
pinconf {
pins = "gpio8";
function = PMIC_GPIO_FUNC_NORMAL;
output-low;
power-source = <PM8994_GPIO_S4>; // 1.8V
qcom,drive-strength = <PMIC_GPIO_STRENGTH_LOW>;
bias-pull-down;
};
};
volume_up_gpio: pm8996_gpio2 { volume_up_gpio: pm8996_gpio2 {
pinconf { pinconf {
pins = "gpio2"; pins = "gpio2";
@ -26,6 +48,16 @@ pinconf {
}; };
}; };
divclk4_pin_a: divclk4 {
pinconf {
pins = "gpio18";
function = PMIC_GPIO_FUNC_FUNC2;
bias-disable;
power-source = <PM8994_GPIO_S4>;
};
};
usb3_vbus_det_gpio: pm8996_gpio22 { usb3_vbus_det_gpio: pm8996_gpio22 {
pinconf { pinconf {
pins = "gpio22"; pins = "gpio22";

View File

@ -23,6 +23,7 @@ / {
aliases { aliases {
serial0 = &blsp2_uart1; serial0 = &blsp2_uart1;
serial1 = &blsp2_uart2; serial1 = &blsp2_uart2;
serial2 = &blsp1_uart1;
i2c0 = &blsp1_i2c2; i2c0 = &blsp1_i2c2;
i2c1 = &blsp2_i2c1; i2c1 = &blsp2_i2c1;
i2c2 = &blsp2_i2c0; i2c2 = &blsp2_i2c0;
@ -34,7 +35,36 @@ chosen {
stdout-path = "serial0:115200n8"; stdout-path = "serial0:115200n8";
}; };
clocks {
divclk4: divclk4 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <32768>;
clock-output-names = "divclk4";
pinctrl-names = "default";
pinctrl-0 = <&divclk4_pin_a>;
};
};
soc { soc {
serial@7570000 {
label = "BT-UART";
status = "okay";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&blsp1_uart1_default>;
pinctrl-1 = <&blsp1_uart1_sleep>;
bluetooth {
compatible = "qcom,qca6174-bt";
/* bt_disable_n gpio */
enable-gpios = <&pm8994_gpios 19 GPIO_ACTIVE_HIGH>;
clocks = <&divclk4>;
};
};
serial@75b0000 { serial@75b0000 {
label = "LS-UART1"; label = "LS-UART1";
status = "okay"; status = "okay";
@ -139,9 +169,40 @@ usb2_id: usb2-id {
pinctrl-0 = <&usb2_vbus_det_gpio>; pinctrl-0 = <&usb2_vbus_det_gpio>;
}; };
bt_en: bt-en-1-8v {
pinctrl-names = "default";
pinctrl-0 = <&bt_en_gpios>;
compatible = "regulator-fixed";
regulator-name = "bt-en-regulator";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
/* WLAN card specific delay */
startup-delay-us = <70000>;
enable-active-high;
};
wlan_en: wlan-en-1-8v {
pinctrl-names = "default";
pinctrl-0 = <&wlan_en_gpios>;
compatible = "regulator-fixed";
regulator-name = "wlan-en-regulator";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
gpio = <&pm8994_gpios 8 0>;
/* WLAN card specific delay */
startup-delay-us = <70000>;
enable-active-high;
};
agnoc@0 { agnoc@0 {
qcom,pcie@600000 { qcom,pcie@600000 {
status = "okay";
perst-gpio = <&msmgpio 35 GPIO_ACTIVE_LOW>; perst-gpio = <&msmgpio 35 GPIO_ACTIVE_LOW>;
vddpe-supply = <&wlan_en>;
vddpe1-supply = <&bt_en>;
}; };
qcom,pcie@608000 { qcom,pcie@608000 {

View File

@ -419,6 +419,16 @@ kryocc: clock-controller@6400000 {
#clock-cells = <1>; #clock-cells = <1>;
}; };
blsp1_uart1: serial@7570000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0x07570000 0x1000>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>,
<&gcc GCC_BLSP1_AHB_CLK>;
clock-names = "core", "iface";
status = "disabled";
};
blsp1_spi0: spi@7575000 { blsp1_spi0: spi@7575000 {
compatible = "qcom,spi-qup-v2.2.1"; compatible = "qcom,spi-qup-v2.2.1";
reg = <0x07575000 0x600>; reg = <0x07575000 0x600>;

View File

@ -197,6 +197,7 @@ config BT_HCIUART_BCM
config BT_HCIUART_QCA config BT_HCIUART_QCA
bool "Qualcomm Atheros protocol support" bool "Qualcomm Atheros protocol support"
depends on BT_HCIUART depends on BT_HCIUART
depends on BT_HCIUART_SERDEV
select BT_HCIUART_H4 select BT_HCIUART_H4
select BT_QCA select BT_QCA
help help

View File

@ -315,10 +315,12 @@ static int btbcm_read_info(struct hci_dev *hdev)
return 0; return 0;
} }
static const struct { struct bcm_subver_table {
u16 subver; u16 subver;
const char *name; const char *name;
} bcm_uart_subver_table[] = { };
static const struct bcm_subver_table bcm_uart_subver_table[] = {
{ 0x4103, "BCM4330B1" }, /* 002.001.003 */ { 0x4103, "BCM4330B1" }, /* 002.001.003 */
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */ { 0x410e, "BCM43341B0" }, /* 002.001.014 */
{ 0x4406, "BCM4324B3" }, /* 002.004.006 */ { 0x4406, "BCM4324B3" }, /* 002.004.006 */
@ -330,98 +332,7 @@ static const struct {
{ } { }
}; };
int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len) static const struct bcm_subver_table bcm_usb_subver_table[] = {
{
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 controller information */
err = btbcm_read_info(hdev);
if (err)
return err;
switch ((rev & 0xf000) >> 12) {
case 0:
case 1:
case 2:
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_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u",
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_dev_info(hdev, "BCM (%3.3u.%3.3u.%3.3u) build %4.4u",
(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;
} bcm_usb_subver_table[] = {
{ 0x210b, "BCM43142A0" }, /* 001.001.011 */ { 0x210b, "BCM43142A0" }, /* 001.001.011 */
{ 0x2112, "BCM4314A0" }, /* 001.001.018 */ { 0x2112, "BCM4314A0" }, /* 001.001.018 */
{ 0x2118, "BCM20702A0" }, /* 001.001.024 */ { 0x2118, "BCM20702A0" }, /* 001.001.024 */
@ -435,14 +346,14 @@ static const struct {
{ } { }
}; };
int btbcm_setup_patchram(struct hci_dev *hdev) int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len,
bool reinit)
{ {
char fw_name[64];
const struct firmware *fw;
u16 subver, rev, pid, vid; u16 subver, rev, pid, vid;
const char *hw_name = NULL; const char *hw_name = "BCM";
struct sk_buff *skb; struct sk_buff *skb;
struct hci_rp_read_local_version *ver; struct hci_rp_read_local_version *ver;
const struct bcm_subver_table *bcm_subver_table;
int i, err; int i, err;
/* Reset */ /* Reset */
@ -461,25 +372,27 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
kfree_skb(skb); kfree_skb(skb);
/* Read controller information */ /* Read controller information */
err = btbcm_read_info(hdev); if (!reinit) {
if (err) err = btbcm_read_info(hdev);
return err; if (err)
return err;
}
switch ((rev & 0xf000) >> 12) { /* Upper nibble of rev should be between 0 and 3? */
case 0: if (((rev & 0xf000) >> 12) > 3)
case 3: return 0;
for (i = 0; bcm_uart_subver_table[i].name; i++) {
if (subver == bcm_uart_subver_table[i].subver) { bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table :
hw_name = bcm_uart_subver_table[i].name; bcm_uart_subver_table;
break;
} for (i = 0; bcm_subver_table[i].name; i++) {
if (subver == bcm_subver_table[i].subver) {
hw_name = bcm_subver_table[i].name;
break;
} }
}
snprintf(fw_name, sizeof(fw_name), "brcm/%s.hcd", if (hdev->bus == HCI_USB) {
hw_name ? : "BCM");
break;
case 1:
case 2:
/* Read USB Product Info */ /* Read USB Product Info */
skb = btbcm_read_usb_product(hdev); skb = btbcm_read_usb_product(hdev);
if (IS_ERR(skb)) if (IS_ERR(skb))
@ -489,24 +402,50 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
pid = get_unaligned_le16(skb->data + 3); pid = get_unaligned_le16(skb->data + 3);
kfree_skb(skb); kfree_skb(skb);
for (i = 0; bcm_usb_subver_table[i].name; i++) { snprintf(fw_name, len, "brcm/%s-%4.4x-%4.4x.hcd",
if (subver == bcm_usb_subver_table[i].subver) { hw_name, vid, pid);
hw_name = bcm_usb_subver_table[i].name; } else {
break; snprintf(fw_name, len, "brcm/%s.hcd", hw_name);
}
}
snprintf(fw_name, sizeof(fw_name), "brcm/%s-%4.4x-%4.4x.hcd",
hw_name ? : "BCM", vid, pid);
break;
default:
return 0;
} }
bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u", bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u",
hw_name ? : "BCM", (subver & 0xe000) >> 13, hw_name, (subver & 0xe000) >> 13,
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
return 0;
}
EXPORT_SYMBOL_GPL(btbcm_initialize);
int btbcm_finalize(struct hci_dev *hdev)
{
char fw_name[64];
int err;
/* Re-initialize */
err = btbcm_initialize(hdev, fw_name, sizeof(fw_name), true);
if (err)
return err;
btbcm_check_bdaddr(hdev);
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
return 0;
}
EXPORT_SYMBOL_GPL(btbcm_finalize);
int btbcm_setup_patchram(struct hci_dev *hdev)
{
char fw_name[64];
const struct firmware *fw;
struct sk_buff *skb;
int err;
/* Initialize */
err = btbcm_initialize(hdev, fw_name, sizeof(fw_name), false);
if (err)
return err;
err = request_firmware(&fw, fw_name, &hdev->dev); err = request_firmware(&fw, fw_name, &hdev->dev);
if (err < 0) { if (err < 0) {
bt_dev_info(hdev, "BCM: Patch %s not found", fw_name); bt_dev_info(hdev, "BCM: Patch %s not found", fw_name);
@ -517,25 +456,11 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
release_firmware(fw); release_firmware(fw);
/* Reset */ /* Re-initialize */
err = btbcm_reset(hdev); err = btbcm_initialize(hdev, fw_name, sizeof(fw_name), true);
if (err) if (err)
return 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_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u",
hw_name ? : "BCM", (subver & 0xe000) >> 13,
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
/* Read Local Name */ /* Read Local Name */
skb = btbcm_read_local_name(hdev); skb = btbcm_read_local_name(hdev);
if (IS_ERR(skb)) if (IS_ERR(skb))

View File

@ -73,7 +73,8 @@ int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw);
int btbcm_setup_patchram(struct hci_dev *hdev); int btbcm_setup_patchram(struct hci_dev *hdev);
int btbcm_setup_apple(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_initialize(struct hci_dev *hdev, char *fw_name, size_t len,
bool reinit);
int btbcm_finalize(struct hci_dev *hdev); int btbcm_finalize(struct hci_dev *hdev);
#else #else
@ -104,7 +105,7 @@ static inline int btbcm_setup_apple(struct hci_dev *hdev)
} }
static inline int btbcm_initialize(struct hci_dev *hdev, char *fw_name, static inline int btbcm_initialize(struct hci_dev *hdev, char *fw_name,
size_t len) size_t len, bool reinit)
{ {
return 0; return 0;
} }

View File

@ -127,28 +127,41 @@ static void rome_tlv_check_data(struct rome_config *config,
BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff); BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
BT_DBG("Length\t\t : %d bytes", length); BT_DBG("Length\t\t : %d bytes", length);
config->dnld_mode = ROME_SKIP_EVT_NONE;
switch (config->type) { switch (config->type) {
case TLV_TYPE_PATCH: case TLV_TYPE_PATCH:
tlv_patch = (struct tlv_type_patch *)tlv->data; tlv_patch = (struct tlv_type_patch *)tlv->data;
BT_DBG("Total Length\t\t : %d bytes",
/* For Rome version 1.1 to 3.1, all segment commands
* are acked by a vendor specific event (VSE).
* For Rome >= 3.2, the download mode field indicates
* if VSE is skipped by the controller.
* In case VSE is skipped, only the last segment is acked.
*/
config->dnld_mode = tlv_patch->download_mode;
BT_DBG("Total Length : %d bytes",
le32_to_cpu(tlv_patch->total_size)); le32_to_cpu(tlv_patch->total_size));
BT_DBG("Patch Data Length\t : %d bytes", BT_DBG("Patch Data Length : %d bytes",
le32_to_cpu(tlv_patch->data_length)); le32_to_cpu(tlv_patch->data_length));
BT_DBG("Signing Format Version : 0x%x", BT_DBG("Signing Format Version : 0x%x",
tlv_patch->format_version); tlv_patch->format_version);
BT_DBG("Signature Algorithm\t : 0x%x", BT_DBG("Signature Algorithm : 0x%x",
tlv_patch->signature); tlv_patch->signature);
BT_DBG("Reserved\t\t : 0x%x", BT_DBG("Download mode : 0x%x",
le16_to_cpu(tlv_patch->reserved1)); tlv_patch->download_mode);
BT_DBG("Product ID\t\t : 0x%04x", BT_DBG("Reserved : 0x%x",
tlv_patch->reserved1);
BT_DBG("Product ID : 0x%04x",
le16_to_cpu(tlv_patch->product_id)); le16_to_cpu(tlv_patch->product_id));
BT_DBG("Rom Build Version\t : 0x%04x", BT_DBG("Rom Build Version : 0x%04x",
le16_to_cpu(tlv_patch->rom_build)); le16_to_cpu(tlv_patch->rom_build));
BT_DBG("Patch Version\t\t : 0x%04x", BT_DBG("Patch Version : 0x%04x",
le16_to_cpu(tlv_patch->patch_version)); le16_to_cpu(tlv_patch->patch_version));
BT_DBG("Reserved\t\t : 0x%x", BT_DBG("Reserved : 0x%x",
le16_to_cpu(tlv_patch->reserved2)); le16_to_cpu(tlv_patch->reserved2));
BT_DBG("Patch Entry Address\t : 0x%x", BT_DBG("Patch Entry Address : 0x%x",
le32_to_cpu(tlv_patch->entry)); le32_to_cpu(tlv_patch->entry));
break; break;
@ -194,8 +207,8 @@ static void rome_tlv_check_data(struct rome_config *config,
} }
} }
static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int seg_size, static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size,
const u8 *data) const u8 *data, enum rome_tlv_dnld_mode mode)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct edl_event_hdr *edl; struct edl_event_hdr *edl;
@ -203,12 +216,14 @@ static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int seg_size,
u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2]; u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2];
int err = 0; int err = 0;
BT_DBG("%s: Download segment #%d size %d", hdev->name, idx, seg_size);
cmd[0] = EDL_PATCH_TLV_REQ_CMD; cmd[0] = EDL_PATCH_TLV_REQ_CMD;
cmd[1] = seg_size; cmd[1] = seg_size;
memcpy(cmd + 2, data, seg_size); memcpy(cmd + 2, data, seg_size);
if (mode == ROME_SKIP_EVT_VSE_CC || mode == ROME_SKIP_EVT_VSE)
return __hci_cmd_send(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2,
cmd);
skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, cmd, skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, cmd,
HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) { if (IS_ERR(skb)) {
@ -245,47 +260,12 @@ static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int seg_size,
return err; 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, static int rome_download_firmware(struct hci_dev *hdev,
struct rome_config *config) struct rome_config *config)
{ {
const struct firmware *fw; const struct firmware *fw;
int ret; const u8 *segment;
int ret, remain, i = 0;
bt_dev_info(hdev, "ROME Downloading %s", config->fwname); bt_dev_info(hdev, "ROME Downloading %s", config->fwname);
@ -298,10 +278,24 @@ static int rome_download_firmware(struct hci_dev *hdev,
rome_tlv_check_data(config, fw); rome_tlv_check_data(config, fw);
ret = rome_tlv_download_request(hdev, fw); segment = fw->data;
if (ret) { remain = fw->size;
BT_ERR("%s: Failed to download file: %s (%d)", hdev->name, while (remain > 0) {
config->fwname, ret); int segsize = min(MAX_SIZE_PER_TLV_SEGMENT, remain);
bt_dev_dbg(hdev, "Send segment %d, size %d", i++, segsize);
remain -= segsize;
/* The last segment is always acked regardless download mode */
if (!remain || segsize < MAX_SIZE_PER_TLV_SEGMENT)
config->dnld_mode = ROME_SKIP_EVT_NONE;
ret = rome_tlv_send_segment(hdev, segsize, segment,
config->dnld_mode);
if (ret)
break;
segment += segsize;
} }
release_firmware(fw); release_firmware(fw);

View File

@ -61,6 +61,13 @@ enum qca_bardrate {
QCA_BAUDRATE_RESERVED QCA_BAUDRATE_RESERVED
}; };
enum rome_tlv_dnld_mode {
ROME_SKIP_EVT_NONE,
ROME_SKIP_EVT_VSE,
ROME_SKIP_EVT_CC,
ROME_SKIP_EVT_VSE_CC
};
enum rome_tlv_type { enum rome_tlv_type {
TLV_TYPE_PATCH = 1, TLV_TYPE_PATCH = 1,
TLV_TYPE_NVM TLV_TYPE_NVM
@ -70,6 +77,7 @@ struct rome_config {
u8 type; u8 type;
char fwname[64]; char fwname[64];
uint8_t user_baud_rate; uint8_t user_baud_rate;
enum rome_tlv_dnld_mode dnld_mode;
}; };
struct edl_event_hdr { struct edl_event_hdr {
@ -94,7 +102,8 @@ struct tlv_type_patch {
__le32 data_length; __le32 data_length;
__u8 format_version; __u8 format_version;
__u8 signature; __u8 signature;
__le16 reserved1; __u8 download_mode;
__u8 reserved1;
__le16 product_id; __le16 product_id;
__le16 rom_build; __le16 rom_build;
__le16 patch_version; __le16 patch_version;

View File

@ -65,6 +65,7 @@ static int btqcomsmd_cmd_callback(struct rpmsg_device *rpdev, void *data,
{ {
struct btqcomsmd *btq = priv; struct btqcomsmd *btq = priv;
btq->hdev->stat.byte_rx += count;
return btqcomsmd_recv(btq->hdev, HCI_EVENT_PKT, data, count); return btqcomsmd_recv(btq->hdev, HCI_EVENT_PKT, data, count);
} }
@ -76,12 +77,21 @@ static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb)
switch (hci_skb_pkt_type(skb)) { switch (hci_skb_pkt_type(skb)) {
case HCI_ACLDATA_PKT: case HCI_ACLDATA_PKT:
ret = rpmsg_send(btq->acl_channel, skb->data, skb->len); ret = rpmsg_send(btq->acl_channel, skb->data, skb->len);
if (ret) {
hdev->stat.err_tx++;
break;
}
hdev->stat.acl_tx++; hdev->stat.acl_tx++;
hdev->stat.byte_tx += skb->len; hdev->stat.byte_tx += skb->len;
break; break;
case HCI_COMMAND_PKT: case HCI_COMMAND_PKT:
ret = rpmsg_send(btq->cmd_channel, skb->data, skb->len); ret = rpmsg_send(btq->cmd_channel, skb->data, skb->len);
if (ret) {
hdev->stat.err_tx++;
break;
}
hdev->stat.cmd_tx++; hdev->stat.cmd_tx++;
hdev->stat.byte_tx += skb->len;
break; break;
default: default:
ret = -EILSEQ; ret = -EILSEQ;

View File

@ -276,6 +276,8 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x04ca, 0x301a), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x13d3, 0x3496), .driver_info = BTUSB_QCA_ROME },
/* Broadcom BCM2035 */ /* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },

View File

@ -501,7 +501,7 @@ static int bcm_setup(struct hci_uart *hu)
hu->hdev->set_diag = bcm_set_diag; hu->hdev->set_diag = bcm_set_diag;
hu->hdev->set_bdaddr = btbcm_set_bdaddr; hu->hdev->set_bdaddr = btbcm_set_bdaddr;
err = btbcm_initialize(hu->hdev, fw_name, sizeof(fw_name)); err = btbcm_initialize(hu->hdev, fw_name, sizeof(fw_name), false);
if (err) if (err)
return err; return err;
@ -794,19 +794,21 @@ static const struct acpi_gpio_mapping acpi_bcm_int_first_gpios[] = {
{ }, { },
}; };
#ifdef CONFIG_ACPI /* Some firmware reports an IRQ which does not work (wrong pin in fw table?) */
/* IRQ polarity of some chipsets are not defined correctly in ACPI table. */ static const struct dmi_system_id bcm_broken_irq_dmi_table[] = {
static const struct dmi_system_id bcm_active_low_irq_dmi_table[] = { {
{ /* Handle ThinkPad 8 tablets with BCM2E55 chipset ACPI ID */ .ident = "Meegopad T08",
.ident = "Lenovo ThinkPad 8",
.matches = { .matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_EXACT_MATCH(DMI_BOARD_VENDOR,
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"), "To be filled by OEM."),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "T3 MRD"),
DMI_EXACT_MATCH(DMI_BOARD_VERSION, "V1.1"),
}, },
}, },
{ } { }
}; };
#ifdef CONFIG_ACPI
static int bcm_resource(struct acpi_resource *ares, void *data) static int bcm_resource(struct acpi_resource *ares, void *data)
{ {
struct bcm_device *dev = data; struct bcm_device *dev = data;
@ -904,6 +906,8 @@ static int bcm_gpio_set_shutdown(struct bcm_device *dev, bool powered)
static int bcm_get_resources(struct bcm_device *dev) static int bcm_get_resources(struct bcm_device *dev)
{ {
const struct dmi_system_id *dmi_id;
dev->name = dev_name(dev->dev); dev->name = dev_name(dev->dev);
if (x86_apple_machine && !bcm_apple_get_resources(dev)) if (x86_apple_machine && !bcm_apple_get_resources(dev))
@ -936,6 +940,13 @@ static int bcm_get_resources(struct bcm_device *dev)
dev->irq = gpiod_to_irq(gpio); dev->irq = gpiod_to_irq(gpio);
} }
dmi_id = dmi_first_match(bcm_broken_irq_dmi_table);
if (dmi_id) {
dev_info(dev->dev, "%s: Has a broken IRQ config, disabling IRQ support / runtime-pm\n",
dmi_id->ident);
dev->irq = 0;
}
dev_dbg(dev->dev, "BCM irq: %d\n", dev->irq); dev_dbg(dev->dev, "BCM irq: %d\n", dev->irq);
return 0; return 0;
} }
@ -944,7 +955,6 @@ static int bcm_get_resources(struct bcm_device *dev)
static int bcm_acpi_probe(struct bcm_device *dev) static int bcm_acpi_probe(struct bcm_device *dev)
{ {
LIST_HEAD(resources); LIST_HEAD(resources);
const struct dmi_system_id *dmi_id;
const struct acpi_gpio_mapping *gpio_mapping = acpi_bcm_int_last_gpios; const struct acpi_gpio_mapping *gpio_mapping = acpi_bcm_int_last_gpios;
struct resource_entry *entry; struct resource_entry *entry;
int ret; int ret;
@ -991,13 +1001,6 @@ static int bcm_acpi_probe(struct bcm_device *dev)
dev->irq_active_low = irq_polarity; dev->irq_active_low = irq_polarity;
dev_warn(dev->dev, "Overwriting IRQ polarity to active %s by module-param\n", dev_warn(dev->dev, "Overwriting IRQ polarity to active %s by module-param\n",
dev->irq_active_low ? "low" : "high"); dev->irq_active_low ? "low" : "high");
} else {
dmi_id = dmi_first_match(bcm_active_low_irq_dmi_table);
if (dmi_id) {
dev_warn(dev->dev, "%s: Overwriting IRQ polarity to active low",
dmi_id->ident);
dev->irq_active_low = true;
}
} }
return 0; return 0;

View File

@ -447,6 +447,8 @@ static int hci_uart_setup(struct hci_dev *hdev)
btbcm_check_bdaddr(hdev); btbcm_check_bdaddr(hdev);
break; break;
#endif #endif
default:
break;
} }
done: done:

View File

@ -29,7 +29,12 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/gpio/consumer.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/serdev.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
@ -50,6 +55,9 @@
#define IBS_TX_IDLE_TIMEOUT_MS 2000 #define IBS_TX_IDLE_TIMEOUT_MS 2000
#define BAUDRATE_SETTLE_TIMEOUT_MS 300 #define BAUDRATE_SETTLE_TIMEOUT_MS 300
/* susclk rate */
#define SUSCLK_RATE_32KHZ 32768
/* HCI_IBS transmit side sleep protocol states */ /* HCI_IBS transmit side sleep protocol states */
enum tx_ibs_states { enum tx_ibs_states {
HCI_IBS_TX_ASLEEP, HCI_IBS_TX_ASLEEP,
@ -111,6 +119,12 @@ struct qca_data {
u64 votes_off; u64 votes_off;
}; };
struct qca_serdev {
struct hci_uart serdev_hu;
struct gpio_desc *bt_en;
struct clk *susclk;
};
static void __serial_clock_on(struct tty_struct *tty) static void __serial_clock_on(struct tty_struct *tty)
{ {
/* TODO: Some chipset requires to enable UART clock on client /* TODO: Some chipset requires to enable UART clock on client
@ -386,6 +400,7 @@ static void hci_ibs_wake_retrans_timeout(struct timer_list *t)
/* Initialize protocol */ /* Initialize protocol */
static int qca_open(struct hci_uart *hu) static int qca_open(struct hci_uart *hu)
{ {
struct qca_serdev *qcadev;
struct qca_data *qca; struct qca_data *qca;
BT_DBG("hu %p qca_open", hu); BT_DBG("hu %p qca_open", hu);
@ -444,6 +459,13 @@ static int qca_open(struct hci_uart *hu)
timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0); timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS; qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
if (hu->serdev) {
serdev_device_open(hu->serdev);
qcadev = serdev_device_get_drvdata(hu->serdev);
gpiod_set_value_cansleep(qcadev->bt_en, 1);
}
BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u", BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
qca->tx_idle_delay, qca->wake_retrans); qca->tx_idle_delay, qca->wake_retrans);
@ -512,6 +534,7 @@ static int qca_flush(struct hci_uart *hu)
/* Close protocol */ /* Close protocol */
static int qca_close(struct hci_uart *hu) static int qca_close(struct hci_uart *hu)
{ {
struct qca_serdev *qcadev;
struct qca_data *qca = hu->priv; struct qca_data *qca = hu->priv;
BT_DBG("hu %p qca close", hu); BT_DBG("hu %p qca close", hu);
@ -525,6 +548,13 @@ static int qca_close(struct hci_uart *hu)
destroy_workqueue(qca->workqueue); destroy_workqueue(qca->workqueue);
qca->hu = NULL; qca->hu = NULL;
if (hu->serdev) {
serdev_device_close(hu->serdev);
qcadev = serdev_device_get_drvdata(hu->serdev);
gpiod_set_value_cansleep(qcadev->bt_en, 0);
}
kfree_skb(qca->rx_skb); kfree_skb(qca->rx_skb);
hu->priv = NULL; hu->priv = NULL;
@ -885,6 +915,14 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
return 0; return 0;
} }
static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed)
{
if (hu->serdev)
serdev_device_set_baudrate(hu->serdev, speed);
else
hci_uart_set_baudrate(hu, speed);
}
static int qca_setup(struct hci_uart *hu) static int qca_setup(struct hci_uart *hu)
{ {
struct hci_dev *hdev = hu->hdev; struct hci_dev *hdev = hu->hdev;
@ -905,7 +943,7 @@ static int qca_setup(struct hci_uart *hu)
speed = hu->proto->init_speed; speed = hu->proto->init_speed;
if (speed) if (speed)
hci_uart_set_baudrate(hu, speed); host_set_baudrate(hu, speed);
/* Setup user speed if needed */ /* Setup user speed if needed */
speed = 0; speed = 0;
@ -924,7 +962,7 @@ static int qca_setup(struct hci_uart *hu)
ret); ret);
return ret; return ret;
} }
hci_uart_set_baudrate(hu, speed); host_set_baudrate(hu, speed);
} }
/* Setup patch / NVM configurations */ /* Setup patch / NVM configurations */
@ -935,6 +973,12 @@ static int qca_setup(struct hci_uart *hu)
} else if (ret == -ENOENT) { } else if (ret == -ENOENT) {
/* No patch/nvm-config found, run with original fw/config */ /* No patch/nvm-config found, run with original fw/config */
ret = 0; ret = 0;
} else if (ret == -EAGAIN) {
/*
* Userspace firmware loader will return -EAGAIN in case no
* patch/nvm-config is found, so run with original fw/config.
*/
ret = 0;
} }
/* Setup bdaddr */ /* Setup bdaddr */
@ -958,12 +1002,80 @@ static struct hci_uart_proto qca_proto = {
.dequeue = qca_dequeue, .dequeue = qca_dequeue,
}; };
static int qca_serdev_probe(struct serdev_device *serdev)
{
struct qca_serdev *qcadev;
int err;
qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL);
if (!qcadev)
return -ENOMEM;
qcadev->serdev_hu.serdev = serdev;
serdev_device_set_drvdata(serdev, qcadev);
qcadev->bt_en = devm_gpiod_get(&serdev->dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR(qcadev->bt_en)) {
dev_err(&serdev->dev, "failed to acquire enable gpio\n");
return PTR_ERR(qcadev->bt_en);
}
qcadev->susclk = devm_clk_get(&serdev->dev, NULL);
if (IS_ERR(qcadev->susclk)) {
dev_err(&serdev->dev, "failed to acquire clk\n");
return PTR_ERR(qcadev->susclk);
}
err = clk_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ);
if (err)
return err;
err = clk_prepare_enable(qcadev->susclk);
if (err)
return err;
err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
if (err)
clk_disable_unprepare(qcadev->susclk);
return err;
}
static void qca_serdev_remove(struct serdev_device *serdev)
{
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
hci_uart_unregister_device(&qcadev->serdev_hu);
clk_disable_unprepare(qcadev->susclk);
}
static const struct of_device_id qca_bluetooth_of_match[] = {
{ .compatible = "qcom,qca6174-bt" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
static struct serdev_device_driver qca_serdev_driver = {
.probe = qca_serdev_probe,
.remove = qca_serdev_remove,
.driver = {
.name = "hci_uart_qca",
.of_match_table = qca_bluetooth_of_match,
},
};
int __init qca_init(void) int __init qca_init(void)
{ {
serdev_device_driver_register(&qca_serdev_driver);
return hci_uart_register_proto(&qca_proto); return hci_uart_register_proto(&qca_proto);
} }
int __exit qca_deinit(void) int __exit qca_deinit(void)
{ {
serdev_device_driver_unregister(&qca_serdev_driver);
return hci_uart_unregister_proto(&qca_proto); return hci_uart_unregister_proto(&qca_proto);
} }

View File

@ -1393,6 +1393,8 @@ struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u32 timeout); const void *param, u32 timeout);
struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u8 event, u32 timeout); const void *param, u8 event, u32 timeout);
int __hci_cmd_send(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param);
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
const void *param); const void *param);

View File

@ -3422,6 +3422,37 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
return 0; return 0;
} }
int __hci_cmd_send(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param)
{
struct sk_buff *skb;
if (hci_opcode_ogf(opcode) != 0x3f) {
/* A controller receiving a command shall respond with either
* a Command Status Event or a Command Complete Event.
* Therefore, all standard HCI commands must be sent via the
* standard API, using hci_send_cmd or hci_cmd_sync helpers.
* Some vendors do not comply with this rule for vendor-specific
* commands and do not return any event. We want to support
* unresponded commands for such cases only.
*/
bt_dev_err(hdev, "unresponded command not supported");
return -EINVAL;
}
skb = hci_prepare_cmd(hdev, opcode, plen, param);
if (!skb) {
bt_dev_err(hdev, "no memory for command (opcode 0x%4.4x)",
opcode);
return -ENOMEM;
}
hci_send_frame(hdev, skb);
return 0;
}
EXPORT_SYMBOL(__hci_cmd_send);
/* Get data from the previously sent command */ /* Get data from the previously sent command */
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode) void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
{ {

View File

@ -4942,10 +4942,14 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
struct hci_ev_le_advertising_info *ev = ptr; struct hci_ev_le_advertising_info *ev = ptr;
s8 rssi; s8 rssi;
rssi = ev->data[ev->length]; if (ev->length <= HCI_MAX_AD_LENGTH) {
process_adv_report(hdev, ev->evt_type, &ev->bdaddr, rssi = ev->data[ev->length];
ev->bdaddr_type, NULL, 0, rssi, process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
ev->data, ev->length); ev->bdaddr_type, NULL, 0, rssi,
ev->data, ev->length);
} else {
bt_dev_err(hdev, "Dropping invalid advertising data");
}
ptr += sizeof(*ev) + ev->length + 1; ptr += sizeof(*ev) + ev->length + 1;
} }

View File

@ -122,7 +122,6 @@ void hci_req_sync_cancel(struct hci_dev *hdev, int err)
struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u8 event, u32 timeout) const void *param, u8 event, u32 timeout)
{ {
DECLARE_WAITQUEUE(wait, current);
struct hci_request req; struct hci_request req;
struct sk_buff *skb; struct sk_buff *skb;
int err = 0; int err = 0;
@ -135,21 +134,14 @@ struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
hdev->req_status = HCI_REQ_PEND; 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); err = hci_req_run_skb(&req, hci_req_sync_complete);
if (err < 0) { if (err < 0)
remove_wait_queue(&hdev->req_wait_q, &wait);
set_current_state(TASK_RUNNING);
return ERR_PTR(err); return ERR_PTR(err);
}
schedule_timeout(timeout); err = wait_event_interruptible_timeout(hdev->req_wait_q,
hdev->req_status != HCI_REQ_PEND, timeout);
remove_wait_queue(&hdev->req_wait_q, &wait); if (err == -ERESTARTSYS)
if (signal_pending(current))
return ERR_PTR(-EINTR); return ERR_PTR(-EINTR);
switch (hdev->req_status) { switch (hdev->req_status) {
@ -197,7 +189,6 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
unsigned long opt, u32 timeout, u8 *hci_status) unsigned long opt, u32 timeout, u8 *hci_status)
{ {
struct hci_request req; struct hci_request req;
DECLARE_WAITQUEUE(wait, current);
int err = 0; int err = 0;
BT_DBG("%s start", hdev->name); BT_DBG("%s start", hdev->name);
@ -213,16 +204,10 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
return err; 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); err = hci_req_run_skb(&req, hci_req_sync_complete);
if (err < 0) { if (err < 0) {
hdev->req_status = 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. /* ENODATA means the HCI request command queue is empty.
* This can happen when a request with conditionals doesn't * This can happen when a request with conditionals doesn't
* trigger any commands to be sent. This is normal behavior * trigger any commands to be sent. This is normal behavior
@ -240,11 +225,10 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
return err; return err;
} }
schedule_timeout(timeout); err = wait_event_interruptible_timeout(hdev->req_wait_q,
hdev->req_status != HCI_REQ_PEND, timeout);
remove_wait_queue(&hdev->req_wait_q, &wait); if (err == -ERESTARTSYS)
if (signal_pending(current))
return -EINTR; return -EINTR;
switch (hdev->req_status) { switch (hdev->req_status) {