Skip to content

Commit

Permalink
leds: fix multiple requests and releases of IRQ for GPIO LED Trigger
Browse files Browse the repository at this point in the history
When setting the same GPIO number, multiple IRQ shared requests will be
done without freing the previous request.  It will also try to free a
failed request or an already freed IRQ if 0 was written to the gpio file.

All these oops and leaks were fixed with the following solution: keep the
previous allocated GPIO (if any) still allocated in case the new request
fails.  The alternative solution would desallocate the previous allocated
GPIO and set gpio as 0.

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
Signed-off-by: Samuel R. C. Vale <srcvale@holoscopio.com>
Cc: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Thadeu Lima de Souza Cascardo authored and Linus Torvalds committed Aug 27, 2009
1 parent bdf57de commit 48cccd2
Showing 1 changed file with 14 additions and 7 deletions.
21 changes: 14 additions & 7 deletions drivers/leds/ledtrig-gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,20 +146,26 @@ static ssize_t gpio_trig_gpio_store(struct device *dev,
return -EINVAL;
}

if (gpio_data->gpio == gpio)
return n;

if (!gpio) {
free_irq(gpio_to_irq(gpio_data->gpio), led);
if (gpio_data->gpio != 0)
free_irq(gpio_to_irq(gpio_data->gpio), led);
gpio_data->gpio = 0;
return n;
}

if (gpio_data->gpio > 0 && gpio_data->gpio != gpio)
free_irq(gpio_to_irq(gpio_data->gpio), led);

gpio_data->gpio = gpio;
ret = request_irq(gpio_to_irq(gpio), gpio_trig_irq,
IRQF_SHARED | IRQF_TRIGGER_RISING
| IRQF_TRIGGER_FALLING, "ledtrig-gpio", led);
if (ret)
if (ret) {
dev_err(dev, "request_irq failed with error %d\n", ret);
} else {
if (gpio_data->gpio != 0)
free_irq(gpio_to_irq(gpio_data->gpio), led);
gpio_data->gpio = gpio;
}

return ret ? ret : n;
}
Expand Down Expand Up @@ -211,7 +217,8 @@ static void gpio_trig_deactivate(struct led_classdev *led)
device_remove_file(led->dev, &dev_attr_inverted);
device_remove_file(led->dev, &dev_attr_desired_brightness);
flush_work(&gpio_data->work);
free_irq(gpio_to_irq(gpio_data->gpio),led);
if (gpio_data->gpio != 0)
free_irq(gpio_to_irq(gpio_data->gpio), led);
kfree(gpio_data);
}
}
Expand Down

0 comments on commit 48cccd2

Please sign in to comment.