Commit 45e826fd authored by David S. Miller's avatar David S. Miller

Merge branch 'for-upstream' of...

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-02-03

Here's what's likely the last bluetooth-next pull request for 3.20.
Notable changes include:

 - xHCI workaround + a new id for the ath3k driver
 - Several new ids for the btusb driver
 - Support for new Intel Bluetooth controllers
 - Minor cleanups to ieee802154 code
 - Nested sleep warning fix in socket accept() code path
 - Fixes for Out of Band pairing handling
 - Support for LE scan restarting for HCI_QUIRK_STRICT_DUPLICATE_FILTER
 - Improvements to data we expose through debugfs
 - Proper handling of Hardware Error HCI events

Please let me know if there are any issues pulling. Thanks.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents dcdc8994 88d9077c
...@@ -108,6 +108,7 @@ static const struct usb_device_id ath3k_table[] = { ...@@ -108,6 +108,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x13d3, 0x3393) }, { USB_DEVICE(0x13d3, 0x3393) },
{ USB_DEVICE(0x13d3, 0x3402) }, { USB_DEVICE(0x13d3, 0x3402) },
{ USB_DEVICE(0x13d3, 0x3408) }, { USB_DEVICE(0x13d3, 0x3408) },
{ USB_DEVICE(0x13d3, 0x3423) },
{ USB_DEVICE(0x13d3, 0x3432) }, { USB_DEVICE(0x13d3, 0x3432) },
/* Atheros AR5BBU12 with sflash firmware */ /* Atheros AR5BBU12 with sflash firmware */
...@@ -162,6 +163,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { ...@@ -162,6 +163,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */ /* Atheros AR5BBU22 with sflash firmware */
...@@ -174,6 +176,8 @@ static const struct usb_device_id ath3k_blist_tbl[] = { ...@@ -174,6 +176,8 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
#define USB_REQ_DFU_DNLOAD 1 #define USB_REQ_DFU_DNLOAD 1
#define BULK_SIZE 4096 #define BULK_SIZE 4096
#define FW_HDR_SIZE 20 #define FW_HDR_SIZE 20
#define TIMEGAP_USEC_MIN 50
#define TIMEGAP_USEC_MAX 100
static int ath3k_load_firmware(struct usb_device *udev, static int ath3k_load_firmware(struct usb_device *udev,
const struct firmware *firmware) const struct firmware *firmware)
...@@ -205,6 +209,9 @@ static int ath3k_load_firmware(struct usb_device *udev, ...@@ -205,6 +209,9 @@ static int ath3k_load_firmware(struct usb_device *udev,
pipe = usb_sndbulkpipe(udev, 0x02); pipe = usb_sndbulkpipe(udev, 0x02);
while (count) { while (count) {
/* workaround the compatibility issue with xHCI controller*/
usleep_range(TIMEGAP_USEC_MIN, TIMEGAP_USEC_MAX);
size = min_t(uint, count, BULK_SIZE); size = min_t(uint, count, BULK_SIZE);
memcpy(send_buf, firmware->data + sent, size); memcpy(send_buf, firmware->data + sent, size);
...@@ -302,6 +309,9 @@ static int ath3k_load_fwfile(struct usb_device *udev, ...@@ -302,6 +309,9 @@ static int ath3k_load_fwfile(struct usb_device *udev,
pipe = usb_sndbulkpipe(udev, 0x02); pipe = usb_sndbulkpipe(udev, 0x02);
while (count) { while (count) {
/* workaround the compatibility issue with xHCI controller*/
usleep_range(TIMEGAP_USEC_MIN, TIMEGAP_USEC_MAX);
size = min_t(uint, count, BULK_SIZE); size = min_t(uint, count, BULK_SIZE);
memcpy(send_buf, firmware->data + sent, size); memcpy(send_buf, firmware->data + sent, size);
......
This diff is collapsed.
...@@ -44,9 +44,9 @@ ...@@ -44,9 +44,9 @@
#define CC2520_FREG_MASK 0x3F #define CC2520_FREG_MASK 0x3F
/* status byte values */ /* status byte values */
#define CC2520_STATUS_XOSC32M_STABLE (1 << 7) #define CC2520_STATUS_XOSC32M_STABLE BIT(7)
#define CC2520_STATUS_RSSI_VALID (1 << 6) #define CC2520_STATUS_RSSI_VALID BIT(6)
#define CC2520_STATUS_TX_UNDERFLOW (1 << 3) #define CC2520_STATUS_TX_UNDERFLOW BIT(3)
/* IEEE-802.15.4 defined constants (2.4 GHz logical channels) */ /* IEEE-802.15.4 defined constants (2.4 GHz logical channels) */
#define CC2520_MINCHANNEL 11 #define CC2520_MINCHANNEL 11
...@@ -549,14 +549,14 @@ cc2520_ed(struct ieee802154_hw *hw, u8 *level) ...@@ -549,14 +549,14 @@ cc2520_ed(struct ieee802154_hw *hw, u8 *level)
u8 rssi; u8 rssi;
int ret; int ret;
ret = cc2520_read_register(priv , CC2520_RSSISTAT, &status); ret = cc2520_read_register(priv, CC2520_RSSISTAT, &status);
if (ret) if (ret)
return ret; return ret;
if (status != RSSI_VALID) if (status != RSSI_VALID)
return -EINVAL; return -EINVAL;
ret = cc2520_read_register(priv , CC2520_RSSI, &rssi); ret = cc2520_read_register(priv, CC2520_RSSI, &rssi);
if (ret) if (ret)
return ret; return ret;
......
...@@ -79,6 +79,8 @@ struct discovery_state { ...@@ -79,6 +79,8 @@ struct discovery_state {
s8 rssi; s8 rssi;
u16 uuid_count; u16 uuid_count;
u8 (*uuids)[16]; u8 (*uuids)[16];
unsigned long scan_start;
unsigned long scan_duration;
}; };
struct hci_conn_hash { struct hci_conn_hash {
...@@ -145,6 +147,7 @@ struct oob_data { ...@@ -145,6 +147,7 @@ struct oob_data {
struct list_head list; struct list_head list;
bdaddr_t bdaddr; bdaddr_t bdaddr;
u8 bdaddr_type; u8 bdaddr_type;
u8 present;
u8 hash192[16]; u8 hash192[16];
u8 rand192[16]; u8 rand192[16];
u8 hash256[16]; u8 hash256[16];
...@@ -232,6 +235,7 @@ struct hci_dev { ...@@ -232,6 +235,7 @@ struct hci_dev {
__u16 conn_info_min_age; __u16 conn_info_min_age;
__u16 conn_info_max_age; __u16 conn_info_max_age;
__u8 ssp_debug_mode; __u8 ssp_debug_mode;
__u8 hw_error_code;
__u32 clock; __u32 clock;
__u16 devid_source; __u16 devid_source;
...@@ -293,6 +297,7 @@ struct hci_dev { ...@@ -293,6 +297,7 @@ struct hci_dev {
struct work_struct power_on; struct work_struct power_on;
struct delayed_work power_off; struct delayed_work power_off;
struct work_struct error_reset;
__u16 discov_timeout; __u16 discov_timeout;
struct delayed_work discov_off; struct delayed_work discov_off;
...@@ -351,6 +356,7 @@ struct hci_dev { ...@@ -351,6 +356,7 @@ struct hci_dev {
unsigned long dev_flags; unsigned long dev_flags;
struct delayed_work le_scan_disable; struct delayed_work le_scan_disable;
struct delayed_work le_scan_restart;
__s8 adv_tx_power; __s8 adv_tx_power;
__u8 adv_data[HCI_MAX_AD_LENGTH]; __u8 adv_data[HCI_MAX_AD_LENGTH];
...@@ -369,6 +375,7 @@ struct hci_dev { ...@@ -369,6 +375,7 @@ struct hci_dev {
int (*setup)(struct hci_dev *hdev); int (*setup)(struct hci_dev *hdev);
int (*send)(struct hci_dev *hdev, struct sk_buff *skb); int (*send)(struct hci_dev *hdev, struct sk_buff *skb);
void (*notify)(struct hci_dev *hdev, unsigned int evt); void (*notify)(struct hci_dev *hdev, unsigned int evt);
void (*hw_error)(struct hci_dev *hdev, u8 code);
int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr); int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
}; };
...@@ -527,6 +534,8 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev) ...@@ -527,6 +534,8 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
hdev->discovery.uuid_count = 0; hdev->discovery.uuid_count = 0;
kfree(hdev->discovery.uuids); kfree(hdev->discovery.uuids);
hdev->discovery.uuids = NULL; hdev->discovery.uuids = NULL;
hdev->discovery.scan_start = 0;
hdev->discovery.scan_duration = 0;
} }
bool hci_discovery_active(struct hci_dev *hdev); bool hci_discovery_active(struct hci_dev *hdev);
...@@ -1325,6 +1334,7 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event); ...@@ -1325,6 +1334,7 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event);
#define DISCOV_INTERLEAVED_TIMEOUT 5120 /* msec */ #define DISCOV_INTERLEAVED_TIMEOUT 5120 /* msec */
#define DISCOV_INTERLEAVED_INQUIRY_LEN 0x04 #define DISCOV_INTERLEAVED_INQUIRY_LEN 0x04
#define DISCOV_BREDR_INQUIRY_LEN 0x08 #define DISCOV_BREDR_INQUIRY_LEN 0x08
#define DISCOV_LE_RESTART_DELAY msecs_to_jiffies(200) /* msec */
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len); int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
int mgmt_new_settings(struct hci_dev *hdev); int mgmt_new_settings(struct hci_dev *hdev);
...@@ -1369,7 +1379,6 @@ int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr, ...@@ -1369,7 +1379,6 @@ int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
void mgmt_auth_failed(struct hci_conn *conn, u8 status); void mgmt_auth_failed(struct hci_conn *conn, u8 status);
void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
u8 status); u8 status);
void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
......
...@@ -301,10 +301,6 @@ struct mgmt_cp_user_passkey_neg_reply { ...@@ -301,10 +301,6 @@ struct mgmt_cp_user_passkey_neg_reply {
#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0020 #define MGMT_OP_READ_LOCAL_OOB_DATA 0x0020
#define MGMT_READ_LOCAL_OOB_DATA_SIZE 0 #define MGMT_READ_LOCAL_OOB_DATA_SIZE 0
struct mgmt_rp_read_local_oob_data { struct mgmt_rp_read_local_oob_data {
__u8 hash[16];
__u8 rand[16];
} __packed;
struct mgmt_rp_read_local_oob_ext_data {
__u8 hash192[16]; __u8 hash192[16];
__u8 rand192[16]; __u8 rand192[16];
__u8 hash256[16]; __u8 hash256[16];
......
...@@ -511,13 +511,12 @@ static int bnep_session(void *arg) ...@@ -511,13 +511,12 @@ static int bnep_session(void *arg)
static struct device *bnep_get_device(struct bnep_session *session) static struct device *bnep_get_device(struct bnep_session *session)
{ {
struct hci_conn *conn; struct l2cap_conn *conn = l2cap_pi(session->sock->sk)->chan->conn;
conn = l2cap_pi(session->sock->sk)->chan->conn->hcon; if (!conn || !conn->hcon)
if (!conn)
return NULL; return NULL;
return &conn->dev; return &conn->hcon->dev;
} }
static struct device_type bnep_type = { static struct device_type bnep_type = {
......
...@@ -609,6 +609,7 @@ static void hci_init2_req(struct hci_request *req, unsigned long opt) ...@@ -609,6 +609,7 @@ static void hci_init2_req(struct hci_request *req, unsigned long opt)
if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
u8 mode = 0x01; u8 mode = 0x01;
hci_req_add(req, HCI_OP_WRITE_SSP_MODE, hci_req_add(req, HCI_OP_WRITE_SSP_MODE,
sizeof(mode), &mode); sizeof(mode), &mode);
} else { } else {
...@@ -870,8 +871,10 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) ...@@ -870,8 +871,10 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt)
hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL);
/* Enable Secure Connections if supported and configured */ /* Enable Secure Connections if supported and configured */
if (bredr_sc_enabled(hdev)) { if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
bredr_sc_enabled(hdev)) {
u8 support = 0x01; u8 support = 0x01;
hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT, hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT,
sizeof(support), &support); sizeof(support), &support);
} }
...@@ -1614,6 +1617,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) ...@@ -1614,6 +1617,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
cancel_delayed_work(&hdev->service_cache); cancel_delayed_work(&hdev->service_cache);
cancel_delayed_work_sync(&hdev->le_scan_disable); cancel_delayed_work_sync(&hdev->le_scan_disable);
cancel_delayed_work_sync(&hdev->le_scan_restart);
if (test_bit(HCI_MGMT, &hdev->dev_flags)) if (test_bit(HCI_MGMT, &hdev->dev_flags))
cancel_delayed_work_sync(&hdev->rpa_expired); cancel_delayed_work_sync(&hdev->rpa_expired);
...@@ -1625,6 +1629,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) ...@@ -1625,6 +1629,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hci_dev_lock(hdev); hci_dev_lock(hdev);
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
if (hdev->dev_type == HCI_BREDR) if (hdev->dev_type == HCI_BREDR)
mgmt_powered(hdev, 0); mgmt_powered(hdev, 0);
...@@ -1635,6 +1641,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) ...@@ -1635,6 +1641,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hci_conn_hash_flush(hdev); hci_conn_hash_flush(hdev);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
smp_unregister(hdev);
hci_notify(hdev, HCI_DEV_DOWN); hci_notify(hdev, HCI_DEV_DOWN);
if (hdev->flush) if (hdev->flush)
...@@ -1714,32 +1722,14 @@ done: ...@@ -1714,32 +1722,14 @@ done:
return err; return err;
} }
int hci_dev_reset(__u16 dev) static int hci_dev_do_reset(struct hci_dev *hdev)
{ {
struct hci_dev *hdev; int ret;
int ret = 0;
hdev = hci_dev_get(dev); BT_DBG("%s %p", hdev->name, hdev);
if (!hdev)
return -ENODEV;
hci_req_lock(hdev); hci_req_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
ret = -ENETDOWN;
goto done;
}
if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
ret = -EBUSY;
goto done;
}
if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) {
ret = -EOPNOTSUPP;
goto done;
}
/* Drop queues */ /* Drop queues */
skb_queue_purge(&hdev->rx_q); skb_queue_purge(&hdev->rx_q);
skb_queue_purge(&hdev->cmd_q); skb_queue_purge(&hdev->cmd_q);
...@@ -1762,12 +1752,41 @@ int hci_dev_reset(__u16 dev) ...@@ -1762,12 +1752,41 @@ int hci_dev_reset(__u16 dev)
ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT); ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
done:
hci_req_unlock(hdev); hci_req_unlock(hdev);
hci_dev_put(hdev);
return ret; return ret;
} }
int hci_dev_reset(__u16 dev)
{
struct hci_dev *hdev;
int err;
hdev = hci_dev_get(dev);
if (!hdev)
return -ENODEV;
if (!test_bit(HCI_UP, &hdev->flags)) {
err = -ENETDOWN;
goto done;
}
if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
err = -EBUSY;
goto done;
}
if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) {
err = -EOPNOTSUPP;
goto done;
}
err = hci_dev_do_reset(hdev);
done:
hci_dev_put(hdev);
return err;
}
int hci_dev_reset_stat(__u16 dev) int hci_dev_reset_stat(__u16 dev)
{ {
struct hci_dev *hdev; struct hci_dev *hdev;
...@@ -2131,8 +2150,24 @@ static void hci_power_off(struct work_struct *work) ...@@ -2131,8 +2150,24 @@ static void hci_power_off(struct work_struct *work)
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
hci_dev_do_close(hdev); hci_dev_do_close(hdev);
}
smp_unregister(hdev); static void hci_error_reset(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev, error_reset);
BT_DBG("%s", hdev->name);
if (hdev->hw_error)
hdev->hw_error(hdev, hdev->hw_error_code);
else
BT_ERR("%s hardware error 0x%2.2x", hdev->name,
hdev->hw_error_code);
if (hci_dev_do_close(hdev))
return;
hci_dev_do_open(hdev);
} }
static void hci_discov_off(struct work_struct *work) static void hci_discov_off(struct work_struct *work)
...@@ -2547,9 +2582,15 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, ...@@ -2547,9 +2582,15 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
if (hash192 && rand192) { if (hash192 && rand192) {
memcpy(data->hash192, hash192, sizeof(data->hash192)); memcpy(data->hash192, hash192, sizeof(data->hash192));
memcpy(data->rand192, rand192, sizeof(data->rand192)); memcpy(data->rand192, rand192, sizeof(data->rand192));
if (hash256 && rand256)
data->present = 0x03;
} else { } else {
memset(data->hash192, 0, sizeof(data->hash192)); memset(data->hash192, 0, sizeof(data->hash192));
memset(data->rand192, 0, sizeof(data->rand192)); memset(data->rand192, 0, sizeof(data->rand192));
if (hash256 && rand256)
data->present = 0x02;
else
data->present = 0x00;
} }
if (hash256 && rand256) { if (hash256 && rand256) {
...@@ -2558,6 +2599,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, ...@@ -2558,6 +2599,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
} else { } else {
memset(data->hash256, 0, sizeof(data->hash256)); memset(data->hash256, 0, sizeof(data->hash256));
memset(data->rand256, 0, sizeof(data->rand256)); memset(data->rand256, 0, sizeof(data->rand256));
if (hash192 && rand192)
data->present = 0x01;
} }
BT_DBG("%s for %pMR", hdev->name, bdaddr); BT_DBG("%s for %pMR", hdev->name, bdaddr);
...@@ -2788,6 +2831,8 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status, ...@@ -2788,6 +2831,8 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status,
return; return;
} }
hdev->discovery.scan_start = 0;
switch (hdev->discovery.type) { switch (hdev->discovery.type) {
case DISCOV_TYPE_LE: case DISCOV_TYPE_LE:
hci_dev_lock(hdev); hci_dev_lock(hdev);
...@@ -2827,6 +2872,8 @@ static void le_scan_disable_work(struct work_struct *work) ...@@ -2827,6 +2872,8 @@ static void le_scan_disable_work(struct work_struct *work)
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
cancel_delayed_work_sync(&hdev->le_scan_restart);
hci_req_init(&req, hdev); hci_req_init(&req, hdev);
hci_req_add_le_scan_disable(&req); hci_req_add_le_scan_disable(&req);
...@@ -2836,6 +2883,74 @@ static void le_scan_disable_work(struct work_struct *work) ...@@ -2836,6 +2883,74 @@ static void le_scan_disable_work(struct work_struct *work)
BT_ERR("Disable LE scanning request failed: err %d", err); BT_ERR("Disable LE scanning request failed: err %d", err);
} }
static void le_scan_restart_work_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
unsigned long timeout, duration, scan_start, now;
BT_DBG("%s", hdev->name);
if (status) {
BT_ERR("Failed to restart LE scan: status %d", status);
return;
}
if (!test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) ||
!hdev->discovery.scan_start)
return;
/* When the scan was started, hdev->le_scan_disable has been queued
* after duration from scan_start. During scan restart this job
* has been canceled, and we need to queue it again after proper
* timeout, to make sure that scan does not run indefinitely.
*/
duration = hdev->discovery.scan_duration;
scan_start = hdev->discovery.scan_start;
now = jiffies;
if (now - scan_start <= duration) {
int elapsed;
if (now >= scan_start)
elapsed = now - scan_start;
else
elapsed = ULONG_MAX - scan_start + now;
timeout = duration - elapsed;
} else {
timeout = 0;
}
queue_delayed_work(hdev->workqueue,
&hdev->le_scan_disable, timeout);
}
static void le_scan_restart_work(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev,
le_scan_restart.work);
struct hci_request req;
struct hci_cp_le_set_scan_enable cp;
int err;
BT_DBG("%s", hdev->name);
/* If controller is not scanning we are done. */
if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags))
return;
hci_req_init(&req, hdev);
hci_req_add_le_scan_disable(&req);
memset(&cp, 0, sizeof(cp));
cp.enable = LE_SCAN_ENABLE;
cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
err = hci_req_run(&req, le_scan_restart_work_complete);
if (err)
BT_ERR("Restart LE scan request failed: err %d", err);
}
/* Copy the Identity Address of the controller. /* Copy the Identity Address of the controller.
* *
* If the controller has a public BD_ADDR, then by default use that one. * If the controller has a public BD_ADDR, then by default use that one.
...@@ -2927,10 +3042,12 @@ struct hci_dev *hci_alloc_dev(void) ...@@ -2927,10 +3042,12 @@ struct hci_dev *hci_alloc_dev(void)
INIT_WORK(&hdev->cmd_work, hci_cmd_work); INIT_WORK(&hdev->cmd_work, hci_cmd_work);
INIT_WORK(&hdev->tx_work, hci_tx_work); INIT_WORK(&hdev->tx_work, hci_tx_work);
INIT_WORK(&hdev->power_on, hci_power_on); INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->error_reset, hci_error_reset);
INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);