Commit 29af30fb authored by Vojtech Pavlik's avatar Vojtech Pavlik

input: An attempt at fixing locking in i8042.c and serio.c

parent 01cb4053
......@@ -95,6 +95,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs);
/*
* The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
* be ready for reading values from it / writing values to it.
* Called always with i8042_lock held.
*/
static int i8042_wait_read(void)
......@@ -677,6 +678,7 @@ static void i8042_timer_func(unsigned long data)
static int i8042_controller_init(void)
{
unsigned long flags;
/*
* Test the i8042. We need to know if it thinks it's working correctly
......@@ -723,12 +725,14 @@ static int i8042_controller_init(void)
* Handle keylock.
*/
spin_lock_irqsave(&i8042_lock, flags);
if (~i8042_read_status() & I8042_STR_KEYLOCK) {
if (i8042_unlock)
i8042_ctr |= I8042_CTR_IGNKEYLOCK;
else
printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
}
spin_unlock_irqrestore(&i8042_lock, flags);
/*
* If the chip is configured into nontranslated mode by the BIOS, don't
......
......@@ -67,12 +67,18 @@ struct serio_event {
struct list_head node;
};
static DECLARE_MUTEX(serio_sem);
spinlock_t serio_lock = SPIN_LOCK_UNLOCKED; /* protects serio_event_list and serio->dev */
static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_dev_list */
static LIST_HEAD(serio_list);
static LIST_HEAD(serio_dev_list);
static LIST_HEAD(serio_event_list);
static int serio_pid;
/*
* serio_find_dev() must be called with serio_sem down.
*/
static void serio_find_dev(struct serio *serio)
{
struct serio_dev *dev;
......@@ -96,22 +102,42 @@ static DECLARE_COMPLETION(serio_exited);
static void serio_invalidate_pending_events(struct serio *serio)
{
struct serio_event *event;
unsigned long flags;
spin_lock_irqsave(&serio_lock, flags);
list_for_each_entry(event, &serio_event_list, node)
if (event->serio == serio)
event->serio = NULL;
spin_unlock_irqrestore(&serio_lock, flags);
}
void serio_handle_events(void)
{
struct list_head *node, *next;
struct list_head *node;
struct serio_event *event;
unsigned long flags;
while (1) {
spin_lock_irqsave(&serio_lock, flags);
if (list_empty(&serio_event_list)) {
spin_unlock_irqrestore(&serio_lock, flags);
break;
}
list_for_each_safe(node, next, &serio_event_list) {
node = serio_event_list.next;
event = container_of(node, struct serio_event, node);
list_del_init(node);
spin_unlock_irqrestore(&serio_lock, flags);
down(&serio_sem);
if (event->serio == NULL)
if (event->serio == NULL) /*!!!*/
goto event_done;
switch (event->type) {
......@@ -139,7 +165,6 @@ void serio_handle_events(void)
}
event_done:
up(&serio_sem);
list_del_init(node);
kfree(event);
}
}
......@@ -178,12 +203,18 @@ static void serio_queue_event(struct serio *serio, int event_type)
void serio_rescan(struct serio *serio)
{
unsigned long flags;
spin_lock_irqsave(&serio_lock, flags);
serio_queue_event(serio, SERIO_RESCAN);
spin_unlock_irqrestore(&serio_lock, flags);
}
void serio_reconnect(struct serio *serio)
{
unsigned long flags;
spin_lock_irqsave(&serio_lock, flags);
serio_queue_event(serio, SERIO_RECONNECT);
spin_unlock_irqrestore(&serio_lock, flags);
}
irqreturn_t serio_interrupt(struct serio *serio,
......@@ -191,17 +222,22 @@ irqreturn_t serio_interrupt(struct serio *serio,
{
irqreturn_t ret = IRQ_NONE;
spin_lock_irq(&serio_lock);
if (serio->dev && serio->dev->interrupt) {
ret = serio->dev->interrupt(serio, data, flags, regs);
} else {
if (!flags) {
if ((serio->type == SERIO_8042 ||
serio->type == SERIO_8042_XL) && (data != 0xaa))
return ret;
serio_rescan(serio);
ret = IRQ_HANDLED;
if ((serio->type != SERIO_8042 &&
serio->type != SERIO_8042_XL) || (data == 0xaa)) {
serio_queue_event(serio, SERIO_RESCAN);
ret = IRQ_HANDLED;
}
}
}
spin_unlock_irq(&serio_lock);
return ret;
}
......@@ -292,7 +328,11 @@ void serio_unregister_device(struct serio_dev *dev)
/* called from serio_dev->connect/disconnect methods under serio_sem */
int serio_open(struct serio *serio, struct serio_dev *dev)
{
unsigned long flags;
spin_lock_irqsave(&serio_lock, flags);
serio->dev = dev;
spin_unlock_irqrestore(&serio_lock, flags);
if (serio->open && serio->open(serio)) {
serio->dev = NULL;
return -1;
......@@ -303,9 +343,13 @@ int serio_open(struct serio *serio, struct serio_dev *dev)
/* called from serio_dev->connect/disconnect methods under serio_sem */
void serio_close(struct serio *serio)
{
unsigned long flags;
if (serio->close)
serio->close(serio);
spin_lock_irqsave(&serio_lock, flags);
serio->dev = NULL;
spin_unlock_irqrestore(&serio_lock, flags);
}
static int __init serio_init(void)
......
......@@ -36,7 +36,7 @@ struct serio {
int (*open)(struct serio *);
void (*close)(struct serio *);
struct serio_dev *dev;
struct serio_dev *dev; /* Accessed from interrupt, writes must be protected by serio_lock */
struct list_head node;
};
......
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