summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2009-06-02 00:49:25 +0400
committerJohn W. Linville <linville@tuxdriver.com>2009-06-03 22:05:15 +0400
commit6d7db193f2097d2f12fdc6b2300439a91a3196be (patch)
treed918f4737ac2093e5eaf5538d802571157db2e44 /drivers
parent66d008139c61d610f3ade9b46ad610e2cd277fb9 (diff)
downloadlinux-6d7db193f2097d2f12fdc6b2300439a91a3196be.tar.xz
ar9170: cancel led worker properly on exit
"[PATCH 3/4 v2] ar9170: fix LED power state handling" revealed a bug which can cause a ugly crash. The delayed worker is canceled before the LED class functions are unregistered... So, if something manages to update the LEDs while unregister routine is running the timer could fire _after_ the module has been unloaded. Signed-off-by: Christian Lamparter <chunkeey@web.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ar9170/led.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c
index 3c8a5728920d..63fda6cd2101 100644
--- a/drivers/net/wireless/ath/ar9170/led.c
+++ b/drivers/net/wireless/ath/ar9170/led.c
@@ -74,7 +74,7 @@ static void ar9170_update_leds(struct work_struct *work)
mutex_lock(&ar->mutex);
for (i = 0; i < AR9170_NUM_LEDS; i++)
- if (ar->leds[i].toggled) {
+ if (ar->leds[i].registered && ar->leds[i].toggled) {
led_val |= 1 << i;
tmp = 70 + 200 / (ar->leds[i].toggled);
@@ -101,6 +101,9 @@ static void ar9170_led_brightness_set(struct led_classdev *led,
struct ar9170_led *arl = container_of(led, struct ar9170_led, l);
struct ar9170 *ar = arl->ar;
+ if (unlikely(!arl->registered))
+ return ;
+
if (arl->last_state != !!brightness) {
arl->toggled++;
arl->last_state = !!brightness;
@@ -139,13 +142,14 @@ void ar9170_unregister_leds(struct ar9170 *ar)
{
int i;
- cancel_delayed_work_sync(&ar->led_work);
-
for (i = 0; i < AR9170_NUM_LEDS; i++)
if (ar->leds[i].registered) {
led_classdev_unregister(&ar->leds[i].l);
ar->leds[i].registered = false;
+ ar->leds[i].toggled = 0;
}
+
+ cancel_delayed_work_sync(&ar->led_work);
}
int ar9170_register_leds(struct ar9170 *ar)