Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== pull request: bluetooth-next 2019-10-23 Here's the main bluetooth-next pull request for the 5.5 kernel: - Multiple fixes to hci_qca driver - Fix for HCI_USER_CHANNEL initialization - btwlink: drop superseded driver - Add support for Intel FW download error recovery - Various other smaller fixes & improvements Please let me know if there are any issues pulling. Thanks. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
8ca12bc36f
|
@ -380,17 +380,6 @@ config BT_ATH3K
|
|||
Say Y here to compile support for "Atheros firmware download driver"
|
||||
into the kernel or say M to compile it as module (ath3k).
|
||||
|
||||
config BT_WILINK
|
||||
tristate "Texas Instruments WiLink7 driver"
|
||||
depends on TI_ST
|
||||
help
|
||||
This enables the Bluetooth driver for Texas Instrument's BT/FM/GPS
|
||||
combo devices. This makes use of shared transport line discipline
|
||||
core driver to communicate with the BT core of the combo chip.
|
||||
|
||||
Say Y here to compile support for Texas Instrument's WiLink7 driver
|
||||
into the kernel or say M to compile it as module (btwilink).
|
||||
|
||||
config BT_MTKSDIO
|
||||
tristate "MediaTek HCI SDIO driver"
|
||||
depends on MMC
|
||||
|
|
|
@ -19,7 +19,6 @@ obj-$(CONFIG_BT_INTEL) += btintel.o
|
|||
obj-$(CONFIG_BT_ATH3K) += ath3k.o
|
||||
obj-$(CONFIG_BT_MRVL) += btmrvl.o
|
||||
obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
|
||||
obj-$(CONFIG_BT_WILINK) += btwilink.o
|
||||
obj-$(CONFIG_BT_MTKSDIO) += btmtksdio.o
|
||||
obj-$(CONFIG_BT_MTKUART) += btmtkuart.o
|
||||
obj-$(CONFIG_BT_QCOMSMD) += btqcomsmd.o
|
||||
|
|
|
@ -709,6 +709,51 @@ done:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_download_firmware);
|
||||
|
||||
void btintel_reset_to_bootloader(struct hci_dev *hdev)
|
||||
{
|
||||
struct intel_reset params;
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Send Intel Reset command. This will result in
|
||||
* re-enumeration of BT controller.
|
||||
*
|
||||
* Intel Reset parameter description:
|
||||
* reset_type : 0x00 (Soft reset),
|
||||
* 0x01 (Hard reset)
|
||||
* patch_enable : 0x00 (Do not enable),
|
||||
* 0x01 (Enable)
|
||||
* ddc_reload : 0x00 (Do not reload),
|
||||
* 0x01 (Reload)
|
||||
* boot_option: 0x00 (Current image),
|
||||
* 0x01 (Specified boot address)
|
||||
* boot_param: Boot address
|
||||
*
|
||||
*/
|
||||
params.reset_type = 0x01;
|
||||
params.patch_enable = 0x01;
|
||||
params.ddc_reload = 0x01;
|
||||
params.boot_option = 0x00;
|
||||
params.boot_param = cpu_to_le32(0x00000000);
|
||||
|
||||
skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params),
|
||||
¶ms, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_err(hdev, "FW download error recovery failed (%ld)",
|
||||
PTR_ERR(skb));
|
||||
return;
|
||||
}
|
||||
bt_dev_info(hdev, "Intel reset sent to retry FW download");
|
||||
kfree_skb(skb);
|
||||
|
||||
/* Current Intel BT controllers(ThP/JfP) hold the USB reset
|
||||
* lines for 2ms when it receives Intel Reset in bootloader mode.
|
||||
* Whereas, the upcoming Intel BT controllers will hold USB reset
|
||||
* for 150ms. To keep the delay generic, 150ms is chosen here.
|
||||
*/
|
||||
msleep(150);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_reset_to_bootloader);
|
||||
|
||||
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
|
||||
MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
|
|
|
@ -87,6 +87,7 @@ int btintel_read_boot_params(struct hci_dev *hdev,
|
|||
struct intel_boot_params *params);
|
||||
int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw,
|
||||
u32 *boot_param);
|
||||
void btintel_reset_to_bootloader(struct hci_dev *hdev);
|
||||
#else
|
||||
|
||||
static inline int btintel_check_bdaddr(struct hci_dev *hdev)
|
||||
|
@ -181,4 +182,8 @@ static inline int btintel_download_firmware(struct hci_dev *dev,
|
|||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void btintel_reset_to_bootloader(struct hci_dev *hdev)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -418,7 +418,7 @@ static int rtl_download_firmware(struct hci_dev *hdev,
|
|||
if (IS_ERR(skb)) {
|
||||
rtl_dev_err(hdev, "download fw command failed (%ld)",
|
||||
PTR_ERR(skb));
|
||||
ret = -PTR_ERR(skb);
|
||||
ret = PTR_ERR(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
@ -2182,8 +2182,11 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
|
|||
* loaded.
|
||||
*/
|
||||
err = btintel_read_version(hdev, &ver);
|
||||
if (err)
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Intel Read version failed (%d)", err);
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The hardware platform number has a fixed value of 0x37 and
|
||||
* for now only accept this single value.
|
||||
|
@ -2326,9 +2329,13 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
|
|||
|
||||
/* Start firmware downloading and get boot parameter */
|
||||
err = btintel_download_firmware(hdev, fw, &boot_param);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
/* When FW download fails, send Intel Reset to retry
|
||||
* FW download.
|
||||
*/
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
goto done;
|
||||
|
||||
}
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
|
||||
bt_dev_info(hdev, "Waiting for firmware download to complete");
|
||||
|
@ -2355,6 +2362,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
|
|||
if (err) {
|
||||
bt_dev_err(hdev, "Firmware loading timeout");
|
||||
err = -ETIMEDOUT;
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -2381,8 +2389,11 @@ done:
|
|||
set_bit(BTUSB_BOOTING, &data->flags);
|
||||
|
||||
err = btintel_send_intel_reset(hdev, boot_param);
|
||||
if (err)
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Intel Soft Reset failed (%d)", err);
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The bootloader will not indicate when the device is ready. This
|
||||
* is done by the operational firmware sending bootup notification.
|
||||
|
@ -2404,6 +2415,7 @@ done:
|
|||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Device boot timeout");
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
@ -2432,6 +2444,13 @@ done:
|
|||
*/
|
||||
btintel_set_event_mask(hdev, false);
|
||||
|
||||
/* Read the Intel version information after loading the FW */
|
||||
err = btintel_read_version(hdev, &ver);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
btintel_version_info(hdev, &ver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2489,8 +2508,6 @@ static int btusb_shutdown_intel_new(struct hci_dev *hdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BT_HCIBTUSB_MTK
|
||||
|
||||
#define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin"
|
||||
#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"
|
||||
|
||||
|
@ -3051,7 +3068,6 @@ static int btusb_mtk_shutdown(struct hci_dev *hdev)
|
|||
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7663);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7668);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/* Configure an out-of-band gpio as wake-up pin, if specified in device tree */
|
||||
|
@ -3411,7 +3427,6 @@ static int btusb_setup_qca(struct hci_dev *hdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BT_HCIBTUSB_BCM
|
||||
static inline int __set_diag_interface(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
|
@ -3498,7 +3513,6 @@ static int btusb_bcm_set_diag(struct hci_dev *hdev, bool enable)
|
|||
|
||||
return submit_or_queue_tx_urb(hdev, urb);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static irqreturn_t btusb_oob_wake_handler(int irq, void *priv)
|
||||
|
@ -3724,8 +3738,8 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
if (id->driver_info & BTUSB_BCM92035)
|
||||
hdev->setup = btusb_setup_bcm92035;
|
||||
|
||||
#ifdef CONFIG_BT_HCIBTUSB_BCM
|
||||
if (id->driver_info & BTUSB_BCM_PATCHRAM) {
|
||||
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_BCM) &&
|
||||
(id->driver_info & BTUSB_BCM_PATCHRAM)) {
|
||||
hdev->manufacturer = 15;
|
||||
hdev->setup = btbcm_setup_patchram;
|
||||
hdev->set_diag = btusb_bcm_set_diag;
|
||||
|
@ -3735,7 +3749,8 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
|
||||
}
|
||||
|
||||
if (id->driver_info & BTUSB_BCM_APPLE) {
|
||||
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_BCM) &&
|
||||
(id->driver_info & BTUSB_BCM_APPLE)) {
|
||||
hdev->manufacturer = 15;
|
||||
hdev->setup = btbcm_setup_apple;
|
||||
hdev->set_diag = btusb_bcm_set_diag;
|
||||
|
@ -3743,7 +3758,6 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
/* Broadcom LM_DIAG Interface numbers are hardcoded */
|
||||
data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (id->driver_info & BTUSB_INTEL) {
|
||||
hdev->manufacturer = 2;
|
||||
|
@ -3774,14 +3788,13 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
if (id->driver_info & BTUSB_MARVELL)
|
||||
hdev->set_bdaddr = btusb_set_bdaddr_marvell;
|
||||
|
||||
#ifdef CONFIG_BT_HCIBTUSB_MTK
|
||||
if (id->driver_info & BTUSB_MEDIATEK) {
|
||||
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) &&
|
||||
(id->driver_info & BTUSB_MEDIATEK)) {
|
||||
hdev->setup = btusb_mtk_setup;
|
||||
hdev->shutdown = btusb_mtk_shutdown;
|
||||
hdev->manufacturer = 70;
|
||||
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (id->driver_info & BTUSB_SWAVE) {
|
||||
set_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks);
|
||||
|
@ -3807,8 +3820,8 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
btusb_check_needs_reset_resume(intf);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BT_HCIBTUSB_RTL
|
||||
if (id->driver_info & BTUSB_REALTEK) {
|
||||
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) &&
|
||||
(id->driver_info & BTUSB_REALTEK)) {
|
||||
hdev->setup = btrtl_setup_realtek;
|
||||
hdev->shutdown = btrtl_shutdown_realtek;
|
||||
hdev->cmd_timeout = btusb_rtl_cmd_timeout;
|
||||
|
@ -3819,7 +3832,6 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
*/
|
||||
set_bit(BTUSB_WAKEUP_DISABLE, &data->flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (id->driver_info & BTUSB_AMP) {
|
||||
/* AMP controllers do not support SCO packets */
|
||||
|
@ -3887,15 +3899,13 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
goto out_free_dev;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BT_HCIBTUSB_BCM
|
||||
if (data->diag) {
|
||||
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_BCM) && data->diag) {
|
||||
if (!usb_driver_claim_interface(&btusb_driver,
|
||||
data->diag, data))
|
||||
__set_diag_interface(hdev);
|
||||
else
|
||||
data->diag = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (enable_autosuspend)
|
||||
usb_enable_autosuspend(data->udev);
|
||||
|
|
|
@ -1,337 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Texas Instrument's Bluetooth Driver For Shared Transport.
|
||||
*
|
||||
* Bluetooth Driver acts as interface between HCI core and
|
||||
* TI Shared Transport Layer.
|
||||
*
|
||||
* Copyright (C) 2009-2010 Texas Instruments
|
||||
* Author: Raja Mani <raja_mani@ti.com>
|
||||
* Pavan Savoy <pavan_savoy@ti.com>
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/hci.h>
|
||||
|
||||
#include <linux/ti_wilink_st.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/* Bluetooth Driver Version */
|
||||
#define VERSION "1.0"
|
||||
#define MAX_BT_CHNL_IDS 3
|
||||
|
||||
/* Number of seconds to wait for registration completion
|
||||
* when ST returns PENDING status.
|
||||
*/
|
||||
#define BT_REGISTER_TIMEOUT 6000 /* 6 sec */
|
||||
|
||||
/**
|
||||
* struct ti_st - driver operation structure
|
||||
* @hdev: hci device pointer which binds to bt driver
|
||||
* @reg_status: ST registration callback status
|
||||
* @st_write: write function provided by the ST driver
|
||||
* to be used by the driver during send_frame.
|
||||
* @wait_reg_completion - completion sync between ti_st_open
|
||||
* and st_reg_completion_cb.
|
||||
*/
|
||||
struct ti_st {
|
||||
struct hci_dev *hdev;
|
||||
int reg_status;
|
||||
long (*st_write) (struct sk_buff *);
|
||||
struct completion wait_reg_completion;
|
||||
};
|
||||
|
||||
/* Increments HCI counters based on pocket ID (cmd,acl,sco) */
|
||||
static inline void ti_st_tx_complete(struct ti_st *hst, int pkt_type)
|
||||
{
|
||||
struct hci_dev *hdev = hst->hdev;
|
||||
|
||||
/* Update HCI stat counters */
|
||||
switch (pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
hdev->stat.cmd_tx++;
|
||||
break;
|
||||
|
||||
case HCI_ACLDATA_PKT:
|
||||
hdev->stat.acl_tx++;
|
||||
break;
|
||||
|
||||
case HCI_SCODATA_PKT:
|
||||
hdev->stat.sco_tx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------- Interfaces to Shared Transport ------ */
|
||||
|
||||
/* Called by ST layer to indicate protocol registration completion
|
||||
* status.ti_st_open() function will wait for signal from this
|
||||
* API when st_register() function returns ST_PENDING.
|
||||
*/
|
||||
static void st_reg_completion_cb(void *priv_data, int data)
|
||||
{
|
||||
struct ti_st *lhst = priv_data;
|
||||
|
||||
/* Save registration status for use in ti_st_open() */
|
||||
lhst->reg_status = data;
|
||||
/* complete the wait in ti_st_open() */
|
||||
complete(&lhst->wait_reg_completion);
|
||||
}
|
||||
|
||||
/* Called by Shared Transport layer when receive data is available */
|
||||
static long st_receive(void *priv_data, struct sk_buff *skb)
|
||||
{
|
||||
struct ti_st *lhst = priv_data;
|
||||
int err;
|
||||
|
||||
if (!skb)
|
||||
return -EFAULT;
|
||||
|
||||
if (!lhst) {
|
||||
kfree_skb(skb);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Forward skb to HCI core layer */
|
||||
err = hci_recv_frame(lhst->hdev, skb);
|
||||
if (err < 0) {
|
||||
BT_ERR("Unable to push skb to HCI core(%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
lhst->hdev->stat.byte_rx += skb->len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------- Interfaces to HCI layer ------ */
|
||||
/* protocol structure registered with shared transport */
|
||||
static struct st_proto_s ti_st_proto[MAX_BT_CHNL_IDS] = {
|
||||
{
|
||||
.chnl_id = HCI_EVENT_PKT, /* HCI Events */
|
||||
.hdr_len = sizeof(struct hci_event_hdr),
|
||||
.offset_len_in_hdr = offsetof(struct hci_event_hdr, plen),
|
||||
.len_size = 1, /* sizeof(plen) in struct hci_event_hdr */
|
||||
.reserve = 8,
|
||||
},
|
||||
{
|
||||
.chnl_id = HCI_ACLDATA_PKT, /* ACL */
|
||||
.hdr_len = sizeof(struct hci_acl_hdr),
|
||||
.offset_len_in_hdr = offsetof(struct hci_acl_hdr, dlen),
|
||||
.len_size = 2, /* sizeof(dlen) in struct hci_acl_hdr */
|
||||
.reserve = 8,
|
||||
},
|
||||
{
|
||||
.chnl_id = HCI_SCODATA_PKT, /* SCO */
|
||||
.hdr_len = sizeof(struct hci_sco_hdr),
|
||||
.offset_len_in_hdr = offsetof(struct hci_sco_hdr, dlen),
|
||||
.len_size = 1, /* sizeof(dlen) in struct hci_sco_hdr */
|
||||
.reserve = 8,
|
||||
},
|
||||
};
|
||||
|
||||
/* Called from HCI core to initialize the device */
|
||||
static int ti_st_open(struct hci_dev *hdev)
|
||||
{
|
||||
unsigned long timeleft;
|
||||
struct ti_st *hst;
|
||||
int err, i;
|
||||
|
||||
BT_DBG("%s %p", hdev->name, hdev);
|
||||
|
||||
/* provide contexts for callbacks from ST */
|
||||
hst = hci_get_drvdata(hdev);
|
||||
|
||||
for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
|
||||
ti_st_proto[i].priv_data = hst;
|
||||
ti_st_proto[i].max_frame_size = HCI_MAX_FRAME_SIZE;
|
||||
ti_st_proto[i].recv = st_receive;
|
||||
ti_st_proto[i].reg_complete_cb = st_reg_completion_cb;
|
||||
|
||||
/* Prepare wait-for-completion handler */
|
||||
init_completion(&hst->wait_reg_completion);
|
||||
/* Reset ST registration callback status flag,
|
||||
* this value will be updated in
|
||||
* st_reg_completion_cb()
|
||||
* function whenever it called from ST driver.
|
||||
*/
|
||||
hst->reg_status = -EINPROGRESS;
|
||||
|
||||
err = st_register(&ti_st_proto[i]);
|
||||
if (!err)
|
||||
goto done;
|
||||
|
||||
if (err != -EINPROGRESS) {
|
||||
BT_ERR("st_register failed %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* ST is busy with either protocol
|
||||
* registration or firmware download.
|
||||
*/
|
||||
BT_DBG("waiting for registration "
|
||||
"completion signal from ST");
|
||||
timeleft = wait_for_completion_timeout
|
||||
(&hst->wait_reg_completion,
|
||||
msecs_to_jiffies(BT_REGISTER_TIMEOUT));
|
||||
if (!timeleft) {
|
||||
BT_ERR("Timeout(%d sec),didn't get reg "
|
||||
"completion signal from ST",
|
||||
BT_REGISTER_TIMEOUT / 1000);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Is ST registration callback
|
||||
* called with ERROR status?
|
||||
*/
|
||||
if (hst->reg_status != 0) {
|
||||
BT_ERR("ST registration completed with invalid "
|
||||
"status %d", hst->reg_status);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
done:
|
||||
hst->st_write = ti_st_proto[i].write;
|
||||
if (!hst->st_write) {
|
||||
BT_ERR("undefined ST write function");
|
||||
for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
|
||||
/* Undo registration with ST */
|
||||
err = st_unregister(&ti_st_proto[i]);
|
||||
if (err)
|
||||
BT_ERR("st_unregister() failed with "
|
||||
"error %d", err);
|
||||
hst->st_write = NULL;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Close device */
|
||||
static int ti_st_close(struct hci_dev *hdev)
|
||||
{
|
||||
int err, i;
|
||||
struct ti_st *hst = hci_get_drvdata(hdev);
|
||||
|
||||
for (i = MAX_BT_CHNL_IDS-1; i >= 0; i--) {
|
||||
err = st_unregister(&ti_st_proto[i]);
|
||||
if (err)
|
||||
BT_ERR("st_unregister(%d) failed with error %d",
|
||||
ti_st_proto[i].chnl_id, err);
|
||||
}
|
||||
|
||||
hst->st_write = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ti_st_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct ti_st *hst;
|
||||
long len;
|
||||
int pkt_type;
|
||||
|
||||
hst = hci_get_drvdata(hdev);
|
||||
|
||||
/* Prepend skb with frame type */
|
||||
memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
|
||||
|
||||
BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb),
|
||||
skb->len);
|
||||
|
||||
/* Insert skb to shared transport layer's transmit queue.
|
||||
* Freeing skb memory is taken care in shared transport layer,
|
||||
* so don't free skb memory here.
|
||||
*/
|
||||
pkt_type = hci_skb_pkt_type(skb);
|
||||
len = hst->st_write(skb);
|
||||
if (len < 0) {
|
||||
BT_ERR("ST write failed (%ld)", len);
|
||||
/* Try Again, would only fail if UART has gone bad */
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* ST accepted our skb. So, Go ahead and do rest */
|
||||
hdev->stat.byte_tx += len;
|
||||
ti_st_tx_complete(hst, pkt_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt_ti_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ti_st *hst;
|
||||
struct hci_dev *hdev;
|
||||
int err;
|
||||
|
||||
hst = devm_kzalloc(&pdev->dev, sizeof(struct ti_st), GFP_KERNEL);
|
||||
if (!hst)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Expose "hciX" device to user space */
|
||||
hdev = hci_alloc_dev();
|
||||
if (!hdev)
|
||||
return -ENOMEM;
|
||||
|
||||
BT_DBG("hdev %p", hdev);
|
||||
|
||||
hst->hdev = hdev;
|
||||
hdev->bus = HCI_UART;
|
||||
hci_set_drvdata(hdev, hst);
|
||||
hdev->open = ti_st_open;
|
||||
hdev->close = ti_st_close;
|
||||
hdev->flush = NULL;
|
||||
hdev->send = ti_st_send_frame;
|
||||
|
||||
err = hci_register_dev(hdev);
|
||||
if (err < 0) {
|
||||
BT_ERR("Can't register HCI device error %d", err);
|
||||
hci_free_dev(hdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_DBG("HCI device registered (hdev %p)", hdev);
|
||||
|
||||
dev_set_drvdata(&pdev->dev, hst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt_ti_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hci_dev *hdev;
|
||||
struct ti_st *hst = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
if (!hst)
|
||||
return -EFAULT;
|
||||
|
||||
BT_DBG("%s", hst->hdev->name);
|
||||
|
||||
hdev = hst->hdev;
|
||||
ti_st_close(hdev);
|
||||
hci_unregister_dev(hdev);
|
||||
|
||||
hci_free_dev(hdev);
|
||||
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver btwilink_driver = {
|
||||
.probe = bt_ti_probe,
|
||||
.remove = bt_ti_remove,
|
||||
.driver = {
|
||||
.name = "btwilink",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(btwilink_driver);
|
||||
|
||||
/* ------ Module Info ------ */
|
||||
|
||||
MODULE_AUTHOR("Raja Mani <raja_mani@ti.com>");
|
||||
MODULE_DESCRIPTION("Bluetooth Driver for TI Shared Transport" VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
|
@ -445,9 +445,11 @@ static int bcm_open(struct hci_uart *hu)
|
|||
|
||||
out:
|
||||
if (bcm->dev) {
|
||||
hci_uart_set_flow_control(hu, true);
|
||||
hu->init_speed = bcm->dev->init_speed;
|
||||
hu->oper_speed = bcm->dev->oper_speed;
|
||||
err = bcm_gpio_set_power(bcm->dev, true);
|
||||
hci_uart_set_flow_control(hu, false);
|
||||
if (err)
|
||||
goto err_unset_hu;
|
||||
}
|
||||
|
|
|
@ -621,13 +621,6 @@ static int ll_setup(struct hci_uart *hu)
|
|||
|
||||
serdev_device_set_flow_control(serdev, true);
|
||||
|
||||
if (hu->oper_speed)
|
||||
speed = hu->oper_speed;
|
||||
else if (hu->proto->oper_speed)
|
||||
speed = hu->proto->oper_speed;
|
||||
else
|
||||
speed = 0;
|
||||
|
||||
do {
|
||||
/* Reset the Bluetooth device */
|
||||
gpiod_set_value_cansleep(lldev->enable_gpio, 0);
|
||||
|
@ -639,20 +632,6 @@ static int ll_setup(struct hci_uart *hu)
|
|||
return err;
|
||||
}
|
||||
|
||||
if (speed) {
|
||||
__le32 speed_le = cpu_to_le32(speed);
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = __hci_cmd_sync(hu->hdev,
|
||||
HCI_VS_UPDATE_UART_HCI_BAUDRATE,
|
||||
sizeof(speed_le), &speed_le,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (!IS_ERR(skb)) {
|
||||
kfree_skb(skb);
|
||||
serdev_device_set_baudrate(serdev, speed);
|
||||
}
|
||||
}
|
||||
|
||||
err = download_firmware(lldev);
|
||||
if (!err)
|
||||
break;
|
||||
|
@ -677,7 +656,25 @@ static int ll_setup(struct hci_uart *hu)
|
|||
}
|
||||
|
||||
/* Operational speed if any */
|
||||
if (hu->oper_speed)
|
||||
speed = hu->oper_speed;
|
||||
else if (hu->proto->oper_speed)
|
||||
speed = hu->proto->oper_speed;
|
||||
else
|
||||
speed = 0;
|
||||
|
||||
if (speed) {
|
||||
__le32 speed_le = cpu_to_le32(speed);
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = __hci_cmd_sync(hu->hdev, HCI_VS_UPDATE_UART_HCI_BAUDRATE,
|
||||
sizeof(speed_le), &speed_le,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (!IS_ERR(skb)) {
|
||||
kfree_skb(skb);
|
||||
serdev_device_set_baudrate(serdev, speed);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -520,7 +520,7 @@ static int nokia_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
|||
err = skb_pad(skb, 1);
|
||||
if (err)
|
||||
return err;
|
||||
skb_put_u8(skb, 0x00);
|
||||
skb_put(skb, 1);
|
||||
}
|
||||
|
||||
skb_queue_tail(&btdev->txq, skb);
|
||||
|
|
|
@ -130,8 +130,6 @@ enum qca_speed_type {
|
|||
*/
|
||||
struct qca_vreg {
|
||||
const char *name;
|
||||
unsigned int min_uV;
|
||||
unsigned int max_uV;
|
||||
unsigned int load_uA;
|
||||
};
|
||||
|
||||
|
@ -146,8 +144,8 @@ struct qca_vreg_data {
|
|||
*/
|
||||
struct qca_power {
|
||||
struct device *dev;
|
||||
const struct qca_vreg_data *vreg_data;
|
||||
struct regulator_bulk_data *vreg_bulk;
|
||||
int num_vregs;
|
||||
bool vregs_on;
|
||||
};
|
||||
|
||||
|
@ -162,7 +160,8 @@ struct qca_serdev {
|
|||
const char *firmware_name;
|
||||
};
|
||||
|
||||
static int qca_power_setup(struct hci_uart *hu, bool on);
|
||||
static int qca_regulator_enable(struct qca_serdev *qcadev);
|
||||
static void qca_regulator_disable(struct qca_serdev *qcadev);
|
||||
static void qca_power_shutdown(struct hci_uart *hu);
|
||||
static int qca_power_off(struct hci_dev *hdev);
|
||||
|
||||
|
@ -518,7 +517,7 @@ static int qca_open(struct hci_uart *hu)
|
|||
} else {
|
||||
hu->init_speed = qcadev->init_speed;
|
||||
hu->oper_speed = qcadev->oper_speed;
|
||||
ret = qca_power_setup(hu, true);
|
||||
ret = qca_regulator_enable(qcadev);
|
||||
if (ret) {
|
||||
destroy_workqueue(qca->workqueue);
|
||||
kfree_skb(qca->rx_skb);
|
||||
|
@ -1188,7 +1187,7 @@ static int qca_wcn3990_init(struct hci_uart *hu)
|
|||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
if (!qcadev->bt_power->vregs_on) {
|
||||
serdev_device_close(hu->serdev);
|
||||
ret = qca_power_setup(hu, true);
|
||||
ret = qca_regulator_enable(qcadev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1332,10 +1331,10 @@ static const struct hci_uart_proto qca_proto = {
|
|||
static const struct qca_vreg_data qca_soc_data_wcn3990 = {
|
||||
.soc_type = QCA_WCN3990,
|
||||
.vregs = (struct qca_vreg []) {
|
||||
{ "vddio", 1800000, 1900000, 15000 },
|
||||
{ "vddxo", 1800000, 1900000, 80000 },
|
||||
{ "vddrf", 1300000, 1350000, 300000 },
|
||||
{ "vddch0", 3300000, 3400000, 450000 },
|
||||
{ "vddio", 15000 },
|
||||
{ "vddxo", 80000 },
|
||||
{ "vddrf", 300000 },
|
||||
{ "vddch0", 450000 },
|
||||
},
|
||||
.num_vregs = 4,
|
||||
};
|
||||
|
@ -1343,19 +1342,22 @@ static const struct qca_vreg_data qca_soc_data_wcn3990 = {
|
|||
static const struct qca_vreg_data qca_soc_data_wcn3998 = {
|
||||
.soc_type = QCA_WCN3998,
|
||||
.vregs = (struct qca_vreg []) {
|
||||
{ "vddio", 1800000, 1900000, 10000 },
|
||||
{ "vddxo", 1800000, 1900000, 80000 },
|
||||
{ "vddrf", 1300000, 1352000, 300000 },
|
||||
{ "vddch0", 3300000, 3300000, 450000 },
|
||||
{ "vddio", 10000 },
|
||||
{ "vddxo", 80000 },
|
||||
{ "vddrf", 300000 },
|
||||
{ "vddch0", 450000 },
|
||||
},
|
||||
.num_vregs = 4,
|
||||
};
|
||||
|
||||
static void qca_power_shutdown(struct hci_uart *hu)
|
||||
{
|
||||
struct qca_serdev *qcadev;
|
||||
struct qca_data *qca = hu->priv;
|
||||
unsigned long flags;
|
||||
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
|
||||
/* 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.
|
||||
|
@ -1367,7 +1369,7 @@ static void qca_power_shutdown(struct hci_uart *hu)
|
|||
|
||||
host_set_baudrate(hu, 2400);
|
||||
qca_send_power_pulse(hu, false);
|
||||
qca_power_setup(hu, false);
|
||||
qca_regulator_disable(qcadev);
|
||||
}
|
||||
|
||||
static int qca_power_off(struct hci_dev *hdev)
|
||||
|
@ -1383,97 +1385,71 @@ static int qca_power_off(struct hci_dev *hdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int qca_enable_regulator(struct qca_vreg vregs,
|
||||
struct regulator *regulator)
|
||||
static int qca_regulator_enable(struct qca_serdev *qcadev)
|
||||
{
|
||||
struct qca_power *power = qcadev->bt_power;
|
||||
int ret;
|
||||
|
||||
ret = regulator_set_voltage(regulator, vregs.min_uV,
|
||||
vregs.max_uV);
|
||||
/* Already enabled */
|
||||
if (power->vregs_on)
|
||||
return 0;
|
||||
|
||||
BT_DBG("enabling %d regulators)", power->num_vregs);
|
||||
|
||||
ret = regulator_bulk_enable(power->num_vregs, power->vreg_bulk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (vregs.load_uA)
|
||||
ret = regulator_set_load(regulator,
|
||||
vregs.load_uA);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regulator_enable(regulator);
|
||||
power->vregs_on = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qca_disable_regulator(struct qca_vreg vregs,
|
||||
struct regulator *regulator)
|
||||
static void qca_regulator_disable(struct qca_serdev *qcadev)
|
||||
{
|
||||
regulator_disable(regulator);
|
||||
regulator_set_voltage(regulator, 0, vregs.max_uV);
|
||||
if (vregs.load_uA)
|
||||
regulator_set_load(regulator, 0);
|
||||
struct qca_power *power;
|
||||
|
||||
}
|
||||
if (!qcadev)
|
||||
return;
|
||||
|
||||
static int qca_power_setup(struct hci_uart *hu, bool on)
|
||||
{
|
||||
struct qca_vreg *vregs;
|
||||
struct regulator_bulk_data *vreg_bulk;
|
||||
struct qca_serdev *qcadev;
|
||||
int i, num_vregs, ret = 0;
|
||||
power = qcadev->bt_power;
|
||||
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
if (!qcadev || !qcadev->bt_power || !qcadev->bt_power->vreg_data ||
|
||||
!qcadev->bt_power->vreg_bulk)
|
||||
return -EINVAL;
|
||||
/* Already disabled? */
|
||||
if (!power->vregs_on)
|
||||
return;
|
||||
|
||||
vregs = qcadev->bt_power->vreg_data->vregs;
|
||||
vreg_bulk = qcadev->bt_power->vreg_bulk;
|
||||
num_vregs = qcadev->bt_power->vreg_data->num_vregs;
|
||||
BT_DBG("on: %d", on);
|
||||
if (on && !qcadev->bt_power->vregs_on) {
|
||||
for (i = 0; i < num_vregs; i++) {
|
||||
ret = qca_enable_regulator(vregs[i],
|
||||
vreg_bulk[i].consumer);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
BT_ERR("failed to enable regulator:%s", vregs[i].name);
|
||||
/* turn off regulators which are enabled */
|
||||
for (i = i - 1; i >= 0; i--)
|
||||
qca_disable_regulator(vregs[i],
|
||||
vreg_bulk[i].consumer);
|
||||
} else {
|
||||
qcadev->bt_power->vregs_on = true;
|
||||
}
|
||||
} else if (!on && qcadev->bt_power->vregs_on) {
|
||||
/* turn off regulator in reverse order */
|
||||
i = qcadev->bt_power->vreg_data->num_vregs - 1;
|
||||
for ( ; i >= 0; i--)
|
||||
qca_disable_regulator(vregs[i], vreg_bulk[i].consumer);
|
||||
|
||||
qcadev->bt_power->vregs_on = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
regulator_bulk_disable(power->num_vregs, power->vreg_bulk);
|
||||
power->vregs_on = false;
|
||||
}
|
||||
|
||||
static int qca_init_regulators(struct qca_power *qca,
|
||||
const struct qca_vreg *vregs, size_t num_vregs)
|
||||
{
|
||||
struct regulator_bulk_data *bulk;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
qca->vreg_bulk = devm_kcalloc(qca->dev, num_vregs,
|
||||
sizeof(struct regulator_bulk_data),
|
||||
GFP_KERNEL);
|
||||
if (!qca->vreg_bulk)
|
||||
bulk = devm_kcalloc(qca->dev, num_vregs, sizeof(*bulk), GFP_KERNEL);
|
||||
if (!bulk)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_vregs; i++)
|
||||
qca->vreg_bulk[i].supply = vregs[i].name;
|
||||
bulk[i].supply = vregs[i].name;
|
||||
|
||||
return devm_regulator_bulk_get(qca->dev, num_vregs, qca->vreg_bulk);
|
||||
ret = devm_regulator_bulk_get(qca->dev, num_vregs, bulk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < num_vregs; i++) {
|
||||
ret = regulator_set_load(bulk[i].consumer, vregs[i].load_uA);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
qca->vreg_bulk = bulk;
|
||||
qca->num_vregs = num_vregs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qca_serdev_probe(struct serdev_device *serdev)
|
||||
|
@ -1500,7 +1476,6 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
|||
return -ENOMEM;
|
||||
|
||||
qcadev->bt_power->dev = &serdev->dev;
|
||||
qcadev->bt_power->vreg_data = data;
|
||||
err = qca_init_regulators(qcadev->bt_power, data->vregs,
|
||||
data->num_vregs);
|
||||
if (err) {
|
||||
|
|
|
@ -934,6 +934,14 @@ static void hci_req_directed_advertising(struct hci_request *req,
|
|||
return;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
|
||||
/* Some controllers might reject command if intervals are not
|
||||
* within range for undirected advertising.
|
||||
* BCM20702A0 is known to be affected by this.
|
||||
*/
|
||||
cp.min_interval = cpu_to_le16(0x0020);
|
||||
cp.max_interval = cpu_to_le16(0x0020);
|
||||
|
||||
cp.type = LE_ADV_DIRECT_IND;
|
||||
cp.own_address_type = own_addr_type;
|
||||
cp.direct_addr_type = conn->dst_type;
|
||||
|
|
|
@ -842,8 +842,8 @@ static int hci_init4_req(struct hci_request *req, unsigned long opt)
|
|||
if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT) {
|
||||
struct hci_cp_le_write_def_data_len cp;
|
||||
|
||||
cp.tx_len = hdev->le_max_tx_len;
|
||||
cp.tx_time = hdev->le_max_tx_time;
|
||||
cp.tx_len = cpu_to_le16(hdev->le_max_tx_len);
|
||||
cp.tx_time = cpu_to_le16(hdev->le_max_tx_time);
|
||||
hci_req_add(req, HCI_OP_LE_WRITE_DEF_DATA_LEN, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
|
@ -4440,7 +4440,14 @@ static void hci_rx_work(struct work_struct *work)
|
|||
hci_send_to_sock(hdev, skb);
|
||||
}
|
||||
|
||||
if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
|
||||
/* If the device has been opened in HCI_USER_CHANNEL,
|
||||
* the userspace has exclusive access to device.
|
||||
* When device is HCI_INIT, we still need to process
|
||||
* the data packets to the driver in order
|
||||
* to complete its setup().
|
||||
*/
|
||||
if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
|
||||
!test_bit(HCI_INIT, &hdev->flags)) {
|
||||
kfree_skb(skb);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -502,15 +502,12 @@ bool smp_irk_matches(struct hci_dev *hdev, const u8 irk[16],
|
|||
const bdaddr_t *bdaddr)
|
||||
{
|
||||
struct l2cap_chan *chan = hdev->smp_data;
|
||||
struct smp_dev *smp;
|
||||
u8 hash[3];
|
||||
int err;
|
||||
|
||||
if (!chan || !chan->data)
|
||||
return false;
|
||||
|
||||
smp = chan->data;
|
||||
|
||||
BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk);
|
||||
|
||||
err = smp_ah(irk, &bdaddr->b[3], hash);
|
||||
|
@ -523,14 +520,11 @@ bool smp_irk_matches(struct hci_dev *hdev, const u8 irk[16],
|
|||
int smp_generate_rpa(struct hci_dev *hdev, const u8 irk[16], bdaddr_t *rpa)
|
||||
{
|
||||
struct l2cap_chan *chan = hdev->smp_data;
|
||||
struct smp_dev *smp;
|
||||
int err;
|
||||
|
||||
if (!chan || !chan->data)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
smp = chan->data;
|
||||
|
||||
get_random_bytes(&rpa->b[3], 3);
|
||||
|
||||
rpa->b[5] &= 0x3f; /* Clear two most significant bits */
|
||||
|
|
Загрузка…
Ссылка в новой задаче