Commit 07d2334a authored by Jakub Pawlowski's avatar Jakub Pawlowski Committed by Johan Hedberg

Bluetooth: Add simultaneous dual mode scan

When doing scan through mgmt api, some controllers can do both le and
classic scan at same time. They can be distinguished by
HCI_QUIRK_SIMULTANEOUS_DISCOVERY set.

This patch enables them to use this feature when doing dual mode scan.
Instead of doing le, then classic scan, both scans are run at once.
Signed-off-by: default avatarJakub Pawlowski <jpawlowski@google.com>
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
parent 812abb13
...@@ -2902,12 +2902,26 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status, ...@@ -2902,12 +2902,26 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status,
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
&hdev->quirks)) {
/* If we were running LE only scan, change discovery
* state. If we were running both LE and BR/EDR inquiry
* simultaneously, and BR/EDR inquiry is already
* finished, stop discovery, otherwise BR/EDR inquiry
* will stop discovery when finished.
*/
if (!test_bit(HCI_INQUIRY, &hdev->flags))
hci_discovery_set_state(hdev,
DISCOVERY_STOPPED);
} else {
hci_inquiry_cache_flush(hdev); hci_inquiry_cache_flush(hdev);
err = hci_req_run(&req, inquiry_complete); err = hci_req_run(&req, inquiry_complete);
if (err) { if (err) {
BT_ERR("Inquiry request failed: err %d", err); BT_ERR("Inquiry request failed: err %d", err);
hci_discovery_set_state(hdev, DISCOVERY_STOPPED); hci_discovery_set_state(hdev,
DISCOVERY_STOPPED);
}
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
......
...@@ -2126,6 +2126,15 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2126,6 +2126,15 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
goto unlock; goto unlock;
if (list_empty(&discov->resolve)) { if (list_empty(&discov->resolve)) {
/* When BR/EDR inquiry is active and no LE scanning is in
* progress, then change discovery state to indicate completion.
*
* When running LE scanning and BR/EDR inquiry simultaneously
* and the LE scan already finished, then change the discovery
* state to indicate completion.
*/
if (!hci_dev_test_flag(hdev, HCI_LE_SCAN) ||
!test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks))
hci_discovery_set_state(hdev, DISCOVERY_STOPPED); hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
goto unlock; goto unlock;
} }
...@@ -2135,6 +2144,15 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2135,6 +2144,15 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
e->name_state = NAME_PENDING; e->name_state = NAME_PENDING;
hci_discovery_set_state(hdev, DISCOVERY_RESOLVING); hci_discovery_set_state(hdev, DISCOVERY_RESOLVING);
} else { } else {
/* When BR/EDR inquiry is active and no LE scanning is in
* progress, then change discovery state to indicate completion.
*
* When running LE scanning and BR/EDR inquiry simultaneously
* and the LE scan already finished, then change the discovery
* state to indicate completion.
*/
if (!hci_dev_test_flag(hdev, HCI_LE_SCAN) ||
!test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks))
hci_discovery_set_state(hdev, DISCOVERY_STOPPED); hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
} }
......
...@@ -1408,9 +1408,10 @@ static bool hci_stop_discovery(struct hci_request *req) ...@@ -1408,9 +1408,10 @@ static bool hci_stop_discovery(struct hci_request *req)
switch (hdev->discovery.state) { switch (hdev->discovery.state) {
case DISCOVERY_FINDING: case DISCOVERY_FINDING:
if (test_bit(HCI_INQUIRY, &hdev->flags)) { if (test_bit(HCI_INQUIRY, &hdev->flags))
hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL); hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
} else {
if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
cancel_delayed_work(&hdev->le_scan_disable); cancel_delayed_work(&hdev->le_scan_disable);
hci_req_add_le_scan_disable(req); hci_req_add_le_scan_disable(req);
} }
...@@ -4019,6 +4020,22 @@ static bool trigger_discovery(struct hci_request *req, u8 *status) ...@@ -4019,6 +4020,22 @@ static bool trigger_discovery(struct hci_request *req, u8 *status)
break; break;
case DISCOV_TYPE_INTERLEAVED: case DISCOV_TYPE_INTERLEAVED:
if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
&hdev->quirks)) {
/* During simultaneous discovery, we double LE scan
* interval. We must leave some time for the controller
* to do BR/EDR inquiry.
*/
if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT * 2,
status))
return false;
if (!trigger_bredr_inquiry(req, status))
return false;
return true;
}
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) { if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
*status = MGMT_STATUS_NOT_SUPPORTED; *status = MGMT_STATUS_NOT_SUPPORTED;
return false; return false;
...@@ -4072,6 +4089,17 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status, ...@@ -4072,6 +4089,17 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status,
timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT); timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
break; break;
case DISCOV_TYPE_INTERLEAVED: case DISCOV_TYPE_INTERLEAVED:
/* When running simultaneous discovery, the LE scanning time
* should occupy the whole discovery time sine BR/EDR inquiry
* and LE scanning are scheduled by the controller.
*
* For interleaving discovery in comparison, BR/EDR inquiry
* and LE scanning are done sequentially with separate
* timeouts.
*/
if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks))
timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
else
timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout); timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
break; break;
case DISCOV_TYPE_BREDR: case DISCOV_TYPE_BREDR:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment