aboutsummaryrefslogtreecommitdiff
path: root/mubios/services/int16.c
diff options
context:
space:
mode:
Diffstat (limited to 'mubios/services/int16.c')
-rw-r--r--mubios/services/int16.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/mubios/services/int16.c b/mubios/services/int16.c
new file mode 100644
index 0000000..7acccfb
--- /dev/null
+++ b/mubios/services/int16.c
@@ -0,0 +1,143 @@
+/*
+ RCC-Project
+
+ Copyright (C) 2026 Richard Qin
+
+ This file is part of RCC-Project.
+
+ RCC-Project is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your option)
+ any later version.
+
+ RCC-Project is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+ */
+
+#include "bios.h"
+#include "regs.h"
+
+#define BIOS_ZF 0x0040u
+#define BDA_KBD_HEAD 0x041Au
+#define BDA_KBD_TAIL 0x041Cu
+#define BDA_KBD_BUFFER 0x041Eu
+#define BDA_KBD_BUFFER_END 0x043Eu
+
+static u8
+scancode_to_ascii (u8 scancode)
+{
+ switch (scancode)
+ {
+ case 0x1Eu:
+ return 'a';
+ case 0x30u:
+ return 'b';
+ case 0x2Eu:
+ return 'c';
+ case 0x20u:
+ return 'd';
+ case 0x12u:
+ return 'e';
+ case 0x21u:
+ return 'f';
+ case 0x22u:
+ return 'g';
+ case 0x23u:
+ return 'h';
+ case 0x17u:
+ return 'i';
+ case 0x24u:
+ return 'j';
+ case 0x25u:
+ return 'k';
+ case 0x26u:
+ return 'l';
+ case 0x32u:
+ return 'm';
+ case 0x31u:
+ return 'n';
+ case 0x18u:
+ return 'o';
+ case 0x19u:
+ return 'p';
+ case 0x10u:
+ return 'q';
+ case 0x13u:
+ return 'r';
+ case 0x1Fu:
+ return 's';
+ case 0x14u:
+ return 't';
+ case 0x16u:
+ return 'u';
+ case 0x2Fu:
+ return 'v';
+ case 0x11u:
+ return 'w';
+ case 0x2Du:
+ return 'x';
+ case 0x15u:
+ return 'y';
+ case 0x2Cu:
+ return 'z';
+ case 0x39u:
+ return ' ';
+ case 0x1Cu:
+ return '\r';
+ default:
+ return 0;
+ }
+}
+
+void
+int16_service (struct bios_regs *regs)
+{
+ volatile u16 *head;
+ volatile u16 *tail;
+ volatile u16 *buffer;
+ u8 function;
+ u16 position;
+ u16 value;
+ u8 scancode;
+ u8 ascii;
+
+ function = (u8)(regs->eax >> 8);
+
+ if (function != 0x00u && function != 0x01u)
+ {
+ regs->eax = 0;
+ regs->flags |= BIOS_ZF;
+ return;
+ }
+
+ head = (volatile u16 *)BDA_KBD_HEAD;
+ tail = (volatile u16 *)BDA_KBD_TAIL;
+ buffer = (volatile u16 *)BDA_KBD_BUFFER;
+
+ if (*head == *tail)
+ {
+ regs->eax = 0;
+ regs->flags |= BIOS_ZF;
+ return;
+ }
+
+ position = *head;
+ value = buffer[(position - BDA_KBD_BUFFER) >> 1];
+ scancode = (u8)(value >> 8);
+ ascii = scancode_to_ascii (scancode);
+
+ regs->eax = ((u32)scancode << 8) | ascii;
+ regs->flags &= (u16)~BIOS_ZF;
+
+ if (function == 0x00u)
+ {
+ position += 2;
+
+ if (position >= BDA_KBD_BUFFER_END)
+ position = BDA_KBD_BUFFER;
+
+ *head = position;
+ }
+}