You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== pull request: bluetooth-next 2015-03-27 Here's another set of Bluetooth & 802.15.4 patches for 4.1: - New API to control LE advertising data (i.e. peripheral role) - mac802154 & at86rf230 cleanups - Support for toggling quirks from debugfs (useful for testing) - Memory leak fix for LE scanning - Extra version info reading support for Broadcom controllers Please let me know if there are any issues pulling. Thanks. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
@@ -53,6 +54,7 @@ static struct usb_driver btusb_driver;
|
||||
#define BTUSB_INTEL_NEW 0x2000
|
||||
#define BTUSB_AMP 0x4000
|
||||
#define BTUSB_QCA_ROME 0x8000
|
||||
#define BTUSB_BCM_APPLE 0x10000
|
||||
|
||||
static const struct usb_device_id btusb_table[] = {
|
||||
/* Generic Bluetooth USB device */
|
||||
@@ -62,7 +64,8 @@ static const struct usb_device_id btusb_table[] = {
|
||||
{ USB_DEVICE_INFO(0xe0, 0x01, 0x04), .driver_info = BTUSB_AMP },
|
||||
|
||||
/* Apple-specific (Broadcom) devices */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) },
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01),
|
||||
.driver_info = BTUSB_BCM_APPLE },
|
||||
|
||||
/* MediaTek MT76x0E */
|
||||
{ USB_DEVICE(0x0e8d, 0x763f) },
|
||||
@@ -2458,6 +2461,25 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
|
||||
subver = le16_to_cpu(ver->lmp_subver);
|
||||
kfree_skb(skb);
|
||||
|
||||
/* Read Verbose Config Version Info */
|
||||
skb = __hci_cmd_sync(hdev, 0xfc79, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
BT_ERR("%s: BCM: Read Verbose Version failed (%ld)",
|
||||
hdev->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (skb->len != 7) {
|
||||
BT_ERR("%s: BCM: Read Verbose Version event length mismatch",
|
||||
hdev->name);
|
||||
kfree_skb(skb);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]);
|
||||
kfree_skb(skb);
|
||||
|
||||
for (i = 0; bcm_subver_table[i].name; i++) {
|
||||
if (subver == bcm_subver_table[i].subver) {
|
||||
hw_name = bcm_subver_table[i].name;
|
||||
@@ -2615,6 +2637,34 @@ static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_setup_bcm_apple(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
/* Read Verbose Config Version Info */
|
||||
skb = __hci_cmd_sync(hdev, 0xfc79, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
BT_ERR("%s: BCM: Read Verbose Version failed (%d)",
|
||||
hdev->name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (skb->len != 7) {
|
||||
BT_ERR("%s: BCM: Read Verbose Version event length mismatch",
|
||||
hdev->name);
|
||||
kfree_skb(skb);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1],
|
||||
get_unaligned_le16(skb->data + 5));
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,
|
||||
const bdaddr_t *bdaddr)
|
||||
{
|
||||
@@ -3014,6 +3064,11 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
|
||||
}
|
||||
|
||||
if (id->driver_info & BTUSB_BCM_APPLE) {
|
||||
hdev->setup = btusb_setup_bcm_apple;
|
||||
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
|
||||
}
|
||||
|
||||
if (id->driver_info & BTUSB_INTEL) {
|
||||
hdev->setup = btusb_setup_intel;
|
||||
hdev->shutdown = btusb_shutdown_intel;
|
||||
|
||||
@@ -261,6 +261,16 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hci_uart_setup(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
|
||||
if (hu->proto->setup)
|
||||
return hu->proto->setup(hu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------ LDISC part ------ */
|
||||
/* hci_uart_tty_open
|
||||
*
|
||||
@@ -426,6 +436,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
|
||||
hdev->close = hci_uart_close;
|
||||
hdev->flush = hci_uart_flush;
|
||||
hdev->send = hci_uart_send_frame;
|
||||
hdev->setup = hci_uart_setup;
|
||||
SET_HCIDEV_DEV(hdev, hu->tty->dev);
|
||||
|
||||
if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
|
||||
|
||||
@@ -59,6 +59,7 @@ struct hci_uart_proto {
|
||||
int (*flush)(struct hci_uart *hu);
|
||||
int (*recv)(struct hci_uart *hu, void *data, int len);
|
||||
int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
|
||||
int (*setup)(struct hci_uart *hu);
|
||||
struct sk_buff *(*dequeue)(struct hci_uart *hu);
|
||||
};
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/at86rf230.h>
|
||||
#include <linux/regmap.h>
|
||||
@@ -96,8 +95,6 @@ struct at86rf230_local {
|
||||
unsigned long cal_timeout;
|
||||
s8 max_frame_retries;
|
||||
bool is_tx;
|
||||
/* spinlock for is_tx protection */
|
||||
spinlock_t lock;
|
||||
u8 tx_retry;
|
||||
struct sk_buff *tx_skb;
|
||||
struct at86rf230_state_change tx;
|
||||
@@ -460,6 +457,7 @@ at86rf230_async_error_recover(void *context)
|
||||
struct at86rf230_state_change *ctx = context;
|
||||
struct at86rf230_local *lp = ctx->lp;
|
||||
|
||||
lp->is_tx = 0;
|
||||
at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL, false);
|
||||
ieee802154_wake_queue(lp->hw);
|
||||
}
|
||||
@@ -878,10 +876,8 @@ at86rf230_rx_trac_check(void *context)
|
||||
static void
|
||||
at86rf230_irq_trx_end(struct at86rf230_local *lp)
|
||||
{
|
||||
spin_lock(&lp->lock);
|
||||
if (lp->is_tx) {
|
||||
lp->is_tx = 0;
|
||||
spin_unlock(&lp->lock);
|
||||
|
||||
if (lp->tx_aret)
|
||||
at86rf230_async_state_change(lp, &lp->irq,
|
||||
@@ -894,7 +890,6 @@ at86rf230_irq_trx_end(struct at86rf230_local *lp)
|
||||
at86rf230_tx_complete,
|
||||
true);
|
||||
} else {
|
||||
spin_unlock(&lp->lock);
|
||||
at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq,
|
||||
at86rf230_rx_trac_check, true);
|
||||
}
|
||||
@@ -964,9 +959,7 @@ at86rf230_write_frame(void *context)
|
||||
u8 *buf = ctx->buf;
|
||||
int rc;
|
||||
|
||||
spin_lock(&lp->lock);
|
||||
lp->is_tx = 1;
|
||||
spin_unlock(&lp->lock);
|
||||
|
||||
buf[0] = CMD_FB | CMD_WRITE;
|
||||
buf[1] = skb->len + 2;
|
||||
@@ -1698,7 +1691,6 @@ static int at86rf230_probe(struct spi_device *spi)
|
||||
if (rc < 0)
|
||||
goto free_dev;
|
||||
|
||||
spin_lock_init(&lp->lock);
|
||||
init_completion(&lp->state_complete);
|
||||
|
||||
spi_set_drvdata(spi, lp);
|
||||
|
||||
@@ -227,6 +227,7 @@ enum {
|
||||
HCI_LE_ENABLED,
|
||||
HCI_ADVERTISING,
|
||||
HCI_ADVERTISING_CONNECTABLE,
|
||||
HCI_ADVERTISING_INSTANCE,
|
||||
HCI_CONNECTABLE,
|
||||
HCI_DISCOVERABLE,
|
||||
HCI_LIMITED_DISCOVERABLE,
|
||||
@@ -465,6 +466,7 @@ enum {
|
||||
#define EIR_SSP_HASH_C 0x0E /* Simple Pairing Hash C */
|
||||
#define EIR_SSP_RAND_R 0x0F /* Simple Pairing Randomizer R */
|
||||
#define EIR_DEVICE_ID 0x10 /* device ID */
|
||||
#define EIR_APPEARANCE 0x19 /* Device appearance */
|
||||
#define EIR_LE_BDADDR 0x1B /* LE Bluetooth device address */
|
||||
#define EIR_LE_ROLE 0x1C /* LE role */
|
||||
#define EIR_LE_SC_CONFIRM 0x22 /* LE SC Confirmation Value */
|
||||
|
||||
@@ -155,6 +155,17 @@ struct oob_data {
|
||||
u8 rand256[16];
|
||||
};
|
||||
|
||||
struct adv_info {
|
||||
struct delayed_work timeout_exp;
|
||||
__u8 instance;
|
||||
__u32 flags;
|
||||
__u16 timeout;
|
||||
__u16 adv_data_len;
|
||||
__u8 adv_data[HCI_MAX_AD_LENGTH];
|
||||
__u16 scan_rsp_len;
|
||||
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
|
||||
};
|
||||
|
||||
#define HCI_MAX_SHORT_NAME_LENGTH 10
|
||||
|
||||
/* Default LE RPA expiry time, 15 minutes */
|
||||
@@ -364,6 +375,8 @@ struct hci_dev {
|
||||
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
|
||||
__u8 scan_rsp_data_len;
|
||||
|
||||
struct adv_info adv_instance;
|
||||
|
||||
__u8 irk[16];
|
||||
__u32 rpa_timeout;
|
||||
struct delayed_work rpa_expired;
|
||||
@@ -550,6 +563,11 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
|
||||
hdev->discovery.scan_duration = 0;
|
||||
}
|
||||
|
||||
static inline void adv_info_init(struct hci_dev *hdev)
|
||||
{
|
||||
memset(&hdev->adv_instance, 0, sizeof(struct adv_info));
|
||||
}
|
||||
|
||||
bool hci_discovery_active(struct hci_dev *hdev);
|
||||
|
||||
void hci_discovery_set_state(struct hci_dev *hdev, int state);
|
||||
|
||||
@@ -539,6 +539,38 @@ struct mgmt_rp_read_adv_features {
|
||||
__u8 instance[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_ADD_ADVERTISING 0x003E
|
||||
struct mgmt_cp_add_advertising {
|
||||
__u8 instance;
|
||||
__le32 flags;
|
||||
__le16 duration;
|
||||
__le16 timeout;
|
||||
__u8 adv_data_len;
|
||||
__u8 scan_rsp_len;
|
||||
__u8 data[0];
|
||||
} __packed;
|
||||
#define MGMT_ADD_ADVERTISING_SIZE 11
|
||||
struct mgmt_rp_add_advertising {
|
||||
__u8 instance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_ADV_FLAG_CONNECTABLE BIT(0)
|
||||
#define MGMT_ADV_FLAG_DISCOV BIT(1)
|
||||
#define MGMT_ADV_FLAG_LIMITED_DISCOV BIT(2)
|
||||
#define MGMT_ADV_FLAG_MANAGED_FLAGS BIT(3)
|
||||
#define MGMT_ADV_FLAG_TX_POWER BIT(4)
|
||||
#define MGMT_ADV_FLAG_APPEARANCE BIT(5)
|
||||
#define MGMT_ADV_FLAG_LOCAL_NAME BIT(6)
|
||||
|
||||
#define MGMT_OP_REMOVE_ADVERTISING 0x003F
|
||||
struct mgmt_cp_remove_advertising {
|
||||
__u8 instance;
|
||||
} __packed;
|
||||
#define MGMT_REMOVE_ADVERTISING_SIZE 1
|
||||
struct mgmt_rp_remove_advertising {
|
||||
__u8 instance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CMD_COMPLETE 0x0001
|
||||
struct mgmt_ev_cmd_complete {
|
||||
__le16 opcode;
|
||||
@@ -742,3 +774,13 @@ struct mgmt_ev_local_oob_data_updated {
|
||||
__le16 eir_len;
|
||||
__u8 eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_ADVERTISING_ADDED 0x0023
|
||||
struct mgmt_ev_advertising_added {
|
||||
__u8 instance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_ADVERTISING_REMOVED 0x0024
|
||||
struct mgmt_ev_advertising_removed {
|
||||
__u8 instance;
|
||||
} __packed;
|
||||
|
||||
@@ -2874,7 +2874,6 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status,
|
||||
{
|
||||
/* General inquiry access code (GIAC) */
|
||||
u8 lap[3] = { 0x33, 0x8b, 0x9e };
|
||||
struct hci_request req;
|
||||
struct hci_cp_inquiry cp;
|
||||
int err;
|
||||
|
||||
@@ -2893,13 +2892,6 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status,
|
||||
break;
|
||||
|
||||
case DISCOV_TYPE_INTERLEAVED:
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
memcpy(&cp.lap, lap, sizeof(cp.lap));
|
||||
cp.length = DISCOV_INTERLEAVED_INQUIRY_LEN;
|
||||
hci_req_add(&req, HCI_OP_INQUIRY, sizeof(cp), &cp);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
|
||||
@@ -2914,8 +2906,17 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status,
|
||||
hci_discovery_set_state(hdev,
|
||||
DISCOVERY_STOPPED);
|
||||
} else {
|
||||
struct hci_request req;
|
||||
|
||||
hci_inquiry_cache_flush(hdev);
|
||||
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
memcpy(&cp.lap, lap, sizeof(cp.lap));
|
||||
cp.length = DISCOV_INTERLEAVED_INQUIRY_LEN;
|
||||
hci_req_add(&req, HCI_OP_INQUIRY, sizeof(cp), &cp);
|
||||
|
||||
err = hci_req_run(&req, inquiry_complete);
|
||||
if (err) {
|
||||
BT_ERR("Inquiry request failed: err %d", err);
|
||||
@@ -3125,6 +3126,7 @@ struct hci_dev *hci_alloc_dev(void)
|
||||
|
||||
hci_init_sysfs(hdev);
|
||||
discovery_init(hdev);
|
||||
adv_info_init(hdev);
|
||||
|
||||
return hdev;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,54 @@
|
||||
|
||||
#include "hci_debugfs.h"
|
||||
|
||||
#define DEFINE_QUIRK_ATTRIBUTE(__name, __quirk) \
|
||||
static ssize_t __name ## _read(struct file *file, \
|
||||
char __user *user_buf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct hci_dev *hdev = file->private_data; \
|
||||
char buf[3]; \
|
||||
\
|
||||
buf[0] = test_bit(__quirk, &hdev->quirks) ? 'Y' : 'N'; \
|
||||
buf[1] = '\n'; \
|
||||
buf[2] = '\0'; \
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, 2); \
|
||||
} \
|
||||
\
|
||||
static ssize_t __name ## _write(struct file *file, \
|
||||
const char __user *user_buf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct hci_dev *hdev = file->private_data; \
|
||||
char buf[32]; \
|
||||
size_t buf_size = min(count, (sizeof(buf) - 1)); \
|
||||
bool enable; \
|
||||
\
|
||||
if (test_bit(HCI_UP, &hdev->flags)) \
|
||||
return -EBUSY; \
|
||||
\
|
||||
if (copy_from_user(buf, user_buf, buf_size)) \
|
||||
return -EFAULT; \
|
||||
\
|
||||
buf[buf_size] = '\0'; \
|
||||
if (strtobool(buf, &enable)) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
if (enable == test_bit(__quirk, &hdev->quirks)) \
|
||||
return -EALREADY; \
|
||||
\
|
||||
change_bit(__quirk, &hdev->quirks); \
|
||||
\
|
||||
return count; \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations __name ## _fops = { \
|
||||
.open = simple_open, \
|
||||
.read = __name ## _read, \
|
||||
.write = __name ## _write, \
|
||||
.llseek = default_llseek, \
|
||||
} \
|
||||
|
||||
static int features_show(struct seq_file *f, void *ptr)
|
||||
{
|
||||
struct hci_dev *hdev = f->private;
|
||||
@@ -997,6 +1045,11 @@ static int adv_max_interval_get(void *data, u64 *val)
|
||||
DEFINE_SIMPLE_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get,
|
||||
adv_max_interval_set, "%llu\n");
|
||||
|
||||
DEFINE_QUIRK_ATTRIBUTE(quirk_strict_duplicate_filter,
|
||||
HCI_QUIRK_STRICT_DUPLICATE_FILTER);
|
||||
DEFINE_QUIRK_ATTRIBUTE(quirk_simultaneous_discovery,
|
||||
HCI_QUIRK_SIMULTANEOUS_DISCOVERY);
|
||||
|
||||
void hci_debugfs_create_le(struct hci_dev *hdev)
|
||||
{
|
||||
debugfs_create_file("identity", 0400, hdev->debugfs, hdev,
|
||||
@@ -1041,6 +1094,13 @@ void hci_debugfs_create_le(struct hci_dev *hdev)
|
||||
&adv_max_interval_fops);
|
||||
debugfs_create_u16("discov_interleaved_timeout", 0644, hdev->debugfs,
|
||||
&hdev->discov_interleaved_timeout);
|
||||
|
||||
debugfs_create_file("quirk_strict_duplicate_filter", 0644,
|
||||
hdev->debugfs, hdev,
|
||||
&quirk_strict_duplicate_filter_fops);
|
||||
debugfs_create_file("quirk_simultaneous_discovery", 0644,
|
||||
hdev->debugfs, hdev,
|
||||
&quirk_simultaneous_discovery_fops);
|
||||
}
|
||||
|
||||
void hci_debugfs_create_conn(struct hci_conn *conn)
|
||||
|
||||
+657
-62
File diff suppressed because it is too large
Load Diff
+6
-14
@@ -174,24 +174,16 @@ ieee802154_check_mac_settings(struct ieee802154_local *local,
|
||||
}
|
||||
|
||||
if (local->hw.flags & IEEE802154_HW_AFILT) {
|
||||
if (wpan_dev->pan_id != nwpan_dev->pan_id)
|
||||
return -EBUSY;
|
||||
|
||||
if (wpan_dev->short_addr != nwpan_dev->short_addr)
|
||||
return -EBUSY;
|
||||
|
||||
if (wpan_dev->extended_addr != nwpan_dev->extended_addr)
|
||||
if (wpan_dev->pan_id != nwpan_dev->pan_id ||
|
||||
wpan_dev->short_addr != nwpan_dev->short_addr ||
|
||||
wpan_dev->extended_addr != nwpan_dev->extended_addr)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
|
||||
if (wpan_dev->min_be != nwpan_dev->min_be)
|
||||
return -EBUSY;
|
||||
|
||||
if (wpan_dev->max_be != nwpan_dev->max_be)
|
||||
return -EBUSY;
|
||||
|
||||
if (wpan_dev->csma_retries != nwpan_dev->csma_retries)
|
||||
if (wpan_dev->min_be != nwpan_dev->min_be ||
|
||||
wpan_dev->max_be != nwpan_dev->max_be ||
|
||||
wpan_dev->csma_retries != nwpan_dev->csma_retries)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user