Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== Here's the main bluetooth-next pull request for the 5.1 kernel. - Fixes & improvements to mediatek, hci_qca, btrtl, and btmrvl HCI drivers - Fixes to parsing invalid L2CAP config option sizes - Locking fix to bt_accept_enqueue() - Add support for new Marvel sd8977 chipset - Various other smaller fixes & cleanups ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
e8b47b53a1
|
@ -336,7 +336,7 @@ config BT_MRVL
|
||||||
The core driver to support Marvell Bluetooth devices.
|
The core driver to support Marvell Bluetooth devices.
|
||||||
|
|
||||||
This driver is required if you want to support
|
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/8977/8997.
|
||||||
|
|
||||||
Say Y here to compile Marvell Bluetooth driver
|
Say Y here to compile Marvell Bluetooth driver
|
||||||
into the kernel or say M to compile it as module.
|
into the kernel or say M to compile it as module.
|
||||||
|
@ -350,7 +350,7 @@ config BT_MRVL_SDIO
|
||||||
The driver for Marvell Bluetooth chipsets with SDIO interface.
|
The driver for Marvell Bluetooth chipsets with SDIO interface.
|
||||||
|
|
||||||
This driver is required if you want to use Marvell Bluetooth
|
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/SD8977/SD8997
|
||||||
chipsets are supported.
|
chipsets are supported.
|
||||||
|
|
||||||
Say Y here to compile support for Marvell BT-over-SDIO driver
|
Say Y here to compile support for Marvell BT-over-SDIO driver
|
||||||
|
|
|
@ -24,11 +24,9 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <net/bluetooth/bluetooth.h>
|
#include <net/bluetooth/bluetooth.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/gpio.h>
|
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/of_gpio.h>
|
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
|
|
@ -62,13 +62,14 @@ static const struct of_device_id btmrvl_sdio_of_match_table[] = {
|
||||||
static irqreturn_t btmrvl_wake_irq_bt(int irq, void *priv)
|
static irqreturn_t btmrvl_wake_irq_bt(int irq, void *priv)
|
||||||
{
|
{
|
||||||
struct btmrvl_sdio_card *card = priv;
|
struct btmrvl_sdio_card *card = priv;
|
||||||
|
struct device *dev = &card->func->dev;
|
||||||
struct btmrvl_plt_wake_cfg *cfg = card->plt_wake_cfg;
|
struct btmrvl_plt_wake_cfg *cfg = card->plt_wake_cfg;
|
||||||
|
|
||||||
pr_info("%s: wake by bt\n", __func__);
|
dev_info(dev, "wake by bt\n");
|
||||||
cfg->wake_by_bt = true;
|
cfg->wake_by_bt = true;
|
||||||
disable_irq_nosync(irq);
|
disable_irq_nosync(irq);
|
||||||
|
|
||||||
pm_wakeup_event(&card->func->dev, 0);
|
pm_wakeup_event(dev, 0);
|
||||||
pm_system_wakeup();
|
pm_system_wakeup();
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
@ -87,7 +88,7 @@ static int btmrvl_sdio_probe_of(struct device *dev,
|
||||||
|
|
||||||
if (!dev->of_node ||
|
if (!dev->of_node ||
|
||||||
!of_match_node(btmrvl_sdio_of_match_table, dev->of_node)) {
|
!of_match_node(btmrvl_sdio_of_match_table, dev->of_node)) {
|
||||||
pr_err("sdio platform data not available\n");
|
dev_info(dev, "sdio device tree data not available\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,6 +212,29 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = {
|
||||||
.fw_dump_end = 0xea,
|
.fw_dump_end = 0xea,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct btmrvl_sdio_card_reg btmrvl_reg_8977 = {
|
||||||
|
.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_card_reg btmrvl_reg_8997 = {
|
static const struct btmrvl_sdio_card_reg btmrvl_reg_8997 = {
|
||||||
.cfg = 0x00,
|
.cfg = 0x00,
|
||||||
.host_int_mask = 0x08,
|
.host_int_mask = 0x08,
|
||||||
|
@ -279,6 +303,15 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
|
||||||
.supports_fw_dump = true,
|
.supports_fw_dump = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct btmrvl_sdio_device btmrvl_sdio_sd8977 = {
|
||||||
|
.helper = NULL,
|
||||||
|
.firmware = "mrvl/sd8977_uapsta.bin",
|
||||||
|
.reg = &btmrvl_reg_8977,
|
||||||
|
.support_pscan_win_report = true,
|
||||||
|
.sd_blksz_fw_dl = 256,
|
||||||
|
.supports_fw_dump = true,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = {
|
static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = {
|
||||||
.helper = NULL,
|
.helper = NULL,
|
||||||
.firmware = "mrvl/sd8997_uapsta.bin",
|
.firmware = "mrvl/sd8997_uapsta.bin",
|
||||||
|
@ -307,6 +340,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
|
||||||
/* Marvell SD8897 Bluetooth device */
|
/* Marvell SD8897 Bluetooth device */
|
||||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
|
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
|
||||||
.driver_data = (unsigned long)&btmrvl_sdio_sd8897 },
|
.driver_data = (unsigned long)&btmrvl_sdio_sd8897 },
|
||||||
|
/* Marvell SD8977 Bluetooth device */
|
||||||
|
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9146),
|
||||||
|
.driver_data = (unsigned long)&btmrvl_sdio_sd8977 },
|
||||||
/* Marvell SD8997 Bluetooth device */
|
/* Marvell SD8997 Bluetooth device */
|
||||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9142),
|
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9142),
|
||||||
.driver_data = (unsigned long)&btmrvl_sdio_sd8997 },
|
.driver_data = (unsigned long)&btmrvl_sdio_sd8997 },
|
||||||
|
@ -1760,4 +1796,5 @@ MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
|
||||||
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
|
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
|
||||||
MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin");
|
MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin");
|
||||||
MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
|
MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
|
||||||
|
MODULE_FIRMWARE("mrvl/sd8977_uapsta.bin");
|
||||||
MODULE_FIRMWARE("mrvl/sd8997_uapsta.bin");
|
MODULE_FIRMWARE("mrvl/sd8997_uapsta.bin");
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
@ -37,7 +38,17 @@
|
||||||
enum {
|
enum {
|
||||||
MTK_WMT_PATCH_DWNLD = 0x1,
|
MTK_WMT_PATCH_DWNLD = 0x1,
|
||||||
MTK_WMT_FUNC_CTRL = 0x6,
|
MTK_WMT_FUNC_CTRL = 0x6,
|
||||||
MTK_WMT_RST = 0x7
|
MTK_WMT_RST = 0x7,
|
||||||
|
MTK_WMT_SEMAPHORE = 0x17,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BTMTK_WMT_INVALID,
|
||||||
|
BTMTK_WMT_PATCH_UNDONE,
|
||||||
|
BTMTK_WMT_PATCH_DONE,
|
||||||
|
BTMTK_WMT_ON_UNDONE,
|
||||||
|
BTMTK_WMT_ON_DONE,
|
||||||
|
BTMTK_WMT_ON_PROGRESS,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mtk_stp_hdr {
|
struct mtk_stp_hdr {
|
||||||
|
@ -58,6 +69,32 @@ struct mtk_hci_wmt_cmd {
|
||||||
u8 data[256];
|
u8 data[256];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct btmtk_hci_wmt_evt {
|
||||||
|
struct hci_event_hdr hhdr;
|
||||||
|
struct mtk_wmt_hdr whdr;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct btmtk_hci_wmt_evt_funcc {
|
||||||
|
struct btmtk_hci_wmt_evt hwhdr;
|
||||||
|
__be16 status;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct btmtk_tci_sleep {
|
||||||
|
u8 mode;
|
||||||
|
__le16 duration;
|
||||||
|
__le16 host_duration;
|
||||||
|
u8 host_wakeup_pin;
|
||||||
|
u8 time_compensation;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct btmtk_hci_wmt_params {
|
||||||
|
u8 op;
|
||||||
|
u8 flag;
|
||||||
|
u16 dlen;
|
||||||
|
const void *data;
|
||||||
|
u32 *status;
|
||||||
|
};
|
||||||
|
|
||||||
struct btmtkuart_dev {
|
struct btmtkuart_dev {
|
||||||
struct hci_dev *hdev;
|
struct hci_dev *hdev;
|
||||||
struct serdev_device *serdev;
|
struct serdev_device *serdev;
|
||||||
|
@ -68,31 +105,34 @@ struct btmtkuart_dev {
|
||||||
struct sk_buff_head txq;
|
struct sk_buff_head txq;
|
||||||
|
|
||||||
struct sk_buff *rx_skb;
|
struct sk_buff *rx_skb;
|
||||||
|
struct sk_buff *evt_skb;
|
||||||
|
|
||||||
u8 stp_pad[6];
|
u8 stp_pad[6];
|
||||||
u8 stp_cursor;
|
u8 stp_cursor;
|
||||||
u16 stp_dlen;
|
u16 stp_dlen;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mtk_hci_wmt_sync(struct hci_dev *hdev, u8 op, u8 flag, u16 plen,
|
static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
||||||
const void *param)
|
struct btmtk_hci_wmt_params *wmt_params)
|
||||||
{
|
{
|
||||||
struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
|
struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
|
||||||
|
struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc;
|
||||||
|
u32 hlen, status = BTMTK_WMT_INVALID;
|
||||||
|
struct btmtk_hci_wmt_evt *wmt_evt;
|
||||||
struct mtk_hci_wmt_cmd wc;
|
struct mtk_hci_wmt_cmd wc;
|
||||||
struct mtk_wmt_hdr *hdr;
|
struct mtk_wmt_hdr *hdr;
|
||||||
u32 hlen;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
hlen = sizeof(*hdr) + plen;
|
hlen = sizeof(*hdr) + wmt_params->dlen;
|
||||||
if (hlen > 255)
|
if (hlen > 255)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
hdr = (struct mtk_wmt_hdr *)&wc;
|
hdr = (struct mtk_wmt_hdr *)&wc;
|
||||||
hdr->dir = 1;
|
hdr->dir = 1;
|
||||||
hdr->op = op;
|
hdr->op = wmt_params->op;
|
||||||
hdr->dlen = cpu_to_le16(plen + 1);
|
hdr->dlen = cpu_to_le16(wmt_params->dlen + 1);
|
||||||
hdr->flag = flag;
|
hdr->flag = wmt_params->flag;
|
||||||
memcpy(wc.data, param, plen);
|
memcpy(wc.data, wmt_params->data, wmt_params->dlen);
|
||||||
|
|
||||||
set_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
|
set_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
|
||||||
|
|
||||||
|
@ -107,7 +147,7 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev, u8 op, u8 flag, u16 plen,
|
||||||
* Complete as with usual HCI command flow control.
|
* Complete as with usual HCI command flow control.
|
||||||
*
|
*
|
||||||
* After sending the command, wait for BTMTKUART_TX_WAIT_VND_EVT
|
* After sending the command, wait for BTMTKUART_TX_WAIT_VND_EVT
|
||||||
* state to be cleared. The driver speicfic event receive routine
|
* state to be cleared. The driver specific event receive routine
|
||||||
* will clear that state and with that indicate completion of the
|
* will clear that state and with that indicate completion of the
|
||||||
* WMT command.
|
* WMT command.
|
||||||
*/
|
*/
|
||||||
|
@ -115,19 +155,56 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev, u8 op, u8 flag, u16 plen,
|
||||||
TASK_INTERRUPTIBLE, HCI_INIT_TIMEOUT);
|
TASK_INTERRUPTIBLE, HCI_INIT_TIMEOUT);
|
||||||
if (err == -EINTR) {
|
if (err == -EINTR) {
|
||||||
bt_dev_err(hdev, "Execution of wmt command interrupted");
|
bt_dev_err(hdev, "Execution of wmt command interrupted");
|
||||||
|
clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
bt_dev_err(hdev, "Execution of wmt command timed out");
|
bt_dev_err(hdev, "Execution of wmt command timed out");
|
||||||
|
clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
/* Parse and handle the return WMT event */
|
||||||
|
wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data;
|
||||||
|
if (wmt_evt->whdr.op != hdr->op) {
|
||||||
|
bt_dev_err(hdev, "Wrong op received %d expected %d",
|
||||||
|
wmt_evt->whdr.op, hdr->op);
|
||||||
|
err = -EIO;
|
||||||
|
goto err_free_skb;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (wmt_evt->whdr.op) {
|
||||||
|
case MTK_WMT_SEMAPHORE:
|
||||||
|
if (wmt_evt->whdr.flag == 2)
|
||||||
|
status = BTMTK_WMT_PATCH_UNDONE;
|
||||||
|
else
|
||||||
|
status = BTMTK_WMT_PATCH_DONE;
|
||||||
|
break;
|
||||||
|
case MTK_WMT_FUNC_CTRL:
|
||||||
|
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
|
||||||
|
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
|
||||||
|
status = BTMTK_WMT_ON_DONE;
|
||||||
|
else if (be16_to_cpu(wmt_evt_funcc->status) == 0x420)
|
||||||
|
status = BTMTK_WMT_ON_PROGRESS;
|
||||||
|
else
|
||||||
|
status = BTMTK_WMT_ON_UNDONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wmt_params->status)
|
||||||
|
*wmt_params->status = status;
|
||||||
|
|
||||||
|
err_free_skb:
|
||||||
|
kfree_skb(bdev->evt_skb);
|
||||||
|
bdev->evt_skb = NULL;
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mtk_setup_fw(struct hci_dev *hdev)
|
static int mtk_setup_fw(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
|
struct btmtk_hci_wmt_params wmt_params;
|
||||||
const struct firmware *fw;
|
const struct firmware *fw;
|
||||||
const u8 *fw_ptr;
|
const u8 *fw_ptr;
|
||||||
size_t fw_size;
|
size_t fw_size;
|
||||||
|
@ -153,6 +230,9 @@ static int mtk_setup_fw(struct hci_dev *hdev)
|
||||||
fw_ptr += 30;
|
fw_ptr += 30;
|
||||||
flag = 1;
|
flag = 1;
|
||||||
|
|
||||||
|
wmt_params.op = MTK_WMT_PATCH_DWNLD;
|
||||||
|
wmt_params.status = NULL;
|
||||||
|
|
||||||
while (fw_size > 0) {
|
while (fw_size > 0) {
|
||||||
dlen = min_t(int, 250, fw_size);
|
dlen = min_t(int, 250, fw_size);
|
||||||
|
|
||||||
|
@ -162,18 +242,37 @@ static int mtk_setup_fw(struct hci_dev *hdev)
|
||||||
else if (fw_size < fw->size - 30)
|
else if (fw_size < fw->size - 30)
|
||||||
flag = 2;
|
flag = 2;
|
||||||
|
|
||||||
err = mtk_hci_wmt_sync(hdev, MTK_WMT_PATCH_DWNLD, flag, dlen,
|
wmt_params.flag = flag;
|
||||||
fw_ptr);
|
wmt_params.dlen = dlen;
|
||||||
|
wmt_params.data = fw_ptr;
|
||||||
|
|
||||||
|
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
|
bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
|
||||||
err);
|
err);
|
||||||
break;
|
goto free_fw;
|
||||||
}
|
}
|
||||||
|
|
||||||
fw_size -= dlen;
|
fw_size -= dlen;
|
||||||
fw_ptr += dlen;
|
fw_ptr += dlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wmt_params.op = MTK_WMT_RST;
|
||||||
|
wmt_params.flag = 4;
|
||||||
|
wmt_params.dlen = 0;
|
||||||
|
wmt_params.data = NULL;
|
||||||
|
wmt_params.status = NULL;
|
||||||
|
|
||||||
|
/* Activate funciton the firmware providing to */
|
||||||
|
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||||
|
if (err < 0) {
|
||||||
|
bt_dev_err(hdev, "Failed to send wmt rst (%d)", err);
|
||||||
|
goto free_fw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait a few moments for firmware activation done */
|
||||||
|
usleep_range(10000, 12000);
|
||||||
|
|
||||||
free_fw:
|
free_fw:
|
||||||
release_firmware(fw);
|
release_firmware(fw);
|
||||||
return err;
|
return err;
|
||||||
|
@ -192,7 +291,20 @@ static int btmtkuart_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
if (hdr->evt == 0xe4)
|
if (hdr->evt == 0xe4)
|
||||||
hdr->evt = HCI_EV_VENDOR;
|
hdr->evt = HCI_EV_VENDOR;
|
||||||
|
|
||||||
|
/* When someone waits for the WMT event, the skb is being cloned
|
||||||
|
* and being processed the events from there then.
|
||||||
|
*/
|
||||||
|
if (test_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state)) {
|
||||||
|
bdev->evt_skb = skb_clone(skb, GFP_KERNEL);
|
||||||
|
if (!bdev->evt_skb) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = hci_recv_frame(hdev, skb);
|
err = hci_recv_frame(hdev, skb);
|
||||||
|
if (err < 0)
|
||||||
|
goto err_free_skb;
|
||||||
|
|
||||||
if (hdr->evt == HCI_EV_VENDOR) {
|
if (hdr->evt == HCI_EV_VENDOR) {
|
||||||
if (test_and_clear_bit(BTMTKUART_TX_WAIT_VND_EVT,
|
if (test_and_clear_bit(BTMTKUART_TX_WAIT_VND_EVT,
|
||||||
|
@ -203,6 +315,13 @@ static int btmtkuart_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_free_skb:
|
||||||
|
kfree_skb(bdev->evt_skb);
|
||||||
|
bdev->evt_skb = NULL;
|
||||||
|
|
||||||
|
err_out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,42 +584,134 @@ static int btmtkuart_flush(struct hci_dev *hdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int btmtkuart_func_query(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
struct btmtk_hci_wmt_params wmt_params;
|
||||||
|
int status, err;
|
||||||
|
u8 param = 0;
|
||||||
|
|
||||||
|
/* Query whether the function is enabled */
|
||||||
|
wmt_params.op = MTK_WMT_FUNC_CTRL;
|
||||||
|
wmt_params.flag = 4;
|
||||||
|
wmt_params.dlen = sizeof(param);
|
||||||
|
wmt_params.data = ¶m;
|
||||||
|
wmt_params.status = &status;
|
||||||
|
|
||||||
|
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||||
|
if (err < 0) {
|
||||||
|
bt_dev_err(hdev, "Failed to query function status (%d)", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static int btmtkuart_setup(struct hci_dev *hdev)
|
static int btmtkuart_setup(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
|
struct btmtk_hci_wmt_params wmt_params;
|
||||||
|
ktime_t calltime, delta, rettime;
|
||||||
|
struct btmtk_tci_sleep tci_sleep;
|
||||||
|
unsigned long long duration;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int err, status;
|
||||||
u8 param = 0x1;
|
u8 param = 0x1;
|
||||||
int err = 0;
|
|
||||||
|
calltime = ktime_get();
|
||||||
|
|
||||||
|
/* Query whether the firmware is already download */
|
||||||
|
wmt_params.op = MTK_WMT_SEMAPHORE;
|
||||||
|
wmt_params.flag = 1;
|
||||||
|
wmt_params.dlen = 0;
|
||||||
|
wmt_params.data = NULL;
|
||||||
|
wmt_params.status = &status;
|
||||||
|
|
||||||
|
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||||
|
if (err < 0) {
|
||||||
|
bt_dev_err(hdev, "Failed to query firmware status (%d)", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == BTMTK_WMT_PATCH_DONE) {
|
||||||
|
bt_dev_info(hdev, "Firmware already downloaded");
|
||||||
|
goto ignore_setup_fw;
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup a firmware which the device definitely requires */
|
/* Setup a firmware which the device definitely requires */
|
||||||
err = mtk_setup_fw(hdev);
|
err = mtk_setup_fw(hdev);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
/* Activate function the firmware providing to */
|
ignore_setup_fw:
|
||||||
err = mtk_hci_wmt_sync(hdev, MTK_WMT_RST, 0x4, 0, 0);
|
/* Query whether the device is already enabled */
|
||||||
if (err < 0) {
|
err = readx_poll_timeout(btmtkuart_func_query, hdev, status,
|
||||||
bt_dev_err(hdev, "Failed to send wmt rst (%d)", err);
|
status < 0 || status != BTMTK_WMT_ON_PROGRESS,
|
||||||
|
2000, 5000000);
|
||||||
|
/* -ETIMEDOUT happens */
|
||||||
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
/* The other errors happen in btusb_mtk_func_query */
|
||||||
|
if (status < 0)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if (status == BTMTK_WMT_ON_DONE) {
|
||||||
|
bt_dev_info(hdev, "function already on");
|
||||||
|
goto ignore_func_on;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable Bluetooth protocol */
|
/* Enable Bluetooth protocol */
|
||||||
err = mtk_hci_wmt_sync(hdev, MTK_WMT_FUNC_CTRL, 0x0, sizeof(param),
|
wmt_params.op = MTK_WMT_FUNC_CTRL;
|
||||||
¶m);
|
wmt_params.flag = 0;
|
||||||
|
wmt_params.dlen = sizeof(param);
|
||||||
|
wmt_params.data = ¶m;
|
||||||
|
wmt_params.status = NULL;
|
||||||
|
|
||||||
|
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
|
bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ignore_func_on:
|
||||||
|
/* Apply the low power environment setup */
|
||||||
|
tci_sleep.mode = 0x5;
|
||||||
|
tci_sleep.duration = cpu_to_le16(0x640);
|
||||||
|
tci_sleep.host_duration = cpu_to_le16(0x640);
|
||||||
|
tci_sleep.host_wakeup_pin = 0;
|
||||||
|
tci_sleep.time_compensation = 0;
|
||||||
|
|
||||||
|
skb = __hci_cmd_sync(hdev, 0xfc7a, sizeof(tci_sleep), &tci_sleep,
|
||||||
|
HCI_INIT_TIMEOUT);
|
||||||
|
if (IS_ERR(skb)) {
|
||||||
|
err = PTR_ERR(skb);
|
||||||
|
bt_dev_err(hdev, "Failed to apply low power setting (%d)", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
kfree_skb(skb);
|
||||||
|
|
||||||
|
rettime = ktime_get();
|
||||||
|
delta = ktime_sub(rettime, calltime);
|
||||||
|
duration = (unsigned long long)ktime_to_ns(delta) >> 10;
|
||||||
|
|
||||||
|
bt_dev_info(hdev, "Device setup in %llu usecs", duration);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int btmtkuart_shutdown(struct hci_dev *hdev)
|
static int btmtkuart_shutdown(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
|
struct btmtk_hci_wmt_params wmt_params;
|
||||||
u8 param = 0x0;
|
u8 param = 0x0;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* Disable the device */
|
/* Disable the device */
|
||||||
err = mtk_hci_wmt_sync(hdev, MTK_WMT_FUNC_CTRL, 0x0, sizeof(param),
|
wmt_params.op = MTK_WMT_FUNC_CTRL;
|
||||||
¶m);
|
wmt_params.flag = 0;
|
||||||
|
wmt_params.dlen = sizeof(param);
|
||||||
|
wmt_params.data = ¶m;
|
||||||
|
wmt_params.status = NULL;
|
||||||
|
|
||||||
|
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
|
bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -391,6 +391,25 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(qca_uart_setup);
|
EXPORT_SYMBOL_GPL(qca_uart_setup);
|
||||||
|
|
||||||
|
int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, 6, bdaddr,
|
||||||
|
HCI_EV_VENDOR, HCI_INIT_TIMEOUT);
|
||||||
|
if (IS_ERR(skb)) {
|
||||||
|
err = PTR_ERR(skb);
|
||||||
|
bt_dev_err(hdev, "QCA Change address cmd failed (%d)", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree_skb(skb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(qca_set_bdaddr);
|
||||||
|
|
||||||
MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>");
|
MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>");
|
||||||
MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION);
|
MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION);
|
||||||
MODULE_VERSION(VERSION);
|
MODULE_VERSION(VERSION);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#define EDL_PATCH_CMD_OPCODE (0xFC00)
|
#define EDL_PATCH_CMD_OPCODE (0xFC00)
|
||||||
#define EDL_NVM_ACCESS_OPCODE (0xFC0B)
|
#define EDL_NVM_ACCESS_OPCODE (0xFC0B)
|
||||||
|
#define EDL_WRITE_BD_ADDR_OPCODE (0xFC14)
|
||||||
#define EDL_PATCH_CMD_LEN (1)
|
#define EDL_PATCH_CMD_LEN (1)
|
||||||
#define EDL_PATCH_VER_REQ_CMD (0x19)
|
#define EDL_PATCH_VER_REQ_CMD (0x19)
|
||||||
#define EDL_PATCH_TLV_REQ_CMD (0x1E)
|
#define EDL_PATCH_TLV_REQ_CMD (0x1E)
|
||||||
|
@ -140,7 +141,7 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr);
|
||||||
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||||
enum qca_btsoc_type soc_type, u32 soc_ver);
|
enum qca_btsoc_type soc_type, u32 soc_ver);
|
||||||
int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version);
|
int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version);
|
||||||
|
int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||||
|
@ -159,4 +160,9 @@ static inline int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -552,10 +552,9 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
|
||||||
hdev->bus);
|
hdev->bus);
|
||||||
|
|
||||||
if (!btrtl_dev->ic_info) {
|
if (!btrtl_dev->ic_info) {
|
||||||
rtl_dev_err(hdev, "rtl: unknown IC info, lmp subver %04x, hci rev %04x, hci ver %04x",
|
rtl_dev_info(hdev, "rtl: unknown IC info, lmp subver %04x, hci rev %04x, hci ver %04x",
|
||||||
lmp_subver, hci_rev, hci_ver);
|
lmp_subver, hci_rev, hci_ver);
|
||||||
ret = -EINVAL;
|
return btrtl_dev;
|
||||||
goto err_free;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (btrtl_dev->ic_info->has_rom_version) {
|
if (btrtl_dev->ic_info->has_rom_version) {
|
||||||
|
@ -610,6 +609,11 @@ int btrtl_download_firmware(struct hci_dev *hdev,
|
||||||
* standard btusb. Once that firmware is uploaded, the subver changes
|
* standard btusb. Once that firmware is uploaded, the subver changes
|
||||||
* to a different value.
|
* to a different value.
|
||||||
*/
|
*/
|
||||||
|
if (!btrtl_dev->ic_info) {
|
||||||
|
rtl_dev_info(hdev, "rtl: assuming no firmware upload needed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
switch (btrtl_dev->ic_info->lmp_subver) {
|
switch (btrtl_dev->ic_info->lmp_subver) {
|
||||||
case RTL_ROM_LMP_8723A:
|
case RTL_ROM_LMP_8723A:
|
||||||
case RTL_ROM_LMP_3499:
|
case RTL_ROM_LMP_3499:
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
#include <net/bluetooth/bluetooth.h>
|
#include <net/bluetooth/bluetooth.h>
|
||||||
|
@ -439,6 +440,7 @@ static const struct dmi_system_id btusb_needs_reset_resume_table[] = {
|
||||||
#define BTUSB_BOOTING 9
|
#define BTUSB_BOOTING 9
|
||||||
#define BTUSB_DIAG_RUNNING 10
|
#define BTUSB_DIAG_RUNNING 10
|
||||||
#define BTUSB_OOB_WAKE_ENABLED 11
|
#define BTUSB_OOB_WAKE_ENABLED 11
|
||||||
|
#define BTUSB_HW_RESET_ACTIVE 12
|
||||||
|
|
||||||
struct btusb_data {
|
struct btusb_data {
|
||||||
struct hci_dev *hdev;
|
struct hci_dev *hdev;
|
||||||
|
@ -476,6 +478,8 @@ struct btusb_data {
|
||||||
struct usb_endpoint_descriptor *diag_tx_ep;
|
struct usb_endpoint_descriptor *diag_tx_ep;
|
||||||
struct usb_endpoint_descriptor *diag_rx_ep;
|
struct usb_endpoint_descriptor *diag_rx_ep;
|
||||||
|
|
||||||
|
struct gpio_desc *reset_gpio;
|
||||||
|
|
||||||
__u8 cmdreq_type;
|
__u8 cmdreq_type;
|
||||||
__u8 cmdreq;
|
__u8 cmdreq;
|
||||||
|
|
||||||
|
@ -489,8 +493,41 @@ struct btusb_data {
|
||||||
int (*setup_on_usb)(struct hci_dev *hdev);
|
int (*setup_on_usb)(struct hci_dev *hdev);
|
||||||
|
|
||||||
int oob_wake_irq; /* irq for out-of-band wake-on-bt */
|
int oob_wake_irq; /* irq for out-of-band wake-on-bt */
|
||||||
|
unsigned cmd_timeout_cnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void btusb_intel_cmd_timeout(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||||
|
struct gpio_desc *reset_gpio = data->reset_gpio;
|
||||||
|
|
||||||
|
if (++data->cmd_timeout_cnt < 5)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!reset_gpio) {
|
||||||
|
bt_dev_err(hdev, "No way to reset. Ignoring and continuing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Toggle the hard reset line if the platform provides one. The reset
|
||||||
|
* is going to yank the device off the USB and then replug. So doing
|
||||||
|
* once is enough. The cleanup is handled correctly on the way out
|
||||||
|
* (standard USB disconnect), and the new device is detected cleanly
|
||||||
|
* and bound to the driver again like it should be.
|
||||||
|
*/
|
||||||
|
if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
|
||||||
|
bt_dev_err(hdev, "last reset failed? Not resetting again");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_dev_err(hdev, "Initiating HW reset via gpio");
|
||||||
|
gpiod_set_value_cansleep(reset_gpio, 1);
|
||||||
|
msleep(100);
|
||||||
|
gpiod_set_value_cansleep(reset_gpio, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void btusb_free_frags(struct btusb_data *data)
|
static inline void btusb_free_frags(struct btusb_data *data)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -2397,6 +2434,24 @@ static int btusb_shutdown_intel(struct hci_dev *hdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int btusb_shutdown_intel_new(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
/* Send HCI Reset to the controller to stop any BT activity which
|
||||||
|
* were triggered. This will help to save power and maintain the
|
||||||
|
* sync b/w Host and controller
|
||||||
|
*/
|
||||||
|
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
|
||||||
|
if (IS_ERR(skb)) {
|
||||||
|
bt_dev_err(hdev, "HCI reset during shutdown failed");
|
||||||
|
return PTR_ERR(skb);
|
||||||
|
}
|
||||||
|
kfree_skb(skb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
/* Configure an out-of-band gpio as wake-up pin, if specified in device tree */
|
/* Configure an out-of-band gpio as wake-up pin, if specified in device tree */
|
||||||
static int marvell_config_oob_wake(struct hci_dev *hdev)
|
static int marvell_config_oob_wake(struct hci_dev *hdev)
|
||||||
|
@ -2915,6 +2970,7 @@ static int btusb_probe(struct usb_interface *intf,
|
||||||
const struct usb_device_id *id)
|
const struct usb_device_id *id)
|
||||||
{
|
{
|
||||||
struct usb_endpoint_descriptor *ep_desc;
|
struct usb_endpoint_descriptor *ep_desc;
|
||||||
|
struct gpio_desc *reset_gpio;
|
||||||
struct btusb_data *data;
|
struct btusb_data *data;
|
||||||
struct hci_dev *hdev;
|
struct hci_dev *hdev;
|
||||||
unsigned ifnum_base;
|
unsigned ifnum_base;
|
||||||
|
@ -3028,6 +3084,15 @@ static int btusb_probe(struct usb_interface *intf,
|
||||||
|
|
||||||
SET_HCIDEV_DEV(hdev, &intf->dev);
|
SET_HCIDEV_DEV(hdev, &intf->dev);
|
||||||
|
|
||||||
|
reset_gpio = gpiod_get_optional(&data->udev->dev, "reset",
|
||||||
|
GPIOD_OUT_LOW);
|
||||||
|
if (IS_ERR(reset_gpio)) {
|
||||||
|
err = PTR_ERR(reset_gpio);
|
||||||
|
goto out_free_dev;
|
||||||
|
} else if (reset_gpio) {
|
||||||
|
data->reset_gpio = reset_gpio;
|
||||||
|
}
|
||||||
|
|
||||||
hdev->open = btusb_open;
|
hdev->open = btusb_open;
|
||||||
hdev->close = btusb_close;
|
hdev->close = btusb_close;
|
||||||
hdev->flush = btusb_flush;
|
hdev->flush = btusb_flush;
|
||||||
|
@ -3082,6 +3147,7 @@ static int btusb_probe(struct usb_interface *intf,
|
||||||
hdev->shutdown = btusb_shutdown_intel;
|
hdev->shutdown = btusb_shutdown_intel;
|
||||||
hdev->set_diag = btintel_set_diag_mfg;
|
hdev->set_diag = btintel_set_diag_mfg;
|
||||||
hdev->set_bdaddr = btintel_set_bdaddr;
|
hdev->set_bdaddr = btintel_set_bdaddr;
|
||||||
|
hdev->cmd_timeout = btusb_intel_cmd_timeout;
|
||||||
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
|
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
|
||||||
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
||||||
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
|
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
|
||||||
|
@ -3091,9 +3157,11 @@ static int btusb_probe(struct usb_interface *intf,
|
||||||
hdev->manufacturer = 2;
|
hdev->manufacturer = 2;
|
||||||
hdev->send = btusb_send_frame_intel;
|
hdev->send = btusb_send_frame_intel;
|
||||||
hdev->setup = btusb_setup_intel_new;
|
hdev->setup = btusb_setup_intel_new;
|
||||||
|
hdev->shutdown = btusb_shutdown_intel_new;
|
||||||
hdev->hw_error = btintel_hw_error;
|
hdev->hw_error = btintel_hw_error;
|
||||||
hdev->set_diag = btintel_set_diag;
|
hdev->set_diag = btintel_set_diag;
|
||||||
hdev->set_bdaddr = btintel_set_bdaddr;
|
hdev->set_bdaddr = btintel_set_bdaddr;
|
||||||
|
hdev->cmd_timeout = btusb_intel_cmd_timeout;
|
||||||
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
|
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
|
||||||
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
||||||
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
|
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
|
||||||
|
@ -3226,6 +3294,8 @@ static int btusb_probe(struct usb_interface *intf,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_free_dev:
|
out_free_dev:
|
||||||
|
if (data->reset_gpio)
|
||||||
|
gpiod_put(data->reset_gpio);
|
||||||
hci_free_dev(hdev);
|
hci_free_dev(hdev);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -3269,6 +3339,9 @@ static void btusb_disconnect(struct usb_interface *intf)
|
||||||
if (data->oob_wake_irq)
|
if (data->oob_wake_irq)
|
||||||
device_init_wakeup(&data->udev->dev, false);
|
device_init_wakeup(&data->udev->dev, false);
|
||||||
|
|
||||||
|
if (data->reset_gpio)
|
||||||
|
gpiod_put(data->reset_gpio);
|
||||||
|
|
||||||
hci_free_dev(hdev);
|
hci_free_dev(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,12 +60,13 @@ static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev,
|
||||||
const struct h4_recv_pkt *pkts,
|
const struct h4_recv_pkt *pkts,
|
||||||
int pkts_count)
|
int pkts_count)
|
||||||
{
|
{
|
||||||
|
/* Check for error from previous call */
|
||||||
|
if (IS_ERR(skb))
|
||||||
|
skb = NULL;
|
||||||
|
|
||||||
while (count) {
|
while (count) {
|
||||||
int i, len;
|
int i, len;
|
||||||
|
|
||||||
if (!count)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!skb) {
|
if (!skb) {
|
||||||
for (i = 0; i < pkts_count; i++) {
|
for (i = 0; i < pkts_count; i++) {
|
||||||
if (buffer[0] != (&pkts[i])->type)
|
if (buffer[0] != (&pkts[i])->type)
|
||||||
|
|
|
@ -174,6 +174,10 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
|
||||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||||
u8 alignment = hu->alignment ? hu->alignment : 1;
|
u8 alignment = hu->alignment ? hu->alignment : 1;
|
||||||
|
|
||||||
|
/* Check for error from previous call */
|
||||||
|
if (IS_ERR(skb))
|
||||||
|
skb = NULL;
|
||||||
|
|
||||||
while (count) {
|
while (count) {
|
||||||
int i, len;
|
int i, len;
|
||||||
|
|
||||||
|
|
|
@ -207,11 +207,11 @@ void hci_uart_init_work(struct work_struct *work)
|
||||||
err = hci_register_dev(hu->hdev);
|
err = hci_register_dev(hu->hdev);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
BT_ERR("Can't register HCI device");
|
BT_ERR("Can't register HCI device");
|
||||||
|
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||||
|
hu->proto->close(hu);
|
||||||
hdev = hu->hdev;
|
hdev = hu->hdev;
|
||||||
hu->hdev = NULL;
|
hu->hdev = NULL;
|
||||||
hci_free_dev(hdev);
|
hci_free_dev(hdev);
|
||||||
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
|
||||||
hu->proto->close(hu);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -616,6 +616,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
|
||||||
static int hci_uart_register_dev(struct hci_uart *hu)
|
static int hci_uart_register_dev(struct hci_uart *hu)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev;
|
struct hci_dev *hdev;
|
||||||
|
int err;
|
||||||
|
|
||||||
BT_DBG("");
|
BT_DBG("");
|
||||||
|
|
||||||
|
@ -659,11 +660,22 @@ static int hci_uart_register_dev(struct hci_uart *hu)
|
||||||
else
|
else
|
||||||
hdev->dev_type = HCI_PRIMARY;
|
hdev->dev_type = HCI_PRIMARY;
|
||||||
|
|
||||||
|
/* Only call open() for the protocol after hdev is fully initialized as
|
||||||
|
* open() (or a timer/workqueue it starts) may attempt to reference it.
|
||||||
|
*/
|
||||||
|
err = hu->proto->open(hu);
|
||||||
|
if (err) {
|
||||||
|
hu->hdev = NULL;
|
||||||
|
hci_free_dev(hdev);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
|
if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (hci_register_dev(hdev) < 0) {
|
if (hci_register_dev(hdev) < 0) {
|
||||||
BT_ERR("Can't register HCI device");
|
BT_ERR("Can't register HCI device");
|
||||||
|
hu->proto->close(hu);
|
||||||
hu->hdev = NULL;
|
hu->hdev = NULL;
|
||||||
hci_free_dev(hdev);
|
hci_free_dev(hdev);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -683,17 +695,12 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
|
||||||
if (!p)
|
if (!p)
|
||||||
return -EPROTONOSUPPORT;
|
return -EPROTONOSUPPORT;
|
||||||
|
|
||||||
err = p->open(hu);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
hu->proto = p;
|
hu->proto = p;
|
||||||
set_bit(HCI_UART_PROTO_READY, &hu->flags);
|
set_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||||
|
|
||||||
err = hci_uart_register_dev(hu);
|
err = hci_uart_register_dev(hu);
|
||||||
if (err) {
|
if (err) {
|
||||||
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||||
p->close(hu);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
#define IBS_WAKE_RETRANS_TIMEOUT_MS 100
|
#define IBS_WAKE_RETRANS_TIMEOUT_MS 100
|
||||||
#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
|
||||||
|
#define POWER_PULSE_TRANS_TIMEOUT_MS 100
|
||||||
|
|
||||||
/* susclk rate */
|
/* susclk rate */
|
||||||
#define SUSCLK_RATE_32KHZ 32768
|
#define SUSCLK_RATE_32KHZ 32768
|
||||||
|
@ -770,16 +771,17 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
||||||
/* Prepend skb with frame type */
|
/* Prepend skb with frame type */
|
||||||
memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
|
memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&qca->hci_ibs_lock, flags);
|
||||||
|
|
||||||
/* Don't go to sleep in middle of patch download or
|
/* Don't go to sleep in middle of patch download or
|
||||||
* Out-Of-Band(GPIOs control) sleep is selected.
|
* Out-Of-Band(GPIOs control) sleep is selected.
|
||||||
*/
|
*/
|
||||||
if (!test_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags)) {
|
if (!test_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags)) {
|
||||||
skb_queue_tail(&qca->txq, skb);
|
skb_queue_tail(&qca->txq, skb);
|
||||||
|
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&qca->hci_ibs_lock, flags);
|
|
||||||
|
|
||||||
/* Act according to current state */
|
/* Act according to current state */
|
||||||
switch (qca->tx_ibs_state) {
|
switch (qca->tx_ibs_state) {
|
||||||
case HCI_IBS_TX_AWAKE:
|
case HCI_IBS_TX_AWAKE:
|
||||||
|
@ -963,7 +965,6 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
|
||||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||||
struct qca_data *qca = hu->priv;
|
struct qca_data *qca = hu->priv;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct qca_serdev *qcadev;
|
|
||||||
u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
|
u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 };
|
||||||
|
|
||||||
if (baudrate > QCA_BAUDRATE_3200000)
|
if (baudrate > QCA_BAUDRATE_3200000)
|
||||||
|
@ -977,13 +978,6 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disabling hardware flow control is mandatory while
|
|
||||||
* sending change baudrate request to wcn3990 SoC.
|
|
||||||
*/
|
|
||||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
|
||||||
if (qcadev->btsoc_type == QCA_WCN3990)
|
|
||||||
hci_uart_set_flow_control(hu, true);
|
|
||||||
|
|
||||||
/* Assign commands to change baudrate and packet type. */
|
/* Assign commands to change baudrate and packet type. */
|
||||||
skb_put_data(skb, cmd, sizeof(cmd));
|
skb_put_data(skb, cmd, sizeof(cmd));
|
||||||
hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
|
hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
|
||||||
|
@ -999,9 +993,6 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
|
||||||
schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
|
schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS));
|
||||||
set_current_state(TASK_RUNNING);
|
set_current_state(TASK_RUNNING);
|
||||||
|
|
||||||
if (qcadev->btsoc_type == QCA_WCN3990)
|
|
||||||
hci_uart_set_flow_control(hu, false);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1013,11 +1004,10 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed)
|
||||||
hci_uart_set_baudrate(hu, speed);
|
hci_uart_set_baudrate(hu, speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qca_send_power_pulse(struct hci_dev *hdev, u8 cmd)
|
static int qca_send_power_pulse(struct hci_uart *hu, u8 cmd)
|
||||||
{
|
{
|
||||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
int ret;
|
||||||
struct qca_data *qca = hu->priv;
|
int timeout = msecs_to_jiffies(POWER_PULSE_TRANS_TIMEOUT_MS);
|
||||||
struct sk_buff *skb;
|
|
||||||
|
|
||||||
/* These power pulses are single byte command which are sent
|
/* These power pulses are single byte command which are sent
|
||||||
* at required baudrate to wcn3990. On wcn3990, we have an external
|
* at required baudrate to wcn3990. On wcn3990, we have an external
|
||||||
|
@ -1029,19 +1019,17 @@ static int qca_send_power_pulse(struct hci_dev *hdev, u8 cmd)
|
||||||
* save power. Disabling hardware flow control is mandatory while
|
* save power. Disabling hardware flow control is mandatory while
|
||||||
* sending power pulses to SoC.
|
* sending power pulses to SoC.
|
||||||
*/
|
*/
|
||||||
bt_dev_dbg(hdev, "sending power pulse %02x to SoC", cmd);
|
bt_dev_dbg(hu->hdev, "sending power pulse %02x to controller", cmd);
|
||||||
|
|
||||||
skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
|
|
||||||
if (!skb)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
|
serdev_device_write_flush(hu->serdev);
|
||||||
hci_uart_set_flow_control(hu, true);
|
hci_uart_set_flow_control(hu, true);
|
||||||
|
ret = serdev_device_write_buf(hu->serdev, &cmd, sizeof(cmd));
|
||||||
|
if (ret < 0) {
|
||||||
|
bt_dev_err(hu->hdev, "failed to send power pulse %02x", cmd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
skb_put_u8(skb, cmd);
|
serdev_device_wait_until_sent(hu->serdev, timeout);
|
||||||
hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
|
|
||||||
|
|
||||||
skb_queue_tail(&qca->txq, skb);
|
|
||||||
hci_uart_tx_wakeup(hu);
|
|
||||||
|
|
||||||
/* Wait for 100 uS for SoC to settle down */
|
/* Wait for 100 uS for SoC to settle down */
|
||||||
usleep_range(100, 200);
|
usleep_range(100, 200);
|
||||||
|
@ -1091,7 +1079,8 @@ static int qca_check_speeds(struct hci_uart *hu)
|
||||||
static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
|
static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
|
||||||
{
|
{
|
||||||
unsigned int speed, qca_baudrate;
|
unsigned int speed, qca_baudrate;
|
||||||
int ret;
|
struct qca_serdev *qcadev;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (speed_type == QCA_INIT_SPEED) {
|
if (speed_type == QCA_INIT_SPEED) {
|
||||||
speed = qca_get_speed(hu, QCA_INIT_SPEED);
|
speed = qca_get_speed(hu, QCA_INIT_SPEED);
|
||||||
|
@ -1102,21 +1091,31 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
|
||||||
if (!speed)
|
if (!speed)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Disable flow control for wcn3990 to deassert RTS while
|
||||||
|
* changing the baudrate of chip and host.
|
||||||
|
*/
|
||||||
|
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||||
|
if (qcadev->btsoc_type == QCA_WCN3990)
|
||||||
|
hci_uart_set_flow_control(hu, true);
|
||||||
|
|
||||||
qca_baudrate = qca_get_baudrate_value(speed);
|
qca_baudrate = qca_get_baudrate_value(speed);
|
||||||
bt_dev_dbg(hu->hdev, "Set UART speed to %d", speed);
|
bt_dev_dbg(hu->hdev, "Set UART speed to %d", speed);
|
||||||
ret = qca_set_baudrate(hu->hdev, qca_baudrate);
|
ret = qca_set_baudrate(hu->hdev, qca_baudrate);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto error;
|
||||||
|
|
||||||
host_set_baudrate(hu, speed);
|
host_set_baudrate(hu, speed);
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (qcadev->btsoc_type == QCA_WCN3990)
|
||||||
|
hci_uart_set_flow_control(hu, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qca_wcn3990_init(struct hci_uart *hu)
|
static int qca_wcn3990_init(struct hci_uart *hu)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev = hu->hdev;
|
|
||||||
struct qca_serdev *qcadev;
|
struct qca_serdev *qcadev;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1139,12 +1138,12 @@ static int qca_wcn3990_init(struct hci_uart *hu)
|
||||||
|
|
||||||
/* Forcefully enable wcn3990 to enter in to boot mode. */
|
/* Forcefully enable wcn3990 to enter in to boot mode. */
|
||||||
host_set_baudrate(hu, 2400);
|
host_set_baudrate(hu, 2400);
|
||||||
ret = qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE);
|
ret = qca_send_power_pulse(hu, QCA_WCN3990_POWEROFF_PULSE);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
qca_set_speed(hu, QCA_INIT_SPEED);
|
qca_set_speed(hu, QCA_INIT_SPEED);
|
||||||
ret = qca_send_power_pulse(hdev, QCA_WCN3990_POWERON_PULSE);
|
ret = qca_send_power_pulse(hu, QCA_WCN3990_POWERON_PULSE);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -1241,6 +1240,9 @@ static int qca_setup(struct hci_uart *hu)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup bdaddr */
|
/* Setup bdaddr */
|
||||||
|
if (qcadev->btsoc_type == QCA_WCN3990)
|
||||||
|
hu->hdev->set_bdaddr = qca_set_bdaddr;
|
||||||
|
else
|
||||||
hu->hdev->set_bdaddr = qca_set_bdaddr_rome;
|
hu->hdev->set_bdaddr = qca_set_bdaddr_rome;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1274,13 +1276,20 @@ static const struct qca_vreg_data qca_soc_data = {
|
||||||
|
|
||||||
static void qca_power_shutdown(struct hci_uart *hu)
|
static void qca_power_shutdown(struct hci_uart *hu)
|
||||||
{
|
{
|
||||||
struct serdev_device *serdev = hu->serdev;
|
struct qca_data *qca = hu->priv;
|
||||||
unsigned char cmd = QCA_WCN3990_POWEROFF_PULSE;
|
unsigned long flags;
|
||||||
|
|
||||||
|
/* From this point we go into power off state. But serial port is
|
||||||
|
* still open, stop queueing the IBS data and flush all the buffered
|
||||||
|
* data in skb's.
|
||||||
|
*/
|
||||||
|
spin_lock_irqsave(&qca->hci_ibs_lock, flags);
|
||||||
|
clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
|
||||||
|
qca_flush(hu);
|
||||||
|
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
|
||||||
|
|
||||||
host_set_baudrate(hu, 2400);
|
host_set_baudrate(hu, 2400);
|
||||||
hci_uart_set_flow_control(hu, true);
|
qca_send_power_pulse(hu, QCA_WCN3990_POWEROFF_PULSE);
|
||||||
serdev_device_write_buf(serdev, &cmd, sizeof(cmd));
|
|
||||||
hci_uart_set_flow_control(hu, false);
|
|
||||||
qca_power_setup(hu, false);
|
qca_power_setup(hu, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,42 +139,16 @@ static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
|
||||||
return acpi_find_child_device(parent, raw, false);
|
return acpi_find_child_device(parent, raw, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct acpi_device *usb_acpi_find_companion(struct device *dev)
|
static struct acpi_device *
|
||||||
|
usb_acpi_get_companion_for_port(struct usb_port *port_dev)
|
||||||
{
|
{
|
||||||
struct usb_device *udev;
|
struct usb_device *udev;
|
||||||
struct acpi_device *adev;
|
struct acpi_device *adev;
|
||||||
acpi_handle *parent_handle;
|
acpi_handle *parent_handle;
|
||||||
|
int port1;
|
||||||
/*
|
|
||||||
* In the ACPI DSDT table, only usb root hub and usb ports are
|
|
||||||
* acpi device nodes. The hierarchy like following.
|
|
||||||
* Device (EHC1)
|
|
||||||
* Device (HUBN)
|
|
||||||
* Device (PR01)
|
|
||||||
* Device (PR11)
|
|
||||||
* Device (PR12)
|
|
||||||
* Device (PR13)
|
|
||||||
* ...
|
|
||||||
* So all binding process is divided into two parts. binding
|
|
||||||
* root hub and usb ports.
|
|
||||||
*/
|
|
||||||
if (is_usb_device(dev)) {
|
|
||||||
udev = to_usb_device(dev);
|
|
||||||
if (udev->parent)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* root hub is only child (_ADR=0) under its parent, the HC */
|
|
||||||
adev = ACPI_COMPANION(dev->parent);
|
|
||||||
return acpi_find_child_device(adev, 0, false);
|
|
||||||
} else if (is_usb_port(dev)) {
|
|
||||||
struct usb_port *port_dev = to_usb_port(dev);
|
|
||||||
int port1 = port_dev->portnum;
|
|
||||||
struct acpi_pld_info *pld;
|
|
||||||
acpi_handle *handle;
|
|
||||||
acpi_status status;
|
|
||||||
|
|
||||||
/* Get the struct usb_device point of port's hub */
|
/* Get the struct usb_device point of port's hub */
|
||||||
udev = to_usb_device(dev->parent->parent);
|
udev = to_usb_device(port_dev->dev.parent->parent);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The root hub ports' parent is the root hub. The non-root-hub
|
* The root hub ports' parent is the root hub. The non-root-hub
|
||||||
|
@ -182,43 +156,106 @@ static struct acpi_device *usb_acpi_find_companion(struct device *dev)
|
||||||
* connected to.
|
* connected to.
|
||||||
*/
|
*/
|
||||||
if (!udev->parent) {
|
if (!udev->parent) {
|
||||||
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
adev = ACPI_COMPANION(&udev->dev);
|
||||||
int raw;
|
port1 = usb_hcd_find_raw_port_number(bus_to_hcd(udev->bus),
|
||||||
|
port_dev->portnum);
|
||||||
raw = usb_hcd_find_raw_port_number(hcd, port1);
|
|
||||||
|
|
||||||
adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev),
|
|
||||||
raw);
|
|
||||||
|
|
||||||
if (!adev)
|
|
||||||
return NULL;
|
|
||||||
} else {
|
} else {
|
||||||
parent_handle =
|
parent_handle = usb_get_hub_port_acpi_handle(udev->parent,
|
||||||
usb_get_hub_port_acpi_handle(udev->parent,
|
|
||||||
udev->portnum);
|
udev->portnum);
|
||||||
if (!parent_handle)
|
if (!parent_handle)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
acpi_bus_get_device(parent_handle, &adev);
|
acpi_bus_get_device(parent_handle, &adev);
|
||||||
|
port1 = port_dev->portnum;
|
||||||
|
}
|
||||||
|
|
||||||
adev = usb_acpi_find_port(adev, port1);
|
return usb_acpi_find_port(adev, port1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct acpi_device *
|
||||||
|
usb_acpi_find_companion_for_port(struct usb_port *port_dev)
|
||||||
|
{
|
||||||
|
struct acpi_device *adev;
|
||||||
|
struct acpi_pld_info *pld;
|
||||||
|
acpi_handle *handle;
|
||||||
|
acpi_status status;
|
||||||
|
|
||||||
|
adev = usb_acpi_get_companion_for_port(port_dev);
|
||||||
if (!adev)
|
if (!adev)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
handle = adev->handle;
|
handle = adev->handle;
|
||||||
status = acpi_get_physical_device_location(handle, &pld);
|
status = acpi_get_physical_device_location(handle, &pld);
|
||||||
if (ACPI_FAILURE(status) || !pld)
|
if (!ACPI_FAILURE(status) && pld) {
|
||||||
return adev;
|
|
||||||
|
|
||||||
port_dev->location = USB_ACPI_LOCATION_VALID
|
port_dev->location = USB_ACPI_LOCATION_VALID
|
||||||
| pld->group_token << 8 | pld->group_position;
|
| pld->group_token << 8 | pld->group_position;
|
||||||
port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
|
port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
|
||||||
ACPI_FREE(pld);
|
ACPI_FREE(pld);
|
||||||
|
}
|
||||||
|
|
||||||
return adev;
|
return adev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct acpi_device *
|
||||||
|
usb_acpi_find_companion_for_device(struct usb_device *udev)
|
||||||
|
{
|
||||||
|
struct acpi_device *adev;
|
||||||
|
struct usb_port *port_dev;
|
||||||
|
struct usb_hub *hub;
|
||||||
|
|
||||||
|
if (!udev->parent) {
|
||||||
|
/* root hub is only child (_ADR=0) under its parent, the HC */
|
||||||
|
adev = ACPI_COMPANION(udev->dev.parent);
|
||||||
|
return acpi_find_child_device(adev, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
hub = usb_hub_to_struct_hub(udev->parent);
|
||||||
|
if (!hub)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an embedded USB device connected to a port and such
|
||||||
|
* devices share port's ACPI companion.
|
||||||
|
*/
|
||||||
|
port_dev = hub->ports[udev->portnum - 1];
|
||||||
|
return usb_acpi_get_companion_for_port(port_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct acpi_device *usb_acpi_find_companion(struct device *dev)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The USB hierarchy like following:
|
||||||
|
*
|
||||||
|
* Device (EHC1)
|
||||||
|
* Device (HUBN)
|
||||||
|
* Device (PR01)
|
||||||
|
* Device (PR11)
|
||||||
|
* Device (PR12)
|
||||||
|
* Device (FN12)
|
||||||
|
* Device (FN13)
|
||||||
|
* Device (PR13)
|
||||||
|
* ...
|
||||||
|
* where HUBN is root hub, and PRNN are USB ports and devices
|
||||||
|
* connected to them, and FNNN are individualk functions for
|
||||||
|
* connected composite USB devices. PRNN and FNNN may contain
|
||||||
|
* _CRS and other methods describing sideband resources for
|
||||||
|
* the connected device.
|
||||||
|
*
|
||||||
|
* On the kernel side both root hub and embedded USB devices are
|
||||||
|
* represented as instances of usb_device structure, and ports
|
||||||
|
* are represented as usb_port structures, so the whole process
|
||||||
|
* is split into 2 parts: finding companions for devices and
|
||||||
|
* finding companions for ports.
|
||||||
|
*
|
||||||
|
* Note that we do not handle individual functions of composite
|
||||||
|
* devices yet, for that we would need to assign companions to
|
||||||
|
* devices corresponding to USB interfaces.
|
||||||
|
*/
|
||||||
|
if (is_usb_device(dev))
|
||||||
|
return usb_acpi_find_companion_for_device(to_usb_device(dev));
|
||||||
|
else if (is_usb_port(dev))
|
||||||
|
return usb_acpi_find_companion_for_port(to_usb_port(dev));
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -276,7 +276,7 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
|
||||||
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
|
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
|
||||||
int bt_sock_wait_ready(struct sock *sk, unsigned long flags);
|
int bt_sock_wait_ready(struct sock *sk, unsigned long flags);
|
||||||
|
|
||||||
void bt_accept_enqueue(struct sock *parent, struct sock *sk);
|
void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh);
|
||||||
void bt_accept_unlink(struct sock *sk);
|
void bt_accept_unlink(struct sock *sk);
|
||||||
struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
|
struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
|
||||||
|
|
||||||
|
|
|
@ -437,6 +437,7 @@ struct hci_dev {
|
||||||
int (*post_init)(struct hci_dev *hdev);
|
int (*post_init)(struct hci_dev *hdev);
|
||||||
int (*set_diag)(struct hci_dev *hdev, bool enable);
|
int (*set_diag)(struct hci_dev *hdev, bool enable);
|
||||||
int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
|
int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
|
||||||
|
void (*cmd_timeout)(struct hci_dev *hdev);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HCI_PHY_HANDLE(handle) (handle & 0xff)
|
#define HCI_PHY_HANDLE(handle) (handle & 0xff)
|
||||||
|
|
|
@ -41,7 +41,7 @@ static int lowpan_ctx_flag_active_get(void *data, u64 *val)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_flag_active_fops,
|
DEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_flag_active_fops,
|
||||||
lowpan_ctx_flag_active_get,
|
lowpan_ctx_flag_active_get,
|
||||||
lowpan_ctx_flag_active_set, "%llu\n");
|
lowpan_ctx_flag_active_set, "%llu\n");
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ static int lowpan_ctx_flag_c_get(void *data, u64 *val)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_flag_c_fops, lowpan_ctx_flag_c_get,
|
DEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_flag_c_fops, lowpan_ctx_flag_c_get,
|
||||||
lowpan_ctx_flag_c_set, "%llu\n");
|
lowpan_ctx_flag_c_set, "%llu\n");
|
||||||
|
|
||||||
static int lowpan_ctx_plen_set(void *data, u64 val)
|
static int lowpan_ctx_plen_set(void *data, u64 val)
|
||||||
|
@ -97,7 +97,7 @@ static int lowpan_ctx_plen_get(void *data, u64 *val)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_plen_fops, lowpan_ctx_plen_get,
|
DEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_plen_fops, lowpan_ctx_plen_get,
|
||||||
lowpan_ctx_plen_set, "%llu\n");
|
lowpan_ctx_plen_set, "%llu\n");
|
||||||
|
|
||||||
static int lowpan_ctx_pfx_show(struct seq_file *file, void *offset)
|
static int lowpan_ctx_pfx_show(struct seq_file *file, void *offset)
|
||||||
|
@ -184,13 +184,13 @@ static int lowpan_dev_debugfs_ctx_init(struct net_device *dev,
|
||||||
if (!root)
|
if (!root)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
dentry = debugfs_create_file("active", 0644, root,
|
dentry = debugfs_create_file_unsafe("active", 0644, root,
|
||||||
&ldev->ctx.table[id],
|
&ldev->ctx.table[id],
|
||||||
&lowpan_ctx_flag_active_fops);
|
&lowpan_ctx_flag_active_fops);
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
dentry = debugfs_create_file("compression", 0644, root,
|
dentry = debugfs_create_file_unsafe("compression", 0644, root,
|
||||||
&ldev->ctx.table[id],
|
&ldev->ctx.table[id],
|
||||||
&lowpan_ctx_flag_c_fops);
|
&lowpan_ctx_flag_c_fops);
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
|
@ -202,7 +202,7 @@ static int lowpan_dev_debugfs_ctx_init(struct net_device *dev,
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
dentry = debugfs_create_file("prefix_len", 0644, root,
|
dentry = debugfs_create_file_unsafe("prefix_len", 0644, root,
|
||||||
&ldev->ctx.table[id],
|
&ldev->ctx.table[id],
|
||||||
&lowpan_ctx_plen_fops);
|
&lowpan_ctx_plen_fops);
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
|
@ -245,8 +245,8 @@ static int lowpan_short_addr_get(void *data, u64 *val)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_SIMPLE_ATTRIBUTE(lowpan_short_addr_fops, lowpan_short_addr_get,
|
DEFINE_DEBUGFS_ATTRIBUTE(lowpan_short_addr_fops, lowpan_short_addr_get, NULL,
|
||||||
NULL, "0x%04llx\n");
|
"0x%04llx\n");
|
||||||
|
|
||||||
static int lowpan_dev_debugfs_802154_init(const struct net_device *dev,
|
static int lowpan_dev_debugfs_802154_init(const struct net_device *dev,
|
||||||
struct lowpan_dev *ldev)
|
struct lowpan_dev *ldev)
|
||||||
|
@ -260,7 +260,7 @@ static int lowpan_dev_debugfs_802154_init(const struct net_device *dev,
|
||||||
if (!root)
|
if (!root)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
dentry = debugfs_create_file("short_addr", 0444, root,
|
dentry = debugfs_create_file_unsafe("short_addr", 0444, root,
|
||||||
lowpan_802154_dev(dev)->wdev->ieee802154_ptr,
|
lowpan_802154_dev(dev)->wdev->ieee802154_ptr,
|
||||||
&lowpan_short_addr_fops);
|
&lowpan_short_addr_fops);
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
|
|
|
@ -1108,7 +1108,7 @@ static int lowpan_enable_get(void *data, u64 *val)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_SIMPLE_ATTRIBUTE(lowpan_enable_fops, lowpan_enable_get,
|
DEFINE_DEBUGFS_ATTRIBUTE(lowpan_enable_fops, lowpan_enable_get,
|
||||||
lowpan_enable_set, "%llu\n");
|
lowpan_enable_set, "%llu\n");
|
||||||
|
|
||||||
static ssize_t lowpan_control_write(struct file *fp,
|
static ssize_t lowpan_control_write(struct file *fp,
|
||||||
|
@ -1278,8 +1278,9 @@ static struct notifier_block bt_6lowpan_dev_notifier = {
|
||||||
|
|
||||||
static int __init bt_6lowpan_init(void)
|
static int __init bt_6lowpan_init(void)
|
||||||
{
|
{
|
||||||
lowpan_enable_debugfs = debugfs_create_file("6lowpan_enable", 0644,
|
lowpan_enable_debugfs = debugfs_create_file_unsafe("6lowpan_enable",
|
||||||
bt_debugfs, NULL,
|
0644, bt_debugfs,
|
||||||
|
NULL,
|
||||||
&lowpan_enable_fops);
|
&lowpan_enable_fops);
|
||||||
lowpan_control_debugfs = debugfs_create_file("6lowpan_control", 0644,
|
lowpan_control_debugfs = debugfs_create_file("6lowpan_control", 0644,
|
||||||
bt_debugfs, NULL,
|
bt_debugfs, NULL,
|
||||||
|
|
|
@ -174,7 +174,7 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||||
num_ctrl++;
|
num_ctrl++;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp);
|
len = struct_size(rsp, cl, num_ctrl);
|
||||||
rsp = kmalloc(len, GFP_ATOMIC);
|
rsp = kmalloc(len, GFP_ATOMIC);
|
||||||
if (!rsp) {
|
if (!rsp) {
|
||||||
read_unlock(&hci_dev_list_lock);
|
read_unlock(&hci_dev_list_lock);
|
||||||
|
|
|
@ -154,15 +154,25 @@ void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bt_sock_unlink);
|
EXPORT_SYMBOL(bt_sock_unlink);
|
||||||
|
|
||||||
void bt_accept_enqueue(struct sock *parent, struct sock *sk)
|
void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
|
||||||
{
|
{
|
||||||
BT_DBG("parent %p, sk %p", parent, sk);
|
BT_DBG("parent %p, sk %p", parent, sk);
|
||||||
|
|
||||||
sock_hold(sk);
|
sock_hold(sk);
|
||||||
|
|
||||||
|
if (bh)
|
||||||
|
bh_lock_sock_nested(sk);
|
||||||
|
else
|
||||||
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
|
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
|
||||||
|
|
||||||
list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
|
list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
|
||||||
bt_sk(sk)->parent = parent;
|
bt_sk(sk)->parent = parent;
|
||||||
|
|
||||||
|
if (bh)
|
||||||
|
bh_unlock_sock(sk);
|
||||||
|
else
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
|
|
||||||
parent->sk_ack_backlog++;
|
parent->sk_ack_backlog++;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bt_accept_enqueue);
|
EXPORT_SYMBOL(bt_accept_enqueue);
|
||||||
|
|
|
@ -2578,6 +2578,9 @@ static void hci_cmd_timeout(struct work_struct *work)
|
||||||
bt_dev_err(hdev, "command tx timeout");
|
bt_dev_err(hdev, "command tx timeout");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hdev->cmd_timeout)
|
||||||
|
hdev->cmd_timeout(hdev);
|
||||||
|
|
||||||
atomic_set(&hdev->cmd_cnt, 1);
|
atomic_set(&hdev->cmd_cnt, 1);
|
||||||
queue_work(hdev->workqueue, &hdev->cmd_work);
|
queue_work(hdev->workqueue, &hdev->cmd_work);
|
||||||
}
|
}
|
||||||
|
@ -3401,7 +3404,7 @@ EXPORT_SYMBOL(hci_resume_dev);
|
||||||
/* Reset HCI device */
|
/* Reset HCI device */
|
||||||
int hci_reset_dev(struct hci_dev *hdev)
|
int hci_reset_dev(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
const u8 hw_err[] = { HCI_EV_HARDWARE_ERROR, 0x01, 0x00 };
|
static const u8 hw_err[] = { HCI_EV_HARDWARE_ERROR, 0x01, 0x00 };
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
skb = bt_skb_alloc(3, GFP_ATOMIC);
|
skb = bt_skb_alloc(3, GFP_ATOMIC);
|
||||||
|
|
|
@ -3556,8 +3556,8 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
|
if (skb->len < sizeof(*ev) ||
|
||||||
ev->num_hndl * sizeof(struct hci_comp_pkts_info)) {
|
skb->len < struct_size(ev, handles, ev->num_hndl)) {
|
||||||
BT_DBG("%s bad parameters", hdev->name);
|
BT_DBG("%s bad parameters", hdev->name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3644,8 +3644,8 @@ static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
|
if (skb->len < sizeof(*ev) ||
|
||||||
ev->num_hndl * sizeof(struct hci_comp_blocks_info)) {
|
skb->len < struct_size(ev, handles, ev->num_hndl)) {
|
||||||
BT_DBG("%s bad parameters", hdev->name);
|
BT_DBG("%s bad parameters", hdev->name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -831,8 +831,6 @@ static int hci_sock_release(struct socket *sock)
|
||||||
if (!sk)
|
if (!sk)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
hdev = hci_pi(sk)->hdev;
|
|
||||||
|
|
||||||
switch (hci_pi(sk)->channel) {
|
switch (hci_pi(sk)->channel) {
|
||||||
case HCI_CHANNEL_MONITOR:
|
case HCI_CHANNEL_MONITOR:
|
||||||
atomic_dec(&monitor_promisc);
|
atomic_dec(&monitor_promisc);
|
||||||
|
@ -854,6 +852,7 @@ static int hci_sock_release(struct socket *sock)
|
||||||
|
|
||||||
bt_sock_unlink(&hci_sk_list, sk);
|
bt_sock_unlink(&hci_sk_list, sk);
|
||||||
|
|
||||||
|
hdev = hci_pi(sk)->hdev;
|
||||||
if (hdev) {
|
if (hdev) {
|
||||||
if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
|
if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
|
||||||
/* When releasing a user channel exclusive access,
|
/* When releasing a user channel exclusive access,
|
||||||
|
|
|
@ -3337,16 +3337,22 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
|
||||||
|
|
||||||
while (len >= L2CAP_CONF_OPT_SIZE) {
|
while (len >= L2CAP_CONF_OPT_SIZE) {
|
||||||
len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
|
len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
|
||||||
|
if (len < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
hint = type & L2CAP_CONF_HINT;
|
hint = type & L2CAP_CONF_HINT;
|
||||||
type &= L2CAP_CONF_MASK;
|
type &= L2CAP_CONF_MASK;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case L2CAP_CONF_MTU:
|
case L2CAP_CONF_MTU:
|
||||||
|
if (olen != 2)
|
||||||
|
break;
|
||||||
mtu = val;
|
mtu = val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L2CAP_CONF_FLUSH_TO:
|
case L2CAP_CONF_FLUSH_TO:
|
||||||
|
if (olen != 2)
|
||||||
|
break;
|
||||||
chan->flush_to = val;
|
chan->flush_to = val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -3354,26 +3360,30 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L2CAP_CONF_RFC:
|
case L2CAP_CONF_RFC:
|
||||||
if (olen == sizeof(rfc))
|
if (olen != sizeof(rfc))
|
||||||
|
break;
|
||||||
memcpy(&rfc, (void *) val, olen);
|
memcpy(&rfc, (void *) val, olen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L2CAP_CONF_FCS:
|
case L2CAP_CONF_FCS:
|
||||||
|
if (olen != 1)
|
||||||
|
break;
|
||||||
if (val == L2CAP_FCS_NONE)
|
if (val == L2CAP_FCS_NONE)
|
||||||
set_bit(CONF_RECV_NO_FCS, &chan->conf_state);
|
set_bit(CONF_RECV_NO_FCS, &chan->conf_state);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L2CAP_CONF_EFS:
|
case L2CAP_CONF_EFS:
|
||||||
if (olen == sizeof(efs)) {
|
if (olen != sizeof(efs))
|
||||||
|
break;
|
||||||
remote_efs = 1;
|
remote_efs = 1;
|
||||||
memcpy(&efs, (void *) val, olen);
|
memcpy(&efs, (void *) val, olen);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L2CAP_CONF_EWS:
|
case L2CAP_CONF_EWS:
|
||||||
|
if (olen != 2)
|
||||||
|
break;
|
||||||
if (!(chan->conn->local_fixed_chan & L2CAP_FC_A2MP))
|
if (!(chan->conn->local_fixed_chan & L2CAP_FC_A2MP))
|
||||||
return -ECONNREFUSED;
|
return -ECONNREFUSED;
|
||||||
|
|
||||||
set_bit(FLAG_EXT_CTRL, &chan->flags);
|
set_bit(FLAG_EXT_CTRL, &chan->flags);
|
||||||
set_bit(CONF_EWS_RECV, &chan->conf_state);
|
set_bit(CONF_EWS_RECV, &chan->conf_state);
|
||||||
chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
|
chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
|
||||||
|
@ -3383,7 +3393,6 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
|
||||||
default:
|
default:
|
||||||
if (hint)
|
if (hint)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
result = L2CAP_CONF_UNKNOWN;
|
result = L2CAP_CONF_UNKNOWN;
|
||||||
*((u8 *) ptr++) = type;
|
*((u8 *) ptr++) = type;
|
||||||
break;
|
break;
|
||||||
|
@ -3548,58 +3557,65 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
|
||||||
|
|
||||||
while (len >= L2CAP_CONF_OPT_SIZE) {
|
while (len >= L2CAP_CONF_OPT_SIZE) {
|
||||||
len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
|
len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
|
||||||
|
if (len < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case L2CAP_CONF_MTU:
|
case L2CAP_CONF_MTU:
|
||||||
|
if (olen != 2)
|
||||||
|
break;
|
||||||
if (val < L2CAP_DEFAULT_MIN_MTU) {
|
if (val < L2CAP_DEFAULT_MIN_MTU) {
|
||||||
*result = L2CAP_CONF_UNACCEPT;
|
*result = L2CAP_CONF_UNACCEPT;
|
||||||
chan->imtu = L2CAP_DEFAULT_MIN_MTU;
|
chan->imtu = L2CAP_DEFAULT_MIN_MTU;
|
||||||
} else
|
} else
|
||||||
chan->imtu = val;
|
chan->imtu = val;
|
||||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr);
|
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu,
|
||||||
|
endptr - ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L2CAP_CONF_FLUSH_TO:
|
case L2CAP_CONF_FLUSH_TO:
|
||||||
|
if (olen != 2)
|
||||||
|
break;
|
||||||
chan->flush_to = val;
|
chan->flush_to = val;
|
||||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
|
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2,
|
||||||
2, chan->flush_to, endptr - ptr);
|
chan->flush_to, endptr - ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L2CAP_CONF_RFC:
|
case L2CAP_CONF_RFC:
|
||||||
if (olen == sizeof(rfc))
|
if (olen != sizeof(rfc))
|
||||||
|
break;
|
||||||
memcpy(&rfc, (void *)val, olen);
|
memcpy(&rfc, (void *)val, olen);
|
||||||
|
|
||||||
if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
|
if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
|
||||||
rfc.mode != chan->mode)
|
rfc.mode != chan->mode)
|
||||||
return -ECONNREFUSED;
|
return -ECONNREFUSED;
|
||||||
|
|
||||||
chan->fcs = 0;
|
chan->fcs = 0;
|
||||||
|
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
|
||||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
|
(unsigned long) &rfc, endptr - ptr);
|
||||||
sizeof(rfc), (unsigned long) &rfc, endptr - ptr);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L2CAP_CONF_EWS:
|
case L2CAP_CONF_EWS:
|
||||||
|
if (olen != 2)
|
||||||
|
break;
|
||||||
chan->ack_win = min_t(u16, val, chan->ack_win);
|
chan->ack_win = min_t(u16, val, chan->ack_win);
|
||||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
|
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
|
||||||
chan->tx_win, endptr - ptr);
|
chan->tx_win, endptr - ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L2CAP_CONF_EFS:
|
case L2CAP_CONF_EFS:
|
||||||
if (olen == sizeof(efs)) {
|
if (olen != sizeof(efs))
|
||||||
|
break;
|
||||||
memcpy(&efs, (void *)val, olen);
|
memcpy(&efs, (void *)val, olen);
|
||||||
|
|
||||||
if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
|
if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
|
||||||
efs.stype != L2CAP_SERV_NOTRAFIC &&
|
efs.stype != L2CAP_SERV_NOTRAFIC &&
|
||||||
efs.stype != chan->local_stype)
|
efs.stype != chan->local_stype)
|
||||||
return -ECONNREFUSED;
|
return -ECONNREFUSED;
|
||||||
|
|
||||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
|
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
|
||||||
(unsigned long) &efs, endptr - ptr);
|
(unsigned long) &efs, endptr - ptr);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L2CAP_CONF_FCS:
|
case L2CAP_CONF_FCS:
|
||||||
|
if (olen != 1)
|
||||||
|
break;
|
||||||
if (*result == L2CAP_CONF_PENDING)
|
if (*result == L2CAP_CONF_PENDING)
|
||||||
if (val == L2CAP_FCS_NONE)
|
if (val == L2CAP_FCS_NONE)
|
||||||
set_bit(CONF_RECV_NO_FCS,
|
set_bit(CONF_RECV_NO_FCS,
|
||||||
|
@ -3728,13 +3744,18 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
|
||||||
|
|
||||||
while (len >= L2CAP_CONF_OPT_SIZE) {
|
while (len >= L2CAP_CONF_OPT_SIZE) {
|
||||||
len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
|
len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
|
||||||
|
if (len < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case L2CAP_CONF_RFC:
|
case L2CAP_CONF_RFC:
|
||||||
if (olen == sizeof(rfc))
|
if (olen != sizeof(rfc))
|
||||||
|
break;
|
||||||
memcpy(&rfc, (void *)val, olen);
|
memcpy(&rfc, (void *)val, olen);
|
||||||
break;
|
break;
|
||||||
case L2CAP_CONF_EWS:
|
case L2CAP_CONF_EWS:
|
||||||
|
if (olen != 2)
|
||||||
|
break;
|
||||||
txwin_ext = val;
|
txwin_ext = val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4244,6 +4265,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* fall through */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
l2cap_chan_set_err(chan, ECONNRESET);
|
l2cap_chan_set_err(chan, ECONNRESET);
|
||||||
|
|
|
@ -1252,7 +1252,7 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
|
||||||
|
|
||||||
l2cap_sock_init(sk, parent);
|
l2cap_sock_init(sk, parent);
|
||||||
|
|
||||||
bt_accept_enqueue(parent, sk);
|
bt_accept_enqueue(parent, sk, false);
|
||||||
|
|
||||||
release_sock(parent);
|
release_sock(parent);
|
||||||
|
|
||||||
|
|
|
@ -483,6 +483,7 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
|
||||||
/* if closing a dlc in a session that hasn't been started,
|
/* if closing a dlc in a session that hasn't been started,
|
||||||
* just close and unlink the dlc
|
* just close and unlink the dlc
|
||||||
*/
|
*/
|
||||||
|
/* fall through */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
rfcomm_dlc_clear_timer(d);
|
rfcomm_dlc_clear_timer(d);
|
||||||
|
|
|
@ -988,7 +988,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
|
||||||
rfcomm_pi(sk)->channel = channel;
|
rfcomm_pi(sk)->channel = channel;
|
||||||
|
|
||||||
sk->sk_state = BT_CONFIG;
|
sk->sk_state = BT_CONFIG;
|
||||||
bt_accept_enqueue(parent, sk);
|
bt_accept_enqueue(parent, sk, true);
|
||||||
|
|
||||||
/* Accept connection and return socket DLC */
|
/* Accept connection and return socket DLC */
|
||||||
*d = rfcomm_pi(sk)->dlc;
|
*d = rfcomm_pi(sk)->dlc;
|
||||||
|
|
|
@ -193,7 +193,7 @@ static void __sco_chan_add(struct sco_conn *conn, struct sock *sk,
|
||||||
conn->sk = sk;
|
conn->sk = sk;
|
||||||
|
|
||||||
if (parent)
|
if (parent)
|
||||||
bt_accept_enqueue(parent, sk);
|
bt_accept_enqueue(parent, sk, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
|
static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
|
||||||
|
|
Loading…
Reference in New Issue