diff options
| -rw-r--r-- | mubios/arch/irq.S | 30 | ||||
| -rw-r--r-- | mubios/core/post.c | 1 | ||||
| -rw-r--r-- | mubios/drivers/kbd.c | 133 | ||||
| -rw-r--r-- | mubios/include/bios.h | 1 | ||||
| -rw-r--r-- | mubios/services/int16.c | 15 |
5 files changed, 150 insertions, 30 deletions
diff --git a/mubios/arch/irq.S b/mubios/arch/irq.S index 99eb9b3..b22578b 100644 --- a/mubios/arch/irq.S +++ b/mubios/arch/irq.S @@ -25,8 +25,6 @@ .equ BDA_BASE, 0x0400 .equ BDA_KBD_BUFFER_START, 0x001E .equ BDA_KBD_BUFFER_END, 0x003E - .equ BDA_KBD_BREAK_PREFIX, 0x0497 - .equ TIMER_TICKS_PER_DAY_LOW, 0x00B0 .equ TIMER_TICKS_PER_DAY_HIGH, 0x0018 @@ -80,26 +78,24 @@ irq1_entry: push ds push si - # Read the PS/2 scan code before sending EOI. - in al, 0x60 - mov dl, al - xor ax, ax mov ds, ax - # Ignore a PS/2 set-2 break prefix and its following release code. - cmp dl, 0xF0 - jne irq1_check_break_prefix - mov byte ptr [BDA_KBD_BREAK_PREFIX], 1 - jmp irq1_send_eoi + # Only read the data port when the controller holds a byte for the CPU. + in al, 0x64 + test al, 0x01 + jz irq1_send_eoi + + mov ah, al -irq1_check_break_prefix: - cmp byte ptr [BDA_KBD_BREAK_PREFIX], 0 - je irq1_check_set1_break - mov byte ptr [BDA_KBD_BREAK_PREFIX], 0 - jmp irq1_send_eoi + in al, 0x60 + mov dl, al + + # Drop bytes that belong to the auxiliary port. + test ah, 0x20 + jnz irq1_send_eoi -irq1_check_set1_break: + # Set 1 break codes carry bit 7 in the scan code itself. test dl, 0x80 jnz irq1_send_eoi diff --git a/mubios/core/post.c b/mubios/core/post.c index 7c6769f..15d07ed 100644 --- a/mubios/core/post.c +++ b/mubios/core/post.c @@ -33,6 +33,7 @@ post_main (void) ivt_init (); + kbd_init (); pic_init (); pit_init (); ioapic_init (); diff --git a/mubios/drivers/kbd.c b/mubios/drivers/kbd.c new file mode 100644 index 0000000..4de0a96 --- /dev/null +++ b/mubios/drivers/kbd.c @@ -0,0 +1,133 @@ +/* + 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 "io.h" + +#define KBD_STATUS_PORT 0x0064u +#define KBD_DATA_PORT 0x0060u + +#define KBD_STATUS_OBF 0x01u +#define KBD_STATUS_IBF 0x02u +#define KBD_STATUS_AUX 0x20u + +#define KBD_CMD_READ_CONFIG 0x20u +#define KBD_CMD_WRITE_CONFIG 0x60u +#define KBD_CMD_DISABLE_KBD 0xADu +#define KBD_CMD_ENABLE_KBD 0xAEu + +/* + * 8042 command byte bits. + * Bit 0 enables the keyboard IRQ, bit 1 the auxiliary port IRQ, bit 4 and bit 5 + * hold the keyboard and auxiliary clock, and bit 6 selects set 1 scan codes on + * the keyboard interface. + */ +#define KBD_CONFIG_IRQ1 0x01u +#define KBD_CONFIG_IRQ12 0x02u +#define KBD_CONFIG_DISABLE_KBD_CLOCK 0x10u +#define KBD_CONFIG_DISABLE_AUX_CLOCK 0x20u +#define KBD_CONFIG_TRANSLATE 0x40u + +#define KBD_DEVICE_ENABLE_SCAN 0xF4u + +#define KBD_WAIT_LIMIT 0x10000u + +static int +wait_input_clear (void) +{ + u32 count; + + for (count = 0; count < KBD_WAIT_LIMIT; count++) + { + if ((io_in8 (KBD_STATUS_PORT) & KBD_STATUS_IBF) == 0u) + return 0; + } + + return -1; +} + +static int +wait_output_full (void) +{ + u32 count; + + for (count = 0; count < KBD_WAIT_LIMIT; count++) + { + if ((io_in8 (KBD_STATUS_PORT) & KBD_STATUS_OBF) != 0u) + return 0; + } + + return -1; +} + +static int +kbd_write_command (u8 command) +{ + if (wait_input_clear () != 0) + return -1; + + io_out8 (KBD_STATUS_PORT, command); + return 0; +} + +static int +kbd_write_data (u8 value) +{ + if (wait_input_clear () != 0) + return -1; + + io_out8 (KBD_DATA_PORT, value); + return 0; +} + +void +kbd_init (void) +{ + u8 config; + + /* Disable both ports before the controller is reconfigured. */ + kbd_write_command (KBD_CMD_DISABLE_KBD); + + /* Drain the self-test and any pending scan code left in the output buffer. */ + while ((io_in8 (KBD_STATUS_PORT) & KBD_STATUS_OBF) != 0u) + (void)io_in8 (KBD_DATA_PORT); + + if (kbd_write_command (KBD_CMD_READ_CONFIG) != 0) + return; + + if (wait_output_full () != 0) + return; + + config = io_in8 (KBD_DATA_PORT); + + config &= (u8)~(KBD_CONFIG_DISABLE_KBD_CLOCK | KBD_CONFIG_DISABLE_AUX_CLOCK); + config |= KBD_CONFIG_IRQ1 | KBD_CONFIG_IRQ12 | KBD_CONFIG_TRANSLATE; + + if (kbd_write_command (KBD_CMD_WRITE_CONFIG) != 0) + return; + + kbd_write_data (config); + + kbd_write_command (KBD_CMD_ENABLE_KBD); + + /* Ask the keyboard to start scanning and consume its acknowledge byte. */ + kbd_write_data (KBD_DEVICE_ENABLE_SCAN); + + if (wait_output_full () == 0) + (void)io_in8 (KBD_DATA_PORT); +} diff --git a/mubios/include/bios.h b/mubios/include/bios.h index c4eb465..c1c70d8 100644 --- a/mubios/include/bios.h +++ b/mubios/include/bios.h @@ -44,6 +44,7 @@ void serial_init (void); void serial_putc (u8 value); void serial_write (const char *text); +void kbd_init (void); void pic_init (void); void pit_init (void); void ioapic_init (void); diff --git a/mubios/services/int16.c b/mubios/services/int16.c index 5872fb1..cadc1ff 100644 --- a/mubios/services/int16.c +++ b/mubios/services/int16.c @@ -17,6 +17,7 @@ */ #include "bios.h" +#include "io.h" #include "regs.h" #define BIOS_ZF 0x0040u @@ -27,18 +28,6 @@ #define BDA_KBD_BUFFER_END 0x003Eu static u8 -normalize_scancode (u8 scancode) -{ - switch (scancode) - { - case 0x5Au: - return 0x1Cu; - default: - return scancode; - } -} - -static u8 scancode_to_ascii (u8 scancode) { switch (scancode) @@ -138,7 +127,7 @@ int16_service (struct bios_regs *regs) position = *head; value = buffer[(position - BDA_KBD_BUFFER_START) >> 1]; - scancode = normalize_scancode ((u8)(value >> 8)); + scancode = (u8)(value >> 8); ascii = scancode_to_ascii (scancode); regs->eax = ((u32)scancode << 8) | ascii; |
