162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PS/2 driver library
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 1999-2002 Vojtech Pavlik
662306a36Sopenharmony_ci * Copyright (c) 2004 Dmitry Torokhov
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/sched.h>
1362306a36Sopenharmony_ci#include <linux/interrupt.h>
1462306a36Sopenharmony_ci#include <linux/input.h>
1562306a36Sopenharmony_ci#include <linux/kmsan-checks.h>
1662306a36Sopenharmony_ci#include <linux/serio.h>
1762306a36Sopenharmony_ci#include <linux/i8042.h>
1862306a36Sopenharmony_ci#include <linux/libps2.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define DRIVER_DESC	"PS/2 driver library"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define PS2_CMD_SETSCALE11	0x00e6
2362306a36Sopenharmony_ci#define PS2_CMD_SETRES		0x10e8
2462306a36Sopenharmony_ci#define PS2_CMD_EX_SETLEDS	0x20eb
2562306a36Sopenharmony_ci#define PS2_CMD_SETLEDS		0x10ed
2662306a36Sopenharmony_ci#define PS2_CMD_GETID		0x02f2
2762306a36Sopenharmony_ci#define PS2_CMD_SETREP		0x10f3 /* Set repeat rate/set report rate */
2862306a36Sopenharmony_ci#define PS2_CMD_RESET_BAT	0x02ff
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define PS2_RET_BAT		0xaa
3162306a36Sopenharmony_ci#define PS2_RET_ID		0x00
3262306a36Sopenharmony_ci#define PS2_RET_ACK		0xfa
3362306a36Sopenharmony_ci#define PS2_RET_NAK		0xfe
3462306a36Sopenharmony_ci#define PS2_RET_ERR		0xfc
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define PS2_FLAG_ACK		BIT(0)	/* Waiting for ACK/NAK */
3762306a36Sopenharmony_ci#define PS2_FLAG_CMD		BIT(1)	/* Waiting for a command to finish */
3862306a36Sopenharmony_ci#define PS2_FLAG_CMD1		BIT(2)	/* Waiting for the first byte of command response */
3962306a36Sopenharmony_ci#define PS2_FLAG_WAITID		BIT(3)	/* Command executing is GET ID */
4062306a36Sopenharmony_ci#define PS2_FLAG_NAK		BIT(4)	/* Last transmission was NAKed */
4162306a36Sopenharmony_ci#define PS2_FLAG_PASS_NOACK	BIT(5)	/* Pass non-ACK byte to receive handler */
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte,
4462306a36Sopenharmony_ci			   unsigned int timeout, unsigned int max_attempts)
4562306a36Sopenharmony_ci	__releases(&ps2dev->serio->lock) __acquires(&ps2dev->serio->lock)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	int attempt = 0;
4862306a36Sopenharmony_ci	int error;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	lockdep_assert_held(&ps2dev->serio->lock);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	do {
5362306a36Sopenharmony_ci		ps2dev->nak = 1;
5462306a36Sopenharmony_ci		ps2dev->flags |= PS2_FLAG_ACK;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci		serio_continue_rx(ps2dev->serio);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci		error = serio_write(ps2dev->serio, byte);
5962306a36Sopenharmony_ci		if (error)
6062306a36Sopenharmony_ci			dev_dbg(&ps2dev->serio->dev,
6162306a36Sopenharmony_ci				"failed to write %#02x: %d\n", byte, error);
6262306a36Sopenharmony_ci		else
6362306a36Sopenharmony_ci			wait_event_timeout(ps2dev->wait,
6462306a36Sopenharmony_ci					   !(ps2dev->flags & PS2_FLAG_ACK),
6562306a36Sopenharmony_ci					   msecs_to_jiffies(timeout));
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		serio_pause_rx(ps2dev->serio);
6862306a36Sopenharmony_ci	} while (ps2dev->nak == PS2_RET_NAK && ++attempt < max_attempts);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	ps2dev->flags &= ~PS2_FLAG_ACK;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (!error) {
7362306a36Sopenharmony_ci		switch (ps2dev->nak) {
7462306a36Sopenharmony_ci		case 0:
7562306a36Sopenharmony_ci			break;
7662306a36Sopenharmony_ci		case PS2_RET_NAK:
7762306a36Sopenharmony_ci			error = -EAGAIN;
7862306a36Sopenharmony_ci			break;
7962306a36Sopenharmony_ci		case PS2_RET_ERR:
8062306a36Sopenharmony_ci			error = -EPROTO;
8162306a36Sopenharmony_ci			break;
8262306a36Sopenharmony_ci		default:
8362306a36Sopenharmony_ci			error = -EIO;
8462306a36Sopenharmony_ci			break;
8562306a36Sopenharmony_ci		}
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (error || attempt > 1)
8962306a36Sopenharmony_ci		dev_dbg(&ps2dev->serio->dev,
9062306a36Sopenharmony_ci			"%02x - %d (%x), attempt %d\n",
9162306a36Sopenharmony_ci			byte, error, ps2dev->nak, attempt);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	return error;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/**
9762306a36Sopenharmony_ci * ps2_sendbyte - sends a byte to the device and wait for acknowledgement
9862306a36Sopenharmony_ci * @ps2dev: a PS/2 device to send the data to
9962306a36Sopenharmony_ci * @byte: data to be sent to the device
10062306a36Sopenharmony_ci * @timeout: timeout for sending the data and receiving an acknowledge
10162306a36Sopenharmony_ci *
10262306a36Sopenharmony_ci * The function doesn't handle retransmission, the caller is expected to handle
10362306a36Sopenharmony_ci * it when needed.
10462306a36Sopenharmony_ci *
10562306a36Sopenharmony_ci * ps2_sendbyte() can only be called from a process context.
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_ciint ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	int retval;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	serio_pause_rx(ps2dev->serio);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	retval = ps2_do_sendbyte(ps2dev, byte, timeout, 1);
11462306a36Sopenharmony_ci	dev_dbg(&ps2dev->serio->dev, "%02x - %x\n", byte, ps2dev->nak);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	serio_continue_rx(ps2dev->serio);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	return retval;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ciEXPORT_SYMBOL(ps2_sendbyte);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/**
12362306a36Sopenharmony_ci * ps2_begin_command - mark beginning of execution of a complex command
12462306a36Sopenharmony_ci * @ps2dev: a PS/2 device executing the command
12562306a36Sopenharmony_ci *
12662306a36Sopenharmony_ci * Serializes a complex/compound command. Once command is finished
12762306a36Sopenharmony_ci * ps2_end_command() should be called.
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_civoid ps2_begin_command(struct ps2dev *ps2dev)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	mutex_lock(m);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ciEXPORT_SYMBOL(ps2_begin_command);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/**
13862306a36Sopenharmony_ci * ps2_end_command - mark end of execution of a complex command
13962306a36Sopenharmony_ci * @ps2dev: a PS/2 device executing the command
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_civoid ps2_end_command(struct ps2dev *ps2dev)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	mutex_unlock(m);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ciEXPORT_SYMBOL(ps2_end_command);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/**
15062306a36Sopenharmony_ci * ps2_drain - waits for device to transmit requested number of bytes
15162306a36Sopenharmony_ci * and discards them
15262306a36Sopenharmony_ci * @ps2dev: the PS/2 device that should be drained
15362306a36Sopenharmony_ci * @maxbytes: maximum number of bytes to be drained
15462306a36Sopenharmony_ci * @timeout: time to drain the device
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_civoid ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	if (maxbytes > sizeof(ps2dev->cmdbuf)) {
15962306a36Sopenharmony_ci		WARN_ON(1);
16062306a36Sopenharmony_ci		maxbytes = sizeof(ps2dev->cmdbuf);
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	ps2_begin_command(ps2dev);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	serio_pause_rx(ps2dev->serio);
16662306a36Sopenharmony_ci	ps2dev->flags = PS2_FLAG_CMD;
16762306a36Sopenharmony_ci	ps2dev->cmdcnt = maxbytes;
16862306a36Sopenharmony_ci	serio_continue_rx(ps2dev->serio);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	wait_event_timeout(ps2dev->wait,
17162306a36Sopenharmony_ci			   !(ps2dev->flags & PS2_FLAG_CMD),
17262306a36Sopenharmony_ci			   msecs_to_jiffies(timeout));
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	ps2_end_command(ps2dev);
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ciEXPORT_SYMBOL(ps2_drain);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/**
17962306a36Sopenharmony_ci * ps2_is_keyboard_id - checks received ID byte against the list of
18062306a36Sopenharmony_ci *   known keyboard IDs
18162306a36Sopenharmony_ci * @id_byte: data byte that should be checked
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_cibool ps2_is_keyboard_id(u8 id_byte)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	static const u8 keyboard_ids[] = {
18662306a36Sopenharmony_ci		0xab,	/* Regular keyboards		*/
18762306a36Sopenharmony_ci		0xac,	/* NCD Sun keyboard		*/
18862306a36Sopenharmony_ci		0x2b,	/* Trust keyboard, translated	*/
18962306a36Sopenharmony_ci		0x5d,	/* Trust keyboard		*/
19062306a36Sopenharmony_ci		0x60,	/* NMB SGI keyboard, translated */
19162306a36Sopenharmony_ci		0x47,	/* NMB SGI keyboard		*/
19262306a36Sopenharmony_ci	};
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ciEXPORT_SYMBOL(ps2_is_keyboard_id);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/*
19962306a36Sopenharmony_ci * ps2_adjust_timeout() is called after receiving 1st byte of command
20062306a36Sopenharmony_ci * response and tries to reduce remaining timeout to speed up command
20162306a36Sopenharmony_ci * completion.
20262306a36Sopenharmony_ci */
20362306a36Sopenharmony_cistatic int ps2_adjust_timeout(struct ps2dev *ps2dev,
20462306a36Sopenharmony_ci			      unsigned int command, unsigned int timeout)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	switch (command) {
20762306a36Sopenharmony_ci	case PS2_CMD_RESET_BAT:
20862306a36Sopenharmony_ci		/*
20962306a36Sopenharmony_ci		 * Device has sent the first response byte after
21062306a36Sopenharmony_ci		 * reset command, reset is thus done, so we can
21162306a36Sopenharmony_ci		 * shorten the timeout.
21262306a36Sopenharmony_ci		 * The next byte will come soon (keyboard) or not
21362306a36Sopenharmony_ci		 * at all (mouse).
21462306a36Sopenharmony_ci		 */
21562306a36Sopenharmony_ci		if (timeout > msecs_to_jiffies(100))
21662306a36Sopenharmony_ci			timeout = msecs_to_jiffies(100);
21762306a36Sopenharmony_ci		break;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	case PS2_CMD_GETID:
22062306a36Sopenharmony_ci		/*
22162306a36Sopenharmony_ci		 * Microsoft Natural Elite keyboard responds to
22262306a36Sopenharmony_ci		 * the GET ID command as it were a mouse, with
22362306a36Sopenharmony_ci		 * a single byte. Fail the command so atkbd will
22462306a36Sopenharmony_ci		 * use alternative probe to detect it.
22562306a36Sopenharmony_ci		 */
22662306a36Sopenharmony_ci		if (ps2dev->cmdbuf[1] == 0xaa) {
22762306a36Sopenharmony_ci			serio_pause_rx(ps2dev->serio);
22862306a36Sopenharmony_ci			ps2dev->flags = 0;
22962306a36Sopenharmony_ci			serio_continue_rx(ps2dev->serio);
23062306a36Sopenharmony_ci			timeout = 0;
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		/*
23462306a36Sopenharmony_ci		 * If device behind the port is not a keyboard there
23562306a36Sopenharmony_ci		 * won't be 2nd byte of ID response.
23662306a36Sopenharmony_ci		 */
23762306a36Sopenharmony_ci		if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
23862306a36Sopenharmony_ci			serio_pause_rx(ps2dev->serio);
23962306a36Sopenharmony_ci			ps2dev->flags = ps2dev->cmdcnt = 0;
24062306a36Sopenharmony_ci			serio_continue_rx(ps2dev->serio);
24162306a36Sopenharmony_ci			timeout = 0;
24262306a36Sopenharmony_ci		}
24362306a36Sopenharmony_ci		break;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	default:
24662306a36Sopenharmony_ci		break;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return timeout;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci/**
25362306a36Sopenharmony_ci * __ps2_command - send a command to PS/2 device
25462306a36Sopenharmony_ci * @ps2dev: the PS/2 device that should execute the command
25562306a36Sopenharmony_ci * @param: a buffer containing parameters to be sent along with the command,
25662306a36Sopenharmony_ci *   or place where the results of the command execution will be deposited,
25762306a36Sopenharmony_ci *   or both
25862306a36Sopenharmony_ci * @command: command word that encodes the command itself, as well as number of
25962306a36Sopenharmony_ci *   additional parameter bytes that should be sent to the device and expected
26062306a36Sopenharmony_ci *   length of the command response
26162306a36Sopenharmony_ci *
26262306a36Sopenharmony_ci * Not serialized. Callers should use ps2_begin_command() and ps2_end_command()
26362306a36Sopenharmony_ci * to ensure proper serialization for complex commands.
26462306a36Sopenharmony_ci */
26562306a36Sopenharmony_ciint __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	unsigned int timeout;
26862306a36Sopenharmony_ci	unsigned int send = (command >> 12) & 0xf;
26962306a36Sopenharmony_ci	unsigned int receive = (command >> 8) & 0xf;
27062306a36Sopenharmony_ci	int rc;
27162306a36Sopenharmony_ci	int i;
27262306a36Sopenharmony_ci	u8 send_param[16];
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (receive > sizeof(ps2dev->cmdbuf)) {
27562306a36Sopenharmony_ci		WARN_ON(1);
27662306a36Sopenharmony_ci		return -EINVAL;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (send && !param) {
28062306a36Sopenharmony_ci		WARN_ON(1);
28162306a36Sopenharmony_ci		return -EINVAL;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	memcpy(send_param, param, send);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	serio_pause_rx(ps2dev->serio);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	ps2dev->cmdcnt = receive;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	switch (command) {
29162306a36Sopenharmony_ci	case PS2_CMD_GETID:
29262306a36Sopenharmony_ci		/*
29362306a36Sopenharmony_ci		 * Some mice do not ACK the "get ID" command, prepare to
29462306a36Sopenharmony_ci		 * handle this.
29562306a36Sopenharmony_ci		 */
29662306a36Sopenharmony_ci		ps2dev->flags = PS2_FLAG_WAITID;
29762306a36Sopenharmony_ci		break;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	case PS2_CMD_SETLEDS:
30062306a36Sopenharmony_ci	case PS2_CMD_EX_SETLEDS:
30162306a36Sopenharmony_ci	case PS2_CMD_SETREP:
30262306a36Sopenharmony_ci		ps2dev->flags = PS2_FLAG_PASS_NOACK;
30362306a36Sopenharmony_ci		break;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	default:
30662306a36Sopenharmony_ci		ps2dev->flags = 0;
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (receive) {
31162306a36Sopenharmony_ci		/* Indicate that we expect response to the command. */
31262306a36Sopenharmony_ci		ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1;
31362306a36Sopenharmony_ci		if (param)
31462306a36Sopenharmony_ci			for (i = 0; i < receive; i++)
31562306a36Sopenharmony_ci				ps2dev->cmdbuf[(receive - 1) - i] = param[i];
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	/*
31962306a36Sopenharmony_ci	 * Some devices (Synaptics) perform the reset before
32062306a36Sopenharmony_ci	 * ACKing the reset command, and so it can take a long
32162306a36Sopenharmony_ci	 * time before the ACK arrives.
32262306a36Sopenharmony_ci	 */
32362306a36Sopenharmony_ci	timeout = command == PS2_CMD_RESET_BAT ? 1000 : 200;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	rc = ps2_do_sendbyte(ps2dev, command & 0xff, timeout, 2);
32662306a36Sopenharmony_ci	if (rc)
32762306a36Sopenharmony_ci		goto out_reset_flags;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	/* Send command parameters, if any. */
33062306a36Sopenharmony_ci	for (i = 0; i < send; i++) {
33162306a36Sopenharmony_ci		rc = ps2_do_sendbyte(ps2dev, param[i], 200, 2);
33262306a36Sopenharmony_ci		if (rc)
33362306a36Sopenharmony_ci			goto out_reset_flags;
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	serio_continue_rx(ps2dev->serio);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/*
33962306a36Sopenharmony_ci	 * The reset command takes a long time to execute.
34062306a36Sopenharmony_ci	 */
34162306a36Sopenharmony_ci	timeout = msecs_to_jiffies(command == PS2_CMD_RESET_BAT ? 4000 : 500);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	timeout = wait_event_timeout(ps2dev->wait,
34462306a36Sopenharmony_ci				     !(ps2dev->flags & PS2_FLAG_CMD1), timeout);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (ps2dev->cmdcnt && !(ps2dev->flags & PS2_FLAG_CMD1)) {
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		timeout = ps2_adjust_timeout(ps2dev, command, timeout);
34962306a36Sopenharmony_ci		wait_event_timeout(ps2dev->wait,
35062306a36Sopenharmony_ci				   !(ps2dev->flags & PS2_FLAG_CMD), timeout);
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	serio_pause_rx(ps2dev->serio);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (param) {
35662306a36Sopenharmony_ci		for (i = 0; i < receive; i++)
35762306a36Sopenharmony_ci			param[i] = ps2dev->cmdbuf[(receive - 1) - i];
35862306a36Sopenharmony_ci		kmsan_unpoison_memory(param, receive);
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (ps2dev->cmdcnt &&
36262306a36Sopenharmony_ci	    (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) {
36362306a36Sopenharmony_ci		rc = -EPROTO;
36462306a36Sopenharmony_ci		goto out_reset_flags;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	rc = 0;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci out_reset_flags:
37062306a36Sopenharmony_ci	ps2dev->flags = 0;
37162306a36Sopenharmony_ci	serio_continue_rx(ps2dev->serio);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	dev_dbg(&ps2dev->serio->dev,
37462306a36Sopenharmony_ci		"%02x [%*ph] - %x/%08lx [%*ph]\n",
37562306a36Sopenharmony_ci		command & 0xff, send, send_param,
37662306a36Sopenharmony_ci		ps2dev->nak, ps2dev->flags,
37762306a36Sopenharmony_ci		receive, param ?: send_param);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/*
38062306a36Sopenharmony_ci	 * ps_command() handles resends itself, so do not leak -EAGAIN
38162306a36Sopenharmony_ci	 * to the callers.
38262306a36Sopenharmony_ci	 */
38362306a36Sopenharmony_ci	return rc != -EAGAIN ? rc : -EPROTO;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ciEXPORT_SYMBOL(__ps2_command);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/**
38862306a36Sopenharmony_ci * ps2_command - send a command to PS/2 device
38962306a36Sopenharmony_ci * @ps2dev: the PS/2 device that should execute the command
39062306a36Sopenharmony_ci * @param: a buffer containing parameters to be sent along with the command,
39162306a36Sopenharmony_ci *   or place where the results of the command execution will be deposited,
39262306a36Sopenharmony_ci *   or both
39362306a36Sopenharmony_ci * @command: command word that encodes the command itself, as well as number of
39462306a36Sopenharmony_ci *   additional parameter bytes that should be sent to the device and expected
39562306a36Sopenharmony_ci *   length of the command response
39662306a36Sopenharmony_ci *
39762306a36Sopenharmony_ci * Note: ps2_command() serializes the command execution so that only one
39862306a36Sopenharmony_ci * command can be executed at a time for either individual port or the entire
39962306a36Sopenharmony_ci * 8042 controller.
40062306a36Sopenharmony_ci */
40162306a36Sopenharmony_ciint ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	int rc;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	ps2_begin_command(ps2dev);
40662306a36Sopenharmony_ci	rc = __ps2_command(ps2dev, param, command);
40762306a36Sopenharmony_ci	ps2_end_command(ps2dev);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	return rc;
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ciEXPORT_SYMBOL(ps2_command);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci/**
41462306a36Sopenharmony_ci * ps2_sliced_command - sends an extended PS/2 command to a mouse
41562306a36Sopenharmony_ci * @ps2dev: the PS/2 device that should execute the command
41662306a36Sopenharmony_ci * @command: command byte
41762306a36Sopenharmony_ci *
41862306a36Sopenharmony_ci * The command is sent using "sliced" syntax understood by advanced devices,
41962306a36Sopenharmony_ci * such as Logitech or Synaptics touchpads. The command is encoded as:
42062306a36Sopenharmony_ci * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
42162306a36Sopenharmony_ci * is the command.
42262306a36Sopenharmony_ci */
42362306a36Sopenharmony_ciint ps2_sliced_command(struct ps2dev *ps2dev, u8 command)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	int i;
42662306a36Sopenharmony_ci	int retval;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	ps2_begin_command(ps2dev);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	retval = __ps2_command(ps2dev, NULL, PS2_CMD_SETSCALE11);
43162306a36Sopenharmony_ci	if (retval)
43262306a36Sopenharmony_ci		goto out;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	for (i = 6; i >= 0; i -= 2) {
43562306a36Sopenharmony_ci		u8 d = (command >> i) & 3;
43662306a36Sopenharmony_ci		retval = __ps2_command(ps2dev, &d, PS2_CMD_SETRES);
43762306a36Sopenharmony_ci		if (retval)
43862306a36Sopenharmony_ci			break;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ciout:
44262306a36Sopenharmony_ci	dev_dbg(&ps2dev->serio->dev, "%02x - %d\n", command, retval);
44362306a36Sopenharmony_ci	ps2_end_command(ps2dev);
44462306a36Sopenharmony_ci	return retval;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ciEXPORT_SYMBOL(ps2_sliced_command);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci/**
44962306a36Sopenharmony_ci * ps2_init - initializes ps2dev structure
45062306a36Sopenharmony_ci * @ps2dev: structure to be initialized
45162306a36Sopenharmony_ci * @serio: serio port associated with the PS/2 device
45262306a36Sopenharmony_ci * @pre_receive_handler: validation handler to check basic communication state
45362306a36Sopenharmony_ci * @receive_handler: main protocol handler
45462306a36Sopenharmony_ci *
45562306a36Sopenharmony_ci * Prepares ps2dev structure for use in drivers for PS/2 devices.
45662306a36Sopenharmony_ci */
45762306a36Sopenharmony_civoid ps2_init(struct ps2dev *ps2dev, struct serio *serio,
45862306a36Sopenharmony_ci	      ps2_pre_receive_handler_t pre_receive_handler,
45962306a36Sopenharmony_ci	      ps2_receive_handler_t receive_handler)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	ps2dev->pre_receive_handler = pre_receive_handler;
46262306a36Sopenharmony_ci	ps2dev->receive_handler = receive_handler;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	mutex_init(&ps2dev->cmd_mutex);
46562306a36Sopenharmony_ci	lockdep_set_subclass(&ps2dev->cmd_mutex, serio->depth);
46662306a36Sopenharmony_ci	init_waitqueue_head(&ps2dev->wait);
46762306a36Sopenharmony_ci	ps2dev->serio = serio;
46862306a36Sopenharmony_ci	serio_set_drvdata(serio, ps2dev);
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ciEXPORT_SYMBOL(ps2_init);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci/*
47362306a36Sopenharmony_ci * ps2_handle_response() stores device's response to a command and notifies
47462306a36Sopenharmony_ci * the process waiting for completion of the command. Note that there is a
47562306a36Sopenharmony_ci * distinction between waiting for the first byte of the response, and
47662306a36Sopenharmony_ci * waiting for subsequent bytes. It is done so that callers could shorten
47762306a36Sopenharmony_ci * timeouts once first byte of response is received.
47862306a36Sopenharmony_ci */
47962306a36Sopenharmony_cistatic void ps2_handle_response(struct ps2dev *ps2dev, u8 data)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	if (ps2dev->cmdcnt)
48262306a36Sopenharmony_ci		ps2dev->cmdbuf[--ps2dev->cmdcnt] = data;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (ps2dev->flags & PS2_FLAG_CMD1) {
48562306a36Sopenharmony_ci		ps2dev->flags &= ~PS2_FLAG_CMD1;
48662306a36Sopenharmony_ci		if (ps2dev->cmdcnt)
48762306a36Sopenharmony_ci			wake_up(&ps2dev->wait);
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (!ps2dev->cmdcnt) {
49162306a36Sopenharmony_ci		ps2dev->flags &= ~PS2_FLAG_CMD;
49262306a36Sopenharmony_ci		wake_up(&ps2dev->wait);
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci/*
49762306a36Sopenharmony_ci * ps2_handle_ack() processes ACK/NAK of a command from a PS/2 device,
49862306a36Sopenharmony_ci * possibly applying workarounds for mice not acknowledging the "get ID"
49962306a36Sopenharmony_ci * command.
50062306a36Sopenharmony_ci */
50162306a36Sopenharmony_cistatic void ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	switch (data) {
50462306a36Sopenharmony_ci	case PS2_RET_ACK:
50562306a36Sopenharmony_ci		ps2dev->nak = 0;
50662306a36Sopenharmony_ci		break;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	case PS2_RET_NAK:
50962306a36Sopenharmony_ci		ps2dev->flags |= PS2_FLAG_NAK;
51062306a36Sopenharmony_ci		ps2dev->nak = PS2_RET_NAK;
51162306a36Sopenharmony_ci		break;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	case PS2_RET_ERR:
51462306a36Sopenharmony_ci		if (ps2dev->flags & PS2_FLAG_NAK) {
51562306a36Sopenharmony_ci			ps2dev->flags &= ~PS2_FLAG_NAK;
51662306a36Sopenharmony_ci			ps2dev->nak = PS2_RET_ERR;
51762306a36Sopenharmony_ci			break;
51862306a36Sopenharmony_ci		}
51962306a36Sopenharmony_ci		fallthrough;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/*
52262306a36Sopenharmony_ci	 * Workaround for mice which don't ACK the Get ID command.
52362306a36Sopenharmony_ci	 * These are valid mouse IDs that we recognize.
52462306a36Sopenharmony_ci	 */
52562306a36Sopenharmony_ci	case 0x00:
52662306a36Sopenharmony_ci	case 0x03:
52762306a36Sopenharmony_ci	case 0x04:
52862306a36Sopenharmony_ci		if (ps2dev->flags & PS2_FLAG_WAITID) {
52962306a36Sopenharmony_ci			ps2dev->nak = 0;
53062306a36Sopenharmony_ci			break;
53162306a36Sopenharmony_ci		}
53262306a36Sopenharmony_ci		fallthrough;
53362306a36Sopenharmony_ci	default:
53462306a36Sopenharmony_ci		/*
53562306a36Sopenharmony_ci		 * Do not signal errors if we get unexpected reply while
53662306a36Sopenharmony_ci		 * waiting for an ACK to the initial (first) command byte:
53762306a36Sopenharmony_ci		 * the device might not be quiesced yet and continue
53862306a36Sopenharmony_ci		 * delivering data. For certain commands (such as set leds and
53962306a36Sopenharmony_ci		 * set repeat rate) that can be used during normal device
54062306a36Sopenharmony_ci		 * operation, we even pass this data byte to the normal receive
54162306a36Sopenharmony_ci		 * handler.
54262306a36Sopenharmony_ci		 * Note that we reset PS2_FLAG_WAITID flag, so the workaround
54362306a36Sopenharmony_ci		 * for mice not acknowledging the Get ID command only triggers
54462306a36Sopenharmony_ci		 * on the 1st byte; if device spews data we really want to see
54562306a36Sopenharmony_ci		 * a real ACK from it.
54662306a36Sopenharmony_ci		 */
54762306a36Sopenharmony_ci		dev_dbg(&ps2dev->serio->dev, "unexpected %#02x\n", data);
54862306a36Sopenharmony_ci		if (ps2dev->flags & PS2_FLAG_PASS_NOACK)
54962306a36Sopenharmony_ci			ps2dev->receive_handler(ps2dev, data);
55062306a36Sopenharmony_ci		ps2dev->flags &= ~(PS2_FLAG_WAITID | PS2_FLAG_PASS_NOACK);
55162306a36Sopenharmony_ci		return;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	if (!ps2dev->nak)
55562306a36Sopenharmony_ci		ps2dev->flags &= ~PS2_FLAG_NAK;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	ps2dev->flags &= ~PS2_FLAG_ACK;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if (!ps2dev->nak && data != PS2_RET_ACK)
56062306a36Sopenharmony_ci		ps2_handle_response(ps2dev, data);
56162306a36Sopenharmony_ci	else
56262306a36Sopenharmony_ci		wake_up(&ps2dev->wait);
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci/*
56662306a36Sopenharmony_ci * Clears state of PS/2 device after communication error by resetting majority
56762306a36Sopenharmony_ci * of flags and waking up waiters, if any.
56862306a36Sopenharmony_ci */
56962306a36Sopenharmony_cistatic void ps2_cleanup(struct ps2dev *ps2dev)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	unsigned long old_flags = ps2dev->flags;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	/* reset all flags except last nak */
57462306a36Sopenharmony_ci	ps2dev->flags &= PS2_FLAG_NAK;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (old_flags & PS2_FLAG_ACK)
57762306a36Sopenharmony_ci		ps2dev->nak = 1;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	if (old_flags & (PS2_FLAG_ACK | PS2_FLAG_CMD))
58062306a36Sopenharmony_ci		wake_up(&ps2dev->wait);
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci/**
58462306a36Sopenharmony_ci * ps2_interrupt - common interrupt handler for PS/2 devices
58562306a36Sopenharmony_ci * @serio: serio port for the device
58662306a36Sopenharmony_ci * @data: a data byte received from the device
58762306a36Sopenharmony_ci * @flags: flags such as %SERIO_PARITY or %SERIO_TIMEOUT indicating state of
58862306a36Sopenharmony_ci *   the data transfer
58962306a36Sopenharmony_ci *
59062306a36Sopenharmony_ci * ps2_interrupt() invokes pre-receive handler, optionally handles command
59162306a36Sopenharmony_ci * acknowledgement and response from the device, and finally passes the data
59262306a36Sopenharmony_ci * to the main protocol handler for future processing.
59362306a36Sopenharmony_ci */
59462306a36Sopenharmony_ciirqreturn_t ps2_interrupt(struct serio *serio, u8 data, unsigned int flags) {
59562306a36Sopenharmony_ci	struct ps2dev *ps2dev = serio_get_drvdata(serio);
59662306a36Sopenharmony_ci	enum ps2_disposition rc;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	rc = ps2dev->pre_receive_handler(ps2dev, data, flags);
59962306a36Sopenharmony_ci	switch (rc) {
60062306a36Sopenharmony_ci	case PS2_ERROR:
60162306a36Sopenharmony_ci		ps2_cleanup(ps2dev);
60262306a36Sopenharmony_ci		break;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	case PS2_IGNORE:
60562306a36Sopenharmony_ci		break;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	case PS2_PROCESS:
60862306a36Sopenharmony_ci		if (ps2dev->flags & PS2_FLAG_ACK)
60962306a36Sopenharmony_ci			ps2_handle_ack(ps2dev, data);
61062306a36Sopenharmony_ci		else if (ps2dev->flags & PS2_FLAG_CMD)
61162306a36Sopenharmony_ci			ps2_handle_response(ps2dev, data);
61262306a36Sopenharmony_ci		else
61362306a36Sopenharmony_ci			ps2dev->receive_handler(ps2dev, data);
61462306a36Sopenharmony_ci		break;
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	return IRQ_HANDLED;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ciEXPORT_SYMBOL(ps2_interrupt);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ciMODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
62262306a36Sopenharmony_ciMODULE_DESCRIPTION("PS/2 driver library");
62362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
624