summaryrefslogtreecommitdiff
path: root/net/bluetooth
diff options
context:
space:
mode:
authorAndre Guedes <andre.guedes@openbossa.org>2012-02-18 03:39:38 +0400
committerJohan Hedberg <johan.hedberg@intel.com>2012-02-19 14:34:55 +0400
commit5e0452c00a2e4b04ec1482248c897dacf106f1df (patch)
tree34bbd940ed96cc736dcd8dd9311414f8f035839e /net/bluetooth
parent343f935bfa44189c68527102c409286b0cfc4526 (diff)
downloadlinux-5e0452c00a2e4b04ec1482248c897dacf106f1df.tar.xz
Bluetooth: Interleaved discovery support
This patch adds interleaved discovery support to MGMT Start Discovery command. In case interleaved discovery is not supported (not a dual mode device), we perform BR/EDR or LE-only discovery according to the device capabilities. Signed-off-by: Andre Guedes <andre.guedes@openbossa.org> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hci_event.c13
-rw-r--r--net/bluetooth/mgmt.c47
2 files changed, 55 insertions, 5 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 9aea7b898821..04fb1f02dfcc 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1090,11 +1090,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
- hci_dev_lock(hdev);
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- hci_dev_unlock(hdev);
-
schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT);
+
+ if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED) {
+ mgmt_interleaved_discovery(hdev);
+ } else {
+ hci_dev_lock(hdev);
+ hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+ hci_dev_unlock(hdev);
+ }
+
break;
default:
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a9cd38dc2cab..89754bbcd02b 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -108,8 +108,10 @@ static const u16 mgmt_events[] = {
#define LE_SCAN_WIN 0x12
#define LE_SCAN_INT 0x12
#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
+#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
+#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
#define SERVICE_CACHE_TIMEOUT (5 * 1000)
@@ -2153,6 +2155,46 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
return err;
}
+static int discovery(struct hci_dev *hdev)
+{
+ int err;
+
+ if (lmp_host_le_capable(hdev)) {
+ if (lmp_bredr_capable(hdev)) {
+ err = hci_le_scan(hdev, LE_SCAN_TYPE,
+ LE_SCAN_INT, LE_SCAN_WIN,
+ LE_SCAN_TIMEOUT_BREDR_LE);
+ } else {
+ hdev->discovery.type = DISCOV_TYPE_LE;
+ err = hci_le_scan(hdev, LE_SCAN_TYPE,
+ LE_SCAN_INT, LE_SCAN_WIN,
+ LE_SCAN_TIMEOUT_LE_ONLY);
+ }
+ } else {
+ hdev->discovery.type = DISCOV_TYPE_BREDR;
+ err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
+ }
+
+ return err;
+}
+
+int mgmt_interleaved_discovery(struct hci_dev *hdev)
+{
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ hci_dev_lock(hdev);
+
+ err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
+ if (err < 0)
+ hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+
+ hci_dev_unlock(hdev);
+
+ return err;
+}
+
static int start_discovery(struct sock *sk, u16 index,
void *data, u16 len)
{
@@ -2196,7 +2238,6 @@ static int start_discovery(struct sock *sk, u16 index,
switch (hdev->discovery.type) {
case DISCOV_TYPE_BREDR:
- case DISCOV_TYPE_INTERLEAVED:
err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
break;
@@ -2205,6 +2246,10 @@ static int start_discovery(struct sock *sk, u16 index,
LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
break;
+ case DISCOV_TYPE_INTERLEAVED:
+ err = discovery(hdev);
+ break;
+
default:
err = -EINVAL;
}