aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mubios/arch/irq.S30
-rw-r--r--mubios/core/post.c1
-rw-r--r--mubios/drivers/kbd.c133
-rw-r--r--mubios/include/bios.h1
-rw-r--r--mubios/services/int16.c15
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;