aboutsummaryrefslogtreecommitdiff
path: root/mubios
diff options
context:
space:
mode:
Diffstat (limited to 'mubios')
-rw-r--r--mubios/arch/interrupt.S1
-rw-r--r--mubios/arch/irq.S29
-rw-r--r--mubios/core/bda.c5
-rw-r--r--mubios/core/interrupt.c4
-rw-r--r--mubios/include/bios.h1
-rw-r--r--mubios/services/int16.c143
6 files changed, 183 insertions, 0 deletions
diff --git a/mubios/arch/interrupt.S b/mubios/arch/interrupt.S
index 805cc50..021a83f 100644
--- a/mubios/arch/interrupt.S
+++ b/mubios/arch/interrupt.S
@@ -88,3 +88,4 @@ int1a_return:
BIOS_SERVICE_ENTRY int10_entry, 0x10
BIOS_SERVICE_ENTRY int13_entry, 0x13
BIOS_SERVICE_ENTRY int15_entry, 0x15
+ BIOS_SERVICE_ENTRY int16_entry, 0x16
diff --git a/mubios/arch/irq.S b/mubios/arch/irq.S
index dbde8ad..324ae05 100644
--- a/mubios/arch/irq.S
+++ b/mubios/arch/irq.S
@@ -69,12 +69,41 @@ irq0_send_eoi:
irq1_entry:
push ax
+ push bx
+ push dx
+ push ds
# Read the PS/2 scan code before sending EOI.
in al, 0x60
+ mov dl, al
+
+ test dl, 0x80
+ jnz irq1_send_eoi
+
+ xor ax, ax
+ mov ds, ax
+
+ mov bx, word ptr [0x041C]
+ mov ax, bx
+ add ax, 2
+ cmp ax, 0x043E
+ jb irq1_next_tail_ready
+ mov ax, 0x041E
+irq1_next_tail_ready:
+ cmp ax, word ptr [0x041A]
+ je irq1_send_eoi
+
+ mov byte ptr [bx], 0
+ mov byte ptr [bx + 1], dl
+ mov word ptr [0x041C], ax
+
+irq1_send_eoi:
mov al, 0x20
out 0x20, al
+ pop ds
+ pop dx
+ pop bx
pop ax
iret
diff --git a/mubios/core/bda.c b/mubios/core/bda.c
index 8417605..7220719 100644
--- a/mubios/core/bda.c
+++ b/mubios/core/bda.c
@@ -44,6 +44,9 @@ bda_init (void)
store_u16 (bda + BDA_EQUIPMENT_OFFSET, (u16)(ebda_base >> 4));
store_u16 (bda + BDA_CONVENTIONAL_MEMORY_OFFSET, (u16)(ebda_base >> 10));
+
+ store_u16 (bda + 0x001Au, 0x041Eu);
+ store_u16 (bda + 0x001Cu, 0x041Eu);
}
struct ivt_entry
@@ -60,6 +63,7 @@ extern void int1a_entry (void);
extern void int10_entry (void);
extern void int13_entry (void);
extern void int15_entry (void);
+extern void int16_entry (void);
static void
install_ivt_entry (u8 vector, void (*handler) (void))
@@ -85,4 +89,5 @@ ivt_init (void)
install_ivt_entry (0x10u, int10_entry);
install_ivt_entry (0x13u, int13_entry);
install_ivt_entry (0x15u, int15_entry);
+ install_ivt_entry (0x16u, int16_entry);
}
diff --git a/mubios/core/interrupt.c b/mubios/core/interrupt.c
index 9c71492..bf2ebc3 100644
--- a/mubios/core/interrupt.c
+++ b/mubios/core/interrupt.c
@@ -39,6 +39,10 @@ bios_service_dispatch (u8 vector, struct bios_regs *regs)
int15_service (regs);
break;
+ case 0x16u:
+ int16_service (regs);
+ break;
+
default:
regs->eax = 0x0100u;
regs->flags |= 0x0001u;
diff --git a/mubios/include/bios.h b/mubios/include/bios.h
index 1094bed..456d212 100644
--- a/mubios/include/bios.h
+++ b/mubios/include/bios.h
@@ -58,5 +58,6 @@ void bios_service_dispatch (u8 vector, struct bios_regs *regs);
void int10_service (struct bios_regs *regs);
void int13_service (struct bios_regs *regs);
void int15_service (struct bios_regs *regs);
+void int16_service (struct bios_regs *regs);
#endif // MUBIOS_BIOS_H
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;
+ }
+}