aboutsummaryrefslogtreecommitdiff
path: root/src/kbd.c
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2008-07-20 10:08:59 -0400
committerKevin O'Connor <kevin@koconnor.net>2008-07-20 10:08:59 -0400
commit3b897198775966fbcf459bc3284c92358ee9154f (patch)
tree304b7d03dfc173d9ebea9a3f06f1d61d075db491 /src/kbd.c
parent65e63420e588f72ac2849f09d43483f8097e24fe (diff)
downloadseabios-hppa-3b897198775966fbcf459bc3284c92358ee9154f.zip
seabios-hppa-3b897198775966fbcf459bc3284c92358ee9154f.tar.gz
seabios-hppa-3b897198775966fbcf459bc3284c92358ee9154f.tar.bz2
Rewrite ps2 port (keyboard/mouse) handling.
Use command sending code for communicating with the ps2 port.
Diffstat (limited to 'src/kbd.c')
-rw-r--r--src/kbd.c233
1 files changed, 70 insertions, 163 deletions
diff --git a/src/kbd.c b/src/kbd.c
index d63c8c3..b47b3ca 100644
--- a/src/kbd.c
+++ b/src/kbd.c
@@ -10,142 +10,73 @@
#include "config.h" // CONFIG_*
#include "pic.h" // eoi_pic1
#include "bregs.h" // struct bregs
+#include "ps2port.h" // i8042_flush
-//--------------------------------------------------------------------------
-// keyboard_panic
-//--------------------------------------------------------------------------
-static void
-keyboard_panic(u16 status)
-{
- // If you're getting a 993 keyboard panic here,
- // please see the comment in keyboard_init
-
- BX_PANIC("Keyboard error:%u\n",status);
-}
-
-static void
-kbd_flush(u8 code)
-{
- u16 max = 0xffff;
- while ((inb(PORT_PS2_STATUS) & 0x02) && (--max > 0))
- outb(code, PORT_DIAG);
- if (!max && code != 0xff)
- keyboard_panic(code);
-}
-
-static void
-kbd_waitdata(u8 code)
-{
- u16 max = 0xffff;
- while ( ((inb(PORT_PS2_STATUS) & 0x01) == 0) && (--max>0) )
- outb(code, PORT_DIAG);
- if (!max)
- keyboard_panic(code);
-}
-
-//--------------------------------------------------------------------------
-// keyboard_init
-//--------------------------------------------------------------------------
-// this file is based on LinuxBIOS implementation of keyboard.c
static void
keyboard_init()
{
if (CONFIG_COREBOOT)
// Coreboot already does low-level keyboard init.
- return;
-
- /* ------------------- Flush buffers ------------------------*/
- /* Wait until buffer is empty */
- kbd_flush(0xff);
+ goto end;
/* flush incoming keys */
- u16 max=0x2000;
- while (--max > 0) {
- outb(0x00, PORT_DIAG);
- if (inb(PORT_PS2_STATUS) & 0x01) {
- inb(PORT_PS2_DATA);
- max = 0x2000;
- }
- }
-
- // Due to timer issues, and if the IPS setting is > 15000000,
- // the incoming keys might not be flushed here. That will
- // cause a panic a few lines below. See sourceforge bug report :
- // [ 642031 ] FATAL: Keyboard RESET error:993
-
- /* ------------------- controller side ----------------------*/
- /* send cmd = 0xAA, self test 8042 */
- outb(0xaa, PORT_PS2_STATUS);
-
- kbd_flush(0x00);
- kbd_waitdata(0x01);
-
- /* read self-test result, 0x55 should be returned from 0x60 */
- if (inb(PORT_PS2_DATA) != 0x55)
- keyboard_panic(991);
+ int ret = i8042_flush();
+ if (ret)
+ return;
- /* send cmd = 0xAB, keyboard interface test */
- outb(0xab, PORT_PS2_STATUS);
+ // Controller self-test.
+ u8 param[2];
+ ret = i8042_command(I8042_CMD_CTL_TEST, param);
+ if (ret)
+ return;
+ if (param[0] != 0x55) {
+ dprintf(1, "i8042 self test failed (got %x not 0x55\n", param[0]);
+ return;
+ }
- kbd_flush(0x10);
- kbd_waitdata(0x11);
+ // Controller keyboard test.
+ ret = i8042_command(I8042_CMD_KBD_TEST, param);
+ if (ret)
+ return;
+ if (param[0] != 0x00) {
+ dprintf(1, "i8042 keyboard test failed (got %x not 0x00\n", param[0]);
+ return;
+ }
- /* read keyboard interface test result, */
- /* 0x00 should be returned form 0x60 */
- if (inb(PORT_PS2_DATA) != 0x00)
- keyboard_panic(992);
+ // Enable keyboard and mouse ports.
+ ret = i8042_command(I8042_CMD_KBD_ENABLE, NULL);
+ if (ret)
+ return;
+ ret = i8042_command(I8042_CMD_AUX_ENABLE, NULL);
+ if (ret)
+ return;
- /* Enable Keyboard clock */
- outb(0xae, PORT_PS2_STATUS);
- outb(0xa8, PORT_PS2_STATUS);
/* ------------------- keyboard side ------------------------*/
- /* reset kerboard and self test (keyboard side) */
- outb(0xff, PORT_PS2_DATA);
-
- kbd_flush(0x20);
- kbd_waitdata(0x21);
-
- /* keyboard should return ACK */
- if (inb(PORT_PS2_DATA) != 0xfa)
- keyboard_panic(993);
-
- kbd_waitdata(0x31);
-
- if (inb(PORT_PS2_DATA) != 0xaa)
- keyboard_panic(994);
+ /* reset keyboard and self test (keyboard side) */
+ ret = kbd_command(ATKBD_CMD_RESET_BAT, param);
+ if (ret)
+ return;
+ if (param[0] != 0xaa) {
+ dprintf(1, "keyboard self test failed (got %x not 0xaa\n", param[0]);
+ return;
+ }
/* Disable keyboard */
- outb(0xf5, PORT_PS2_DATA);
-
- kbd_flush(0x40);
- kbd_waitdata(0x41);
-
- /* keyboard should return ACK */
- if (inb(PORT_PS2_DATA) != 0xfa)
- keyboard_panic(995);
-
- /* Write Keyboard Mode */
- outb(0x60, PORT_PS2_STATUS);
-
- kbd_flush(0x50);
-
- /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
- outb(0x61, PORT_PS2_DATA);
+ ret = kbd_command(ATKBD_CMD_RESET_DIS, NULL);
+ if (ret)
+ return;
- kbd_flush(0x60);
+end:
+ // Keyboard Mode: scan code convert, disable mouse, enable IRQ 1
+ SET_EBDA(ps2ctr, I8042_CTR_AUXDIS | I8042_CTR_XLATE | I8042_CTR_KBDINT);
/* Enable keyboard */
- outb(0xf4, PORT_PS2_DATA);
-
- kbd_flush(0x70);
- kbd_waitdata(0x71);
-
- /* keyboard should return ACK */
- if (inb(PORT_PS2_DATA) != 0xfa)
- keyboard_panic(996);
+ ret = kbd_command(ATKBD_CMD_ENABLE, NULL);
+ if (ret)
+ return;
- outb(0x77, PORT_DIAG);
+ dprintf(1, "keyboard initialized\n");
}
void
@@ -286,29 +217,13 @@ handle_1609(struct bregs *regs)
static void
handle_160a(struct bregs *regs)
{
- outb(0xf2, PORT_PS2_DATA);
- /* Wait for data */
- u16 max=0xffff;
- while ( ((inb(PORT_PS2_STATUS) & 0x01) == 0) && (--max>0) )
- outb(0x00, PORT_DIAG);
- if (!max)
- return;
- if (inb(PORT_PS2_DATA) != 0xfa) {
+ u8 param[2];
+ int ret = kbd_command(ATKBD_CMD_GETID, param);
+ if (ret) {
regs->bx = 0;
return;
}
- u16 kbd_code = 0;
- u8 count = 2;
- do {
- max=0xffff;
- while ( ((inb(PORT_PS2_STATUS) & 0x01) == 0) && (--max>0) )
- outb(0x00, PORT_DIAG);
- if (max>0x0) {
- kbd_code >>= 8;
- kbd_code |= (inb(PORT_PS2_DATA) << 8);
- }
- } while (--count>0);
- regs->bx = kbd_code;
+ regs->bx = (param[1] << 8) | param[0];
}
// read MF-II keyboard input
@@ -372,23 +287,18 @@ handle_16a2(struct bregs *regs)
static void
set_leds()
{
- u8 shift_flags = GET_BDA(kbd_flag0);
- u8 led_flags = GET_BDA(kbd_led);
- if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) == 0)
+ u8 shift_flags = (GET_BDA(kbd_flag0) >> 4) & 0x07;
+ u8 kbd_led = GET_BDA(kbd_led);
+ u8 led_flags = kbd_led & 0x07;
+ if (shift_flags == led_flags)
return;
- outb(0xed, PORT_PS2_DATA);
- while ((inb(PORT_PS2_STATUS) & 0x01) == 0)
- outb(0x21, PORT_DIAG);
- if (inb(PORT_PS2_DATA) == 0xfa) {
- led_flags &= 0xf8;
- led_flags |= (shift_flags >> 4) & 0x07;
- outb(led_flags & 0x07, PORT_PS2_DATA);
- while ((inb(PORT_PS2_STATUS) & 0x01) == 0)
- outb(0x21, PORT_DIAG);
- inb(PORT_PS2_DATA);
- SET_BDA(kbd_led, led_flags);
- }
+ int ret = kbd_command(ATKBD_CMD_SETLEDS, &shift_flags);
+ if (ret)
+ // Error
+ return;
+ kbd_led = (kbd_led & ~0x07) | shift_flags;
+ SET_BDA(kbd_led, kbd_led);
}
// INT 16h Keyboard Service Entry Point
@@ -397,10 +307,10 @@ handle_16(struct bregs *regs)
{
debug_enter(regs, DEBUG_HDL_16);
- set_leds();
-
irq_enable();
+ set_leds();
+
switch (regs->ah) {
case 0x00: handle_1600(regs); break;
case 0x01: handle_1601(regs); break;
@@ -707,15 +617,14 @@ handle_09()
{
debug_isr(DEBUG_ISR_09);
- // disable keyboard
- outb(0xad, PORT_PS2_STATUS);
-
- // Make sure there really is a keyboard irq pending.
- if (! (get_pic1_isr() & PIC1_IRQ1))
- goto done;
-
// read key from keyboard controller
+ u8 v = inb(PORT_PS2_STATUS);
+ if ((v & 0x21) != 0x01) {
+ dprintf(1, "int09 but no keyboard data.\n");
+ goto done;
+ }
u8 key = inb(PORT_PS2_DATA);
+
irq_enable();
if (CONFIG_KBD_CALL_INT15_4F) {
// allow for keyboard intercept
@@ -732,9 +641,7 @@ handle_09()
process_key(key);
irq_disable();
- eoi_pic1();
done:
- // enable keyboard
- outb(0xae, PORT_PS2_STATUS);
+ eoi_pic1();
}