Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== pull request: bluetooth-next 2017-12-18 Here's the first bluetooth-next pull request for the 4.16 kernel. - hci_ll: multiple cleanups & fixes - Remove Gustavo Padovan from the MAINTAINERS file - Support BLE Adversing while connected (if the controller can do it) - DT updates for TI chips - Various other smaller cleanups & fixes 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:
Коммит
748a709974
|
@ -1,10 +1,18 @@
|
|||
TI WiLink 7/8 (wl12xx/wl18xx) Shared Transport BT/FM/GPS devices
|
||||
Texas Instruments Bluetooth Chips
|
||||
---------------------------------
|
||||
|
||||
This documents the binding structure and common properties for serial
|
||||
attached TI Bluetooth devices. The following chips are included in this
|
||||
binding:
|
||||
|
||||
* TI CC256x Bluetooth devices
|
||||
* TI WiLink 7/8 (wl12xx/wl18xx) Shared Transport BT/FM/GPS devices
|
||||
|
||||
TI WiLink devices have a UART interface for providing Bluetooth, FM radio,
|
||||
and GPS over what's called "shared transport". The shared transport is
|
||||
standard BT HCI protocol with additional channels for the other functions.
|
||||
|
||||
These devices also have a separate WiFi interface as described in
|
||||
TI WiLink devices also have a separate WiFi interface as described in
|
||||
wireless/ti,wlcore.txt.
|
||||
|
||||
This bindings follows the UART slave device binding in
|
||||
|
@ -12,6 +20,7 @@ This bindings follows the UART slave device binding in
|
|||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"ti,cc2560"
|
||||
"ti,wl1271-st"
|
||||
"ti,wl1273-st"
|
||||
"ti,wl1281-st"
|
||||
|
@ -32,6 +41,9 @@ Optional properties:
|
|||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names : Must include the following entry:
|
||||
"ext_clock" (External clock provided to the TI combo chip).
|
||||
- nvmem-cells: phandle to nvmem data cell that contains a 6 byte BD address
|
||||
with the most significant byte first (big-endian).
|
||||
- nvmem-cell-names: "bd-address" (required when nvmem-cells is specified)
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -43,5 +55,7 @@ Example:
|
|||
enable-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
|
||||
clocks = <&clk32k_wl18xx>;
|
||||
clock-names = "ext_clock";
|
||||
nvmem-cells = <&bd_address>;
|
||||
nvmem-cell-names = "bd-address";
|
||||
};
|
||||
};
|
|
@ -2689,7 +2689,6 @@ F: drivers/mtd/devices/block2mtd.c
|
|||
|
||||
BLUETOOTH DRIVERS
|
||||
M: Marcel Holtmann <marcel@holtmann.org>
|
||||
M: Gustavo Padovan <gustavo@padovan.org>
|
||||
M: Johan Hedberg <johan.hedberg@gmail.com>
|
||||
L: linux-bluetooth@vger.kernel.org
|
||||
W: http://www.bluez.org/
|
||||
|
@ -2700,7 +2699,6 @@ F: drivers/bluetooth/
|
|||
|
||||
BLUETOOTH SUBSYSTEM
|
||||
M: Marcel Holtmann <marcel@holtmann.org>
|
||||
M: Gustavo Padovan <gustavo@padovan.org>
|
||||
M: Johan Hedberg <johan.hedberg@gmail.com>
|
||||
L: linux-bluetooth@vger.kernel.org
|
||||
W: http://www.bluez.org/
|
||||
|
|
|
@ -31,6 +31,16 @@ config BT_HCIBTUSB
|
|||
Say Y here to compile support for Bluetooth USB devices into the
|
||||
kernel or say M to compile it as module (btusb).
|
||||
|
||||
config BT_HCIBTUSB_AUTOSUSPEND
|
||||
bool "Enable USB autosuspend for Bluetooth USB devices by default"
|
||||
depends on BT_HCIBTUSB
|
||||
help
|
||||
Say Y here to enable USB autosuspend for Bluetooth USB devices by
|
||||
default.
|
||||
|
||||
This can be overridden by passing btusb.enable_autosuspend=[y|n]
|
||||
on the kernel commandline.
|
||||
|
||||
config BT_HCIBTUSB_BCM
|
||||
bool "Broadcom protocol support"
|
||||
depends on BT_HCIBTUSB
|
||||
|
|
|
@ -302,9 +302,7 @@ static void bluecard_write_wakeup(struct bluecard_info *info)
|
|||
}
|
||||
|
||||
/* Wait until the command reaches the baseband */
|
||||
prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(HZ/10);
|
||||
finish_wait(&wq, &wait);
|
||||
mdelay(100);
|
||||
|
||||
/* Set baud on baseband */
|
||||
info->ctrl_reg &= ~0x03;
|
||||
|
@ -316,9 +314,7 @@ static void bluecard_write_wakeup(struct bluecard_info *info)
|
|||
outb(info->ctrl_reg, iobase + REG_CONTROL);
|
||||
|
||||
/* Wait before the next HCI packet can be send */
|
||||
prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(HZ);
|
||||
finish_wait(&wq, &wait);
|
||||
mdelay(1000);
|
||||
}
|
||||
|
||||
if (len == skb->len) {
|
||||
|
|
|
@ -88,6 +88,7 @@ static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
break;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
kfree_skb(skb);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
|
||||
|
@ -292,6 +293,14 @@ static int btsdio_probe(struct sdio_func *func,
|
|||
tuple = tuple->next;
|
||||
}
|
||||
|
||||
/* BCM43341 devices soldered onto the PCB (non-removable) use an
|
||||
* uart connection for bluetooth, ignore the BT SDIO interface.
|
||||
*/
|
||||
if (func->vendor == SDIO_VENDOR_ID_BROADCOM &&
|
||||
func->device == SDIO_DEVICE_ID_BROADCOM_43341 &&
|
||||
!mmc_card_is_removable(func->card->host))
|
||||
return -ENODEV;
|
||||
|
||||
data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
static bool disable_scofix;
|
||||
static bool force_scofix;
|
||||
static bool enable_autosuspend = IS_ENABLED(CONFIG_BT_HCIBTUSB_AUTOSUSPEND);
|
||||
|
||||
static bool reset = true;
|
||||
|
||||
|
@ -3213,6 +3214,9 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
}
|
||||
#endif
|
||||
|
||||
if (enable_autosuspend)
|
||||
usb_enable_autosuspend(data->udev);
|
||||
|
||||
err = hci_register_dev(hdev);
|
||||
if (err < 0)
|
||||
goto out_free_dev;
|
||||
|
@ -3425,6 +3429,9 @@ MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size");
|
|||
module_param(force_scofix, bool, 0644);
|
||||
MODULE_PARM_DESC(force_scofix, "Force fixup of wrong SCO buffers size");
|
||||
|
||||
module_param(enable_autosuspend, bool, 0644);
|
||||
MODULE_PARM_DESC(enable_autosuspend, "Enable USB autosuspend by default");
|
||||
|
||||
module_param(reset, bool, 0644);
|
||||
MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
|
||||
|
||||
|
|
|
@ -939,6 +939,7 @@ static const struct acpi_device_id bcm_acpi_match[] = {
|
|||
{ "BCM2E65", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
|
||||
{ "BCM2E67", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
|
||||
{ "BCM2E71", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
|
||||
{ "BCM2E72", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
|
||||
{ "BCM2E7B", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
|
||||
{ "BCM2E7C", (kernel_ulong_t)&acpi_bcm_int_last_gpios },
|
||||
{ "BCM2E7E", (kernel_ulong_t)&acpi_bcm_int_first_gpios },
|
||||
|
|
|
@ -53,9 +53,14 @@
|
|||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
|
||||
#include "hci_uart.h"
|
||||
|
||||
/* Vendor-specific HCI commands */
|
||||
#define HCI_VS_WRITE_BD_ADDR 0xfc06
|
||||
#define HCI_VS_UPDATE_UART_HCI_BAUDRATE 0xff36
|
||||
|
||||
/* HCILL commands */
|
||||
#define HCILL_GO_TO_SLEEP_IND 0x30
|
||||
#define HCILL_GO_TO_SLEEP_ACK 0x31
|
||||
|
@ -86,6 +91,7 @@ struct ll_device {
|
|||
struct serdev_device *serdev;
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct clk *ext_clk;
|
||||
bdaddr_t bdaddr;
|
||||
};
|
||||
|
||||
struct ll_struct {
|
||||
|
@ -620,7 +626,7 @@ static int download_firmware(struct ll_device *lldev)
|
|||
case ACTION_SEND_COMMAND: /* action send */
|
||||
bt_dev_dbg(lldev->hu.hdev, "S");
|
||||
cmd = (struct hci_command *)action_ptr;
|
||||
if (cmd->opcode == 0xff36) {
|
||||
if (cmd->opcode == HCI_VS_UPDATE_UART_HCI_BAUDRATE) {
|
||||
/* ignore remote change
|
||||
* baud rate HCI VS command
|
||||
*/
|
||||
|
@ -628,11 +634,11 @@ static int download_firmware(struct ll_device *lldev)
|
|||
break;
|
||||
}
|
||||
if (cmd->prefix != 1)
|
||||
bt_dev_dbg(lldev->hu.hdev, "command type %d\n", cmd->prefix);
|
||||
bt_dev_dbg(lldev->hu.hdev, "command type %d", cmd->prefix);
|
||||
|
||||
skb = __hci_cmd_sync(lldev->hu.hdev, cmd->opcode, cmd->plen, &cmd->speed, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_err(lldev->hu.hdev, "send command failed\n");
|
||||
bt_dev_err(lldev->hu.hdev, "send command failed");
|
||||
err = PTR_ERR(skb);
|
||||
goto out_rel_fw;
|
||||
}
|
||||
|
@ -659,6 +665,24 @@ out_rel_fw:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ll_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
{
|
||||
bdaddr_t bdaddr_swapped;
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* HCI_VS_WRITE_BD_ADDR (at least on a CC2560A chip) expects the BD
|
||||
* address to be MSB first, but bdaddr_t has the convention of being
|
||||
* LSB first.
|
||||
*/
|
||||
baswap(&bdaddr_swapped, bdaddr);
|
||||
skb = __hci_cmd_sync(hdev, HCI_VS_WRITE_BD_ADDR, sizeof(bdaddr_t),
|
||||
&bdaddr_swapped, HCI_INIT_TIMEOUT);
|
||||
if (!IS_ERR(skb))
|
||||
kfree_skb(skb);
|
||||
|
||||
return PTR_ERR_OR_ZERO(skb);
|
||||
}
|
||||
|
||||
static int ll_setup(struct hci_uart *hu)
|
||||
{
|
||||
int err, retry = 3;
|
||||
|
@ -671,14 +695,20 @@ static int ll_setup(struct hci_uart *hu)
|
|||
|
||||
lldev = serdev_device_get_drvdata(serdev);
|
||||
|
||||
hu->hdev->set_bdaddr = ll_set_bdaddr;
|
||||
|
||||
serdev_device_set_flow_control(serdev, true);
|
||||
|
||||
do {
|
||||
/* Configure BT_EN to HIGH state */
|
||||
/* Reset the Bluetooth device */
|
||||
gpiod_set_value_cansleep(lldev->enable_gpio, 0);
|
||||
msleep(5);
|
||||
gpiod_set_value_cansleep(lldev->enable_gpio, 1);
|
||||
msleep(100);
|
||||
err = serdev_device_wait_for_cts(serdev, true, 200);
|
||||
if (err) {
|
||||
bt_dev_err(hu->hdev, "Failed to get CTS");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = download_firmware(lldev);
|
||||
if (!err)
|
||||
|
@ -691,6 +721,18 @@ static int ll_setup(struct hci_uart *hu)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
/* Set BD address if one was specified at probe */
|
||||
if (!bacmp(&lldev->bdaddr, BDADDR_NONE)) {
|
||||
/* This means that there was an error getting the BD address
|
||||
* during probe, so mark the device as having a bad address.
|
||||
*/
|
||||
set_bit(HCI_QUIRK_INVALID_BDADDR, &hu->hdev->quirks);
|
||||
} else if (bacmp(&lldev->bdaddr, BDADDR_ANY)) {
|
||||
err = ll_set_bdaddr(hu->hdev, &lldev->bdaddr);
|
||||
if (err)
|
||||
set_bit(HCI_QUIRK_INVALID_BDADDR, &hu->hdev->quirks);
|
||||
}
|
||||
|
||||
/* Operational speed if any */
|
||||
if (hu->oper_speed)
|
||||
speed = hu->oper_speed;
|
||||
|
@ -700,7 +742,12 @@ static int ll_setup(struct hci_uart *hu)
|
|||
speed = 0;
|
||||
|
||||
if (speed) {
|
||||
struct sk_buff *skb = __hci_cmd_sync(hu->hdev, 0xff36, sizeof(speed), &speed, HCI_INIT_TIMEOUT);
|
||||
__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);
|
||||
|
@ -716,6 +763,7 @@ static int hci_ti_probe(struct serdev_device *serdev)
|
|||
{
|
||||
struct hci_uart *hu;
|
||||
struct ll_device *lldev;
|
||||
struct nvmem_cell *bdaddr_cell;
|
||||
u32 max_speed = 3000000;
|
||||
|
||||
lldev = devm_kzalloc(&serdev->dev, sizeof(struct ll_device), GFP_KERNEL);
|
||||
|
@ -737,6 +785,52 @@ static int hci_ti_probe(struct serdev_device *serdev)
|
|||
of_property_read_u32(serdev->dev.of_node, "max-speed", &max_speed);
|
||||
hci_uart_set_speeds(hu, 115200, max_speed);
|
||||
|
||||
/* optional BD address from nvram */
|
||||
bdaddr_cell = nvmem_cell_get(&serdev->dev, "bd-address");
|
||||
if (IS_ERR(bdaddr_cell)) {
|
||||
int err = PTR_ERR(bdaddr_cell);
|
||||
|
||||
if (err == -EPROBE_DEFER)
|
||||
return err;
|
||||
|
||||
/* ENOENT means there is no matching nvmem cell and ENOSYS
|
||||
* means that nvmem is not enabled in the kernel configuration.
|
||||
*/
|
||||
if (err != -ENOENT && err != -ENOSYS) {
|
||||
/* If there was some other error, give userspace a
|
||||
* chance to fix the problem instead of failing to load
|
||||
* the driver. Using BDADDR_NONE as a flag that is
|
||||
* tested later in the setup function.
|
||||
*/
|
||||
dev_warn(&serdev->dev,
|
||||
"Failed to get \"bd-address\" nvmem cell (%d)\n",
|
||||
err);
|
||||
bacpy(&lldev->bdaddr, BDADDR_NONE);
|
||||
}
|
||||
} else {
|
||||
bdaddr_t *bdaddr;
|
||||
size_t len;
|
||||
|
||||
bdaddr = nvmem_cell_read(bdaddr_cell, &len);
|
||||
nvmem_cell_put(bdaddr_cell);
|
||||
if (IS_ERR(bdaddr)) {
|
||||
dev_err(&serdev->dev, "Failed to read nvmem bd-address\n");
|
||||
return PTR_ERR(bdaddr);
|
||||
}
|
||||
if (len != sizeof(bdaddr_t)) {
|
||||
dev_err(&serdev->dev, "Invalid nvmem bd-address length\n");
|
||||
kfree(bdaddr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* As per the device tree bindings, the value from nvmem is
|
||||
* expected to be MSB first, but in the kernel it is expected
|
||||
* that bdaddr_t is LSB first.
|
||||
*/
|
||||
baswap(&lldev->bdaddr, bdaddr);
|
||||
kfree(bdaddr);
|
||||
}
|
||||
|
||||
return hci_uart_register_device(hu, &llp);
|
||||
}
|
||||
|
||||
|
@ -748,6 +842,7 @@ static void hci_ti_remove(struct serdev_device *serdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id hci_ti_of_match[] = {
|
||||
{ .compatible = "ti,cc2560" },
|
||||
{ .compatible = "ti,wl1271-st" },
|
||||
{ .compatible = "ti,wl1273-st" },
|
||||
{ .compatible = "ti,wl1281-st" },
|
||||
|
|
|
@ -932,6 +932,9 @@ static int qca_setup(struct hci_uart *hu)
|
|||
if (!ret) {
|
||||
set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
|
||||
qca_debugfs_init(hdev);
|
||||
} else if (ret == -ENOENT) {
|
||||
/* No patch/nvm-config found, run with original fw/config */
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Setup bdaddr */
|
||||
|
|
|
@ -303,6 +303,7 @@ int hci_uart_register_device(struct hci_uart *hu,
|
|||
hci_set_drvdata(hdev, hu);
|
||||
|
||||
INIT_WORK(&hu->write_work, hci_uart_write_work);
|
||||
percpu_init_rwsem(&hu->proto_lock);
|
||||
|
||||
/* Only when vendor specific setup callback is provided, consider
|
||||
* the manufacturer information valid. This avoids filling in the
|
||||
|
|
|
@ -766,43 +766,39 @@ static int __init bt_init(void)
|
|||
return err;
|
||||
|
||||
err = sock_register(&bt_sock_family_ops);
|
||||
if (err < 0) {
|
||||
bt_sysfs_cleanup();
|
||||
return err;
|
||||
}
|
||||
if (err)
|
||||
goto cleanup_sysfs;
|
||||
|
||||
BT_INFO("HCI device and connection manager initialized");
|
||||
|
||||
err = hci_sock_init();
|
||||
if (err < 0)
|
||||
goto error;
|
||||
if (err)
|
||||
goto unregister_socket;
|
||||
|
||||
err = l2cap_init();
|
||||
if (err < 0)
|
||||
goto sock_err;
|
||||
if (err)
|
||||
goto cleanup_socket;
|
||||
|
||||
err = sco_init();
|
||||
if (err < 0) {
|
||||
l2cap_exit();
|
||||
goto sock_err;
|
||||
}
|
||||
if (err)
|
||||
goto cleanup_cap;
|
||||
|
||||
err = mgmt_init();
|
||||
if (err < 0) {
|
||||
sco_exit();
|
||||
l2cap_exit();
|
||||
goto sock_err;
|
||||
}
|
||||
if (err)
|
||||
goto cleanup_sco;
|
||||
|
||||
return 0;
|
||||
|
||||
sock_err:
|
||||
cleanup_sco:
|
||||
sco_exit();
|
||||
cleanup_cap:
|
||||
l2cap_exit();
|
||||
cleanup_socket:
|
||||
hci_sock_cleanup();
|
||||
|
||||
error:
|
||||
unregister_socket:
|
||||
sock_unregister(PF_BLUETOOTH);
|
||||
cleanup_sysfs:
|
||||
bt_sysfs_cleanup();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,9 @@ static int __name ## _show(struct seq_file *f, void *ptr) \
|
|||
return 0; \
|
||||
} \
|
||||
\
|
||||
DEFINE_SHOW_ATTRIBUTE(__name)
|
||||
|
||||
#define DEFINE_SHOW_ATTRIBUTE(__name) \
|
||||
static int __name ## _open(struct inode *inode, struct file *file) \
|
||||
{ \
|
||||
return single_open(file, __name ## _show, inode->i_private); \
|
||||
|
@ -106,37 +109,16 @@ static int features_show(struct seq_file *f, void *ptr)
|
|||
u8 p;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
for (p = 0; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) {
|
||||
seq_printf(f, "%2u: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
|
||||
"0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", p,
|
||||
hdev->features[p][0], hdev->features[p][1],
|
||||
hdev->features[p][2], hdev->features[p][3],
|
||||
hdev->features[p][4], hdev->features[p][5],
|
||||
hdev->features[p][6], hdev->features[p][7]);
|
||||
}
|
||||
for (p = 0; p < HCI_MAX_PAGES && p <= hdev->max_page; p++)
|
||||
seq_printf(f, "%2u: %8ph\n", p, hdev->features[p]);
|
||||
if (lmp_le_capable(hdev))
|
||||
seq_printf(f, "LE: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
|
||||
"0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
|
||||
hdev->le_features[0], hdev->le_features[1],
|
||||
hdev->le_features[2], hdev->le_features[3],
|
||||
hdev->le_features[4], hdev->le_features[5],
|
||||
hdev->le_features[6], hdev->le_features[7]);
|
||||
seq_printf(f, "LE: %8ph\n", hdev->le_features);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int features_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, features_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations features_fops = {
|
||||
.open = features_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(features);
|
||||
|
||||
static int device_id_show(struct seq_file *f, void *ptr)
|
||||
{
|
||||
|
@ -150,17 +132,7 @@ static int device_id_show(struct seq_file *f, void *ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int device_id_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, device_id_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations device_id_fops = {
|
||||
.open = device_id_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(device_id);
|
||||
|
||||
static int device_list_show(struct seq_file *f, void *ptr)
|
||||
{
|
||||
|
@ -180,17 +152,7 @@ static int device_list_show(struct seq_file *f, void *ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int device_list_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, device_list_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations device_list_fops = {
|
||||
.open = device_list_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(device_list);
|
||||
|
||||
static int blacklist_show(struct seq_file *f, void *p)
|
||||
{
|
||||
|
@ -205,17 +167,7 @@ static int blacklist_show(struct seq_file *f, void *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int blacklist_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, blacklist_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations blacklist_fops = {
|
||||
.open = blacklist_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(blacklist);
|
||||
|
||||
static int uuids_show(struct seq_file *f, void *p)
|
||||
{
|
||||
|
@ -240,17 +192,7 @@ static int uuids_show(struct seq_file *f, void *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int uuids_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, uuids_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations uuids_fops = {
|
||||
.open = uuids_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(uuids);
|
||||
|
||||
static int remote_oob_show(struct seq_file *f, void *ptr)
|
||||
{
|
||||
|
@ -269,17 +211,7 @@ static int remote_oob_show(struct seq_file *f, void *ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int remote_oob_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, remote_oob_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations remote_oob_fops = {
|
||||
.open = remote_oob_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(remote_oob);
|
||||
|
||||
static int conn_info_min_age_set(void *data, u64 val)
|
||||
{
|
||||
|
@ -443,17 +375,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int inquiry_cache_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, inquiry_cache_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations inquiry_cache_fops = {
|
||||
.open = inquiry_cache_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(inquiry_cache);
|
||||
|
||||
static int link_keys_show(struct seq_file *f, void *ptr)
|
||||
{
|
||||
|
@ -469,17 +391,7 @@ static int link_keys_show(struct seq_file *f, void *ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int link_keys_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, link_keys_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations link_keys_fops = {
|
||||
.open = link_keys_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(link_keys);
|
||||
|
||||
static int dev_class_show(struct seq_file *f, void *ptr)
|
||||
{
|
||||
|
@ -493,17 +405,7 @@ static int dev_class_show(struct seq_file *f, void *ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dev_class_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, dev_class_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations dev_class_fops = {
|
||||
.open = dev_class_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(dev_class);
|
||||
|
||||
static int voice_setting_get(void *data, u64 *val)
|
||||
{
|
||||
|
@ -692,17 +594,7 @@ static int identity_show(struct seq_file *f, void *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int identity_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, identity_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations identity_fops = {
|
||||
.open = identity_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(identity);
|
||||
|
||||
static int rpa_timeout_set(void *data, u64 val)
|
||||
{
|
||||
|
@ -746,17 +638,7 @@ static int random_address_show(struct seq_file *f, void *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int random_address_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, random_address_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations random_address_fops = {
|
||||
.open = random_address_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(random_address);
|
||||
|
||||
static int static_address_show(struct seq_file *f, void *p)
|
||||
{
|
||||
|
@ -769,17 +651,7 @@ static int static_address_show(struct seq_file *f, void *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int static_address_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, static_address_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations static_address_fops = {
|
||||
.open = static_address_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(static_address);
|
||||
|
||||
static ssize_t force_static_address_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
|
@ -841,17 +713,7 @@ static int white_list_show(struct seq_file *f, void *ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int white_list_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, white_list_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations white_list_fops = {
|
||||
.open = white_list_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(white_list);
|
||||
|
||||
static int identity_resolving_keys_show(struct seq_file *f, void *ptr)
|
||||
{
|
||||
|
@ -869,18 +731,7 @@ static int identity_resolving_keys_show(struct seq_file *f, void *ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int identity_resolving_keys_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, identity_resolving_keys_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations identity_resolving_keys_fops = {
|
||||
.open = identity_resolving_keys_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(identity_resolving_keys);
|
||||
|
||||
static int long_term_keys_show(struct seq_file *f, void *ptr)
|
||||
{
|
||||
|
@ -898,17 +749,7 @@ static int long_term_keys_show(struct seq_file *f, void *ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int long_term_keys_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, long_term_keys_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations long_term_keys_fops = {
|
||||
.open = long_term_keys_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(long_term_keys);
|
||||
|
||||
static int conn_min_interval_set(void *data, u64 val)
|
||||
{
|
||||
|
|
|
@ -919,6 +919,43 @@ static bool adv_use_rpa(struct hci_dev *hdev, uint32_t flags)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool is_advertising_allowed(struct hci_dev *hdev, bool connectable)
|
||||
{
|
||||
/* If there is no connection we are OK to advertise. */
|
||||
if (hci_conn_num(hdev, LE_LINK) == 0)
|
||||
return true;
|
||||
|
||||
/* Check le_states if there is any connection in slave role. */
|
||||
if (hdev->conn_hash.le_num_slave > 0) {
|
||||
/* Slave connection state and non connectable mode bit 20. */
|
||||
if (!connectable && !(hdev->le_states[2] & 0x10))
|
||||
return false;
|
||||
|
||||
/* Slave connection state and connectable mode bit 38
|
||||
* and scannable bit 21.
|
||||
*/
|
||||
if (connectable && (!(hdev->le_states[4] & 0x01) ||
|
||||
!(hdev->le_states[2] & 0x40)))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check le_states if there is any connection in master role. */
|
||||
if (hci_conn_num(hdev, LE_LINK) != hdev->conn_hash.le_num_slave) {
|
||||
/* Master connection state and non connectable mode bit 18. */
|
||||
if (!connectable && !(hdev->le_states[2] & 0x02))
|
||||
return false;
|
||||
|
||||
/* Master connection state and connectable mode bit 35 and
|
||||
* scannable 19.
|
||||
*/
|
||||
if (connectable && (!(hdev->le_states[4] & 0x10) ||
|
||||
!(hdev->le_states[2] & 0x08)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void __hci_req_enable_advertising(struct hci_request *req)
|
||||
{
|
||||
struct hci_dev *hdev = req->hdev;
|
||||
|
@ -927,7 +964,15 @@ void __hci_req_enable_advertising(struct hci_request *req)
|
|||
bool connectable;
|
||||
u32 flags;
|
||||
|
||||
if (hci_conn_num(hdev, LE_LINK) > 0)
|
||||
flags = get_adv_instance_flags(hdev, hdev->cur_adv_instance);
|
||||
|
||||
/* If the "connectable" instance flag was not set, then choose between
|
||||
* ADV_IND and ADV_NONCONN_IND based on the global connectable setting.
|
||||
*/
|
||||
connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
|
||||
mgmt_get_connectable(hdev);
|
||||
|
||||
if (!is_advertising_allowed(hdev, connectable))
|
||||
return;
|
||||
|
||||
if (hci_dev_test_flag(hdev, HCI_LE_ADV))
|
||||
|
@ -940,14 +985,6 @@ void __hci_req_enable_advertising(struct hci_request *req)
|
|||
*/
|
||||
hci_dev_clear_flag(hdev, HCI_LE_ADV);
|
||||
|
||||
flags = get_adv_instance_flags(hdev, hdev->cur_adv_instance);
|
||||
|
||||
/* If the "connectable" instance flag was not set, then choose between
|
||||
* ADV_IND and ADV_NONCONN_IND based on the global connectable setting.
|
||||
*/
|
||||
connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
|
||||
mgmt_get_connectable(hdev);
|
||||
|
||||
/* Set require_privacy to true only when non-connectable
|
||||
* advertising is used. In that case it is fine to use a
|
||||
* non-resolvable private address.
|
||||
|
@ -1985,13 +2022,6 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void disable_advertising(struct hci_request *req)
|
||||
{
|
||||
u8 enable = 0x00;
|
||||
|
||||
hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
|
||||
}
|
||||
|
||||
static int active_scan(struct hci_request *req, unsigned long opt)
|
||||
{
|
||||
uint16_t interval = opt;
|
||||
|
@ -2017,7 +2047,7 @@ static int active_scan(struct hci_request *req, unsigned long opt)
|
|||
cancel_adv_timeout(hdev);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
disable_advertising(req);
|
||||
__hci_req_disable_advertising(req);
|
||||
}
|
||||
|
||||
/* If controller is scanning, it means the background scanning is
|
||||
|
|
Загрузка…
Ссылка в новой задаче