diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-06-02 13:01:37 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-06-03 20:06:13 +0200 |
commit | 19d337dff95cbf76edd3ad95c0cee2732c3e1ec5 (patch) | |
tree | 33326eeb09cb9664cc8427a5dc7cd2b08b5a57c3 /drivers/net/wireless/b43legacy/rfkill.c | |
parent | nl80211: use GFP_ATOMIC for michael mic failure message (diff) | |
download | linux-19d337dff95cbf76edd3ad95c0cee2732c3e1ec5.tar.xz linux-19d337dff95cbf76edd3ad95c0cee2732c3e1ec5.zip |
rfkill: rewrite
This patch completely rewrites the rfkill core to address
the following deficiencies:
* all rfkill drivers need to implement polling where necessary
rather than having one central implementation
* updating the rfkill state cannot be done from arbitrary
contexts, forcing drivers to use schedule_work and requiring
lots of code
* rfkill drivers need to keep track of soft/hard blocked
internally -- the core should do this
* the rfkill API has many unexpected quirks, for example being
asymmetric wrt. alloc/free and register/unregister
* rfkill can call back into a driver from within a function the
driver called -- this is prone to deadlocks and generally
should be avoided
* rfkill-input pointlessly is a separate module
* drivers need to #ifdef rfkill functions (unless they want to
depend on or select RFKILL) -- rfkill should provide inlines
that do nothing if it isn't compiled in
* the rfkill structure is not opaque -- drivers need to initialise
it correctly (lots of sanity checking code required) -- instead
force drivers to pass the right variables to rfkill_alloc()
* the documentation is hard to read because it always assumes the
reader is completely clueless and contains way TOO MANY CAPS
* the rfkill code needlessly uses a lot of locks and atomic
operations in locked sections
* fix LED trigger to actually change the LED when the radio state
changes -- this wasn't done before
Tested-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> [thinkpad]
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43legacy/rfkill.c')
-rw-r--r-- | drivers/net/wireless/b43legacy/rfkill.c | 123 |
1 files changed, 39 insertions, 84 deletions
diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index 4b0c7d27a51f..c6230a64505a 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -45,12 +45,11 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) } /* The poll callback for the hardware button. */ -static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) +static void b43legacy_rfkill_poll(struct rfkill *rfkill, void *data) { - struct b43legacy_wldev *dev = poll_dev->private; + struct b43legacy_wldev *dev = data; struct b43legacy_wl *wl = dev->wl; bool enabled; - bool report_change = 0; mutex_lock(&wl->mutex); if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { @@ -60,71 +59,64 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) enabled = b43legacy_is_hw_radio_enabled(dev); if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; - report_change = 1; b43legacyinfo(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); + enabled = !rfkill_set_hw_state(rfkill, !enabled); + if (enabled != dev->phy.radio_on) { + if (enabled) + b43legacy_radio_turn_on(dev); + else + b43legacy_radio_turn_off(dev, 0); + } } mutex_unlock(&wl->mutex); - - /* send the radio switch event to the system - note both a key press - * and a release are required */ - if (unlikely(report_change)) { - input_report_key(poll_dev->input, KEY_WLAN, 1); - input_report_key(poll_dev->input, KEY_WLAN, 0); - } } /* Called when the RFKILL toggled in software. * This is called without locking. */ -static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) +static int b43legacy_rfkill_soft_set(void *data, bool blocked) { struct b43legacy_wldev *dev = data; struct b43legacy_wl *wl = dev->wl; - int err = -EBUSY; + int ret = -EINVAL; if (!wl->rfkill.registered) - return 0; + return -EINVAL; mutex_lock(&wl->mutex); if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) goto out_unlock; - err = 0; - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (!dev->radio_hw_enable) { - /* No luck. We can't toggle the hardware RF-kill - * button from software. */ - err = -EBUSY; - goto out_unlock; - } - if (!dev->phy.radio_on) + + if (!dev->radio_hw_enable) + goto out_unlock; + + if (!blocked != dev->phy.radio_on) { + if (!blocked) b43legacy_radio_turn_on(dev); - break; - case RFKILL_STATE_SOFT_BLOCKED: - if (dev->phy.radio_on) + else b43legacy_radio_turn_off(dev, 0); - break; - default: - b43legacywarn(wl, "Received unexpected rfkill state %d.\n", - state); - break; } + ret = 0; out_unlock: mutex_unlock(&wl->mutex); - - return err; + return ret; } -char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) +const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) { struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); if (!rfk->registered) return NULL; - return rfkill_get_led_name(rfk->rfkill); + return rfkill_get_led_trigger_name(rfk->rfkill); } +static const struct rfkill_ops b43legacy_rfkill_ops = { + .set_block = b43legacy_rfkill_soft_set, + .poll = b43legacy_rfkill_poll, +}; + void b43legacy_rfkill_init(struct b43legacy_wldev *dev) { struct b43legacy_wl *wl = dev->wl; @@ -133,60 +125,25 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev) rfk->registered = 0; - rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); - if (!rfk->rfkill) - goto out_error; snprintf(rfk->name, sizeof(rfk->name), "b43legacy-%s", wiphy_name(wl->hw->wiphy)); - rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; - rfk->rfkill->data = dev; - rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; - - rfk->poll_dev = input_allocate_polled_device(); - if (!rfk->poll_dev) { - rfkill_free(rfk->rfkill); - goto err_freed_rfk; - } - - rfk->poll_dev->private = dev; - rfk->poll_dev->poll = b43legacy_rfkill_poll; - rfk->poll_dev->poll_interval = 1000; /* msecs */ - - rfk->poll_dev->input->name = rfk->name; - rfk->poll_dev->input->id.bustype = BUS_HOST; - rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; - rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); + rfk->rfkill = rfkill_alloc(rfk->name, + dev->dev->dev, + RFKILL_TYPE_WLAN, + &b43legacy_rfkill_ops, dev); + if (!rfk->rfkill) + goto out_error; err = rfkill_register(rfk->rfkill); if (err) - goto err_free_polldev; - -#ifdef CONFIG_RFKILL_INPUT_MODULE - /* B43legacy RF-kill isn't useful without the rfkill-input subsystem. - * Try to load the module. */ - err = request_module("rfkill-input"); - if (err) - b43legacywarn(wl, "Failed to load the rfkill-input module." - "The built-in radio LED will not work.\n"); -#endif /* CONFIG_RFKILL_INPUT */ - - err = input_register_polled_device(rfk->poll_dev); - if (err) - goto err_unreg_rfk; + goto err_free; rfk->registered = 1; return; -err_unreg_rfk: - rfkill_unregister(rfk->rfkill); -err_free_polldev: - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; -err_freed_rfk: - rfk->rfkill = NULL; -out_error: + err_free: + rfkill_destroy(rfk->rfkill); + out_error: rfk->registered = 0; b43legacywarn(wl, "RF-kill button init failed\n"); } @@ -199,10 +156,8 @@ void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) return; rfk->registered = 0; - input_unregister_polled_device(rfk->poll_dev); rfkill_unregister(rfk->rfkill); - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; + rfkill_destroy(rfk->rfkill); rfk->rfkill = NULL; } |