summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--src/biosvar.h2
-rw-r--r--src/kbd.c233
-rw-r--r--src/mouse.c256
-rw-r--r--src/ps2port.c240
-rw-r--r--src/ps2port.h62
6 files changed, 459 insertions, 338 deletions
diff --git a/Makefile b/Makefile
index c7ab73a..abe60a7 100644
--- a/Makefile
+++ b/Makefile
@@ -9,8 +9,8 @@ OUT=out/
# Source files
SRCBOTH=output.c util.c floppy.c ata.c system.c mouse.c kbd.c pci.c \
- serial.c clock.c pic.c cdrom.c
-SRC16=$(SRCBOTH) disk.c apm.c pcibios.c
+ serial.c clock.c pic.c cdrom.c ps2port.c
+SRC16=$(SRCBOTH) disk.c apm.c pcibios.c vgahooks.c
SRC32=$(SRCBOTH) post.c shadow.c post_menu.c memmap.c coreboot.c boot.c \
acpi.c pirtable.c smm.c smpdetect.c mptable.c smbios.c pciinit.c
TABLESRC=font.c cbt.c floppy_dbt.c
diff --git a/src/biosvar.h b/src/biosvar.h
index 808f83b..3d03cec 100644
--- a/src/biosvar.h
+++ b/src/biosvar.h
@@ -258,6 +258,8 @@ struct extended_bios_data_area_s {
// 0x5d
u8 other2[0xC4];
+ u8 ps2ctr;
+
// Physical memory available.
u32 ram_size;
u16 e820_count;
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();
}
diff --git a/src/mouse.c b/src/mouse.c
index cb471db..22d0148 100644
--- a/src/mouse.c
+++ b/src/mouse.c
@@ -9,8 +9,7 @@
#include "util.h" // debug_isr
#include "pic.h" // unmask_pic2
#include "bregs.h" // struct bregs
-
-static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
+#include "ps2port.h" // aux_command
void
mouse_setup()
@@ -24,75 +23,6 @@ mouse_setup()
unmask_pic2(PIC2_IRQ12);
}
-static void
-set_kbd_command_byte(u8 command_byte)
-{
- if (inb(PORT_PS2_STATUS) & 0x02)
- BX_PANIC(panic_msg_keyb_buffer_full, "setkbdcomm");
- outb(0xD4, PORT_PS2_STATUS);
-
- outb(0x60, PORT_PS2_STATUS); // write command byte
- outb(command_byte, PORT_PS2_DATA);
-}
-
-static u8
-inhibit_mouse_int_and_events()
-{
- // Turn off IRQ generation and aux data line
- if (inb(PORT_PS2_STATUS) & 0x02)
- BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
- outb(0x20, PORT_PS2_STATUS); // get command byte
- while ((inb(PORT_PS2_STATUS) & 0x01) != 0x01)
- ;
- u8 prev_command_byte = inb(PORT_PS2_DATA);
- u8 command_byte = prev_command_byte;
- //while ( (inb(PORT_PS2_STATUS) & 0x02) );
- if ( inb(PORT_PS2_STATUS) & 0x02 )
- BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
- command_byte &= 0xfd; // turn off IRQ 12 generation
- command_byte |= 0x20; // disable mouse serial clock line
- outb(0x60, PORT_PS2_STATUS); // write command byte
- outb(command_byte, PORT_PS2_DATA);
- return prev_command_byte;
-}
-
-static void
-enable_mouse_int_and_events()
-{
- // Turn on IRQ generation and aux data line
- if ( inb(PORT_PS2_STATUS) & 0x02 )
- BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
- outb(0x20, PORT_PS2_STATUS); // get command byte
- while ((inb(PORT_PS2_STATUS) & 0x01) != 0x01)
- ;
- u8 command_byte = inb(PORT_PS2_DATA);
- //while ( (inb(PORT_PS2_STATUS) & 0x02) );
- if (inb(PORT_PS2_STATUS) & 0x02)
- BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
- command_byte |= 0x02; // turn on IRQ 12 generation
- command_byte &= 0xdf; // enable mouse serial clock line
- outb(0x60, PORT_PS2_STATUS); // write command byte
- outb(command_byte, PORT_PS2_DATA);
-}
-
-static void
-send_to_mouse_ctrl(u8 sendbyte)
-{
- // wait for chance to write to ctrl
- if (inb(PORT_PS2_STATUS) & 0x02)
- BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
- outb(0xD4, PORT_PS2_STATUS);
- outb(sendbyte, PORT_PS2_DATA);
-}
-
-static void
-get_mouse_data(u8 *data)
-{
- while ((inb(PORT_PS2_STATUS) & 0x21) != 0x21)
- ;
- *data = inb(PORT_PS2_DATA);
-}
-
#define RET_SUCCESS 0x00
#define RET_EINVFUNCTION 0x01
#define RET_EINVINPUT 0x02
@@ -100,39 +30,48 @@ get_mouse_data(u8 *data)
#define RET_ENEEDRESEND 0x04
#define RET_ENOHANDLER 0x05
+static int
+disable_mouse()
+{
+ u8 ps2ctr = GET_EBDA(ps2ctr);
+ ps2ctr |= I8042_CTR_AUXDIS;
+ ps2ctr &= ~I8042_CTR_AUXINT;
+ SET_EBDA(ps2ctr, ps2ctr);
+
+ return aux_command(PSMOUSE_CMD_DISABLE, NULL);
+}
+
// Disable Mouse
static void
mouse_15c20000(struct bregs *regs)
{
- inhibit_mouse_int_and_events(); // disable IRQ12 and packets
- send_to_mouse_ctrl(0xF5); // disable mouse command
- u8 mouse_data1;
- get_mouse_data(&mouse_data1);
- set_code_success(regs);
+ int ret = disable_mouse();
+ if (ret)
+ set_code_fail(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
}
-#define BX_DEBUG_INT15(args...)
-
// Enable Mouse
static void
mouse_15c20001(struct bregs *regs)
{
u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
if ((mouse_flags_2 & 0x80) == 0) {
- BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
set_code_fail(regs, RET_ENOHANDLER);
return;
}
- inhibit_mouse_int_and_events(); // disable IRQ12 and packets
- send_to_mouse_ctrl(0xF4); // enable mouse command
- u8 mouse_data1;
- get_mouse_data(&mouse_data1);
- if (mouse_data1 == 0xFA) {
- enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
+
+ u8 ps2ctr = GET_EBDA(ps2ctr);
+ ps2ctr &= ~I8042_CTR_AUXDIS;
+ ps2ctr |= I8042_CTR_AUXINT;
+ SET_EBDA(ps2ctr, ps2ctr);
+
+ int ret = aux_command(PSMOUSE_CMD_ENABLE, NULL);
+ if (ret)
+ set_code_fail(regs, RET_ENEEDRESEND);
+ else
set_code_success(regs);
- return;
- }
- set_code_fail(regs, RET_ENEEDRESEND);
}
static void
@@ -156,24 +95,14 @@ mouse_15c200(struct bregs *regs)
static void
mouse_15c201(struct bregs *regs)
{
- inhibit_mouse_int_and_events(); // disable IRQ12 and packets
- send_to_mouse_ctrl(0xFF); // reset mouse command
- u8 mouse_data1, mouse_data2, mouse_data3;
- get_mouse_data(&mouse_data3);
- // if no mouse attached, it will return RESEND
- if (mouse_data3 == 0xfe) {
+ u8 param[2];
+ int ret = aux_command(PSMOUSE_CMD_RESET_BAT, param);
+ if (ret) {
set_code_fail(regs, RET_ENEEDRESEND);
return;
}
- if (mouse_data3 != 0xfa)
- BX_PANIC("Mouse reset returned %02x (should be ack)\n"
- , (unsigned)mouse_data3);
- get_mouse_data(&mouse_data1);
- get_mouse_data(&mouse_data2);
- // turn IRQ12 and packet generation on
- enable_mouse_int_and_events();
- regs->bl = mouse_data1;
- regs->bh = mouse_data2;
+ regs->bl = param[0];
+ regs->bh = param[1];
set_code_success(regs);
}
@@ -181,19 +110,17 @@ mouse_15c201(struct bregs *regs)
static void
mouse_15c202(struct bregs *regs)
{
- if (regs->bh >= 7) {
- set_code_fail(regs, RET_EUNSUPPORTED);
+ static u8 sample_rates[7] = {10, 20, 40, 60, 80, 100, 200};
+ if (regs->bh >= ARRAY_SIZE(sample_rates)) {
+ set_code_fail(regs, RET_EINVINPUT);
return;
}
- u8 mouse_data1 = regs->bh * 20;
- if (!mouse_data1)
- mouse_data1 = 10;
- send_to_mouse_ctrl(0xF3); // set sample rate command
- u8 mouse_data2;
- get_mouse_data(&mouse_data2);
- send_to_mouse_ctrl(mouse_data1);
- get_mouse_data(&mouse_data2);
- set_code_success(regs);
+ u8 mouse_data1 = GET_VAR(CS, sample_rates[regs->bh]);
+ int ret = aux_command(PSMOUSE_CMD_SETRATE, &mouse_data1);
+ if (ret)
+ set_code_fail(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
}
// Set Resolution
@@ -205,38 +132,29 @@ mouse_15c203(struct bregs *regs)
// 1 = 50 dpi, 2 counts per millimeter
// 2 = 100 dpi, 4 counts per millimeter
// 3 = 200 dpi, 8 counts per millimeter
- u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
if (regs->bh >= 4) {
- set_code_fail(regs, RET_EUNSUPPORTED);
- goto done;
+ set_code_fail(regs, RET_EINVINPUT);
+ return;
}
- send_to_mouse_ctrl(0xE8); // set resolution command
- u8 mouse_data1;
- get_mouse_data(&mouse_data1);
- if (mouse_data1 != 0xfa)
- BX_PANIC("Mouse status returned %02x (should be ack)\n"
- , (unsigned)mouse_data1);
- send_to_mouse_ctrl(regs->bh);
- get_mouse_data(&mouse_data1);
- if (mouse_data1 != 0xfa)
- BX_PANIC("Mouse status returned %02x (should be ack)\n"
- , (unsigned)mouse_data1);
- set_code_success(regs);
-
-done:
- set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
+ u8 param = regs->bh;
+ int ret = aux_command(PSMOUSE_CMD_SETRES, &param);
+ if (ret)
+ set_code_fail(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
}
// Get Device ID
static void
mouse_15c204(struct bregs *regs)
{
- inhibit_mouse_int_and_events(); // disable IRQ12 and packets
- send_to_mouse_ctrl(0xF2); // get mouse ID command
- u8 mouse_data1, mouse_data2;
- get_mouse_data(&mouse_data1);
- get_mouse_data(&mouse_data2);
- regs->bh = mouse_data2;
+ u8 param[2];
+ int ret = aux_command(PSMOUSE_CMD_GETID, param);
+ if (ret) {
+ set_code_fail(regs, RET_ENEEDRESEND);
+ return;
+ }
+ regs->bh = param[0];
set_code_success(regs);
}
@@ -259,55 +177,44 @@ mouse_15c205(struct bregs *regs)
static void
mouse_15c20600(struct bregs *regs)
{
- u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
- send_to_mouse_ctrl(0xE9); // get mouse info command
- u8 mouse_data1, mouse_data2, mouse_data3;
- get_mouse_data(&mouse_data1);
- if (mouse_data1 != 0xfa)
- BX_PANIC("Mouse status returned %02x (should be ack)\n"
- , (unsigned)mouse_data1);
- get_mouse_data(&mouse_data1);
- get_mouse_data(&mouse_data2);
- get_mouse_data(&mouse_data3);
- regs->bl = mouse_data1;
- regs->cl = mouse_data2;
- regs->dl = mouse_data3;
+ u8 param[3];
+ int ret = aux_command(PSMOUSE_CMD_GETINFO, param);
+ if (ret) {
+ set_code_fail(regs, RET_ENEEDRESEND);
+ return;
+ }
+ regs->bl = param[0];
+ regs->cl = param[1];
+ regs->dl = param[2];
set_code_success(regs);
- set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
-}
-
-static void
-set_scaling(struct bregs *regs, u8 cmd)
-{
- u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
- send_to_mouse_ctrl(0xE6);
- u8 mouse_data1;
- get_mouse_data(&mouse_data1);
- if (mouse_data1 != 0xFA)
- set_code_fail(regs, RET_EUNSUPPORTED);
- else
- set_code_success(regs);
- set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
}
// Set Scaling Factor to 1:1
static void
mouse_15c20601(struct bregs *regs)
{
- set_scaling(regs, 0xE6);
+ int ret = aux_command(PSMOUSE_CMD_SETSCALE11, NULL);
+ if (ret)
+ set_code_fail(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
}
// Set Scaling Factor to 2:1
static void
mouse_15c20602(struct bregs *regs)
{
- set_scaling(regs, 0xE7);
+ int ret = aux_command(PSMOUSE_CMD_SETSCALE21, NULL);
+ if (ret)
+ set_code_fail(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
}
static void
mouse_15c206XX(struct bregs *regs)
{
- BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", regs->bh);
+ set_code_fail(regs, RET_EINVFUNCTION);
}
// Return Status & Set Scaling Factor...
@@ -327,19 +234,19 @@ static void
mouse_15c207(struct bregs *regs)
{
u32 farptr = (regs->es << 16) | regs->bx;
- SET_EBDA(far_call_pointer, farptr);
u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
if (! farptr) {
/* remove handler */
if ((mouse_flags_2 & 0x80) != 0) {
mouse_flags_2 &= ~0x80;
- inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+ disable_mouse();
}
} else {
/* install handler */
mouse_flags_2 |= 0x80;
}
SET_EBDA(mouse_flag2, mouse_flags_2);
+ SET_EBDA(far_call_pointer, farptr);
set_code_success(regs);
}
@@ -359,6 +266,8 @@ handle_15c2(struct bregs *regs)
return;
}
+ irq_enable();
+
switch (regs->al) {
case 0x00: mouse_15c200(regs); break;
case 0x01: mouse_15c201(regs); break;
@@ -376,9 +285,10 @@ static void
int74_function()
{
u8 v = inb(PORT_PS2_STATUS);
- if ((v & 0x21) != 0x21)
+ if ((v & 0x21) != 0x21) {
+ dprintf(1, "int74 but no mouse data.\n");
return;
-
+ }
v = inb(PORT_PS2_DATA);
u8 mouse_flags_1 = GET_EBDA(mouse_flag1);
diff --git a/src/ps2port.c b/src/ps2port.c
new file mode 100644
index 0000000..f707064
--- /dev/null
+++ b/src/ps2port.c
@@ -0,0 +1,240 @@
+// 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
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "ioport.h" // inb
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "ps2port.h" // kbd_command
+
+
+/****************************************************************
+ * Low level i8042 commands.
+ ****************************************************************/
+
+// Timeout value.
+#define I8042_CTL_TIMEOUT 10000
+
+#define I8042_BUFFER_SIZE 16
+
+static void
+udelay(int usecs)
+{
+ // XXX - implement real udelay
+ outb(0x00, PORT_DIAG);
+}
+
+static int
+i8042_wait_read(void)
+{
+ int i;
+ for (i=0; i<I8042_CTL_TIMEOUT; i++) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (status & I8042_STR_OBF)
+ return 0;
+ udelay(50);
+ }
+ dprintf(1, "i8042 timeout on wait read\n");
+ return -1;
+}
+
+static int
+i8042_wait_write(void)
+{
+ int i;
+ for (i=0; i<I8042_CTL_TIMEOUT; i++) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (! (status & I8042_STR_IBF))
+ return 0;
+ udelay(50);
+ }
+ dprintf(1, "i8042 timeout on wait write\n");
+ return -1;
+}
+
+int
+i8042_flush(void)
+{
+ unsigned long flags = irq_save();
+
+ int i;
+ for (i=0; i<I8042_BUFFER_SIZE; i++) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (! (status & I8042_STR_OBF)) {
+ irq_restore(flags);
+ return 0;
+ }
+ udelay(50);
+ inb(PORT_PS2_DATA);
+ }
+
+ irq_restore(flags);
+ dprintf(1, "i8042 timeout on flush\n");
+ return -1;
+}
+
+static int
+__i8042_command(int command, u8 *param)
+{
+ int receive = (command >> 8) & 0xf;
+ int send = (command >> 12) & 0xf;
+
+ // Send the command.
+ int ret = i8042_wait_write();
+ if (ret)
+ return ret;
+ outb(command, PORT_PS2_STATUS);
+
+ // Send parameters (if any).
+ int i;
+ for (i = 0; i < send; i++) {
+ ret = i8042_wait_write();
+ if (ret)
+ return ret;
+ outb(param[i], PORT_PS2_DATA);
+ }
+
+ // Receive parameters (if any).
+ for (i = 0; i < receive; i++) {
+ ret = i8042_wait_read();
+ if (ret)
+ return ret;
+ param[i] = inb(PORT_PS2_DATA);
+ }
+
+ return 0;
+}
+
+int
+i8042_command(int command, u8 *param)
+{
+ unsigned long flags = irq_save();
+ int ret = __i8042_command(command, param);
+ irq_restore(flags);
+ if (ret)
+ dprintf(2, "i8042 command %x failed\n", command);
+ return ret;
+}
+
+static int
+i8042_kbd_write(u8 c)
+{
+ unsigned long flags = irq_save();
+
+ int ret = i8042_wait_write();
+ if (! ret)
+ outb(c, PORT_PS2_DATA);
+
+ irq_restore(flags);
+
+ return ret;
+}
+
+static int
+i8042_aux_write(u8 c)
+{
+ return i8042_command(I8042_CMD_AUX_SEND, &c);
+}
+
+
+/****************************************************************
+ * Device commands.
+ ****************************************************************/
+
+#define PS2_RET_ACK 0xfa
+#define PS2_RET_NAK 0xfe
+
+static int
+ps2_sendbyte(int aux, u8 command)
+{
+ int ret;
+ if (aux)
+ ret = i8042_aux_write(command);
+ else
+ ret = i8042_kbd_write(command);
+ if (ret)
+ return ret;
+
+ // Read ack.
+ ret = i8042_wait_read();
+ if (ret)
+ return ret;
+ u8 ack = inb(PORT_PS2_DATA);
+ if (ack != PS2_RET_ACK) {
+ dprintf(1, "Missing ack (got %x not %x)\n", ack, PS2_RET_ACK);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+ps2_command(int aux, int command, u8 *param)
+{
+ int ret2;
+ int receive = (command >> 8) & 0xf;
+ int send = (command >> 12) & 0xf;
+
+ // Disable interrupts and keyboard/mouse.
+ u8 ps2ctr = GET_EBDA(ps2ctr);
+ u8 newctr = ps2ctr;
+ if (aux)
+ newctr |= I8042_CTR_KBDDIS;
+ else
+ newctr |= I8042_CTR_AUXDIS;
+ newctr &= ~(I8042_CTR_KBDINT|I8042_CTR_AUXINT);
+ dprintf(6, "i8042 ctr old=%x new=%x\n", ps2ctr, newctr);
+ int ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr);
+ if (ret)
+ return ret;
+
+ // Send command.
+ ret = ps2_sendbyte(aux, command);
+ if (ret)
+ goto fail;
+
+ // Send parameters (if any).
+ int i;
+ for (i = 0; i < send; i++) {
+ ret = ps2_sendbyte(aux, command);
+ if (ret)
+ goto fail;
+ }
+
+ // Receive parameters (if any).
+ for (i = 0; i < receive; i++) {
+ ret = i8042_wait_read();
+ if (ret)
+ goto fail;
+ param[i] = inb(PORT_PS2_DATA);
+ }
+
+fail:
+ // Restore interrupts and keyboard/mouse.
+ ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr);
+ if (ret2)
+ return ret2;
+
+ return ret;
+}
+
+int
+kbd_command(int command, u8 *param)
+{
+ int ret = ps2_command(0, command, param);
+ if (ret)
+ dprintf(2, "keyboard command %x failed\n", command);
+ return ret;
+}
+
+int
+aux_command(int command, u8 *param)
+{
+ int ret = ps2_command(1, command, param);
+ if (ret)
+ dprintf(2, "mouse command %x failed\n", command);
+ return ret;
+}
diff --git a/src/ps2port.h b/src/ps2port.h
new file mode 100644
index 0000000..fa73a06
--- /dev/null
+++ b/src/ps2port.h
@@ -0,0 +1,62 @@
+// Basic ps2 port (keyboard/mouse) command handling.
+#ifndef __PS2PORT_H
+#define __PS2PORT_H
+
+#include "types.h" // u8
+
+// Standard commands.
+#define I8042_CMD_CTL_RCTR 0x0120
+#define I8042_CMD_CTL_WCTR 0x1060
+#define I8042_CMD_CTL_TEST 0x01aa
+
+#define I8042_CMD_KBD_TEST 0x01ab
+#define I8042_CMD_KBD_DISABLE 0x00ad
+#define I8042_CMD_KBD_ENABLE 0x00ae
+
+#define I8042_CMD_AUX_DISABLE 0x00a7
+#define I8042_CMD_AUX_ENABLE 0x00a8
+#define I8042_CMD_AUX_SEND 0x10d4
+
+// Keyboard commands
+#define ATKBD_CMD_SETLEDS 0x10ed
+#define ATKBD_CMD_GETID 0x02f2
+#define ATKBD_CMD_ENABLE 0x00f4
+#define ATKBD_CMD_RESET_DIS 0x00f5
+#define ATKBD_CMD_RESET_BAT 0x01ff
+
+// Mouse commands
+#define PSMOUSE_CMD_SETSCALE11 0x00e6
+#define PSMOUSE_CMD_SETSCALE21 0x00e7
+#define PSMOUSE_CMD_SETRES 0x10e8
+#define PSMOUSE_CMD_GETINFO 0x03e9
+#define PSMOUSE_CMD_GETID 0x02f2
+#define PSMOUSE_CMD_SETRATE 0x10f3
+#define PSMOUSE_CMD_ENABLE 0x00f4
+#define PSMOUSE_CMD_DISABLE 0x00f5
+#define PSMOUSE_CMD_RESET_BAT 0x02ff
+
+// Status register bits.
+#define I8042_STR_PARITY 0x80
+#define I8042_STR_TIMEOUT 0x40
+#define I8042_STR_AUXDATA 0x20
+#define I8042_STR_KEYLOCK 0x10
+#define I8042_STR_CMDDAT 0x08
+#define I8042_STR_MUXERR 0x04
+#define I8042_STR_IBF 0x02
+#define I8042_STR_OBF 0x01
+
+// Control register bits.
+#define I8042_CTR_KBDINT 0x01
+#define I8042_CTR_AUXINT 0x02
+#define I8042_CTR_IGNKEYLOCK 0x08
+#define I8042_CTR_KBDDIS 0x10
+#define I8042_CTR_AUXDIS 0x20
+#define I8042_CTR_XLATE 0x40
+
+// functions
+int i8042_flush(void);
+int i8042_command(int command, u8 *param);
+int kbd_command(int command, u8 *param);
+int aux_command(int command, u8 *param);
+
+#endif // ps2port.h