mirror of https://gitee.com/openkylin/linux.git
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:
commit
2c71ab4bb4
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -36,4 +36,30 @@ config {
|
|||
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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
pinconf {
|
||||
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 {
|
||||
pinconf {
|
||||
pins = "gpio22";
|
||||
|
|
|
@ -23,6 +23,7 @@ / {
|
|||
aliases {
|
||||
serial0 = &blsp2_uart1;
|
||||
serial1 = &blsp2_uart2;
|
||||
serial2 = &blsp1_uart1;
|
||||
i2c0 = &blsp1_i2c2;
|
||||
i2c1 = &blsp2_i2c1;
|
||||
i2c2 = &blsp2_i2c0;
|
||||
|
@ -34,7 +35,36 @@ chosen {
|
|||
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 {
|
||||
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 {
|
||||
label = "LS-UART1";
|
||||
status = "okay";
|
||||
|
@ -139,9 +169,40 @@ usb2_id: usb2-id {
|
|||
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 {
|
||||
qcom,pcie@600000 {
|
||||
status = "okay";
|
||||
perst-gpio = <&msmgpio 35 GPIO_ACTIVE_LOW>;
|
||||
vddpe-supply = <&wlan_en>;
|
||||
vddpe1-supply = <&bt_en>;
|
||||
};
|
||||
|
||||
qcom,pcie@608000 {
|
||||
|
|
|
@ -419,6 +419,16 @@ kryocc: clock-controller@6400000 {
|
|||
#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 {
|
||||
compatible = "qcom,spi-qup-v2.2.1";
|
||||
reg = <0x07575000 0x600>;
|
||||
|
|
|
@ -197,6 +197,7 @@ config BT_HCIUART_BCM
|
|||
config BT_HCIUART_QCA
|
||||
bool "Qualcomm Atheros protocol support"
|
||||
depends on BT_HCIUART
|
||||
depends on BT_HCIUART_SERDEV
|
||||
select BT_HCIUART_H4
|
||||
select BT_QCA
|
||||
help
|
||||
|
|
|
@ -315,10 +315,12 @@ static int btbcm_read_info(struct hci_dev *hdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
struct bcm_subver_table {
|
||||
u16 subver;
|
||||
const char *name;
|
||||
} bcm_uart_subver_table[] = {
|
||||
};
|
||||
|
||||
static const struct bcm_subver_table bcm_uart_subver_table[] = {
|
||||
{ 0x4103, "BCM4330B1" }, /* 002.001.003 */
|
||||
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */
|
||||
{ 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)
|
||||
{
|
||||
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[] = {
|
||||
static const struct bcm_subver_table bcm_usb_subver_table[] = {
|
||||
{ 0x210b, "BCM43142A0" }, /* 001.001.011 */
|
||||
{ 0x2112, "BCM4314A0" }, /* 001.001.018 */
|
||||
{ 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;
|
||||
const char *hw_name = NULL;
|
||||
const char *hw_name = "BCM";
|
||||
struct sk_buff *skb;
|
||||
struct hci_rp_read_local_version *ver;
|
||||
const struct bcm_subver_table *bcm_subver_table;
|
||||
int i, err;
|
||||
|
||||
/* Reset */
|
||||
|
@ -461,25 +372,27 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
|
|||
kfree_skb(skb);
|
||||
|
||||
/* Read controller information */
|
||||
err = btbcm_read_info(hdev);
|
||||
if (err)
|
||||
return err;
|
||||
if (!reinit) {
|
||||
err = btbcm_read_info(hdev);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
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;
|
||||
break;
|
||||
}
|
||||
/* Upper nibble of rev should be between 0 and 3? */
|
||||
if (((rev & 0xf000) >> 12) > 3)
|
||||
return 0;
|
||||
|
||||
bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table :
|
||||
bcm_uart_subver_table;
|
||||
|
||||
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",
|
||||
hw_name ? : "BCM");
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
if (hdev->bus == HCI_USB) {
|
||||
/* Read USB Product Info */
|
||||
skb = btbcm_read_usb_product(hdev);
|
||||
if (IS_ERR(skb))
|
||||
|
@ -489,24 +402,50 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
|
|||
pid = get_unaligned_le16(skb->data + 3);
|
||||
kfree_skb(skb);
|
||||
|
||||
for (i = 0; bcm_usb_subver_table[i].name; i++) {
|
||||
if (subver == bcm_usb_subver_table[i].subver) {
|
||||
hw_name = bcm_usb_subver_table[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(fw_name, sizeof(fw_name), "brcm/%s-%4.4x-%4.4x.hcd",
|
||||
hw_name ? : "BCM", vid, pid);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
snprintf(fw_name, len, "brcm/%s-%4.4x-%4.4x.hcd",
|
||||
hw_name, vid, pid);
|
||||
} else {
|
||||
snprintf(fw_name, len, "brcm/%s.hcd", hw_name);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
if (err < 0) {
|
||||
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);
|
||||
|
||||
/* Reset */
|
||||
err = btbcm_reset(hdev);
|
||||
/* Re-initialize */
|
||||
err = btbcm_initialize(hdev, fw_name, sizeof(fw_name), true);
|
||||
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, "%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 */
|
||||
skb = btbcm_read_local_name(hdev);
|
||||
if (IS_ERR(skb))
|
||||
|
|
|
@ -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_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);
|
||||
|
||||
#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,
|
||||
size_t len)
|
||||
size_t len, bool reinit)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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("Length\t\t : %d bytes", length);
|
||||
|
||||
config->dnld_mode = ROME_SKIP_EVT_NONE;
|
||||
|
||||
switch (config->type) {
|
||||
case TLV_TYPE_PATCH:
|
||||
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));
|
||||
BT_DBG("Patch Data Length\t : %d bytes",
|
||||
BT_DBG("Patch Data Length : %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",
|
||||
BT_DBG("Signature Algorithm : 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",
|
||||
BT_DBG("Download mode : 0x%x",
|
||||
tlv_patch->download_mode);
|
||||
BT_DBG("Reserved : 0x%x",
|
||||
tlv_patch->reserved1);
|
||||
BT_DBG("Product ID : 0x%04x",
|
||||
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));
|
||||
BT_DBG("Patch Version\t\t : 0x%04x",
|
||||
BT_DBG("Patch Version : 0x%04x",
|
||||
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));
|
||||
BT_DBG("Patch Entry Address\t : 0x%x",
|
||||
BT_DBG("Patch Entry Address : 0x%x",
|
||||
le32_to_cpu(tlv_patch->entry));
|
||||
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,
|
||||
const u8 *data)
|
||||
static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size,
|
||||
const u8 *data, enum rome_tlv_dnld_mode mode)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
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];
|
||||
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);
|
||||
|
||||
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,
|
||||
HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
const u8 *segment;
|
||||
int ret, remain, i = 0;
|
||||
|
||||
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);
|
||||
|
||||
ret = rome_tlv_download_request(hdev, fw);
|
||||
if (ret) {
|
||||
BT_ERR("%s: Failed to download file: %s (%d)", hdev->name,
|
||||
config->fwname, ret);
|
||||
segment = fw->data;
|
||||
remain = fw->size;
|
||||
while (remain > 0) {
|
||||
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);
|
||||
|
|
|
@ -61,6 +61,13 @@ enum qca_bardrate {
|
|||
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 {
|
||||
TLV_TYPE_PATCH = 1,
|
||||
TLV_TYPE_NVM
|
||||
|
@ -70,6 +77,7 @@ struct rome_config {
|
|||
u8 type;
|
||||
char fwname[64];
|
||||
uint8_t user_baud_rate;
|
||||
enum rome_tlv_dnld_mode dnld_mode;
|
||||
};
|
||||
|
||||
struct edl_event_hdr {
|
||||
|
@ -94,7 +102,8 @@ struct tlv_type_patch {
|
|||
__le32 data_length;
|
||||
__u8 format_version;
|
||||
__u8 signature;
|
||||
__le16 reserved1;
|
||||
__u8 download_mode;
|
||||
__u8 reserved1;
|
||||
__le16 product_id;
|
||||
__le16 rom_build;
|
||||
__le16 patch_version;
|
||||
|
|
|
@ -65,6 +65,7 @@ static int btqcomsmd_cmd_callback(struct rpmsg_device *rpdev, void *data,
|
|||
{
|
||||
struct btqcomsmd *btq = priv;
|
||||
|
||||
btq->hdev->stat.byte_rx += 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)) {
|
||||
case HCI_ACLDATA_PKT:
|
||||
ret = rpmsg_send(btq->acl_channel, skb->data, skb->len);
|
||||
if (ret) {
|
||||
hdev->stat.err_tx++;
|
||||
break;
|
||||
}
|
||||
hdev->stat.acl_tx++;
|
||||
hdev->stat.byte_tx += skb->len;
|
||||
break;
|
||||
case HCI_COMMAND_PKT:
|
||||
ret = rpmsg_send(btq->cmd_channel, skb->data, skb->len);
|
||||
if (ret) {
|
||||
hdev->stat.err_tx++;
|
||||
break;
|
||||
}
|
||||
hdev->stat.cmd_tx++;
|
||||
hdev->stat.byte_tx += skb->len;
|
||||
break;
|
||||
default:
|
||||
ret = -EILSEQ;
|
||||
|
|
|
@ -276,6 +276,8 @@ static const struct usb_device_id blacklist_table[] = {
|
|||
{ USB_DEVICE(0x04ca, 0x3011), .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, 0x301a), .driver_info = BTUSB_QCA_ROME },
|
||||
{ USB_DEVICE(0x13d3, 0x3496), .driver_info = BTUSB_QCA_ROME },
|
||||
|
||||
/* Broadcom BCM2035 */
|
||||
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
|
||||
|
|
|
@ -501,7 +501,7 @@ static int bcm_setup(struct hci_uart *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));
|
||||
err = btbcm_initialize(hu->hdev, fw_name, sizeof(fw_name), false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -794,19 +794,21 @@ static const struct acpi_gpio_mapping acpi_bcm_int_first_gpios[] = {
|
|||
{ },
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
/* IRQ polarity of some chipsets are not defined correctly in ACPI table. */
|
||||
static const struct dmi_system_id bcm_active_low_irq_dmi_table[] = {
|
||||
{ /* Handle ThinkPad 8 tablets with BCM2E55 chipset ACPI ID */
|
||||
.ident = "Lenovo ThinkPad 8",
|
||||
/* Some firmware reports an IRQ which does not work (wrong pin in fw table?) */
|
||||
static const struct dmi_system_id bcm_broken_irq_dmi_table[] = {
|
||||
{
|
||||
.ident = "Meegopad T08",
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_VENDOR,
|
||||
"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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
const struct dmi_system_id *dmi_id;
|
||||
|
||||
dev->name = dev_name(dev->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);
|
||||
}
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -944,7 +955,6 @@ static int bcm_get_resources(struct bcm_device *dev)
|
|||
static int bcm_acpi_probe(struct bcm_device *dev)
|
||||
{
|
||||
LIST_HEAD(resources);
|
||||
const struct dmi_system_id *dmi_id;
|
||||
const struct acpi_gpio_mapping *gpio_mapping = acpi_bcm_int_last_gpios;
|
||||
struct resource_entry *entry;
|
||||
int ret;
|
||||
|
@ -991,13 +1001,6 @@ static int bcm_acpi_probe(struct bcm_device *dev)
|
|||
dev->irq_active_low = irq_polarity;
|
||||
dev_warn(dev->dev, "Overwriting IRQ polarity to active %s by module-param\n",
|
||||
dev->irq_active_low ? "low" : "high");
|
||||
} else {
|
||||
dmi_id = dmi_first_match(bcm_active_low_irq_dmi_table);
|
||||
if (dmi_id) {
|
||||
dev_warn(dev->dev, "%s: Overwriting IRQ polarity to active low",
|
||||
dmi_id->ident);
|
||||
dev->irq_active_low = true;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -447,6 +447,8 @@ static int hci_uart_setup(struct hci_dev *hdev)
|
|||
btbcm_check_bdaddr(hdev);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
|
|
|
@ -29,7 +29,12 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.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/hci_core.h>
|
||||
|
@ -50,6 +55,9 @@
|
|||
#define IBS_TX_IDLE_TIMEOUT_MS 2000
|
||||
#define BAUDRATE_SETTLE_TIMEOUT_MS 300
|
||||
|
||||
/* susclk rate */
|
||||
#define SUSCLK_RATE_32KHZ 32768
|
||||
|
||||
/* HCI_IBS transmit side sleep protocol states */
|
||||
enum tx_ibs_states {
|
||||
HCI_IBS_TX_ASLEEP,
|
||||
|
@ -111,6 +119,12 @@ struct qca_data {
|
|||
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)
|
||||
{
|
||||
/* 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 */
|
||||
static int qca_open(struct hci_uart *hu)
|
||||
{
|
||||
struct qca_serdev *qcadev;
|
||||
struct qca_data *qca;
|
||||
|
||||
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);
|
||||
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",
|
||||
qca->tx_idle_delay, qca->wake_retrans);
|
||||
|
||||
|
@ -512,6 +534,7 @@ static int qca_flush(struct hci_uart *hu)
|
|||
/* Close protocol */
|
||||
static int qca_close(struct hci_uart *hu)
|
||||
{
|
||||
struct qca_serdev *qcadev;
|
||||
struct qca_data *qca = hu->priv;
|
||||
|
||||
BT_DBG("hu %p qca close", hu);
|
||||
|
@ -525,6 +548,13 @@ static int qca_close(struct hci_uart *hu)
|
|||
destroy_workqueue(qca->workqueue);
|
||||
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);
|
||||
|
||||
hu->priv = NULL;
|
||||
|
@ -885,6 +915,14 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
|
|||
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)
|
||||
{
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
|
@ -905,7 +943,7 @@ static int qca_setup(struct hci_uart *hu)
|
|||
speed = hu->proto->init_speed;
|
||||
|
||||
if (speed)
|
||||
hci_uart_set_baudrate(hu, speed);
|
||||
host_set_baudrate(hu, speed);
|
||||
|
||||
/* Setup user speed if needed */
|
||||
speed = 0;
|
||||
|
@ -924,7 +962,7 @@ static int qca_setup(struct hci_uart *hu)
|
|||
ret);
|
||||
return ret;
|
||||
}
|
||||
hci_uart_set_baudrate(hu, speed);
|
||||
host_set_baudrate(hu, speed);
|
||||
}
|
||||
|
||||
/* Setup patch / NVM configurations */
|
||||
|
@ -935,6 +973,12 @@ static int qca_setup(struct hci_uart *hu)
|
|||
} else if (ret == -ENOENT) {
|
||||
/* No patch/nvm-config found, run with original fw/config */
|
||||
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 */
|
||||
|
@ -958,12 +1002,80 @@ static struct hci_uart_proto qca_proto = {
|
|||
.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)
|
||||
{
|
||||
serdev_device_driver_register(&qca_serdev_driver);
|
||||
|
||||
return hci_uart_register_proto(&qca_proto);
|
||||
}
|
||||
|
||||
int __exit qca_deinit(void)
|
||||
{
|
||||
serdev_device_driver_unregister(&qca_serdev_driver);
|
||||
|
||||
return hci_uart_unregister_proto(&qca_proto);
|
||||
}
|
||||
|
|
|
@ -1393,6 +1393,8 @@ struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
|
|||
const void *param, u32 timeout);
|
||||
struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
|
||||
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,
|
||||
const void *param);
|
||||
|
|
|
@ -3422,6 +3422,37 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
|
|||
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 */
|
||||
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
s8 rssi;
|
||||
|
||||
rssi = ev->data[ev->length];
|
||||
process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
|
||||
ev->bdaddr_type, NULL, 0, rssi,
|
||||
ev->data, ev->length);
|
||||
if (ev->length <= HCI_MAX_AD_LENGTH) {
|
||||
rssi = ev->data[ev->length];
|
||||
process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
const void *param, u8 event, u32 timeout)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
struct hci_request req;
|
||||
struct sk_buff *skb;
|
||||
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;
|
||||
|
||||
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);
|
||||
if (err < 0)
|
||||
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 (signal_pending(current))
|
||||
if (err == -ERESTARTSYS)
|
||||
return ERR_PTR(-EINTR);
|
||||
|
||||
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)
|
||||
{
|
||||
struct hci_request req;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
int err = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -240,11 +225,10 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
|
|||
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 (signal_pending(current))
|
||||
if (err == -ERESTARTSYS)
|
||||
return -EINTR;
|
||||
|
||||
switch (hdev->req_status) {
|
||||
|
|
Loading…
Reference in New Issue