Skip to content

Commit

Permalink
V4L/DVB (10939): ir-kbd-i2c: Prevent general protection fault on rmmod
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jean Delvare authored and Mauro Carvalho Chehab committed Mar 30, 2009
1 parent f263bac commit c1089bd
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 17 deletions.
20 changes: 5 additions & 15 deletions drivers/media/video/ir-kbd-i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,15 +279,9 @@ static void ir_key_poll(struct IR_i2c *ir)
}
}

static void ir_timer(unsigned long data)
{
struct IR_i2c *ir = (struct IR_i2c*)data;
schedule_work(&ir->work);
}

static void ir_work(struct work_struct *work)
{
struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work);
int polling_interval = 100;

/* MSI TV@nywhere Plus requires more frequent polling
Expand All @@ -296,7 +290,7 @@ static void ir_work(struct work_struct *work)
polling_interval = 50;

ir_key_poll(ir);
mod_timer(&ir->timer, jiffies + msecs_to_jiffies(polling_interval));
schedule_delayed_work(&ir->work, msecs_to_jiffies(polling_interval));
}

/* ----------------------------------------------------------------------- */
Expand Down Expand Up @@ -452,11 +446,8 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
ir->input->name, ir->input->phys, adap->name);

/* start polling via eventd */
INIT_WORK(&ir->work, ir_work);
init_timer(&ir->timer);
ir->timer.function = ir_timer;
ir->timer.data = (unsigned long)ir;
schedule_work(&ir->work);
INIT_DELAYED_WORK(&ir->work, ir_work);
schedule_delayed_work(&ir->work, 0);

return 0;

Expand All @@ -473,8 +464,7 @@ static int ir_detach(struct i2c_client *client)
struct IR_i2c *ir = i2c_get_clientdata(client);

/* kill outstanding polls */
del_timer_sync(&ir->timer);
flush_scheduled_work();
cancel_delayed_work_sync(&ir->work);

/* unregister devices */
input_unregister_device(ir->input);
Expand Down
3 changes: 1 addition & 2 deletions include/media/ir-kbd-i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ struct IR_i2c {
/* Used to avoid fast repeating */
unsigned char old;

struct work_struct work;
struct timer_list timer;
struct delayed_work work;
char phys[32];
int (*get_key)(struct IR_i2c*, u32*, u32*);
};
Expand Down

0 comments on commit c1089bd

Please sign in to comment.