aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2009-03-07 05:43:01 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-30 11:43:17 -0400
commitf263bac9f7181df80b732b7bc11a7a4e38ca962f (patch)
tree8f764ca109e26828f05acbcb49ce3c9f19f6c2dc /drivers/media
parentc61402bae843f1f7ec29a6fe81681be21c3d201c (diff)
V4L/DVB (10938): em28xx: Prevent general protection fault on rmmod
The removal of the timer which polls the infrared input is racy. Replacing the timer with a delayed work solves the problem. Signed-off-by: Jean Delvare <khali@linux-fr.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c22
1 files changed, 6 insertions, 16 deletions
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 0443afe09ff8..a5abfd7a19f5 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -68,8 +68,7 @@ struct em28xx_IR {
68 68
69 /* poll external decoder */ 69 /* poll external decoder */
70 int polling; 70 int polling;
71 struct work_struct work; 71 struct delayed_work work;
72 struct timer_list timer;
73 unsigned int last_toggle:1; 72 unsigned int last_toggle:1;
74 unsigned int last_readcount; 73 unsigned int last_readcount;
75 unsigned int repeat_interval; 74 unsigned int repeat_interval;
@@ -292,32 +291,23 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
292 return; 291 return;
293} 292}
294 293
295static void ir_timer(unsigned long data)
296{
297 struct em28xx_IR *ir = (struct em28xx_IR *)data;
298
299 schedule_work(&ir->work);
300}
301
302static void em28xx_ir_work(struct work_struct *work) 294static void em28xx_ir_work(struct work_struct *work)
303{ 295{
304 struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work); 296 struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);
305 297
306 em28xx_ir_handle_key(ir); 298 em28xx_ir_handle_key(ir);
307 mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); 299 schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
308} 300}
309 301
310static void em28xx_ir_start(struct em28xx_IR *ir) 302static void em28xx_ir_start(struct em28xx_IR *ir)
311{ 303{
312 setup_timer(&ir->timer, ir_timer, (unsigned long)ir); 304 INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
313 INIT_WORK(&ir->work, em28xx_ir_work); 305 schedule_delayed_work(&ir->work, 0);
314 schedule_work(&ir->work);
315} 306}
316 307
317static void em28xx_ir_stop(struct em28xx_IR *ir) 308static void em28xx_ir_stop(struct em28xx_IR *ir)
318{ 309{
319 del_timer_sync(&ir->timer); 310 cancel_delayed_work_sync(&ir->work);
320 flush_scheduled_work();
321} 311}
322 312
323int em28xx_ir_init(struct em28xx *dev) 313int em28xx_ir_init(struct em28xx *dev)