From a978d788b6f1e4ab418ba46a4c8d8bb2a2489791 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 9 Oct 2009 16:49:07 +0200 Subject: [PATCH 1/2] Bluetooth: Add native RFKILL soft-switch support for all devices 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 Signed-off-by: Corentin Chary --- include/net/bluetooth/hci_core.h | 2 + net/bluetooth/hci_core.c | 41 +++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 46a43b7..4d09275 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -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); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ba78cc1..851b51f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -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); -- 1.6.4.2