From 3b897198775966fbcf459bc3284c92358ee9154f Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Sun, 20 Jul 2008 10:08:59 -0400 Subject: [PATCH] Rewrite ps2 port (keyboard/mouse) handling. Use command sending code for communicating with the ps2 port. --- Makefile | 4 +- src/biosvar.h | 2 + src/kbd.c | 233 ++++++++++++++------------------------------- src/mouse.c | 256 ++++++++++++++++---------------------------------- src/ps2port.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++ src/ps2port.h | 62 ++++++++++++ 6 files changed, 459 insertions(+), 338 deletions(-) create mode 100644 src/ps2port.c create mode 100644 src/ps2port.h 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, ¶m); + 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 +// 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> 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 -- 2.25.1