// Support for handling the PS/2 mouse/keyboard ports.
//
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
-// Based on code Copyright (c) 1999-2004 Vojtech Pavlik
+// Several ideas taken from code Copyright (c) 1999-2004 Vojtech Pavlik
//
-// This file may be distributed under the terms of the GNU GPLv3 license.
+// This file may be distributed under the terms of the GNU LGPLv3 license.
#include "ioport.h" // inb
#include "util.h" // dprintf
}
udelay(50);
u8 data = inb(PORT_PS2_DATA);
- dprintf(7, "i8042 flushed %x\n", data);
+ dprintf(7, "i8042 flushed %x (status=%x)\n", data, status);
}
irq_restore(flags);
{
u64 end = calc_future_tsc(timeout);
for (;;) {
- if (rdtscll() >= end) {
+ if (check_time(end)) {
dprintf(1, "ps2_recvbyte timeout\n");
return -1;
}
u8 data = inb(PORT_PS2_DATA);
dprintf(7, "ps2 read %x\n", data);
- if ((!!(status & I8042_STR_AUXDATA) != aux)
- || (needack && data != PS2_RET_ACK)) {
- // This data not for us - XXX - just discard it for now.
- dprintf(1, "Discarding ps2 data %x\n", data);
- continue;
+ if (!!(status & I8042_STR_AUXDATA) == aux) {
+ if (!needack)
+ return data;
+ if (data == PS2_RET_ACK)
+ return data;
+ if (data == PS2_RET_NAK) {
+ dprintf(1, "Got ps2 nak (status=%x); continuing\n", status);
+ return data;
+ }
}
- return data;
+ // This data not for us - XXX - just discard it for now.
+ dprintf(1, "Discarding ps2 data %x (status=%x)\n", data, status);
}
}
static int
-ps2_sendbyte(int aux, u8 command)
+ps2_sendbyte(int aux, u8 command, int timeout)
{
dprintf(7, "ps2_sendbyte aux=%d cmd=%x\n", aux, command);
int ret;
return ret;
// Read ack.
- ret = ps2_recvbyte(aux, 1, 200);
+ ret = ps2_recvbyte(aux, 1, timeout);
if (ret < 0)
return ret;
if (ret)
return ret;
- // Send command.
- ret = ps2_sendbyte(aux, command);
- if (ret)
- goto fail;
+ if (command == ATKBD_CMD_RESET_BAT) {
+ // Reset is special wrt timeouts.
- // Send parameters (if any).
- int i;
- for (i = 0; i < send; i++) {
- ret = ps2_sendbyte(aux, param[i]);
+ // Send command.
+ ret = ps2_sendbyte(aux, command, 1000);
if (ret)
goto fail;
- }
- // Receive parameters (if any).
- for (i = 0; i < receive; i++) {
- u8 data = ps2_recvbyte(aux, 0, 200);
- if (data < 0) {
- // On a receive timeout, return the item number that the
- // transfer failed on.
- ret = i + 1;
+ // Receive parameters.
+ ret = ps2_recvbyte(aux, 0, 4000);
+ if (ret < 0)
+ goto fail;
+ param[0] = ret;
+ ret = ps2_recvbyte(aux, 0, 100);
+ if (ret < 0)
+ // Some devices only respond with one byte on reset.
+ ret = 0;
+ param[1] = ret;
+ } else {
+ // Send command.
+ ret = ps2_sendbyte(aux, command, 200);
+ if (ret)
goto fail;
+
+ // Send parameters (if any).
+ int i;
+ for (i = 0; i < send; i++) {
+ ret = ps2_sendbyte(aux, param[i], 200);
+ if (ret)
+ goto fail;
+ }
+
+ // Receive parameters (if any).
+ for (i = 0; i < receive; i++) {
+ ret = ps2_recvbyte(aux, 0, 500);
+ if (ret < 0)
+ goto fail;
+ param[i] = ret;
}
- param[i] = data;
}
+ ret = 0;
+
fail:
// Restore interrupts and keyboard/mouse.
ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr);
dprintf(7, "kbd_command cmd=%x\n", command);
int ret = ps2_command(0, command, param);
if (ret)
- dprintf(2, "keyboard command %x failed (ret=%d)\n", command, ret);
+ dprintf(2, "keyboard command %x failed\n", command);
return ret;
}
dprintf(7, "aux_command cmd=%x\n", command);
int ret = ps2_command(1, command, param);
if (ret)
- dprintf(2, "mouse command %x failed (ret=%d)\n", command, ret);
+ dprintf(2, "mouse command %x failed\n", command);
return ret;
}