summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2009-06-01 22:49:25 +0200
committerJohn W. Linville <linville@tuxdriver.com>2009-06-03 14:05:15 -0400
commit6d7db193f2097d2f12fdc6b2300439a91a3196be (patch)
treed918f4737ac2093e5eaf5538d802571157db2e44
parent66d008139c61d610f3ade9b46ad610e2cd277fb9 (diff)
downloadlinux-6d7db193f2097d2f12fdc6b2300439a91a3196be.tar.bz2
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>
-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)