locking in psmouse

From: Pavel Machek
Date: Wed Apr 28 2004 - 16:48:00 EST


Hi!

psmouse-base.c does not have any locking. For example psmouse_command
could race with data coming from the mouse, resulting in problem. This
should fix it.
Pavel

--- clean/drivers/input/mouse/psmouse.h 2004-04-05 10:45:16.000000000 +0200
+++ linux/drivers/input/mouse/psmouse.h 2004-04-28 23:26:36.000000000 +0200
@@ -47,7 +47,7 @@
unsigned long last;
unsigned char state;
char acking;
- volatile char ack;
+ char ack;
char error;
char devname[64];
char phys[32];
--- clean/drivers/input/mouse/psmouse-base.c 2004-04-05 10:45:16.000000000 +0200
+++ linux/drivers/input/mouse/psmouse-base.c 2004-04-28 23:24:51.000000000 +0200
@@ -53,6 +53,8 @@
__obsolete_setup("psmouse_resetafter=");
__obsolete_setup("psmouse_rate=");

+static spinlock_t psmouse_lock = SPIN_LOCK_UNLOCKED;
+
static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};

/*
@@ -124,6 +126,7 @@
{
struct psmouse *psmouse = serio->private;

+ spin_lock_irq(&psmouse_lock);
if (psmouse->state == PSMOUSE_IGNORE)
goto out;

@@ -208,6 +211,7 @@
goto out;
}
out:
+ spin_unlock_irq(&psmouse_lock);
return IRQ_HANDLED;
}

@@ -215,6 +219,8 @@
* psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge.
* It doesn't handle retransmission, though it could - because when there would
* be need for retransmissions, the mouse has to be replaced anyway.
+ *
+ * Must be called with psmouse_lock held.
*/

static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
@@ -228,7 +234,11 @@
return -1;
}

- while (!psmouse->ack && timeout--) udelay(10);
+ while (!psmouse->ack && timeout--) {
+ spin_unlock_irq(&psmouse_lock);
+ udelay(10);
+ spin_lock_irq(&psmouse_lock);
+ }

return -(psmouse->ack <= 0);
}
@@ -243,8 +253,9 @@
int timeout = 500000; /* 500 msec */
int send = (command >> 12) & 0xf;
int receive = (command >> 8) & 0xf;
- int i;
+ int i, ret = 0;

+ spin_lock_irq(&psmouse_lock);
psmouse->cmdcnt = receive;

if (command == PSMOUSE_CMD_RESET_BAT)
@@ -257,11 +268,11 @@

if (command & 0xff)
if (psmouse_sendbyte(psmouse, command & 0xff))
- return (psmouse->cmdcnt = 0) - 1;
+ goto error;

for (i = 0; i < send; i++)
if (psmouse_sendbyte(psmouse, param[i]))
- return (psmouse->cmdcnt = 0) - 1;
+ goto error;

while (psmouse->cmdcnt && timeout--) {

@@ -275,16 +286,21 @@
break;
}

+ spin_unlock_irq(&psmouse_lock);
udelay(1);
+ spin_lock_irq(&psmouse_lock);
}

for (i = 0; i < receive; i++)
param[i] = psmouse->cmdbuf[(receive - 1) - i];

- if (psmouse->cmdcnt)
- return (psmouse->cmdcnt = 0) - 1;
-
- return 0;
+ if (psmouse->cmdcnt) {
+ error:
+ psmouse->cmdcnt = 0;
+ ret = - 1;
+ }
+ spin_unlock_irq(&psmouse_lock);
+ return ret;
}


@@ -575,7 +591,9 @@
{
struct psmouse *psmouse = serio->private;

+ spin_lock_irq(&psmouse_lock);
psmouse->state = PSMOUSE_CMD_MODE;
+ spin_unlock_irq(&psmouse_lock);

if (psmouse->ptport) {
if (psmouse->ptport->deactivate)
@@ -588,7 +606,9 @@
if (psmouse->disconnect)
psmouse->disconnect(psmouse);

+ spin_lock_irq(&psmouse_lock);
psmouse->state = PSMOUSE_IGNORE;
+ spin_unlock_irq(&psmouse_lock);

input_unregister_device(&psmouse->dev);
serio_close(serio);
@@ -675,10 +695,13 @@
return -1;
}

+ spin_lock_irq(&psmouse_lock);
old_type = psmouse->type;

psmouse->state = PSMOUSE_CMD_MODE;
psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0;
+ spin_unlock_irq(&psmouse_lock);
+
if (psmouse->reconnect) {
if (psmouse->reconnect(psmouse))
return -1;

--
934a471f20d6580d5aad759bf0d97ddc
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/