summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43/rfkill.c
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2007-09-28 14:22:33 +0200
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 16:54:13 -0700
commit42bb4cd5ae320dd46630533fecb91b940d4468e2 (patch)
tree13635dd2a2457f53f4ff09a6b429f8e4ac23c246 /drivers/net/wireless/b43/rfkill.c
parent8e9f7529fdfe34ed519f048682eb404fbd8004e8 (diff)
[B43]: Use input-polldev for the rfkill switch
This removes the direct call to rfkill on an rfkill event and replaces it with an input device. This way userspace is also notified about the event. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/wireless/b43/rfkill.c')
-rw-r--r--drivers/net/wireless/b43/rfkill.c129
1 files changed, 79 insertions, 50 deletions
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
index c25fd9956a9..800e0a61a7f 100644
--- a/drivers/net/wireless/b43/rfkill.c
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -26,46 +26,39 @@
#include "b43.h"
-static void b43_notify_rfkill_press(struct work_struct *work)
+/* Returns TRUE, if the radio is enabled in hardware. */
+static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
{
- struct b43_rfkill *rfk = container_of(work, struct b43_rfkill,
- notify_work);
- struct b43_wl *wl = container_of(rfk, struct b43_wl, rfkill);
- struct b43_wldev *dev;
- enum rfkill_state state;
-
- mutex_lock(&wl->mutex);
- dev = wl->current_dev;
- if (b43_status(dev) < B43_STAT_INITIALIZED) {
- mutex_unlock(&wl->mutex);
- return;
- }
- if (dev->radio_hw_enable)
- state = RFKILL_STATE_ON;
- else
- state = RFKILL_STATE_OFF;
- b43info(wl, "Radio hardware status changed to %s\n",
- dev->radio_hw_enable ? "ENABLED" : "DISABLED");
- mutex_unlock(&wl->mutex);
-
- if (rfk->rfkill) {
- /* Be careful. This calls back into the software toggle routines.
- * So we must unlock before calling. */
- rfkill_switch_all(rfk->rfkill->type, state);
+ if (dev->phy.rev >= 3) {
+ if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI)
+ & B43_MMIO_RADIO_HWENABLED_HI_MASK))
+ return 1;
+ } else {
+ if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO)
+ & B43_MMIO_RADIO_HWENABLED_LO_MASK)
+ return 1;
}
+ return 0;
}
-/* Called when the RFKILL toggled in hardware.
- * This is called with the mutex locked. */
-void b43_rfkill_toggled(struct b43_wldev *dev, bool on)
+/* The poll callback for the hardware button. */
+static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
{
+ struct b43_wldev *dev = poll_dev->private;
struct b43_wl *wl = dev->wl;
+ bool enabled;
+ mutex_lock(&wl->mutex);
B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
- /* Update the RF status asynchronously, as rfkill will
- * call back into the software toggle handler.
- * This would deadlock if done synchronously. */
- queue_work(wl->hw->workqueue, &wl->rfkill.notify_work);
+ enabled = b43_is_hw_radio_enabled(dev);
+ if (unlikely(enabled != dev->radio_hw_enable)) {
+ dev->radio_hw_enable = enabled;
+ b43info(wl, "Radio hardware status changed to %s\n",
+ enabled ? "ENABLED" : "DISABLED");
+ mutex_unlock(&wl->mutex);
+ input_report_key(poll_dev->input, KEY_WLAN, enabled);
+ } else
+ mutex_unlock(&wl->mutex);
}
/* Called when the RFKILL toggled in software.
@@ -118,38 +111,74 @@ void b43_rfkill_init(struct b43_wldev *dev)
struct b43_rfkill *rfk = &(wl->rfkill);
int err;
+ if (rfk->rfkill) {
+ err = rfkill_register(rfk->rfkill);
+ if (err) {
+ b43warn(wl, "Failed to register RF-kill button\n");
+ goto err_free_rfk;
+ }
+ }
+ if (rfk->poll_dev) {
+ err = input_register_polled_device(rfk->poll_dev);
+ if (err) {
+ b43warn(wl, "Failed to register RF-kill polldev\n");
+ goto err_free_polldev;
+ }
+ }
+
+ return;
+err_free_rfk:
+ rfkill_free(rfk->rfkill);
+ rfk->rfkill = NULL;
+err_free_polldev:
+ input_free_polled_device(rfk->poll_dev);
+ rfk->poll_dev = NULL;
+}
+
+void b43_rfkill_exit(struct b43_wldev *dev)
+{
+ struct b43_rfkill *rfk = &(dev->wl->rfkill);
+
+ if (rfk->poll_dev)
+ input_unregister_polled_device(rfk->poll_dev);
+ if (rfk->rfkill)
+ rfkill_unregister(rfk->rfkill);
+}
+
+void b43_rfkill_alloc(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ struct b43_rfkill *rfk = &(wl->rfkill);
+
snprintf(rfk->name, sizeof(rfk->name),
"b43-%s", wiphy_name(wl->hw->wiphy));
+
rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
- if (!rfk->rfkill)
- goto error;
+ if (!rfk->rfkill) {
+ b43warn(wl, "Failed to allocate RF-kill button\n");
+ return;
+ }
rfk->rfkill->name = rfk->name;
rfk->rfkill->state = RFKILL_STATE_ON;
rfk->rfkill->data = dev;
rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle;
rfk->rfkill->user_claim_unsupported = 1;
- INIT_WORK(&rfk->notify_work, b43_notify_rfkill_press);
-
- err = rfkill_register(rfk->rfkill);
- if (err)
- goto error;
-
- return;
-error:
- b43warn(dev->wl, "Failed to initialize the RF-kill button\n");
- rfkill_free(rfk->rfkill);
- rfk->rfkill = NULL;
+ rfk->poll_dev = input_allocate_polled_device();
+ if (rfk->poll_dev) {
+ rfk->poll_dev->private = dev;
+ rfk->poll_dev->poll = b43_rfkill_poll;
+ rfk->poll_dev->poll_interval = 1000; /* msecs */
+ } else
+ b43warn(wl, "Failed to allocate RF-kill polldev\n");
}
-void b43_rfkill_exit(struct b43_wldev *dev)
+void b43_rfkill_free(struct b43_wldev *dev)
{
struct b43_rfkill *rfk = &(dev->wl->rfkill);
- if (!rfk->rfkill)
- return;
- cancel_work_sync(&rfk->notify_work);
- rfkill_unregister(rfk->rfkill);
+ input_free_polled_device(rfk->poll_dev);
+ rfk->poll_dev = NULL;
rfkill_free(rfk->rfkill);
rfk->rfkill = NULL;
}