Commit 6d7db193 authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville

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: default avatarChristian Lamparter <chunkeey@web.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 66d00813
...@@ -74,7 +74,7 @@ static void ar9170_update_leds(struct work_struct *work) ...@@ -74,7 +74,7 @@ static void ar9170_update_leds(struct work_struct *work)
mutex_lock(&ar->mutex); mutex_lock(&ar->mutex);
for (i = 0; i < AR9170_NUM_LEDS; i++) 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; led_val |= 1 << i;
tmp = 70 + 200 / (ar->leds[i].toggled); tmp = 70 + 200 / (ar->leds[i].toggled);
...@@ -101,6 +101,9 @@ static void ar9170_led_brightness_set(struct led_classdev *led, ...@@ -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_led *arl = container_of(led, struct ar9170_led, l);
struct ar9170 *ar = arl->ar; struct ar9170 *ar = arl->ar;
if (unlikely(!arl->registered))
return ;
if (arl->last_state != !!brightness) { if (arl->last_state != !!brightness) {
arl->toggled++; arl->toggled++;
arl->last_state = !!brightness; arl->last_state = !!brightness;
...@@ -139,13 +142,14 @@ void ar9170_unregister_leds(struct ar9170 *ar) ...@@ -139,13 +142,14 @@ void ar9170_unregister_leds(struct ar9170 *ar)
{ {
int i; int i;
cancel_delayed_work_sync(&ar->led_work);
for (i = 0; i < AR9170_NUM_LEDS; i++) for (i = 0; i < AR9170_NUM_LEDS; i++)
if (ar->leds[i].registered) { if (ar->leds[i].registered) {
led_classdev_unregister(&ar->leds[i].l); led_classdev_unregister(&ar->leds[i].l);
ar->leds[i].registered = false; ar->leds[i].registered = false;
ar->leds[i].toggled = 0;
} }
cancel_delayed_work_sync(&ar->led_work);
} }
int ar9170_register_leds(struct ar9170 *ar) int ar9170_register_leds(struct ar9170 *ar)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment