diff options
Diffstat (limited to 'mubios')
| -rw-r--r-- | mubios/arch/interrupt.S | 1 | ||||
| -rw-r--r-- | mubios/arch/irq.S | 29 | ||||
| -rw-r--r-- | mubios/core/bda.c | 5 | ||||
| -rw-r--r-- | mubios/core/interrupt.c | 4 | ||||
| -rw-r--r-- | mubios/include/bios.h | 1 | ||||
| -rw-r--r-- | mubios/services/int16.c | 143 |
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; + } +} |
