Bluetooth: Unobfuscate tasklet_schedule usage
[safe/jmp/linux-2.6] / net / bluetooth / hci_core.c
index 55dc42e..94ba349 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
 
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
 
    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
    SOFTWARE IS DISCLAIMED.
 */
 
 /* Bluetooth HCI core. */
 
    SOFTWARE IS DISCLAIMED.
 */
 
 /* Bluetooth HCI core. */
 
-#include <linux/config.h>
+#include <linux/jiffies.h>
 #include <linux/module.h>
 #include <linux/kmod.h>
 
 #include <linux/module.h>
 #include <linux/kmod.h>
 
@@ -39,6 +39,7 @@
 #include <linux/skbuff.h>
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/skbuff.h>
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
+#include <linux/rfkill.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef CONFIG_BT_HCI_CORE_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 static void hci_cmd_task(unsigned long arg);
 static void hci_rx_task(unsigned long arg);
 static void hci_tx_task(unsigned long arg);
 static void hci_cmd_task(unsigned long arg);
 static void hci_rx_task(unsigned long arg);
 static void hci_tx_task(unsigned long arg);
@@ -73,23 +69,23 @@ DEFINE_RWLOCK(hci_cb_list_lock);
 struct hci_proto *hci_proto[HCI_MAX_PROTO];
 
 /* HCI notifiers list */
 struct hci_proto *hci_proto[HCI_MAX_PROTO];
 
 /* HCI notifiers list */
-static struct notifier_block *hci_notifier;
+static ATOMIC_NOTIFIER_HEAD(hci_notifier);
 
 /* ---- HCI notifications ---- */
 
 int hci_register_notifier(struct notifier_block *nb)
 {
 
 /* ---- HCI notifications ---- */
 
 int hci_register_notifier(struct notifier_block *nb)
 {
-       return notifier_chain_register(&hci_notifier, nb);
+       return atomic_notifier_chain_register(&hci_notifier, nb);
 }
 
 int hci_unregister_notifier(struct notifier_block *nb)
 {
 }
 
 int hci_unregister_notifier(struct notifier_block *nb)
 {
-       return notifier_chain_unregister(&hci_notifier, nb);
+       return atomic_notifier_chain_unregister(&hci_notifier, nb);
 }
 
 }
 
-void hci_notify(struct hci_dev *hdev, int event)
+static void hci_notify(struct hci_dev *hdev, int event)
 {
 {
-       notifier_call_chain(&hci_notifier, event, hdev);
+       atomic_notifier_call_chain(&hci_notifier, event, hdev);
 }
 
 /* ---- HCI requests ---- */
 }
 
 /* ---- HCI requests ---- */
@@ -117,7 +113,7 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
 }
 
 /* Execute request and wait for completion. */
 }
 
 /* Execute request and wait for completion. */
-static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), 
+static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
                                unsigned long opt, __u32 timeout)
 {
        DECLARE_WAITQUEUE(wait, current);
                                unsigned long opt, __u32 timeout)
 {
        DECLARE_WAITQUEUE(wait, current);
@@ -150,7 +146,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
        default:
                err = -ETIMEDOUT;
                break;
        default:
                err = -ETIMEDOUT;
                break;
-       };
+       }
 
        hdev->req_status = hdev->req_result = 0;
 
 
        hdev->req_status = hdev->req_result = 0;
 
@@ -164,6 +160,9 @@ static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *
 {
        int ret;
 
 {
        int ret;
 
+       if (!test_bit(HCI_UP, &hdev->flags))
+               return -ENETDOWN;
+
        /* Serialize all requests */
        hci_req_lock(hdev);
        ret = __hci_request(hdev, req, opt, timeout);
        /* Serialize all requests */
        hci_req_lock(hdev);
        ret = __hci_request(hdev, req, opt, timeout);
@@ -177,13 +176,14 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
        BT_DBG("%s %ld", hdev->name, opt);
 
        /* Reset device */
        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)
 {
        struct sk_buff *skb;
 }
 
 static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 {
        struct sk_buff *skb;
-       __u16 param;
+       __le16 param;
+       __u8 flt_type;
 
        BT_DBG("%s %ld", hdev->name, opt);
 
 
        BT_DBG("%s %ld", hdev->name, opt);
 
@@ -193,57 +193,64 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
        while ((skb = skb_dequeue(&hdev->driver_init))) {
                bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
                skb->dev = (void *) hdev;
        while ((skb = skb_dequeue(&hdev->driver_init))) {
                bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
                skb->dev = (void *) hdev;
+
                skb_queue_tail(&hdev->cmd_q, skb);
                skb_queue_tail(&hdev->cmd_q, skb);
-               hci_sched_cmd(hdev);
+               tasklet_schedule(&hdev->cmd_task);
        }
        skb_queue_purge(&hdev->driver_init);
 
        /* Mandatory initialization */
 
        /* Reset */
        }
        skb_queue_purge(&hdev->driver_init);
 
        /* Mandatory initialization */
 
        /* Reset */
-       if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks))
-                       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
+       if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks))
+                       hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
 
        /* Read Local Supported Features */
 
        /* 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, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
 
        /* Read Buffer Size (ACL mtu, max pkt, etc.) */
 
        /* 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 */
        {
                struct hci_cp_host_buffer_size cp;
 
 #if 0
        /* Host buffer size */
        {
                struct hci_cp_host_buffer_size cp;
-               cp.acl_mtu = __cpu_to_le16(HCI_MAX_ACL_SIZE);
+               cp.acl_mtu = cpu_to_le16(HCI_MAX_ACL_SIZE);
                cp.sco_mtu = HCI_MAX_SCO_SIZE;
                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);
+               cp.acl_max_pkt = cpu_to_le16(0xffff);
+               cp.sco_max_pkt = cpu_to_le16(0xffff);
+               hci_send_cmd(hdev, HCI_OP_HOST_BUFFER_SIZE, sizeof(cp), &cp);
        }
 #endif
 
        /* Read BD Address */
        }
 #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 */
 
        /* 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 */
 
        /* Optional initialization */
 
        /* Clear Event Filters */
-       {
-               struct hci_cp_set_event_flt cp;
-               cp.flt_type  = HCI_FLT_CLEAR_ALL;
-               hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, sizeof(cp), &cp);
-       }
+       flt_type = HCI_FLT_CLEAR_ALL;
+       hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
 
        /* Page timeout ~20 secs */
 
        /* Page timeout ~20 secs */
-       param = __cpu_to_le16(0x8000);
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_PG_TIMEOUT, 2, &param);
+       param = cpu_to_le16(0x8000);
+       hci_send_cmd(hdev, HCI_OP_WRITE_PG_TIMEOUT, 2, &param);
 
        /* Connection accept timeout ~20 secs */
 
        /* Connection accept timeout ~20 secs */
-       param = __cpu_to_le16(0x7d00);
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_CA_TIMEOUT, 2, &param);
+       param = cpu_to_le16(0x7d00);
+       hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
 }
 
 static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
 }
 
 static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
@@ -253,7 +260,7 @@ static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
        BT_DBG("%s %x", hdev->name, scan);
 
        /* Inquiry and Page scans */
        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)
 }
 
 static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
@@ -263,7 +270,7 @@ static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
        BT_DBG("%s %x", hdev->name, auth);
 
        /* Authentication */
        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)
 }
 
 static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
@@ -272,11 +279,21 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
 
        BT_DBG("%s %x", hdev->name, encrypt);
 
 
        BT_DBG("%s %x", hdev->name, encrypt);
 
-       /* Authentication */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt);
+       /* Encryption */
+       hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
+}
+
+static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
+{
+       __le16 policy = cpu_to_le16(opt);
+
+       BT_DBG("%s %x", hdev->name, policy);
+
+       /* Default link policy */
+       hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
 }
 
 }
 
-/* Get HCI device by index. 
+/* Get HCI device by index.
  * Device is held on return. */
 struct hci_dev *hci_dev_get(int index)
 {
  * Device is held on return. */
 struct hci_dev *hci_dev_get(int index)
 {
@@ -337,9 +354,8 @@ void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data)
 
        if (!(e = hci_inquiry_cache_lookup(hdev, &data->bdaddr))) {
                /* Entry not in the cache. Add new one. */
 
        if (!(e = hci_inquiry_cache_lookup(hdev, &data->bdaddr))) {
                /* Entry not in the cache. Add new one. */
-               if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
+               if (!(e = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
                        return;
                        return;
-               memset(e, 0, sizeof(struct inquiry_entry));
                e->next     = cache->list;
                cache->list = e;
        }
                e->next     = cache->list;
                cache->list = e;
        }
@@ -385,7 +401,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;
        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)
 }
 
 int hci_inquiry(void __user *arg)
@@ -404,7 +420,7 @@ int hci_inquiry(void __user *arg)
                return -ENODEV;
 
        hci_dev_lock_bh(hdev);
                return -ENODEV;
 
        hci_dev_lock_bh(hdev);
-       if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || 
+       if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
                                        inquiry_cache_empty(hdev) ||
                                        ir.flags & IREQ_CACHE_FLUSH) {
                inquiry_cache_flush(hdev);
                                        inquiry_cache_empty(hdev) ||
                                        ir.flags & IREQ_CACHE_FLUSH) {
                inquiry_cache_flush(hdev);
@@ -412,7 +428,7 @@ int hci_inquiry(void __user *arg)
        }
        hci_dev_unlock_bh(hdev);
 
        }
        hci_dev_unlock_bh(hdev);
 
-       timeo = ir.length * 2 * HZ;
+       timeo = ir.length * msecs_to_jiffies(2000);
        if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
                goto done;
 
        if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
                goto done;
 
@@ -438,7 +454,7 @@ int hci_inquiry(void __user *arg)
                if (copy_to_user(ptr, buf, sizeof(struct inquiry_info) *
                                        ir.num_rsp))
                        err = -EFAULT;
                if (copy_to_user(ptr, buf, sizeof(struct inquiry_info) *
                                        ir.num_rsp))
                        err = -EFAULT;
-       } else 
+       } else
                err = -EFAULT;
 
        kfree(buf);
                err = -EFAULT;
 
        kfree(buf);
@@ -462,6 +478,11 @@ int hci_dev_open(__u16 dev)
 
        hci_req_lock(hdev);
 
 
        hci_req_lock(hdev);
 
+       if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) {
+               ret = -ERFKILL;
+               goto done;
+       }
+
        if (test_bit(HCI_UP, &hdev->flags)) {
                ret = -EALREADY;
                goto done;
        if (test_bit(HCI_UP, &hdev->flags)) {
                ret = -EALREADY;
                goto done;
@@ -480,7 +501,8 @@ int hci_dev_open(__u16 dev)
                set_bit(HCI_INIT, &hdev->flags);
 
                //__hci_request(hdev, hci_reset_req, 0, HZ);
                set_bit(HCI_INIT, &hdev->flags);
 
                //__hci_request(hdev, hci_reset_req, 0, HZ);
-               ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
+               ret = __hci_request(hdev, hci_init_req, 0,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
                clear_bit(HCI_INIT, &hdev->flags);
        }
 
                clear_bit(HCI_INIT, &hdev->flags);
        }
@@ -489,7 +511,7 @@ int hci_dev_open(__u16 dev)
                hci_dev_hold(hdev);
                set_bit(HCI_UP, &hdev->flags);
                hci_notify(hdev, HCI_DEV_UP);
                hci_dev_hold(hdev);
                set_bit(HCI_UP, &hdev->flags);
                hci_notify(hdev, HCI_DEV_UP);
-       } else {        
+       } else {
                /* Init failed, cleanup */
                tasklet_kill(&hdev->rx_task);
                tasklet_kill(&hdev->tx_task);
                /* Init failed, cleanup */
                tasklet_kill(&hdev->rx_task);
                tasklet_kill(&hdev->tx_task);
@@ -547,7 +569,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        atomic_set(&hdev->cmd_cnt, 1);
        if (!test_bit(HCI_RAW, &hdev->flags)) {
                set_bit(HCI_INIT, &hdev->flags);
        atomic_set(&hdev->cmd_cnt, 1);
        if (!test_bit(HCI_RAW, &hdev->flags)) {
                set_bit(HCI_INIT, &hdev->flags);
-               __hci_request(hdev, hci_reset_req, 0, HZ/4);
+               __hci_request(hdev, hci_reset_req, 0,
+                                       msecs_to_jiffies(250));
                clear_bit(HCI_INIT, &hdev->flags);
        }
 
                clear_bit(HCI_INIT, &hdev->flags);
        }
 
@@ -616,11 +639,12 @@ int hci_dev_reset(__u16 dev)
        if (hdev->flush)
                hdev->flush(hdev);
 
        if (hdev->flush)
                hdev->flush(hdev);
 
-       atomic_set(&hdev->cmd_cnt, 1); 
+       atomic_set(&hdev->cmd_cnt, 1);
        hdev->acl_cnt = 0; hdev->sco_cnt = 0;
 
        if (!test_bit(HCI_RAW, &hdev->flags))
        hdev->acl_cnt = 0; hdev->sco_cnt = 0;
 
        if (!test_bit(HCI_RAW, &hdev->flags))
-               ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
+               ret = __hci_request(hdev, hci_reset_req, 0,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
 done:
        tasklet_enable(&hdev->tx_task);
 
 done:
        tasklet_enable(&hdev->tx_task);
@@ -658,7 +682,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
 
        switch (cmd) {
        case HCISETAUTH:
 
        switch (cmd) {
        case HCISETAUTH:
-               err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+               err = hci_request(hdev, hci_auth_req, dr.dev_opt,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETENCRYPT:
                break;
 
        case HCISETENCRYPT:
@@ -669,46 +694,50 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
 
                if (!test_bit(HCI_AUTH, &hdev->flags)) {
                        /* Auth must be enabled first */
 
                if (!test_bit(HCI_AUTH, &hdev->flags)) {
                        /* Auth must be enabled first */
-                       err = hci_request(hdev, hci_auth_req,
-                                       dr.dev_opt, HCI_INIT_TIMEOUT);
+                       err = hci_request(hdev, hci_auth_req, dr.dev_opt,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
                        if (err)
                                break;
                }
 
                        if (err)
                                break;
                }
 
-               err = hci_request(hdev, hci_encrypt_req,
-                                       dr.dev_opt, HCI_INIT_TIMEOUT);
+               err = hci_request(hdev, hci_encrypt_req, dr.dev_opt,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETSCAN:
                break;
 
        case HCISETSCAN:
-               err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
-               break;
-
-       case HCISETPTYPE:
-               hdev->pkt_type = (__u16) dr.dev_opt;
+               err = hci_request(hdev, hci_scan_req, dr.dev_opt,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETLINKPOL:
                break;
 
        case HCISETLINKPOL:
-               hdev->link_policy = (__u16) dr.dev_opt;
+               err = hci_request(hdev, hci_linkpol_req, dr.dev_opt,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETLINKMODE:
                break;
 
        case HCISETLINKMODE:
-               hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT);
+               hdev->link_mode = ((__u16) dr.dev_opt) &
+                                       (HCI_LM_MASTER | HCI_LM_ACCEPT);
+               break;
+
+       case HCISETPTYPE:
+               hdev->pkt_type = (__u16) dr.dev_opt;
                break;
 
        case HCISETACLMTU:
                break;
 
        case HCISETACLMTU:
-               hdev->acl_mtu  = *((__u16 *)&dr.dev_opt + 1);
-               hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0);
+               hdev->acl_mtu  = *((__u16 *) &dr.dev_opt + 1);
+               hdev->acl_pkts = *((__u16 *) &dr.dev_opt + 0);
                break;
 
        case HCISETSCOMTU:
                break;
 
        case HCISETSCOMTU:
-               hdev->sco_mtu  = *((__u16 *)&dr.dev_opt + 1);
-               hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0);
+               hdev->sco_mtu  = *((__u16 *) &dr.dev_opt + 1);
+               hdev->sco_pkts = *((__u16 *) &dr.dev_opt + 0);
                break;
 
        default:
                err = -EINVAL;
                break;
        }
                break;
 
        default:
                err = -EINVAL;
                break;
        }
+
        hci_dev_put(hdev);
        return err;
 }
        hci_dev_put(hdev);
        return err;
 }
@@ -729,7 +758,7 @@ int hci_get_dev_list(void __user *arg)
 
        size = sizeof(*dl) + dev_num * sizeof(*dr);
 
 
        size = sizeof(*dl) + dev_num * sizeof(*dr);
 
-       if (!(dl = kmalloc(size, GFP_KERNEL)))
+       if (!(dl = kzalloc(size, GFP_KERNEL)))
                return -ENOMEM;
 
        dr = dl->dev_req;
                return -ENOMEM;
 
        dr = dl->dev_req;
@@ -791,17 +820,33 @@ int hci_get_dev_info(void __user *arg)
 
 /* ---- Interface to HCI drivers ---- */
 
 
 /* ---- Interface to HCI drivers ---- */
 
+static int hci_rfkill_set_block(void *data, bool blocked)
+{
+       struct hci_dev *hdev = data;
+
+       BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);
+
+       if (!blocked)
+               return 0;
+
+       hci_dev_do_close(hdev);
+
+       return 0;
+}
+
+static const struct rfkill_ops hci_rfkill_ops = {
+       .set_block = hci_rfkill_set_block,
+};
+
 /* Alloc HCI device */
 struct hci_dev *hci_alloc_dev(void)
 {
        struct hci_dev *hdev;
 
 /* Alloc HCI device */
 struct hci_dev *hci_alloc_dev(void)
 {
        struct hci_dev *hdev;
 
-       hdev = kmalloc(sizeof(struct hci_dev), GFP_KERNEL);
+       hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL);
        if (!hdev)
                return NULL;
 
        if (!hdev)
                return NULL;
 
-       memset(hdev, 0, sizeof(struct hci_dev));
-
        skb_queue_head_init(&hdev->driver_init);
 
        return hdev;
        skb_queue_head_init(&hdev->driver_init);
 
        return hdev;
@@ -813,8 +858,8 @@ void hci_free_dev(struct hci_dev *hdev)
 {
        skb_queue_purge(&hdev->driver_init);
 
 {
        skb_queue_purge(&hdev->driver_init);
 
-       /* will free via class release */
-       class_device_put(&hdev->class_dev);
+       /* will free via device release */
+       put_device(&hdev->dev);
 }
 EXPORT_SYMBOL(hci_free_dev);
 
 }
 EXPORT_SYMBOL(hci_free_dev);
 
@@ -822,9 +867,10 @@ EXPORT_SYMBOL(hci_free_dev);
 int hci_register_dev(struct hci_dev *hdev)
 {
        struct list_head *head = &hci_dev_list, *p;
 int hci_register_dev(struct hci_dev *hdev)
 {
        struct list_head *head = &hci_dev_list, *p;
-       int id = 0;
+       int i, id = 0;
 
 
-       BT_DBG("%p name %s type %d owner %p", hdev, hdev->name, hdev->type, hdev->owner);
+       BT_DBG("%p name %s type %d owner %p", hdev, hdev->name,
+                                               hdev->type, hdev->owner);
 
        if (!hdev->open || !hdev->close || !hdev->destruct)
                return -EINVAL;
 
        if (!hdev->open || !hdev->close || !hdev->destruct)
                return -EINVAL;
@@ -837,7 +883,7 @@ int hci_register_dev(struct hci_dev *hdev)
                        break;
                head = p; id++;
        }
                        break;
                head = p; id++;
        }
-       
+
        sprintf(hdev->name, "hci%d", id);
        hdev->id = id;
        list_add(&hdev->list, head);
        sprintf(hdev->name, "hci%d", id);
        hdev->id = id;
        list_add(&hdev->list, head);
@@ -847,8 +893,13 @@ int hci_register_dev(struct hci_dev *hdev)
 
        hdev->flags = 0;
        hdev->pkt_type  = (HCI_DM1 | HCI_DH1 | HCI_HV1);
 
        hdev->flags = 0;
        hdev->pkt_type  = (HCI_DM1 | HCI_DH1 | HCI_HV1);
+       hdev->esco_type = (ESCO_HV1);
        hdev->link_mode = (HCI_LM_ACCEPT);
 
        hdev->link_mode = (HCI_LM_ACCEPT);
 
+       hdev->idle_timeout = 0;
+       hdev->sniff_max_interval = 800;
+       hdev->sniff_min_interval = 80;
+
        tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev);
        tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
        tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
        tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev);
        tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
        tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
@@ -857,8 +908,11 @@ int hci_register_dev(struct hci_dev *hdev)
        skb_queue_head_init(&hdev->cmd_q);
        skb_queue_head_init(&hdev->raw_q);
 
        skb_queue_head_init(&hdev->cmd_q);
        skb_queue_head_init(&hdev->raw_q);
 
+       for (i = 0; i < 3; i++)
+               hdev->reassembly[i] = NULL;
+
        init_waitqueue_head(&hdev->req_wait_q);
        init_waitqueue_head(&hdev->req_wait_q);
-       init_MUTEX(&hdev->req_lock);
+       mutex_init(&hdev->req_lock);
 
        inquiry_cache_init(hdev);
 
 
        inquiry_cache_init(hdev);
 
@@ -872,6 +926,15 @@ int hci_register_dev(struct hci_dev *hdev)
 
        hci_register_sysfs(hdev);
 
 
        hci_register_sysfs(hdev);
 
+       hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
+                               RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
+       if (hdev->rfkill) {
+               if (rfkill_register(hdev->rfkill) < 0) {
+                       rfkill_destroy(hdev->rfkill);
+                       hdev->rfkill = NULL;
+               }
+       }
+
        hci_notify(hdev, HCI_DEV_REG);
 
        return id;
        hci_notify(hdev, HCI_DEV_REG);
 
        return id;
@@ -881,9 +944,9 @@ EXPORT_SYMBOL(hci_register_dev);
 /* Unregister HCI device */
 int hci_unregister_dev(struct hci_dev *hdev)
 {
 /* Unregister HCI device */
 int hci_unregister_dev(struct hci_dev *hdev)
 {
-       BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+       int i;
 
 
-       hci_unregister_sysfs(hdev);
+       BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
 
        write_lock_bh(&hci_dev_list_lock);
        list_del(&hdev->list);
 
        write_lock_bh(&hci_dev_list_lock);
        list_del(&hdev->list);
@@ -891,9 +954,20 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
        hci_dev_do_close(hdev);
 
 
        hci_dev_do_close(hdev);
 
+       for (i = 0; i < 3; i++)
+               kfree_skb(hdev->reassembly[i]);
+
        hci_notify(hdev, HCI_DEV_UNREG);
 
        hci_notify(hdev, HCI_DEV_UNREG);
 
+       if (hdev->rfkill) {
+               rfkill_unregister(hdev->rfkill);
+               rfkill_destroy(hdev->rfkill);
+       }
+
+       hci_unregister_sysfs(hdev);
+
        __hci_dev_put(hdev);
        __hci_dev_put(hdev);
+
        return 0;
 }
 EXPORT_SYMBOL(hci_unregister_dev);
        return 0;
 }
 EXPORT_SYMBOL(hci_unregister_dev);
@@ -914,6 +988,114 @@ int hci_resume_dev(struct hci_dev *hdev)
 }
 EXPORT_SYMBOL(hci_resume_dev);
 
 }
 EXPORT_SYMBOL(hci_resume_dev);
 
+/* Receive frame from HCI drivers */
+int hci_recv_frame(struct sk_buff *skb)
+{
+       struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+       if (!hdev || (!test_bit(HCI_UP, &hdev->flags)
+                               && !test_bit(HCI_INIT, &hdev->flags))) {
+               kfree_skb(skb);
+               return -ENXIO;
+       }
+
+       /* Incomming skb */
+       bt_cb(skb)->incoming = 1;
+
+       /* Time stamp */
+       __net_timestamp(skb);
+
+       /* Queue frame for rx task */
+       skb_queue_tail(&hdev->rx_q, skb);
+       tasklet_schedule(&hdev->rx_task);
+
+       return 0;
+}
+EXPORT_SYMBOL(hci_recv_frame);
+
+/* Receive packet type fragment */
+#define __reassembly(hdev, type)  ((hdev)->reassembly[(type) - 2])
+
+int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
+{
+       if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
+               return -EILSEQ;
+
+       while (count) {
+               struct sk_buff *skb = __reassembly(hdev, type);
+               struct { int expect; } *scb;
+               int len = 0;
+
+               if (!skb) {
+                       /* Start of the frame */
+
+                       switch (type) {
+                       case HCI_EVENT_PKT:
+                               if (count >= HCI_EVENT_HDR_SIZE) {
+                                       struct hci_event_hdr *h = data;
+                                       len = HCI_EVENT_HDR_SIZE + h->plen;
+                               } else
+                                       return -EILSEQ;
+                               break;
+
+                       case HCI_ACLDATA_PKT:
+                               if (count >= HCI_ACL_HDR_SIZE) {
+                                       struct hci_acl_hdr *h = data;
+                                       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 = data;
+                                       len = HCI_SCO_HDR_SIZE + 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;
+                       bt_cb(skb)->pkt_type = type;
+
+                       __reassembly(hdev, type) = skb;
+
+                       scb = (void *) skb->cb;
+                       scb->expect = len;
+               } else {
+                       /* Continuation */
+
+                       scb = (void *) skb->cb;
+                       len = scb->expect;
+               }
+
+               len = min(len, count);
+
+               memcpy(skb_put(skb, len), data, len);
+
+               scb->expect -= len;
+
+               if (scb->expect == 0) {
+                       /* Complete frame */
+
+                       __reassembly(hdev, type) = NULL;
+
+                       bt_cb(skb)->pkt_type = type;
+                       hci_recv_frame(skb);
+               }
+
+               count -= len; data += len;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(hci_recv_fragment);
+
 /* ---- Interface to upper protocols ---- */
 
 /* Register/Unregister protocols.
 /* ---- Interface to upper protocols ---- */
 
 /* Register/Unregister protocols.
@@ -1011,22 +1193,22 @@ static int hci_send_frame(struct sk_buff *skb)
 }
 
 /* Send HCI command */
 }
 
 /* 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;
 
 {
        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) {
 
        skb = bt_skb_alloc(len, GFP_ATOMIC);
        if (!skb) {
-               BT_ERR("%s Can't allocate memory for HCI command", hdev->name);
+               BT_ERR("%s no memory for command", hdev->name);
                return -ENOMEM;
        }
 
        hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
                return -ENOMEM;
        }
 
        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)
        hdr->plen   = plen;
 
        if (plen)
@@ -1036,14 +1218,15 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
 
        bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
        skb->dev = (void *) hdev;
 
        bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
        skb->dev = (void *) hdev;
+
        skb_queue_tail(&hdev->cmd_q, skb);
        skb_queue_tail(&hdev->cmd_q, skb);
-       hci_sched_cmd(hdev);
+       tasklet_schedule(&hdev->cmd_task);
 
        return 0;
 }
 
 /* Get data from the previously sent command */
 
        return 0;
 }
 
 /* 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;
 
 {
        struct hci_command_hdr *hdr;
 
@@ -1052,10 +1235,10 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
 
        hdr = (void *) hdev->sent_cmd->data;
 
 
        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;
 
                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;
 }
 
        return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
 }
@@ -1066,11 +1249,11 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
        struct hci_acl_hdr *hdr;
        int len = skb->len;
 
        struct hci_acl_hdr *hdr;
        int len = skb->len;
 
-       hdr = (struct hci_acl_hdr *) skb_push(skb, HCI_ACL_HDR_SIZE);
-       hdr->handle = __cpu_to_le16(hci_handle_pack(handle, flags));
-       hdr->dlen   = __cpu_to_le16(len);
-
-       skb->h.raw = (void *) hdr;
+       skb_push(skb, HCI_ACL_HDR_SIZE);
+       skb_reset_transport_header(skb);
+       hdr = (struct hci_acl_hdr *)skb_transport_header(skb);
+       hdr->handle = cpu_to_le16(hci_handle_pack(handle, flags));
+       hdr->dlen   = cpu_to_le16(len);
 }
 
 int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
 }
 
 int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
@@ -1101,7 +1284,7 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
                __skb_queue_tail(&conn->data_q, skb);
                do {
                        skb = list; list = list->next;
                __skb_queue_tail(&conn->data_q, skb);
                do {
                        skb = list; list = list->next;
-                       
+
                        skb->dev = (void *) hdev;
                        bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
                        hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
                        skb->dev = (void *) hdev;
                        bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
                        hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
@@ -1114,7 +1297,8 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
                spin_unlock_bh(&conn->data_q.lock);
        }
 
                spin_unlock_bh(&conn->data_q.lock);
        }
 
-       hci_sched_tx(hdev);
+       tasklet_schedule(&hdev->tx_task);
+
        return 0;
 }
 EXPORT_SYMBOL(hci_send_acl);
        return 0;
 }
 EXPORT_SYMBOL(hci_send_acl);
@@ -1132,16 +1316,19 @@ int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
                return -EINVAL;
        }
 
                return -EINVAL;
        }
 
-       hdr.handle = __cpu_to_le16(conn->handle);
+       hdr.handle = cpu_to_le16(conn->handle);
        hdr.dlen   = skb->len;
 
        hdr.dlen   = skb->len;
 
-       skb->h.raw = skb_push(skb, HCI_SCO_HDR_SIZE);
-       memcpy(skb->h.raw, &hdr, HCI_SCO_HDR_SIZE);
+       skb_push(skb, HCI_SCO_HDR_SIZE);
+       skb_reset_transport_header(skb);
+       memcpy(skb_transport_header(skb), &hdr, HCI_SCO_HDR_SIZE);
 
        skb->dev = (void *) hdev;
        bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
 
        skb->dev = (void *) hdev;
        bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
+
        skb_queue_tail(&conn->data_q, skb);
        skb_queue_tail(&conn->data_q, skb);
-       hci_sched_tx(hdev);
+       tasklet_schedule(&hdev->tx_task);
+
        return 0;
 }
 EXPORT_SYMBOL(hci_send_sco);
        return 0;
 }
 EXPORT_SYMBOL(hci_send_sco);
@@ -1152,19 +1339,22 @@ EXPORT_SYMBOL(hci_send_sco);
 static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
 static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       struct hci_conn  *conn = NULL;
+       struct hci_conn *conn = NULL;
        int num = 0, min = ~0;
        struct list_head *p;
 
        int num = 0, min = ~0;
        struct list_head *p;
 
-       /* We don't have to lock device here. Connections are always 
+       /* We don't have to lock device here. Connections are always
         * added and removed with TX task disabled. */
        list_for_each(p, &h->list) {
                struct hci_conn *c;
                c = list_entry(p, struct hci_conn, list);
 
         * added and removed with TX task disabled. */
        list_for_each(p, &h->list) {
                struct hci_conn *c;
                c = list_entry(p, struct hci_conn, list);
 
-               if (c->type != type || c->state != BT_CONNECTED
-                               || skb_queue_empty(&c->data_q))
+               if (c->type != type || skb_queue_empty(&c->data_q))
                        continue;
                        continue;
+
+               if (c->state != BT_CONNECTED && c->state != BT_CONFIG)
+                       continue;
+
                num++;
 
                if (c->sent < min) {
                num++;
 
                if (c->sent < min) {
@@ -1214,13 +1404,16 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
        if (!test_bit(HCI_RAW, &hdev->flags)) {
                /* ACL tx timeout must be longer than maximum
                 * link supervision timeout (40.9 seconds) */
        if (!test_bit(HCI_RAW, &hdev->flags)) {
                /* ACL tx timeout must be longer than maximum
                 * link supervision timeout (40.9 seconds) */
-               if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45))
+               if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45))
                        hci_acl_tx_to(hdev);
        }
 
        while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
                while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
                        BT_DBG("skb %p len %d", skb, skb->len);
                        hci_acl_tx_to(hdev);
        }
 
        while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
                while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
                        BT_DBG("skb %p len %d", skb, skb->len);
+
+                       hci_conn_enter_active_mode(conn);
+
                        hci_send_frame(skb);
                        hdev->acl_last_tx = jiffies;
 
                        hci_send_frame(skb);
                        hdev->acl_last_tx = jiffies;
 
@@ -1251,6 +1444,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;
 static void hci_tx_task(unsigned long arg)
 {
        struct hci_dev *hdev = (struct hci_dev *) arg;
@@ -1266,6 +1479,8 @@ static void hci_tx_task(unsigned long arg)
 
        hci_sched_sco(hdev);
 
 
        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);
        /* Send next queued raw (unknown type) packet */
        while ((skb = skb_dequeue(&hdev->raw_q)))
                hci_send_frame(skb);
@@ -1295,17 +1510,19 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_lock(hdev);
        conn = hci_conn_hash_lookup_handle(hdev, handle);
        hci_dev_unlock(hdev);
        hci_dev_lock(hdev);
        conn = hci_conn_hash_lookup_handle(hdev, handle);
        hci_dev_unlock(hdev);
-       
+
        if (conn) {
                register struct hci_proto *hp;
 
        if (conn) {
                register struct hci_proto *hp;
 
+               hci_conn_enter_active_mode(conn);
+
                /* Send to upper protocol */
                if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) {
                        hp->recv_acldata(conn, skb, flags);
                        return;
                }
        } else {
                /* Send to upper protocol */
                if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) {
                        hp->recv_acldata(conn, skb, flags);
                        return;
                }
        } else {
-               BT_ERR("%s ACL packet for unknown connection handle %d", 
+               BT_ERR("%s ACL packet for unknown connection handle %d",
                        hdev->name, handle);
        }
 
                        hdev->name, handle);
        }
 
@@ -1340,14 +1557,14 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
                        return;
                }
        } else {
                        return;
                }
        } else {
-               BT_ERR("%s SCO packet for unknown connection handle %d", 
+               BT_ERR("%s SCO packet for unknown connection handle %d",
                        hdev->name, handle);
        }
 
        kfree_skb(skb);
 }
 
                        hdev->name, handle);
        }
 
        kfree_skb(skb);
 }
 
-void hci_rx_task(unsigned long arg)
+static void hci_rx_task(unsigned long arg)
 {
        struct hci_dev *hdev = (struct hci_dev *) arg;
        struct sk_buff *skb;
 {
        struct hci_dev *hdev = (struct hci_dev *) arg;
        struct sk_buff *skb;
@@ -1374,7 +1591,7 @@ void hci_rx_task(unsigned long arg)
                        case HCI_SCODATA_PKT:
                                kfree_skb(skb);
                                continue;
                        case HCI_SCODATA_PKT:
                                kfree_skb(skb);
                                continue;
-                       };
+                       }
                }
 
                /* Process frame */
                }
 
                /* Process frame */
@@ -1409,15 +1626,14 @@ static void hci_cmd_task(unsigned long arg)
 
        BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
 
 
        BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
 
-       if (!atomic_read(&hdev->cmd_cnt) && (jiffies - hdev->cmd_last_tx) > HZ) {
+       if (!atomic_read(&hdev->cmd_cnt) && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
                BT_ERR("%s command tx timeout", hdev->name);
                atomic_set(&hdev->cmd_cnt, 1);
        }
 
        /* Send queued commands */
        if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
                BT_ERR("%s command tx timeout", hdev->name);
                atomic_set(&hdev->cmd_cnt, 1);
        }
 
        /* Send queued commands */
        if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
-               if (hdev->sent_cmd)
-                       kfree_skb(hdev->sent_cmd);
+               kfree_skb(hdev->sent_cmd);
 
                if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
                        atomic_dec(&hdev->cmd_cnt);
 
                if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
                        atomic_dec(&hdev->cmd_cnt);
@@ -1425,7 +1641,7 @@ static void hci_cmd_task(unsigned long arg)
                        hdev->cmd_last_tx = jiffies;
                } else {
                        skb_queue_head(&hdev->cmd_q, skb);
                        hdev->cmd_last_tx = jiffies;
                } else {
                        skb_queue_head(&hdev->cmd_q, skb);
-                       hci_sched_cmd(hdev);
+                       tasklet_schedule(&hdev->cmd_task);
                }
        }
 }
                }
        }
 }