diff options
author | Ville Tervo <ville.tervo@nokia.com> | 2011-02-10 20:38:47 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-02-16 14:32:45 -0500 |
commit | fcd89c09a59a054fb986861e0862aa2fff7d7c40 (patch) | |
tree | 115d525a9789e974b0a118d9cc22b792370f40f7 /net/bluetooth/hci_conn.c | |
parent | 63185f64ef06464706b32c9a301f71f68cd93e52 (diff) |
Bluetooth: Add LE connect support
Bluetooth V4.0 adds support for Low Energy (LE) connections.
Specification introduces new set of hci commands to control LE
connection. This patch adds logic to create, cancel and disconnect
LE connections.
Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/hci_conn.c')
-rw-r--r-- | net/bluetooth/hci_conn.c | 51 |
1 files changed, 48 insertions, 3 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 42dc39f25b72..d0c470c18f9d 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -45,6 +45,32 @@ | |||
45 | #include <net/bluetooth/bluetooth.h> | 45 | #include <net/bluetooth/bluetooth.h> |
46 | #include <net/bluetooth/hci_core.h> | 46 | #include <net/bluetooth/hci_core.h> |
47 | 47 | ||
48 | static void hci_le_connect(struct hci_conn *conn) | ||
49 | { | ||
50 | struct hci_dev *hdev = conn->hdev; | ||
51 | struct hci_cp_le_create_conn cp; | ||
52 | |||
53 | conn->state = BT_CONNECT; | ||
54 | conn->out = 1; | ||
55 | |||
56 | memset(&cp, 0, sizeof(cp)); | ||
57 | cp.scan_interval = cpu_to_le16(0x0004); | ||
58 | cp.scan_window = cpu_to_le16(0x0004); | ||
59 | bacpy(&cp.peer_addr, &conn->dst); | ||
60 | cp.conn_interval_min = cpu_to_le16(0x0008); | ||
61 | cp.conn_interval_max = cpu_to_le16(0x0100); | ||
62 | cp.supervision_timeout = cpu_to_le16(0x0064); | ||
63 | cp.min_ce_len = cpu_to_le16(0x0001); | ||
64 | cp.max_ce_len = cpu_to_le16(0x0001); | ||
65 | |||
66 | hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); | ||
67 | } | ||
68 | |||
69 | static void hci_le_connect_cancel(struct hci_conn *conn) | ||
70 | { | ||
71 | hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL); | ||
72 | } | ||
73 | |||
48 | void hci_acl_connect(struct hci_conn *conn) | 74 | void hci_acl_connect(struct hci_conn *conn) |
49 | { | 75 | { |
50 | struct hci_dev *hdev = conn->hdev; | 76 | struct hci_dev *hdev = conn->hdev; |
@@ -193,8 +219,12 @@ static void hci_conn_timeout(unsigned long arg) | |||
193 | switch (conn->state) { | 219 | switch (conn->state) { |
194 | case BT_CONNECT: | 220 | case BT_CONNECT: |
195 | case BT_CONNECT2: | 221 | case BT_CONNECT2: |
196 | if (conn->type == ACL_LINK && conn->out) | 222 | if (conn->out) { |
197 | hci_acl_connect_cancel(conn); | 223 | if (conn->type == ACL_LINK) |
224 | hci_acl_connect_cancel(conn); | ||
225 | else if (conn->type == LE_LINK) | ||
226 | hci_le_connect_cancel(conn); | ||
227 | } | ||
198 | break; | 228 | break; |
199 | case BT_CONFIG: | 229 | case BT_CONFIG: |
200 | case BT_CONNECTED: | 230 | case BT_CONNECTED: |
@@ -361,15 +391,30 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) | |||
361 | } | 391 | } |
362 | EXPORT_SYMBOL(hci_get_route); | 392 | EXPORT_SYMBOL(hci_get_route); |
363 | 393 | ||
364 | /* Create SCO or ACL connection. | 394 | /* Create SCO, ACL or LE connection. |
365 | * Device _must_ be locked */ | 395 | * Device _must_ be locked */ |
366 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) | 396 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) |
367 | { | 397 | { |
368 | struct hci_conn *acl; | 398 | struct hci_conn *acl; |
369 | struct hci_conn *sco; | 399 | struct hci_conn *sco; |
400 | struct hci_conn *le; | ||
370 | 401 | ||
371 | BT_DBG("%s dst %s", hdev->name, batostr(dst)); | 402 | BT_DBG("%s dst %s", hdev->name, batostr(dst)); |
372 | 403 | ||
404 | if (type == LE_LINK) { | ||
405 | le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); | ||
406 | if (!le) | ||
407 | le = hci_conn_add(hdev, LE_LINK, dst); | ||
408 | if (!le) | ||
409 | return NULL; | ||
410 | if (le->state == BT_OPEN) | ||
411 | hci_le_connect(le); | ||
412 | |||
413 | hci_conn_hold(le); | ||
414 | |||
415 | return le; | ||
416 | } | ||
417 | |||
373 | acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); | 418 | acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); |
374 | if (!acl) { | 419 | if (!acl) { |
375 | acl = hci_conn_add(hdev, ACL_LINK, dst); | 420 | acl = hci_conn_add(hdev, ACL_LINK, dst); |