sdhci-pltfm: implement platform data passing
[safe/jmp/linux-2.6] / net / bluetooth / hci_core.c
index fa7c537..2f768de 100644 (file)
 #include <linux/fcntl.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
+#include <linux/workqueue.h>
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
+#include <linux/rfkill.h>
 #include <net/sock.h>
 
 #include <asm/system.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);
@@ -197,8 +194,9 @@ 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;
+
                skb_queue_tail(&hdev->cmd_q, skb);
-               hci_sched_cmd(hdev);
+               tasklet_schedule(&hdev->cmd_task);
        }
        skb_queue_purge(&hdev->driver_init);
 
@@ -290,7 +288,7 @@ static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
 {
        __le16 policy = cpu_to_le16(opt);
 
-       BT_DBG("%s %x", hdev->name, opt);
+       BT_DBG("%s %x", hdev->name, policy);
 
        /* Default link policy */
        hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
@@ -481,6 +479,11 @@ int hci_dev_open(__u16 dev)
 
        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;
@@ -489,6 +492,10 @@ int hci_dev_open(__u16 dev)
        if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
                set_bit(HCI_RAW, &hdev->flags);
 
+       /* Treat all non BR/EDR controllers as raw devices for now */
+       if (hdev->dev_type != HCI_BREDR)
+               set_bit(HCI_RAW, &hdev->flags);
+
        if (hdev->open(hdev)) {
                ret = -EIO;
                goto done;
@@ -795,7 +802,7 @@ int hci_get_dev_info(void __user *arg)
 
        strcpy(di.name, hdev->name);
        di.bdaddr   = hdev->bdaddr;
-       di.type     = hdev->type;
+       di.type     = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
        di.flags    = hdev->flags;
        di.pkt_type = hdev->pkt_type;
        di.acl_mtu  = hdev->acl_mtu;
@@ -818,6 +825,24 @@ int hci_get_dev_info(void __user *arg)
 
 /* ---- 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)
 {
@@ -849,7 +874,8 @@ int hci_register_dev(struct hci_dev *hdev)
        struct list_head *head = &hci_dev_list, *p;
        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 bus %d owner %p", hdev, hdev->name,
+                                               hdev->bus, hdev->owner);
 
        if (!hdev->open || !hdev->close || !hdev->destruct)
                return -EINVAL;
@@ -891,7 +917,7 @@ int hci_register_dev(struct hci_dev *hdev)
                hdev->reassembly[i] = NULL;
 
        init_waitqueue_head(&hdev->req_wait_q);
-       init_MUTEX(&hdev->req_lock);
+       mutex_init(&hdev->req_lock);
 
        inquiry_cache_init(hdev);
 
@@ -903,11 +929,31 @@ int hci_register_dev(struct hci_dev *hdev)
 
        write_unlock_bh(&hci_dev_list_lock);
 
+       hdev->workqueue = create_singlethread_workqueue(hdev->name);
+       if (!hdev->workqueue)
+               goto nomem;
+
        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;
+
+nomem:
+       write_lock_bh(&hci_dev_list_lock);
+       list_del(&hdev->list);
+       write_unlock_bh(&hci_dev_list_lock);
+
+       return -ENOMEM;
 }
 EXPORT_SYMBOL(hci_register_dev);
 
@@ -916,7 +962,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
 {
        int i;
 
-       BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+       BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
        write_lock_bh(&hci_dev_list_lock);
        list_del(&hdev->list);
@@ -929,8 +975,15 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
        hci_notify(hdev, HCI_DEV_UNREG);
 
+       if (hdev->rfkill) {
+               rfkill_unregister(hdev->rfkill);
+               rfkill_destroy(hdev->rfkill);
+       }
+
        hci_unregister_sysfs(hdev);
 
+       destroy_workqueue(hdev->workqueue);
+
        __hci_dev_put(hdev);
 
        return 0;
@@ -953,6 +1006,30 @@ int hci_resume_dev(struct hci_dev *hdev)
 }
 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])
 
@@ -1159,8 +1236,9 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
 
        bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
        skb->dev = (void *) hdev;
+
        skb_queue_tail(&hdev->cmd_q, skb);
-       hci_sched_cmd(hdev);
+       tasklet_schedule(&hdev->cmd_task);
 
        return 0;
 }
@@ -1196,7 +1274,7 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
        hdr->dlen   = cpu_to_le16(len);
 }
 
-int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
+void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
 {
        struct hci_dev *hdev = conn->hdev;
        struct sk_buff *list;
@@ -1237,24 +1315,18 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
                spin_unlock_bh(&conn->data_q.lock);
        }
 
-       hci_sched_tx(hdev);
-       return 0;
+       tasklet_schedule(&hdev->tx_task);
 }
 EXPORT_SYMBOL(hci_send_acl);
 
 /* Send SCO data */
-int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
+void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
 {
        struct hci_dev *hdev = conn->hdev;
        struct hci_sco_hdr hdr;
 
        BT_DBG("%s len %d", hdev->name, skb->len);
 
-       if (skb->len > hdev->sco_mtu) {
-               kfree_skb(skb);
-               return -EINVAL;
-       }
-
        hdr.handle = cpu_to_le16(conn->handle);
        hdr.dlen   = skb->len;
 
@@ -1264,9 +1336,9 @@ int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
 
        skb->dev = (void *) hdev;
        bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
+
        skb_queue_tail(&conn->data_q, skb);
-       hci_sched_tx(hdev);
-       return 0;
+       tasklet_schedule(&hdev->tx_task);
 }
 EXPORT_SYMBOL(hci_send_sco);
 
@@ -1570,8 +1642,7 @@ static void hci_cmd_task(unsigned long arg)
 
        /* 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);
@@ -1579,7 +1650,7 @@ static void hci_cmd_task(unsigned long arg)
                        hdev->cmd_last_tx = jiffies;
                } else {
                        skb_queue_head(&hdev->cmd_q, skb);
-                       hci_sched_cmd(hdev);
+                       tasklet_schedule(&hdev->cmd_task);
                }
        }
 }