//
// This file may be distributed under the terms of the GNU GPLv3 license.
-#include "biosvar.h" // struct bregs
+#include "biosvar.h" // GET_BDA
#include "util.h" // debug_enter
#include "config.h" // CONFIG_*
+#include "pic.h" // eoi_pic1
+#include "bregs.h" // struct bregs
+#include "ps2port.h" // i8042_flush
+
+static void
+keyboard_init()
+{
+ if (CONFIG_COREBOOT)
+ // Coreboot already does low-level keyboard init.
+ goto end;
+
+ /* flush incoming keys */
+ int ret = i8042_flush();
+ if (ret)
+ return;
+
+ // 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;
+ }
+
+ // 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;
+ }
+
+ // 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;
+
+
+ /* ------------------- keyboard side ------------------------*/
+ /* reset keyboard and self test (keyboard side) */
+ ret = kbd_command(ATKBD_CMD_RESET_BAT, param);
+ if (ret != 0 && ret != 2)
+ return;
+ if (param[0] != 0xaa) {
+ dprintf(1, "keyboard self test failed (got %x not 0xaa)\n", param[0]);
+ return;
+ }
+
+ /* Disable keyboard */
+ ret = kbd_command(ATKBD_CMD_RESET_DIS, NULL);
+ if (ret)
+ return;
+
+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 */
+ ret = kbd_command(ATKBD_CMD_ENABLE, NULL);
+ if (ret)
+ return;
+
+ dprintf(1, "keyboard initialized\n");
+}
+
+void
+kbd_setup()
+{
+ dprintf(3, "init keyboard\n");
+ u16 x = offsetof(struct bios_data_area_s, kbd_buf) - 0x400;
+ SET_BDA(kbd_mode, 0x10);
+ SET_BDA(kbd_buf_head, x);
+ SET_BDA(kbd_buf_tail, x);
+ SET_BDA(kbd_buf_start_offset, x);
+
+ SET_BDA(kbd_buf_end_offset
+ , x + FIELD_SIZEOF(struct bios_data_area_s, kbd_buf));
+
+ if (! CONFIG_KEYBOARD)
+ return;
+
+ keyboard_init();
+
+ enable_hwirq(1, entry_09);
+}
static u8
enqueue_key(u8 scan_code, u8 ascii_code)
if (buffer_tail == buffer_head)
return 0;
- SET_FARVAR(0x0000, *(u8*)(temp_tail+0x400+0), ascii_code);
- SET_FARVAR(0x0000, *(u8*)(temp_tail+0x400+1), scan_code);
+ SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+0x400+0), ascii_code);
+ SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+0x400+1), scan_code);
SET_BDA(kbd_buf_tail, buffer_tail);
return 1;
}
break;
if (!incr)
return 0;
- nop();
+ cpu_relax();
}
- *ascii_code = GET_FARVAR(0x0000, *(u8*)(buffer_head+0x400+0));
- *scan_code = GET_FARVAR(0x0000, *(u8*)(buffer_head+0x400+1));
+ *ascii_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+0x400+0));
+ *scan_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+0x400+1));
if (incr) {
u16 buffer_start = GET_BDA(kbd_buf_start_offset);
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
// don't change AH : function int16 ah=0x20-0x22 NOT supported
}
+static void
+handle_16XX(struct bregs *regs)
+{
+ debug_stub(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
-void VISIBLE
+void VISIBLE16
handle_16(struct bregs *regs)
{
-// debug_enter(regs);
-
- set_leds();
+ debug_enter(regs, DEBUG_HDL_16);
+ if (! CONFIG_KEYBOARD)
+ return;
irq_enable();
+ set_leds();
+
switch (regs->ah) {
case 0x00: handle_1600(regs); break;
case 0x01: handle_1601(regs); break;
case 0x92: handle_1692(regs); break;
case 0xa2: handle_16a2(regs); break;
case 0x6f: handle_166f(regs); break;
+ default: handle_16XX(regs); break;
}
}
{ none, none, none, none, none },
{ none, none, none, none, none },
{ 0x565c, 0x567c, none, none, none }, /* \| */
- { 0x5700, 0x5700, none, none, none }, /* F11 */
- { 0x5800, 0x5800, none, none, none } /* F12 */
+ { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
+ { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */
};
static void
switch (scancode) {
case 0x00:
- BX_INFO("KBD: int09 handler: AL=0\n");
+ dprintf(1, "KBD: int09 handler: AL=0\n");
return;
case 0x3a: /* Caps Lock press */
return;
default:
- if (scancode & 0x80) {
- break; /* toss key releases ... */
- }
+ if (scancode & 0x80)
+ // toss key releases
+ break;
+ if (scancode == 0x53 && (shift_flags & 0x0c) == 0x0c)
+ // Ctrl+alt+del - reset machine.
+ reset_vector();
if (scancode > MAX_SCAN_CODE) {
- BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
+ dprintf(1, "KBD: int09h_handler(): unknown scancode read: 0x%02x!\n"
+ , scancode);
return;
}
u8 asciicode;
struct scaninfo *info = &scan_to_scanascii[scancode];
if (shift_flags & 0x08) { /* ALT */
- asciicode = GET_VAR(CS, info->alt);
- scancode = GET_VAR(CS, info->alt) >> 8;
+ asciicode = GET_GLOBAL(info->alt);
+ scancode = GET_GLOBAL(info->alt) >> 8;
} else if (shift_flags & 0x04) { /* CONTROL */
- asciicode = GET_VAR(CS, info->control);
- scancode = GET_VAR(CS, info->control) >> 8;
- } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
+ asciicode = GET_GLOBAL(info->control);
+ scancode = GET_GLOBAL(info->control) >> 8;
+ } else if ((mf2_state & 0x02) > 0
+ && scancode >= 0x47 && scancode <= 0x53) {
/* extended keys handling */
asciicode = 0xe0;
- scancode = GET_VAR(CS, info->normal) >> 8;
+ scancode = GET_GLOBAL(info->normal) >> 8;
} else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
/* check if lock state should be ignored
* because a SHIFT key are pressed */
- if (shift_flags & GET_VAR(CS, info->lock_flags)) {
- asciicode = GET_VAR(CS, info->normal);
- scancode = GET_VAR(CS, info->normal) >> 8;
+ if (shift_flags & GET_GLOBAL(info->lock_flags)) {
+ asciicode = GET_GLOBAL(info->normal);
+ scancode = GET_GLOBAL(info->normal) >> 8;
} else {
- asciicode = GET_VAR(CS, info->shift);
- scancode = GET_VAR(CS, info->shift) >> 8;
+ asciicode = GET_GLOBAL(info->shift);
+ scancode = GET_GLOBAL(info->shift) >> 8;
}
} else {
/* check if lock is on */
- if (shift_flags & GET_VAR(CS, info->lock_flags)) {
- asciicode = GET_VAR(CS, info->shift);
- scancode = GET_VAR(CS, info->shift) >> 8;
+ if (shift_flags & GET_GLOBAL(info->lock_flags)) {
+ asciicode = GET_GLOBAL(info->shift);
+ scancode = GET_GLOBAL(info->shift) >> 8;
} else {
- asciicode = GET_VAR(CS, info->normal);
- scancode = GET_VAR(CS, info->normal) >> 8;
+ asciicode = GET_GLOBAL(info->normal);
+ scancode = GET_GLOBAL(info->normal) >> 8;
}
}
if (scancode==0 && asciicode==0) {
- BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
+ dprintf(1, "KBD: int09h_handler():"
+ " scancode & asciicode are zero?\n");
}
enqueue_key(scancode, asciicode);
break;
}
// INT09h : Keyboard Hardware Service Entry Point
-void VISIBLE
-handle_09(struct bregs *regs)
+void VISIBLE16
+handle_09()
{
-// debug_enter(regs);
-
- outb(0x0b, PORT_PIC1);
- if ((inb(PORT_PIC1) & 0x02) == 0)
- return;
-
- // disable keyboard
- outb(0xad, PORT_PS2_STATUS);
+ debug_isr(DEBUG_ISR_09);
+ if (! CONFIG_KEYBOARD)
+ 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
tr.ah = 0x4f;
tr.flags = F_CF;
call16_int(0x15, &tr);
- if (!tr.flags & F_CF)
+ if (!(tr.flags & F_CF))
goto done;
key = tr.al;
}
process_key(key);
irq_disable();
- eoi_master_pic();
done:
- // enable keyboard
- outb(0xae, PORT_PS2_STATUS);
+ eoi_pic1();
}