Commit c472d33b authored by Dmitry Torokhov's avatar Dmitry Torokhov

Input: cypress_ps2 - fix waiting for command response

Commit 8bccf667 ("Input: cypress_ps2 - report timeouts when reading
command status") uncovered an existing problem with cypress_ps2 driver:
it tries waiting on a PS/2 device waitqueue without using the rest of
libps2. Unfortunately without it nobody signals wakeup for the
waiting process, and each "extended" command was timing out. But the
rest of the code simply did not notice it.

Fix this by switching from homegrown way of sending request to get
command response and reading it to standard ps2_command() which does
the right thing.
Reported-by: default avatarWoody Suwalski <terraluna977@gmail.com>
Tested-by: default avatarWoody Suwalski <terraluna977@gmail.com>
Fixes: 8bccf667 ("Input: cypress_ps2 - report timeouts when reading command status")
Link: https://lore.kernel.org/r/a8252e0f-dab4-ef5e-2aa1-407a6f4c7204@gmail.comSigned-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 4e870e6b
...@@ -91,48 +91,6 @@ static int cypress_ps2_ext_cmd(struct psmouse *psmouse, u8 prefix, u8 nibble) ...@@ -91,48 +91,6 @@ static int cypress_ps2_ext_cmd(struct psmouse *psmouse, u8 prefix, u8 nibble)
return rc; return rc;
} }
static int cypress_ps2_read_cmd_status(struct psmouse *psmouse,
u8 cmd, u8 *param)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
enum psmouse_state old_state;
int pktsize;
int rc;
ps2_begin_command(ps2dev);
old_state = psmouse->state;
psmouse->state = PSMOUSE_CMD_MODE;
psmouse->pktcnt = 0;
pktsize = (cmd == CYTP_CMD_READ_TP_METRICS) ? 8 : 3;
memset(param, 0, pktsize);
rc = cypress_ps2_sendbyte(psmouse, PSMOUSE_CMD_GETINFO & 0xff);
if (rc)
goto out;
if (!wait_event_timeout(ps2dev->wait,
psmouse->pktcnt >= pktsize,
msecs_to_jiffies(CYTP_CMD_TIMEOUT))) {
rc = -ETIMEDOUT;
goto out;
}
memcpy(param, psmouse->packet, pktsize);
psmouse_dbg(psmouse, "Command 0x%02x response data (0x): %*ph\n",
cmd, pktsize, param);
out:
psmouse->state = old_state;
psmouse->pktcnt = 0;
ps2_end_command(ps2dev);
return rc;
}
static bool cypress_verify_cmd_state(struct psmouse *psmouse, u8 cmd, u8* param) static bool cypress_verify_cmd_state(struct psmouse *psmouse, u8 cmd, u8* param)
{ {
bool rate_match = false; bool rate_match = false;
...@@ -166,6 +124,8 @@ static bool cypress_verify_cmd_state(struct psmouse *psmouse, u8 cmd, u8* param) ...@@ -166,6 +124,8 @@ static bool cypress_verify_cmd_state(struct psmouse *psmouse, u8 cmd, u8* param)
static int cypress_send_ext_cmd(struct psmouse *psmouse, u8 cmd, u8 *param) static int cypress_send_ext_cmd(struct psmouse *psmouse, u8 cmd, u8 *param)
{ {
u8 cmd_prefix = PSMOUSE_CMD_SETRES & 0xff; u8 cmd_prefix = PSMOUSE_CMD_SETRES & 0xff;
unsigned int resp_size = cmd == CYTP_CMD_READ_TP_METRICS ? 8 : 3;
unsigned int ps2_cmd = (PSMOUSE_CMD_GETINFO & 0xff) | (resp_size << 8);
int tries = CYTP_PS2_CMD_TRIES; int tries = CYTP_PS2_CMD_TRIES;
int error; int error;
...@@ -179,10 +139,18 @@ static int cypress_send_ext_cmd(struct psmouse *psmouse, u8 cmd, u8 *param) ...@@ -179,10 +139,18 @@ static int cypress_send_ext_cmd(struct psmouse *psmouse, u8 cmd, u8 *param)
cypress_ps2_ext_cmd(psmouse, cmd_prefix, DECODE_CMD_BB(cmd)); cypress_ps2_ext_cmd(psmouse, cmd_prefix, DECODE_CMD_BB(cmd));
cypress_ps2_ext_cmd(psmouse, cmd_prefix, DECODE_CMD_AA(cmd)); cypress_ps2_ext_cmd(psmouse, cmd_prefix, DECODE_CMD_AA(cmd));
error = cypress_ps2_read_cmd_status(psmouse, cmd, param); error = ps2_command(&psmouse->ps2dev, param, ps2_cmd);
if (!error && cypress_verify_cmd_state(psmouse, cmd, param)) if (error) {
return 0; psmouse_dbg(psmouse, "Command 0x%02x failed: %d\n",
cmd, error);
} else {
psmouse_dbg(psmouse,
"Command 0x%02x response data (0x): %*ph\n",
cmd, resp_size, param);
if (cypress_verify_cmd_state(psmouse, cmd, param))
return 0;
}
} while (--tries > 0); } while (--tries > 0);
return -EIO; return -EIO;
......
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