// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2002 MandrakeSoft S.A.
//
-// 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 "biosvar.h" // GET_BDA
#include "util.h" // debug_enter
kbd_setup()
{
dprintf(3, "init keyboard\n");
- u16 x = offsetof(struct bios_data_area_s, kbd_buf) - 0x400;
+ u16 x = offsetof(struct bios_data_area_s, kbd_buf);
SET_BDA(kbd_mode, 0x10);
SET_BDA(kbd_buf_head, x);
SET_BDA(kbd_buf_tail, x);
if (buffer_tail == buffer_head)
return 0;
- SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+0x400+0), ascii_code);
- SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+0x400+1), scan_code);
+ SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+0), ascii_code);
+ SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+1), scan_code);
SET_BDA(kbd_buf_tail, buffer_tail);
return 1;
}
-static u8
-dequeue_key(u8 *scan_code, u8 *ascii_code, u8 incr)
+static void
+dequeue_key(struct bregs *regs, int incr, int extended)
{
u16 buffer_head;
u16 buffer_tail;
if (buffer_head != buffer_tail)
break;
- if (!incr)
- return 0;
+ if (!incr) {
+ regs->flags |= F_ZF;
+ return;
+ }
cpu_relax();
}
- *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);
- u16 buffer_end = GET_BDA(kbd_buf_end_offset);
+ u8 ascii_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+0));
+ u8 scan_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+1));
+ if ((ascii_code == 0xF0 && scan_code != 0)
+ || (ascii_code == 0xE0 && !extended))
+ ascii_code = 0;
+ regs->ax = (scan_code << 8) | ascii_code;
- buffer_head += 2;
- if (buffer_head >= buffer_end)
- buffer_head = buffer_start;
- SET_BDA(kbd_buf_head, buffer_head);
+ if (!incr) {
+ regs->flags &= ~F_ZF;
+ return;
}
- return 1;
+ u16 buffer_start = GET_BDA(kbd_buf_start_offset);
+ u16 buffer_end = GET_BDA(kbd_buf_end_offset);
+
+ buffer_head += 2;
+ if (buffer_head >= buffer_end)
+ buffer_head = buffer_start;
+ SET_BDA(kbd_buf_head, buffer_head);
}
// read keyboard input
static void
handle_1600(struct bregs *regs)
{
- u8 scan_code, ascii_code;
- dequeue_key(&scan_code, &ascii_code, 1);
- if (scan_code != 0 && ascii_code == 0xF0)
- ascii_code = 0;
- else if (ascii_code == 0xE0)
- ascii_code = 0;
- regs->ax = (scan_code << 8) | ascii_code;
+ dequeue_key(regs, 1, 0);
}
// check keyboard status
static void
handle_1601(struct bregs *regs)
{
- u8 scan_code, ascii_code;
- if (!dequeue_key(&scan_code, &ascii_code, 0)) {
- regs->flags |= F_ZF;
- return;
- }
- if (scan_code != 0 && ascii_code == 0xF0)
- ascii_code = 0;
- else if (ascii_code == 0xE0)
- ascii_code = 0;
- regs->ax = (scan_code << 8) | ascii_code;
- regs->flags &= ~F_ZF;
+ dequeue_key(regs, 0, 0);
}
// get shift flag status
static void
handle_1610(struct bregs *regs)
{
- u8 scan_code, ascii_code;
- dequeue_key(&scan_code, &ascii_code, 1);
- if (scan_code != 0 && ascii_code == 0xF0)
- ascii_code = 0;
- regs->ax = (scan_code << 8) | ascii_code;
+ dequeue_key(regs, 1, 1);
}
// check MF-II keyboard status
static void
handle_1611(struct bregs *regs)
{
- u8 scan_code, ascii_code;
- if (!dequeue_key(&scan_code, &ascii_code, 0)) {
- regs->flags |= F_ZF;
- return;
- }
- if (scan_code != 0 && ascii_code == 0xF0)
- ascii_code = 0;
- regs->ax = (scan_code << 8) | ascii_code;
- regs->flags &= ~F_ZF;
+ dequeue_key(regs, 0, 1);
}
// get extended keyboard status
u16 control;
u16 alt;
u8 lock_flags;
-} scan_to_scanascii[MAX_SCAN_CODE + 1] = {
+} scan_to_scanascii[MAX_SCAN_CODE + 1] VAR16 = {
{ none, none, none, none, none },
{ 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
{ 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
{ 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */
};
-static void
+// Handle a scancode read from the ps2 port. Note that "noinline" is
+// used to make sure the call to call16_simpint in handle_09 doesn't
+// have the overhead of this function's stack.
+static void noinline
process_key(u8 scancode)
{
u8 shift_flags = GET_BDA(kbd_flag0);
// read key from keyboard controller
u8 v = inb(PORT_PS2_STATUS);
- if ((v & 0x21) != 0x01) {
- dprintf(1, "int09 but no keyboard data.\n");
+ if ((v & (I8042_STR_OBF|I8042_STR_AUXDATA)) != I8042_STR_OBF) {
+ dprintf(1, "keyboard irq 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
- struct bregs tr;
- memset(&tr, 0, sizeof(tr));
- tr.al = key;
- tr.ah = 0x4f;
- tr.flags = F_CF;
- call16_int(0x15, &tr);
- if (!(tr.flags & F_CF))
+ u32 eax = (0x4f << 8) | key;
+ u32 flags;
+ call16_simpint(0x15, &eax, &flags);
+ if (!(flags & F_CF))
goto done;
- key = tr.al;
+ key = eax;
}
process_key(key);
- irq_disable();
-
done:
eoi_pic1();
}