Commit 6ce315cc authored by Dmitry Torokhov's avatar Dmitry Torokhov

Input: psmouse - harden command mode processing logic

Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 83d0c706
...@@ -150,36 +150,47 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -150,36 +150,47 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
goto out; goto out;
} }
if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags)) if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags)) {
switch (data) { switch (data) {
case PSMOUSE_RET_ACK: case PSMOUSE_RET_ACK:
psmouse->nak = 0; psmouse->nak = 0;
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
goto out;
break; break;
case PSMOUSE_RET_NAK: case PSMOUSE_RET_NAK:
psmouse->nak = 1; psmouse->nak = 1;
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); break;
goto out;
/*
* Workaround for mice which don't ACK the Get ID command.
* These are valid mouse IDs that we recognize.
*/
case 0x00:
case 0x03:
case 0x04:
if (test_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags)) {
psmouse->nak = 0;
break;
}
/* Fall through */
default: default:
psmouse->nak = 0; /* Workaround for mice which don't ACK the Get ID command */
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
if (!test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags))
goto out; goto out;
}
if (!psmouse->nak && psmouse->cmdcnt) {
set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
} }
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) { if (data == PSMOUSE_RET_ACK || data == PSMOUSE_RET_NAK)
goto out;
}
psmouse->cmdcnt--; if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) {
psmouse->cmdbuf[psmouse->cmdcnt] = data; if (psmouse->cmdcnt)
psmouse->cmdbuf[--psmouse->cmdcnt] = data;
if (psmouse->cmdcnt == 1) {
if (data != 0xab && data != 0xac)
clear_bit(PSMOUSE_FLAG_ID, &psmouse->flags);
clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
}
if (!psmouse->cmdcnt) if (!psmouse->cmdcnt)
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
...@@ -284,6 +295,7 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) ...@@ -284,6 +295,7 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
int timeout = 500000; /* 500 msec */ int timeout = 500000; /* 500 msec */
int send = (command >> 12) & 0xf; int send = (command >> 12) & 0xf;
int receive = (command >> 8) & 0xf; int receive = (command >> 8) & 0xf;
int rc = -1;
int i; int i;
psmouse->cmdcnt = receive; psmouse->cmdcnt = receive;
...@@ -291,27 +303,20 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) ...@@ -291,27 +303,20 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
if (command == PSMOUSE_CMD_RESET_BAT) if (command == PSMOUSE_CMD_RESET_BAT)
timeout = 4000000; /* 4 sec */ timeout = 4000000; /* 4 sec */
if (command == PSMOUSE_CMD_GETID)
set_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags);
if (receive && param) if (receive && param)
for (i = 0; i < receive; i++) for (i = 0; i < receive; i++)
psmouse->cmdbuf[(receive - 1) - i] = param[i]; psmouse->cmdbuf[(receive - 1) - i] = param[i];
if (receive) {
set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
set_bit(PSMOUSE_FLAG_ID, &psmouse->flags);
}
if (command & 0xff) if (command & 0xff)
if (psmouse_sendbyte(psmouse, command & 0xff)) { if (psmouse_sendbyte(psmouse, command & 0xff))
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); goto out;
return -1;
}
for (i = 0; i < send; i++) for (i = 0; i < send; i++)
if (psmouse_sendbyte(psmouse, param[i])) { if (psmouse_sendbyte(psmouse, param[i]))
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); goto out;
return -1;
}
while (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags) && timeout--) { while (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags) && timeout--) {
...@@ -320,7 +325,13 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) ...@@ -320,7 +325,13 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
if (command == PSMOUSE_CMD_RESET_BAT && timeout > 100000) if (command == PSMOUSE_CMD_RESET_BAT && timeout > 100000)
timeout = 100000; timeout = 100000;
if (command == PSMOUSE_CMD_GETID && !test_bit(PSMOUSE_FLAG_ID, &psmouse->flags)) { if (command == PSMOUSE_CMD_GETID &&
psmouse->cmdbuf[receive - 1] != 0xab && psmouse->cmdbuf[receive - 1] != 0xac) {
/*
* Device behind the port is not a keyboard
* so we don't need to wait for the 2nd byte
* of ID response.
*/
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
psmouse->cmdcnt = 0; psmouse->cmdcnt = 0;
break; break;
...@@ -330,19 +341,20 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) ...@@ -330,19 +341,20 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
udelay(1); udelay(1);
} }
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
if (param) if (param)
for (i = 0; i < receive; i++) for (i = 0; i < receive; i++)
param[i] = psmouse->cmdbuf[(receive - 1) - i]; param[i] = psmouse->cmdbuf[(receive - 1) - i];
if (command == PSMOUSE_CMD_RESET_BAT && psmouse->cmdcnt == 1) if (psmouse->cmdcnt && (command != PSMOUSE_CMD_RESET_BAT || psmouse->cmdcnt != 1))
return 0; goto out;
if (psmouse->cmdcnt) rc = 0;
return -1;
return 0; out:
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
clear_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags);
return rc;
} }
/* /*
......
...@@ -20,8 +20,8 @@ ...@@ -20,8 +20,8 @@
#define PSMOUSE_FLAG_ACK 0 /* Waiting for ACK/NAK */ #define PSMOUSE_FLAG_ACK 0 /* Waiting for ACK/NAK */
#define PSMOUSE_FLAG_CMD 1 /* Waiting for command to finish */ #define PSMOUSE_FLAG_CMD 1 /* Waiting for command to finish */
#define PSMOUSE_FLAG_CMD1 2 /* First byte of command response */ #define PSMOUSE_FLAG_CMD1 2 /* Waiting for the first byte of command response */
#define PSMOUSE_FLAG_ID 3 /* First byte is not keyboard ID */ #define PSMOUSE_FLAG_WAITID 3 /* Command execiting is GET ID */
enum psmouse_state { enum psmouse_state {
PSMOUSE_IGNORE, PSMOUSE_IGNORE,
......
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