[Bluetooth] Track connection packet type changes

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Linux Kernel Mailing List
Date: Sunday, July 20, 2008 - 7:57 pm

Gitweb:     http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=a87464...
Commit:     a8746417e864da1ed36dd2432a399fbeb843c2a0
Parent:     9dc0a3afc08d6c20c284994dcd84531787d00ec2
Author:     Marcel Holtmann <marcel@holtmann.org>
AuthorDate: Mon Jul 14 20:13:46 2008 +0200
Committer:  Marcel Holtmann <marcel@holtmann.org>
CommitDate: Mon Jul 14 20:13:46 2008 +0200

    [Bluetooth] Track connection packet type changes
    
    The connection packet type can be changed after the connection has been
    established and thus needs to be properly tracked to ensure that the
    host stack has always correct and valid information about it.
    
    On incoming connections the Bluetooth core switches the supported packet
    types to the configured list for this controller. However the usefulness
    of this feature has been questioned a lot. The general consent is that
    every Bluetooth host stack should enable as many packet types as the
    hardware actually supports and leave the decision to the link manager
    software running on the Bluetooth chip.
    
    When running on Bluetooth 2.0 or later hardware, don't change the packet
    type for incoming connections anymore. This hardware likely supports
    Enhanced Data Rate and thus leave it completely up to the link manager
    to pick the best packet type.
    
    Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/hci.h      |    9 +++++++++
 include/net/bluetooth/hci_core.h |    1 +
 net/bluetooth/hci_conn.c         |   32 ++++++++++++++++++++++++--------
 net/bluetooth/hci_event.c        |   32 +++++++++++++++++++++++++-------
 4 files changed, 59 insertions(+), 15 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index a8a9eb6..f1dc174 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -137,6 +137,8 @@ enum {
 #define ESCO_EV4	0x0010
 #define ESCO_EV5	0x0020
 
+#define SCO_ESCO_MASK  (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)
+
 /* ACL flags */
 #define ACL_CONT		0x01
 #define ACL_START		0x02
@@ -696,6 +698,13 @@ struct hci_ev_clock_offset {
 	__le16   clock_offset;
 } __attribute__ ((packed));
 
+#define HCI_EV_PKT_TYPE_CHANGE		0x1d
+struct hci_ev_pkt_type_change {
+	__u8     status;
+	__le16   handle;
+	__le16   pkt_type;
+} __attribute__ ((packed));
+
 #define HCI_EV_PSCAN_REP_MODE		0x20
 struct hci_ev_pscan_rep_mode {
 	bdaddr_t bdaddr;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index c8255ad..6424d63 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -162,6 +162,7 @@ struct hci_conn {
 	__u8		 dev_class[3];
 	__u8             features[8];
 	__u16            interval;
+	__u16            pkt_type;
 	__u16            link_policy;
 	__u32		 link_mode;
 	__u8             power_save;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index f888026..69c64ce 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -59,7 +59,8 @@ void hci_acl_connect(struct hci_conn *conn)
 	BT_DBG("%p", conn);
 
 	conn->state = BT_CONNECT;
-	conn->out   = 1;
+	conn->out = 1;
+
 	conn->link_mode = HCI_LM_MASTER;
 
 	conn->attempt++;
@@ -76,7 +77,7 @@ void hci_acl_connect(struct hci_conn *conn)
 		memcpy(conn->dev_class, ie->data.dev_class, 3);
 	}
 
-	cp.pkt_type = cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
+	cp.pkt_type = cpu_to_le16(conn->pkt_type);
 	if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
 		cp.role_switch = 0x01;
 	else
@@ -122,7 +123,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
 	conn->out = 1;
 
 	cp.handle   = cpu_to_le16(handle);
-	cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
+	cp.pkt_type = cpu_to_le16(conn->pkt_type);
 
 	hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
 }
@@ -138,7 +139,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
 	conn->out = 1;
 
 	cp.handle   = cpu_to_le16(handle);
-	cp.pkt_type = cpu_to_le16(hdev->esco_type);
+	cp.pkt_type = cpu_to_le16(conn->pkt_type);
 
 	cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
 	cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
@@ -199,13 +200,28 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 		return NULL;
 
 	bacpy(&conn->dst, dst);
-	conn->hdev   = hdev;
-	conn->type   = type;
-	conn->mode   = HCI_CM_ACTIVE;
-	conn->state  = BT_OPEN;
+	conn->hdev  = hdev;
+	conn->type  = type;
+	conn->mode  = HCI_CM_ACTIVE;
+	conn->state = BT_OPEN;
 
 	conn->power_save = 1;
 
+	switch (type) {
+	case ACL_LINK:
+		conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
+		break;
+	case SCO_LINK:
+		if (lmp_esco_capable(hdev))
+			conn->pkt_type = hdev->esco_type & SCO_ESCO_MASK;
+		else
+			conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
+		break;
+	case ESCO_LINK:
+		conn->pkt_type = hdev->esco_type;
+		break;
+	}
+
 	skb_queue_head_init(&conn->data_q);
 
 	setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 6bc5a05..d4d2dcc 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -699,14 +699,12 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 		}
 
 		/* Set packet type for incoming connection */
-		if (!conn->out) {
+		if (!conn->out && hdev->hci_ver < 3) {
 			struct hci_cp_change_conn_ptype cp;
 			cp.handle = ev->handle;
-			cp.pkt_type = (conn->type == ACL_LINK) ?
-				cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
-				cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
-
-			hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
+			cp.pkt_type = cpu_to_le16(conn->pkt_type);
+			hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE,
+							sizeof(cp), &cp);
 		} else {
 			/* Update disconnect timer */
 			hci_conn_hold(conn);
@@ -786,7 +784,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 			struct hci_cp_accept_sync_conn_req cp;
 
 			bacpy(&cp.bdaddr, &ev->bdaddr);
-			cp.pkt_type = cpu_to_le16(hdev->esco_type);
+			cp.pkt_type = cpu_to_le16(conn->pkt_type);
 
 			cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
 			cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
@@ -1237,6 +1235,22 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
 	hci_dev_unlock(hdev);
 }
 
+static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_pkt_type_change *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_handle(hdev, __le16_to_cpu(ev->handle));
+	if (conn && !ev->status)
+		conn->pkt_type = __le16_to_cpu(ev->pkt_type);
+
+	hci_dev_unlock(hdev);
+}
+
 static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
@@ -1480,6 +1494,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_clock_offset_evt(hdev, skb);
 		break;
 
+	case HCI_EV_PKT_TYPE_CHANGE:
+		hci_pkt_type_change_evt(hdev, skb);
+		break;
+
 	case HCI_EV_PSCAN_REP_MODE:
 		hci_pscan_rep_mode_evt(hdev, skb);
 		break;
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[Bluetooth] Track connection packet type changes, Linux Kernel Mailing ..., (Sun Jul 20, 7:57 pm)