Skip to content

Commit

Permalink
Bluetooth: Add simultaneous dual mode scan
Browse files Browse the repository at this point in the history
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: Jakub Pawlowski <jpawlowski@google.com>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
  • Loading branch information
Jakub Pawlowski authored and Johan Hedberg committed Mar 17, 2015
1 parent 812abb1 commit 07d2334
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 10 deletions.
24 changes: 19 additions & 5 deletions net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2902,12 +2902,26 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status,

hci_dev_lock(hdev);

hci_inquiry_cache_flush(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);

err = hci_req_run(&req, inquiry_complete);
if (err) {
BT_ERR("Inquiry request failed: err %d", err);
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
err = hci_req_run(&req, inquiry_complete);
if (err) {
BT_ERR("Inquiry request failed: err %d", err);
hci_discovery_set_state(hdev,
DISCOVERY_STOPPED);
}
}

hci_dev_unlock(hdev);
Expand Down
22 changes: 20 additions & 2 deletions net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -2126,7 +2126,16 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
goto unlock;

if (list_empty(&discov->resolve)) {
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
/* 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);
goto unlock;
}

Expand All @@ -2135,7 +2144,16 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
e->name_state = NAME_PENDING;
hci_discovery_set_state(hdev, DISCOVERY_RESOLVING);
} else {
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
/* 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);
}

unlock:
Expand Down
34 changes: 31 additions & 3 deletions net/bluetooth/mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1408,9 +1408,10 @@ static bool hci_stop_discovery(struct hci_request *req)

switch (hdev->discovery.state) {
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);
} else {

if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
cancel_delayed_work(&hdev->le_scan_disable);
hci_req_add_le_scan_disable(req);
}
Expand Down Expand Up @@ -4019,6 +4020,22 @@ static bool trigger_discovery(struct hci_request *req, u8 *status)
break;

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)) {
*status = MGMT_STATUS_NOT_SUPPORTED;
return false;
Expand Down Expand Up @@ -4072,7 +4089,18 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status,
timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
break;
case DISCOV_TYPE_INTERLEAVED:
timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
/* 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);
break;
case DISCOV_TYPE_BREDR:
timeout = 0;
Expand Down

0 comments on commit 07d2334

Please sign in to comment.