#define PS2_FLAG_ACK BIT(0) /* Waiting for ACK/NAK */ #define PS2_FLAG_CMD BIT(1) /* Waiting for a command to finish */ #define PS2_FLAG_CMD1 BIT(2) /* Waiting for the first byte of command response */ #define PS2_FLAG_WAITID BIT(3) /* Command executing is GET ID */ #define PS2_FLAG_NAK BIT(4) /* Last transmission was NAKed */ #define PS2_FLAG_PASS_NOACK BIT(5) /* Pass non-ACK byte to receive handler */
staticint ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte, unsignedint timeout, unsignedint max_attempts)
__releases(&ps2dev->serio->lock) __acquires(&ps2dev->serio->lock)
{ int attempt = 0; int error;
lockdep_assert_held(&ps2dev->serio->lock);
do {
ps2dev->nak = 1;
ps2dev->flags |= PS2_FLAG_ACK;
serio_continue_rx(ps2dev->serio);
error = serio_write(ps2dev->serio, byte); if (error)
dev_dbg(&ps2dev->serio->dev, "failed to write %#02x: %d\n", byte, error); else
wait_event_timeout(ps2dev->wait,
!(ps2dev->flags & PS2_FLAG_ACK),
msecs_to_jiffies(timeout));
serio_pause_rx(ps2dev->serio);
} while (ps2dev->nak == PS2_RET_NAK && ++attempt < max_attempts);
ps2dev->flags &= ~PS2_FLAG_ACK;
if (!error) { switch (ps2dev->nak) { case 0: break; case PS2_RET_NAK:
error = -EAGAIN; break; case PS2_RET_ERR:
error = -EPROTO; break; default:
error = -EIO; break;
}
}
/** * ps2_sendbyte - sends a byte to the device and wait for acknowledgement * @ps2dev: a PS/2 device to send the data to * @byte: data to be sent to the device * @timeout: timeout for sending the data and receiving an acknowledge * * The function doesn't handle retransmission, the caller is expected to handle * it when needed. * * ps2_sendbyte() can only be called from a process context.
*/ int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsignedint timeout)
{ int retval;
/** * ps2_begin_command - mark beginning of execution of a complex command * @ps2dev: a PS/2 device executing the command * * Serializes a complex/compound command. Once command is finished * ps2_end_command() should be called.
*/ void ps2_begin_command(struct ps2dev *ps2dev)
{ struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
/** * ps2_end_command - mark end of execution of a complex command * @ps2dev: a PS/2 device executing the command
*/ void ps2_end_command(struct ps2dev *ps2dev)
{ struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
/** * ps2_drain - waits for device to transmit requested number of bytes * and discards them * @ps2dev: the PS/2 device that should be drained * @maxbytes: maximum number of bytes to be drained * @timeout: time to drain the device
*/ void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsignedint timeout)
{ if (maxbytes > sizeof(ps2dev->cmdbuf)) {
WARN_ON(1);
maxbytes = sizeof(ps2dev->cmdbuf);
}
/* * ps2_adjust_timeout() is called after receiving 1st byte of command * response and tries to reduce remaining timeout to speed up command * completion.
*/ staticint ps2_adjust_timeout(struct ps2dev *ps2dev, unsignedint command, unsignedint timeout)
{ switch (command) { case PS2_CMD_RESET_BAT: /* * Device has sent the first response byte after * reset command, reset is thus done, so we can * shorten the timeout. * The next byte will come soon (keyboard) or not * at all (mouse).
*/ if (timeout > msecs_to_jiffies(100))
timeout = msecs_to_jiffies(100); break;
case PS2_CMD_GETID: /* * Microsoft Natural Elite keyboard responds to * the GET ID command as it were a mouse, with * a single byte. Fail the command so atkbd will * use alternative probe to detect it.
*/ if (ps2dev->cmdbuf[1] == 0xaa) {
scoped_guard(serio_pause_rx, ps2dev->serio)
ps2dev->flags = 0;
timeout = 0;
}
/* * If device behind the port is not a keyboard there * won't be 2nd byte of ID response.
*/ if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
scoped_guard(serio_pause_rx, ps2dev->serio)
ps2dev->flags = ps2dev->cmdcnt = 0;
timeout = 0;
} break;
default: break;
}
return timeout;
}
/** * __ps2_command - send a command to PS/2 device * @ps2dev: the PS/2 device that should execute the command * @param: a buffer containing parameters to be sent along with the command, * or place where the results of the command execution will be deposited, * or both * @command: command word that encodes the command itself, as well as number of * additional parameter bytes that should be sent to the device and expected * length of the command response * * Not serialized. Callers should use ps2_begin_command() and ps2_end_command() * to ensure proper serialization for complex commands.
*/ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsignedint command)
{ unsignedint timeout; unsignedint send = (command >> 12) & 0xf; unsignedint receive = (command >> 8) & 0xf; int rc; int i;
u8 send_param[16];
if (receive > sizeof(ps2dev->cmdbuf)) {
WARN_ON(1); return -EINVAL;
}
if (send && !param) {
WARN_ON(1); return -EINVAL;
}
memcpy(send_param, param, send);
/* * Not using guard notation because we need to break critical * section below while waiting for the response.
*/
serio_pause_rx(ps2dev->serio);
ps2dev->cmdcnt = receive;
switch (command) { case PS2_CMD_GETID: /* * Some mice do not ACK the "get ID" command, prepare to * handle this.
*/
ps2dev->flags = PS2_FLAG_WAITID; break;
case PS2_CMD_SETLEDS: case PS2_CMD_EX_SETLEDS: case PS2_CMD_SETREP:
ps2dev->flags = PS2_FLAG_PASS_NOACK; break;
default:
ps2dev->flags = 0; break;
}
if (receive) { /* Indicate that we expect response to the command. */
ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1; if (param) for (i = 0; i < receive; i++)
ps2dev->cmdbuf[(receive - 1) - i] = param[i];
}
/* * Some devices (Synaptics) perform the reset before * ACKing the reset command, and so it can take a long * time before the ACK arrives.
*/
timeout = command == PS2_CMD_RESET_BAT ? 1000 : 200;
/* * ps_command() handles resends itself, so do not leak -EAGAIN * to the callers.
*/ return rc != -EAGAIN ? rc : -EPROTO;
}
EXPORT_SYMBOL(__ps2_command);
/** * ps2_command - send a command to PS/2 device * @ps2dev: the PS/2 device that should execute the command * @param: a buffer containing parameters to be sent along with the command, * or place where the results of the command execution will be deposited, * or both * @command: command word that encodes the command itself, as well as number of * additional parameter bytes that should be sent to the device and expected * length of the command response * * Note: ps2_command() serializes the command execution so that only one * command can be executed at a time for either individual port or the entire * 8042 controller.
*/ int ps2_command(struct ps2dev *ps2dev, u8 *param, unsignedint command)
{ int rc;
/** * ps2_sliced_command - sends an extended PS/2 command to a mouse * @ps2dev: the PS/2 device that should execute the command * @command: command byte * * The command is sent using "sliced" syntax understood by advanced devices, * such as Logitech or Synaptics touchpads. The command is encoded as: * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu * is the command.
*/ int ps2_sliced_command(struct ps2dev *ps2dev, u8 command)
{ int i; int retval;
ps2_begin_command(ps2dev);
retval = __ps2_command(ps2dev, NULL, PS2_CMD_SETSCALE11); if (retval) goto out;
for (i = 6; i >= 0; i -= 2) {
u8 d = (command >> i) & 3;
retval = __ps2_command(ps2dev, &d, PS2_CMD_SETRES); if (retval) break;
}
/* * ps2_handle_response() stores device's response to a command and notifies * the process waiting for completion of the command. Note that there is a * distinction between waiting for the first byte of the response, and * waiting for subsequent bytes. It is done so that callers could shorten * timeouts once first byte of response is received.
*/ staticvoid ps2_handle_response(struct ps2dev *ps2dev, u8 data)
{ if (ps2dev->cmdcnt)
ps2dev->cmdbuf[--ps2dev->cmdcnt] = data;
if (ps2dev->flags & PS2_FLAG_CMD1) {
ps2dev->flags &= ~PS2_FLAG_CMD1; if (ps2dev->cmdcnt)
wake_up(&ps2dev->wait);
}
if (!ps2dev->cmdcnt) {
ps2dev->flags &= ~PS2_FLAG_CMD;
wake_up(&ps2dev->wait);
}
}
/* * ps2_handle_ack() processes ACK/NAK of a command from a PS/2 device, * possibly applying workarounds for mice not acknowledging the "get ID" * command.
*/ staticvoid ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
{ switch (data) { case PS2_RET_ACK:
ps2dev->nak = 0; break;
case PS2_RET_NAK:
ps2dev->flags |= PS2_FLAG_NAK;
ps2dev->nak = PS2_RET_NAK; break;
case PS2_RET_ERR: if (ps2dev->flags & PS2_FLAG_NAK) {
ps2dev->flags &= ~PS2_FLAG_NAK;
ps2dev->nak = PS2_RET_ERR; break;
}
fallthrough;
/* * 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 (ps2dev->flags & PS2_FLAG_WAITID) {
ps2dev->nak = 0; break;
}
fallthrough; default: /* * Do not signal errors if we get unexpected reply while * waiting for an ACK to the initial (first) command byte: * the device might not be quiesced yet and continue * delivering data. For certain commands (such as set leds and * set repeat rate) that can be used during normal device * operation, we even pass this data byte to the normal receive * handler. * Note that we reset PS2_FLAG_WAITID flag, so the workaround * for mice not acknowledging the Get ID command only triggers * on the 1st byte; if device spews data we really want to see * a real ACK from it.
*/
dev_dbg(&ps2dev->serio->dev, "unexpected %#02x\n", data); if (ps2dev->flags & PS2_FLAG_PASS_NOACK)
ps2dev->receive_handler(ps2dev, data);
ps2dev->flags &= ~(PS2_FLAG_WAITID | PS2_FLAG_PASS_NOACK); return;
}
if (!ps2dev->nak)
ps2dev->flags &= ~PS2_FLAG_NAK;
ps2dev->flags &= ~PS2_FLAG_ACK;
if (!ps2dev->nak && data != PS2_RET_ACK)
ps2_handle_response(ps2dev, data); else
wake_up(&ps2dev->wait);
}
/* * Clears state of PS/2 device after communication error by resetting majority * of flags and waking up waiters, if any.
*/ staticvoid ps2_cleanup(struct ps2dev *ps2dev)
{ unsignedlong old_flags = ps2dev->flags;
/* reset all flags except last nak */
ps2dev->flags &= PS2_FLAG_NAK;
if (old_flags & PS2_FLAG_ACK)
ps2dev->nak = 1;
if (old_flags & (PS2_FLAG_ACK | PS2_FLAG_CMD))
wake_up(&ps2dev->wait);
}
/** * ps2_interrupt - common interrupt handler for PS/2 devices * @serio: serio port for the device * @data: a data byte received from the device * @flags: flags such as %SERIO_PARITY or %SERIO_TIMEOUT indicating state of * the data transfer * * ps2_interrupt() invokes pre-receive handler, optionally handles command * acknowledgement and response from the device, and finally passes the data * to the main protocol handler for future processing.
*/
irqreturn_t ps2_interrupt(struct serio *serio, u8 data, unsignedint flags) { struct ps2dev *ps2dev = serio_get_drvdata(serio); enum ps2_disposition rc;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.