* [PATCH 1/2] Change Battery Service on attribute sample server
From: Claudio Takahasi @ 2010-10-06 20:39 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
Add an optional Client Characteristic Configuration attribute for
Battery State to control which clients want notification/indication
when this attribute value changes.
---
attrib/example.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/attrib/example.c b/attrib/example.c
index 76afce9..c29e1e4 100644
--- a/attrib/example.c
+++ b/attrib/example.c
@@ -161,10 +161,15 @@ static int register_attributes(void)
/* Battery: battery state attribute */
sdp_uuid16_create(&uuid, BATTERY_STATE_UUID);
- u16 = htons(BATTERY_STATE_UUID);
atval[0] = 0x04;
attrib_db_add(0x0110, &uuid, atval, 1);
+ /* Battery: Client Characteristic Configuration */
+ sdp_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+ atval[0] = 0x00;
+ atval[1] = 0x00;
+ attrib_db_add(0x0111, &uuid, atval, 2);
+
timeout_id = g_timeout_add_seconds(10, change_battery_state, NULL);
/* Thermometer: primary service definition */
--
1.7.3.1
^ permalink raw reply related
* [PATCH] TODO: Add attribute permission verification for attribute server
From: Claudio Takahasi @ 2010-10-06 20:34 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
---
TODO | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/TODO b/TODO
index 7ebbbe3..2cd141b 100644
--- a/TODO
+++ b/TODO
@@ -32,6 +32,13 @@ ATT/GATT
Priority: Low
Complexity: C1
+- Attribute server shall implement attribute permission verification,
+ returning an error code if necessary. See Volume 3, Part F, 3.2.5
+ for more information.
+
+ Priority: Low
+ Complexity: C2
+
- Long reads/writes don't work (consisting of multiple request packets)
Priority: Low
--
1.7.3.1
^ permalink raw reply related
* Re: [PATCH 5/7] Bluetooth: Add LE connection support to L2CAP
From: Anderson Lizardo @ 2010-10-06 20:14 UTC (permalink / raw)
To: Ville Tervo; +Cc: linux-bluetooth
In-Reply-To: <1286390535-27462-6-git-send-email-ville.tervo@nokia.com>
On Wed, Oct 6, 2010 at 2:42 PM, Ville Tervo <ville.tervo@nokia.com> wrote:
> @@ -1014,13 +1029,13 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
> len = min_t(unsigned int, sizeof(la), alen);
> memcpy(&la, addr, len);
>
> - if (la.l2_cid)
> ++ if (la.l2_cid && la.l2_psm)
> return -EINVAL;
>
> lock_sock(sk);
>
> if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
> - && !la.l2_psm) {
> + && !(la.l2_psm || la.la_cid)) {
> err = -EINVAL;
> goto done;
> }
This snippet looks strange for two reasons:
1) the "++" marker looks weird. Corrupted patch?
2) there is a typo here : la.la_cid -> la.l2_cid . Didn't the compiler
catch this?
Note that there are some other occurrences of "++" in this patch.
Regards,
--
Anderson Lizardo
OpenBossa Labs - INdT
Manaus - Brazil
^ permalink raw reply
* Re: [PATCH 3/7] Bluetooth: LE disconnection and connect cancel support
From: Anderson Lizardo @ 2010-10-06 19:57 UTC (permalink / raw)
To: Ville Tervo; +Cc: linux-bluetooth
In-Reply-To: <1286390535-27462-4-git-send-email-ville.tervo@nokia.com>
Hi Ville,
On Wed, Oct 6, 2010 at 2:42 PM, Ville Tervo <ville.tervo@nokia.com> wrote:
> @@ -627,9 +629,6 @@ struct hci_cp_le_create_conn {
> } __packed;
>
> #define HCI_OP_LE_CREATE_CONN_CANCEL 0x200e
> -struct hci_cp_le_create_conn_cancel {
> - __u8 status;
> -} __packed;
>
> #define HCI_OP_LE_SET_ADVERTISE_ENABLE 0x200a
> #define LE_ADVERTISE_ENABLED 0x01
The struct above is added in 1/7 then removed on this one, so you
could drop it from patch 1/7 instead?
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 89f4b10..a430a57 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -455,10 +455,13 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
> #define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH)
> #define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT)
> #define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
> +#define lmp_br_capable(dev) (!((dev)->features[4] & LMP_NO_BR))
> +#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE)
> #define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
> #define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
> #define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
>
> +
> /* ----- HCI protocols ----- */
Unrelated extra line added above.
> struct hci_proto {
> char *name;
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index cb41d64..50f8973 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -66,6 +66,31 @@ void hci_le_connect(struct hci_conn *conn)
> hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
> }
>
> +static void hci_le_connect_cancel(struct hci_conn *conn)
> +{
> + struct hci_dev *hdev = conn->hdev;
> +
> + BT_DBG("%p", conn);
This debug message could be made more readable, e.g.:
BT_DBG("%s conn %p", hdev->name, conn);
(or simply dropped if not that useful).
> +
> + if (!lmp_le_capable(hdev))
> + return;
> +
> + hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
> +}
> +
> +void hci_le_disconn(struct hci_conn *conn, __u8 reason)
> +{
> + struct hci_cp_disconnect cp;
> +
> + BT_DBG("%p", conn);
Same here.
Regards,
--
Anderson Lizardo
OpenBossa Labs - INdT
Manaus - Brazil
^ permalink raw reply
* [PATCH 7/7] Bluetooth: Do not send disconn comand over LE links
From: Ville Tervo @ 2010-10-06 18:42 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ville Tervo
In-Reply-To: <1286390535-27462-1-git-send-email-ville.tervo@nokia.com>
l2cap over LE links can be disconnected without sending
disconnect command first.
Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
---
net/bluetooth/l2cap_core.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 20be2f9..53860f6 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -836,6 +836,8 @@ void l2cap_sock_kill(struct sock *sk)
void __l2cap_sock_close(struct sock *sk, int reason)
{
+ struct l2cap_conn *conn;
+
BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
switch (sk->sk_state) {
@@ -845,8 +847,10 @@ void __l2cap_sock_close(struct sock *sk, int reason)
case BT_CONNECTED:
case BT_CONFIG:
- if (sk->sk_type == SOCK_SEQPACKET ||
- sk->sk_type == SOCK_STREAM) {
+ conn = l2cap_pi(sk)->conn;
+ if ((sk->sk_type == SOCK_SEQPACKET ||
+ sk->sk_type == SOCK_STREAM) &&
+ conn->hcon->type != LE_LINK) {
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
@@ -856,9 +860,10 @@ void __l2cap_sock_close(struct sock *sk, int reason)
break;
case BT_CONNECT2:
- if (sk->sk_type == SOCK_SEQPACKET ||
- sk->sk_type == SOCK_STREAM) {
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+ conn = l2cap_pi(sk)->conn;
+ if ((sk->sk_type == SOCK_SEQPACKET ||
+ sk->sk_type == SOCK_STREAM) &&
+ conn->hcon->type != LE_LINK) {
struct l2cap_conn_rsp rsp;
__u16 result;
--
1.7.0.1
^ permalink raw reply related
* [PATCH 6/7] Bluetooth: Add server socket support for LE connection
From: Ville Tervo @ 2010-10-06 18:42 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ville Tervo
In-Reply-To: <1286390535-27462-1-git-send-email-ville.tervo@nokia.com>
Add support for LE server sockets.
Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
---
include/net/bluetooth/l2cap.h | 1 +
net/bluetooth/hci_event.c | 10 +++-
net/bluetooth/l2cap_core.c | 117 ++++++++++++++++++++++++++++++++++++-----
3 files changed, 113 insertions(+), 15 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 41374ad..e655b31 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -38,6 +38,7 @@
#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */
#define L2CAP_DEFAULT_ACK_TO 200
#define L2CAP_LOCAL_BUSY_TRIES 12
+#define L2CAP_LE_DEFAULT_MTU 23
#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index a914314..fa945e9 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1961,8 +1961,14 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
+ if (!conn) {
+ conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
+ if (!conn) {
+ BT_ERR("No memory for new connection");
+ hci_dev_unlock(hdev);
+ return;
+ }
+ }
if (ev->status) {
hci_proto_connect_cfm(conn, ev->status);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 1d43280..20be2f9 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -78,6 +78,8 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
+static void l2cap_le_conn_ready(struct l2cap_conn *conn);
+
/* ---- L2CAP timers ---- */
static void l2cap_sock_set_timer(struct sock *sk, long timeout)
{
@@ -199,8 +201,16 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
l2cap_pi(sk)->conn = conn;
if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) {
- /* Alloc CID for connection-oriented socket */
- l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
+ if (conn->hcon->type == LE_LINK) {
+ /* LE connection */
+ l2cap_pi(sk)->omtu = L2CAP_LE_DEFAULT_MTU;
+ l2cap_pi(sk)->scid = L2CAP_CID_LE_DATA;
+ l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA;
+ } else {
+ /* Alloc CID for connection-oriented socket */
+ l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
+ l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+ }
} else if (sk->sk_type == SOCK_DGRAM) {
/* Connectionless socket */
l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS;
@@ -583,15 +593,18 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
BT_DBG("conn %p", conn);
+ if (!conn->hcon->out && conn->hcon->type == LE_LINK)
+ l2cap_le_conn_ready(conn);
+
read_lock(&l->lock);
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
bh_lock_sock(sk);
if (conn->hcon->type == LE_LINK) {
- l2cap_sock_clear_timer(sk);
- sk->sk_state = BT_CONNECTED;
- sk->sk_state_change(sk);
+ l2cap_sock_clear_timer(sk);
+ sk->sk_state = BT_CONNECTED;
+ sk->sk_state_change(sk);
}
if (sk->sk_type != SOCK_SEQPACKET &&
@@ -665,7 +678,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
spin_lock_init(&conn->lock);
rwlock_init(&conn->chan_list.lock);
- setup_timer(&conn->info_timer, l2cap_info_timeout,
+ if (hcon->type != LE_LINK)
+ setup_timer(&conn->info_timer, l2cap_info_timeout,
(unsigned long) conn);
conn->disc_reason = 0x13;
@@ -759,6 +773,37 @@ static inline struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t
return s;
}
+static inline struct sock *l2cap_get_sock_by_cid(int state, __le16 cid, bdaddr_t *src)
+{
+ struct sock *s;
+ struct sock *sk = NULL, *sk1 = NULL;
+ struct hlist_node *node;
+
+ read_lock(&l2cap_sk_list.lock);
+ sk_for_each(sk, node, &l2cap_sk_list.head) {
+ if (state && sk->sk_state != state)
+ continue;
+
+ if (l2cap_pi(sk)->dcid == cid) {
+ /* Exact match. */
+ if (!bacmp(&bt_sk(sk)->src, src))
+ break;
+
+ /* Closest match */
+ if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
+ sk1 = sk;
+ }
+ }
+
+ s = node ? sk : sk1;
+
+ if (s)
+ bh_lock_sock(s);
+ read_unlock(&l2cap_sk_list.lock);
+
+ return s;
+}
+
static void l2cap_sock_cleanup_listen(struct sock *parent)
{
struct sock *sk;
@@ -868,7 +913,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
len = min_t(unsigned int, sizeof(la), alen);
memcpy(&la, addr, len);
- if (la.l2_cid)
+ if (la.l2_cid && la.l2_psm)
return -EINVAL;
lock_sock(sk);
@@ -910,6 +955,9 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
}
+ if (la.l2_cid)
+ l2cap_pi(sk)->dcid = la.l2_cid;
+
write_unlock_bh(&l2cap_sk_list.lock);
done:
@@ -1029,13 +1077,13 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
len = min_t(unsigned int, sizeof(la), alen);
memcpy(&la, addr, len);
-+ if (la.l2_cid && la.l2_psm)
+ if (la.l2_cid && la.l2_psm)
return -EINVAL;
lock_sock(sk);
if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
- && !(la.l2_psm || la.la_cid)) {
+ && !(la.l2_psm || la.l2_cid)) {
err = -EINVAL;
goto done;
}
@@ -1085,7 +1133,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
/* Set destination address and psm or cid */
bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
l2cap_pi(sk)->psm = la.l2_psm;
-+ l2cap_pi(sk)->dcid = la.l2_cid;
+ l2cap_pi(sk)->dcid = la.l2_cid;
err = l2cap_do_connect(sk);
if (err)
@@ -1127,7 +1175,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
goto done;
}
- if (!l2cap_pi(sk)->psm) {
+ if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->dcid) {
bdaddr_t *src = &bt_sk(sk)->src;
u16 psm;
@@ -1237,6 +1285,49 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
return 0;
}
+static void l2cap_le_conn_ready(struct l2cap_conn *conn)
+{
+ struct l2cap_chan_list *list = &conn->chan_list;
+ struct sock *parent, *uninitialized_var(sk);
+
+ BT_DBG("");
+
+ /* Check if we have socket listening on cid */
+ parent = l2cap_get_sock_by_cid(BT_LISTEN, 0x04, conn->src);
+ if (!parent)
+ goto clean;
+
+ /* Check for backlog size */
+ if (sk_acceptq_is_full(parent)) {
+ BT_DBG("backlog full %d", parent->sk_ack_backlog);
+ goto clean;
+ }
+
+ sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
+ if (!sk)
+ goto clean;
+
+ write_lock_bh(&list->lock);
+
+ hci_conn_hold(conn->hcon);
+
+ l2cap_sock_init(sk, parent);
+ bacpy(&bt_sk(sk)->src, conn->src);
+ bacpy(&bt_sk(sk)->dst, conn->dst);
+
+ __l2cap_chan_add(conn, sk, parent);
+
+ l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
+
+ sk->sk_state = BT_CONNECTED;
+ parent->sk_data_ready(parent, 0);
+
+ write_unlock_bh(&list->lock);
+
+clean:
+ bh_unlock_sock(parent);
+}
+
static int __l2cap_wait_ack(struct sock *sk)
{
DECLARE_WAITQUEUE(wait, current);
@@ -4396,7 +4487,7 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
-+ if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
+ if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
return -EINVAL;
if (!status) {
@@ -4425,7 +4516,7 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
-+ if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
+ if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
return -EINVAL;
l2cap_conn_del(hcon, bt_err(reason));
--
1.7.0.1
^ permalink raw reply related
* [PATCH 5/7] Bluetooth: Add LE connection support to L2CAP
From: Ville Tervo @ 2010-10-06 18:42 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ville Tervo
In-Reply-To: <1286390535-27462-1-git-send-email-ville.tervo@nokia.com>
Add basic LE connection support to L2CAP
Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
---
include/net/bluetooth/l2cap.h | 4 ++++
net/bluetooth/l2cap_core.c | 32 ++++++++++++++++++++++++--------
2 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index df599dc..41374ad 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -160,6 +160,9 @@ struct l2cap_conn_rsp {
/* channel indentifier */
#define L2CAP_CID_SIGNALING 0x0001
#define L2CAP_CID_CONN_LESS 0x0002
+#define L2CAP_CID_LE_DATA 0x0004
+#define L2CAP_CID_LE_SIGNALING 0x0005
+#define L2CAP_CID_SMP 0x0006
#define L2CAP_CID_DYN_START 0x0040
#define L2CAP_CID_DYN_END 0xffff
@@ -269,6 +272,7 @@ struct l2cap_conn {
bdaddr_t *src;
unsigned int mtu;
+ unsigned int le_mtu;
__u32 feat_mask;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 07b55c1..1d43280 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -588,6 +588,12 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
bh_lock_sock(sk);
+ if (conn->hcon->type == LE_LINK) {
+ l2cap_sock_clear_timer(sk);
+ sk->sk_state = BT_CONNECTED;
+ sk->sk_state_change(sk);
+ }
+
if (sk->sk_type != SOCK_SEQPACKET &&
sk->sk_type != SOCK_STREAM) {
l2cap_sock_clear_timer(sk);
@@ -646,7 +652,11 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
BT_DBG("hcon %p conn %p", hcon, conn);
- conn->mtu = hcon->hdev->acl_mtu;
+ if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
+ conn->mtu = hcon->hdev->le_mtu;
+ else
+ conn->mtu = hcon->hdev->acl_mtu;
+
conn->src = &hcon->hdev->bdaddr;
conn->dst = &hcon->dst;
@@ -962,8 +972,13 @@ static int l2cap_do_connect(struct sock *sk)
}
}
- hcon = hci_connect(hdev, ACL_LINK, dst,
+ if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA)
+ hcon = hci_connect(hdev, LE_LINK, dst,
+ l2cap_pi(sk)->sec_level, auth_type);
+ else
+ hcon = hci_connect(hdev, ACL_LINK, dst,
l2cap_pi(sk)->sec_level, auth_type);
+
if (!hcon)
goto done;
@@ -1014,13 +1029,13 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
len = min_t(unsigned int, sizeof(la), alen);
memcpy(&la, addr, len);
- if (la.l2_cid)
++ if (la.l2_cid && la.l2_psm)
return -EINVAL;
lock_sock(sk);
if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
- && !la.l2_psm) {
+ && !(la.l2_psm || la.la_cid)) {
err = -EINVAL;
goto done;
}
@@ -1062,14 +1077,15 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
/* PSM must be odd and lsb of upper byte must be 0 */
if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 &&
- sk->sk_type != SOCK_RAW) {
+ sk->sk_type != SOCK_RAW && !la.l2_cid) {
err = -EINVAL;
goto done;
}
- /* Set destination address and psm */
+ /* Set destination address and psm or cid */
bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
l2cap_pi(sk)->psm = la.l2_psm;
++ l2cap_pi(sk)->dcid = la.l2_cid;
err = l2cap_do_connect(sk);
if (err)
@@ -4380,7 +4396,7 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
- if (hcon->type != ACL_LINK)
++ if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
return -EINVAL;
if (!status) {
@@ -4409,7 +4425,7 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
- if (hcon->type != ACL_LINK)
++ if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
return -EINVAL;
l2cap_conn_del(hcon, bt_err(reason));
--
1.7.0.1
^ permalink raw reply related
* [PATCH 4/7] Bluetooth: Use LE buffers for LE traffic
From: Ville Tervo @ 2010-10-06 18:42 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ville Tervo
In-Reply-To: <1286390535-27462-1-git-send-email-ville.tervo@nokia.com>
BLuetooth chips may have separate buffers for
LE traffic. This patch add support to use LE
buffers provided by the chip.
Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
---
include/net/bluetooth/hci_core.h | 6 +++
net/bluetooth/hci_conn.c | 11 +++++-
net/bluetooth/hci_core.c | 77 +++++++++++++++++++++++++++++++++++--
net/bluetooth/hci_event.c | 34 ++++++++++++++++-
4 files changed, 120 insertions(+), 8 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a430a57..2eb314f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -102,15 +102,19 @@ struct hci_dev {
atomic_t cmd_cnt;
unsigned int acl_cnt;
unsigned int sco_cnt;
+ unsigned int le_cnt;
unsigned int acl_mtu;
unsigned int sco_mtu;
+ unsigned int le_mtu;
unsigned int acl_pkts;
unsigned int sco_pkts;
+ unsigned int le_pkts;
unsigned long cmd_last_tx;
unsigned long acl_last_tx;
unsigned long sco_last_tx;
+ unsigned long le_last_tx;
struct workqueue_struct *workqueue;
@@ -358,6 +362,8 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn);
void hci_conn_hold_device(struct hci_conn *conn);
void hci_conn_put_device(struct hci_conn *conn);
+void hci_le_disconn(struct hci_conn *conn, __u8 reason);
+
static inline void hci_conn_hold(struct hci_conn *conn)
{
atomic_inc(&conn->refcnt);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 50f8973..3443065 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -232,6 +232,7 @@ static void hci_conn_timeout(unsigned long arg)
{
struct hci_conn *conn = (void *) arg;
struct hci_dev *hdev = conn->hdev;
+ __u16 state;
__u8 reason;
BT_DBG("conn %p state %d", conn, conn->state);
@@ -241,7 +242,12 @@ static void hci_conn_timeout(unsigned long arg)
hci_dev_lock(hdev);
- switch (conn->state) {
+ if (conn->type == LE_LINK)
+ state = conn->le_state;
+ else
+ state = conn->state;
+
+ switch (state) {
case BT_CONNECT:
case BT_CONNECT2:
if (conn->type == ACL_LINK && conn->out)
@@ -348,6 +354,8 @@ int hci_conn_del(struct hci_conn *conn)
/* Unacked frames */
hdev->acl_cnt += conn->sent;
+ } else if (conn->type == LE_LINK) {
+ hdev->le_cnt += conn->sent;
} else {
struct hci_conn *acl = conn->link;
if (acl) {
@@ -436,6 +444,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
return NULL;
hci_le_connect(le);
+ hci_conn_hold(le);
return le;
}
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index bc2a052..b320798 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -254,6 +254,14 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);
}
+static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
+{
+ BT_DBG("%s", hdev->name);
+
+ /* Read LE buffer size */
+ hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
+}
+
static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
{
__u8 scan = opt;
@@ -509,6 +517,10 @@ int hci_dev_open(__u16 dev)
ret = __hci_request(hdev, hci_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT));
+ if (lmp_le_capable(hdev))
+ ret = __hci_request(hdev, hci_le_init_req, 0,
+ msecs_to_jiffies(HCI_INIT_TIMEOUT));
+
clear_bit(HCI_INIT, &hdev->flags);
}
@@ -645,7 +657,7 @@ int hci_dev_reset(__u16 dev)
hdev->flush(hdev);
atomic_set(&hdev->cmd_cnt, 1);
- hdev->acl_cnt = 0; hdev->sco_cnt = 0;
+ hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
if (!test_bit(HCI_RAW, &hdev->flags))
ret = __hci_request(hdev, hci_reset_req, 0,
@@ -1444,7 +1456,8 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
if (c->type != type || skb_queue_empty(&c->data_q))
continue;
- if (c->state != BT_CONNECTED && c->state != BT_CONFIG)
+ if ((c->state != BT_CONNECTED && c->state != BT_CONFIG) &&
+ (c->le_state != BT_CONNECTED && c->le_state != BT_CONFIG))
continue;
num++;
@@ -1456,8 +1469,25 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
}
if (conn) {
- int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt);
- int q = cnt / num;
+ int cnt, q;
+
+ switch (conn->type) {
+ case ACL_LINK:
+ cnt = hdev->acl_cnt;
+ break;
+ case SCO_LINK:
+ case ESCO_LINK:
+ cnt = hdev->sco_cnt;
+ break;
+ case LE_LINK:
+ cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
+ break;
+ default:
+ cnt = 0;
+ BT_ERR("Unknown link type");
+ }
+
+ q = cnt / num;
*quote = q ? q : 1;
} else
*quote = 0;
@@ -1482,6 +1512,11 @@ static inline void hci_acl_tx_to(struct hci_dev *hdev)
hdev->name, batostr(&c->dst));
hci_acl_disconn(c, 0x13);
}
+ if (c->type == LE_LINK && c->sent) {
+ BT_ERR("%s killing stalled LE connection %s",
+ hdev->name, batostr(&c->dst));
+ hci_le_disconn(c, 0x13);
+ }
}
}
@@ -1556,6 +1591,35 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
}
}
+static inline void hci_sched_le(struct hci_dev *hdev)
+{
+ struct hci_conn *conn;
+ struct sk_buff *skb;
+ int quote;
+
+ BT_DBG("%s", hdev->name);
+
+ if (!test_bit(HCI_RAW, &hdev->flags)) {
+ /* ACL tx timeout must be longer than maximum
+ * link supervision timeout (40.9 seconds) */
+ if (!hdev->le_cnt &&
+ time_after(jiffies, hdev->le_last_tx + HZ * 45))
+ hci_acl_tx_to(hdev);
+ }
+
+ while (hdev->le_cnt && (conn = hci_low_sent(hdev, LE_LINK, "e))) {
+ while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
+ BT_DBG("skb %p len %d", skb, skb->len);
+
+ hci_send_frame(skb);
+ hdev->le_last_tx = jiffies;
+
+ hdev->le_cnt--;
+ conn->sent++;
+ }
+ }
+}
+
static void hci_tx_task(unsigned long arg)
{
struct hci_dev *hdev = (struct hci_dev *) arg;
@@ -1563,7 +1627,8 @@ static void hci_tx_task(unsigned long arg)
read_lock(&hci_task_lock);
- BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
+ BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt,
+ hdev->sco_cnt, hdev->le_cnt);
/* Schedule queues and send stuff to HCI driver */
@@ -1573,6 +1638,8 @@ static void hci_tx_task(unsigned long arg)
hci_sched_esco(hdev);
+ hci_sched_le(hdev);
+
/* Send next queued raw (unknown type) packet */
while ((skb = skb_dequeue(&hdev->raw_q)))
hci_send_frame(skb);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0b979ae..a914314 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -539,6 +539,26 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
hci_req_complete(hdev, rp->status);
}
+static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_rp_le_read_buffer_size *rp = (void *) skb->data;
+
+ BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+ if (rp->status)
+ return;
+
+ hdev->le_mtu = __le16_to_cpu(rp->le_mtu);
+ hdev->le_pkts = rp->le_max_pkt;
+
+ hdev->le_cnt = hdev->le_pkts;
+
+ BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts);
+
+ hci_req_complete(hdev, rp->status);
+}
+
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{
BT_DBG("%s status 0x%x", hdev->name, status);
@@ -1397,6 +1417,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_read_bd_addr(hdev, skb);
break;
+ case HCI_OP_LE_READ_BUFFER_SIZE:
+ hci_cc_le_read_buffer_size(hdev, skb);
+ break;
+
case HCI_OP_LE_SET_ADVERTISE_ENABLE:
hci_cc_le_set_advertise(hdev, skb);
break;
@@ -1542,10 +1566,16 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
conn->sent -= count;
if (conn->type == ACL_LINK) {
- if ((hdev->acl_cnt += count) > hdev->acl_pkts)
+ hdev->acl_cnt += count;
+ if (hdev->acl_cnt > hdev->acl_pkts)
hdev->acl_cnt = hdev->acl_pkts;
+ } else if (conn->type == LE_LINK) {
+ hdev->le_cnt += count;
+ if (hdev->le_cnt > hdev->le_pkts)
+ hdev->le_cnt = hdev->le_pkts;
} else {
- if ((hdev->sco_cnt += count) > hdev->sco_pkts)
+ hdev->sco_cnt += count;
+ if (hdev->sco_cnt > hdev->sco_pkts)
hdev->sco_cnt = hdev->sco_pkts;
}
}
--
1.7.0.1
^ permalink raw reply related
* [PATCH 3/7] Bluetooth: LE disconnection and connect cancel support
From: Ville Tervo @ 2010-10-06 18:42 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ville Tervo
In-Reply-To: <1286390535-27462-1-git-send-email-ville.tervo@nokia.com>
Add supprt to cancel and disconnet connections.
Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
---
include/net/bluetooth/hci.h | 5 ++---
include/net/bluetooth/hci_core.h | 3 +++
net/bluetooth/hci_conn.c | 30 ++++++++++++++++++++++++++++++
3 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index b326240..d04ecea 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -191,6 +191,8 @@ enum {
#define LMP_EV4 0x01
#define LMP_EV5 0x02
+#define LMP_NO_BR 0x20
+#define LMP_LE 0x40
#define LMP_SNIFF_SUBR 0x02
#define LMP_EDR_ESCO_2M 0x20
@@ -627,9 +629,6 @@ struct hci_cp_le_create_conn {
} __packed;
#define HCI_OP_LE_CREATE_CONN_CANCEL 0x200e
-struct hci_cp_le_create_conn_cancel {
- __u8 status;
-} __packed;
#define HCI_OP_LE_SET_ADVERTISE_ENABLE 0x200a
#define LE_ADVERTISE_ENABLED 0x01
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 89f4b10..a430a57 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -455,10 +455,13 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH)
#define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT)
#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
+#define lmp_br_capable(dev) (!((dev)->features[4] & LMP_NO_BR))
+#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE)
#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
+
/* ----- HCI protocols ----- */
struct hci_proto {
char *name;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index cb41d64..50f8973 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -66,6 +66,31 @@ void hci_le_connect(struct hci_conn *conn)
hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
}
+static void hci_le_connect_cancel(struct hci_conn *conn)
+{
+ struct hci_dev *hdev = conn->hdev;
+
+ BT_DBG("%p", conn);
+
+ if (!lmp_le_capable(hdev))
+ return;
+
+ hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
+}
+
+void hci_le_disconn(struct hci_conn *conn, __u8 reason)
+{
+ struct hci_cp_disconnect cp;
+
+ BT_DBG("%p", conn);
+
+ conn->le_state = BT_DISCONN;
+
+ cp.handle = cpu_to_le16(conn->handle);
+ cp.reason = reason;
+ hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
+}
+
void hci_acl_connect(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
@@ -221,6 +246,8 @@ static void hci_conn_timeout(unsigned long arg)
case BT_CONNECT2:
if (conn->type == ACL_LINK && conn->out)
hci_acl_connect_cancel(conn);
+ if (conn->type == LE_LINK && conn->out)
+ hci_le_connect_cancel(conn);
break;
case BT_CONFIG:
case BT_CONNECTED:
@@ -397,6 +424,9 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
BT_DBG("%s dst %s", hdev->name, batostr(dst));
if (type == LE_LINK) {
+ if (!lmp_le_capable(hdev))
+ return NULL;
+
le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
if (!le)
--
1.7.0.1
^ permalink raw reply related
* [PATCH 2/7] Bluetooth: Add LE connect support
From: Ville Tervo @ 2010-10-06 18:42 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ville Tervo
In-Reply-To: <1286390535-27462-1-git-send-email-ville.tervo@nokia.com>
Add logic to create LE connections.
Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
---
include/net/bluetooth/hci.h | 1 +
include/net/bluetooth/hci_core.h | 6 ++-
net/bluetooth/hci_conn.c | 38 ++++++++++++++-
net/bluetooth/hci_event.c | 100 +++++++++++++++++++++++++++++++++++++-
4 files changed, 141 insertions(+), 4 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index b86aed5..b326240 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -162,6 +162,7 @@ enum {
#define SCO_LINK 0x00
#define ACL_LINK 0x01
#define ESCO_LINK 0x02
+#define LE_LINK 0x03
/* LMP features */
#define LMP_3SLOT 0x01
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index ebec8c9..89f4b10 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -170,6 +170,7 @@ struct hci_conn {
bdaddr_t dst;
__u16 handle;
__u16 state;
+ __u16 le_state;
__u8 mode;
__u8 type;
__u8 out;
@@ -203,6 +204,7 @@ struct hci_conn {
struct hci_dev *hdev;
void *l2cap_data;
void *sco_data;
+ void *le_data;
void *priv;
struct hci_conn *link;
@@ -272,7 +274,7 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
{
struct hci_conn_hash *h = &hdev->conn_hash;
list_add(&c->list, &h->list);
- if (c->type == ACL_LINK)
+ if (c->type == ACL_LINK || c->type == LE_LINK)
h->acl_num++;
else
h->sco_num++;
@@ -282,7 +284,7 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
{
struct hci_conn_hash *h = &hdev->conn_hash;
list_del(&c->list);
- if (c->type == ACL_LINK)
+ if (c->type == ACL_LINK || c->type == LE_LINK)
h->acl_num--;
else
h->sco_num--;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 145993f..cb41d64 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -45,6 +45,27 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
+void hci_le_connect(struct hci_conn *conn)
+{
+ struct hci_dev *hdev = conn->hdev;
+ struct hci_cp_le_create_conn cp;
+
+ conn->le_state = BT_CONNECT;
+ conn->out = 1;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.scan_interval = cpu_to_le16(0x0004);
+ cp.scan_window = cpu_to_le16(0x0004);
+ bacpy(&cp.peer_addr, &conn->dst);
+ cp.conn_interval_min = cpu_to_le16(0x0008);
+ cp.conn_interval_max = cpu_to_le16(0x0100);
+ cp.supervision_timeout = cpu_to_le16(0x0064);
+ cp.min_ce_len = cpu_to_le16(0x0001);
+ cp.max_ce_len = cpu_to_le16(0xffff);
+
+ hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
+}
+
void hci_acl_connect(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
@@ -365,15 +386,30 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
}
EXPORT_SYMBOL(hci_get_route);
-/* Create SCO or ACL connection.
+/* Create SCO, ACL or LE connection.
* Device _must_ be locked */
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
{
struct hci_conn *acl;
struct hci_conn *sco;
+ struct hci_conn *le;
BT_DBG("%s dst %s", hdev->name, batostr(dst));
+ if (type == LE_LINK) {
+ le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
+
+ if (!le)
+ le = hci_conn_add(hdev, LE_LINK, dst);
+
+ if (!le)
+ return NULL;
+
+ hci_le_connect(le);
+
+ return le;
+ }
+
if (!(acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
return NULL;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d3c68de..0b979ae 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -868,6 +868,44 @@ static void hci_cc_le_set_scan(struct hci_dev *hdev, struct sk_buff *skb)
hci_req_complete(hdev, status);
}
+static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
+{
+ struct hci_cp_le_create_conn *cp;
+ struct hci_conn *conn;
+
+ BT_DBG("%s status 0x%x", hdev->name, status);
+
+ cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
+ if (!cp)
+ return;
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
+
+ BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
+ conn);
+
+ if (status) {
+ if (conn && conn->le_state == BT_CONNECT) {
+ conn->le_state = BT_CLOSED;
+ hci_proto_connect_cfm(conn, status);
+ hci_conn_del(conn);
+ }
+ } else {
+ if (!conn) {
+ conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
+ if (conn) {
+ conn->out = 1;
+ conn->link_mode |= HCI_LM_MASTER;
+ } else
+ BT_ERR("No memory for new connection");
+ }
+ }
+
+ hci_dev_unlock(hdev);
+}
+
static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
@@ -1069,7 +1107,10 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
- conn->state = BT_CLOSED;
+ if (conn->type == LE_LINK)
+ conn->le_state = BT_CLOSED;
+ else
+ conn->state = BT_CLOSED;
hci_proto_disconn_cfm(conn, ev->reason);
hci_conn_del(conn);
@@ -1430,6 +1471,10 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_exit_sniff_mode(hdev, ev->status);
break;
+ case HCI_OP_LE_CREATE_CONN:
+ hci_cs_le_create_conn(hdev, ev->status);
+ break;
+
default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break;
@@ -1875,6 +1920,55 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
hci_dev_unlock(hdev);
}
+static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_ev_le_conn_complete *ev = (void *) skb->data;
+ struct hci_conn *conn;
+
+ BT_DBG("%s status %d", hdev->name, ev->status);
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
+
+ if (!conn)
+ goto unlock;
+
+ if (ev->status) {
+ hci_proto_connect_cfm(conn, ev->status);
+ conn->le_state = BT_CLOSED;
+ hci_conn_del(conn);
+ goto unlock;
+ }
+
+ conn->handle = __le16_to_cpu(ev->handle);
+ conn->le_state = BT_CONNECTED;
+
+ hci_conn_hold_device(conn);
+ hci_conn_add_sysfs(conn);
+
+ hci_proto_connect_cfm(conn, ev->status);
+unlock:
+ hci_dev_unlock(hdev);
+}
+
+static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_ev_le_meta *le_ev = (void *) skb->data;
+ __u8 event = le_ev->subevent;
+
+ skb_pull(skb, sizeof(*le_ev));
+
+ switch (event) {
+ case HCI_EV_LE_CONN_COMPLETE:
+ hci_le_conn_complete_evt(hdev, skb);
+ break;
+
+ default:
+ break;
+ }
+}
+
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_event_hdr *hdr = (void *) skb->data;
@@ -2011,6 +2105,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_remote_host_features_evt(hdev, skb);
break;
+ case HCI_EV_LE_META:
+ hci_le_meta_evt(hdev, skb);
+ break;
+
default:
BT_DBG("%s event 0x%x", hdev->name, event);
break;
--
1.7.0.1
^ permalink raw reply related
* [PATCH 1/7] Bluetooth: Add low energy commands and events
From: Ville Tervo @ 2010-10-06 18:42 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ville Tervo
In-Reply-To: <1286390535-27462-1-git-send-email-ville.tervo@nokia.com>
Add needed HCI command and event to create LE connections.
Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
---
include/net/bluetooth/hci.h | 52 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 52 insertions(+), 0 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 740e5de..b86aed5 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -597,6 +597,39 @@ struct hci_rp_read_bd_addr {
} __packed;
/* --- HCI LE Commands --- */
+#define HCI_OP_LE_SET_EVENT_MASK 0x2001
+struct hci_cp_le_set_event_mask {
+ __u8 mask[8];
+} __packed;
+
+#define HCI_OP_LE_READ_BUFFER_SIZE 0x2002
+struct hci_rp_le_read_buffer_size {
+ __u8 status;
+ __le16 le_mtu;
+ __u8 le_max_pkt;
+} __packed;
+
+#define HCI_OP_LE_CREATE_CONN 0x200d
+struct hci_cp_le_create_conn {
+ __le16 scan_interval;
+ __le16 scan_window;
+ __u8 filter_policy;
+ __u8 peer_addr_type;
+ bdaddr_t peer_addr;
+ __u8 own_address_type;
+ __le16 conn_interval_min;
+ __le16 conn_interval_max;
+ __le16 conn_latency;
+ __le16 supervision_timeout;
+ __le16 min_ce_len;
+ __le16 max_ce_len;
+} __packed;
+
+#define HCI_OP_LE_CREATE_CONN_CANCEL 0x200e
+struct hci_cp_le_create_conn_cancel {
+ __u8 status;
+} __packed;
+
#define HCI_OP_LE_SET_ADVERTISE_ENABLE 0x200a
#define LE_ADVERTISE_ENABLED 0x01
#define LE_ADVERTISE_DISABLED 0x00
@@ -857,6 +890,25 @@ struct hci_ev_remote_host_features {
__u8 features[8];
} __packed;
+#define HCI_EV_LE_META 0x3e
+struct hci_ev_le_meta {
+ __u8 subevent;
+} __packed;
+
+/* Low energy meta events */
+#define HCI_EV_LE_CONN_COMPLETE 0x01
+struct hci_ev_le_conn_complete {
+ __u8 status;
+ __le16 handle;
+ __u8 role;
+ __u8 bdaddr_type;
+ bdaddr_t bdaddr;
+ __le16 interval;
+ __le16 latency;
+ __le16 supervision_timeout;
+ __u8 clk_accurancy;
+} __packed;
+
/* Internal events generated by Bluetooth stack */
#define HCI_EV_STACK_INTERNAL 0xfd
struct hci_ev_stack_internal {
--
1.7.0.1
^ permalink raw reply related
* [RFC] Basic Bluetooth LE support
From: Ville Tervo @ 2010-10-06 18:42 UTC (permalink / raw)
To: linux-bluetooth
Hi,
This pathcset introduses basic Bluetooth LE support. Please review.
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Luis R. Rodriguez @ 2010-10-06 18:33 UTC (permalink / raw)
To: Johannes Berg
Cc: Luis Rodriguez, Marcel Holtmann, linux-bluetooth,
linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org,
Deepak Dhamdhere, Sree Durbha
In-Reply-To: <1286389697.3655.401.camel@jlt3.sipsolutions.net>
On Wed, Oct 06, 2010 at 11:28:17AM -0700, Johannes Berg wrote:
> On Wed, 2010-10-06 at 11:26 -0700, Luis R. Rodriguez wrote:
>
> > > Good idea, I forgot about possible firmware changes :) Lets see if our
> > > team can do that. Thanks for all the feedback.
> >
> > Deepak a proof of concept test can involve simply hex-editing the
> > ath3k-1.fw and replacing 0x3002 to 0x3003, then the above patch might
> > work.
>
> $ hd ath3k-1.fw
> ...
> 00000670 00 00 00 00 00 00 00 00 00 00 00 00 f3 0c 02 30 |...............0|
> 00000680 12 01 10 01 e0 01 01 40 f3 0c 02 30 01 00 00 00 |.......@...0....|
> ...
>
> that looks a lot like the IDs right there, in little endian :-)
Furthermore another idea by johannes is that if we cannot fix this
in firmware by changing the exposed device ID, we could just check
in btusb for some USB component that would come alive once the firmware
does get loaded, like endpoints, or speed, or whatever. But that would
be last resort.
Luis
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Johannes Berg @ 2010-10-06 18:28 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: Marcel Holtmann, Luis Rodriguez, linux-bluetooth,
linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org,
Deepak Dhamdhere, Sree Durbha
In-Reply-To: <AANLkTi=o4Mc72NrNoALBdS3YHeY7RMyyAJPsCy=uW3+F@mail.gmail.com>
On Wed, 2010-10-06 at 11:26 -0700, Luis R. Rodriguez wrote:
> > Good idea, I forgot about possible firmware changes :) Lets see if our
> > team can do that. Thanks for all the feedback.
>
> Deepak a proof of concept test can involve simply hex-editing the
> ath3k-1.fw and replacing 0x3002 to 0x3003, then the above patch might
> work.
$ hd ath3k-1.fw
...
00000670 00 00 00 00 00 00 00 00 00 00 00 00 f3 0c 02 30 |...............0|
00000680 12 01 10 01 e0 01 01 40 f3 0c 02 30 01 00 00 00 |.......@...0....|
...
that looks a lot like the IDs right there, in little endian :-)
johannes
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Luis R. Rodriguez @ 2010-10-06 18:26 UTC (permalink / raw)
To: Johannes Berg
Cc: Marcel Holtmann, Luis Rodriguez, linux-bluetooth,
linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org,
Deepak Dhamdhere, Sree Durbha
In-Reply-To: <AANLkTikYRSQw-+Tcj4VS1qxi=OaeF9C5hjAMWVu+0M=v@mail.gmail.com>
On Wed, Oct 6, 2010 at 11:22 AM, Luis R. Rodriguez
<lrodriguez@atheros.com> wrote:
> On Wed, Oct 6, 2010 at 10:54 AM, Johannes Berg
> <johannes@sipsolutions.net> wrote:
>> On Wed, 2010-10-06 at 10:39 -0700, Luis R. Rodriguez wrote:
>>
>>
>>> > With sflash based AR3011 hardware, when we connect the device to USB
>>> > port it gets detected as a Bluetooth device because of firmware in
>>> > Flash (VID=0x0CF3, PID=0x3002). This triggers the Bluetooth sub
>>> > system driver (btusb.ko) directly in the host instead of ath3k
>>> > DFU driver. Therefore, there is no firmware downloaded in to the
>>> > RAM to bring up Bluetooth at this point. This is the problem
>>> > we're trying to "fix".
>>
>> So the easiest fix for this would be to
>> a) ignore 0x0cf3,0x3002 in btusb
>> b) add it to ath3k firmware loading
>> c) change the ath3k firmware to load with 0x0cf3,0x3003 (or whatever
>> else you want, as long as it's not 0x3000 and not 0x3002)
>>
>> Then the ignore in btusb won't affect ath3k after that new firmware was
>> loaded.
>
> Good idea, I forgot about possible firmware changes :) Lets see if our
> team can do that. Thanks for all the feedback.
Deepak a proof of concept test can involve simply hex-editing the
ath3k-1.fw and replacing 0x3002 to 0x3003, then the above patch might
work.
Luis
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Luis R. Rodriguez @ 2010-10-06 18:22 UTC (permalink / raw)
To: Johannes Berg
Cc: Marcel Holtmann, Luis Rodriguez, linux-bluetooth,
linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org,
Deepak Dhamdhere, Sree Durbha
In-Reply-To: <1286387660.3655.382.camel@jlt3.sipsolutions.net>
On Wed, Oct 6, 2010 at 10:54 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Wed, 2010-10-06 at 10:39 -0700, Luis R. Rodriguez wrote:
>
>
>> > With sflash based AR3011 hardware, when we connect the device to USB
>> > port it gets detected as a Bluetooth device because of firmware in
>> > Flash (VID=0x0CF3, PID=0x3002). This triggers the Bluetooth sub
>> > system driver (btusb.ko) directly in the host instead of ath3k
>> > DFU driver. Therefore, there is no firmware downloaded in to the
>> > RAM to bring up Bluetooth at this point. This is the problem
>> > we're trying to "fix".
>
> So the easiest fix for this would be to
> a) ignore 0x0cf3,0x3002 in btusb
> b) add it to ath3k firmware loading
> c) change the ath3k firmware to load with 0x0cf3,0x3003 (or whatever
> else you want, as long as it's not 0x3000 and not 0x3002)
>
> Then the ignore in btusb won't affect ath3k after that new firmware was
> loaded.
Good idea, I forgot about possible firmware changes :) Lets see if our
team can do that. Thanks for all the feedback.
Luis
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Johannes Berg @ 2010-10-06 17:54 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: Marcel Holtmann, Luis Rodriguez, linux-bluetooth,
linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org,
Deepak Dhamdhere, Sree Durbha
In-Reply-To: <20101006173949.GG7070@tux>
On Wed, 2010-10-06 at 10:39 -0700, Luis R. Rodriguez wrote:
> > With sflash based AR3011 hardware, when we connect the device to USB
> > port it gets detected as a Bluetooth device because of firmware in
> > Flash (VID=0x0CF3, PID=0x3002). This triggers the Bluetooth sub
> > system driver (btusb.ko) directly in the host instead of ath3k
> > DFU driver. Therefore, there is no firmware downloaded in to the
> > RAM to bring up Bluetooth at this point. This is the problem
> > we're trying to "fix".
So the easiest fix for this would be to
a) ignore 0x0cf3,0x3002 in btusb
b) add it to ath3k firmware loading
c) change the ath3k firmware to load with 0x0cf3,0x3003 (or whatever
else you want, as long as it's not 0x3000 and not 0x3002)
Then the ignore in btusb won't affect ath3k after that new firmware was
loaded.
johannes
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Sven-Haegar Koch @ 2010-10-06 17:52 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: Marcel Holtmann, Luis Rodriguez, linux-bluetooth,
linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org,
Deepak Dhamdhere, Sree Durbha
In-Reply-To: <AANLkTik9w4_PdcEsbRHakLcxcD334_1Q8hGArxTXPCGF@mail.gmail.com>
On Wed, 6 Oct 2010, Luis R. Rodriguez wrote:
> I just got this description from Sady:
>
> -------------------------------------------------------------------------------------------------------------------
> With eeprom based AR3011 hardware, normally this device gets detected
> as a normal USB device with VID=0x0CF3, PID=0x3000.
> Ath3k DFU driver will download the firmware in to RAM.
> Due to firmware download in the RAM it is exposed as new device
> with VID=0x0CF3, PID=0x3002 to host Bluetooth sub system and btusb.ko
> driver probe routine gets called to bring up Bluetooth interface.
> This is the normal procedure we have done so far on Linux.
>
> With sflash based AR3011 hardware, when we connect the device to USB
> port it gets detected as a Bluetooth device because of firmware in
> Flash (VID=0x0CF3, PID=0x3002). This triggers the Bluetooth sub
> system driver (btusb.ko) directly in the host instead of ath3k
> DFU driver. Therefore, there is no firmware downloaded in to the
> RAM to bring up Bluetooth at this point. This is the problem
> we're trying to "fix".
> -------------------------------------------------------------------------------------------------------------------
>
> With the above patch we'd get ath3k to do the firmware uploading but
> I'm afraid that we'll go into a loop here unless we can figure out a
> way to get btusb to know the device is now ready.
Modify the firmware file so that after loading the firmware it gets for
example VID=0x0CF3, PID=0x3003.
Blacklist VID=0x0CF3, PID=0x3002 in btusb and add it to ath3k.
>From then on VID=0x0CF3, PID=0x3000 and PID=0x3002 mean "need firmware"
and PID=0x3003 is the operational state (like half of your PID=0x3002
usage is now)
c'ya
sven-haegar
--
Three may keep a secret, if two of them are dead.
- Ben F.
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Luis R. Rodriguez @ 2010-10-06 17:39 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Luis Rodriguez, linux-bluetooth, linux-kernel@vger.kernel.org,
linux-wireless@vger.kernel.org, Deepak Dhamdhere, Sree Durbha
In-Reply-To: <AANLkTik9w4_PdcEsbRHakLcxcD334_1Q8hGArxTXPCGF@mail.gmail.com>
On Wed, Oct 06, 2010 at 10:37:46AM -0700, Luis R. Rodriguez wrote:
> On Wed, Oct 6, 2010 at 9:38 AM, Luis R. Rodriguez
> <lrodriguez@atheros.com> wrote:
> > On Wed, Oct 06, 2010 at 08:56:06AM -0700, Marcel Holtmann wrote:
> >> Hi Luis,
> >>
> >> > > Now I am failing to understand why this was done wrong in the first
> >> > > place. Especially if the loading procedure happens as you say it
> >> > > happens.
> >> >
> >> > You got me :) Anyone?
> >> >
> >> > > This is the example for the Broadcom 203x devices:
> >> > >
> >> > > static struct usb_device_id blacklist_table[] = {
> >> > > /* Broadcom BCM2033 without firmware */
> >> > > { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
> >> > >
> >> > > The btusb driver clearly blacklists them. And then bcm203x can take over
> >> > > loading the firmware:
> >> > >
> >> > > static const struct usb_device_id bcm203x_table[] = {
> >> > > /* Broadcom Blutonium (BCM2033) */
> >> > > { USB_DEVICE(0x0a5c, 0x2033) },
> >> > >
> >> > > So there is a working example of this already in the kernel tree since
> >> > > forever.
> >> >
> >> > Nice, thanks for the pointer. Our team will review and try to address
> >> > an alternative patch.
> >> >
> >> > Now for my own sanity -- I still don't think I get this how this
> >> > BCM2033 blacklist trick works, I take it the device once plugged in
> >> > gets a generic btusb USB device vendor:device ID. The btusb driver
> >> > then picks up the the blacklist table, and searches for a
> >> > usb_match_id() on it for the given interface... What I don't get is
> >> > how there will be a match here if the USB vendor:device ID is just the
> >> > generic btusb one. Can you help me understand how this trick works?
> >>
> >> the generic Bluetooth USB class descriptors is what btusb uses. With a
> >> few expectation for devices that use VID:PID combination.
> >
> > Ahhh... got it..
> >
> >> So in general what happens if a device gets matched via the Bluetooth
> >> USB class descriptors the btusb driver will claim. We do however check
> >> against out blacklist first. If the VID:PID is listed in the blacklist
> >> we do return ENODEV. That means that the USB subsystem goes ahead and
> >> tries the next driver. In this case bcm203x driver. This will claim it,
> >> load the firmware, reset it and come back with different VID:PID values.
> >> After that the btusb can successfully claim it since it is no longer in
> >> the blacklist.
> >
> > Ah neat.
> >
> >> If I understand this all correct without having the hardware available
> >> for verifying this, then it should be like this:
> >>
> >> Just add this to blacklist_table[] in btusb.c:
> >>
> >> /* Atheros AR3011 without firmware */
> >> { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
> >>
> >> And then we can add the firmware loading to ath3k driver to load the
> >> specific 1st stage firmware. And then ath3k can load the 2nd stage as
> >> well. After that it should become a default Bluetooth USB device and the
> >> btusb driver can take care of it.
> >
> > Got it... thanks for the clarification. So ath3k actually doesn't seem to
> > have 2-stage firmware files, ath3k-2.fw actually seems to be a new firmware
> > upgrade. The firmware already made it into linux-firmware.git tree but the
> > respective patch just never made it upstream. I am not sure of the
> > differences between these firmware but I do remember reading from Vikram
> > that no new API was changed. I asked for clarification on the firmware
> > updates and asked if it can be documented here:
> >
> > http://wireless.kernel.org/en/users/Drivers/ath3k
> >
> > If the device can live with simply getting ath3k-1.fw loaded once then
> > perhaps the change you described above is all that is needed, not sure.
> >
> > Deepak, can you please try this patch, I don't have hardware to test
> > this with.
> >
> > diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> > index d22ce3c..a62c1b2 100644
> > --- a/drivers/bluetooth/btusb.c
> > +++ b/drivers/bluetooth/btusb.c
> > @@ -140,6 +140,9 @@ static struct usb_device_id blacklist_table[] = {
> > /* Frontline ComProbe Bluetooth Sniffer */
> > { USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER },
> >
> > + /* Atheros AR3011 without firmware */
> > + { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
> > +
> > { } /* Terminating entry */
> > };
>
> I just got this description from Sady:
>
> -------------------------------------------------------------------------------------------------------------------
> With eeprom based AR3011 hardware, normally this device gets detected
> as a normal USB device with VID=0x0CF3, PID=0x3000.
> Ath3k DFU driver will download the firmware in to RAM.
> Due to firmware download in the RAM it is exposed as new device
> with VID=0x0CF3, PID=0x3002 to host Bluetooth sub system and btusb.ko
> driver probe routine gets called to bring up Bluetooth interface.
> This is the normal procedure we have done so far on Linux.
>
> With sflash based AR3011 hardware, when we connect the device to USB
> port it gets detected as a Bluetooth device because of firmware in
> Flash (VID=0x0CF3, PID=0x3002). This triggers the Bluetooth sub
> system driver (btusb.ko) directly in the host instead of ath3k
> DFU driver. Therefore, there is no firmware downloaded in to the
> RAM to bring up Bluetooth at this point. This is the problem
> we're trying to "fix".
> -------------------------------------------------------------------------------------------------------------------
>
> With the above patch we'd get ath3k to do the firmware uploading but
> I'm afraid that we'll go into a loop here unless we can figure out a
> way to get btusb to know the device is now ready.
Oh and we'd still need something like this instead:
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 128cae4..c90512d 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -35,6 +35,7 @@
static struct usb_device_id ath3k_table[] = {
/* Atheros AR3011 */
{ USB_DEVICE(0x0CF3, 0x3000) },
+ { USB_DEVICE(0x0CF3, 0x3002) },
{ } /* Terminating entry */
};
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index d22ce3c..a62c1b2 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -140,6 +140,9 @@ static struct usb_device_id blacklist_table[] = {
/* Frontline ComProbe Bluetooth Sniffer */
{ USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER },
+ /* Atheros AR3011 without firmware */
+ { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
+
{ } /* Terminating entry */
};
But yeah, not sure how to prevent a loop. I'm actually not sure
what would happen once we hit the ath3k driver on the sflash
based devices with this patch.
Luis
^ permalink raw reply related
* Re: RFC: btusb firmware load help
From: Luis R. Rodriguez @ 2010-10-06 17:37 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Luis Rodriguez, linux-bluetooth, linux-kernel@vger.kernel.org,
linux-wireless@vger.kernel.org, Deepak Dhamdhere, Sree Durbha
In-Reply-To: <20101006163816.GE7070@tux>
On Wed, Oct 6, 2010 at 9:38 AM, Luis R. Rodriguez
<lrodriguez@atheros.com> wrote:
> On Wed, Oct 06, 2010 at 08:56:06AM -0700, Marcel Holtmann wrote:
>> Hi Luis,
>>
>> > > Now I am failing to understand why this was done wrong in the first
>> > > place. Especially if the loading procedure happens as you say it
>> > > happens.
>> >
>> > You got me :) Anyone?
>> >
>> > > This is the example for the Broadcom 203x devices:
>> > >
>> > > static struct usb_device_id blacklist_table[] = {
>> > > /* Broadcom BCM2033 without firmware */
>> > > { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
>> > >
>> > > The btusb driver clearly blacklists them. And then bcm203x can take over
>> > > loading the firmware:
>> > >
>> > > static const struct usb_device_id bcm203x_table[] = {
>> > > /* Broadcom Blutonium (BCM2033) */
>> > > { USB_DEVICE(0x0a5c, 0x2033) },
>> > >
>> > > So there is a working example of this already in the kernel tree since
>> > > forever.
>> >
>> > Nice, thanks for the pointer. Our team will review and try to address
>> > an alternative patch.
>> >
>> > Now for my own sanity -- I still don't think I get this how this
>> > BCM2033 blacklist trick works, I take it the device once plugged in
>> > gets a generic btusb USB device vendor:device ID. The btusb driver
>> > then picks up the the blacklist table, and searches for a
>> > usb_match_id() on it for the given interface... What I don't get is
>> > how there will be a match here if the USB vendor:device ID is just the
>> > generic btusb one. Can you help me understand how this trick works?
>>
>> the generic Bluetooth USB class descriptors is what btusb uses. With a
>> few expectation for devices that use VID:PID combination.
>
> Ahhh... got it..
>
>> So in general what happens if a device gets matched via the Bluetooth
>> USB class descriptors the btusb driver will claim. We do however check
>> against out blacklist first. If the VID:PID is listed in the blacklist
>> we do return ENODEV. That means that the USB subsystem goes ahead and
>> tries the next driver. In this case bcm203x driver. This will claim it,
>> load the firmware, reset it and come back with different VID:PID values.
>> After that the btusb can successfully claim it since it is no longer in
>> the blacklist.
>
> Ah neat.
>
>> If I understand this all correct without having the hardware available
>> for verifying this, then it should be like this:
>>
>> Just add this to blacklist_table[] in btusb.c:
>>
>> /* Atheros AR3011 without firmware */
>> { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
>>
>> And then we can add the firmware loading to ath3k driver to load the
>> specific 1st stage firmware. And then ath3k can load the 2nd stage as
>> well. After that it should become a default Bluetooth USB device and the
>> btusb driver can take care of it.
>
> Got it... thanks for the clarification. So ath3k actually doesn't seem to
> have 2-stage firmware files, ath3k-2.fw actually seems to be a new firmware
> upgrade. The firmware already made it into linux-firmware.git tree but the
> respective patch just never made it upstream. I am not sure of the
> differences between these firmware but I do remember reading from Vikram
> that no new API was changed. I asked for clarification on the firmware
> updates and asked if it can be documented here:
>
> http://wireless.kernel.org/en/users/Drivers/ath3k
>
> If the device can live with simply getting ath3k-1.fw loaded once then
> perhaps the change you described above is all that is needed, not sure.
>
> Deepak, can you please try this patch, I don't have hardware to test
> this with.
>
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index d22ce3c..a62c1b2 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -140,6 +140,9 @@ static struct usb_device_id blacklist_table[] = {
> /* Frontline ComProbe Bluetooth Sniffer */
> { USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER },
>
> + /* Atheros AR3011 without firmware */
> + { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
> +
> { } /* Terminating entry */
> };
I just got this description from Sady:
-------------------------------------------------------------------------------------------------------------------
With eeprom based AR3011 hardware, normally this device gets detected
as a normal USB device with VID=0x0CF3, PID=0x3000.
Ath3k DFU driver will download the firmware in to RAM.
Due to firmware download in the RAM it is exposed as new device
with VID=0x0CF3, PID=0x3002 to host Bluetooth sub system and btusb.ko
driver probe routine gets called to bring up Bluetooth interface.
This is the normal procedure we have done so far on Linux.
With sflash based AR3011 hardware, when we connect the device to USB
port it gets detected as a Bluetooth device because of firmware in
Flash (VID=0x0CF3, PID=0x3002). This triggers the Bluetooth sub
system driver (btusb.ko) directly in the host instead of ath3k
DFU driver. Therefore, there is no firmware downloaded in to the
RAM to bring up Bluetooth at this point. This is the problem
we're trying to "fix".
-------------------------------------------------------------------------------------------------------------------
With the above patch we'd get ath3k to do the firmware uploading but
I'm afraid that we'll go into a loop here unless we can figure out a
way to get btusb to know the device is now ready.
Luis
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Luis R. Rodriguez @ 2010-10-06 16:38 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Luis Rodriguez, linux-bluetooth, linux-kernel@vger.kernel.org,
linux-wireless@vger.kernel.org, Deepak Dhamdhere, Sree Durbha
In-Reply-To: <1286380566.6145.42.camel@aeonflux>
On Wed, Oct 06, 2010 at 08:56:06AM -0700, Marcel Holtmann wrote:
> Hi Luis,
>
> > > Now I am failing to understand why this was done wrong in the first
> > > place. Especially if the loading procedure happens as you say it
> > > happens.
> >
> > You got me :) Anyone?
> >
> > > This is the example for the Broadcom 203x devices:
> > >
> > > static struct usb_device_id blacklist_table[] = {
> > > /* Broadcom BCM2033 without firmware */
> > > { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
> > >
> > > The btusb driver clearly blacklists them. And then bcm203x can take over
> > > loading the firmware:
> > >
> > > static const struct usb_device_id bcm203x_table[] = {
> > > /* Broadcom Blutonium (BCM2033) */
> > > { USB_DEVICE(0x0a5c, 0x2033) },
> > >
> > > So there is a working example of this already in the kernel tree since
> > > forever.
> >
> > Nice, thanks for the pointer. Our team will review and try to address
> > an alternative patch.
> >
> > Now for my own sanity -- I still don't think I get this how this
> > BCM2033 blacklist trick works, I take it the device once plugged in
> > gets a generic btusb USB device vendor:device ID. The btusb driver
> > then picks up the the blacklist table, and searches for a
> > usb_match_id() on it for the given interface... What I don't get is
> > how there will be a match here if the USB vendor:device ID is just the
> > generic btusb one. Can you help me understand how this trick works?
>
> the generic Bluetooth USB class descriptors is what btusb uses. With a
> few expectation for devices that use VID:PID combination.
Ahhh... got it..
> So in general what happens if a device gets matched via the Bluetooth
> USB class descriptors the btusb driver will claim. We do however check
> against out blacklist first. If the VID:PID is listed in the blacklist
> we do return ENODEV. That means that the USB subsystem goes ahead and
> tries the next driver. In this case bcm203x driver. This will claim it,
> load the firmware, reset it and come back with different VID:PID values.
> After that the btusb can successfully claim it since it is no longer in
> the blacklist.
Ah neat.
> If I understand this all correct without having the hardware available
> for verifying this, then it should be like this:
>
> Just add this to blacklist_table[] in btusb.c:
>
> /* Atheros AR3011 without firmware */
> { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
>
> And then we can add the firmware loading to ath3k driver to load the
> specific 1st stage firmware. And then ath3k can load the 2nd stage as
> well. After that it should become a default Bluetooth USB device and the
> btusb driver can take care of it.
Got it... thanks for the clarification. So ath3k actually doesn't seem to
have 2-stage firmware files, ath3k-2.fw actually seems to be a new firmware
upgrade. The firmware already made it into linux-firmware.git tree but the
respective patch just never made it upstream. I am not sure of the
differences between these firmware but I do remember reading from Vikram
that no new API was changed. I asked for clarification on the firmware
updates and asked if it can be documented here:
http://wireless.kernel.org/en/users/Drivers/ath3k
If the device can live with simply getting ath3k-1.fw loaded once then
perhaps the change you described above is all that is needed, not sure.
Deepak, can you please try this patch, I don't have hardware to test
this with.
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index d22ce3c..a62c1b2 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -140,6 +140,9 @@ static struct usb_device_id blacklist_table[] = {
/* Frontline ComProbe Bluetooth Sniffer */
{ USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER },
+ /* Atheros AR3011 without firmware */
+ { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
+
{ } /* Terminating entry */
};
^ permalink raw reply related
* Re: RFC: btusb firmware load help
From: Marcel Holtmann @ 2010-10-06 15:56 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: Luis Rodriguez, linux-bluetooth, linux-kernel@vger.kernel.org,
linux-wireless@vger.kernel.org, Deepak Dhamdhere, Sree Durbha
In-Reply-To: <AANLkTimDvgFtoGLEjgWyYRrhQy6Num-rn_2WYO4Lf84b@mail.gmail.com>
Hi Luis,
> > Now I am failing to understand why this was done wrong in the first
> > place. Especially if the loading procedure happens as you say it
> > happens.
>
> You got me :) Anyone?
>
> > This is the example for the Broadcom 203x devices:
> >
> > static struct usb_device_id blacklist_table[] = {
> > /* Broadcom BCM2033 without firmware */
> > { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
> >
> > The btusb driver clearly blacklists them. And then bcm203x can take over
> > loading the firmware:
> >
> > static const struct usb_device_id bcm203x_table[] = {
> > /* Broadcom Blutonium (BCM2033) */
> > { USB_DEVICE(0x0a5c, 0x2033) },
> >
> > So there is a working example of this already in the kernel tree since
> > forever.
>
> Nice, thanks for the pointer. Our team will review and try to address
> an alternative patch.
>
> Now for my own sanity -- I still don't think I get this how this
> BCM2033 blacklist trick works, I take it the device once plugged in
> gets a generic btusb USB device vendor:device ID. The btusb driver
> then picks up the the blacklist table, and searches for a
> usb_match_id() on it for the given interface... What I don't get is
> how there will be a match here if the USB vendor:device ID is just the
> generic btusb one. Can you help me understand how this trick works?
the generic Bluetooth USB class descriptors is what btusb uses. With a
few expectation for devices that use VID:PID combination.
So in general what happens if a device gets matched via the Bluetooth
USB class descriptors the btusb driver will claim. We do however check
against out blacklist first. If the VID:PID is listed in the blacklist
we do return ENODEV. That means that the USB subsystem goes ahead and
tries the next driver. In this case bcm203x driver. This will claim it,
load the firmware, reset it and come back with different VID:PID values.
After that the btusb can successfully claim it since it is no longer in
the blacklist.
If I understand this all correct without having the hardware available
for verifying this, then it should be like this:
Just add this to blacklist_table[] in btusb.c:
/* Atheros AR3011 without firmware */
{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
And then we can add the firmware loading to ath3k driver to load the
specific 1st stage firmware. And then ath3k can load the 2nd stage as
well. After that it should become a default Bluetooth USB device and the
btusb driver can take care of it.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH] Fix problem with invalid read from array
From: Lukasz Pawlik @ 2010-10-06 15:33 UTC (permalink / raw)
To: Lukasz Pawlik, linux-bluetooth
In-Reply-To: <20101006133206.GA8696@jh-x301>
Hi,
Sorry. My bad. It was never my intention to change src/adapter.c. I've
prepared two patches with the same name and of course send the wrong
one. Problem with invalid read fix change made in src/sdpd-service.c
file.
Lukasz
2010/10/6 Johan Hedberg <johan.hedberg@gmail.com>:
> Hi Lukasz,
>
> On Wed, Oct 06, 2010, Lukasz Pawlik wrote:
>> This patch fix problem with reading data from out of the array range in
>> function used to create EIR response.
>
> You'll need to explain in more detail exactly what was wrong with the
> old code and how your patch fixes it (and why it is the correct fix).
>
>> - uint8_t data[240];
>> + uint8_t data[242];
>
> Why 242? The core spec defines the EIR data as a 240 byte field.
>
>> - uuid128_data[SIZEOF_UUID128 - k])
>> + uuid128_data[SIZEOF_UUID128 - 1 - k])
>
> This change looks fine (the index of the last byte is sizeof(uuid128) - 1).
>
> Johan
>
^ permalink raw reply
* Re: RFC: btusb firmware load help
From: Luis R. Rodriguez @ 2010-10-06 15:26 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Luis Rodriguez, linux-bluetooth, linux-kernel@vger.kernel.org,
linux-wireless@vger.kernel.org, Deepak Dhamdhere, Sree Durbha
In-Reply-To: <1286349552.6145.11.camel@aeonflux>
On Wed, Oct 6, 2010 at 12:19 AM, Marcel Holtmann
<holtmann@linux.intel.com> wrote:
> Hi Luis,
>
>> > most likely via a separate firmware loading driver.
>>
>> Like the fwload patch ? Or something different?
>
> something clean of course and not this hacking around, but in general
> along that.
>
>> > Your ath3k driver is such a driver. Same as the bcm203x driver.
>>
>> Right -- so ath3k depends on some atheros USB device IDs, and its a
>> stupid driver that just loads firmware. The problem with this new
>> device is that it requires two phases. One to load some sort of
>> firmware onto it to get it to read as an ath3k device, and then ath3k
>> will load the right firmware to it. So the hardware device is already
>> claiming a btusb vendor:device ID, we can't change that I believe. Of
>> course for future devices we can, and we've addressed this and its
>> been fixed.
>
> So your current loading procedure is this:
>
> 1) btusb with hacked firmware loading
> 2) ath3k
> 3) btusb with HCI
Not sure of the 3rd part as I do not know what the ath3k firmware
does. I am not sure if by loading the ath3k firmware it then
redeclares itself as a btusb device. Also upon further review I just
noticed the fwload hack used ath3k-1.fw and not ath3k-2.fw. A patch
submitted ages ago to you added ath3k-2.fw upstream but that patch
never made it through upstream, so now I wonder if the fwload crap
thing should be using ath3k-2.fw as well. Anyway, I am also not sure
why after loading the firmware from btusb a second load using ath3k
driver would be needed.
> Who thought that this is a good idea in the first place?
Not sure, this was the way the hardware was designed, it just so
happens there seems to be no generic btusb module equivalent on
Windows or Mac OS X so they have full control over how this is handled
there and apparently in Windows and Mac OS X you can get away with
murder on crap code on drivers, so long as shit works. My
understanding is that the stuff implemented was just some workarounds
to get this to work on Linux. Due to our higher requirement on code
quality, and though process I recommend device drivers get written for
Linux first, perhaps a lesson will be learned here to try to do this
moving forward.
> And more important that I would accept this upstream? This is even worse than I
> thought it is.
Heh, I don't think anyone knew any better. Your suggestions of how to
handle this properly in a way that is agreeable to you is what we were
looking for.
> Please get this craziness fixed.
Without proper feedback the team was not sure what to do, the feedback
I read they got was what they were doing was was crazy but I also saw
no alternative method suggested. It took us a while (this thread) to
get alternatives suggested, but I appreciate them.
>> > They don't do anything than claiming that USB device, loading the firmware, and then let it reset.
>>
>> Right but if the SFLASH configurations hardware is already shipping
>> and without firmware is claiming to be a BT USB device which matches
>> the USB vendor:device ID of the btusb driver. Unfortunately it does
>> not accept HCI commands which as you indicates breaks some
>> specification. We can and have fixed this in future chipsets but this
>> one cannot be addressed. So what do we do?
>>
>> > And after the reset the btusb can claim the one where the firmware has
>> > been loaded and which behaves like a proper USB dongle.
>>
>> Right, that's what the fwload patch from our BT team does, no?
>
> Yes, but not inside the btusb driver. Stop hacking a generic driver with
> crazy firmware loading only because the USB Bluetooth class descriptors
> got screwed up in the first place.
Thanks for the pointers on this, I believe our team was not familiar
about these specification violations, they could have learned of the
violations through the old threads with you or through other means,
either way they have been addressed for future hardware it seems. So
while new hardware is fixed we still need to address this old hardware
situation. I'll be honest, our team actually gave up completely on
supporting the older hardware upstream on the Linux kernel as they
were under the impression there was no way to support the device in an
acceptable way by you. Our team should have nagged for alternatives
back then but it would have been easier if these would have come from
you instead of a simple NACK of the patch and indicating their
strategy to resolve this was loony.
>> > The part that I don't understand is that you have the ath3k driver doing
>> > it exactly how it should be done, why now started to make nasty hacks in
>> > the btusb driver.
>>
>> Yeah that seems to have been a shortcoming, its something you should
>> expect from us moving forward. I've been told AR3012 and future
>> Atheros chipsets will not have behave this way, and this issue is only
>> present for the AR3011 devices with SFLASH configuration.
>
> Most likely including the flashing into ath3k firmware loading driver
> and that being called bound twice might be a good idea.
Wouldn't ath3k have to claim the generic btusb device IDs for this to work?
> However we are not doing the firmware loading in btusb. Then a patch to blacklist this
> broken device. And then ensure that the firmware changes the USB PIDs
> after success.
>
> And if I understand you correct, then it does this anyway right now
> already. Otherwise the ath3k driver would not bind to it.
Right, I'm under the impression btusb will load, upload the ath3k-1.fw
to the device, then it re-enumerates itself to match the ath3k USB
vendor:device ID, then ath3k will once again load ath3k-1.fw. Not sure
what happens after that as that is all the code I see and am familiar
with. I'll remind you I am not a Bluetooth developer but an 802.11
developer dragged into this as no traction was being made and we need
to start supporting customers on Linux with this, so please bare with
me if I'm off on the BT stuff.
> Now I am failing to understand why this was done wrong in the first
> place. Especially if the loading procedure happens as you say it
> happens.
You got me :) Anyone?
> This is the example for the Broadcom 203x devices:
>
> static struct usb_device_id blacklist_table[] = {
> /* Broadcom BCM2033 without firmware */
> { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
>
> The btusb driver clearly blacklists them. And then bcm203x can take over
> loading the firmware:
>
> static const struct usb_device_id bcm203x_table[] = {
> /* Broadcom Blutonium (BCM2033) */
> { USB_DEVICE(0x0a5c, 0x2033) },
>
> So there is a working example of this already in the kernel tree since
> forever.
Nice, thanks for the pointer. Our team will review and try to address
an alternative patch.
Now for my own sanity -- I still don't think I get this how this
BCM2033 blacklist trick works, I take it the device once plugged in
gets a generic btusb USB device vendor:device ID. The btusb driver
then picks up the the blacklist table, and searches for a
usb_match_id() on it for the given interface... What I don't get is
how there will be a match here if the USB vendor:device ID is just the
generic btusb one. Can you help me understand how this trick works?
Luis
^ permalink raw reply
* Re: [PATCH] Fix problem with invalid read from array
From: Johan Hedberg @ 2010-10-06 13:32 UTC (permalink / raw)
To: Lukasz Pawlik; +Cc: linux-bluetooth
In-Reply-To: <1286369566-1453-1-git-send-email-lucas.pawlik@gmail.com>
Hi Lukasz,
On Wed, Oct 06, 2010, Lukasz Pawlik wrote:
> This patch fix problem with reading data from out of the array range in
> function used to create EIR response.
You'll need to explain in more detail exactly what was wrong with the
old code and how your patch fixes it (and why it is the correct fix).
> - uint8_t data[240];
> + uint8_t data[242];
Why 242? The core spec defines the EIR data as a 240 byte field.
> - uuid128_data[SIZEOF_UUID128 - k])
> + uuid128_data[SIZEOF_UUID128 - 1 - k])
This change looks fine (the index of the last byte is sizeof(uuid128) - 1).
Johan
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox