diff options
author | Jakub Pawlowski <jpawlowski@google.com> | 2015-03-17 12:04:14 -0400 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2015-03-17 12:31:00 -0400 |
commit | 07d2334ae747772fc4426077340aa3efe499f50b (patch) | |
tree | a6d218d89270d7713d418ce44034691f101142b5 | |
parent | 812abb13a97b7049c883ffb8431b81eb404a0938 (diff) |
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: Jakub Pawlowski <jpawlowski@google.com>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
-rw-r--r-- | net/bluetooth/hci_core.c | 24 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 22 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 34 |
3 files changed, 70 insertions, 10 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 750d3445f2d2..773f2164d9a1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -2902,12 +2902,26 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status, | |||
2902 | 2902 | ||
2903 | hci_dev_lock(hdev); | 2903 | hci_dev_lock(hdev); |
2904 | 2904 | ||
2905 | hci_inquiry_cache_flush(hdev); | 2905 | if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, |
2906 | &hdev->quirks)) { | ||
2907 | /* If we were running LE only scan, change discovery | ||
2908 | * state. If we were running both LE and BR/EDR inquiry | ||
2909 | * simultaneously, and BR/EDR inquiry is already | ||
2910 | * finished, stop discovery, otherwise BR/EDR inquiry | ||
2911 | * will stop discovery when finished. | ||
2912 | */ | ||
2913 | if (!test_bit(HCI_INQUIRY, &hdev->flags)) | ||
2914 | hci_discovery_set_state(hdev, | ||
2915 | DISCOVERY_STOPPED); | ||
2916 | } else { | ||
2917 | hci_inquiry_cache_flush(hdev); | ||
2906 | 2918 | ||
2907 | err = hci_req_run(&req, inquiry_complete); | 2919 | err = hci_req_run(&req, inquiry_complete); |
2908 | if (err) { | 2920 | if (err) { |
2909 | BT_ERR("Inquiry request failed: err %d", err); | 2921 | BT_ERR("Inquiry request failed: err %d", err); |
2910 | hci_discovery_set_state(hdev, DISCOVERY_STOPPED); | 2922 | hci_discovery_set_state(hdev, |
2923 | DISCOVERY_STOPPED); | ||
2924 | } | ||
2911 | } | 2925 | } |
2912 | 2926 | ||
2913 | hci_dev_unlock(hdev); | 2927 | hci_dev_unlock(hdev); |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d800f0c5aa21..62f92a508961 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -2126,7 +2126,16 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
2126 | goto unlock; | 2126 | goto unlock; |
2127 | 2127 | ||
2128 | if (list_empty(&discov->resolve)) { | 2128 | if (list_empty(&discov->resolve)) { |
2129 | hci_discovery_set_state(hdev, DISCOVERY_STOPPED); | 2129 | /* When BR/EDR inquiry is active and no LE scanning is in |
2130 | * progress, then change discovery state to indicate completion. | ||
2131 | * | ||
2132 | * When running LE scanning and BR/EDR inquiry simultaneously | ||
2133 | * and the LE scan already finished, then change the discovery | ||
2134 | * state to indicate completion. | ||
2135 | */ | ||
2136 | if (!hci_dev_test_flag(hdev, HCI_LE_SCAN) || | ||
2137 | !test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks)) | ||
2138 | hci_discovery_set_state(hdev, DISCOVERY_STOPPED); | ||
2130 | goto unlock; | 2139 | goto unlock; |
2131 | } | 2140 | } |
2132 | 2141 | ||
@@ -2135,7 +2144,16 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
2135 | e->name_state = NAME_PENDING; | 2144 | e->name_state = NAME_PENDING; |
2136 | hci_discovery_set_state(hdev, DISCOVERY_RESOLVING); | 2145 | hci_discovery_set_state(hdev, DISCOVERY_RESOLVING); |
2137 | } else { | 2146 | } else { |
2138 | hci_discovery_set_state(hdev, DISCOVERY_STOPPED); | 2147 | /* When BR/EDR inquiry is active and no LE scanning is in |
2148 | * progress, then change discovery state to indicate completion. | ||
2149 | * | ||
2150 | * When running LE scanning and BR/EDR inquiry simultaneously | ||
2151 | * and the LE scan already finished, then change the discovery | ||
2152 | * state to indicate completion. | ||
2153 | */ | ||
2154 | if (!hci_dev_test_flag(hdev, HCI_LE_SCAN) || | ||
2155 | !test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks)) | ||
2156 | hci_discovery_set_state(hdev, DISCOVERY_STOPPED); | ||
2139 | } | 2157 | } |
2140 | 2158 | ||
2141 | unlock: | 2159 | unlock: |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5a4b9d5a224f..7bcdf61afe11 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -1408,9 +1408,10 @@ static bool hci_stop_discovery(struct hci_request *req) | |||
1408 | 1408 | ||
1409 | switch (hdev->discovery.state) { | 1409 | switch (hdev->discovery.state) { |
1410 | case DISCOVERY_FINDING: | 1410 | case DISCOVERY_FINDING: |
1411 | if (test_bit(HCI_INQUIRY, &hdev->flags)) { | 1411 | if (test_bit(HCI_INQUIRY, &hdev->flags)) |
1412 | hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL); | 1412 | hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL); |
1413 | } else { | 1413 | |
1414 | if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) { | ||
1414 | cancel_delayed_work(&hdev->le_scan_disable); | 1415 | cancel_delayed_work(&hdev->le_scan_disable); |
1415 | hci_req_add_le_scan_disable(req); | 1416 | hci_req_add_le_scan_disable(req); |
1416 | } | 1417 | } |
@@ -4019,6 +4020,22 @@ static bool trigger_discovery(struct hci_request *req, u8 *status) | |||
4019 | break; | 4020 | break; |
4020 | 4021 | ||
4021 | case DISCOV_TYPE_INTERLEAVED: | 4022 | case DISCOV_TYPE_INTERLEAVED: |
4023 | if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, | ||
4024 | &hdev->quirks)) { | ||
4025 | /* During simultaneous discovery, we double LE scan | ||
4026 | * interval. We must leave some time for the controller | ||
4027 | * to do BR/EDR inquiry. | ||
4028 | */ | ||
4029 | if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT * 2, | ||
4030 | status)) | ||
4031 | return false; | ||
4032 | |||
4033 | if (!trigger_bredr_inquiry(req, status)) | ||
4034 | return false; | ||
4035 | |||
4036 | return true; | ||
4037 | } | ||
4038 | |||
4022 | if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) { | 4039 | if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) { |
4023 | *status = MGMT_STATUS_NOT_SUPPORTED; | 4040 | *status = MGMT_STATUS_NOT_SUPPORTED; |
4024 | return false; | 4041 | return false; |
@@ -4072,7 +4089,18 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status, | |||
4072 | timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT); | 4089 | timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT); |
4073 | break; | 4090 | break; |
4074 | case DISCOV_TYPE_INTERLEAVED: | 4091 | case DISCOV_TYPE_INTERLEAVED: |
4075 | timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout); | 4092 | /* When running simultaneous discovery, the LE scanning time |
4093 | * should occupy the whole discovery time sine BR/EDR inquiry | ||
4094 | * and LE scanning are scheduled by the controller. | ||
4095 | * | ||
4096 | * For interleaving discovery in comparison, BR/EDR inquiry | ||
4097 | * and LE scanning are done sequentially with separate | ||
4098 | * timeouts. | ||
4099 | */ | ||
4100 | if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks)) | ||
4101 | timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT); | ||
4102 | else | ||
4103 | timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout); | ||
4076 | break; | 4104 | break; |
4077 | case DISCOV_TYPE_BREDR: | 4105 | case DISCOV_TYPE_BREDR: |
4078 | timeout = 0; | 4106 | timeout = 0; |