From a9de9248064bfc8eb0a183a6a951a4e7b5ca10a4 Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 13:33:56 +0200
Subject: [PATCH 01/30] [Bluetooth] Switch from OGF+OCF to using only opcodes

The Bluetooth HCI commands are divided into logical OGF groups for
easier identification of their purposes. While this still makes sense
for the written specification, its makes the code only more complex
and harder to read. So instead of using separate OGF and OCF values
to identify the commands, use a common 16-bit opcode that combines
both values. As a side effect this also reduces the complexity of
OGF and OCF calculations during command header parsing.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 drivers/bluetooth/hci_bcsp.c     |    3 +-
 include/net/bluetooth/hci.h      |  884 +++++++-------
 include/net/bluetooth/hci_core.h |   12 +-
 net/bluetooth/hci_conn.c         |   43 +-
 net/bluetooth/hci_core.c         |   48 +-
 net/bluetooth/hci_event.c        | 1866 ++++++++++++++++--------------
 net/bluetooth/hci_sock.c         |    2 +-
 net/bluetooth/hci_sysfs.c        |   37 +
 8 files changed, 1589 insertions(+), 1306 deletions(-)

diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index d66064ccb31c..696f7528f022 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -237,7 +237,8 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
 	if (hciextn && chan == 5) {
 		struct hci_command_hdr *hdr = (struct hci_command_hdr *) data;
 
-		if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == OGF_VENDOR_CMD) {
+		/* Vendor specific commands */
+		if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == 0x3f) {
 			u8 desc = *(data + HCI_COMMAND_HDR_SIZE);
 			if ((desc & 0xf0) == 0xc0) {
 				data += HCI_COMMAND_HDR_SIZE + 1;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index ebfb96b41106..a8a9eb6af966 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -200,65 +200,224 @@ enum {
 #define HCI_LM_SECURE	0x0020
 
 /* -----  HCI Commands ---- */
-/* OGF & OCF values */
-
-/* Informational Parameters */
-#define OGF_INFO_PARAM	0x04
-
-#define OCF_READ_LOCAL_VERSION	0x0001
-struct hci_rp_read_loc_version {
-	__u8     status;
-	__u8     hci_ver;
-	__le16   hci_rev;
-	__u8     lmp_ver;
-	__le16   manufacturer;
-	__le16   lmp_subver;
+#define HCI_OP_INQUIRY			0x0401
+struct hci_cp_inquiry {
+	__u8     lap[3];
+	__u8     length;
+	__u8     num_rsp;
 } __attribute__ ((packed));
 
-#define OCF_READ_LOCAL_FEATURES	0x0003
-struct hci_rp_read_local_features {
-	__u8 status;
-	__u8 features[8];
+#define HCI_OP_INQUIRY_CANCEL		0x0402
+
+#define HCI_OP_EXIT_PERIODIC_INQ	0x0404
+
+#define HCI_OP_CREATE_CONN		0x0405
+struct hci_cp_create_conn {
+	bdaddr_t bdaddr;
+	__le16   pkt_type;
+	__u8     pscan_rep_mode;
+	__u8     pscan_mode;
+	__le16   clock_offset;
+	__u8     role_switch;
 } __attribute__ ((packed));
 
-#define OCF_READ_BUFFER_SIZE	0x0005
-struct hci_rp_read_buffer_size {
-	__u8     status;
-	__le16   acl_mtu;
-	__u8     sco_mtu;
-	__le16   acl_max_pkt;
-	__le16   sco_max_pkt;
+#define HCI_OP_DISCONNECT		0x0406
+struct hci_cp_disconnect {
+	__le16   handle;
+	__u8     reason;
 } __attribute__ ((packed));
 
-#define OCF_READ_BD_ADDR	0x0009
-struct hci_rp_read_bd_addr {
-	__u8     status;
+#define HCI_OP_ADD_SCO			0x0407
+struct hci_cp_add_sco {
+	__le16   handle;
+	__le16   pkt_type;
+} __attribute__ ((packed));
+
+#define HCI_OP_CREATE_CONN_CANCEL	0x0408
+struct hci_cp_create_conn_cancel {
 	bdaddr_t bdaddr;
 } __attribute__ ((packed));
 
-/* Host Controller and Baseband */
-#define OGF_HOST_CTL	0x03
-#define OCF_RESET		0x0003
-#define OCF_READ_AUTH_ENABLE	0x001F
-#define OCF_WRITE_AUTH_ENABLE	0x0020
-	#define AUTH_DISABLED		0x00
-	#define AUTH_ENABLED		0x01
+#define HCI_OP_ACCEPT_CONN_REQ		0x0409
+struct hci_cp_accept_conn_req {
+	bdaddr_t bdaddr;
+	__u8     role;
+} __attribute__ ((packed));
 
-#define OCF_READ_ENCRYPT_MODE	0x0021
-#define OCF_WRITE_ENCRYPT_MODE	0x0022
-	#define ENCRYPT_DISABLED	0x00
-	#define ENCRYPT_P2P		0x01
-	#define ENCRYPT_BOTH		0x02
+#define HCI_OP_REJECT_CONN_REQ		0x040a
+struct hci_cp_reject_conn_req {
+	bdaddr_t bdaddr;
+	__u8     reason;
+} __attribute__ ((packed));
 
-#define OCF_WRITE_CA_TIMEOUT  	0x0016	
-#define OCF_WRITE_PG_TIMEOUT  	0x0018
+#define HCI_OP_LINK_KEY_REPLY		0x040b
+struct hci_cp_link_key_reply {
+	bdaddr_t bdaddr;
+	__u8     link_key[16];
+} __attribute__ ((packed));
 
-#define OCF_WRITE_SCAN_ENABLE 	0x001A
-	#define SCAN_DISABLED		0x00
-	#define SCAN_INQUIRY		0x01
-	#define SCAN_PAGE		0x02
+#define HCI_OP_LINK_KEY_NEG_REPLY	0x040c
+struct hci_cp_link_key_neg_reply {
+	bdaddr_t bdaddr;
+} __attribute__ ((packed));
 
-#define OCF_SET_EVENT_FLT	0x0005
+#define HCI_OP_PIN_CODE_REPLY		0x040d
+struct hci_cp_pin_code_reply {
+	bdaddr_t bdaddr;
+	__u8     pin_len;
+	__u8     pin_code[16];
+} __attribute__ ((packed));
+
+#define HCI_OP_PIN_CODE_NEG_REPLY	0x040e
+struct hci_cp_pin_code_neg_reply {
+	bdaddr_t bdaddr;
+} __attribute__ ((packed));
+
+#define HCI_OP_CHANGE_CONN_PTYPE	0x040f
+struct hci_cp_change_conn_ptype {
+	__le16   handle;
+	__le16   pkt_type;
+} __attribute__ ((packed));
+
+#define HCI_OP_AUTH_REQUESTED		0x0411
+struct hci_cp_auth_requested {
+	__le16   handle;
+} __attribute__ ((packed));
+
+#define HCI_OP_SET_CONN_ENCRYPT		0x0413
+struct hci_cp_set_conn_encrypt {
+	__le16   handle;
+	__u8     encrypt;
+} __attribute__ ((packed));
+
+#define HCI_OP_CHANGE_CONN_LINK_KEY	0x0415
+struct hci_cp_change_conn_link_key {
+	__le16   handle;
+} __attribute__ ((packed));
+
+#define HCI_OP_REMOTE_NAME_REQ		0x0419
+struct hci_cp_remote_name_req {
+	bdaddr_t bdaddr;
+	__u8     pscan_rep_mode;
+	__u8     pscan_mode;
+	__le16   clock_offset;
+} __attribute__ ((packed));
+
+#define HCI_OP_REMOTE_NAME_REQ_CANCEL	0x041a
+struct hci_cp_remote_name_req_cancel {
+	bdaddr_t bdaddr;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_REMOTE_FEATURES	0x041b
+struct hci_cp_read_remote_features {
+	__le16   handle;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_REMOTE_EXT_FEATURES	0x041c
+struct hci_cp_read_remote_ext_features {
+	__le16   handle;
+	__u8     page;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_REMOTE_VERSION	0x041d
+struct hci_cp_read_remote_version {
+	__le16   handle;
+} __attribute__ ((packed));
+
+#define HCI_OP_SETUP_SYNC_CONN		0x0428
+struct hci_cp_setup_sync_conn {
+	__le16   handle;
+	__le32   tx_bandwidth;
+	__le32   rx_bandwidth;
+	__le16   max_latency;
+	__le16   voice_setting;
+	__u8     retrans_effort;
+	__le16   pkt_type;
+} __attribute__ ((packed));
+
+#define HCI_OP_ACCEPT_SYNC_CONN_REQ	0x0429
+struct hci_cp_accept_sync_conn_req {
+	bdaddr_t bdaddr;
+	__le32   tx_bandwidth;
+	__le32   rx_bandwidth;
+	__le16   max_latency;
+	__le16   content_format;
+	__u8     retrans_effort;
+	__le16   pkt_type;
+} __attribute__ ((packed));
+
+#define HCI_OP_REJECT_SYNC_CONN_REQ	0x042a
+struct hci_cp_reject_sync_conn_req {
+	bdaddr_t bdaddr;
+	__u8     reason;
+} __attribute__ ((packed));
+
+#define HCI_OP_SNIFF_MODE		0x0803
+struct hci_cp_sniff_mode {
+	__le16   handle;
+	__le16   max_interval;
+	__le16   min_interval;
+	__le16   attempt;
+	__le16   timeout;
+} __attribute__ ((packed));
+
+#define HCI_OP_EXIT_SNIFF_MODE		0x0804
+struct hci_cp_exit_sniff_mode {
+	__le16   handle;
+} __attribute__ ((packed));
+
+#define HCI_OP_ROLE_DISCOVERY		0x0809
+struct hci_cp_role_discovery {
+	__le16   handle;
+} __attribute__ ((packed));
+struct hci_rp_role_discovery {
+	__u8     status;
+	__le16   handle;
+	__u8     role;
+} __attribute__ ((packed));
+
+#define HCI_OP_SWITCH_ROLE		0x080b
+struct hci_cp_switch_role {
+	bdaddr_t bdaddr;
+	__u8     role;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LINK_POLICY		0x080c
+struct hci_cp_read_link_policy {
+	__le16   handle;
+} __attribute__ ((packed));
+struct hci_rp_read_link_policy {
+	__u8     status;
+	__le16   handle;
+	__le16   policy;
+} __attribute__ ((packed));
+
+#define HCI_OP_WRITE_LINK_POLICY	0x080d
+struct hci_cp_write_link_policy {
+	__le16   handle;
+	__le16   policy;
+} __attribute__ ((packed));
+struct hci_rp_write_link_policy {
+	__u8     status;
+	__le16   handle;
+} __attribute__ ((packed));
+
+#define HCI_OP_SNIFF_SUBRATE		0x0811
+struct hci_cp_sniff_subrate {
+	__le16   handle;
+	__le16   max_latency;
+	__le16   min_remote_timeout;
+	__le16   min_local_timeout;
+} __attribute__ ((packed));
+
+#define HCI_OP_SET_EVENT_MASK		0x0c01
+struct hci_cp_set_event_mask {
+	__u8     mask[8];
+} __attribute__ ((packed));
+
+#define HCI_OP_RESET			0x0c03
+
+#define HCI_OP_SET_EVENT_FLT		0x0c05
 struct hci_cp_set_event_flt {
 	__u8     flt_type;
 	__u8     cond_type;
@@ -279,29 +438,62 @@ struct hci_cp_set_event_flt {
 #define HCI_CONN_SETUP_AUTO_OFF	0x01
 #define HCI_CONN_SETUP_AUTO_ON	0x02
 
-#define OCF_READ_CLASS_OF_DEV	0x0023
-struct hci_rp_read_dev_class {
+#define HCI_OP_WRITE_LOCAL_NAME		0x0c13
+struct hci_cp_write_local_name {
+	__u8     name[248];
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LOCAL_NAME		0x0c14
+struct hci_rp_read_local_name {
+	__u8     status;
+	__u8     name[248];
+} __attribute__ ((packed));
+
+#define HCI_OP_WRITE_CA_TIMEOUT		0x0c16
+
+#define HCI_OP_WRITE_PG_TIMEOUT		0x0c18
+
+#define HCI_OP_WRITE_SCAN_ENABLE 	0x0c1a
+	#define SCAN_DISABLED		0x00
+	#define SCAN_INQUIRY		0x01
+	#define SCAN_PAGE		0x02
+
+#define HCI_OP_READ_AUTH_ENABLE		0x0c1f
+
+#define HCI_OP_WRITE_AUTH_ENABLE	0x0c20
+	#define AUTH_DISABLED		0x00
+	#define AUTH_ENABLED		0x01
+
+#define HCI_OP_READ_ENCRYPT_MODE	0x0c21
+
+#define HCI_OP_WRITE_ENCRYPT_MODE	0x0c22
+	#define ENCRYPT_DISABLED	0x00
+	#define ENCRYPT_P2P		0x01
+	#define ENCRYPT_BOTH		0x02
+
+#define HCI_OP_READ_CLASS_OF_DEV	0x0c23
+struct hci_rp_read_class_of_dev {
 	__u8     status;
 	__u8     dev_class[3];
 } __attribute__ ((packed));
 
-#define OCF_WRITE_CLASS_OF_DEV	0x0024
-struct hci_cp_write_dev_class {
+#define HCI_OP_WRITE_CLASS_OF_DEV	0x0c24
+struct hci_cp_write_class_of_dev {
 	__u8     dev_class[3];
 } __attribute__ ((packed));
 
-#define OCF_READ_VOICE_SETTING	0x0025
+#define HCI_OP_READ_VOICE_SETTING	0x0c25
 struct hci_rp_read_voice_setting {
 	__u8     status;
 	__le16   voice_setting;
 } __attribute__ ((packed));
 
-#define OCF_WRITE_VOICE_SETTING	0x0026
+#define HCI_OP_WRITE_VOICE_SETTING	0x0c26
 struct hci_cp_write_voice_setting {
 	__le16   voice_setting;
 } __attribute__ ((packed));
 
-#define OCF_HOST_BUFFER_SIZE	0x0033
+#define HCI_OP_HOST_BUFFER_SIZE		0x0c33
 struct hci_cp_host_buffer_size {
 	__le16   acl_mtu;
 	__u8     sco_mtu;
@@ -309,188 +501,55 @@ struct hci_cp_host_buffer_size {
 	__le16   sco_max_pkt;
 } __attribute__ ((packed));
 
-/* Link Control */
-#define OGF_LINK_CTL	0x01 
-
-#define OCF_CREATE_CONN		0x0005
-struct hci_cp_create_conn {
-	bdaddr_t bdaddr;
-	__le16   pkt_type;
-	__u8     pscan_rep_mode;
-	__u8     pscan_mode;
-	__le16   clock_offset;
-	__u8     role_switch;
-} __attribute__ ((packed));
-
-#define OCF_CREATE_CONN_CANCEL	0x0008
-struct hci_cp_create_conn_cancel {
-	bdaddr_t bdaddr;
-} __attribute__ ((packed));
-
-#define OCF_ACCEPT_CONN_REQ	0x0009
-struct hci_cp_accept_conn_req {
-	bdaddr_t bdaddr;
-	__u8     role;
-} __attribute__ ((packed));
-
-#define OCF_REJECT_CONN_REQ	0x000a
-struct hci_cp_reject_conn_req {
-	bdaddr_t bdaddr;
-	__u8     reason;
-} __attribute__ ((packed));
-
-#define OCF_DISCONNECT	0x0006
-struct hci_cp_disconnect {
-	__le16   handle;
-	__u8     reason;
-} __attribute__ ((packed));
-
-#define OCF_ADD_SCO	0x0007
-struct hci_cp_add_sco {
-	__le16   handle;
-	__le16   pkt_type;
-} __attribute__ ((packed));
-
-#define OCF_INQUIRY		0x0001
-struct hci_cp_inquiry {
-	__u8     lap[3];
-	__u8     length;
-	__u8     num_rsp;
-} __attribute__ ((packed));
-
-#define OCF_INQUIRY_CANCEL	0x0002
-
-#define OCF_EXIT_PERIODIC_INQ	0x0004
-
-#define OCF_LINK_KEY_REPLY	0x000B
-struct hci_cp_link_key_reply {
-	bdaddr_t bdaddr;
-	__u8     link_key[16];
-} __attribute__ ((packed));
-
-#define OCF_LINK_KEY_NEG_REPLY	0x000C
-struct hci_cp_link_key_neg_reply {
-	bdaddr_t bdaddr;
-} __attribute__ ((packed));
-
-#define OCF_PIN_CODE_REPLY	0x000D
-struct hci_cp_pin_code_reply {
-	bdaddr_t bdaddr;
-	__u8     pin_len;
-	__u8     pin_code[16];
-} __attribute__ ((packed));
-
-#define OCF_PIN_CODE_NEG_REPLY	0x000E
-struct hci_cp_pin_code_neg_reply {
-	bdaddr_t bdaddr;
-} __attribute__ ((packed));
-
-#define OCF_CHANGE_CONN_PTYPE	0x000F
-struct hci_cp_change_conn_ptype {
-	__le16   handle;
-	__le16   pkt_type;
-} __attribute__ ((packed));
-
-#define OCF_AUTH_REQUESTED	0x0011
-struct hci_cp_auth_requested {
-	__le16   handle;
-} __attribute__ ((packed));
-
-#define OCF_SET_CONN_ENCRYPT	0x0013
-struct hci_cp_set_conn_encrypt {
-	__le16   handle;
-	__u8     encrypt;
-} __attribute__ ((packed));
-
-#define OCF_CHANGE_CONN_LINK_KEY 0x0015
-struct hci_cp_change_conn_link_key {
-	__le16   handle;
-} __attribute__ ((packed));
-
-#define OCF_READ_REMOTE_FEATURES 0x001B
-struct hci_cp_read_remote_features {
-	__le16   handle;
-} __attribute__ ((packed));
-
-#define OCF_READ_REMOTE_VERSION 0x001D
-struct hci_cp_read_remote_version {
-	__le16   handle;
-} __attribute__ ((packed));
-
-/* Link Policy */
-#define OGF_LINK_POLICY	0x02   
-
-#define OCF_SNIFF_MODE		0x0003
-struct hci_cp_sniff_mode {
-	__le16   handle;
-	__le16   max_interval;
-	__le16   min_interval;
-	__le16   attempt;
-	__le16   timeout;
-} __attribute__ ((packed));
-
-#define OCF_EXIT_SNIFF_MODE	0x0004
-struct hci_cp_exit_sniff_mode {
-	__le16   handle;
-} __attribute__ ((packed));
-
-#define OCF_ROLE_DISCOVERY	0x0009
-struct hci_cp_role_discovery {
-	__le16   handle;
-} __attribute__ ((packed));
-struct hci_rp_role_discovery {
+#define HCI_OP_READ_LOCAL_VERSION	0x1001
+struct hci_rp_read_local_version {
 	__u8     status;
-	__le16   handle;
-	__u8     role;
+	__u8     hci_ver;
+	__le16   hci_rev;
+	__u8     lmp_ver;
+	__le16   manufacturer;
+	__le16   lmp_subver;
 } __attribute__ ((packed));
 
-#define OCF_READ_LINK_POLICY	0x000C
-struct hci_cp_read_link_policy {
-	__le16   handle;
-} __attribute__ ((packed));
-struct hci_rp_read_link_policy {
+#define HCI_OP_READ_LOCAL_COMMANDS	0x1002
+struct hci_rp_read_local_commands {
 	__u8     status;
-	__le16   handle;
-	__le16   policy;
+	__u8     commands[64];
 } __attribute__ ((packed));
 
-#define OCF_SWITCH_ROLE		0x000B
-struct hci_cp_switch_role {
+#define HCI_OP_READ_LOCAL_FEATURES	0x1003
+struct hci_rp_read_local_features {
+	__u8     status;
+	__u8     features[8];
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LOCAL_EXT_FEATURES	0x1004
+struct hci_rp_read_local_ext_features {
+	__u8     status;
+	__u8     page;
+	__u8     max_page;
+	__u8     features[8];
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_BUFFER_SIZE		0x1005
+struct hci_rp_read_buffer_size {
+	__u8     status;
+	__le16   acl_mtu;
+	__u8     sco_mtu;
+	__le16   acl_max_pkt;
+	__le16   sco_max_pkt;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_BD_ADDR		0x1009
+struct hci_rp_read_bd_addr {
+	__u8     status;
 	bdaddr_t bdaddr;
-	__u8     role;
 } __attribute__ ((packed));
 
-#define OCF_WRITE_LINK_POLICY	0x000D
-struct hci_cp_write_link_policy {
-	__le16   handle;
-	__le16   policy;
-} __attribute__ ((packed));
-struct hci_rp_write_link_policy {
-	__u8     status;
-	__le16   handle;
-} __attribute__ ((packed));
-
-#define OCF_SNIFF_SUBRATE	0x0011
-struct hci_cp_sniff_subrate {
-	__le16   handle;
-	__le16   max_latency;
-	__le16   min_remote_timeout;
-	__le16   min_local_timeout;
-} __attribute__ ((packed));
-
-/* Status params */
-#define OGF_STATUS_PARAM	0x05
-
-/* Testing commands */
-#define OGF_TESTING_CMD		0x3E
-
-/* Vendor specific commands */
-#define OGF_VENDOR_CMD		0x3F
-
 /* ---- HCI Events ---- */
-#define HCI_EV_INQUIRY_COMPLETE	0x01
+#define HCI_EV_INQUIRY_COMPLETE		0x01
 
-#define HCI_EV_INQUIRY_RESULT	0x02
+#define HCI_EV_INQUIRY_RESULT		0x02
 struct inquiry_info {
 	bdaddr_t bdaddr;
 	__u8     pscan_rep_mode;
@@ -500,6 +559,149 @@ struct inquiry_info {
 	__le16   clock_offset;
 } __attribute__ ((packed));
 
+#define HCI_EV_CONN_COMPLETE		0x03
+struct hci_ev_conn_complete {
+	__u8     status;
+	__le16   handle;
+	bdaddr_t bdaddr;
+	__u8     link_type;
+	__u8     encr_mode;
+} __attribute__ ((packed));
+
+#define HCI_EV_CONN_REQUEST		0x04
+struct hci_ev_conn_request {
+	bdaddr_t bdaddr;
+	__u8     dev_class[3];
+	__u8     link_type;
+} __attribute__ ((packed));
+
+#define HCI_EV_DISCONN_COMPLETE		0x05
+struct hci_ev_disconn_complete {
+	__u8     status;
+	__le16   handle;
+	__u8     reason;
+} __attribute__ ((packed));
+
+#define HCI_EV_AUTH_COMPLETE		0x06
+struct hci_ev_auth_complete {
+	__u8     status;
+	__le16   handle;
+} __attribute__ ((packed));
+
+#define HCI_EV_REMOTE_NAME		0x07
+struct hci_ev_remote_name {
+	__u8     status;
+	bdaddr_t bdaddr;
+	__u8     name[248];
+} __attribute__ ((packed));
+
+#define HCI_EV_ENCRYPT_CHANGE		0x08
+struct hci_ev_encrypt_change {
+	__u8     status;
+	__le16   handle;
+	__u8     encrypt;
+} __attribute__ ((packed));
+
+#define HCI_EV_CHANGE_LINK_KEY_COMPLETE	0x09
+struct hci_ev_change_link_key_complete {
+	__u8     status;
+	__le16   handle;
+} __attribute__ ((packed));
+
+#define HCI_EV_REMOTE_FEATURES		0x0b
+struct hci_ev_remote_features {
+	__u8     status;
+	__le16   handle;
+	__u8     features[8];
+} __attribute__ ((packed));
+
+#define HCI_EV_REMOTE_VERSION		0x0c
+struct hci_ev_remote_version {
+	__u8     status;
+	__le16   handle;
+	__u8     lmp_ver;
+	__le16   manufacturer;
+	__le16   lmp_subver;
+} __attribute__ ((packed));
+
+#define HCI_EV_QOS_SETUP_COMPLETE	0x0d
+struct hci_qos {
+	__u8     service_type;
+	__u32    token_rate;
+	__u32    peak_bandwidth;
+	__u32    latency;
+	__u32    delay_variation;
+} __attribute__ ((packed));
+struct hci_ev_qos_setup_complete {
+	__u8     status;
+	__le16   handle;
+	struct   hci_qos qos;
+} __attribute__ ((packed));
+
+#define HCI_EV_CMD_COMPLETE		0x0e
+struct hci_ev_cmd_complete {
+	__u8     ncmd;
+	__le16   opcode;
+} __attribute__ ((packed));
+
+#define HCI_EV_CMD_STATUS		0x0f
+struct hci_ev_cmd_status {
+	__u8     status;
+	__u8     ncmd;
+	__le16   opcode;
+} __attribute__ ((packed));
+
+#define HCI_EV_ROLE_CHANGE		0x12
+struct hci_ev_role_change {
+	__u8     status;
+	bdaddr_t bdaddr;
+	__u8     role;
+} __attribute__ ((packed));
+
+#define HCI_EV_NUM_COMP_PKTS		0x13
+struct hci_ev_num_comp_pkts {
+	__u8     num_hndl;
+	/* variable length part */
+} __attribute__ ((packed));
+
+#define HCI_EV_MODE_CHANGE		0x14
+struct hci_ev_mode_change {
+	__u8     status;
+	__le16   handle;
+	__u8     mode;
+	__le16   interval;
+} __attribute__ ((packed));
+
+#define HCI_EV_PIN_CODE_REQ		0x16
+struct hci_ev_pin_code_req {
+	bdaddr_t bdaddr;
+} __attribute__ ((packed));
+
+#define HCI_EV_LINK_KEY_REQ		0x17
+struct hci_ev_link_key_req {
+	bdaddr_t bdaddr;
+} __attribute__ ((packed));
+
+#define HCI_EV_LINK_KEY_NOTIFY		0x18
+struct hci_ev_link_key_notify {
+	bdaddr_t bdaddr;
+	__u8     link_key[16];
+	__u8     key_type;
+} __attribute__ ((packed));
+
+#define HCI_EV_CLOCK_OFFSET		0x1c
+struct hci_ev_clock_offset {
+	__u8     status;
+	__le16   handle;
+	__le16   clock_offset;
+} __attribute__ ((packed));
+
+#define HCI_EV_PSCAN_REP_MODE		0x20
+struct hci_ev_pscan_rep_mode {
+	bdaddr_t bdaddr;
+	__u8     pscan_rep_mode;
+} __attribute__ ((packed));
+
 #define HCI_EV_INQUIRY_RESULT_WITH_RSSI	0x22
 struct inquiry_info_with_rssi {
 	bdaddr_t bdaddr;
@@ -519,7 +721,49 @@ struct inquiry_info_with_rssi_and_pscan_mode {
 	__s8     rssi;
 } __attribute__ ((packed));
 
-#define HCI_EV_EXTENDED_INQUIRY_RESULT	0x2F
+#define HCI_EV_REMOTE_EXT_FEATURES	0x23
+struct hci_ev_remote_ext_features {
+	__u8     status;
+	__le16   handle;
+	__u8     page;
+	__u8     max_page;
+	__u8     features[8];
+} __attribute__ ((packed));
+
+#define HCI_EV_SYNC_CONN_COMPLETE	0x2c
+struct hci_ev_sync_conn_complete {
+	__u8     status;
+	__le16   handle;
+	bdaddr_t bdaddr;
+	__u8     link_type;
+	__u8     tx_interval;
+	__u8     retrans_window;
+	__le16   rx_pkt_len;
+	__le16   tx_pkt_len;
+	__u8     air_mode;
+} __attribute__ ((packed));
+
+#define HCI_EV_SYNC_CONN_CHANGED	0x2d
+struct hci_ev_sync_conn_changed {
+	__u8     status;
+	__le16   handle;
+	__u8     tx_interval;
+	__u8     retrans_window;
+	__le16   rx_pkt_len;
+	__le16   tx_pkt_len;
+} __attribute__ ((packed));
+
+#define HCI_EV_SNIFF_SUBRATE		0x2e
+struct hci_ev_sniff_subrate {
+	__u8     status;
+	__le16   handle;
+	__le16   max_tx_latency;
+	__le16   max_rx_latency;
+	__le16   max_remote_timeout;
+	__le16   max_local_timeout;
+} __attribute__ ((packed));
+
+#define HCI_EV_EXTENDED_INQUIRY_RESULT	0x2f
 struct extended_inquiry_info {
 	bdaddr_t bdaddr;
 	__u8     pscan_rep_mode;
@@ -530,160 +774,14 @@ struct extended_inquiry_info {
 	__u8     data[240];
 } __attribute__ ((packed));
 
-#define HCI_EV_CONN_COMPLETE 	0x03
-struct hci_ev_conn_complete {
-	__u8     status;
-	__le16   handle;
-	bdaddr_t bdaddr;
-	__u8     link_type;
-	__u8     encr_mode;
-} __attribute__ ((packed));
-
-#define HCI_EV_CONN_REQUEST	0x04
-struct hci_ev_conn_request {
-	bdaddr_t bdaddr;
-	__u8     dev_class[3];
-	__u8     link_type;
-} __attribute__ ((packed));
-
-#define HCI_EV_DISCONN_COMPLETE	0x05
-struct hci_ev_disconn_complete {
-	__u8     status;
-	__le16   handle;
-	__u8     reason;
-} __attribute__ ((packed));
-
-#define HCI_EV_AUTH_COMPLETE	0x06
-struct hci_ev_auth_complete {
-	__u8     status;
-	__le16   handle;
-} __attribute__ ((packed));
-
-#define HCI_EV_ENCRYPT_CHANGE	0x08
-struct hci_ev_encrypt_change {
-	__u8     status;
-	__le16   handle;
-	__u8     encrypt;
-} __attribute__ ((packed));
-
-#define HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE	0x09
-struct hci_ev_change_conn_link_key_complete {
-	__u8     status;
-	__le16   handle;
-} __attribute__ ((packed));
-
-#define HCI_EV_QOS_SETUP_COMPLETE	0x0D
-struct hci_qos {
-	__u8     service_type;
-	__u32    token_rate;
-	__u32    peak_bandwidth;
-	__u32    latency;
-	__u32    delay_variation;
-} __attribute__ ((packed));
-struct hci_ev_qos_setup_complete {
-	__u8     status;
-	__le16   handle;
-	struct   hci_qos qos;
-} __attribute__ ((packed));
-
-#define HCI_EV_CMD_COMPLETE 	0x0E
-struct hci_ev_cmd_complete {
-	__u8     ncmd;
-	__le16   opcode;
-} __attribute__ ((packed));
-
-#define HCI_EV_CMD_STATUS 	0x0F
-struct hci_ev_cmd_status {
-	__u8     status;
-	__u8     ncmd;
-	__le16   opcode;
-} __attribute__ ((packed));
-
-#define HCI_EV_NUM_COMP_PKTS	0x13
-struct hci_ev_num_comp_pkts {
-	__u8     num_hndl;
-	/* variable length part */
-} __attribute__ ((packed));
-
-#define HCI_EV_ROLE_CHANGE	0x12
-struct hci_ev_role_change {
-	__u8     status;
-	bdaddr_t bdaddr;
-	__u8     role;
-} __attribute__ ((packed));
-
-#define HCI_EV_MODE_CHANGE	0x14
-struct hci_ev_mode_change {
-	__u8     status;
-	__le16   handle;
-	__u8     mode;
-	__le16   interval;
-} __attribute__ ((packed));
-
-#define HCI_EV_PIN_CODE_REQ	0x16
-struct hci_ev_pin_code_req {
-	bdaddr_t bdaddr;
-} __attribute__ ((packed));
-
-#define HCI_EV_LINK_KEY_REQ	0x17
-struct hci_ev_link_key_req {
-	bdaddr_t bdaddr;
-} __attribute__ ((packed));
-
-#define HCI_EV_LINK_KEY_NOTIFY	0x18
-struct hci_ev_link_key_notify {
-	bdaddr_t bdaddr;
-	__u8	 link_key[16];
-	__u8	 key_type;
-} __attribute__ ((packed));
-
-#define HCI_EV_REMOTE_FEATURES	0x0B
-struct hci_ev_remote_features {
-	__u8     status;
-	__le16   handle;
-	__u8     features[8];
-} __attribute__ ((packed));
-
-#define HCI_EV_REMOTE_VERSION	0x0C
-struct hci_ev_remote_version {
-	__u8     status;
-	__le16   handle;
-	__u8     lmp_ver;
-	__le16   manufacturer;
-	__le16   lmp_subver;
-} __attribute__ ((packed));
-
-#define HCI_EV_CLOCK_OFFSET	0x01C
-struct hci_ev_clock_offset {
-	__u8     status;
-	__le16   handle;
-	__le16   clock_offset;
-} __attribute__ ((packed));
-
-#define HCI_EV_PSCAN_REP_MODE	0x20
-struct hci_ev_pscan_rep_mode {
-	bdaddr_t bdaddr;
-	__u8     pscan_rep_mode;
-} __attribute__ ((packed));
-
-#define HCI_EV_SNIFF_SUBRATE	0x2E
-struct hci_ev_sniff_subrate {
-	__u8     status;
-	__le16   handle;
-	__le16   max_tx_latency;
-	__le16   max_rx_latency;
-	__le16   max_remote_timeout;
-	__le16   max_local_timeout;
-} __attribute__ ((packed));
-
 /* Internal events generated by Bluetooth stack */
-#define HCI_EV_STACK_INTERNAL	0xFD
+#define HCI_EV_STACK_INTERNAL	0xfd
 struct hci_ev_stack_internal {
 	__u16    type;
 	__u8     data[0];
 } __attribute__ ((packed));
 
-#define HCI_EV_SI_DEVICE  	0x01
+#define HCI_EV_SI_DEVICE	0x01
 struct hci_ev_si_device {
 	__u16    event;
 	__u16    dev_id;
@@ -704,40 +802,40 @@ struct hci_ev_si_security {
 #define HCI_SCO_HDR_SIZE     3
 
 struct hci_command_hdr {
-	__le16 	opcode;		/* OCF & OGF */
+	__le16	opcode;		/* OCF & OGF */
 	__u8 	plen;
 } __attribute__ ((packed));
 
 struct hci_event_hdr {
-	__u8 	evt;
-	__u8 	plen;
+	__u8	evt;
+	__u8	plen;
 } __attribute__ ((packed));
 
 struct hci_acl_hdr {
-	__le16 	handle;		/* Handle & Flags(PB, BC) */
-	__le16 	dlen;
+	__le16	handle;		/* Handle & Flags(PB, BC) */
+	__le16	dlen;
 } __attribute__ ((packed));
 
 struct hci_sco_hdr {
-	__le16 	handle;
-	__u8 	dlen;
+	__le16	handle;
+	__u8	dlen;
 } __attribute__ ((packed));
 
 #ifdef __KERNEL__
 #include <linux/skbuff.h>
 static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb)
 {
-	return (struct hci_event_hdr *)skb->data;
+	return (struct hci_event_hdr *) skb->data;
 }
 
 static inline struct hci_acl_hdr *hci_acl_hdr(const struct sk_buff *skb)
 {
-	return (struct hci_acl_hdr *)skb->data;
+	return (struct hci_acl_hdr *) skb->data;
 }
 
 static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
 {
-	return (struct hci_sco_hdr *)skb->data;
+	return (struct hci_sco_hdr *) skb->data;
 }
 #endif
 
@@ -771,13 +869,13 @@ struct sockaddr_hci {
 struct hci_filter {
 	unsigned long type_mask;
 	unsigned long event_mask[2];
-	__le16   opcode;
+	__le16 opcode;
 };
 
 struct hci_ufilter {
-	__u32   type_mask;
-	__u32   event_mask[2];
-	__le16   opcode;
+	__u32  type_mask;
+	__u32  event_mask[2];
+	__le16 opcode;
 };
 
 #define HCI_FLT_TYPE_BITS	31
@@ -825,15 +923,15 @@ struct hci_dev_info {
 struct hci_conn_info {
 	__u16    handle;
 	bdaddr_t bdaddr;
-	__u8	 type;
-	__u8	 out;
-	__u16	 state;
-	__u32	 link_mode;
+	__u8     type;
+	__u8     out;
+	__u16    state;
+	__u32    link_mode;
 };
 
 struct hci_dev_req {
-	__u16 dev_id;
-	__u32 dev_opt;
+	__u16  dev_id;
+	__u32  dev_opt;
 };
 
 struct hci_dev_list_req {
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 8f67c8a7169b..0db89ed6b00c 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -71,7 +71,10 @@ struct hci_dev {
 	__u16		id;
 	__u8		type;
 	bdaddr_t	bdaddr;
+	__u8		dev_name[248];
+	__u8		dev_class[3];
 	__u8		features[8];
+	__u8		commands[64];
 	__u8		hci_ver;
 	__u16		hci_rev;
 	__u16		manufacturer;
@@ -312,8 +315,9 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
 void hci_add_sco(struct hci_conn *conn, __u16 handle);
 
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
-int    hci_conn_del(struct hci_conn *conn);
-void   hci_conn_hash_flush(struct hci_dev *hdev);
+int hci_conn_del(struct hci_conn *conn);
+void hci_conn_hash_flush(struct hci_dev *hdev);
+void hci_conn_check_pending(struct hci_dev *hdev);
 
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
 int hci_conn_auth(struct hci_conn *conn);
@@ -617,11 +621,11 @@ int hci_unregister_cb(struct hci_cb *hcb);
 int hci_register_notifier(struct notifier_block *nb);
 int hci_unregister_notifier(struct notifier_block *nb);
 
-int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param);
+int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
 int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
 int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 
-void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf);
+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
 
 void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
 
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 5fdfc9a67d39..797a30bec6fd 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -82,7 +82,7 @@ void hci_acl_connect(struct hci_conn *conn)
 	else
 		cp.role_switch	= 0x00;
 
-	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp);
+	hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
 }
 
 static void hci_acl_connect_cancel(struct hci_conn *conn)
@@ -95,8 +95,7 @@ static void hci_acl_connect_cancel(struct hci_conn *conn)
 		return;
 
 	bacpy(&cp.bdaddr, &conn->dst);
-	hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-				OCF_CREATE_CONN_CANCEL, sizeof(cp), &cp);
+	hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
 }
 
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
@@ -109,8 +108,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
 
 	cp.handle = cpu_to_le16(conn->handle);
 	cp.reason = reason;
-	hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-				OCF_DISCONNECT, sizeof(cp), &cp);
+	hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
 }
 
 void hci_add_sco(struct hci_conn *conn, __u16 handle)
@@ -126,7 +124,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
 	cp.handle   = cpu_to_le16(handle);
 	cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
 
-	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, sizeof(cp), &cp);
+	hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
 }
 
 static void hci_conn_timeout(unsigned long arg)
@@ -348,7 +346,7 @@ int hci_conn_auth(struct hci_conn *conn)
 	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
 		struct hci_cp_auth_requested cp;
 		cp.handle = cpu_to_le16(conn->handle);
-		hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED, sizeof(cp), &cp);
+		hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
 	}
 	return 0;
 }
@@ -369,7 +367,7 @@ int hci_conn_encrypt(struct hci_conn *conn)
 		struct hci_cp_set_conn_encrypt cp;
 		cp.handle  = cpu_to_le16(conn->handle);
 		cp.encrypt = 1;
-		hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp);
+		hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp);
 	}
 	return 0;
 }
@@ -383,7 +381,7 @@ int hci_conn_change_link_key(struct hci_conn *conn)
 	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
 		struct hci_cp_change_conn_link_key cp;
 		cp.handle = cpu_to_le16(conn->handle);
-		hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
+		hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
 	}
 	return 0;
 }
@@ -401,7 +399,7 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
 		struct hci_cp_switch_role cp;
 		bacpy(&cp.bdaddr, &conn->dst);
 		cp.role = role;
-		hci_send_cmd(conn->hdev, OGF_LINK_POLICY, OCF_SWITCH_ROLE, sizeof(cp), &cp);
+		hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
 	}
 	return 0;
 }
@@ -423,8 +421,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn)
 	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
 		struct hci_cp_exit_sniff_mode cp;
 		cp.handle = cpu_to_le16(conn->handle);
-		hci_send_cmd(hdev, OGF_LINK_POLICY,
-				OCF_EXIT_SNIFF_MODE, sizeof(cp), &cp);
+		hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
 	}
 
 timer:
@@ -455,8 +452,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn)
 		cp.max_latency        = cpu_to_le16(0);
 		cp.min_remote_timeout = cpu_to_le16(0);
 		cp.min_local_timeout  = cpu_to_le16(0);
-		hci_send_cmd(hdev, OGF_LINK_POLICY,
-				OCF_SNIFF_SUBRATE, sizeof(cp), &cp);
+		hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
 	}
 
 	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
@@ -466,8 +462,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn)
 		cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
 		cp.attempt      = cpu_to_le16(4);
 		cp.timeout      = cpu_to_le16(1);
-		hci_send_cmd(hdev, OGF_LINK_POLICY,
-				OCF_SNIFF_MODE, sizeof(cp), &cp);
+		hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
 	}
 }
 
@@ -493,6 +488,22 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
 	}
 }
 
+/* Check pending connect attempts */
+void hci_conn_check_pending(struct hci_dev *hdev)
+{
+	struct hci_conn *conn;
+
+	BT_DBG("hdev %s", hdev->name);
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
+	if (conn)
+		hci_acl_connect(conn);
+
+	hci_dev_unlock(hdev);
+}
+
 int hci_get_conn_list(void __user *arg)
 {
 	struct hci_conn_list_req req, *cl;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 18e3afc964df..2894382dd26d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -176,7 +176,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
 	BT_DBG("%s %ld", hdev->name, opt);
 
 	/* Reset device */
-	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
+	hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
 }
 
 static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
@@ -202,16 +202,16 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 
 	/* Reset */
 	if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks))
-			hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
+			hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
 
 	/* Read Local Supported Features */
-	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL);
+	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
 
 	/* Read Local Version */
-	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION, 0, NULL);
+	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
 
 	/* Read Buffer Size (ACL mtu, max pkt, etc.) */
-	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
+	hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
 
 #if 0
 	/* Host buffer size */
@@ -221,29 +221,35 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 		cp.sco_mtu = HCI_MAX_SCO_SIZE;
 		cp.acl_max_pkt = cpu_to_le16(0xffff);
 		cp.sco_max_pkt = cpu_to_le16(0xffff);
-		hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE, sizeof(cp), &cp);
+		hci_send_cmd(hdev, HCI_OP_HOST_BUFFER_SIZE, sizeof(cp), &cp);
 	}
 #endif
 
 	/* Read BD Address */
-	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
+	hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
+
+	/* Read Class of Device */
+	hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
+
+	/* Read Local Name */
+	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
 
 	/* Read Voice Setting */
-	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_READ_VOICE_SETTING, 0, NULL);
+	hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
 
 	/* Optional initialization */
 
 	/* Clear Event Filters */
 	flt_type = HCI_FLT_CLEAR_ALL;
-	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &flt_type);
+	hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
 
 	/* Page timeout ~20 secs */
 	param = cpu_to_le16(0x8000);
-	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_PG_TIMEOUT, 2, &param);
+	hci_send_cmd(hdev, HCI_OP_WRITE_PG_TIMEOUT, 2, &param);
 
 	/* Connection accept timeout ~20 secs */
 	param = cpu_to_le16(0x7d00);
-	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_CA_TIMEOUT, 2, &param);
+	hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
 }
 
 static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
@@ -253,7 +259,7 @@ static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
 	BT_DBG("%s %x", hdev->name, scan);
 
 	/* Inquiry and Page scans */
-	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan);
+	hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
 }
 
 static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
@@ -263,7 +269,7 @@ static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
 	BT_DBG("%s %x", hdev->name, auth);
 
 	/* Authentication */
-	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth);
+	hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth);
 }
 
 static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
@@ -273,7 +279,7 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
 	BT_DBG("%s %x", hdev->name, encrypt);
 
 	/* Authentication */
-	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt);
+	hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
 }
 
 /* Get HCI device by index.
@@ -384,7 +390,7 @@ static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
 	memcpy(&cp.lap, &ir->lap, 3);
 	cp.length  = ir->length;
 	cp.num_rsp = ir->num_rsp;
-	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, sizeof(cp), &cp);
+	hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
 }
 
 int hci_inquiry(void __user *arg)
@@ -1111,13 +1117,13 @@ static int hci_send_frame(struct sk_buff *skb)
 }
 
 /* Send HCI command */
-int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param)
+int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
 {
 	int len = HCI_COMMAND_HDR_SIZE + plen;
 	struct hci_command_hdr *hdr;
 	struct sk_buff *skb;
 
-	BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
+	BT_DBG("%s opcode 0x%x plen %d", hdev->name, opcode, plen);
 
 	skb = bt_skb_alloc(len, GFP_ATOMIC);
 	if (!skb) {
@@ -1126,7 +1132,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
 	}
 
 	hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
-	hdr->opcode = cpu_to_le16(hci_opcode_pack(ogf, ocf));
+	hdr->opcode = cpu_to_le16(opcode);
 	hdr->plen   = plen;
 
 	if (plen)
@@ -1143,7 +1149,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
 }
 
 /* Get data from the previously sent command */
-void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
 {
 	struct hci_command_hdr *hdr;
 
@@ -1152,10 +1158,10 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
 
 	hdr = (void *) hdev->sent_cmd->data;
 
-	if (hdr->opcode != cpu_to_le16(hci_opcode_pack(ogf, ocf)))
+	if (hdr->opcode != cpu_to_le16(opcode))
 		return NULL;
 
-	BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
+	BT_DBG("%s opcode 0x%x", hdev->name, opcode);
 
 	return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
 }
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 4baea1e38652..e2cfeea5ee72 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -52,213 +52,273 @@
 
 /* Handle HCI Event packets */
 
-/* Command Complete OGF LINK_CTL  */
-static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	__u8 status;
-	struct hci_conn *pend;
+	__u8 status = *((__u8 *) skb->data);
 
-	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+	BT_DBG("%s status 0x%x", hdev->name, status);
 
-	switch (ocf) {
-	case OCF_INQUIRY_CANCEL:
-	case OCF_EXIT_PERIODIC_INQ:
-		status = *((__u8 *) skb->data);
+	if (status)
+		return;
 
-		if (status) {
-			BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status);
-		} else {
-			clear_bit(HCI_INQUIRY, &hdev->flags);
-			hci_req_complete(hdev, status);
-		}
+	clear_bit(HCI_INQUIRY, &hdev->flags);
 
-		hci_dev_lock(hdev);
+	hci_req_complete(hdev, status);
 
-		pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
-		if (pend)
-			hci_acl_connect(pend);
-
-		hci_dev_unlock(hdev);
-
-		break;
-
-	default:
-		BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
-		break;
-	}
+	hci_conn_check_pending(hdev);
 }
 
-/* Command Complete OGF LINK_POLICY  */
-static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
 {
+	__u8 status = *((__u8 *) skb->data);
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	if (status)
+		return;
+
+	clear_bit(HCI_INQUIRY, &hdev->flags);
+
+	hci_conn_check_pending(hdev);
+}
+
+static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	BT_DBG("%s", hdev->name);
+}
+
+static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_rp_role_discovery *rp = (void *) skb->data;
 	struct hci_conn *conn;
-	struct hci_rp_role_discovery *rd;
-	struct hci_rp_write_link_policy *lp;
-	void *sent;
 
-	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-	switch (ocf) {
-	case OCF_ROLE_DISCOVERY:
-		rd = (void *) skb->data;
+	if (rp->status)
+		return;
 
-		if (rd->status)
-			break;
+	hci_dev_lock(hdev);
 
-		hci_dev_lock(hdev);
-
-		conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle));
-		if (conn) {
-			if (rd->role)
-				conn->link_mode &= ~HCI_LM_MASTER;
-			else
-				conn->link_mode |= HCI_LM_MASTER;
-		}
-
-		hci_dev_unlock(hdev);
-		break;
-
-	case OCF_WRITE_LINK_POLICY:
-		sent = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY);
-		if (!sent)
-			break;
-
-		lp = (struct hci_rp_write_link_policy *) skb->data;
-
-		if (lp->status)
-			break;
-
-		hci_dev_lock(hdev);
-
-		conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(lp->handle));
-		if (conn) {
-			__le16 policy = get_unaligned((__le16 *) (sent + 2));
-			conn->link_policy = __le16_to_cpu(policy);
-		}
-
-		hci_dev_unlock(hdev);
-		break;
-
-	default:
-		BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x",
-				hdev->name, ocf);
-		break;
+	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+	if (conn) {
+		if (rp->role)
+			conn->link_mode &= ~HCI_LM_MASTER;
+		else
+			conn->link_mode |= HCI_LM_MASTER;
 	}
+
+	hci_dev_unlock(hdev);
 }
 
-/* Command Complete OGF HOST_CTL  */
-static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	__u8 status, param;
+	struct hci_rp_write_link_policy *rp = (void *) skb->data;
+	struct hci_conn *conn;
+	void *sent;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LINK_POLICY);
+	if (!sent)
+		return;
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+	if (conn) {
+		__le16 policy = get_unaligned((__le16 *) (sent + 2));
+		conn->link_policy = __le16_to_cpu(policy);
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	hci_req_complete(hdev, status);
+}
+
+static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+	void *sent;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
+	if (!sent)
+		return;
+
+	if (!status)
+		memcpy(hdev->dev_name, sent, 248);
+}
+
+static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_rp_read_local_name *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	memcpy(hdev->dev_name, rp->name, 248);
+}
+
+static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+	void *sent;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_ENABLE);
+	if (!sent)
+		return;
+
+	if (!status) {
+		__u8 param = *((__u8 *) sent);
+
+		if (param == AUTH_ENABLED)
+			set_bit(HCI_AUTH, &hdev->flags);
+		else
+			clear_bit(HCI_AUTH, &hdev->flags);
+	}
+
+	hci_req_complete(hdev, status);
+}
+
+static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+	void *sent;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE);
+	if (!sent)
+		return;
+
+	if (!status) {
+		__u8 param = *((__u8 *) sent);
+
+		if (param)
+			set_bit(HCI_ENCRYPT, &hdev->flags);
+		else
+			clear_bit(HCI_ENCRYPT, &hdev->flags);
+	}
+
+	hci_req_complete(hdev, status);
+}
+
+static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+	void *sent;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE);
+	if (!sent)
+		return;
+
+	if (!status) {
+		__u8 param = *((__u8 *) sent);
+
+		clear_bit(HCI_PSCAN, &hdev->flags);
+		clear_bit(HCI_ISCAN, &hdev->flags);
+
+		if (param & SCAN_INQUIRY)
+			set_bit(HCI_ISCAN, &hdev->flags);
+
+		if (param & SCAN_PAGE)
+			set_bit(HCI_PSCAN, &hdev->flags);
+	}
+
+	hci_req_complete(hdev, status);
+}
+
+static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_rp_read_class_of_dev *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	memcpy(hdev->dev_class, rp->dev_class, 3);
+
+	BT_DBG("%s class 0x%.2x%.2x%.2x", hdev->name,
+		hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
+}
+
+static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+	void *sent;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
+	if (!sent)
+		return;
+
+	if (!status)
+		memcpy(hdev->dev_class, sent, 3);
+}
+
+static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_rp_read_voice_setting *rp = (void *) skb->data;
 	__u16 setting;
-	struct hci_rp_read_voice_setting *vs;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	setting = __le16_to_cpu(rp->voice_setting);
+
+	if (hdev->voice_setting == setting )
+		return;
+
+	hdev->voice_setting = setting;
+
+	BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
+
+	if (hdev->notify) {
+		tasklet_disable(&hdev->tx_task);
+		hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
+		tasklet_enable(&hdev->tx_task);
+	}
+}
+
+static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
 	void *sent;
 
-	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+	BT_DBG("%s status 0x%x", hdev->name, status);
 
-	switch (ocf) {
-	case OCF_RESET:
-		status = *((__u8 *) skb->data);
-		hci_req_complete(hdev, status);
-		break;
+	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_VOICE_SETTING);
+	if (!sent)
+		return;
 
-	case OCF_SET_EVENT_FLT:
-		status = *((__u8 *) skb->data);
-		if (status) {
-			BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
-		} else {
-			BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name);
-		}
-		break;
+	if (!status) {
+		__u16 setting = __le16_to_cpu(get_unaligned((__le16 *) sent));
 
-	case OCF_WRITE_AUTH_ENABLE:
-		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE);
-		if (!sent)
-			break;
-
-		status = *((__u8 *) skb->data);
-		param  = *((__u8 *) sent);
-
-		if (!status) {
-			if (param == AUTH_ENABLED)
-				set_bit(HCI_AUTH, &hdev->flags);
-			else
-				clear_bit(HCI_AUTH, &hdev->flags);
-		}
-		hci_req_complete(hdev, status);
-		break;
-
-	case OCF_WRITE_ENCRYPT_MODE:
-		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE);
-		if (!sent)
-			break;
-
-		status = *((__u8 *) skb->data);
-		param  = *((__u8 *) sent);
-
-		if (!status) {
-			if (param)
-				set_bit(HCI_ENCRYPT, &hdev->flags);
-			else
-				clear_bit(HCI_ENCRYPT, &hdev->flags);
-		}
-		hci_req_complete(hdev, status);
-		break;
-
-	case OCF_WRITE_CA_TIMEOUT:
-		status = *((__u8 *) skb->data);
-		if (status) {
-			BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
-		} else {
-			BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
-		}
-		break;
-
-	case OCF_WRITE_PG_TIMEOUT:
-		status = *((__u8 *) skb->data);
-		if (status) {
-			BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
-		} else {
-			BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
-		}
-		break;
-
-	case OCF_WRITE_SCAN_ENABLE:
-		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
-		if (!sent)
-			break;
-
-		status = *((__u8 *) skb->data);
-		param  = *((__u8 *) sent);
-
-		BT_DBG("param 0x%x", param);
-
-		if (!status) {
-			clear_bit(HCI_PSCAN, &hdev->flags);
-			clear_bit(HCI_ISCAN, &hdev->flags);
-			if (param & SCAN_INQUIRY)
-				set_bit(HCI_ISCAN, &hdev->flags);
-
-			if (param & SCAN_PAGE)
-				set_bit(HCI_PSCAN, &hdev->flags);
-		}
-		hci_req_complete(hdev, status);
-		break;
-
-	case OCF_READ_VOICE_SETTING:
-		vs = (struct hci_rp_read_voice_setting *) skb->data;
-
-		if (vs->status) {
-			BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vs->status);
-			break;
-		}
-
-		setting = __le16_to_cpu(vs->voice_setting);
-
-		if (hdev->voice_setting != setting ) {
+		if (hdev->voice_setting != setting) {
 			hdev->voice_setting = setting;
 
-			BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
+			BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
 
 			if (hdev->notify) {
 				tasklet_disable(&hdev->tx_task);
@@ -266,164 +326,153 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
 				tasklet_enable(&hdev->tx_task);
 			}
 		}
-		break;
-
-	case OCF_WRITE_VOICE_SETTING:
-		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING);
-		if (!sent)
-			break;
-
-		status = *((__u8 *) skb->data);
-		setting = __le16_to_cpu(get_unaligned((__le16 *) sent));
-
-		if (!status && hdev->voice_setting != setting) {
-			hdev->voice_setting = setting;
-
-			BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
-
-			if (hdev->notify) {
-				tasklet_disable(&hdev->tx_task);
-				hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
-				tasklet_enable(&hdev->tx_task);
-			}
-		}
-		hci_req_complete(hdev, status);
-		break;
-
-	case OCF_HOST_BUFFER_SIZE:
-		status = *((__u8 *) skb->data);
-		if (status) {
-			BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status);
-			hci_req_complete(hdev, status);
-		}
-		break;
-
-	default:
-		BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
-		break;
 	}
 }
 
-/* Command Complete OGF INFO_PARAM  */
-static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_read_loc_version *lv;
-	struct hci_rp_read_local_features *lf;
-	struct hci_rp_read_buffer_size *bs;
-	struct hci_rp_read_bd_addr *ba;
+	__u8 status = *((__u8 *) skb->data);
 
-	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+	BT_DBG("%s status 0x%x", hdev->name, status);
 
-	switch (ocf) {
-	case OCF_READ_LOCAL_VERSION:
-		lv = (struct hci_rp_read_loc_version *) skb->data;
-
-		if (lv->status) {
-			BT_DBG("%s READ_LOCAL_VERSION failed %d", hdev->name, lf->status);
-			break;
-		}
-
-		hdev->hci_ver = lv->hci_ver;
-		hdev->hci_rev = btohs(lv->hci_rev);
-		hdev->manufacturer = btohs(lv->manufacturer);
-
-		BT_DBG("%s: manufacturer %d hci_ver %d hci_rev %d", hdev->name,
-				hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
-
-		break;
-
-	case OCF_READ_LOCAL_FEATURES:
-		lf = (struct hci_rp_read_local_features *) skb->data;
-
-		if (lf->status) {
-			BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
-			break;
-		}
-
-		memcpy(hdev->features, lf->features, sizeof(hdev->features));
-
-		/* Adjust default settings according to features
-		 * supported by device. */
-		if (hdev->features[0] & LMP_3SLOT)
-			hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
-
-		if (hdev->features[0] & LMP_5SLOT)
-			hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
-
-		if (hdev->features[1] & LMP_HV2) {
-			hdev->pkt_type  |= (HCI_HV2);
-			hdev->esco_type |= (ESCO_HV2);
-		}
-
-		if (hdev->features[1] & LMP_HV3) {
-			hdev->pkt_type  |= (HCI_HV3);
-			hdev->esco_type |= (ESCO_HV3);
-		}
-
-		if (hdev->features[3] & LMP_ESCO)
-			hdev->esco_type |= (ESCO_EV3);
-
-		if (hdev->features[4] & LMP_EV4)
-			hdev->esco_type |= (ESCO_EV4);
-
-		if (hdev->features[4] & LMP_EV5)
-			hdev->esco_type |= (ESCO_EV5);
-
-		BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name,
-				lf->features[0], lf->features[1], lf->features[2]);
-
-		break;
-
-	case OCF_READ_BUFFER_SIZE:
-		bs = (struct hci_rp_read_buffer_size *) skb->data;
-
-		if (bs->status) {
-			BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
-			hci_req_complete(hdev, bs->status);
-			break;
-		}
-
-		hdev->acl_mtu  = __le16_to_cpu(bs->acl_mtu);
-		hdev->sco_mtu  = bs->sco_mtu;
-		hdev->acl_pkts = __le16_to_cpu(bs->acl_max_pkt);
-		hdev->sco_pkts = __le16_to_cpu(bs->sco_max_pkt);
-
-		if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
-			hdev->sco_mtu  = 64;
-			hdev->sco_pkts = 8;
-		}
-
-		hdev->acl_cnt = hdev->acl_pkts;
-		hdev->sco_cnt = hdev->sco_pkts;
-
-		BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
-			hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
-		break;
-
-	case OCF_READ_BD_ADDR:
-		ba = (struct hci_rp_read_bd_addr *) skb->data;
-
-		if (!ba->status) {
-			bacpy(&hdev->bdaddr, &ba->bdaddr);
-		} else {
-			BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
-		}
-
-		hci_req_complete(hdev, ba->status);
-		break;
-
-	default:
-		BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-		break;
-	}
+	hci_req_complete(hdev, status);
+}
+
+static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_rp_read_local_version *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	hdev->hci_ver = rp->hci_ver;
+	hdev->hci_rev = btohs(rp->hci_rev);
+	hdev->manufacturer = btohs(rp->manufacturer);
+
+	BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
+					hdev->manufacturer,
+					hdev->hci_ver, hdev->hci_rev);
+}
+
+static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_rp_read_local_commands *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
+}
+
+static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_rp_read_local_features *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	memcpy(hdev->features, rp->features, 8);
+
+	/* Adjust default settings according to features
+	 * supported by device. */
+
+	if (hdev->features[0] & LMP_3SLOT)
+		hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
+
+	if (hdev->features[0] & LMP_5SLOT)
+		hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
+
+	if (hdev->features[1] & LMP_HV2) {
+		hdev->pkt_type  |= (HCI_HV2);
+		hdev->esco_type |= (ESCO_HV2);
+	}
+
+	if (hdev->features[1] & LMP_HV3) {
+		hdev->pkt_type  |= (HCI_HV3);
+		hdev->esco_type |= (ESCO_HV3);
+	}
+
+	if (hdev->features[3] & LMP_ESCO)
+		hdev->esco_type |= (ESCO_EV3);
+
+	if (hdev->features[4] & LMP_EV4)
+		hdev->esco_type |= (ESCO_EV4);
+
+	if (hdev->features[4] & LMP_EV5)
+		hdev->esco_type |= (ESCO_EV5);
+
+	BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
+					hdev->features[0], hdev->features[1],
+					hdev->features[2], hdev->features[3],
+					hdev->features[4], hdev->features[5],
+					hdev->features[6], hdev->features[7]);
+}
+
+static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_rp_read_buffer_size *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	hdev->acl_mtu  = __le16_to_cpu(rp->acl_mtu);
+	hdev->sco_mtu  = rp->sco_mtu;
+	hdev->acl_pkts = __le16_to_cpu(rp->acl_max_pkt);
+	hdev->sco_pkts = __le16_to_cpu(rp->sco_max_pkt);
+
+	if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
+		hdev->sco_mtu  = 64;
+		hdev->sco_pkts = 8;
+	}
+
+	hdev->acl_cnt = hdev->acl_pkts;
+	hdev->sco_cnt = hdev->sco_pkts;
+
+	BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name,
+					hdev->acl_mtu, hdev->acl_pkts,
+					hdev->sco_mtu, hdev->sco_pkts);
+}
+
+static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_rp_read_bd_addr *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (!rp->status)
+		bacpy(&hdev->bdaddr, &rp->bdaddr);
+
+	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);
+
+	if (status) {
+		hci_req_complete(hdev, status);
+
+		hci_conn_check_pending(hdev);
+	} else
+		set_bit(HCI_INQUIRY, &hdev->flags);
 }
 
-/* Command Status OGF LINK_CTL  */
 static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 {
+	struct hci_cp_create_conn *cp;
 	struct hci_conn *conn;
-	struct hci_cp_create_conn *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
 
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_CONN);
 	if (!cp)
 		return;
 
@@ -431,8 +480,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
 
-	BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name,
-			status, batostr(&cp->bdaddr), conn);
+	BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->bdaddr), conn);
 
 	if (status) {
 		if (conn && conn->state == BT_CONNECT) {
@@ -457,157 +505,111 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 	hci_dev_unlock(hdev);
 }
 
-static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
+static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
 {
-	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+	struct hci_cp_add_sco *cp;
+	struct hci_conn *acl, *sco;
+	__u16 handle;
 
-	switch (ocf) {
-	case OCF_CREATE_CONN:
-		hci_cs_create_conn(hdev, status);
-		break;
+	if (!status)
+		return;
 
-	case OCF_ADD_SCO:
-		if (status) {
-			struct hci_conn *acl, *sco;
-			struct hci_cp_add_sco *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_ADD_SCO);
-			__u16 handle;
+	BT_DBG("%s status 0x%x", hdev->name, status);
 
-			if (!cp)
-				break;
+	cp = hci_sent_cmd_data(hdev, HCI_OP_ADD_SCO);
+	if (!cp)
+		return;
 
-			handle = __le16_to_cpu(cp->handle);
+	handle = __le16_to_cpu(cp->handle);
 
-			BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status);
-
-			hci_dev_lock(hdev);
-
-			acl = hci_conn_hash_lookup_handle(hdev, handle);
-			if (acl && (sco = acl->link)) {
-				sco->state = BT_CLOSED;
-
-				hci_proto_connect_cfm(sco, status);
-				hci_conn_del(sco);
-			}
-
-			hci_dev_unlock(hdev);
-		}
-		break;
-
-	case OCF_INQUIRY:
-		if (status) {
-			BT_DBG("%s Inquiry error: status 0x%x", hdev->name, status);
-			hci_req_complete(hdev, status);
-		} else {
-			set_bit(HCI_INQUIRY, &hdev->flags);
-		}
-		break;
-
-	default:
-		BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d",
-			hdev->name, ocf, status);
-		break;
-	}
-}
-
-/* Command Status OGF LINK_POLICY */
-static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
-{
-	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-
-	switch (ocf) {
-	case OCF_SNIFF_MODE:
-		if (status) {
-			struct hci_conn *conn;
-			struct hci_cp_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_SNIFF_MODE);
-
-			if (!cp)
-				break;
-
-			hci_dev_lock(hdev);
-
-			conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
-			if (conn) {
-				clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
-			}
-
-			hci_dev_unlock(hdev);
-		}
-		break;
-
-	case OCF_EXIT_SNIFF_MODE:
-		if (status) {
-			struct hci_conn *conn;
-			struct hci_cp_exit_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_EXIT_SNIFF_MODE);
-
-			if (!cp)
-				break;
-
-			hci_dev_lock(hdev);
-
-			conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
-			if (conn) {
-				clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
-			}
-
-			hci_dev_unlock(hdev);
-		}
-		break;
-
-	default:
-		BT_DBG("%s Command status: ogf LINK_POLICY ocf %x", hdev->name, ocf);
-		break;
-	}
-}
-
-/* Command Status OGF HOST_CTL */
-static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
-{
-	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-
-	switch (ocf) {
-	default:
-		BT_DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
-		break;
-	}
-}
-
-/* Command Status OGF INFO_PARAM  */
-static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
-{
-	BT_DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
-
-	switch (ocf) {
-	default:
-		BT_DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-		break;
-	}
-}
-
-/* Inquiry Complete */
-static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	__u8 status = *((__u8 *) skb->data);
-	struct hci_conn *pend;
-
-	BT_DBG("%s status %d", hdev->name, status);
-
-	clear_bit(HCI_INQUIRY, &hdev->flags);
-	hci_req_complete(hdev, status);
+	BT_DBG("%s handle %d", hdev->name, handle);
 
 	hci_dev_lock(hdev);
 
-	pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
-	if (pend)
-		hci_acl_connect(pend);
+	acl = hci_conn_hash_lookup_handle(hdev, handle);
+	if (acl && (sco = acl->link)) {
+		sco->state = BT_CLOSED;
+
+		hci_proto_connect_cfm(sco, status);
+		hci_conn_del(sco);
+	}
 
 	hci_dev_unlock(hdev);
 }
 
-/* Inquiry Result */
+static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
+{
+	BT_DBG("%s status 0x%x", hdev->name, status);
+}
+
+static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
+{
+	BT_DBG("%s status 0x%x", hdev->name, status);
+}
+
+static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
+{
+	struct hci_cp_sniff_mode *cp;
+	struct hci_conn *conn;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	if (!status)
+		return;
+
+	cp = hci_sent_cmd_data(hdev, HCI_OP_SNIFF_MODE);
+	if (!cp)
+		return;
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+	if (conn)
+		clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+
+	hci_dev_unlock(hdev);
+}
+
+static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
+{
+	struct hci_cp_exit_sniff_mode *cp;
+	struct hci_conn *conn;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	if (!status)
+		return;
+
+	cp = hci_sent_cmd_data(hdev, HCI_OP_EXIT_SNIFF_MODE);
+	if (!cp)
+		return;
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+	if (conn)
+		clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+
+	hci_dev_unlock(hdev);
+}
+
+static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+
+	BT_DBG("%s status %d", hdev->name, status);
+
+	clear_bit(HCI_INQUIRY, &hdev->flags);
+
+	hci_req_complete(hdev, status);
+
+	hci_conn_check_pending(hdev);
+}
+
 static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct inquiry_data data;
-	struct inquiry_info *info = (struct inquiry_info *) (skb->data + 1);
+	struct inquiry_info *info = (void *) (skb->data + 1);
 	int num_rsp = *((__u8 *) skb->data);
 
 	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
@@ -632,91 +634,90 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
 	hci_dev_unlock(hdev);
 }
 
-/* Inquiry Result With RSSI */
-static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct inquiry_data data;
-	int num_rsp = *((__u8 *) skb->data);
+	struct hci_ev_conn_complete *ev = (void *) skb->data;
+	struct hci_conn *conn;
 
-	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-
-	if (!num_rsp)
-		return;
+	BT_DBG("%s", hdev->name);
 
 	hci_dev_lock(hdev);
 
-	if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
-		struct inquiry_info_with_rssi_and_pscan_mode *info =
-			(struct inquiry_info_with_rssi_and_pscan_mode *) (skb->data + 1);
+	conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
+	if (!conn)
+		goto unlock;
 
-		for (; num_rsp; num_rsp--) {
-			bacpy(&data.bdaddr, &info->bdaddr);
-			data.pscan_rep_mode	= info->pscan_rep_mode;
-			data.pscan_period_mode	= info->pscan_period_mode;
-			data.pscan_mode		= info->pscan_mode;
-			memcpy(data.dev_class, info->dev_class, 3);
-			data.clock_offset	= info->clock_offset;
-			data.rssi		= info->rssi;
-			info++;
-			hci_inquiry_cache_update(hdev, &data);
+	if (!ev->status) {
+		conn->handle = __le16_to_cpu(ev->handle);
+		conn->state  = BT_CONNECTED;
+
+		if (test_bit(HCI_AUTH, &hdev->flags))
+			conn->link_mode |= HCI_LM_AUTH;
+
+		if (test_bit(HCI_ENCRYPT, &hdev->flags))
+			conn->link_mode |= HCI_LM_ENCRYPT;
+
+		/* Get remote features */
+		if (conn->type == ACL_LINK) {
+			struct hci_cp_read_remote_features cp;
+			cp.handle = ev->handle;
+			hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp);
 		}
-	} else {
-		struct inquiry_info_with_rssi *info =
-			(struct inquiry_info_with_rssi *) (skb->data + 1);
 
-		for (; num_rsp; num_rsp--) {
-			bacpy(&data.bdaddr, &info->bdaddr);
-			data.pscan_rep_mode	= info->pscan_rep_mode;
-			data.pscan_period_mode	= info->pscan_period_mode;
-			data.pscan_mode		= 0x00;
-			memcpy(data.dev_class, info->dev_class, 3);
-			data.clock_offset	= info->clock_offset;
-			data.rssi		= info->rssi;
-			info++;
-			hci_inquiry_cache_update(hdev, &data);
+		/* Set link policy */
+		if (conn->type == ACL_LINK && hdev->link_policy) {
+			struct hci_cp_write_link_policy cp;
+			cp.handle = ev->handle;
+			cp.policy = cpu_to_le16(hdev->link_policy);
+			hci_send_cmd(hdev, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp);
+		}
+
+		/* Set packet type for incoming connection */
+		if (!conn->out) {
+			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);
+		} else {
+			/* Update disconnect timer */
+			hci_conn_hold(conn);
+			hci_conn_put(conn);
+		}
+	} else
+		conn->state = BT_CLOSED;
+
+	if (conn->type == ACL_LINK) {
+		struct hci_conn *sco = conn->link;
+		if (sco) {
+			if (!ev->status)
+				hci_add_sco(sco, conn->handle);
+			else {
+				hci_proto_connect_cfm(sco, ev->status);
+				hci_conn_del(sco);
+			}
 		}
 	}
 
+	hci_proto_connect_cfm(conn, ev->status);
+	if (ev->status)
+		hci_conn_del(conn);
+
+unlock:
 	hci_dev_unlock(hdev);
+
+	hci_conn_check_pending(hdev);
 }
 
-/* Extended Inquiry Result */
-static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	struct inquiry_data data;
-	struct extended_inquiry_info *info = (struct extended_inquiry_info *) (skb->data + 1);
-	int num_rsp = *((__u8 *) skb->data);
-
-	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-
-	if (!num_rsp)
-		return;
-
-	hci_dev_lock(hdev);
-
-	for (; num_rsp; num_rsp--) {
-		bacpy(&data.bdaddr, &info->bdaddr);
-		data.pscan_rep_mode     = info->pscan_rep_mode;
-		data.pscan_period_mode  = info->pscan_period_mode;
-		data.pscan_mode         = 0x00;
-		memcpy(data.dev_class, info->dev_class, 3);
-		data.clock_offset       = info->clock_offset;
-		data.rssi               = info->rssi;
-		info++;
-		hci_inquiry_cache_update(hdev, &data);
-	}
-
-	hci_dev_unlock(hdev);
-}
-
-/* Connect Request */
 static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_conn_request *ev = (struct hci_ev_conn_request *) skb->data;
+	struct hci_ev_conn_request *ev = (void *) skb->data;
 	int mask = hdev->link_mode;
 
-	BT_DBG("%s Connection request: %s type 0x%x", hdev->name,
-			batostr(&ev->bdaddr), ev->link_type);
+	BT_DBG("%s bdaddr %s type 0x%x", hdev->name,
+					batostr(&ev->bdaddr), ev->link_type);
 
 	mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
 
@@ -745,107 +746,20 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 		else
 			cp.role = 0x01; /* Remain slave */
 
-		hci_send_cmd(hdev, OGF_LINK_CTL,
-				OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp);
+		hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp);
 	} else {
 		/* Connection rejected */
 		struct hci_cp_reject_conn_req cp;
 
 		bacpy(&cp.bdaddr, &ev->bdaddr);
 		cp.reason = 0x0f;
-		hci_send_cmd(hdev, OGF_LINK_CTL,
-				OCF_REJECT_CONN_REQ, sizeof(cp), &cp);
+		hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp);
 	}
 }
 
-/* Connect Complete */
-static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data;
-	struct hci_conn *conn, *pend;
-
-	BT_DBG("%s", hdev->name);
-
-	hci_dev_lock(hdev);
-
-	conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
-	if (!conn) {
-		hci_dev_unlock(hdev);
-		return;
-	}
-
-	if (!ev->status) {
-		conn->handle = __le16_to_cpu(ev->handle);
-		conn->state  = BT_CONNECTED;
-
-		if (test_bit(HCI_AUTH, &hdev->flags))
-			conn->link_mode |= HCI_LM_AUTH;
-
-		if (test_bit(HCI_ENCRYPT, &hdev->flags))
-			conn->link_mode |= HCI_LM_ENCRYPT;
-
-		/* Get remote features */
-		if (conn->type == ACL_LINK) {
-			struct hci_cp_read_remote_features cp;
-			cp.handle = ev->handle;
-			hci_send_cmd(hdev, OGF_LINK_CTL,
-				OCF_READ_REMOTE_FEATURES, sizeof(cp), &cp);
-		}
-
-		/* Set link policy */
-		if (conn->type == ACL_LINK && hdev->link_policy) {
-			struct hci_cp_write_link_policy cp;
-			cp.handle = ev->handle;
-			cp.policy = cpu_to_le16(hdev->link_policy);
-			hci_send_cmd(hdev, OGF_LINK_POLICY,
-				OCF_WRITE_LINK_POLICY, sizeof(cp), &cp);
-		}
-
-		/* Set packet type for incoming connection */
-		if (!conn->out) {
-			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, OGF_LINK_CTL,
-				OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
-		} else {
-			/* Update disconnect timer */
-			hci_conn_hold(conn);
-			hci_conn_put(conn);
-		}
-	} else
-		conn->state = BT_CLOSED;
-
-	if (conn->type == ACL_LINK) {
-		struct hci_conn *sco = conn->link;
-		if (sco) {
-			if (!ev->status)
-				hci_add_sco(sco, conn->handle);
-			else {
-				hci_proto_connect_cfm(sco, ev->status);
-				hci_conn_del(sco);
-			}
-		}
-	}
-
-	hci_proto_connect_cfm(conn, ev->status);
-	if (ev->status)
-		hci_conn_del(conn);
-
-	pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
-	if (pend)
-		hci_acl_connect(pend);
-
-	hci_dev_unlock(hdev);
-}
-
-/* Disconnect Complete */
 static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_disconn_complete *ev = (struct hci_ev_disconn_complete *) skb->data;
+	struct hci_ev_disconn_complete *ev = (void *) skb->data;
 	struct hci_conn *conn;
 
 	BT_DBG("%s status %d", hdev->name, ev->status);
@@ -865,10 +779,310 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
 	hci_dev_unlock(hdev);
 }
 
-/* Number of completed packets */
+static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_auth_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_handle(hdev, __le16_to_cpu(ev->handle));
+	if (conn) {
+		if (!ev->status)
+			conn->link_mode |= HCI_LM_AUTH;
+
+		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
+
+		hci_auth_cfm(conn, ev->status);
+
+		if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+			if (!ev->status) {
+				struct hci_cp_set_conn_encrypt cp;
+				cp.handle  = cpu_to_le16(conn->handle);
+				cp.encrypt = 1;
+				hci_send_cmd(conn->hdev,
+					HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp);
+			} else {
+				clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+				hci_encrypt_cfm(conn, ev->status, 0x00);
+			}
+		}
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	BT_DBG("%s", hdev->name);
+
+	hci_conn_check_pending(hdev);
+}
+
+static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_encrypt_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) {
+		if (!ev->status) {
+			if (ev->encrypt)
+				conn->link_mode |= HCI_LM_ENCRYPT;
+			else
+				conn->link_mode &= ~HCI_LM_ENCRYPT;
+		}
+
+		clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+
+		hci_encrypt_cfm(conn, ev->status, ev->encrypt);
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_change_link_key_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_handle(hdev, __le16_to_cpu(ev->handle));
+	if (conn) {
+		if (!ev->status)
+			conn->link_mode |= HCI_LM_SECURE;
+
+		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
+
+		hci_key_change_cfm(conn, ev->status);
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_remote_features *ev = (void *) skb->data;
+	struct hci_conn *conn;
+
+	BT_DBG("%s status %d", hdev->name, ev->status);
+
+	if (ev->status)
+		return;
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+	if (conn)
+		memcpy(conn->features, ev->features, 8);
+
+	hci_dev_unlock(hdev);
+}
+
+static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	BT_DBG("%s", hdev->name);
+}
+
+static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	BT_DBG("%s", hdev->name);
+}
+
+static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_cmd_complete *ev = (void *) skb->data;
+	__u16 opcode;
+
+	skb_pull(skb, sizeof(*ev));
+
+	opcode = __le16_to_cpu(ev->opcode);
+
+	switch (opcode) {
+	case HCI_OP_INQUIRY_CANCEL:
+		hci_cc_inquiry_cancel(hdev, skb);
+		break;
+
+	case HCI_OP_EXIT_PERIODIC_INQ:
+		hci_cc_exit_periodic_inq(hdev, skb);
+		break;
+
+	case HCI_OP_REMOTE_NAME_REQ_CANCEL:
+		hci_cc_remote_name_req_cancel(hdev, skb);
+		break;
+
+	case HCI_OP_ROLE_DISCOVERY:
+		hci_cc_role_discovery(hdev, skb);
+		break;
+
+	case HCI_OP_WRITE_LINK_POLICY:
+		hci_cc_write_link_policy(hdev, skb);
+		break;
+
+	case HCI_OP_RESET:
+		hci_cc_reset(hdev, skb);
+		break;
+
+	case HCI_OP_WRITE_LOCAL_NAME:
+		hci_cc_write_local_name(hdev, skb);
+		break;
+
+	case HCI_OP_READ_LOCAL_NAME:
+		hci_cc_read_local_name(hdev, skb);
+		break;
+
+	case HCI_OP_WRITE_AUTH_ENABLE:
+		hci_cc_write_auth_enable(hdev, skb);
+		break;
+
+	case HCI_OP_WRITE_ENCRYPT_MODE:
+		hci_cc_write_encrypt_mode(hdev, skb);
+		break;
+
+	case HCI_OP_WRITE_SCAN_ENABLE:
+		hci_cc_write_scan_enable(hdev, skb);
+		break;
+
+	case HCI_OP_READ_CLASS_OF_DEV:
+		hci_cc_read_class_of_dev(hdev, skb);
+		break;
+
+	case HCI_OP_WRITE_CLASS_OF_DEV:
+		hci_cc_write_class_of_dev(hdev, skb);
+		break;
+
+	case HCI_OP_READ_VOICE_SETTING:
+		hci_cc_read_voice_setting(hdev, skb);
+		break;
+
+	case HCI_OP_WRITE_VOICE_SETTING:
+		hci_cc_write_voice_setting(hdev, skb);
+		break;
+
+	case HCI_OP_HOST_BUFFER_SIZE:
+		hci_cc_host_buffer_size(hdev, skb);
+		break;
+
+	case HCI_OP_READ_LOCAL_VERSION:
+		hci_cc_read_local_version(hdev, skb);
+		break;
+
+	case HCI_OP_READ_LOCAL_COMMANDS:
+		hci_cc_read_local_commands(hdev, skb);
+		break;
+
+	case HCI_OP_READ_LOCAL_FEATURES:
+		hci_cc_read_local_features(hdev, skb);
+		break;
+
+	case HCI_OP_READ_BUFFER_SIZE:
+		hci_cc_read_buffer_size(hdev, skb);
+		break;
+
+	case HCI_OP_READ_BD_ADDR:
+		hci_cc_read_bd_addr(hdev, skb);
+		break;
+
+	default:
+		BT_DBG("%s opcode 0x%x", hdev->name, opcode);
+		break;
+	}
+
+	if (ev->ncmd) {
+		atomic_set(&hdev->cmd_cnt, 1);
+		if (!skb_queue_empty(&hdev->cmd_q))
+			hci_sched_cmd(hdev);
+	}
+}
+
+static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_cmd_status *ev = (void *) skb->data;
+	__u16 opcode;
+
+	skb_pull(skb, sizeof(*ev));
+
+	opcode = __le16_to_cpu(ev->opcode);
+
+	switch (opcode) {
+	case HCI_OP_INQUIRY:
+		hci_cs_inquiry(hdev, ev->status);
+		break;
+
+	case HCI_OP_CREATE_CONN:
+		hci_cs_create_conn(hdev, ev->status);
+		break;
+
+	case HCI_OP_ADD_SCO:
+		hci_cs_add_sco(hdev, ev->status);
+		break;
+
+	case HCI_OP_REMOTE_NAME_REQ:
+		hci_cs_remote_name_req(hdev, ev->status);
+		break;
+
+	case HCI_OP_SETUP_SYNC_CONN:
+		hci_cs_setup_sync_conn(hdev, ev->status);
+		break;
+
+	case HCI_OP_SNIFF_MODE:
+		hci_cs_sniff_mode(hdev, ev->status);
+		break;
+
+	case HCI_OP_EXIT_SNIFF_MODE:
+		hci_cs_exit_sniff_mode(hdev, ev->status);
+		break;
+
+	default:
+		BT_DBG("%s opcode 0x%x", hdev->name, opcode);
+		break;
+	}
+
+	if (ev->ncmd) {
+		atomic_set(&hdev->cmd_cnt, 1);
+		if (!skb_queue_empty(&hdev->cmd_q))
+			hci_sched_cmd(hdev);
+	}
+}
+
+static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_role_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_ba(hdev, ACL_LINK, &ev->bdaddr);
+	if (conn) {
+		if (!ev->status) {
+			if (ev->role)
+				conn->link_mode &= ~HCI_LM_MASTER;
+			else
+				conn->link_mode |= HCI_LM_MASTER;
+		}
+
+		clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend);
+
+		hci_role_switch_cfm(conn, ev->status, ev->role);
+	}
+
+	hci_dev_unlock(hdev);
+}
+
 static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_num_comp_pkts *ev = (struct hci_ev_num_comp_pkts *) skb->data;
+	struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
 	__le16 *ptr;
 	int i;
 
@@ -903,42 +1117,15 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
 			}
 		}
 	}
+
 	hci_sched_tx(hdev);
 
 	tasklet_enable(&hdev->tx_task);
 }
 
-/* Role Change */
-static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	struct hci_ev_role_change *ev = (struct hci_ev_role_change *) 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, ACL_LINK, &ev->bdaddr);
-	if (conn) {
-		if (!ev->status) {
-			if (ev->role)
-				conn->link_mode &= ~HCI_LM_MASTER;
-			else
-				conn->link_mode |= HCI_LM_MASTER;
-		}
-
-		clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend);
-
-		hci_role_switch_cfm(conn, ev->status, ev->role);
-	}
-
-	hci_dev_unlock(hdev);
-}
-
-/* Mode Change */
 static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_mode_change *ev = (struct hci_ev_mode_change *) skb->data;
+	struct hci_ev_mode_change *ev = (void *) skb->data;
 	struct hci_conn *conn;
 
 	BT_DBG("%s status %d", hdev->name, ev->status);
@@ -961,129 +1148,24 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
 	hci_dev_unlock(hdev);
 }
 
-/* Authentication Complete */
-static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	struct hci_ev_auth_complete *ev = (struct hci_ev_auth_complete *) 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) {
-		if (!ev->status)
-			conn->link_mode |= HCI_LM_AUTH;
-
-		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
-
-		hci_auth_cfm(conn, ev->status);
-
-		if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
-			if (!ev->status) {
-				struct hci_cp_set_conn_encrypt cp;
-				cp.handle  = cpu_to_le16(conn->handle);
-				cp.encrypt = 1;
-				hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-					OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp);
-			} else {
-				clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
-				hci_encrypt_cfm(conn, ev->status, 0x00);
-			}
-		}
-	}
-
-	hci_dev_unlock(hdev);
-}
-
-/* Encryption Change */
-static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	struct hci_ev_encrypt_change *ev = (struct hci_ev_encrypt_change *) 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) {
-		if (!ev->status) {
-			if (ev->encrypt)
-				conn->link_mode |= HCI_LM_ENCRYPT;
-			else
-				conn->link_mode &= ~HCI_LM_ENCRYPT;
-		}
-
-		clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
-
-		hci_encrypt_cfm(conn, ev->status, ev->encrypt);
-	}
-
-	hci_dev_unlock(hdev);
-}
-
-/* Change Connection Link Key Complete */
-static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) 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) {
-		if (!ev->status)
-			conn->link_mode |= HCI_LM_SECURE;
-
-		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
-
-		hci_key_change_cfm(conn, ev->status);
-	}
-
-	hci_dev_unlock(hdev);
-}
-
-/* Pin Code Request*/
 static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
+	BT_DBG("%s", hdev->name);
 }
 
-/* Link Key Request */
 static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
+	BT_DBG("%s", hdev->name);
 }
 
-/* Link Key Notification */
 static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
+	BT_DBG("%s", hdev->name);
 }
 
-/* Remote Features */
-static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	struct hci_ev_remote_features *ev = (struct hci_ev_remote_features *) 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) {
-		memcpy(conn->features, ev->features, sizeof(conn->features));
-	}
-
-	hci_dev_unlock(hdev);
-}
-
-/* Clock Offset */
 static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_clock_offset *ev = (struct hci_ev_clock_offset *) skb->data;
+	struct hci_ev_clock_offset *ev = (void *) skb->data;
 	struct hci_conn *conn;
 
 	BT_DBG("%s status %d", hdev->name, ev->status);
@@ -1103,10 +1185,9 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
 	hci_dev_unlock(hdev);
 }
 
-/* Page Scan Repetition Mode */
 static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_pscan_rep_mode *ev = (struct hci_ev_pscan_rep_mode *) skb->data;
+	struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
 	struct inquiry_entry *ie;
 
 	BT_DBG("%s", hdev->name);
@@ -1121,10 +1202,69 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *
 	hci_dev_unlock(hdev);
 }
 
-/* Sniff Subrate */
+static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct inquiry_data data;
+	int num_rsp = *((__u8 *) skb->data);
+
+	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
+
+	if (!num_rsp)
+		return;
+
+	hci_dev_lock(hdev);
+
+	if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
+		struct inquiry_info_with_rssi_and_pscan_mode *info = (void *) (skb->data + 1);
+
+		for (; num_rsp; num_rsp--) {
+			bacpy(&data.bdaddr, &info->bdaddr);
+			data.pscan_rep_mode	= info->pscan_rep_mode;
+			data.pscan_period_mode	= info->pscan_period_mode;
+			data.pscan_mode		= info->pscan_mode;
+			memcpy(data.dev_class, info->dev_class, 3);
+			data.clock_offset	= info->clock_offset;
+			data.rssi		= info->rssi;
+			info++;
+			hci_inquiry_cache_update(hdev, &data);
+		}
+	} else {
+		struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
+
+		for (; num_rsp; num_rsp--) {
+			bacpy(&data.bdaddr, &info->bdaddr);
+			data.pscan_rep_mode	= info->pscan_rep_mode;
+			data.pscan_period_mode	= info->pscan_period_mode;
+			data.pscan_mode		= 0x00;
+			memcpy(data.dev_class, info->dev_class, 3);
+			data.clock_offset	= info->clock_offset;
+			data.rssi		= info->rssi;
+			info++;
+			hci_inquiry_cache_update(hdev, &data);
+		}
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	BT_DBG("%s", hdev->name);
+}
+
+static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	BT_DBG("%s", hdev->name);
+}
+
+static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	BT_DBG("%s", hdev->name);
+}
+
 static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_sniff_subrate *ev = (struct hci_ev_sniff_subrate *) skb->data;
+	struct hci_ev_sniff_subrate *ev = (void *) skb->data;
 	struct hci_conn *conn;
 
 	BT_DBG("%s status %d", hdev->name, ev->status);
@@ -1138,22 +1278,42 @@ static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *s
 	hci_dev_unlock(hdev);
 }
 
+static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct inquiry_data data;
+	struct extended_inquiry_info *info = (void *) (skb->data + 1);
+	int num_rsp = *((__u8 *) skb->data);
+
+	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
+
+	if (!num_rsp)
+		return;
+
+	hci_dev_lock(hdev);
+
+	for (; num_rsp; num_rsp--) {
+		bacpy(&data.bdaddr, &info->bdaddr);
+		data.pscan_rep_mode     = info->pscan_rep_mode;
+		data.pscan_period_mode  = info->pscan_period_mode;
+		data.pscan_mode         = 0x00;
+		memcpy(data.dev_class, info->dev_class, 3);
+		data.clock_offset       = info->clock_offset;
+		data.rssi               = info->rssi;
+		info++;
+		hci_inquiry_cache_update(hdev, &data);
+	}
+
+	hci_dev_unlock(hdev);
+}
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data;
-	struct hci_ev_cmd_complete *ec;
-	struct hci_ev_cmd_status *cs;
-	u16 opcode, ocf, ogf;
+	struct hci_event_hdr *hdr = (void *) skb->data;
+	__u8 event = hdr->evt;
 
 	skb_pull(skb, HCI_EVENT_HDR_SIZE);
 
-	BT_DBG("%s evt 0x%x", hdev->name, hdr->evt);
-
-	switch (hdr->evt) {
-	case HCI_EV_NUM_COMP_PKTS:
-		hci_num_comp_pkts_evt(hdev, skb);
-		break;
-
+	switch (event) {
 	case HCI_EV_INQUIRY_COMPLETE:
 		hci_inquiry_complete_evt(hdev, skb);
 		break;
@@ -1162,44 +1322,64 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_inquiry_result_evt(hdev, skb);
 		break;
 
-	case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
-		hci_inquiry_result_with_rssi_evt(hdev, skb);
-		break;
-
-	case HCI_EV_EXTENDED_INQUIRY_RESULT:
-		hci_extended_inquiry_result_evt(hdev, skb);
+	case HCI_EV_CONN_COMPLETE:
+		hci_conn_complete_evt(hdev, skb);
 		break;
 
 	case HCI_EV_CONN_REQUEST:
 		hci_conn_request_evt(hdev, skb);
 		break;
 
-	case HCI_EV_CONN_COMPLETE:
-		hci_conn_complete_evt(hdev, skb);
-		break;
-
 	case HCI_EV_DISCONN_COMPLETE:
 		hci_disconn_complete_evt(hdev, skb);
 		break;
 
-	case HCI_EV_ROLE_CHANGE:
-		hci_role_change_evt(hdev, skb);
-		break;
-
-	case HCI_EV_MODE_CHANGE:
-		hci_mode_change_evt(hdev, skb);
-		break;
-
 	case HCI_EV_AUTH_COMPLETE:
 		hci_auth_complete_evt(hdev, skb);
 		break;
 
+	case HCI_EV_REMOTE_NAME:
+		hci_remote_name_evt(hdev, skb);
+		break;
+
 	case HCI_EV_ENCRYPT_CHANGE:
 		hci_encrypt_change_evt(hdev, skb);
 		break;
 
-	case HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE:
-		hci_change_conn_link_key_complete_evt(hdev, skb);
+	case HCI_EV_CHANGE_LINK_KEY_COMPLETE:
+		hci_change_link_key_complete_evt(hdev, skb);
+		break;
+
+	case HCI_EV_REMOTE_FEATURES:
+		hci_remote_features_evt(hdev, skb);
+		break;
+
+	case HCI_EV_REMOTE_VERSION:
+		hci_remote_version_evt(hdev, skb);
+		break;
+
+	case HCI_EV_QOS_SETUP_COMPLETE:
+		hci_qos_setup_complete_evt(hdev, skb);
+		break;
+
+	case HCI_EV_CMD_COMPLETE:
+		hci_cmd_complete_evt(hdev, skb);
+		break;
+
+	case HCI_EV_CMD_STATUS:
+		hci_cmd_status_evt(hdev, skb);
+		break;
+
+	case HCI_EV_ROLE_CHANGE:
+		hci_role_change_evt(hdev, skb);
+		break;
+
+	case HCI_EV_NUM_COMP_PKTS:
+		hci_num_comp_pkts_evt(hdev, skb);
+		break;
+
+	case HCI_EV_MODE_CHANGE:
+		hci_mode_change_evt(hdev, skb);
 		break;
 
 	case HCI_EV_PIN_CODE_REQ:
@@ -1214,10 +1394,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_link_key_notify_evt(hdev, skb);
 		break;
 
-	case HCI_EV_REMOTE_FEATURES:
-		hci_remote_features_evt(hdev, skb);
-		break;
-
 	case HCI_EV_CLOCK_OFFSET:
 		hci_clock_offset_evt(hdev, skb);
 		break;
@@ -1226,82 +1402,32 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_pscan_rep_mode_evt(hdev, skb);
 		break;
 
+	case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
+		hci_inquiry_result_with_rssi_evt(hdev, skb);
+		break;
+
+	case HCI_EV_REMOTE_EXT_FEATURES:
+		hci_remote_ext_features_evt(hdev, skb);
+		break;
+
+	case HCI_EV_SYNC_CONN_COMPLETE:
+		hci_sync_conn_complete_evt(hdev, skb);
+		break;
+
+	case HCI_EV_SYNC_CONN_CHANGED:
+		hci_sync_conn_changed_evt(hdev, skb);
+		break;
+
 	case HCI_EV_SNIFF_SUBRATE:
 		hci_sniff_subrate_evt(hdev, skb);
 		break;
 
-	case HCI_EV_CMD_STATUS:
-		cs = (struct hci_ev_cmd_status *) skb->data;
-		skb_pull(skb, sizeof(cs));
-
-		opcode = __le16_to_cpu(cs->opcode);
-		ogf = hci_opcode_ogf(opcode);
-		ocf = hci_opcode_ocf(opcode);
-
-		switch (ogf) {
-		case OGF_INFO_PARAM:
-			hci_cs_info_param(hdev, ocf, cs->status);
-			break;
-
-		case OGF_HOST_CTL:
-			hci_cs_host_ctl(hdev, ocf, cs->status);
-			break;
-
-		case OGF_LINK_CTL:
-			hci_cs_link_ctl(hdev, ocf, cs->status);
-			break;
-
-		case OGF_LINK_POLICY:
-			hci_cs_link_policy(hdev, ocf, cs->status);
-			break;
-
-		default:
-			BT_DBG("%s Command Status OGF %x", hdev->name, ogf);
-			break;
-		}
-
-		if (cs->ncmd) {
-			atomic_set(&hdev->cmd_cnt, 1);
-			if (!skb_queue_empty(&hdev->cmd_q))
-				hci_sched_cmd(hdev);
-		}
+	case HCI_EV_EXTENDED_INQUIRY_RESULT:
+		hci_extended_inquiry_result_evt(hdev, skb);
 		break;
 
-	case HCI_EV_CMD_COMPLETE:
-		ec = (struct hci_ev_cmd_complete *) skb->data;
-		skb_pull(skb, sizeof(*ec));
-
-		opcode = __le16_to_cpu(ec->opcode);
-		ogf = hci_opcode_ogf(opcode);
-		ocf = hci_opcode_ocf(opcode);
-
-		switch (ogf) {
-		case OGF_INFO_PARAM:
-			hci_cc_info_param(hdev, ocf, skb);
-			break;
-
-		case OGF_HOST_CTL:
-			hci_cc_host_ctl(hdev, ocf, skb);
-			break;
-
-		case OGF_LINK_CTL:
-			hci_cc_link_ctl(hdev, ocf, skb);
-			break;
-
-		case OGF_LINK_POLICY:
-			hci_cc_link_policy(hdev, ocf, skb);
-			break;
-
-		default:
-			BT_DBG("%s Command Completed OGF %x", hdev->name, ogf);
-			break;
-		}
-
-		if (ec->ncmd) {
-			atomic_set(&hdev->cmd_cnt, 1);
-			if (!skb_queue_empty(&hdev->cmd_q))
-				hci_sched_cmd(hdev);
-		}
+	default:
+		BT_DBG("%s event 0x%x", hdev->name, event);
 		break;
 	}
 
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 43dd6373bff9..8825102c517c 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -451,7 +451,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
 			goto drop;
 		}
 
-		if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
+		if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) {
 			skb_queue_tail(&hdev->raw_q, skb);
 			hci_sched_tx(hdev);
 		} else {
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 25835403d659..cef1e3e1881c 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -41,6 +41,26 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char
 	return sprintf(buf, "%s\n", typetostr(hdev->type));
 }
 
+static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct hci_dev *hdev = dev_get_drvdata(dev);
+	char name[249];
+	int i;
+
+	for (i = 0; i < 248; i++)
+		name[i] = hdev->dev_name[i];
+
+	name[248] = '\0';
+	return sprintf(buf, "%s\n", name);
+}
+
+static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct hci_dev *hdev = dev_get_drvdata(dev);
+	return sprintf(buf, "0x%.2x%.2x%.2x\n",
+			hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
+}
+
 static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = dev_get_drvdata(dev);
@@ -49,6 +69,17 @@ static ssize_t show_address(struct device *dev, struct device_attribute *attr, c
 	return sprintf(buf, "%s\n", batostr(&bdaddr));
 }
 
+static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct hci_dev *hdev = dev_get_drvdata(dev);
+
+	return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+				hdev->features[0], hdev->features[1],
+				hdev->features[2], hdev->features[3],
+				hdev->features[4], hdev->features[5],
+				hdev->features[6], hdev->features[7]);
+}
+
 static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = dev_get_drvdata(dev);
@@ -170,7 +201,10 @@ static ssize_t store_sniff_min_interval(struct device *dev, struct device_attrib
 }
 
 static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static DEVICE_ATTR(class, S_IRUGO, show_class, NULL);
 static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
+static DEVICE_ATTR(features, S_IRUGO, show_features, NULL);
 static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL);
 static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
 static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
@@ -185,7 +219,10 @@ static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
 
 static struct device_attribute *bt_attrs[] = {
 	&dev_attr_type,
+	&dev_attr_name,
+	&dev_attr_class,
 	&dev_attr_address,
+	&dev_attr_features,
 	&dev_attr_manufacturer,
 	&dev_attr_hci_version,
 	&dev_attr_hci_revision,

From 876d9484edf77d228adb42aecd4debd58d7739d6 Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 13:35:42 +0200
Subject: [PATCH 02/30] [Bluetooth] Finish L2CAP configuration only with
 acceptable settings

The parameters of the L2CAP output configuration might not be accepted
after the first configuration round. So only indicate a finished output
configuration when acceptable settings are provided.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 net/bluetooth/l2cap.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 36ef27b625db..6ce693d2e5b9 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1370,8 +1370,10 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
 
 		if (pi->conf_mtu < pi->omtu)
 			result = L2CAP_CONF_UNACCEPT;
-		else
+		else {
 			pi->omtu = pi->conf_mtu;
+			pi->conf_state |= L2CAP_CONF_OUTPUT_DONE;
+		}
 
 		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
 	}
@@ -1577,16 +1579,19 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
 	l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
 
-	/* Output config done. */
-	l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE;
-
 	/* Reset config buffer. */
 	l2cap_pi(sk)->conf_len = 0;
 
+	if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE))
+		goto unlock;
+
 	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
 		sk->sk_state = BT_CONNECTED;
 		l2cap_chan_ready(sk);
-	} else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
+		goto unlock;
+	}
+
+	if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
 		u8 req[64];
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 					l2cap_build_conf_req(sk, req), req);
@@ -1646,7 +1651,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	if (flags & 0x01)
 		goto done;
 
-	/* Input config done */
 	l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
 
 	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {

From 861d6882b3dfe1710b35dbddf1b395b962061413 Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 13:37:06 +0200
Subject: [PATCH 03/30] [Bluetooth] Remove global conf_mtu variable from L2CAP

After the change to the L2CAP configuration parameter handling the
global conf_mtu variable is no longer needed and so remove it.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/l2cap.h | 10 +++++-----
 net/bluetooth/l2cap.c         | 12 ++++++------
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 70e70f5d3dd6..f7bcd1f782cb 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -221,7 +221,6 @@ struct l2cap_pinfo {
 	__u8		conf_len;
 	__u8		conf_state;
 	__u8		conf_retry;
-	__u16		conf_mtu;
 
 	__u8		ident;
 
@@ -232,10 +231,11 @@ struct l2cap_pinfo {
 	struct sock		*prev_c;
 };
 
-#define L2CAP_CONF_REQ_SENT    0x01
-#define L2CAP_CONF_INPUT_DONE  0x02
-#define L2CAP_CONF_OUTPUT_DONE 0x04
-#define L2CAP_CONF_MAX_RETRIES 2
+#define L2CAP_CONF_REQ_SENT	0x01
+#define L2CAP_CONF_INPUT_DONE	0x02
+#define L2CAP_CONF_OUTPUT_DONE	0x04
+
+#define L2CAP_CONF_MAX_RETRIES	2
 
 void l2cap_load(void);
 
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 6ce693d2e5b9..fde1606a4f31 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -508,7 +508,6 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
 
 	/* Default config options */
 	pi->conf_len = 0;
-	pi->conf_mtu = L2CAP_DEFAULT_MTU;
 	pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
 }
 
@@ -1256,11 +1255,11 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned
 		break;
 
 	case 2:
-		*val = __le16_to_cpu(*((__le16 *)opt->val));
+		*val = __le16_to_cpu(*((__le16 *) opt->val));
 		break;
 
 	case 4:
-		*val = __le32_to_cpu(*((__le32 *)opt->val));
+		*val = __le32_to_cpu(*((__le32 *) opt->val));
 		break;
 
 	default:
@@ -1332,6 +1331,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
 	int len = pi->conf_len;
 	int type, hint, olen;
 	unsigned long val;
+	u16 mtu = L2CAP_DEFAULT_MTU;
 	u16 result = L2CAP_CONF_SUCCESS;
 
 	BT_DBG("sk %p", sk);
@@ -1344,7 +1344,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
 
 		switch (type) {
 		case L2CAP_CONF_MTU:
-			pi->conf_mtu = val;
+			mtu = val;
 			break;
 
 		case L2CAP_CONF_FLUSH_TO:
@@ -1368,10 +1368,10 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
 		/* Configure output options and let the other side know
 		 * which ones we don't like. */
 
-		if (pi->conf_mtu < pi->omtu)
+		if (mtu < pi->omtu)
 			result = L2CAP_CONF_UNACCEPT;
 		else {
-			pi->omtu = pi->conf_mtu;
+			pi->omtu = mtu;
 			pi->conf_state |= L2CAP_CONF_OUTPUT_DONE;
 		}
 

From 4e8402a3f884427f9233ba436459c158d1f2e114 Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 13:37:56 +0200
Subject: [PATCH 04/30] [Bluetooth] Retrieve L2CAP features mask on connection
 setup

The Bluetooth 1.2 specification introduced a specific features mask
value to interoperate with newer versions of the specification. So far
this piece of information was never needed, but future extensions will
rely on it. This patch adds a generic way to retrieve this information
only once per connection setup.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/l2cap.h |  14 +-
 net/bluetooth/l2cap.c         | 233 ++++++++++++++++++++++------------
 2 files changed, 163 insertions(+), 84 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index f7bcd1f782cb..e1ea64085c4f 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -29,7 +29,8 @@
 #define L2CAP_DEFAULT_MTU	672
 #define L2CAP_DEFAULT_FLUSH_TO	0xFFFF
 
-#define L2CAP_CONN_TIMEOUT	(HZ * 40)
+#define L2CAP_CONN_TIMEOUT	(40000) /* 40 seconds */
+#define L2CAP_INFO_TIMEOUT	(4000)  /*  4 seconds */
 
 /* L2CAP socket address */
 struct sockaddr_l2 {
@@ -160,7 +161,6 @@ struct l2cap_disconn_rsp {
 
 struct l2cap_info_req {
 	__le16      type;
-	__u8        data[0];
 } __attribute__ ((packed));
 
 struct l2cap_info_rsp {
@@ -192,6 +192,13 @@ struct l2cap_conn {
 
 	unsigned int	mtu;
 
+	__u32		feat_mask;
+
+	__u8		info_state;
+	__u8		info_ident;
+
+	struct timer_list info_timer;
+
 	spinlock_t	lock;
 
 	struct sk_buff *rx_skb;
@@ -202,6 +209,9 @@ struct l2cap_conn {
 	struct l2cap_chan_list chan_list;
 };
 
+#define L2CAP_INFO_CL_MTU_REQ_SENT	0x01
+#define L2CAP_INFO_FEAT_MASK_REQ_SENT	0x02
+
 /* ----- L2CAP channel and socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
 
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index fde1606a4f31..896ae5a9c07a 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -258,7 +258,119 @@ static void l2cap_chan_del(struct sock *sk, int err)
 		sk->sk_state_change(sk);
 }
 
+static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
+{
+	u8 id;
+
+	/* Get next available identificator.
+	 *    1 - 128 are used by kernel.
+	 *  129 - 199 are reserved.
+	 *  200 - 254 are used by utilities like l2ping, etc.
+	 */
+
+	spin_lock_bh(&conn->lock);
+
+	if (++conn->tx_ident > 128)
+		conn->tx_ident = 1;
+
+	id = conn->tx_ident;
+
+	spin_unlock_bh(&conn->lock);
+
+	return id;
+}
+
+static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
+{
+	struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
+
+	BT_DBG("code 0x%2.2x", code);
+
+	if (!skb)
+		return -ENOMEM;
+
+	return hci_send_acl(conn->hcon, skb, 0);
+}
+
 /* ---- L2CAP connections ---- */
+static void l2cap_conn_start(struct l2cap_conn *conn)
+{
+	struct l2cap_chan_list *l = &conn->chan_list;
+	struct sock *sk;
+
+	BT_DBG("conn %p", conn);
+
+	read_lock(&l->lock);
+
+	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+		bh_lock_sock(sk);
+
+		if (sk->sk_type != SOCK_SEQPACKET) {
+			l2cap_sock_clear_timer(sk);
+			sk->sk_state = BT_CONNECTED;
+			sk->sk_state_change(sk);
+		} else if (sk->sk_state == BT_CONNECT) {
+			struct l2cap_conn_req req;
+			l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+			req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
+			req.psm  = l2cap_pi(sk)->psm;
+			l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+					L2CAP_CONN_REQ, sizeof(req), &req);
+		}
+
+		bh_unlock_sock(sk);
+	}
+
+	read_unlock(&l->lock);
+}
+
+static void l2cap_conn_ready(struct l2cap_conn *conn)
+{
+	BT_DBG("conn %p", conn);
+
+	if (conn->chan_list.head || !hlist_empty(&l2cap_sk_list.head)) {
+		struct l2cap_info_req req;
+
+		req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+
+		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
+		conn->info_ident = l2cap_get_ident(conn);
+
+		mod_timer(&conn->info_timer,
+			jiffies + msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+
+		l2cap_send_cmd(conn, conn->info_ident,
+					L2CAP_INFO_REQ, sizeof(req), &req);
+	}
+}
+
+/* Notify sockets that we cannot guaranty reliability anymore */
+static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
+{
+	struct l2cap_chan_list *l = &conn->chan_list;
+	struct sock *sk;
+
+	BT_DBG("conn %p", conn);
+
+	read_lock(&l->lock);
+
+	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+		if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
+			sk->sk_err = err;
+	}
+
+	read_unlock(&l->lock);
+}
+
+static void l2cap_info_timeout(unsigned long arg)
+{
+	struct l2cap_conn *conn = (void *) arg;
+
+	conn->info_ident = 0;
+
+	l2cap_conn_start(conn);
+}
+
 static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 {
 	struct l2cap_conn *conn = hcon->l2cap_data;
@@ -279,6 +391,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 	conn->src = &hcon->hdev->bdaddr;
 	conn->dst = &hcon->dst;
 
+	conn->feat_mask = 0;
+
+	init_timer(&conn->info_timer);
+	conn->info_timer.function = l2cap_info_timeout;
+	conn->info_timer.data = (unsigned long) conn;
+
 	spin_lock_init(&conn->lock);
 	rwlock_init(&conn->chan_list.lock);
 
@@ -318,40 +436,6 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, stru
 	write_unlock_bh(&l->lock);
 }
 
-static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
-{
-	u8 id;
-
-	/* Get next available identificator.
-	 *    1 - 128 are used by kernel.
-	 *  129 - 199 are reserved.
-	 *  200 - 254 are used by utilities like l2ping, etc.
-	 */
-
-	spin_lock_bh(&conn->lock);
-
-	if (++conn->tx_ident > 128)
-		conn->tx_ident = 1;
-
-	id = conn->tx_ident;
-
-	spin_unlock_bh(&conn->lock);
-
-	return id;
-}
-
-static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
-{
-	struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
-
-	BT_DBG("code 0x%2.2x", code);
-
-	if (!skb)
-		return -ENOMEM;
-
-	return hci_send_acl(conn->hcon, skb, 0);
-}
-
 /* ---- Socket interface ---- */
 static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
 {
@@ -529,7 +613,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
 	INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
 
 	sk->sk_destruct = l2cap_sock_destruct;
-	sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
+	sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
 
 	sock_reset_flag(sk, SOCK_ZAPPED);
 
@@ -649,6 +733,11 @@ static int l2cap_do_connect(struct sock *sk)
 	l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
 	if (hcon->state == BT_CONNECTED) {
+		if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)) {
+			l2cap_conn_ready(conn);
+			goto done;
+		}
+
 		if (sk->sk_type == SOCK_SEQPACKET) {
 			struct l2cap_conn_req req;
 			l2cap_pi(sk)->ident = l2cap_get_ident(conn);
@@ -1083,52 +1172,6 @@ static int l2cap_sock_release(struct socket *sock)
 	return err;
 }
 
-static void l2cap_conn_ready(struct l2cap_conn *conn)
-{
-	struct l2cap_chan_list *l = &conn->chan_list;
-	struct sock *sk;
-
-	BT_DBG("conn %p", conn);
-
-	read_lock(&l->lock);
-
-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-		bh_lock_sock(sk);
-
-		if (sk->sk_type != SOCK_SEQPACKET) {
-			l2cap_sock_clear_timer(sk);
-			sk->sk_state = BT_CONNECTED;
-			sk->sk_state_change(sk);
-		} else if (sk->sk_state == BT_CONNECT) {
-			struct l2cap_conn_req req;
-			l2cap_pi(sk)->ident = l2cap_get_ident(conn);
-			req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
-			req.psm  = l2cap_pi(sk)->psm;
-			l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONN_REQ, sizeof(req), &req);
-		}
-
-		bh_unlock_sock(sk);
-	}
-
-	read_unlock(&l->lock);
-}
-
-/* Notify sockets that we cannot guaranty reliability anymore */
-static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
-{
-	struct l2cap_chan_list *l = &conn->chan_list;
-	struct sock *sk;
-
-	BT_DBG("conn %p", conn);
-
-	read_lock(&l->lock);
-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-		if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
-			sk->sk_err = err;
-	}
-	read_unlock(&l->lock);
-}
-
 static void l2cap_chan_ready(struct sock *sk)
 {
 	struct sock *parent = bt_sk(sk)->parent;
@@ -1399,6 +1442,23 @@ static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 fla
 	return ptr - data;
 }
 
+static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+{
+	struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
+
+	if (rej->reason != 0x0000)
+		return 0;
+
+	if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
+					cmd->ident == conn->info_ident) {
+		conn->info_ident = 0;
+		del_timer(&conn->info_timer);
+		l2cap_conn_start(conn);
+	}
+
+	return 0;
+}
+
 static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
 {
 	struct l2cap_chan_list *list = &conn->chan_list;
@@ -1739,6 +1799,15 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
 	BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
 
+	conn->info_ident = 0;
+
+	del_timer(&conn->info_timer);
+
+	if (type == L2CAP_IT_FEAT_MASK)
+		conn->feat_mask = __le32_to_cpu(get_unaligned((__le32 *) rsp->data));
+
+	l2cap_conn_start(conn);
+
 	return 0;
 }
 
@@ -1768,7 +1837,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
 
 		switch (cmd.code) {
 		case L2CAP_COMMAND_REJ:
-			/* FIXME: We should process this */
+			l2cap_command_rej(conn, &cmd, data);
 			break;
 
 		case L2CAP_CONN_REQ:

From f0709e03ac3552b1b048ee171cb96ecaacc6813c Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 13:38:51 +0200
Subject: [PATCH 05/30] [Bluetooth] Advertise L2CAP features mask support

Indicate the support for the L2CAP features mask value when the remote
entity tries to negotiate Bluetooth 1.2 specific features.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 net/bluetooth/l2cap.c | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 896ae5a9c07a..733c95dbd07e 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -55,7 +55,9 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "2.8"
+#define VERSION "2.9"
+
+static u32 l2cap_feat_mask = 0x0000;
 
 static const struct proto_ops l2cap_sock_ops;
 
@@ -1775,16 +1777,27 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
 static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
 {
 	struct l2cap_info_req *req = (struct l2cap_info_req *) data;
-	struct l2cap_info_rsp rsp;
 	u16 type;
 
 	type = __le16_to_cpu(req->type);
 
 	BT_DBG("type 0x%4.4x", type);
 
-	rsp.type   = cpu_to_le16(type);
-	rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
-	l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp);
+	if (type == L2CAP_IT_FEAT_MASK) {
+		u8 buf[8];
+		struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
+		rsp->type   = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+		rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
+		put_unaligned(cpu_to_le32(l2cap_feat_mask), (__le32 *) rsp->data);
+		l2cap_send_cmd(conn, cmd->ident,
+					L2CAP_INFO_RSP, sizeof(buf), buf);
+	} else {
+		struct l2cap_info_rsp rsp;
+		rsp.type   = cpu_to_le16(type);
+		rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
+		l2cap_send_cmd(conn, cmd->ident,
+					L2CAP_INFO_RSP, sizeof(rsp), &rsp);
+	}
 
 	return 0;
 }

From 6464f35f3771f69cd8d107fff166dc29ab392f97 Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 13:39:51 +0200
Subject: [PATCH 06/30] [Bluetooth] Fall back to L2CAP in basic mode

In case the remote entity tries to negogiate retransmission or flow
control mode, reject it and fall back to basic mode.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/l2cap.h | 13 +++++++++++++
 net/bluetooth/l2cap.c         | 34 +++++++++++++++++++++++++---------
 2 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index e1ea64085c4f..73e115bc12dd 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -149,6 +149,19 @@ struct l2cap_conf_opt {
 
 #define L2CAP_CONF_MAX_SIZE	22
 
+struct l2cap_conf_rfc {
+	__u8       mode;
+	__u8       txwin_size;
+	__u8       max_transmit;
+	__le16     retrans_timeout;
+	__le16     monitor_timeout;
+	__le16     max_pdu_size;
+} __attribute__ ((packed));
+
+#define L2CAP_MODE_BASIC	0x00
+#define L2CAP_MODE_RETRANS	0x01
+#define L2CAP_MODE_FLOWCTL	0x02
+
 struct l2cap_disconn_req {
 	__le16     dcid;
 	__le16     scid;
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 733c95dbd07e..6fbbae78b304 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1048,7 +1048,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 		opts.imtu     = l2cap_pi(sk)->imtu;
 		opts.omtu     = l2cap_pi(sk)->omtu;
 		opts.flush_to = l2cap_pi(sk)->flush_to;
-		opts.mode     = 0x00;
+		opts.mode     = L2CAP_MODE_BASIC;
 
 		len = min_t(unsigned int, sizeof(opts), optlen);
 		if (copy_from_user((char *) &opts, optval, len)) {
@@ -1097,7 +1097,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 		opts.imtu     = l2cap_pi(sk)->imtu;
 		opts.omtu     = l2cap_pi(sk)->omtu;
 		opts.flush_to = l2cap_pi(sk)->flush_to;
-		opts.mode     = 0x00;
+		opts.mode     = L2CAP_MODE_BASIC;
 
 		len = min_t(unsigned int, len, sizeof(opts));
 		if (copy_to_user(optval, (char *) &opts, len))
@@ -1376,6 +1376,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
 	int len = pi->conf_len;
 	int type, hint, olen;
 	unsigned long val;
+	struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
 	u16 mtu = L2CAP_DEFAULT_MTU;
 	u16 result = L2CAP_CONF_SUCCESS;
 
@@ -1399,6 +1400,11 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
 		case L2CAP_CONF_QOS:
 			break;
 
+		case L2CAP_CONF_RFC:
+			if (olen == sizeof(rfc))
+				memcpy(&rfc, (void *) val, olen);
+			break;
+
 		default:
 			if (hint)
 				break;
@@ -1413,14 +1419,24 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
 		/* Configure output options and let the other side know
 		 * which ones we don't like. */
 
-		if (mtu < pi->omtu)
-			result = L2CAP_CONF_UNACCEPT;
-		else {
-			pi->omtu = mtu;
-			pi->conf_state |= L2CAP_CONF_OUTPUT_DONE;
-		}
+		if (rfc.mode == L2CAP_MODE_BASIC) {
+			if (mtu < pi->omtu)
+				result = L2CAP_CONF_UNACCEPT;
+			else {
+				pi->omtu = mtu;
+				pi->conf_state |= L2CAP_CONF_OUTPUT_DONE;
+			}
 
-		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
+			l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
+		} else {
+			result = L2CAP_CONF_UNACCEPT;
+
+			memset(&rfc, 0, sizeof(rfc));
+			rfc.mode = L2CAP_MODE_BASIC;
+
+			l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
+						sizeof(rfc), (unsigned long) &rfc);
+		}
 	}
 
 	rsp->scid   = cpu_to_le16(pi->dcid);

From e24b21ec85afda6f51b6bc403e971ff2aa7eacee Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 13:41:33 +0200
Subject: [PATCH 07/30] [Bluetooth] Change BPA 100/105 driver to use USB
 anchors

With the new support for USB anchors the driver can become more
simpler and also cleaner. This patch switches to the usage of USB
anchors for all URBs.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 drivers/bluetooth/bpa10x.c | 730 ++++++++++++++++---------------------
 1 file changed, 315 insertions(+), 415 deletions(-)

diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index e8ebd5d3de86..1375b5345a0a 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -2,7 +2,7 @@
  *
  *  Digianswer Bluetooth USB driver
  *
- *  Copyright (C) 2004-2005  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -21,13 +21,14 @@
  *
  */
 
-#include <linux/module.h>
-
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/sched.h>
 #include <linux/errno.h>
+#include <linux/skbuff.h>
 
 #include <linux/usb.h>
 
@@ -39,7 +40,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "0.8"
+#define VERSION "0.9"
 
 static int ignore = 0;
 
@@ -52,393 +53,285 @@ static struct usb_device_id bpa10x_table[] = {
 
 MODULE_DEVICE_TABLE(usb, bpa10x_table);
 
-#define BPA10X_CMD_EP		0x00
-#define BPA10X_EVT_EP		0x81
-#define BPA10X_TX_EP		0x02
-#define BPA10X_RX_EP		0x82
-
-#define BPA10X_CMD_BUF_SIZE	252
-#define BPA10X_EVT_BUF_SIZE	16
-#define BPA10X_TX_BUF_SIZE	384
-#define BPA10X_RX_BUF_SIZE	384
-
 struct bpa10x_data {
-	struct hci_dev		*hdev;
-	struct usb_device	*udev;
+	struct hci_dev    *hdev;
+	struct usb_device *udev;
 
-	rwlock_t		lock;
+	struct usb_anchor tx_anchor;
+	struct usb_anchor rx_anchor;
 
-	struct sk_buff_head	cmd_queue;
-	struct urb		*cmd_urb;
-	struct urb		*evt_urb;
-	struct sk_buff		*evt_skb;
-	unsigned int		evt_len;
-
-	struct sk_buff_head	tx_queue;
-	struct urb		*tx_urb;
-	struct urb		*rx_urb;
+	struct sk_buff *rx_skb[2];
 };
 
-#define HCI_VENDOR_HDR_SIZE	5
+#define HCI_VENDOR_HDR_SIZE 5
 
 struct hci_vendor_hdr {
-	__u8	type;
-	__le16	snum;
-	__le16	dlen;
+	__u8    type;
+	__le16  snum;
+	__le16  dlen;
 } __attribute__ ((packed));
 
-static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int count)
+static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
 {
-	struct hci_acl_hdr *ah;
-	struct hci_sco_hdr *sh;
-	struct hci_vendor_hdr *vh;
-	struct sk_buff *skb;
-	int len;
+	struct bpa10x_data *data = hdev->driver_data;
+
+	BT_DBG("%s queue %d buffer %p count %d", hdev->name,
+							queue, buf, count);
+
+	if (queue < 0 || queue > 1)
+		return -EILSEQ;
+
+	hdev->stat.byte_rx += count;
 
 	while (count) {
-		switch (*buf++) {
-		case HCI_ACLDATA_PKT:
-			ah = (struct hci_acl_hdr *) buf;
-			len = HCI_ACL_HDR_SIZE + __le16_to_cpu(ah->dlen);
-			skb = bt_skb_alloc(len, GFP_ATOMIC);
-			if (skb) {
-				memcpy(skb_put(skb, len), buf, len);
-				skb->dev = (void *) data->hdev;
-				bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
-				hci_recv_frame(skb);
-			}
-			break;
+		struct sk_buff *skb = data->rx_skb[queue];
+		struct { __u8 type; int expect; } *scb;
+		int type, len = 0;
 
-		case HCI_SCODATA_PKT:
-			sh = (struct hci_sco_hdr *) buf;
-			len = HCI_SCO_HDR_SIZE + sh->dlen;
-			skb = bt_skb_alloc(len, GFP_ATOMIC);
-			if (skb) {
-				memcpy(skb_put(skb, len), buf, len);
-				skb->dev = (void *) data->hdev;
-				bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
-				hci_recv_frame(skb);
-			}
-			break;
-
-		case HCI_VENDOR_PKT:
-			vh = (struct hci_vendor_hdr *) buf;
-			len = HCI_VENDOR_HDR_SIZE + __le16_to_cpu(vh->dlen);
-			skb = bt_skb_alloc(len, GFP_ATOMIC);
-			if (skb) {
-				memcpy(skb_put(skb, len), buf, len);
-				skb->dev = (void *) data->hdev;
-				bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
-				hci_recv_frame(skb);
-			}
-			break;
-
-		default:
-			len = count - 1;
-			break;
-		}
-
-		buf   += len;
-		count -= (len + 1);
-	}
-}
-
-static int bpa10x_recv_event(struct bpa10x_data *data, unsigned char *buf, int size)
-{
-	BT_DBG("data %p buf %p size %d", data, buf, size);
-
-	if (data->evt_skb) {
-		struct sk_buff *skb = data->evt_skb;
-
-		memcpy(skb_put(skb, size), buf, size);
-
-		if (skb->len == data->evt_len) {
-			data->evt_skb = NULL;
-			data->evt_len = 0;
-			hci_recv_frame(skb);
-		}
-	} else {
-		struct sk_buff *skb;
-		struct hci_event_hdr *hdr;
-		unsigned char pkt_type;
-		int pkt_len = 0;
-
-		if (size < HCI_EVENT_HDR_SIZE + 1) {
-			BT_ERR("%s event packet block with size %d is too short",
-							data->hdev->name, size);
-			return -EILSEQ;
-		}
-
-		pkt_type = *buf++;
-		size--;
-
-		if (pkt_type != HCI_EVENT_PKT) {
-			BT_ERR("%s unexpected event packet start byte 0x%02x",
-							data->hdev->name, pkt_type);
-			return -EPROTO;
-		}
-
-		hdr = (struct hci_event_hdr *) buf;
-		pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
-
-		skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
 		if (!skb) {
-			BT_ERR("%s no memory for new event packet",
-							data->hdev->name);
-			return -ENOMEM;
-		}
+			/* Start of the frame */
 
-		skb->dev = (void *) data->hdev;
-		bt_cb(skb)->pkt_type = pkt_type;
+			type = *((__u8 *) buf);
+			count--; buf++;
 
-		memcpy(skb_put(skb, size), buf, size);
+			switch (type) {
+			case HCI_EVENT_PKT:
+				if (count >= HCI_EVENT_HDR_SIZE) {
+					struct hci_event_hdr *h = buf;
+					len = HCI_EVENT_HDR_SIZE + h->plen;
+				} else
+					return -EILSEQ;
+				break;
 
-		if (pkt_len == size) {
-			hci_recv_frame(skb);
+			case HCI_ACLDATA_PKT:
+				if (count >= HCI_ACL_HDR_SIZE) {
+					struct hci_acl_hdr *h = buf;
+					len = HCI_ACL_HDR_SIZE +
+							__le16_to_cpu(h->dlen);
+				} else
+					return -EILSEQ;
+				break;
+
+			case HCI_SCODATA_PKT:
+				if (count >= HCI_SCO_HDR_SIZE) {
+					struct hci_sco_hdr *h = buf;
+					len = HCI_SCO_HDR_SIZE + h->dlen;
+				} else
+					return -EILSEQ;
+				break;
+
+			case HCI_VENDOR_PKT:
+				if (count >= HCI_VENDOR_HDR_SIZE) {
+					struct hci_vendor_hdr *h = buf;
+					len = HCI_VENDOR_HDR_SIZE +
+							__le16_to_cpu(h->dlen);
+				} else
+					return -EILSEQ;
+				break;
+			}
+
+			skb = bt_skb_alloc(len, GFP_ATOMIC);
+			if (!skb) {
+				BT_ERR("%s no memory for packet", hdev->name);
+				return -ENOMEM;
+			}
+
+			skb->dev = (void *) hdev;
+
+			data->rx_skb[queue] = skb;
+
+			scb = (void *) skb->cb;
+			scb->type = type;
+			scb->expect = len;
 		} else {
-			data->evt_skb = skb;
-			data->evt_len = pkt_len;
+			/* Continuation */
+
+			scb = (void *) skb->cb;
+			len = scb->expect;
 		}
+
+		len = min(len, count);
+
+		memcpy(skb_put(skb, len), buf, len);
+
+		scb->expect -= len;
+
+		if (scb->expect == 0) {
+			/* Complete frame */
+
+			data->rx_skb[queue] = NULL;
+
+			bt_cb(skb)->pkt_type = scb->type;
+			hci_recv_frame(skb);
+		}
+
+		count -= len; buf += len;
 	}
 
 	return 0;
 }
 
-static void bpa10x_wakeup(struct bpa10x_data *data)
+static void bpa10x_tx_complete(struct urb *urb)
 {
-	struct urb *urb;
-	struct sk_buff *skb;
+	struct sk_buff *skb = urb->context;
+	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+
+	BT_DBG("%s urb %p status %d count %d", hdev->name,
+					urb, urb->status, urb->actual_length);
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		goto done;
+
+	if (!urb->status)
+		hdev->stat.byte_tx += urb->transfer_buffer_length;
+	else
+		hdev->stat.err_tx++;
+
+done:
+	kfree(urb->setup_packet);
+
+	kfree_skb(skb);
+}
+
+static void bpa10x_rx_complete(struct urb *urb)
+{
+	struct hci_dev *hdev = urb->context;
+	struct bpa10x_data *data = hdev->driver_data;
 	int err;
 
-	BT_DBG("data %p", data);
+	BT_DBG("%s urb %p status %d count %d", hdev->name,
+					urb, urb->status, urb->actual_length);
 
-	urb = data->cmd_urb;
-	if (urb->status == -EINPROGRESS)
-		skb = NULL;
-	else
-		skb = skb_dequeue(&data->cmd_queue);
-
-	if (skb) {
-		struct usb_ctrlrequest *cr;
-
-		if (skb->len > BPA10X_CMD_BUF_SIZE) {
-			BT_ERR("%s command packet with size %d is too big",
-							data->hdev->name, skb->len);
-			kfree_skb(skb);
-			return;
-		}
-
-		cr = (struct usb_ctrlrequest *) urb->setup_packet;
-		cr->wLength = __cpu_to_le16(skb->len);
-
-		skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len);
-		urb->transfer_buffer_length = skb->len;
-
-		err = usb_submit_urb(urb, GFP_ATOMIC);
-		if (err < 0 && err != -ENODEV) {
-			BT_ERR("%s submit failed for command urb %p with error %d",
-							data->hdev->name, urb, err);
-			skb_queue_head(&data->cmd_queue, skb);
-		} else
-			kfree_skb(skb);
-	}
-
-	urb = data->tx_urb;
-	if (urb->status == -EINPROGRESS)
-		skb = NULL;
-	else
-		skb = skb_dequeue(&data->tx_queue);
-
-	if (skb) {
-		skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len);
-		urb->transfer_buffer_length = skb->len;
-
-		err = usb_submit_urb(urb, GFP_ATOMIC);
-		if (err < 0 && err != -ENODEV) {
-			BT_ERR("%s submit failed for command urb %p with error %d",
-							data->hdev->name, urb, err);
-			skb_queue_head(&data->tx_queue, skb);
-		} else
-			kfree_skb(skb);
-	}
-}
-
-static void bpa10x_complete(struct urb *urb)
-{
-	struct bpa10x_data *data = urb->context;
-	unsigned char *buf = urb->transfer_buffer;
-	int err, count = urb->actual_length;
-
-	BT_DBG("data %p urb %p buf %p count %d", data, urb, buf, count);
-
-	read_lock(&data->lock);
-
-	if (!test_bit(HCI_RUNNING, &data->hdev->flags))
-		goto unlock;
-
-	if (urb->status < 0 || !count)
-		goto resubmit;
-
-	if (usb_pipein(urb->pipe)) {
-		data->hdev->stat.byte_rx += count;
-
-		if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)
-			bpa10x_recv_event(data, buf, count);
-
-		if (usb_pipetype(urb->pipe) == PIPE_BULK)
-			bpa10x_recv_bulk(data, buf, count);
-	} else {
-		data->hdev->stat.byte_tx += count;
-
-		bpa10x_wakeup(data);
-	}
-
-resubmit:
-	if (usb_pipein(urb->pipe)) {
-		err = usb_submit_urb(urb, GFP_ATOMIC);
-		if (err < 0 && err != -ENODEV) {
-			BT_ERR("%s urb %p type %d resubmit status %d",
-				data->hdev->name, urb, usb_pipetype(urb->pipe), err);
-		}
-	}
-
-unlock:
-	read_unlock(&data->lock);
-}
-
-static inline struct urb *bpa10x_alloc_urb(struct usb_device *udev, unsigned int pipe,
-					size_t size, gfp_t flags, void *data)
-{
-	struct urb *urb;
-	struct usb_ctrlrequest *cr;
-	unsigned char *buf;
-
-	BT_DBG("udev %p data %p", udev, data);
-
-	urb = usb_alloc_urb(0, flags);
-	if (!urb)
-		return NULL;
-
-	buf = kmalloc(size, flags);
-	if (!buf) {
-		usb_free_urb(urb);
-		return NULL;
-	}
-
-	switch (usb_pipetype(pipe)) {
-	case PIPE_CONTROL:
-		cr = kmalloc(sizeof(*cr), flags);
-		if (!cr) {
-			kfree(buf);
-			usb_free_urb(urb);
-			return NULL;
-		}
-
-		cr->bRequestType = USB_TYPE_VENDOR;
-		cr->bRequest     = 0;
-		cr->wIndex       = 0;
-		cr->wValue       = 0;
-		cr->wLength      = __cpu_to_le16(0);
-
-		usb_fill_control_urb(urb, udev, pipe, (void *) cr, buf, 0, bpa10x_complete, data);
-		break;
-
-	case PIPE_INTERRUPT:
-		usb_fill_int_urb(urb, udev, pipe, buf, size, bpa10x_complete, data, 1);
-		break;
-
-	case PIPE_BULK:
-		usb_fill_bulk_urb(urb, udev, pipe, buf, size, bpa10x_complete, data);
-		break;
-
-	default:
-		kfree(buf);
-		usb_free_urb(urb);
-		return NULL;
-	}
-
-	return urb;
-}
-
-static inline void bpa10x_free_urb(struct urb *urb)
-{
-	BT_DBG("urb %p", urb);
-
-	if (!urb)
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return;
 
-	kfree(urb->setup_packet);
-	kfree(urb->transfer_buffer);
+	if (urb->status == 0) {
+		if (bpa10x_recv(hdev, usb_pipebulk(urb->pipe),
+						urb->transfer_buffer,
+						urb->actual_length) < 0) {
+			BT_ERR("%s corrupted event packet", hdev->name);
+			hdev->stat.err_rx++;
+		}
+	}
+
+	usb_anchor_urb(urb, &data->rx_anchor);
+
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err < 0) {
+		BT_ERR("%s urb %p failed to resubmit (%d)",
+						hdev->name, urb, -err);
+		usb_unanchor_urb(urb);
+	}
+}
+
+static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
+{
+	struct bpa10x_data *data = hdev->driver_data;
+	struct urb *urb;
+	unsigned char *buf;
+	unsigned int pipe;
+	int err, size = 16;
+
+	BT_DBG("%s", hdev->name);
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb)
+		return -ENOMEM;
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf) {
+		usb_free_urb(urb);
+		return -ENOMEM;
+	}
+
+	pipe = usb_rcvintpipe(data->udev, 0x81);
+
+	usb_fill_int_urb(urb, data->udev, pipe, buf, size,
+						bpa10x_rx_complete, hdev, 1);
+
+	urb->transfer_flags |= URB_FREE_BUFFER;
+
+	usb_anchor_urb(urb, &data->rx_anchor);
+
+	err = usb_submit_urb(urb, GFP_KERNEL);
+	if (err < 0) {
+		BT_ERR("%s urb %p submission failed (%d)",
+						hdev->name, urb, -err);
+		usb_unanchor_urb(urb);
+		kfree(buf);
+	}
 
 	usb_free_urb(urb);
+
+	return err;
+}
+
+static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
+{
+	struct bpa10x_data *data = hdev->driver_data;
+	struct urb *urb;
+	unsigned char *buf;
+	unsigned int pipe;
+	int err, size = 64;
+
+	BT_DBG("%s", hdev->name);
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb)
+		return -ENOMEM;
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf) {
+		usb_free_urb(urb);
+		return -ENOMEM;
+	}
+
+	pipe = usb_rcvbulkpipe(data->udev, 0x82);
+
+	usb_fill_bulk_urb(urb, data->udev, pipe,
+					buf, size, bpa10x_rx_complete, hdev);
+
+	urb->transfer_flags |= URB_FREE_BUFFER;
+
+	usb_anchor_urb(urb, &data->rx_anchor);
+
+	err = usb_submit_urb(urb, GFP_KERNEL);
+	if (err < 0) {
+		BT_ERR("%s urb %p submission failed (%d)",
+						hdev->name, urb, -err);
+		usb_unanchor_urb(urb);
+		kfree(buf);
+	}
+
+	usb_free_urb(urb);
+
+	return err;
 }
 
 static int bpa10x_open(struct hci_dev *hdev)
 {
 	struct bpa10x_data *data = hdev->driver_data;
-	struct usb_device *udev = data->udev;
-	unsigned long flags;
 	int err;
 
-	BT_DBG("hdev %p data %p", hdev, data);
+	BT_DBG("%s", hdev->name);
 
 	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
 
-	data->cmd_urb = bpa10x_alloc_urb(udev, usb_sndctrlpipe(udev, BPA10X_CMD_EP),
-					BPA10X_CMD_BUF_SIZE, GFP_KERNEL, data);
-	if (!data->cmd_urb) {
-		err = -ENOMEM;
-		goto done;
-	}
-
-	data->evt_urb = bpa10x_alloc_urb(udev, usb_rcvintpipe(udev, BPA10X_EVT_EP),
-					BPA10X_EVT_BUF_SIZE, GFP_KERNEL, data);
-	if (!data->evt_urb) {
-		bpa10x_free_urb(data->cmd_urb);
-		err = -ENOMEM;
-		goto done;
-	}
-
-	data->rx_urb = bpa10x_alloc_urb(udev, usb_rcvbulkpipe(udev, BPA10X_RX_EP),
-					BPA10X_RX_BUF_SIZE, GFP_KERNEL, data);
-	if (!data->rx_urb) {
-		bpa10x_free_urb(data->evt_urb);
-		bpa10x_free_urb(data->cmd_urb);
-		err = -ENOMEM;
-		goto done;
-	}
-
-	data->tx_urb = bpa10x_alloc_urb(udev, usb_sndbulkpipe(udev, BPA10X_TX_EP),
-					BPA10X_TX_BUF_SIZE, GFP_KERNEL, data);
-	if (!data->rx_urb) {
-		bpa10x_free_urb(data->rx_urb);
-		bpa10x_free_urb(data->evt_urb);
-		bpa10x_free_urb(data->cmd_urb);
-		err = -ENOMEM;
-		goto done;
-	}
-
-	write_lock_irqsave(&data->lock, flags);
-
-	err = usb_submit_urb(data->evt_urb, GFP_ATOMIC);
-	if (err < 0) {
-		BT_ERR("%s submit failed for event urb %p with error %d",
-					data->hdev->name, data->evt_urb, err);
-	} else {
-		err = usb_submit_urb(data->rx_urb, GFP_ATOMIC);
-		if (err < 0) {
-			BT_ERR("%s submit failed for rx urb %p with error %d",
-					data->hdev->name, data->evt_urb, err);
-			usb_kill_urb(data->evt_urb);
-		}
-	}
-
-	write_unlock_irqrestore(&data->lock, flags);
-
-done:
+	err = bpa10x_submit_intr_urb(hdev);
 	if (err < 0)
-		clear_bit(HCI_RUNNING, &hdev->flags);
+		goto error;
+
+	err = bpa10x_submit_bulk_urb(hdev);
+	if (err < 0)
+		goto error;
+
+	return 0;
+
+error:
+	usb_kill_anchored_urbs(&data->rx_anchor);
+
+	clear_bit(HCI_RUNNING, &hdev->flags);
 
 	return err;
 }
@@ -446,27 +339,13 @@ done:
 static int bpa10x_close(struct hci_dev *hdev)
 {
 	struct bpa10x_data *data = hdev->driver_data;
-	unsigned long flags;
 
-	BT_DBG("hdev %p data %p", hdev, data);
+	BT_DBG("%s", hdev->name);
 
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
 
-	write_lock_irqsave(&data->lock, flags);
-
-	skb_queue_purge(&data->cmd_queue);
-	usb_kill_urb(data->cmd_urb);
-	usb_kill_urb(data->evt_urb);
-	usb_kill_urb(data->rx_urb);
-	usb_kill_urb(data->tx_urb);
-
-	write_unlock_irqrestore(&data->lock, flags);
-
-	bpa10x_free_urb(data->cmd_urb);
-	bpa10x_free_urb(data->evt_urb);
-	bpa10x_free_urb(data->rx_urb);
-	bpa10x_free_urb(data->tx_urb);
+	usb_kill_anchored_urbs(&data->rx_anchor);
 
 	return 0;
 }
@@ -475,9 +354,9 @@ static int bpa10x_flush(struct hci_dev *hdev)
 {
 	struct bpa10x_data *data = hdev->driver_data;
 
-	BT_DBG("hdev %p data %p", hdev, data);
+	BT_DBG("%s", hdev->name);
 
-	skb_queue_purge(&data->cmd_queue);
+	usb_kill_anchored_urbs(&data->tx_anchor);
 
 	return 0;
 }
@@ -485,45 +364,78 @@ static int bpa10x_flush(struct hci_dev *hdev)
 static int bpa10x_send_frame(struct sk_buff *skb)
 {
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-	struct bpa10x_data *data;
+	struct bpa10x_data *data = hdev->driver_data;
+	struct usb_ctrlrequest *dr;
+	struct urb *urb;
+	unsigned int pipe;
+	int err;
 
-	BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, bt_cb(skb)->pkt_type, skb->len);
-
-	if (!hdev) {
-		BT_ERR("Frame for unknown HCI device");
-		return -ENODEV;
-	}
+	BT_DBG("%s", hdev->name);
 
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return -EBUSY;
 
-	data = hdev->driver_data;
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb)
+		return -ENOMEM;
 
 	/* Prepend skb with frame type */
-	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+	*skb_push(skb, 1) = bt_cb(skb)->pkt_type;
 
 	switch (bt_cb(skb)->pkt_type) {
 	case HCI_COMMAND_PKT:
+		dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
+		if (!dr) {
+			usb_free_urb(urb);
+			return -ENOMEM;
+		}
+
+		dr->bRequestType = USB_TYPE_VENDOR;
+		dr->bRequest     = 0;
+		dr->wIndex       = 0;
+		dr->wValue       = 0;
+		dr->wLength      = __cpu_to_le16(skb->len);
+
+		pipe = usb_sndctrlpipe(data->udev, 0x00);
+
+		usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
+				skb->data, skb->len, bpa10x_tx_complete, skb);
+
 		hdev->stat.cmd_tx++;
-		skb_queue_tail(&data->cmd_queue, skb);
 		break;
 
 	case HCI_ACLDATA_PKT:
+		pipe = usb_sndbulkpipe(data->udev, 0x02);
+
+		usb_fill_bulk_urb(urb, data->udev, pipe,
+				skb->data, skb->len, bpa10x_tx_complete, skb);
+
 		hdev->stat.acl_tx++;
-		skb_queue_tail(&data->tx_queue, skb);
 		break;
 
 	case HCI_SCODATA_PKT:
+		pipe = usb_sndbulkpipe(data->udev, 0x02);
+
+		usb_fill_bulk_urb(urb, data->udev, pipe,
+				skb->data, skb->len, bpa10x_tx_complete, skb);
+
 		hdev->stat.sco_tx++;
-		skb_queue_tail(&data->tx_queue, skb);
 		break;
-	};
 
-	read_lock(&data->lock);
+	default:
+		return -EILSEQ;
+	}
 
-	bpa10x_wakeup(data);
+	usb_anchor_urb(urb, &data->tx_anchor);
 
-	read_unlock(&data->lock);
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err < 0) {
+		BT_ERR("%s urb %p submission failed", hdev->name, urb);
+		kfree(urb->setup_packet);
+		usb_unanchor_urb(urb);
+	}
+
+	usb_free_urb(urb);
 
 	return 0;
 }
@@ -532,16 +444,17 @@ static void bpa10x_destruct(struct hci_dev *hdev)
 {
 	struct bpa10x_data *data = hdev->driver_data;
 
-	BT_DBG("hdev %p data %p", hdev, data);
+	BT_DBG("%s", hdev->name);
 
+	kfree(data->rx_skb[0]);
+	kfree(data->rx_skb[1]);
 	kfree(data);
 }
 
 static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct hci_dev *hdev;
 	struct bpa10x_data *data;
+	struct hci_dev *hdev;
 	int err;
 
 	BT_DBG("intf %p id %p", intf, id);
@@ -549,48 +462,43 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
 	if (ignore)
 		return -ENODEV;
 
-	if (intf->cur_altsetting->desc.bInterfaceNumber > 0)
+	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
 		return -ENODEV;
 
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		BT_ERR("Can't allocate data structure");
+	if (!data)
 		return -ENOMEM;
-	}
 
-	data->udev = udev;
+	data->udev = interface_to_usbdev(intf);
 
-	rwlock_init(&data->lock);
-
-	skb_queue_head_init(&data->cmd_queue);
-	skb_queue_head_init(&data->tx_queue);
+	init_usb_anchor(&data->tx_anchor);
+	init_usb_anchor(&data->rx_anchor);
 
 	hdev = hci_alloc_dev();
 	if (!hdev) {
-		BT_ERR("Can't allocate HCI device");
 		kfree(data);
 		return -ENOMEM;
 	}
 
-	data->hdev = hdev;
-
 	hdev->type = HCI_USB;
 	hdev->driver_data = data;
+
+	data->hdev = hdev;
+
 	SET_HCIDEV_DEV(hdev, &intf->dev);
 
-	hdev->open	= bpa10x_open;
-	hdev->close	= bpa10x_close;
-	hdev->flush	= bpa10x_flush;
-	hdev->send	= bpa10x_send_frame;
-	hdev->destruct	= bpa10x_destruct;
+	hdev->open     = bpa10x_open;
+	hdev->close    = bpa10x_close;
+	hdev->flush    = bpa10x_flush;
+	hdev->send     = bpa10x_send_frame;
+	hdev->destruct = bpa10x_destruct;
 
 	hdev->owner = THIS_MODULE;
 
 	err = hci_register_dev(hdev);
 	if (err < 0) {
-		BT_ERR("Can't register HCI device");
-		kfree(data);
 		hci_free_dev(hdev);
+		kfree(data);
 		return err;
 	}
 
@@ -602,19 +510,17 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
 static void bpa10x_disconnect(struct usb_interface *intf)
 {
 	struct bpa10x_data *data = usb_get_intfdata(intf);
-	struct hci_dev *hdev = data->hdev;
 
 	BT_DBG("intf %p", intf);
 
-	if (!hdev)
+	if (!data)
 		return;
 
 	usb_set_intfdata(intf, NULL);
 
-	if (hci_unregister_dev(hdev) < 0)
-		BT_ERR("Can't unregister HCI device %s", hdev->name);
+	hci_unregister_dev(data->hdev);
 
-	hci_free_dev(hdev);
+	hci_free_dev(data->hdev);
 }
 
 static struct usb_driver bpa10x_driver = {
@@ -626,15 +532,9 @@ static struct usb_driver bpa10x_driver = {
 
 static int __init bpa10x_init(void)
 {
-	int err;
-
 	BT_INFO("Digianswer Bluetooth USB driver ver %s", VERSION);
 
-	err = usb_register(&bpa10x_driver);
-	if (err < 0)
-		BT_ERR("Failed to register USB driver");
-
-	return err;
+	return usb_register(&bpa10x_driver);
 }
 
 static void __exit bpa10x_exit(void)

From 166d2f6a4332aad53cb0750a296f76c06102552d Mon Sep 17 00:00:00 2001
From: Ohad Ben-Cohen <ohad@bencohen.org>
Date: Sat, 20 Oct 2007 13:42:36 +0200
Subject: [PATCH 08/30] [Bluetooth] Add UART driver for Texas Instruments'
 BRF63xx chips

Add support for Texas Instruments' HCI Low Level (HCILL) Bluetooth
protocol, which is a power management extension to H4. The HCILL is
widely used by TI's BRF63xx Bluetooth chips.

Signed-off-by: Ohad Ben-Cohen <ohad@bencohen.org>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 drivers/bluetooth/Kconfig     |  11 +
 drivers/bluetooth/Makefile    |   1 +
 drivers/bluetooth/hci_ldisc.c |   8 +-
 drivers/bluetooth/hci_ll.c    | 531 ++++++++++++++++++++++++++++++++++
 drivers/bluetooth/hci_uart.h  |   8 +-
 5 files changed, 557 insertions(+), 2 deletions(-)
 create mode 100644 drivers/bluetooth/hci_ll.c

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index b9fbe6e7f9ae..62b89b95ace2 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -55,6 +55,17 @@ config BT_HCIUART_BCSP
 
 	  Say Y here to compile support for HCI BCSP protocol.
 
+config BT_HCIUART_LL
+	bool "HCILL protocol support"
+	depends on BT_HCIUART
+	help
+	  HCILL (HCI Low Level) is a serial protocol for communication
+	  between Bluetooth device and host. This protocol is required for
+	  serial Bluetooth devices that are based on Texas Instruments'
+	  BRF chips.
+
+	  Say Y here to compile support for HCILL protocol.
+
 config BT_HCIBCM203X
 	tristate "HCI BCM203x USB driver"
 	depends on USB
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 08c10e178e02..a543dfc2d6f5 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -16,4 +16,5 @@ obj-$(CONFIG_BT_HCIBTUART)	+= btuart_cs.o
 hci_uart-y				:= hci_ldisc.o
 hci_uart-$(CONFIG_BT_HCIUART_H4)	+= hci_h4.o
 hci_uart-$(CONFIG_BT_HCIUART_BCSP)	+= hci_bcsp.o
+hci_uart-$(CONFIG_BT_HCIUART_LL)	+= hci_ll.o
 hci_uart-objs				:= $(hci_uart-y)
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 6055b9c0ac0f..e68821d074b0 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -549,7 +549,10 @@ static int __init hci_uart_init(void)
 #ifdef CONFIG_BT_HCIUART_BCSP
 	bcsp_init();
 #endif
-	
+#ifdef CONFIG_BT_HCIUART_LL
+	ll_init();
+#endif
+
 	return 0;
 }
 
@@ -563,6 +566,9 @@ static void __exit hci_uart_exit(void)
 #ifdef CONFIG_BT_HCIUART_BCSP
 	bcsp_deinit();
 #endif
+#ifdef CONFIG_BT_HCIUART_LL
+	ll_deinit();
+#endif
 
 	/* Release tty registration of line discipline */
 	if ((err = tty_unregister_ldisc(N_HCI)))
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
new file mode 100644
index 000000000000..8c3e62a17b4a
--- /dev/null
+++ b/drivers/bluetooth/hci_ll.c
@@ -0,0 +1,531 @@
+/*
+ *  Texas Instruments' Bluetooth HCILL UART protocol
+ *
+ *  HCILL (HCI Low Level) is a Texas Instruments' power management
+ *  protocol extension to H4.
+ *
+ *  Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ *  Written by Ohad Ben-Cohen <ohad@bencohen.org>
+ *
+ *  Acknowledgements:
+ *  This file is based on hci_h4.c, which was written
+ *  by Maxim Krasnyansky and Marcel Holtmann.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/poll.h>
+
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+/* HCILL commands */
+#define HCILL_GO_TO_SLEEP_IND	0x30
+#define HCILL_GO_TO_SLEEP_ACK	0x31
+#define HCILL_WAKE_UP_IND	0x32
+#define HCILL_WAKE_UP_ACK	0x33
+
+/* HCILL receiver States */
+#define HCILL_W4_PACKET_TYPE	0
+#define HCILL_W4_EVENT_HDR	1
+#define HCILL_W4_ACL_HDR	2
+#define HCILL_W4_SCO_HDR	3
+#define HCILL_W4_DATA		4
+
+/* HCILL states */
+enum hcill_states_e {
+	HCILL_ASLEEP,
+	HCILL_ASLEEP_TO_AWAKE,
+	HCILL_AWAKE,
+	HCILL_AWAKE_TO_ASLEEP
+};
+
+struct hcill_cmd {
+	u8 cmd;
+} __attribute__((packed));
+
+struct ll_struct {
+	unsigned long rx_state;
+	unsigned long rx_count;
+	struct sk_buff *rx_skb;
+	struct sk_buff_head txq;
+	spinlock_t hcill_lock;		/* HCILL state lock	*/
+	unsigned long hcill_state;	/* HCILL power state	*/
+	struct sk_buff_head tx_wait_q;	/* HCILL wait queue	*/
+};
+
+/*
+ * Builds and sends an HCILL command packet.
+ * These are very simple packets with only 1 cmd byte
+ */
+static int send_hcill_cmd(u8 cmd, struct hci_uart *hu)
+{
+	int err = 0;
+	struct sk_buff *skb = NULL;
+	struct ll_struct *ll = hu->priv;
+	struct hcill_cmd *hcill_packet;
+
+	BT_DBG("hu %p cmd 0x%x", hu, cmd);
+
+	/* allocate packet */
+	skb = bt_skb_alloc(1, GFP_ATOMIC);
+	if (!skb) {
+		BT_ERR("cannot allocate memory for HCILL packet");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* prepare packet */
+	hcill_packet = (struct hcill_cmd *) skb_put(skb, 1);
+	hcill_packet->cmd = cmd;
+	skb->dev = (void *) hu->hdev;
+
+	/* send packet */
+	skb_queue_tail(&ll->txq, skb);
+out:
+	return err;
+}
+
+/* Initialize protocol */
+static int ll_open(struct hci_uart *hu)
+{
+	struct ll_struct *ll;
+
+	BT_DBG("hu %p", hu);
+
+	ll = kzalloc(sizeof(*ll), GFP_ATOMIC);
+	if (!ll)
+		return -ENOMEM;
+
+	skb_queue_head_init(&ll->txq);
+	skb_queue_head_init(&ll->tx_wait_q);
+	spin_lock_init(&ll->hcill_lock);
+
+	ll->hcill_state = HCILL_AWAKE;
+
+	hu->priv = ll;
+
+	return 0;
+}
+
+/* Flush protocol data */
+static int ll_flush(struct hci_uart *hu)
+{
+	struct ll_struct *ll = hu->priv;
+
+	BT_DBG("hu %p", hu);
+
+	skb_queue_purge(&ll->tx_wait_q);
+	skb_queue_purge(&ll->txq);
+
+	return 0;
+}
+
+/* Close protocol */
+static int ll_close(struct hci_uart *hu)
+{
+	struct ll_struct *ll = hu->priv;
+
+	BT_DBG("hu %p", hu);
+
+	skb_queue_purge(&ll->tx_wait_q);
+	skb_queue_purge(&ll->txq);
+
+	if (ll->rx_skb)
+		kfree_skb(ll->rx_skb);
+
+	hu->priv = NULL;
+
+	kfree(ll);
+
+	return 0;
+}
+
+/*
+ * internal function, which does common work of the device wake up process:
+ * 1. places all pending packets (waiting in tx_wait_q list) in txq list.
+ * 2. changes internal state to HCILL_AWAKE.
+ * Note: assumes that hcill_lock spinlock is taken,
+ * shouldn't be called otherwise!
+ */
+static void __ll_do_awake(struct ll_struct *ll)
+{
+	struct sk_buff *skb = NULL;
+
+	while ((skb = skb_dequeue(&ll->tx_wait_q)))
+		skb_queue_tail(&ll->txq, skb);
+
+	ll->hcill_state = HCILL_AWAKE;
+}
+
+/*
+ * Called upon a wake-up-indication from the device
+ */
+static void ll_device_want_to_wakeup(struct hci_uart *hu)
+{
+	unsigned long flags;
+	struct ll_struct *ll = hu->priv;
+
+	BT_DBG("hu %p", hu);
+
+	/* lock hcill state */
+	spin_lock_irqsave(&ll->hcill_lock, flags);
+
+	switch (ll->hcill_state) {
+	case HCILL_ASLEEP:
+		/* acknowledge device wake up */
+		if (send_hcill_cmd(HCILL_WAKE_UP_ACK, hu) < 0) {
+			BT_ERR("cannot acknowledge device wake up");
+			goto out;
+		}
+		break;
+	case HCILL_ASLEEP_TO_AWAKE:
+		/*
+		 * this state means that a wake-up-indication
+		 * is already on its way to the device,
+		 * and will serve as the required wake-up-ack
+		 */
+		BT_DBG("dual wake-up-indication");
+		break;
+	default:
+		/* any other state are illegal */
+		BT_ERR("received HCILL_WAKE_UP_IND in state %ld", ll->hcill_state);
+		break;
+	}
+
+	/* send pending packets and change state to HCILL_AWAKE */
+	__ll_do_awake(ll);
+
+out:
+	spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+	/* actually send the packets */
+	hci_uart_tx_wakeup(hu);
+}
+
+/*
+ * Called upon a sleep-indication from the device
+ */
+static void ll_device_want_to_sleep(struct hci_uart *hu)
+{
+	unsigned long flags;
+	struct ll_struct *ll = hu->priv;
+
+	BT_DBG("hu %p", hu);
+
+	/* lock hcill state */
+	spin_lock_irqsave(&ll->hcill_lock, flags);
+
+	/* sanity check */
+	if (ll->hcill_state != HCILL_AWAKE)
+		BT_ERR("ERR: HCILL_GO_TO_SLEEP_IND in state %ld", ll->hcill_state);
+
+	/* acknowledge device sleep */
+	if (send_hcill_cmd(HCILL_GO_TO_SLEEP_ACK, hu) < 0) {
+		BT_ERR("cannot acknowledge device sleep");
+		goto out;
+	}
+
+	/* update state */
+	ll->hcill_state = HCILL_ASLEEP;
+
+out:
+	spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+	/* actually send the sleep ack packet */
+	hci_uart_tx_wakeup(hu);
+}
+
+/*
+ * Called upon wake-up-acknowledgement from the device
+ */
+static void ll_device_woke_up(struct hci_uart *hu)
+{
+	unsigned long flags;
+	struct ll_struct *ll = hu->priv;
+
+	BT_DBG("hu %p", hu);
+
+	/* lock hcill state */
+	spin_lock_irqsave(&ll->hcill_lock, flags);
+
+	/* sanity check */
+	if (ll->hcill_state != HCILL_ASLEEP_TO_AWAKE)
+		BT_ERR("received HCILL_WAKE_UP_ACK in state %ld", ll->hcill_state);
+
+	/* send pending packets and change state to HCILL_AWAKE */
+	__ll_do_awake(ll);
+
+	spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+	/* actually send the packets */
+	hci_uart_tx_wakeup(hu);
+}
+
+/* Enqueue frame for transmittion (padding, crc, etc) */
+/* may be called from two simultaneous tasklets */
+static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+	unsigned long flags = 0;
+	struct ll_struct *ll = hu->priv;
+
+	BT_DBG("hu %p skb %p", hu, skb);
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+	/* lock hcill state */
+	spin_lock_irqsave(&ll->hcill_lock, flags);
+
+	/* act according to current state */
+	switch (ll->hcill_state) {
+	case HCILL_AWAKE:
+		BT_DBG("device awake, sending normally");
+		skb_queue_tail(&ll->txq, skb);
+		break;
+	case HCILL_ASLEEP:
+		BT_DBG("device asleep, waking up and queueing packet");
+		/* save packet for later */
+		skb_queue_tail(&ll->tx_wait_q, skb);
+		/* awake device */
+		if (send_hcill_cmd(HCILL_WAKE_UP_IND, hu) < 0) {
+			BT_ERR("cannot wake up device");
+			break;
+		}
+		ll->hcill_state = HCILL_ASLEEP_TO_AWAKE;
+		break;
+	case HCILL_ASLEEP_TO_AWAKE:
+		BT_DBG("device waking up, queueing packet");
+		/* transient state; just keep packet for later */
+		skb_queue_tail(&ll->tx_wait_q, skb);
+		break;
+	default:
+		BT_ERR("illegal hcill state: %ld (losing packet)", ll->hcill_state);
+		kfree_skb(skb);
+		break;
+	}
+
+	spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+	return 0;
+}
+
+static inline int ll_check_data_len(struct ll_struct *ll, int len)
+{
+	register int room = skb_tailroom(ll->rx_skb);
+
+	BT_DBG("len %d room %d", len, room);
+
+	if (!len) {
+		hci_recv_frame(ll->rx_skb);
+	} else if (len > room) {
+		BT_ERR("Data length is too large");
+		kfree_skb(ll->rx_skb);
+	} else {
+		ll->rx_state = HCILL_W4_DATA;
+		ll->rx_count = len;
+		return len;
+	}
+
+	ll->rx_state = HCILL_W4_PACKET_TYPE;
+	ll->rx_skb   = NULL;
+	ll->rx_count = 0;
+
+	return 0;
+}
+
+/* Recv data */
+static int ll_recv(struct hci_uart *hu, void *data, int count)
+{
+	struct ll_struct *ll = hu->priv;
+	register char *ptr;
+	struct hci_event_hdr *eh;
+	struct hci_acl_hdr   *ah;
+	struct hci_sco_hdr   *sh;
+	register int len, type, dlen;
+
+	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count);
+
+	ptr = data;
+	while (count) {
+		if (ll->rx_count) {
+			len = min_t(unsigned int, ll->rx_count, count);
+			memcpy(skb_put(ll->rx_skb, len), ptr, len);
+			ll->rx_count -= len; count -= len; ptr += len;
+
+			if (ll->rx_count)
+				continue;
+
+			switch (ll->rx_state) {
+			case HCILL_W4_DATA:
+				BT_DBG("Complete data");
+				hci_recv_frame(ll->rx_skb);
+
+				ll->rx_state = HCILL_W4_PACKET_TYPE;
+				ll->rx_skb = NULL;
+				continue;
+
+			case HCILL_W4_EVENT_HDR:
+				eh = (struct hci_event_hdr *) ll->rx_skb->data;
+
+				BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
+
+				ll_check_data_len(ll, eh->plen);
+				continue;
+
+			case HCILL_W4_ACL_HDR:
+				ah = (struct hci_acl_hdr *) ll->rx_skb->data;
+				dlen = __le16_to_cpu(ah->dlen);
+
+				BT_DBG("ACL header: dlen %d", dlen);
+
+				ll_check_data_len(ll, dlen);
+				continue;
+
+			case HCILL_W4_SCO_HDR:
+				sh = (struct hci_sco_hdr *) ll->rx_skb->data;
+
+				BT_DBG("SCO header: dlen %d", sh->dlen);
+
+				ll_check_data_len(ll, sh->dlen);
+				continue;
+			}
+		}
+
+		/* HCILL_W4_PACKET_TYPE */
+		switch (*ptr) {
+		case HCI_EVENT_PKT:
+			BT_DBG("Event packet");
+			ll->rx_state = HCILL_W4_EVENT_HDR;
+			ll->rx_count = HCI_EVENT_HDR_SIZE;
+			type = HCI_EVENT_PKT;
+			break;
+
+		case HCI_ACLDATA_PKT:
+			BT_DBG("ACL packet");
+			ll->rx_state = HCILL_W4_ACL_HDR;
+			ll->rx_count = HCI_ACL_HDR_SIZE;
+			type = HCI_ACLDATA_PKT;
+			break;
+
+		case HCI_SCODATA_PKT:
+			BT_DBG("SCO packet");
+			ll->rx_state = HCILL_W4_SCO_HDR;
+			ll->rx_count = HCI_SCO_HDR_SIZE;
+			type = HCI_SCODATA_PKT;
+			break;
+
+		/* HCILL signals */
+		case HCILL_GO_TO_SLEEP_IND:
+			BT_DBG("HCILL_GO_TO_SLEEP_IND packet");
+			ll_device_want_to_sleep(hu);
+			ptr++; count--;
+			continue;
+
+		case HCILL_GO_TO_SLEEP_ACK:
+			/* shouldn't happen */
+			BT_ERR("received HCILL_GO_TO_SLEEP_ACK (in state %ld)", ll->hcill_state);
+			ptr++; count--;
+			continue;
+
+		case HCILL_WAKE_UP_IND:
+			BT_DBG("HCILL_WAKE_UP_IND packet");
+			ll_device_want_to_wakeup(hu);
+			ptr++; count--;
+			continue;
+
+		case HCILL_WAKE_UP_ACK:
+			BT_DBG("HCILL_WAKE_UP_ACK packet");
+			ll_device_woke_up(hu);
+			ptr++; count--;
+			continue;
+
+		default:
+			BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
+			hu->hdev->stat.err_rx++;
+			ptr++; count--;
+			continue;
+		};
+
+		ptr++; count--;
+
+		/* Allocate packet */
+		ll->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+		if (!ll->rx_skb) {
+			BT_ERR("Can't allocate mem for new packet");
+			ll->rx_state = HCILL_W4_PACKET_TYPE;
+			ll->rx_count = 0;
+			return 0;
+		}
+
+		ll->rx_skb->dev = (void *) hu->hdev;
+		bt_cb(ll->rx_skb)->pkt_type = type;
+	}
+
+	return count;
+}
+
+static struct sk_buff *ll_dequeue(struct hci_uart *hu)
+{
+	struct ll_struct *ll = hu->priv;
+	return skb_dequeue(&ll->txq);
+}
+
+static struct hci_uart_proto llp = {
+	.id		= HCI_UART_LL,
+	.open		= ll_open,
+	.close		= ll_close,
+	.recv		= ll_recv,
+	.enqueue	= ll_enqueue,
+	.dequeue	= ll_dequeue,
+	.flush		= ll_flush,
+};
+
+int ll_init(void)
+{
+	int err = hci_uart_register_proto(&llp);
+
+	if (!err)
+		BT_INFO("HCILL protocol initialized");
+	else
+		BT_ERR("HCILL protocol registration failed");
+
+	return err;
+}
+
+int ll_deinit(void)
+{
+	return hci_uart_unregister_proto(&llp);
+}
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 1097ce72393f..50113db06b9f 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -33,12 +33,13 @@
 #define HCIUARTGETDEVICE	_IOR('U', 202, int)
 
 /* UART protocols */
-#define HCI_UART_MAX_PROTO	4
+#define HCI_UART_MAX_PROTO	5
 
 #define HCI_UART_H4	0
 #define HCI_UART_BCSP	1
 #define HCI_UART_3WIRE	2
 #define HCI_UART_H4DS	3
+#define HCI_UART_LL	4
 
 struct hci_uart;
 
@@ -85,3 +86,8 @@ int h4_deinit(void);
 int bcsp_init(void);
 int bcsp_deinit(void);
 #endif
+
+#ifdef CONFIG_BT_HCIUART_LL
+int ll_init(void);
+int ll_deinit(void);
+#endif

From ac019360fe311dd6aa11b358a02eb3a61675882e Mon Sep 17 00:00:00 2001
From: Jeff Garzik <jeff@garzik.org>
Date: Sat, 20 Oct 2007 13:45:57 +0200
Subject: [PATCH 09/30] [Bluetooth] Eliminate checks for impossible conditions
 in IRQ handler

Our info structure and info->hdev is always passed to the IRQ handler,
so we don't have to worry about these checks in every interrupt.

Leave a BUG_ON() just to help unwary programmers, but these could
probably be removed as well.

Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 drivers/bluetooth/bluecard_cs.c | 5 +----
 drivers/bluetooth/bt3c_cs.c     | 5 +----
 drivers/bluetooth/btuart_cs.c   | 5 +----
 drivers/bluetooth/dtl1_cs.c     | 5 +----
 4 files changed, 4 insertions(+), 16 deletions(-)

diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 851de4d5b7de..bcf57927b7a8 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -503,10 +503,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
 	unsigned int iobase;
 	unsigned char reg;
 
-	if (!info || !info->hdev) {
-		BT_ERR("Call of irq %d for unknown device", irq);
-		return IRQ_NONE;
-	}
+	BUG_ON(!info->hdev);
 
 	if (!test_bit(CARD_READY, &(info->hw_state)))
 		return IRQ_HANDLED;
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 39516074636b..a18f9b8c9e12 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -344,10 +344,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
 	unsigned int iobase;
 	int iir;
 
-	if (!info || !info->hdev) {
-		BT_ERR("Call of irq %d for unknown device", irq);
-		return IRQ_NONE;
-	}
+	BUG_ON(!info->hdev);
 
 	iobase = info->p_dev->io.BasePort1;
 
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index d7d2ea0d86a1..08f48d577aba 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -294,10 +294,7 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
 	int boguscount = 0;
 	int iir, lsr;
 
-	if (!info || !info->hdev) {
-		BT_ERR("Call of irq %d for unknown device", irq);
-		return IRQ_NONE;
-	}
+	BUG_ON(!info->hdev);
 
 	iobase = info->p_dev->io.BasePort1;
 
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 7f9c54b9964a..dae45cdf02b2 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -298,10 +298,7 @@ static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
 	int boguscount = 0;
 	int iir, lsr;
 
-	if (!info || !info->hdev) {
-		BT_ERR("Call of irq %d for unknown device", irq);
-		return IRQ_NONE;
-	}
+	BUG_ON(!info->hdev);
 
 	iobase = info->p_dev->io.BasePort1;
 

From ddbaf13e3609442b64abb931ac21527772d87980 Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 14:02:04 +0200
Subject: [PATCH 10/30] [Bluetooth] Add generic driver for Bluetooth SDIO
 devices

This patch adds a generic driver for Bluetooth SDIO devices. It
supports Type-A and Type-B devices.

Signed-off-by: David Vrabel <david.vrabel@csr.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 drivers/bluetooth/Kconfig  |  11 +
 drivers/bluetooth/Makefile |   2 +
 drivers/bluetooth/btsdio.c | 406 +++++++++++++++++++++++++++++++++++++
 3 files changed, 419 insertions(+)
 create mode 100644 drivers/bluetooth/btsdio.c

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 62b89b95ace2..77bded441cf1 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -22,6 +22,17 @@ config BT_HCIUSB_SCO
 
 	  Say Y here to compile support for SCO over HCI USB.
 
+config BT_HCIBTSDIO
+	tristate "HCI SDIO driver"
+	depends on MMC
+	help
+	  Bluetooth HCI SDIO driver.
+	  This driver is required if you want to use Bluetooth device with
+	  SDIO interface.
+
+	  Say Y here to compile support for Bluetooth SDIO devices into the
+	  kernel or say M to compile it as module (btsdio).
+
 config BT_HCIUART
 	tristate "HCI UART driver"
 	help
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index a543dfc2d6f5..aee12797aa1c 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -13,6 +13,8 @@ obj-$(CONFIG_BT_HCIBT3C)	+= bt3c_cs.o
 obj-$(CONFIG_BT_HCIBLUECARD)	+= bluecard_cs.o
 obj-$(CONFIG_BT_HCIBTUART)	+= btuart_cs.o
 
+obj-$(CONFIG_BT_HCIBTSDIO)	+= btsdio.o
+
 hci_uart-y				:= hci_ldisc.o
 hci_uart-$(CONFIG_BT_HCIUART_H4)	+= hci_h4.o
 hci_uart-$(CONFIG_BT_HCIUART_BCSP)	+= hci_bcsp.o
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
new file mode 100644
index 000000000000..b786f6187902
--- /dev/null
+++ b/drivers/bluetooth/btsdio.c
@@ -0,0 +1,406 @@
+/*
+ *
+ *  Generic Bluetooth SDIO driver
+ *
+ *  Copyright (C) 2007  Cambridge Silicon Radio Ltd.
+ *  Copyright (C) 2007  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#ifndef CONFIG_BT_HCIBTSDIO_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define VERSION "0.1"
+
+static const struct sdio_device_id btsdio_table[] = {
+	/* Generic Bluetooth Type-A SDIO device */
+	{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_A) },
+
+	/* Generic Bluetooth Type-B SDIO device */
+	{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
+
+	{ }	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(sdio, btsdio_table);
+
+struct btsdio_data {
+	struct hci_dev   *hdev;
+	struct sdio_func *func;
+
+	struct work_struct work;
+
+	struct sk_buff_head txq;
+};
+
+#define REG_RDAT     0x00	/* Receiver Data */
+#define REG_TDAT     0x00	/* Transmitter Data */
+#define REG_PC_RRT   0x10	/* Read Packet Control */
+#define REG_PC_WRT   0x11	/* Write Packet Control */
+#define REG_RTC_STAT 0x12	/* Retry Control Status */
+#define REG_RTC_SET  0x12	/* Retry Control Set */
+#define REG_INTRD    0x13	/* Interrupt Indication */
+#define REG_CL_INTRD 0x13	/* Interrupt Clear */
+#define REG_EN_INTRD 0x14	/* Interrupt Enable */
+#define REG_MD_STAT  0x20	/* Bluetooth Mode Status */
+
+static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb)
+{
+	int err;
+
+	BT_DBG("%s", data->hdev->name);
+
+	/* Prepend Type-A header */
+	skb_push(skb, 4);
+	skb->data[0] = (skb->len & 0x0000ff);
+	skb->data[1] = (skb->len & 0x00ff00) >> 8;
+	skb->data[2] = (skb->len & 0xff0000) >> 16;
+	skb->data[3] = bt_cb(skb)->pkt_type;
+
+	err = sdio_writesb(data->func, REG_TDAT, skb->data, skb->len);
+	if (err < 0) {
+		sdio_writeb(data->func, 0x01, REG_PC_WRT, NULL);
+		return err;
+	}
+
+	data->hdev->stat.byte_tx += skb->len;
+
+	kfree_skb(skb);
+
+	return 0;
+}
+
+static void btsdio_work(struct work_struct *work)
+{
+	struct btsdio_data *data = container_of(work, struct btsdio_data, work);
+	struct sk_buff *skb;
+	int err;
+
+	BT_DBG("%s", data->hdev->name);
+
+	sdio_claim_host(data->func);
+
+	while ((skb = skb_dequeue(&data->txq))) {
+		err = btsdio_tx_packet(data, skb);
+		if (err < 0) {
+			data->hdev->stat.err_tx++;
+			skb_queue_head(&data->txq, skb);
+			break;
+		}
+	}
+
+	sdio_release_host(data->func);
+}
+
+static int btsdio_rx_packet(struct btsdio_data *data)
+{
+	u8 hdr[4] __attribute__ ((aligned(4)));
+	struct sk_buff *skb;
+	int err, len;
+
+	BT_DBG("%s", data->hdev->name);
+
+	err = sdio_readsb(data->func, hdr, REG_RDAT, 4);
+	if (err < 0)
+		return err;
+
+	len = hdr[0] | (hdr[1] << 8) | (hdr[2] << 16);
+	if (len < 4 || len > 65543)
+		return -EILSEQ;
+
+	skb = bt_skb_alloc(len - 4, GFP_KERNEL);
+	if (!skb) {
+		/* Out of memory. Prepare a read retry and just
+		 * return with the expectation that the next time
+		 * we're called we'll have more memory. */
+		return -ENOMEM;
+	}
+
+	skb_put(skb, len - 4);
+
+	err = sdio_readsb(data->func, skb->data, REG_RDAT, len - 4);
+	if (err < 0) {
+		kfree(skb);
+		return err;
+	}
+
+	data->hdev->stat.byte_rx += len;
+
+	skb->dev = (void *) data->hdev;
+	bt_cb(skb)->pkt_type = hdr[3];
+
+	err = hci_recv_frame(skb);
+	if (err < 0) {
+		kfree(skb);
+		return err;
+	}
+
+	sdio_writeb(data->func, 0x00, REG_PC_RRT, NULL);
+
+	return 0;
+}
+
+static void btsdio_interrupt(struct sdio_func *func)
+{
+	struct btsdio_data *data = sdio_get_drvdata(func);
+	int intrd;
+
+	BT_DBG("%s", data->hdev->name);
+
+	intrd = sdio_readb(func, REG_INTRD, NULL);
+	if (intrd & 0x01) {
+		sdio_writeb(func, 0x01, REG_CL_INTRD, NULL);
+
+		if (btsdio_rx_packet(data) < 0) {
+			data->hdev->stat.err_rx++;
+			sdio_writeb(data->func, 0x01, REG_PC_RRT, NULL);
+		}
+	}
+}
+
+static int btsdio_open(struct hci_dev *hdev)
+{
+	struct btsdio_data *data = hdev->driver_data;
+	int err;
+
+	BT_DBG("%s", hdev->name);
+
+	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
+
+	sdio_claim_host(data->func);
+
+	err = sdio_enable_func(data->func);
+	if (err < 0) {
+		clear_bit(HCI_RUNNING, &hdev->flags);
+		goto release;
+	}
+
+	err = sdio_claim_irq(data->func, btsdio_interrupt);
+	if (err < 0) {
+		sdio_disable_func(data->func);
+		clear_bit(HCI_RUNNING, &hdev->flags);
+		goto release;
+	}
+
+	if (data->func->class == SDIO_CLASS_BT_B)
+		sdio_writeb(data->func, 0x00, REG_MD_STAT, NULL);
+
+	sdio_writeb(data->func, 0x01, REG_EN_INTRD, NULL);
+
+release:
+	sdio_release_host(data->func);
+
+	return err;
+}
+
+static int btsdio_close(struct hci_dev *hdev)
+{
+	struct btsdio_data *data = hdev->driver_data;
+
+	BT_DBG("%s", hdev->name);
+
+	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
+
+	sdio_claim_host(data->func);
+
+	sdio_writeb(data->func, 0x00, REG_EN_INTRD, NULL);
+
+	sdio_release_irq(data->func);
+	sdio_disable_func(data->func);
+
+	sdio_release_host(data->func);
+
+	return 0;
+}
+
+static int btsdio_flush(struct hci_dev *hdev)
+{
+	struct btsdio_data *data = hdev->driver_data;
+
+	BT_DBG("%s", hdev->name);
+
+	skb_queue_purge(&data->txq);
+
+	return 0;
+}
+
+static int btsdio_send_frame(struct sk_buff *skb)
+{
+	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+	struct btsdio_data *data = hdev->driver_data;
+
+	BT_DBG("%s", hdev->name);
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return -EBUSY;
+
+	switch (bt_cb(skb)->pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+
+	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		break;
+
+	default:
+		return -EILSEQ;
+	}
+
+	skb_queue_tail(&data->txq, skb);
+
+	schedule_work(&data->work);
+
+	return 0;
+}
+
+static void btsdio_destruct(struct hci_dev *hdev)
+{
+	struct btsdio_data *data = hdev->driver_data;
+
+	BT_DBG("%s", hdev->name);
+
+	kfree(data);
+}
+
+static int btsdio_probe(struct sdio_func *func,
+				const struct sdio_device_id *id)
+{
+	struct btsdio_data *data;
+	struct hci_dev *hdev;
+	struct sdio_func_tuple *tuple = func->tuples;
+	int err;
+
+	BT_DBG("func %p id %p class 0x%04x", func, id, func->class);
+
+	while (tuple) {
+		BT_DBG("code 0x%x size %d", tuple->code, tuple->size);
+		tuple = tuple->next;
+	}
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->func = func;
+
+	INIT_WORK(&data->work, btsdio_work);
+
+	skb_queue_head_init(&data->txq);
+
+	hdev = hci_alloc_dev();
+	if (!hdev) {
+		kfree(data);
+		return -ENOMEM;
+	}
+
+	hdev->type = HCI_SDIO;
+	hdev->driver_data = data;
+
+	data->hdev = hdev;
+
+	SET_HCIDEV_DEV(hdev, &func->dev);
+
+	hdev->open     = btsdio_open;
+	hdev->close    = btsdio_close;
+	hdev->flush    = btsdio_flush;
+	hdev->send     = btsdio_send_frame;
+	hdev->destruct = btsdio_destruct;
+
+	hdev->owner = THIS_MODULE;
+
+	err = hci_register_dev(hdev);
+	if (err < 0) {
+		hci_free_dev(hdev);
+		kfree(data);
+		return err;
+	}
+
+	sdio_set_drvdata(func, data);
+
+	return 0;
+}
+
+static void btsdio_remove(struct sdio_func *func)
+{
+	struct btsdio_data *data = sdio_get_drvdata(func);
+	struct hci_dev *hdev;
+
+	BT_DBG("func %p", func);
+
+	if (!data)
+		return;
+
+	hdev = data->hdev;
+
+	sdio_set_drvdata(func, NULL);
+
+	hci_unregister_dev(hdev);
+
+	hci_free_dev(hdev);
+}
+
+static struct sdio_driver btsdio_driver = {
+	.name		= "btsdio",
+	.probe		= btsdio_probe,
+	.remove		= btsdio_remove,
+	.id_table	= btsdio_table,
+};
+
+static int __init btsdio_init(void)
+{
+	BT_INFO("Generic Bluetooth SDIO driver ver %s", VERSION);
+
+	return sdio_register_driver(&btsdio_driver);
+}
+
+static void __exit btsdio_exit(void)
+{
+	sdio_unregister_driver(&btsdio_driver);
+}
+
+module_init(btsdio_init);
+module_exit(btsdio_exit);
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("Generic Bluetooth SDIO driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");

From 5e23b923da03de7e41f00f5664ae22c4f7dcd2a3 Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 14:12:34 +0200
Subject: [PATCH 11/30] [Bluetooth] Add generic driver for Bluetooth USB
 devices

This patch adds a new generic driver for Bluetooth USB devices. This
driver is still experimental at this point, but it is cleaner and
easier to maintain than the current Bluetooth USB driver. It is a
much better starting point for power management improvements.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 drivers/bluetooth/Kconfig  |  13 +
 drivers/bluetooth/Makefile |   1 +
 drivers/bluetooth/btusb.c  | 564 +++++++++++++++++++++++++++++++++++++
 3 files changed, 578 insertions(+)
 create mode 100644 drivers/bluetooth/btusb.c

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 77bded441cf1..075598e1c502 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -22,6 +22,19 @@ config BT_HCIUSB_SCO
 
 	  Say Y here to compile support for SCO over HCI USB.
 
+config BT_HCIBTUSB
+	tristate "HCI USB driver (alternate version)"
+	depends on USB && EXPERIMENTAL && BT_HCIUSB=n
+	help
+	  Bluetooth HCI USB driver.
+	  This driver is required if you want to use Bluetooth devices with
+	  USB interface.
+
+          This driver is still experimental and has no SCO support.
+
+	  Say Y here to compile support for Bluetooth USB devices into the
+	  kernel or say M to compile it as module (btusb).
+
 config BT_HCIBTSDIO
 	tristate "HCI SDIO driver"
 	depends on MMC
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index aee12797aa1c..77444afbf107 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_BT_HCIBT3C)	+= bt3c_cs.o
 obj-$(CONFIG_BT_HCIBLUECARD)	+= bluecard_cs.o
 obj-$(CONFIG_BT_HCIBTUART)	+= btuart_cs.o
 
+obj-$(CONFIG_BT_HCIBTUSB)	+= btusb.o
 obj-$(CONFIG_BT_HCIBTSDIO)	+= btsdio.o
 
 hci_uart-y				:= hci_ldisc.o
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
new file mode 100644
index 000000000000..12e108914f19
--- /dev/null
+++ b/drivers/bluetooth/btusb.c
@@ -0,0 +1,564 @@
+/*
+ *
+ *  Generic Bluetooth USB driver
+ *
+ *  Copyright (C) 2005-2007  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+
+#include <linux/usb.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+//#define CONFIG_BT_HCIBTUSB_DEBUG
+#ifndef CONFIG_BT_HCIBTUSB_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define VERSION "0.1"
+
+static struct usb_device_id btusb_table[] = {
+	/* Generic Bluetooth USB device */
+	{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
+
+	{ }	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, btusb_table);
+
+static struct usb_device_id blacklist_table[] = {
+	{ }	/* Terminating entry */
+};
+
+#define BTUSB_INTR_RUNNING	0
+#define BTUSB_BULK_RUNNING	1
+
+struct btusb_data {
+	struct hci_dev       *hdev;
+	struct usb_device    *udev;
+
+	spinlock_t lock;
+
+	unsigned long flags;
+
+	struct work_struct work;
+
+	struct usb_anchor tx_anchor;
+	struct usb_anchor intr_anchor;
+	struct usb_anchor bulk_anchor;
+
+	struct usb_endpoint_descriptor *intr_ep;
+	struct usb_endpoint_descriptor *bulk_tx_ep;
+	struct usb_endpoint_descriptor *bulk_rx_ep;
+};
+
+static void btusb_intr_complete(struct urb *urb)
+{
+	struct hci_dev *hdev = urb->context;
+	struct btusb_data *data = hdev->driver_data;
+	int err;
+
+	BT_DBG("%s urb %p status %d count %d", hdev->name,
+					urb, urb->status, urb->actual_length);
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return;
+
+	if (urb->status == 0) {
+		if (hci_recv_fragment(hdev, HCI_EVENT_PKT,
+						urb->transfer_buffer,
+						urb->actual_length) < 0) {
+			BT_ERR("%s corrupted event packet", hdev->name);
+			hdev->stat.err_rx++;
+		}
+	}
+
+	if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
+		return;
+
+	usb_anchor_urb(urb, &data->intr_anchor);
+
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err < 0) {
+		BT_ERR("%s urb %p failed to resubmit (%d)",
+						hdev->name, urb, -err);
+		usb_unanchor_urb(urb);
+	}
+}
+
+static inline int btusb_submit_intr_urb(struct hci_dev *hdev)
+{
+	struct btusb_data *data = hdev->driver_data;
+	struct urb *urb;
+	unsigned char *buf;
+	unsigned int pipe;
+	int err, size;
+
+	BT_DBG("%s", hdev->name);
+
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb)
+		return -ENOMEM;
+
+	size = le16_to_cpu(data->intr_ep->wMaxPacketSize);
+
+	buf = kmalloc(size, GFP_ATOMIC);
+	if (!buf) {
+		usb_free_urb(urb);
+		return -ENOMEM;
+	}
+
+	pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress);
+
+	usb_fill_int_urb(urb, data->udev, pipe, buf, size,
+						btusb_intr_complete, hdev,
+						data->intr_ep->bInterval);
+
+	urb->transfer_flags |= URB_FREE_BUFFER;
+
+	usb_anchor_urb(urb, &data->intr_anchor);
+
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err < 0) {
+		BT_ERR("%s urb %p submission failed (%d)",
+						hdev->name, urb, -err);
+		usb_unanchor_urb(urb);
+		kfree(buf);
+	}
+
+	usb_free_urb(urb);
+
+	return err;
+}
+
+static void btusb_bulk_complete(struct urb *urb)
+{
+	struct hci_dev *hdev = urb->context;
+	struct btusb_data *data = hdev->driver_data;
+	int err;
+
+	BT_DBG("%s urb %p status %d count %d", hdev->name,
+					urb, urb->status, urb->actual_length);
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return;
+
+	if (urb->status == 0) {
+		if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,
+						urb->transfer_buffer,
+						urb->actual_length) < 0) {
+			BT_ERR("%s corrupted ACL packet", hdev->name);
+			hdev->stat.err_rx++;
+		}
+	}
+
+	if (!test_bit(BTUSB_BULK_RUNNING, &data->flags))
+		return;
+
+	usb_anchor_urb(urb, &data->bulk_anchor);
+
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err < 0) {
+		BT_ERR("%s urb %p failed to resubmit (%d)",
+						hdev->name, urb, -err);
+		usb_unanchor_urb(urb);
+	}
+}
+
+static inline int btusb_submit_bulk_urb(struct hci_dev *hdev)
+{
+	struct btusb_data *data = hdev->driver_data;
+	struct urb *urb;
+	unsigned char *buf;
+	unsigned int pipe;
+	int err, size;
+
+	BT_DBG("%s", hdev->name);
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb)
+		return -ENOMEM;
+
+	size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize);
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf) {
+		usb_free_urb(urb);
+		return -ENOMEM;
+	}
+
+	pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
+
+	usb_fill_bulk_urb(urb, data->udev, pipe,
+					buf, size, btusb_bulk_complete, hdev);
+
+	urb->transfer_flags |= URB_FREE_BUFFER;
+
+	usb_anchor_urb(urb, &data->bulk_anchor);
+
+	err = usb_submit_urb(urb, GFP_KERNEL);
+	if (err < 0) {
+		BT_ERR("%s urb %p submission failed (%d)",
+						hdev->name, urb, -err);
+		usb_unanchor_urb(urb);
+		kfree(buf);
+	}
+
+	usb_free_urb(urb);
+
+	return err;
+}
+
+static void btusb_tx_complete(struct urb *urb)
+{
+	struct sk_buff *skb = urb->context;
+	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+
+	BT_DBG("%s urb %p status %d count %d", hdev->name,
+					urb, urb->status, urb->actual_length);
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		goto done;
+
+	if (!urb->status)
+		hdev->stat.byte_tx += urb->transfer_buffer_length;
+	else
+		hdev->stat.err_tx++;
+
+done:
+	kfree(urb->setup_packet);
+
+	kfree_skb(skb);
+}
+
+static int btusb_open(struct hci_dev *hdev)
+{
+	struct btusb_data *data = hdev->driver_data;
+	int err;
+
+	BT_DBG("%s", hdev->name);
+
+	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
+
+	if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
+		return 0;
+
+	err = btusb_submit_intr_urb(hdev);
+	if (err < 0) {
+		clear_bit(BTUSB_INTR_RUNNING, &hdev->flags);
+		clear_bit(HCI_RUNNING, &hdev->flags);
+	}
+
+	return err;
+}
+
+static int btusb_close(struct hci_dev *hdev)
+{
+	struct btusb_data *data = hdev->driver_data;
+
+	BT_DBG("%s", hdev->name);
+
+	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
+
+	clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+	usb_kill_anchored_urbs(&data->bulk_anchor);
+
+	clear_bit(BTUSB_INTR_RUNNING, &data->flags);
+	usb_kill_anchored_urbs(&data->intr_anchor);
+
+	return 0;
+}
+
+static int btusb_flush(struct hci_dev *hdev)
+{
+	struct btusb_data *data = hdev->driver_data;
+
+	BT_DBG("%s", hdev->name);
+
+	usb_kill_anchored_urbs(&data->tx_anchor);
+
+	return 0;
+}
+
+static int btusb_send_frame(struct sk_buff *skb)
+{
+	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+	struct btusb_data *data = hdev->driver_data;
+	struct usb_ctrlrequest *dr;
+	struct urb *urb;
+	unsigned int pipe;
+	int err;
+
+	BT_DBG("%s", hdev->name);
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return -EBUSY;
+
+	switch (bt_cb(skb)->pkt_type) {
+	case HCI_COMMAND_PKT:
+		urb = usb_alloc_urb(0, GFP_ATOMIC);
+		if (!urb)
+			return -ENOMEM;
+
+		dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
+		if (!dr) {
+			usb_free_urb(urb);
+			return -ENOMEM;
+		}
+
+		dr->bRequestType = USB_TYPE_CLASS;
+		dr->bRequest     = 0;
+		dr->wIndex       = 0;
+		dr->wValue       = 0;
+		dr->wLength      = __cpu_to_le16(skb->len);
+
+		pipe = usb_sndctrlpipe(data->udev, 0x00);
+
+		usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
+				skb->data, skb->len, btusb_tx_complete, skb);
+
+		hdev->stat.cmd_tx++;
+		break;
+
+	case HCI_ACLDATA_PKT:
+		urb = usb_alloc_urb(0, GFP_ATOMIC);
+		if (!urb)
+			return -ENOMEM;
+
+		pipe = usb_sndbulkpipe(data->udev,
+					data->bulk_tx_ep->bEndpointAddress);
+
+		usb_fill_bulk_urb(urb, data->udev, pipe,
+				skb->data, skb->len, btusb_tx_complete, skb);
+
+		hdev->stat.acl_tx++;
+		break;
+
+	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		kfree_skb(skb);
+		return 0;
+
+	default:
+		return -EILSEQ;
+	}
+
+	usb_anchor_urb(urb, &data->tx_anchor);
+
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err < 0) {
+		BT_ERR("%s urb %p submission failed", hdev->name, urb);
+		kfree(urb->setup_packet);
+		usb_unanchor_urb(urb);
+	}
+
+	usb_free_urb(urb);
+
+	return err;
+}
+
+static void btusb_destruct(struct hci_dev *hdev)
+{
+	struct btusb_data *data = hdev->driver_data;
+
+	BT_DBG("%s", hdev->name);
+
+	kfree(data);
+}
+
+static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
+{
+	struct btusb_data *data = hdev->driver_data;
+
+	BT_DBG("%s evt %d", hdev->name, evt);
+
+	if (evt == HCI_NOTIFY_CONN_ADD || evt == HCI_NOTIFY_CONN_DEL)
+		schedule_work(&data->work);
+}
+
+static void btusb_work(struct work_struct *work)
+{
+	struct btusb_data *data = container_of(work, struct btusb_data, work);
+	struct hci_dev *hdev = data->hdev;
+
+	if (hdev->conn_hash.acl_num == 0) {
+		clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+		usb_kill_anchored_urbs(&data->bulk_anchor);
+		return;
+	}
+
+	if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) {
+		if (btusb_submit_bulk_urb(hdev) < 0)
+			clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+		else
+			btusb_submit_bulk_urb(hdev);
+	}
+}
+
+static int btusb_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	struct usb_endpoint_descriptor *ep_desc;
+	struct btusb_data *data;
+	struct hci_dev *hdev;
+	int i, err;
+
+	BT_DBG("intf %p id %p", intf, id);
+
+	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+		return -ENODEV;
+
+	if (!id->driver_info) {
+		const struct usb_device_id *match;
+		match = usb_match_id(intf, blacklist_table);
+		if (match)
+			id = match;
+	}
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
+		ep_desc = &intf->cur_altsetting->endpoint[i].desc;
+
+		if (!data->intr_ep && usb_endpoint_is_int_in(ep_desc)) {
+			data->intr_ep = ep_desc;
+			continue;
+		}
+
+		if (!data->bulk_tx_ep && usb_endpoint_is_bulk_out(ep_desc)) {
+			data->bulk_tx_ep = ep_desc;
+			continue;
+		}
+
+		if (!data->bulk_rx_ep && usb_endpoint_is_bulk_in(ep_desc)) {
+			data->bulk_rx_ep = ep_desc;
+			continue;
+		}
+	}
+
+	if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) {
+		kfree(data);
+		return -ENODEV;
+	}
+
+	data->udev = interface_to_usbdev(intf);
+
+	spin_lock_init(&data->lock);
+
+	INIT_WORK(&data->work, btusb_work);
+
+	init_usb_anchor(&data->tx_anchor);
+	init_usb_anchor(&data->intr_anchor);
+	init_usb_anchor(&data->bulk_anchor);
+
+	hdev = hci_alloc_dev();
+	if (!hdev) {
+		kfree(data);
+		return -ENOMEM;
+	}
+
+	hdev->type = HCI_USB;
+	hdev->driver_data = data;
+
+	data->hdev = hdev;
+
+	SET_HCIDEV_DEV(hdev, &intf->dev);
+
+	hdev->open     = btusb_open;
+	hdev->close    = btusb_close;
+	hdev->flush    = btusb_flush;
+	hdev->send     = btusb_send_frame;
+	hdev->destruct = btusb_destruct;
+	hdev->notify   = btusb_notify;
+
+	hdev->owner = THIS_MODULE;
+
+	set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
+
+	err = hci_register_dev(hdev);
+	if (err < 0) {
+		hci_free_dev(hdev);
+		kfree(data);
+		return err;
+	}
+
+	usb_set_intfdata(intf, data);
+
+	return 0;
+}
+
+static void btusb_disconnect(struct usb_interface *intf)
+{
+	struct btusb_data *data = usb_get_intfdata(intf);
+	struct hci_dev *hdev;
+
+	BT_DBG("intf %p", intf);
+
+	if (!data)
+		return;
+
+	hdev = data->hdev;
+
+	usb_set_intfdata(intf, NULL);
+
+	hci_unregister_dev(hdev);
+
+	hci_free_dev(hdev);
+}
+
+static struct usb_driver btusb_driver = {
+	.name		= "btusb",
+	.probe		= btusb_probe,
+	.disconnect	= btusb_disconnect,
+	.id_table	= btusb_table,
+};
+
+static int __init btusb_init(void)
+{
+	BT_INFO("Generic Bluetooth USB driver ver %s", VERSION);
+
+	return usb_register(&btusb_driver);
+}
+
+static void __exit btusb_exit(void)
+{
+	usb_deregister(&btusb_driver);
+}
+
+module_init(btusb_init);
+module_exit(btusb_exit);
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("Generic Bluetooth USB driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");

From 6792b5ec8d9e723e4689fd5b16cfa52603985f43 Mon Sep 17 00:00:00 2001
From: Dave Young <hidave.darkstar@gmail.com>
Date: Sat, 20 Oct 2007 14:15:39 +0200
Subject: [PATCH 12/30] [Bluetooth] Fix wrong argument in debug code of HIDP

In the debug code of the hidp_queue_report function, the device
variable does not exist, replace it with session->hid.

Signed-off-by: Dave Young <hidave.darkstar@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 net/bluetooth/hidp/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 66c736953cfe..4bbacddeb49d 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -247,7 +247,7 @@ static inline int hidp_queue_report(struct hidp_session *session, unsigned char
 {
 	struct sk_buff *skb;
 
-	BT_DBG("session %p hid %p data %p size %d", session, device, data, size);
+	BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
 
 	if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
 		BT_ERR("Can't allocate memory for new frame");

From dae6a0f6636d05bcb28ece1f3630b23ed2d66e18 Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 14:52:38 +0200
Subject: [PATCH 13/30] [Bluetooth] Add address and channel attribute to RFCOMM
 TTY device

Export the remote device address and channel of RFCOMM TTY device
via sysfs attributes. This allows udev to create better naming rules
for configured RFCOMM devices.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 net/bluetooth/rfcomm/tty.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 22a832098d44..e447651a2dbe 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -189,6 +189,23 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
 	return conn ? &conn->dev : NULL;
 }
 
+static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
+{
+	struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
+	bdaddr_t bdaddr;
+	baswap(&bdaddr, &dev->dst);
+	return sprintf(buf, "%s\n", batostr(&bdaddr));
+}
+
+static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
+{
+	struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
+	return sprintf(buf, "%d\n", dev->channel);
+}
+
+static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
+static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
+
 static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 {
 	struct rfcomm_dev *dev;
@@ -281,6 +298,14 @@ out:
 		return err;
 	}
 
+	dev_set_drvdata(dev->tty_dev, dev);
+
+	if (device_create_file(dev->tty_dev, &dev_attr_address) < 0)
+		BT_ERR("Failed to create address attribute");
+
+	if (device_create_file(dev->tty_dev, &dev_attr_channel) < 0)
+		BT_ERR("Failed to create channel attribute");
+
 	return dev->id;
 }
 

From b6a0dc822497e1c0b9e8c4add270cc27fce48454 Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 14:55:10 +0200
Subject: [PATCH 14/30] [Bluetooth] Add support for handling simple eSCO links

With the Bluetooth 1.2 specification the Extended SCO feature for
better audio connections was introduced. So far the Bluetooth core
wasn't able to handle any eSCO connections correctly. This patch
adds simple eSCO support while keeping backward compatibility with
older devices.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/hci_core.h |  1 +
 net/bluetooth/hci_conn.c         | 39 +++++++++++--
 net/bluetooth/hci_core.c         | 22 +++++++
 net/bluetooth/hci_event.c        | 99 +++++++++++++++++++++++++++-----
 net/bluetooth/sco.c              | 12 ++--
 5 files changed, 151 insertions(+), 22 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 0db89ed6b00c..ea13baa3851b 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -313,6 +313,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
 void hci_acl_connect(struct hci_conn *conn);
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
 void hci_add_sco(struct hci_conn *conn, __u16 handle);
+void hci_setup_sync(struct hci_conn *conn, __u16 handle);
 
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
 int hci_conn_del(struct hci_conn *conn);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 797a30bec6fd..9483320f6dad 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -78,9 +78,9 @@ void hci_acl_connect(struct hci_conn *conn)
 
 	cp.pkt_type = cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
 	if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
-		cp.role_switch	= 0x01;
+		cp.role_switch = 0x01;
 	else
-		cp.role_switch	= 0x00;
+		cp.role_switch = 0x00;
 
 	hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
 }
@@ -127,6 +127,28 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
 	hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
 }
 
+void hci_setup_sync(struct hci_conn *conn, __u16 handle)
+{
+	struct hci_dev *hdev = conn->hdev;
+	struct hci_cp_setup_sync_conn cp;
+
+	BT_DBG("%p", conn);
+
+	conn->state = BT_CONNECT;
+	conn->out = 1;
+
+	cp.handle   = cpu_to_le16(handle);
+	cp.pkt_type = cpu_to_le16(hdev->esco_type);
+
+	cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
+	cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
+	cp.max_latency    = cpu_to_le16(0xffff);
+	cp.voice_setting  = cpu_to_le16(hdev->voice_setting);
+	cp.retrans_effort = 0xff;
+
+	hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
+}
+
 static void hci_conn_timeout(unsigned long arg)
 {
 	struct hci_conn *conn = (void *) arg;
@@ -141,7 +163,10 @@ static void hci_conn_timeout(unsigned long arg)
 
 	switch (conn->state) {
 	case BT_CONNECT:
-		hci_acl_connect_cancel(conn);
+		if (conn->type == ACL_LINK)
+			hci_acl_connect_cancel(conn);
+		else
+			hci_acl_disconn(conn, 0x13);
 		break;
 	case BT_CONNECTED:
 		hci_acl_disconn(conn, 0x13);
@@ -328,8 +353,12 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
 	hci_conn_hold(sco);
 
 	if (acl->state == BT_CONNECTED &&
-			(sco->state == BT_OPEN || sco->state == BT_CLOSED))
-		hci_add_sco(sco, acl->handle);
+			(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
+		if (lmp_esco_capable(hdev))
+			hci_setup_sync(sco, acl->handle);
+		else
+			hci_add_sco(sco, acl->handle);
+	}
 
 	return sco;
 }
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 2894382dd26d..372b0d3b75a8 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1361,6 +1361,26 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
 	}
 }
 
+static inline void hci_sched_esco(struct hci_dev *hdev)
+{
+	struct hci_conn *conn;
+	struct sk_buff *skb;
+	int quote;
+
+	BT_DBG("%s", hdev->name);
+
+	while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) {
+		while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
+			BT_DBG("skb %p len %d", skb, skb->len);
+			hci_send_frame(skb);
+
+			conn->sent++;
+			if (conn->sent == ~0)
+				conn->sent = 0;
+		}
+	}
+}
+
 static void hci_tx_task(unsigned long arg)
 {
 	struct hci_dev *hdev = (struct hci_dev *) arg;
@@ -1376,6 +1396,8 @@ static void hci_tx_task(unsigned long arg)
 
 	hci_sched_sco(hdev);
 
+	hci_sched_esco(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 e2cfeea5ee72..46df2e403df8 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -511,11 +511,11 @@ static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
 	struct hci_conn *acl, *sco;
 	__u16 handle;
 
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
 	if (!status)
 		return;
 
-	BT_DBG("%s status 0x%x", hdev->name, status);
-
 	cp = hci_sent_cmd_data(hdev, HCI_OP_ADD_SCO);
 	if (!cp)
 		return;
@@ -544,7 +544,34 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
 
 static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
 {
+	struct hci_cp_setup_sync_conn *cp;
+	struct hci_conn *acl, *sco;
+	__u16 handle;
+
 	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	if (!status)
+		return;
+
+	cp = hci_sent_cmd_data(hdev, HCI_OP_SETUP_SYNC_CONN);
+	if (!cp)
+		return;
+
+	handle = __le16_to_cpu(cp->handle);
+
+	BT_DBG("%s handle %d", hdev->name, handle);
+
+	hci_dev_lock(hdev);
+
+	acl = hci_conn_hash_lookup_handle(hdev, handle);
+	if (acl && (sco = acl->link)) {
+		sco->state = BT_CLOSED;
+
+		hci_proto_connect_cfm(sco, status);
+		hci_conn_del(sco);
+	}
+
+	hci_dev_unlock(hdev);
 }
 
 static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
@@ -692,9 +719,12 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 	if (conn->type == ACL_LINK) {
 		struct hci_conn *sco = conn->link;
 		if (sco) {
-			if (!ev->status)
-				hci_add_sco(sco, conn->handle);
-			else {
+			if (!ev->status) {
+				if (lmp_esco_capable(hdev))
+					hci_setup_sync(sco, conn->handle);
+				else
+					hci_add_sco(sco, conn->handle);
+			} else {
 				hci_proto_connect_cfm(sco, ev->status);
 				hci_conn_del(sco);
 			}
@@ -724,9 +754,9 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 	if (mask & HCI_LM_ACCEPT) {
 		/* Connection accepted */
 		struct hci_conn *conn;
-		struct hci_cp_accept_conn_req cp;
 
 		hci_dev_lock(hdev);
+
 		conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
 		if (!conn) {
 			if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) {
@@ -735,18 +765,39 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 				return;
 			}
 		}
+
 		memcpy(conn->dev_class, ev->dev_class, 3);
 		conn->state = BT_CONNECT;
+
 		hci_dev_unlock(hdev);
 
-		bacpy(&cp.bdaddr, &ev->bdaddr);
+		if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) {
+			struct hci_cp_accept_conn_req cp;
 
-		if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
-			cp.role = 0x00; /* Become master */
-		else
-			cp.role = 0x01; /* Remain slave */
+			bacpy(&cp.bdaddr, &ev->bdaddr);
 
-		hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp);
+			if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
+				cp.role = 0x00; /* Become master */
+			else
+				cp.role = 0x01; /* Remain slave */
+
+			hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ,
+							sizeof(cp), &cp);
+		} else {
+			struct hci_cp_accept_sync_conn_req cp;
+
+			bacpy(&cp.bdaddr, &ev->bdaddr);
+			cp.pkt_type = cpu_to_le16(hdev->esco_type);
+
+			cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
+			cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
+			cp.max_latency    = cpu_to_le16(0xffff);
+			cp.content_format = cpu_to_le16(hdev->voice_setting);
+			cp.retrans_effort = 0xff;
+
+			hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
+							sizeof(cp), &cp);
+		}
 	} else {
 		/* Connection rejected */
 		struct hci_cp_reject_conn_req cp;
@@ -1254,7 +1305,29 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
 
 static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	BT_DBG("%s", hdev->name);
+	struct hci_ev_sync_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, ev->link_type, &ev->bdaddr);
+	if (!conn)
+		goto unlock;
+
+	if (!ev->status) {
+		conn->handle = __le16_to_cpu(ev->handle);
+		conn->state  = BT_CONNECTED;
+	} else
+		conn->state = BT_CLOSED;
+
+	hci_proto_connect_cfm(conn, ev->status);
+	if (ev->status)
+		hci_conn_del(conn);
+
+unlock:
+	hci_dev_unlock(hdev);
 }
 
 static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 65b6fb1c4154..82d0dfdfa7e2 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -189,7 +189,7 @@ static int sco_connect(struct sock *sk)
 	struct sco_conn *conn;
 	struct hci_conn *hcon;
 	struct hci_dev  *hdev;
-	int err = 0;
+	int err, type;
 
 	BT_DBG("%s -> %s", batostr(src), batostr(dst));
 
@@ -200,7 +200,9 @@ static int sco_connect(struct sock *sk)
 
 	err = -ENOMEM;
 
-	hcon = hci_connect(hdev, SCO_LINK, dst);
+	type = lmp_esco_capable(hdev) ? ESCO_LINK : SCO_LINK;
+
+	hcon = hci_connect(hdev, type, dst);
 	if (!hcon)
 		goto done;
 
@@ -224,6 +226,7 @@ static int sco_connect(struct sock *sk)
 		sk->sk_state = BT_CONNECT;
 		sco_sock_set_timer(sk, sk->sk_sndtimeo);
 	}
+
 done:
 	hci_dev_unlock_bh(hdev);
 	hci_dev_put(hdev);
@@ -846,7 +849,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
 {
 	BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
 
-	if (hcon->type != SCO_LINK)
+	if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
 		return 0;
 
 	if (!status) {
@@ -865,10 +868,11 @@ static int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
 {
 	BT_DBG("hcon %p reason %d", hcon, reason);
 
-	if (hcon->type != SCO_LINK)
+	if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
 		return 0;
 
 	sco_conn_del(hcon, bt_err(reason));
+
 	return 0;
 }
 

From 2cb3377a295aade1f2e192d4bea948b2196fb162 Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 15:28:08 +0200
Subject: [PATCH 15/30] [Bluetooth] Add constant for Bluetooth socket options
 level

Assign the next free socket options level to be used by the Bluetooth
protocol and address family.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/linux/socket.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index f852e1afd65a..c22ef1c1afb8 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -291,6 +291,7 @@ struct ucred {
 #define SOL_TIPC	271
 #define SOL_RXRPC	272
 #define SOL_PPPOL2TP	273
+#define SOL_BLUETOOTH	274
 
 /* IPX options */
 #define IPX_TYPE	1

From a524eccc7307b1d6e79f03fed79f9f34c016ce56 Mon Sep 17 00:00:00 2001
From: Marcel Holtmann <marcel@holtmann.org>
Date: Sat, 20 Oct 2007 21:37:20 +0200
Subject: [PATCH 16/30] [Bluetooth] Convert RFCOMM to use kthread API

This patch does the full kthread conversion for the RFCOMM protocol. It
makes the code slightly simpler and more maintainable.

Based on a patch from Christoph Hellwig <hch@lst.de>

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 net/bluetooth/rfcomm/core.c | 62 +++++++++++++------------------------
 1 file changed, 22 insertions(+), 40 deletions(-)

diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index bb7220770f2c..e7ac6ba7ecab 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -33,11 +33,11 @@
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/init.h>
-#include <linux/freezer.h>
 #include <linux/wait.h>
 #include <linux/device.h>
 #include <linux/net.h>
 #include <linux/mutex.h>
+#include <linux/kthread.h>
 
 #include <net/sock.h>
 #include <asm/uaccess.h>
@@ -68,7 +68,6 @@ static DEFINE_MUTEX(rfcomm_mutex);
 static unsigned long rfcomm_event;
 
 static LIST_HEAD(session_list);
-static atomic_t terminate, running;
 
 static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
 static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
@@ -1850,26 +1849,6 @@ static inline void rfcomm_process_sessions(void)
 	rfcomm_unlock();
 }
 
-static void rfcomm_worker(void)
-{
-	BT_DBG("");
-
-	while (!atomic_read(&terminate)) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
-			/* No pending events. Let's sleep.
-			 * Incoming connections and data will wake us up. */
-			schedule();
-		}
-		set_current_state(TASK_RUNNING);
-
-		/* Process stuff */
-		clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
-		rfcomm_process_sessions();
-	}
-	return;
-}
-
 static int rfcomm_add_listener(bdaddr_t *ba)
 {
 	struct sockaddr_l2 addr;
@@ -1935,22 +1914,28 @@ static void rfcomm_kill_listener(void)
 
 static int rfcomm_run(void *unused)
 {
-	rfcomm_thread = current;
-
-	atomic_inc(&running);
-
-	daemonize("krfcommd");
-	set_user_nice(current, -10);
-
 	BT_DBG("");
 
+	set_user_nice(current, -10);
+
 	rfcomm_add_listener(BDADDR_ANY);
 
-	rfcomm_worker();
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
+			/* No pending events. Let's sleep.
+			 * Incoming connections and data will wake us up. */
+			schedule();
+		}
+		set_current_state(TASK_RUNNING);
+
+		/* Process stuff */
+		clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
+		rfcomm_process_sessions();
+	}
 
 	rfcomm_kill_listener();
 
-	atomic_dec(&running);
 	return 0;
 }
 
@@ -2059,7 +2044,11 @@ static int __init rfcomm_init(void)
 
 	hci_register_cb(&rfcomm_cb);
 
-	kernel_thread(rfcomm_run, NULL, CLONE_KERNEL);
+	rfcomm_thread = kthread_run(rfcomm_run, NULL, "krfcommd");
+	if (IS_ERR(rfcomm_thread)) {
+		hci_unregister_cb(&rfcomm_cb);
+		return PTR_ERR(rfcomm_thread);
+	}
 
 	if (class_create_file(bt_class, &class_attr_rfcomm_dlc) < 0)
 		BT_ERR("Failed to create RFCOMM info file");
@@ -2081,14 +2070,7 @@ static void __exit rfcomm_exit(void)
 
 	hci_unregister_cb(&rfcomm_cb);
 
-	/* Terminate working thread.
-	 * ie. Set terminate flag and wake it up */
-	atomic_inc(&terminate);
-	rfcomm_schedule(RFCOMM_SCHED_STATE);
-
-	/* Wait until thread is running */
-	while (atomic_read(&running))
-		schedule();
+	kthread_stop(rfcomm_thread);
 
 #ifdef CONFIG_BT_RFCOMM_TTY
 	rfcomm_cleanup_ttys();

From 6c7af27c8a2e8b85cb235a2409d3b2093b18f77d Mon Sep 17 00:00:00 2001
From: Matt Carlson <mcarlson@broadcom.com>
Date: Sun, 21 Oct 2007 16:12:02 -0700
Subject: [PATCH 17/30] [TG3]: Add 5723 support

This patch adds support for upcoming 5723 devices.

Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/tg3.c       | 1 +
 include/linux/pci_ids.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 014dc2cfe4d6..253d7613b921 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -200,6 +200,7 @@ static struct pci_device_id tg3_pci_tbl[] = {
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)},
 	{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index df948b44edad..4e10a074ca56 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1943,6 +1943,7 @@
 #define PCI_DEVICE_ID_TIGON3_5720	0x1658
 #define PCI_DEVICE_ID_TIGON3_5721	0x1659
 #define PCI_DEVICE_ID_TIGON3_5722	0x165a
+#define PCI_DEVICE_ID_TIGON3_5723	0x165b
 #define PCI_DEVICE_ID_TIGON3_5705M	0x165d
 #define PCI_DEVICE_ID_TIGON3_5705M_2	0x165e
 #define PCI_DEVICE_ID_TIGON3_5714	0x1668

From 9c8a620e7f85fff050a54697da44bbd1a66e8e0b Mon Sep 17 00:00:00 2001
From: Matt Carlson <mcarlson@broadcom.com>
Date: Sun, 21 Oct 2007 16:16:08 -0700
Subject: [PATCH 18/30] [TG3]: Add management FW version to ethtool report

This patch appends the management firmware version to the bootcode
firmware string reported through ethtool.

Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/tg3.c | 93 ++++++++++++++++++++++++++++++++++++++---------
 drivers/net/tg3.h |  9 ++++-
 2 files changed, 83 insertions(+), 19 deletions(-)

diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 253d7613b921..98f465828110 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -10821,9 +10821,24 @@ out_not_found:
 		strcpy(tp->board_part_number, "none");
 }
 
+static int __devinit tg3_fw_img_is_valid(struct tg3 *tp, u32 offset)
+{
+	u32 val;
+
+	if (tg3_nvram_read_swab(tp, offset, &val) ||
+	    (val & 0xfc000000) != 0x0c000000 ||
+	    tg3_nvram_read_swab(tp, offset + 4, &val) ||
+	    val != 0)
+		return 0;
+
+	return 1;
+}
+
 static void __devinit tg3_read_fw_ver(struct tg3 *tp)
 {
 	u32 val, offset, start;
+	u32 ver_offset;
+	int i, bcnt;
 
 	if (tg3_nvram_read_swab(tp, 0, &val))
 		return;
@@ -10836,29 +10851,71 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
 		return;
 
 	offset = tg3_nvram_logical_addr(tp, offset);
-	if (tg3_nvram_read_swab(tp, offset, &val))
+
+	if (!tg3_fw_img_is_valid(tp, offset) ||
+	    tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
 		return;
 
-	if ((val & 0xfc000000) == 0x0c000000) {
-		u32 ver_offset, addr;
-		int i;
-
-		if (tg3_nvram_read_swab(tp, offset + 4, &val) ||
-		    tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
+	offset = offset + ver_offset - start;
+	for (i = 0; i < 16; i += 4) {
+		if (tg3_nvram_read(tp, offset + i, &val))
 			return;
 
-		if (val != 0)
-			return;
-
-		addr = offset + ver_offset - start;
-		for (i = 0; i < 16; i += 4) {
-			if (tg3_nvram_read(tp, addr + i, &val))
-				return;
-
-			val = cpu_to_le32(val);
-			memcpy(tp->fw_ver + i, &val, 4);
-		}
+		val = le32_to_cpu(val);
+		memcpy(tp->fw_ver + i, &val, 4);
 	}
+
+	if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+	     (tp->tg3_flags & TG3_FLG3_ENABLE_APE))
+		return;
+
+	for (offset = TG3_NVM_DIR_START;
+	     offset < TG3_NVM_DIR_END;
+	     offset += TG3_NVM_DIRENT_SIZE) {
+		if (tg3_nvram_read_swab(tp, offset, &val))
+			return;
+
+		if ((val >> TG3_NVM_DIRTYPE_SHIFT) == TG3_NVM_DIRTYPE_ASFINI)
+			break;
+	}
+
+	if (offset == TG3_NVM_DIR_END)
+		return;
+
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+		start = 0x08000000;
+	else if (tg3_nvram_read_swab(tp, offset - 4, &start))
+		return;
+
+	if (tg3_nvram_read_swab(tp, offset + 4, &offset) ||
+	    !tg3_fw_img_is_valid(tp, offset) ||
+	    tg3_nvram_read_swab(tp, offset + 8, &val))
+		return;
+
+	offset += val - start;
+
+	bcnt = strlen(tp->fw_ver);
+
+	tp->fw_ver[bcnt++] = ',';
+	tp->fw_ver[bcnt++] = ' ';
+
+	for (i = 0; i < 4; i++) {
+		if (tg3_nvram_read(tp, offset, &val))
+			return;
+
+		val = le32_to_cpu(val);
+		offset += sizeof(val);
+
+		if (bcnt > TG3_VER_SIZE - sizeof(val)) {
+			memcpy(&tp->fw_ver[bcnt], &val, TG3_VER_SIZE - bcnt);
+			break;
+		}
+
+		memcpy(&tp->fw_ver[bcnt], &val, sizeof(val));
+		bcnt += sizeof(val);
+	}
+
+	tp->fw_ver[TG3_VER_SIZE - 1] = 0;
 }
 
 static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 6dbdad2b8f88..495a1dfaba5a 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -1540,6 +1540,12 @@
 #define TG3_EEPROM_MAGIC_HW		0xabcd
 #define TG3_EEPROM_MAGIC_HW_MSK		0xffff
 
+#define TG3_NVM_DIR_START		0x18
+#define TG3_NVM_DIR_END			0x78
+#define TG3_NVM_DIRENT_SIZE		0xc
+#define TG3_NVM_DIRTYPE_SHIFT		24
+#define TG3_NVM_DIRTYPE_ASFINI		1
+
 /* 32K Window into NIC internal memory */
 #define NIC_SRAM_WIN_BASE		0x00008000
 
@@ -2418,7 +2424,8 @@ struct tg3 {
 	u32				pci_cmd;
 
 	char				board_part_number[24];
-	char				fw_ver[16];
+#define TG3_VER_SIZE 32
+	char				fw_ver[TG3_VER_SIZE];
 	u32				nic_sram_data_cfg;
 	u32				pci_clock_ctrl;
 	struct pci_dev			*pdev_peer;

From 8a6eac90e21633e054e17d21454a2c26824aeb18 Mon Sep 17 00:00:00 2001
From: Matt Carlson <mcarlson@broadcom.com>
Date: Sun, 21 Oct 2007 16:17:55 -0700
Subject: [PATCH 19/30] [TG3]: PCI command adjustment

This patch changes the way the driver works with the PCI command
register.  It adjusts the access size from dwords to words.  This patch
is done both as a PCI configuration space cleanup and as preparatory
work for PCI error recovery.

Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/tg3.c | 7 ++-----
 drivers/net/tg3.h | 2 +-
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 98f465828110..328eb4adc10b 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -5029,10 +5029,7 @@ static int tg3_poll_fw(struct tg3 *tp)
 /* Save PCI command register before chip reset */
 static void tg3_save_pci_state(struct tg3 *tp)
 {
-	u32 val;
-
-	pci_read_config_dword(tp->pdev, TG3PCI_COMMAND, &val);
-	tp->pci_cmd = val;
+	pci_read_config_word(tp->pdev, PCI_COMMAND, &tp->pci_cmd);
 }
 
 /* Restore PCI state after chip reset */
@@ -5055,7 +5052,7 @@ static void tg3_restore_pci_state(struct tg3 *tp)
 		       PCISTATE_ALLOW_APE_SHMEM_WR;
 	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
 
-	pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
+	pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd);
 
 	if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) {
 		pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 495a1dfaba5a..1d5b2a3dd29d 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2421,7 +2421,7 @@ struct tg3 {
 #define PHY_REV_BCM5411_X0		0x1 /* Found on Netgear GA302T */
 
 	u32				led_ctrl;
-	u32				pci_cmd;
+	u16				pci_cmd;
 
 	char				board_part_number[24];
 #define TG3_VER_SIZE 32

From 33b0c4fe6d0dd19fc7c9b801855f55c5260f2858 Mon Sep 17 00:00:00 2001
From: Matt Carlson <mcarlson@broadcom.com>
Date: Sun, 21 Oct 2007 16:22:38 -0700
Subject: [PATCH 20/30] [TG3]: Update version to 3.85

This patch updates the version number to 3.85.

Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/tg3.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 328eb4adc10b..09440d783e65 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -64,8 +64,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.84"
-#define DRV_MODULE_RELDATE	"October 12, 2007"
+#define DRV_MODULE_VERSION	"3.85"
+#define DRV_MODULE_RELDATE	"October 18, 2007"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0

From bfb85c9f753a7172bd962e8717118191dfd612cc Mon Sep 17 00:00:00 2001
From: Randy Dunlap <randy.dunlap@oracle.com>
Date: Sun, 21 Oct 2007 16:24:27 -0700
Subject: [PATCH 21/30] [ATM]: Fix clip module reload crash.

net/atm/clip.c crashes the kernel if it (module) is loaded, removed,
and then loaded again.  Its exit call to neigh_table_clear()
should destroy the cache after freeing it.

Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/core/neighbour.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 67ba9914e52e..05979e356963 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1438,6 +1438,9 @@ int neigh_table_clear(struct neigh_table *tbl)
 	free_percpu(tbl->stats);
 	tbl->stats = NULL;
 
+	kmem_cache_destroy(tbl->kmem_cachep);
+	tbl->kmem_cachep = NULL;
+
 	return 0;
 }
 

From deea84b0ae3d26b41502ae0a39fe7fe134e703d0 Mon Sep 17 00:00:00 2001
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Sun, 21 Oct 2007 16:27:46 -0700
Subject: [PATCH 22/30] [NET]: Fix SKB_WITH_OVERHEAD calculation

The calculation in SKB_WITH_OVERHEAD is incorrect in that it can cause
an overflow across a page boundary which is what it's meant to prevent.
In particular, the header length (X) should not be lumped together with
skb_shared_info.  The latter needs to be aligned properly while the header
has no choice but to sit in front of wherever the payload is.

Therefore the correct calculation is to take away the aligned size of
skb_shared_info, and then subtract the header length.  The resulting
quantity L satisfies the following inequality:

	SKB_DATA_ALIGN(L + X) + sizeof(struct skb_shared_info) <= PAGE_SIZE

This is the quantity used by alloc_skb to do the actual allocation.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/linux/skbuff.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f93f22b3d2ff..369f60a4797d 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -41,8 +41,7 @@
 #define SKB_DATA_ALIGN(X)	(((X) + (SMP_CACHE_BYTES - 1)) & \
 				 ~(SMP_CACHE_BYTES - 1))
 #define SKB_WITH_OVERHEAD(X)	\
-	(((X) - sizeof(struct skb_shared_info)) & \
-	 ~(SMP_CACHE_BYTES - 1))
+	((X) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
 #define SKB_MAX_ORDER(X, ORDER) \
 	SKB_WITH_OVERHEAD((PAGE_SIZE << (ORDER)) - (X))
 #define SKB_MAX_HEAD(X)		(SKB_MAX_ORDER((X), 0))

From 81429973cfff7745792c877dd083eec29724ec97 Mon Sep 17 00:00:00 2001
From: Olof Johansson <olof@lixom.net>
Date: Sun, 21 Oct 2007 16:32:58 -0700
Subject: [PATCH 23/30] [NIU]: Cleanup PAGE_SIZE checks a bit

I get the following warning from a powerpc allyesconfig of current
mainline:

drivers/net/niu.c: In function 'niu_size_rbr':
drivers/net/niu.c:3113: warning: large integer implicitly truncated to unsigned type

PAGE_SIZE in this case is 64KB, so I don't quite get why gcc can't
tell that the line in question will never be reached.

I suggest the following instead, but I can unfortunately not do
anything but build test it.

Also, the driver does some other checks to make sure that PAGE_SIZE is
a power of two (BUILD_BUG_ON() in niu_init()), doesn't seem like that
could ever be untrue? Or are there really archs with non-power-of-two
PAGE_SIZE?

Signed-off-by: Olof Johansson <olof@lixom.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/niu.c | 34 +++++-----------------------------
 1 file changed, 5 insertions(+), 29 deletions(-)

diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index ed1f9bbb2a32..112ab079ce7d 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -3103,31 +3103,12 @@ static int niu_alloc_tx_ring_info(struct niu *np,
 
 static void niu_size_rbr(struct niu *np, struct rx_ring_info *rp)
 {
-	u16 bs;
+	u16 bss;
 
-	switch (PAGE_SIZE) {
-	case 4 * 1024:
-	case 8 * 1024:
-	case 16 * 1024:
-	case 32 * 1024:
-		rp->rbr_block_size = PAGE_SIZE;
-		rp->rbr_blocks_per_page = 1;
-		break;
+	bss = min(PAGE_SHIFT, 15);
 
-	default:
-		if (PAGE_SIZE % (32 * 1024) == 0)
-			bs = 32 * 1024;
-		else if (PAGE_SIZE % (16 * 1024) == 0)
-			bs = 16 * 1024;
-		else if (PAGE_SIZE % (8 * 1024) == 0)
-			bs = 8 * 1024;
-		else if (PAGE_SIZE % (4 * 1024) == 0)
-			bs = 4 * 1024;
-		else
-			BUG();
-		rp->rbr_block_size = bs;
-		rp->rbr_blocks_per_page = PAGE_SIZE / bs;
-	}
+	rp->rbr_block_size = 1 << bss;
+	rp->rbr_blocks_per_page = 1 << (PAGE_SHIFT-bss);
 
 	rp->rbr_sizes[0] = 256;
 	rp->rbr_sizes[1] = 1024;
@@ -7902,12 +7883,7 @@ static int __init niu_init(void)
 {
 	int err = 0;
 
-	BUILD_BUG_ON((PAGE_SIZE < 4 * 1024) ||
-		     ((PAGE_SIZE > 32 * 1024) &&
-		      ((PAGE_SIZE % (32 * 1024)) != 0 &&
-		       (PAGE_SIZE % (16 * 1024)) != 0 &&
-		       (PAGE_SIZE % (8 * 1024)) != 0 &&
-		       (PAGE_SIZE % (4 * 1024)) != 0)));
+	BUILD_BUG_ON(PAGE_SIZE < 4 * 1024);
 
 	niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT);
 

From 305e1e96911417d8cda2699f6a20a6f434616a8c Mon Sep 17 00:00:00 2001
From: Jean Delvare <jdelvare@suse.de>
Date: Sun, 21 Oct 2007 16:44:04 -0700
Subject: [PATCH 24/30] [INET]: Let inet_diag and friends autoload

By adding module aliases to inet_diag, tcp_diag and dccp_diag, we let
them load automatically as needed. This makes tools like "ss" run
faster.

Signed-off-by: Jean Delvare <jdelvare@suse.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/linux/net.h  | 4 ++++
 net/dccp/diag.c      | 1 +
 net/ipv4/inet_diag.c | 7 +++++++
 net/ipv4/tcp_diag.c  | 1 +
 4 files changed, 13 insertions(+)

diff --git a/include/linux/net.h b/include/linux/net.h
index c136abce7ef6..dd79cdb8c4cf 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -313,6 +313,10 @@ static const struct proto_ops name##_ops = {			\
 #define MODULE_ALIAS_NET_PF_PROTO(pf, proto) \
 	MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto))
 
+#define MODULE_ALIAS_NET_PF_PROTO_TYPE(pf, proto, type) \
+	MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto) \
+		     "-type-" __stringify(type))
+
 #ifdef CONFIG_SYSCTL
 #include <linux/sysctl.h>
 extern ctl_table net_table[];
diff --git a/net/dccp/diag.c b/net/dccp/diag.c
index 0f3745585a94..d8a3509b26f6 100644
--- a/net/dccp/diag.c
+++ b/net/dccp/diag.c
@@ -68,3 +68,4 @@ module_exit(dccp_diag_fini);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
 MODULE_DESCRIPTION("DCCP inet_diag handler");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_INET_DIAG, DCCPDIAG_GETSOCK);
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 7eb83ebed2ec..dc429b6b0ba6 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -815,6 +815,12 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 	    nlmsg_len(nlh) < hdrlen)
 		return -EINVAL;
 
+#ifdef CONFIG_KMOD
+	if (inet_diag_table[nlh->nlmsg_type] == NULL)
+		request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
+			       NETLINK_INET_DIAG, nlh->nlmsg_type);
+#endif
+
 	if (inet_diag_table[nlh->nlmsg_type] == NULL)
 		return -ENOENT;
 
@@ -914,3 +920,4 @@ static void __exit inet_diag_exit(void)
 module_init(inet_diag_init);
 module_exit(inet_diag_exit);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_INET_DIAG);
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 3904d2158a92..2fbcc7d1b1a0 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -56,3 +56,4 @@ static void __exit tcp_diag_exit(void)
 module_init(tcp_diag_init);
 module_exit(tcp_diag_exit);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_INET_DIAG, TCPDIAG_GETSOCK);

From 7131c6c73656b92aea806c6e688e97aa49ff911e Mon Sep 17 00:00:00 2001
From: Jean Delvare <jdelvare@suse.de>
Date: Sun, 21 Oct 2007 16:45:03 -0700
Subject: [PATCH 25/30] [INET]: Use MODULE_ALIAS_NET_PF_PROTO_TYPE where
 possible.

Now that we have this new macro, use it where possible.

Signed-off-by: Jean Delvare <jdelvare@suse.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/dccp/ipv4.c | 4 ++--
 net/dccp/ipv6.c | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 44f6e17e105f..222549ab274a 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -1037,8 +1037,8 @@ module_exit(dccp_v4_exit);
  * values directly, Also cover the case where the protocol is not specified,
  * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP
  */
-MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6");
-MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 33, 6);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 0, 6);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
 MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index cac53548c2d8..bbadd6681b83 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -1219,8 +1219,8 @@ module_exit(dccp_v6_exit);
  * values directly, Also cover the case where the protocol is not specified,
  * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
  */
-MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-33-type-6");
-MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-0-type-6");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
 MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");

From dfa4091129019959f4608756f76dc687495287ad Mon Sep 17 00:00:00 2001
From: Pavel Emelyanov <xemul@openvz.org>
Date: Sun, 21 Oct 2007 16:57:55 -0700
Subject: [PATCH 26/30] [NET]: Use the skb_set_queue_mapping where appropriate

There's already such a helper to initialize this field.  Use it.

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/core/dev.c    | 2 +-
 net/core/pktgen.c | 6 ++----
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index 38b03da5c1ca..1672cc134853 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1661,7 +1661,7 @@ gso:
 		q = dev->qdisc;
 		if (q->enqueue) {
 			/* reset queue_mapping to zero */
-			skb->queue_mapping = 0;
+			skb_set_queue_mapping(skb, 0);
 			rc = q->enqueue(skb, q);
 			qdisc_run(dev);
 			spin_unlock(&dev->queue_lock);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index c4719edb55c0..b78235e5a7f4 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2603,8 +2603,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
 	skb->network_header = skb->tail;
 	skb->transport_header = skb->network_header + sizeof(struct iphdr);
 	skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));
-	skb->queue_mapping = pkt_dev->cur_queue_map;
-
+	skb_set_queue_mapping(skb, pkt_dev->cur_queue_map);
 	iph = ip_hdr(skb);
 	udph = udp_hdr(skb);
 
@@ -2941,8 +2940,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
 	skb->network_header = skb->tail;
 	skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
 	skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));
-	skb->queue_mapping = pkt_dev->cur_queue_map;
-
+	skb_set_queue_mapping(skb, pkt_dev->cur_queue_map);
 	iph = ipv6_hdr(skb);
 	udph = udp_hdr(skb);
 

From 4e3ab47a547616e583c7a5458beced6aa34c8ef3 Mon Sep 17 00:00:00 2001
From: Pavel Emelyanov <xemul@openvz.org>
Date: Sun, 21 Oct 2007 17:01:29 -0700
Subject: [PATCH 27/30] [NET]: Make and use skb_get_queue_mapping

Make the helper for getting the field, symmetrical to
the "set" one. Return 0 if CONFIG_NETDEVICES_MULTIQUEUE=n

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/cpmac.c    | 2 +-
 include/linux/skbuff.h | 9 +++++++++
 net/sched/sch_teql.c   | 2 +-
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index ed53aaab4c02..ae419736158e 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -471,7 +471,7 @@ static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 
 	len = max(skb->len, ETH_ZLEN);
-	queue = skb->queue_mapping;
+	queue = skb_get_queue_mapping(skb);
 #ifdef CONFIG_NETDEVICES_MULTIQUEUE
 	netif_stop_subqueue(dev, queue);
 #else
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 369f60a4797d..ecb0edef0b39 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1769,6 +1769,15 @@ static inline void skb_set_queue_mapping(struct sk_buff *skb, u16 queue_mapping)
 #endif
 }
 
+static inline u16 skb_get_queue_mapping(struct sk_buff *skb)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+	return skb->queue_mapping;
+#else
+	return 0;
+#endif
+}
+
 static inline void skb_copy_queue_mapping(struct sk_buff *to, const struct sk_buff *from)
 {
 #ifdef CONFIG_NETDEVICES_MULTIQUEUE
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index be57cf317a7f..a9fad7162b5d 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -266,7 +266,7 @@ static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
 	int busy;
 	int nores;
 	int len = skb->len;
-	int subq = skb->queue_mapping;
+	int subq = skb_get_queue_mapping(skb);
 	struct sk_buff *skb_res = NULL;
 
 	start = master->slaves;

From 668f895a85b0c3a62a690425145f13dabebebd7a Mon Sep 17 00:00:00 2001
From: Pavel Emelyanov <xemul@openvz.org>
Date: Sun, 21 Oct 2007 17:01:56 -0700
Subject: [PATCH 28/30] [NET]: Hide the queue_mapping field inside
 netif_subqueue_stopped

Many places get the queue_mapping field from skb to pass it to the
netif_subqueue_stopped() which will be 0 in any case.

Make the helper that works with sk_buff

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/linux/netdevice.h | 7 ++++++-
 net/core/dev.c            | 4 ++--
 net/core/netpoll.c        | 4 ++--
 net/core/pktgen.c         | 6 +++---
 net/sched/sch_teql.c      | 4 ++--
 5 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 6f85db3535e2..4a3f54e358e5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -996,7 +996,7 @@ static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index)
  *
  * Check individual transmit queue of a device with multiple transmit queues.
  */
-static inline int netif_subqueue_stopped(const struct net_device *dev,
+static inline int __netif_subqueue_stopped(const struct net_device *dev,
 					 u16 queue_index)
 {
 #ifdef CONFIG_NETDEVICES_MULTIQUEUE
@@ -1007,6 +1007,11 @@ static inline int netif_subqueue_stopped(const struct net_device *dev,
 #endif
 }
 
+static inline int netif_subqueue_stopped(const struct net_device *dev,
+					 struct sk_buff *skb)
+{
+	return __netif_subqueue_stopped(dev, skb_get_queue_mapping(skb));
+}
 
 /**
  *	netif_wake_subqueue - allow sending packets on subqueue
diff --git a/net/core/dev.c b/net/core/dev.c
index 1672cc134853..872658927e47 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1553,7 +1553,7 @@ gso:
 			return rc;
 		}
 		if (unlikely((netif_queue_stopped(dev) ||
-			     netif_subqueue_stopped(dev, skb->queue_mapping)) &&
+			     netif_subqueue_stopped(dev, skb)) &&
 			     skb->next))
 			return NETDEV_TX_BUSY;
 	} while (skb->next);
@@ -1692,7 +1692,7 @@ gso:
 			HARD_TX_LOCK(dev, cpu);
 
 			if (!netif_queue_stopped(dev) &&
-			    !netif_subqueue_stopped(dev, skb->queue_mapping)) {
+			    !netif_subqueue_stopped(dev, skb)) {
 				rc = 0;
 				if (!dev_hard_start_xmit(skb, dev)) {
 					HARD_TX_UNLOCK(dev);
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 95daba624967..bf8d18f1b013 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -67,7 +67,7 @@ static void queue_process(struct work_struct *work)
 		local_irq_save(flags);
 		netif_tx_lock(dev);
 		if ((netif_queue_stopped(dev) ||
-		     netif_subqueue_stopped(dev, skb->queue_mapping)) ||
+		     netif_subqueue_stopped(dev, skb)) ||
 		     dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) {
 			skb_queue_head(&npinfo->txq, skb);
 			netif_tx_unlock(dev);
@@ -269,7 +269,7 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
 		     tries > 0; --tries) {
 			if (netif_tx_trylock(dev)) {
 				if (!netif_queue_stopped(dev) &&
-				    !netif_subqueue_stopped(dev, skb->queue_mapping))
+				    !netif_subqueue_stopped(dev, skb))
 					status = dev->hard_start_xmit(skb, dev);
 				netif_tx_unlock(dev);
 
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index b78235e5a7f4..de33f36947e9 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -3383,7 +3383,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 
 	if ((netif_queue_stopped(odev) ||
 	     (pkt_dev->skb &&
-	      netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping))) ||
+	      netif_subqueue_stopped(odev, pkt_dev->skb))) ||
 	    need_resched()) {
 		idle_start = getCurUs();
 
@@ -3400,7 +3400,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 		pkt_dev->idle_acc += getCurUs() - idle_start;
 
 		if (netif_queue_stopped(odev) ||
-		    netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
+		    netif_subqueue_stopped(odev, pkt_dev->skb)) {
 			pkt_dev->next_tx_us = getCurUs();	/* TODO */
 			pkt_dev->next_tx_ns = 0;
 			goto out;	/* Try the next interface */
@@ -3429,7 +3429,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 
 	netif_tx_lock_bh(odev);
 	if (!netif_queue_stopped(odev) &&
-	    !netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
+	    !netif_subqueue_stopped(odev, pkt_dev->skb)) {
 
 		atomic_inc(&(pkt_dev->skb->users));
 	      retry_now:
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index a9fad7162b5d..421281d9dd1d 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -284,7 +284,7 @@ restart:
 		if (slave->qdisc_sleeping != q)
 			continue;
 		if (netif_queue_stopped(slave) ||
-		    netif_subqueue_stopped(slave, subq) ||
+		    __netif_subqueue_stopped(slave, subq) ||
 		    !netif_running(slave)) {
 			busy = 1;
 			continue;
@@ -294,7 +294,7 @@ restart:
 		case 0:
 			if (netif_tx_trylock(slave)) {
 				if (!netif_queue_stopped(slave) &&
-				    !netif_subqueue_stopped(slave, subq) &&
+				    !__netif_subqueue_stopped(slave, subq) &&
 				    slave->hard_start_xmit(skb, slave) == 0) {
 					netif_tx_unlock(slave);
 					master->slaves = NEXT_SLAVE(q);

From e3fa259bcbbca25c8e8275c8dcedcf484854465b Mon Sep 17 00:00:00 2001
From: Pavel Emelyanov <xemul@openvz.org>
Date: Sun, 21 Oct 2007 17:02:30 -0700
Subject: [PATCH 29/30] [NET]: Cut off the queue_mapping field from sk_buff

Just hide it behind the #ifdef, because nobody wants
it now.

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/linux/skbuff.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index ecb0edef0b39..fd4e12f24270 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -300,8 +300,9 @@ struct sk_buff {
 #endif
 
 	int			iif;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
 	__u16			queue_mapping;
-
+#endif
 #ifdef CONFIG_NET_SCHED
 	__u16			tc_index;	/* traffic control index */
 #ifdef CONFIG_NET_CLS_ACT

From ea2c47b42f12dadbad9d879fb6df102b9003ab82 Mon Sep 17 00:00:00 2001
From: Masahide NAKAMURA <nakam@linux-ipv6.org>
Date: Mon, 22 Oct 2007 02:30:15 -0700
Subject: [PATCH 30/30] [IPSEC] IPV6: Fix to add tunnel mode SA correctly.

Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv6/ah6.c  | 1 +
 net/ipv6/esp6.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 67cd06613a25..66a9139d46e9 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -483,6 +483,7 @@ static int ah6_init_state(struct xfrm_state *x)
 		break;
 	case XFRM_MODE_TUNNEL:
 		x->props.header_len += sizeof(struct ipv6hdr);
+		break;
 	default:
 		goto error;
 	}
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index b0715432e454..72a659806cad 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -360,6 +360,7 @@ static int esp6_init_state(struct xfrm_state *x)
 		break;
 	case XFRM_MODE_TUNNEL:
 		x->props.header_len += sizeof(struct ipv6hdr);
+		break;
 	default:
 		goto error;
 	}