OSDN Git Service

Bluetooth: Add native RFKILL soft-switch support for all devices
authorCorentin Chary <corentincj@iksaif.net>
Fri, 9 Oct 2009 14:49:07 +0000 (16:49 +0200)
committerChih-Wei Huang <cwhuang@linux.org.tw>
Tue, 20 Oct 2009 02:47:19 +0000 (10:47 +0800)
With the re-write of the RFKILL subsystem it is now possible to easily
integrate RFKILL soft-switch support into the Bluetooth subsystem. All
Bluetooth devices will now get automatically RFKILL support.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Corentin Chary <corentincj@iksaif.net>
include/net/bluetooth/hci_core.h
net/bluetooth/hci_core.c

index ed16efb..79b8fe1 100644 (file)
@@ -137,6 +137,8 @@ struct hci_dev {
        struct device           *parent;
        struct device           dev;
 
+       struct rfkill           *rfkill;
+
        struct module           *owner;
 
        int (*open)(struct hci_dev *hdev);
index cd06151..e2962e2 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/skbuff.h>
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
+#include <linux/rfkill.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
@@ -476,6 +477,13 @@ int hci_dev_open(__u16 dev)
 
        hci_req_lock(hdev);
 
+       if (hdev->rfkill &&
+           (hdev->rfkill->state == RFKILL_STATE_HARD_BLOCKED ||
+            hdev->rfkill->state == RFKILL_STATE_SOFT_BLOCKED)) {
+               ret = -EBUSY;
+               goto done;
+       }
+
        if (test_bit(HCI_UP, &hdev->flags)) {
                ret = -EALREADY;
                goto done;
@@ -813,6 +821,21 @@ int hci_get_dev_info(void __user *arg)
 
 /* ---- Interface to HCI drivers ---- */
 
+static int hci_rfkill_set_block(void *data, enum rfkill_state state)
+{
+       struct hci_dev *hdev = data;
+       bool blocked = !(state == RFKILL_STATE_UNBLOCKED);
+
+       BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);
+
+       if (!blocked)
+               return 0;
+
+       hci_dev_do_close(hdev);
+
+       return 0;
+}
+
 /* Alloc HCI device */
 struct hci_dev *hci_alloc_dev(void)
 {
@@ -844,7 +867,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 type %d owner %p", hdev, hdev->name,
+                                               hdev->type, hdev->owner);
 
        if (!hdev->open || !hdev->close || !hdev->destruct)
                return -EINVAL;
@@ -900,6 +924,17 @@ int hci_register_dev(struct hci_dev *hdev)
 
        hci_register_sysfs(hdev);
 
+       hdev->rfkill = rfkill_allocate(&hdev->dev, RFKILL_TYPE_BLUETOOTH);
+       if (hdev->rfkill) {
+               hdev->rfkill->name = hdev->name;
+               hdev->rfkill->toggle_radio = hci_rfkill_set_block;
+               hdev->rfkill->data = hdev;
+               if (rfkill_register(hdev->rfkill) < 0) {
+                       rfkill_free(hdev->rfkill);
+                       hdev->rfkill = NULL;
+               }
+       }
+
        hci_notify(hdev, HCI_DEV_REG);
 
        return id;
@@ -924,6 +959,10 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
        hci_notify(hdev, HCI_DEV_UNREG);
 
+       if (hdev->rfkill) {
+               rfkill_unregister(hdev->rfkill);
+       }
+
        hci_unregister_sysfs(hdev);
 
        __hci_dev_put(hdev);