[Bluetooth] Update class of device value whenever possible
[pandora-kernel.git] / net / bluetooth / hci_event.c
index d4d2dcc..e476761 100644 (file)
@@ -110,6 +110,25 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_unlock(hdev);
 }
 
+static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_link_policy *rp = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+       if (conn)
+               conn->link_policy = __le16_to_cpu(rp->policy);
+
+       hci_dev_unlock(hdev);
+}
+
 static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_rp_write_link_policy *rp = (void *) skb->data;
@@ -128,13 +147,41 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
-       if (conn) {
+       if (conn)
                conn->link_policy = get_unaligned_le16(sent + 2);
-       }
 
        hci_dev_unlock(hdev);
 }
 
+static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       hdev->link_policy = __le16_to_cpu(rp->policy);
+}
+
+static void hci_cc_write_def_link_policy(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_DEF_LINK_POLICY);
+       if (!sent)
+               return;
+
+       if (!status)
+               hdev->link_policy = get_unaligned_le16(sent);
+
+       hci_req_complete(hdev, status);
+}
+
 static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -151,12 +198,14 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, status);
 
+       if (status)
+               return;
+
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
        if (!sent)
                return;
 
-       if (!status)
-               memcpy(hdev->dev_name, sent, 248);
+       memcpy(hdev->dev_name, sent, 248);
 }
 
 static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -266,12 +315,14 @@ static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, status);
 
+       if (status)
+               return;
+
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
        if (!sent)
                return;
 
-       if (!status)
-               memcpy(hdev->dev_class, sent, 3);
+       memcpy(hdev->dev_class, sent, 3);
 }
 
 static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
@@ -286,7 +337,7 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
 
        setting = __le16_to_cpu(rp->voice_setting);
 
-       if (hdev->voice_setting == setting )
+       if (hdev->voice_setting == setting)
                return;
 
        hdev->voice_setting = setting;
@@ -303,28 +354,31 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
+       __u16 setting;
        void *sent;
 
        BT_DBG("%s status 0x%x", hdev->name, status);
 
+       if (status)
+               return;
+
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_VOICE_SETTING);
        if (!sent)
                return;
 
-       if (!status) {
-               __u16 setting = get_unaligned_le16(sent);
+       setting = get_unaligned_le16(sent);
+
+       if (hdev->voice_setting == setting)
+               return;
 
-               if (hdev->voice_setting != setting) {
-                       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);
-                               hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
-                               tasklet_enable(&hdev->tx_task);
-                       }
-               }
+       if (hdev->notify) {
+               tasklet_disable(&hdev->tx_task);
+               hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
+               tasklet_enable(&hdev->tx_task);
        }
 }
 
@@ -347,8 +401,8 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
                return;
 
        hdev->hci_ver = rp->hci_ver;
-       hdev->hci_rev = btohs(rp->hci_rev);
-       hdev->manufacturer = btohs(rp->manufacturer);
+       hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
+       hdev->manufacturer = __le16_to_cpu(rp->manufacturer);
 
        BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
                                        hdev->manufacturer,
@@ -690,14 +744,6 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        hci_send_cmd(hdev, HCI_OP_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, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp);
-               }
-
                /* Set packet type for incoming connection */
                if (!conn->out && hdev->hci_ver < 3) {
                        struct hci_cp_change_conn_ptype cp;
@@ -750,10 +796,14 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 
        if (mask & HCI_LM_ACCEPT) {
                /* Connection accepted */
+               struct inquiry_entry *ie;
                struct hci_conn *conn;
 
                hci_dev_lock(hdev);
 
+               if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr)))
+                       memcpy(ie->data.dev_class, ev->dev_class, 3);
+
                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))) {
@@ -974,10 +1024,22 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
                hci_cc_role_discovery(hdev, skb);
                break;
 
+       case HCI_OP_READ_LINK_POLICY:
+               hci_cc_read_link_policy(hdev, skb);
+               break;
+
        case HCI_OP_WRITE_LINK_POLICY:
                hci_cc_write_link_policy(hdev, skb);
                break;
 
+       case HCI_OP_READ_DEF_LINK_POLICY:
+               hci_cc_read_def_link_policy(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_DEF_LINK_POLICY:
+               hci_cc_write_def_link_policy(hdev, skb);
+               break;
+
        case HCI_OP_RESET:
                hci_cc_reset(hdev, skb);
                break;