aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThadeu Lima de Souza Cascardo <cascardo@holoscopio.com>2009-08-26 17:29:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-08-26 23:06:53 -0400
commit48cccd26f36511ddb6aeca07485ecf2829683907 (patch)
tree713e481085d33d73a8cf43131317db6c4aa206aa
parentbdf57de4e6abc389cc3f3bd94ec15cce74cf6f4b (diff)
leds: fix multiple requests and releases of IRQ for GPIO LED Trigger
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>
-rw-r--r--drivers/leds/ledtrig-gpio.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/drivers/leds/ledtrig-gpio.c b/drivers/leds/ledtrig-gpio.c
index a247ae63374f..8183b81fca84 100644
--- a/drivers/leds/ledtrig-gpio.c
+++ b/drivers/leds/ledtrig-gpio.c
@@ -146,20 +146,26 @@ static ssize_t gpio_trig_gpio_store(struct device *dev,
146 return -EINVAL; 146 return -EINVAL;
147 } 147 }
148 148
149 if (gpio_data->gpio == gpio)
150 return n;
151
149 if (!gpio) { 152 if (!gpio) {
150 free_irq(gpio_to_irq(gpio_data->gpio), led); 153 if (gpio_data->gpio != 0)
154 free_irq(gpio_to_irq(gpio_data->gpio), led);
155 gpio_data->gpio = 0;
151 return n; 156 return n;
152 } 157 }
153 158
154 if (gpio_data->gpio > 0 && gpio_data->gpio != gpio)
155 free_irq(gpio_to_irq(gpio_data->gpio), led);
156
157 gpio_data->gpio = gpio;
158 ret = request_irq(gpio_to_irq(gpio), gpio_trig_irq, 159 ret = request_irq(gpio_to_irq(gpio), gpio_trig_irq,
159 IRQF_SHARED | IRQF_TRIGGER_RISING 160 IRQF_SHARED | IRQF_TRIGGER_RISING
160 | IRQF_TRIGGER_FALLING, "ledtrig-gpio", led); 161 | IRQF_TRIGGER_FALLING, "ledtrig-gpio", led);
161 if (ret) 162 if (ret) {
162 dev_err(dev, "request_irq failed with error %d\n", ret); 163 dev_err(dev, "request_irq failed with error %d\n", ret);
164 } else {
165 if (gpio_data->gpio != 0)
166 free_irq(gpio_to_irq(gpio_data->gpio), led);
167 gpio_data->gpio = gpio;
168 }
163 169
164 return ret ? ret : n; 170 return ret ? ret : n;
165} 171}
@@ -211,7 +217,8 @@ static void gpio_trig_deactivate(struct led_classdev *led)
211 device_remove_file(led->dev, &dev_attr_inverted); 217 device_remove_file(led->dev, &dev_attr_inverted);
212 device_remove_file(led->dev, &dev_attr_desired_brightness); 218 device_remove_file(led->dev, &dev_attr_desired_brightness);
213 flush_work(&gpio_data->work); 219 flush_work(&gpio_data->work);
214 free_irq(gpio_to_irq(gpio_data->gpio),led); 220 if (gpio_data->gpio != 0)
221 free_irq(gpio_to_irq(gpio_data->gpio), led);
215 kfree(gpio_data); 222 kfree(gpio_data);
216 } 223 }
217} 224}