1
0
Fork 0

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>
hifive-unleashed-5.1
David S. Miller 2019-02-24 22:27:19 -08:00
commit e8b47b53a1
27 changed files with 663 additions and 220 deletions

View File

@ -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

View File

@ -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>

View File

@ -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");

View File

@ -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 = &param;
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;
&param); wmt_params.flag = 0;
wmt_params.dlen = sizeof(param);
wmt_params.data = &param;
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;
&param); wmt_params.flag = 0;
wmt_params.dlen = sizeof(param);
wmt_params.data = &param;
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;

View File

@ -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);

View File

@ -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

View File

@ -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:

View File

@ -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);
} }

View File

@ -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)

View File

@ -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;

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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;
} }

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
} }

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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,