Commit e93edc59 authored by Vojtech Pavlik's avatar Vojtech Pavlik

input: Increase ACK timeouts in libps2 in case the RESET_BAT command is used.

       This should fix most Synaptics "reset failed" cases. Thanks to Keith
       Packard for the report.
       Also add some more keyboard IDs, so that unusual keyboards are accepted
       by libps2 and atkbd.
Signed-off-by: default avatarVojtech Pavlik <vojtech@suse.cz>
parent 33df3225
......@@ -526,8 +526,11 @@ static int atkbd_probe(struct atkbd *atkbd)
return 0;
}
if (param[0] != 0xab && param[0] != 0xac)
if (param[0] != 0xab && param[0] != 0xac && /* Regular and NCD Sun keyboards */
param[0] != 0x2b && param[0] != 0x5d && /* Trust keyboard, raw and translated */
param[0] != 0x60 && param[0] != 0x47) /* NMB SGI keyboard, raw and translated */
return -1;
atkbd->id = (param[0] << 8) | param[1];
if (atkbd->id == 0xaca1 && atkbd->translated) {
......
......@@ -52,7 +52,7 @@ struct ps2work {
* ps2_sendbyte() can only be called from a process context
*/
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte)
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
{
serio_pause_rx(ps2dev->serio);
ps2dev->nak = 1;
......@@ -62,7 +62,7 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte)
if (serio_write(ps2dev->serio, byte) == 0)
wait_event_interruptible_timeout(ps2dev->wait,
!(ps2dev->flags & PS2_FLAG_ACK),
msecs_to_jiffies(200));
msecs_to_jiffies(timeout));
serio_pause_rx(ps2dev->serio);
ps2dev->flags &= ~PS2_FLAG_ACK;
......@@ -88,8 +88,6 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
down(&ps2dev->cmd_sem);
timeout = msecs_to_jiffies(command == PS2_CMD_RESET_BAT ? 4000 : 500);
serio_pause_rx(ps2dev->serio);
ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
ps2dev->cmdcnt = receive;
......@@ -98,23 +96,47 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
ps2dev->cmdbuf[(receive - 1) - i] = param[i];
serio_continue_rx(ps2dev->serio);
/*
* Some devices (Synaptics) peform the reset before
* ACKing the reset command, and so it can take a long
* time before the ACK arrrives.
*/
if (command & 0xff)
if (ps2_sendbyte(ps2dev, command & 0xff))
if (ps2_sendbyte(ps2dev, command & 0xff,
command == PS2_CMD_RESET_BAT ? 1000 : 200))
goto out;
for (i = 0; i < send; i++)
if (ps2_sendbyte(ps2dev, param[i]))
if (ps2_sendbyte(ps2dev, param[i], 200))
goto out;
timeout = wait_event_interruptible_timeout(ps2dev->wait,
!(ps2dev->flags & PS2_FLAG_CMD1), timeout);
/*
* The reset command takes a long time to execute.
*/
timeout = msecs_to_jiffies(command == PS2_CMD_RESET_BAT ? 4000 : 500);
wait_event_interruptible_timeout(ps2dev->wait,
!(ps2dev->flags & PS2_FLAG_CMD1), timeout);
if (ps2dev->cmdcnt && timeout > 0) {
if (command == PS2_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100)
if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) {
/*
* Device has sent the first response byte
* after a reset command, reset is thus done,
* shorten the timeout. The next byte will come
* soon (keyboard) or not at all (mouse).
*/
timeout = msecs_to_jiffies(100);
}
if (command == PS2_CMD_GETID &&
ps2dev->cmdbuf[receive - 1] != 0xab && ps2dev->cmdbuf[receive - 1] != 0xac) {
ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */
ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */
ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */
ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */
ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */
ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */
/*
* Device behind the port is not a keyboard
* so we don't need to wait for the 2nd byte
......
......@@ -40,7 +40,7 @@ struct ps2dev {
};
void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte);
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout);
int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command);
int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
......
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