diff options
author | Andre Guedes <andre.guedes@openbossa.org> | 2012-02-03 15:47:59 -0500 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2012-02-13 10:01:34 -0500 |
commit | 7ba8b4be38e7c83b2b13333a82a0ecde921a7390 (patch) | |
tree | 1ad9bb8b0eafed266538a2e238649149439ccc29 | |
parent | 6fbe195dc41c4fae1fa7aca1a38c888de1d24e2d (diff) |
Bluetooth: Add hci_do_le_scan()
This patch adds to hci_core the hci_do_le_scan function which
should be used to scan LE devices.
In order to enable LE scan, hci_do_le_scan() sends commands (Set
LE Scan Parameters and Set LE Scan Enable) to the controller and
waits for its results. If commands were executed successfully a
delayed work is scheduled to disable the ongoing scanning after
some amount of time. This function blocks.
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>
-rw-r--r-- | include/net/bluetooth/hci_core.h | 8 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 74 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 13 |
3 files changed, 92 insertions, 3 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bf2ef5667887..3e70872bffea 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -122,6 +122,12 @@ struct adv_entry { | |||
122 | u8 bdaddr_type; | 122 | u8 bdaddr_type; |
123 | }; | 123 | }; |
124 | 124 | ||
125 | struct le_scan_params { | ||
126 | u8 type; | ||
127 | u16 interval; | ||
128 | u16 window; | ||
129 | }; | ||
130 | |||
125 | #define NUM_REASSEMBLY 4 | 131 | #define NUM_REASSEMBLY 4 |
126 | struct hci_dev { | 132 | struct hci_dev { |
127 | struct list_head list; | 133 | struct list_head list; |
@@ -261,6 +267,8 @@ struct hci_dev { | |||
261 | 267 | ||
262 | unsigned long dev_flags; | 268 | unsigned long dev_flags; |
263 | 269 | ||
270 | struct delayed_work le_scan_disable; | ||
271 | |||
264 | int (*open)(struct hci_dev *hdev); | 272 | int (*open)(struct hci_dev *hdev); |
265 | int (*close)(struct hci_dev *hdev); | 273 | int (*close)(struct hci_dev *hdev); |
266 | int (*flush)(struct hci_dev *hdev); | 274 | int (*flush)(struct hci_dev *hdev); |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1175f27bd445..ae86cdd80ac0 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -759,6 +759,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) | |||
759 | if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) | 759 | if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) |
760 | cancel_delayed_work(&hdev->service_cache); | 760 | cancel_delayed_work(&hdev->service_cache); |
761 | 761 | ||
762 | cancel_delayed_work_sync(&hdev->le_scan_disable); | ||
763 | |||
762 | hci_dev_lock(hdev); | 764 | hci_dev_lock(hdev); |
763 | inquiry_cache_flush(hdev); | 765 | inquiry_cache_flush(hdev); |
764 | hci_conn_hash_flush(hdev); | 766 | hci_conn_hash_flush(hdev); |
@@ -1596,6 +1598,76 @@ int hci_add_adv_entry(struct hci_dev *hdev, | |||
1596 | return 0; | 1598 | return 0; |
1597 | } | 1599 | } |
1598 | 1600 | ||
1601 | static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt) | ||
1602 | { | ||
1603 | struct le_scan_params *param = (struct le_scan_params *) opt; | ||
1604 | struct hci_cp_le_set_scan_param cp; | ||
1605 | |||
1606 | memset(&cp, 0, sizeof(cp)); | ||
1607 | cp.type = param->type; | ||
1608 | cp.interval = cpu_to_le16(param->interval); | ||
1609 | cp.window = cpu_to_le16(param->window); | ||
1610 | |||
1611 | hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp); | ||
1612 | } | ||
1613 | |||
1614 | static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt) | ||
1615 | { | ||
1616 | struct hci_cp_le_set_scan_enable cp; | ||
1617 | |||
1618 | memset(&cp, 0, sizeof(cp)); | ||
1619 | cp.enable = 1; | ||
1620 | |||
1621 | hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); | ||
1622 | } | ||
1623 | |||
1624 | static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, | ||
1625 | u16 window, int timeout) | ||
1626 | { | ||
1627 | long timeo = msecs_to_jiffies(3000); | ||
1628 | struct le_scan_params param; | ||
1629 | int err; | ||
1630 | |||
1631 | BT_DBG("%s", hdev->name); | ||
1632 | |||
1633 | if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) | ||
1634 | return -EINPROGRESS; | ||
1635 | |||
1636 | param.type = type; | ||
1637 | param.interval = interval; | ||
1638 | param.window = window; | ||
1639 | |||
1640 | hci_req_lock(hdev); | ||
1641 | |||
1642 | err = __hci_request(hdev, le_scan_param_req, (unsigned long) ¶m, | ||
1643 | timeo); | ||
1644 | if (!err) | ||
1645 | err = __hci_request(hdev, le_scan_enable_req, 0, timeo); | ||
1646 | |||
1647 | hci_req_unlock(hdev); | ||
1648 | |||
1649 | if (err < 0) | ||
1650 | return err; | ||
1651 | |||
1652 | schedule_delayed_work(&hdev->le_scan_disable, | ||
1653 | msecs_to_jiffies(timeout)); | ||
1654 | |||
1655 | return 0; | ||
1656 | } | ||
1657 | |||
1658 | static void le_scan_disable_work(struct work_struct *work) | ||
1659 | { | ||
1660 | struct hci_dev *hdev = container_of(work, struct hci_dev, | ||
1661 | le_scan_disable.work); | ||
1662 | struct hci_cp_le_set_scan_enable cp; | ||
1663 | |||
1664 | BT_DBG("%s", hdev->name); | ||
1665 | |||
1666 | memset(&cp, 0, sizeof(cp)); | ||
1667 | |||
1668 | hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); | ||
1669 | } | ||
1670 | |||
1599 | /* Register HCI device */ | 1671 | /* Register HCI device */ |
1600 | int hci_register_dev(struct hci_dev *hdev) | 1672 | int hci_register_dev(struct hci_dev *hdev) |
1601 | { | 1673 | { |
@@ -1682,6 +1754,8 @@ int hci_register_dev(struct hci_dev *hdev) | |||
1682 | 1754 | ||
1683 | atomic_set(&hdev->promisc, 0); | 1755 | atomic_set(&hdev->promisc, 0); |
1684 | 1756 | ||
1757 | INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); | ||
1758 | |||
1685 | write_unlock(&hci_dev_list_lock); | 1759 | write_unlock(&hci_dev_list_lock); |
1686 | 1760 | ||
1687 | hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND | | 1761 | hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND | |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8971c18205c0..97152d9d7116 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -1031,6 +1031,8 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) | |||
1031 | __u8 status = *((__u8 *) skb->data); | 1031 | __u8 status = *((__u8 *) skb->data); |
1032 | 1032 | ||
1033 | BT_DBG("%s status 0x%x", hdev->name, status); | 1033 | BT_DBG("%s status 0x%x", hdev->name, status); |
1034 | |||
1035 | hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status); | ||
1034 | } | 1036 | } |
1035 | 1037 | ||
1036 | static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, | 1038 | static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, |
@@ -1041,15 +1043,17 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, | |||
1041 | 1043 | ||
1042 | BT_DBG("%s status 0x%x", hdev->name, status); | 1044 | BT_DBG("%s status 0x%x", hdev->name, status); |
1043 | 1045 | ||
1044 | if (status) | ||
1045 | return; | ||
1046 | |||
1047 | cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE); | 1046 | cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE); |
1048 | if (!cp) | 1047 | if (!cp) |
1049 | return; | 1048 | return; |
1050 | 1049 | ||
1051 | switch (cp->enable) { | 1050 | switch (cp->enable) { |
1052 | case LE_SCANNING_ENABLED: | 1051 | case LE_SCANNING_ENABLED: |
1052 | hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status); | ||
1053 | |||
1054 | if (status) | ||
1055 | return; | ||
1056 | |||
1053 | set_bit(HCI_LE_SCAN, &hdev->dev_flags); | 1057 | set_bit(HCI_LE_SCAN, &hdev->dev_flags); |
1054 | 1058 | ||
1055 | cancel_delayed_work_sync(&hdev->adv_work); | 1059 | cancel_delayed_work_sync(&hdev->adv_work); |
@@ -1061,6 +1065,9 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, | |||
1061 | break; | 1065 | break; |
1062 | 1066 | ||
1063 | case LE_SCANNING_DISABLED: | 1067 | case LE_SCANNING_DISABLED: |
1068 | if (status) | ||
1069 | return; | ||
1070 | |||
1064 | clear_bit(HCI_LE_SCAN, &hdev->dev_flags); | 1071 | clear_bit(HCI_LE_SCAN, &hdev->dev_flags); |
1065 | 1072 | ||
1066 | hci_dev_lock(hdev); | 1073 | hci_dev_lock(hdev); |