Basic PS/2 keyboard driver, and ...
authorMinep <zelong56@gmail.com>
Fri, 29 Apr 2022 23:29:02 +0000 (00:29 +0100)
committerMinep <zelong56@gmail.com>
Fri, 29 Apr 2022 23:29:02 +0000 (00:29 +0100)
A bit refactoring on timer related api;
New clock api for accessing datatime & epoch stuff;
New log level: debug, is implemented in kprintf.

21 files changed:
lunaix-os/hal/apic.c
lunaix-os/hal/ioapic.c
lunaix-os/hal/rtc.c
lunaix-os/includes/arch/x86/interrupts.h
lunaix-os/includes/hal/apic.h
lunaix-os/includes/lunaix/clock.h [new file with mode: 0644]
lunaix-os/includes/lunaix/keyboard.h [new file with mode: 0644]
lunaix-os/includes/lunaix/mm/vmm.h
lunaix-os/includes/lunaix/peripheral/ps2kbd.h [new file with mode: 0644]
lunaix-os/includes/lunaix/spike.h
lunaix-os/includes/lunaix/syslog.h
lunaix-os/includes/lunaix/time.h [deleted file]
lunaix-os/includes/lunaix/timer.h
lunaix-os/kernel/asm/x86/idt.c
lunaix-os/kernel/asm/x86/interrupt.S
lunaix-os/kernel/k_init.c
lunaix-os/kernel/k_main.c
lunaix-os/kernel/kprintf.c
lunaix-os/kernel/peripheral/ps2kbd.c [new file with mode: 0644]
lunaix-os/kernel/time/clock.c [new file with mode: 0644]
lunaix-os/kernel/time/timer.c [moved from lunaix-os/kernel/timer.c with 90% similarity]

index 30951ef32b77e187d9dda2e467db70be44a0aab3..0d427d1dcaa80691658ff3e7a38ddd6b12c066ea 100644 (file)
@@ -44,7 +44,7 @@ apic_init()
         "rdmsr\n"
         "orl %1, %%eax\n"
         "wrmsr\n"
-        ::"i"(IA32_APIC_BASE_MSR), "i"(IA32_APIC_ENABLE)
+        ::"i"(IA32_MSR_APIC_BASE), "i"(IA32_APIC_ENABLE)
         : "eax", "ecx", "edx"
     );
 
index 80ab13bf6d76af9f5d4b88dd9e521f794db20be3..de4be2a57a1caebede99b419c3457ff32fe3d2c1 100644 (file)
@@ -22,8 +22,14 @@ ioapic_init() {
     
     // The ioapic_get_irq is to make sure we capture those overriden IRQs
 
+    // grab ourselves these irq numbers
+    uint8_t irq_rtc = ioapic_get_irq(acpi_ctx, PC_AT_IRQ_RTC);
+    uint8_t irq_kbd = ioapic_get_irq(acpi_ctx, PC_AT_IRQ_KBD);
+
     // PC_AT_IRQ_RTC -> RTC_TIMER_IV, fixed, edge trigged, polarity=high, physical, APIC ID 0
-    ioapic_redirect(ioapic_get_irq(acpi_ctx, PC_AT_IRQ_RTC), RTC_TIMER_IV, 0, IOAPIC_DELMOD_FIXED);
+    ioapic_redirect(irq_rtc, RTC_TIMER_IV, 0, IOAPIC_DELMOD_FIXED);
+
+    ioapic_redirect(irq_kbd, PC_KBD_IV, 0, IOAPIC_DELMOD_FIXED);
 }
 
 uint8_t
index 0e3673c2184800e39866bf335aaf674c2c8adcc8..2ffe76b14e2b4bf6c41e4bdc63072b417feca3bc 100644 (file)
@@ -9,7 +9,6 @@
  * 
  */
 #include <hal/rtc.h>
-#include <lunaix/time.h>
 #include <klibc/string.h>
 
 void
@@ -42,55 +41,6 @@ bcd2dec(uint8_t bcd)
     return ((bcd & 0xF0) >> 1) + ((bcd & 0xF0) >> 3) + (bcd & 0xf);
 }
 
-int
-rtc_date_same(datetime_t* a, datetime_t* b) {
-    return a->year == b->year &&
-           a->month == b->month &&
-           a->day == b->day &&
-           a->weekday == b->weekday &&
-           a->minute == b->minute &&
-           a->second == b->second;
-}
-
-void
-time_getdatetime(datetime_t* datetime)
-{
-    datetime_t current;
-    
-    do
-    {
-        while (rtc_read_reg(RTC_REG_A) & 0x80);
-        memcpy(&current, datetime, sizeof(datetime_t));
-
-        datetime->year = rtc_read_reg(RTC_REG_YRS);
-        datetime->month = rtc_read_reg(RTC_REG_MTH);
-        datetime->day = rtc_read_reg(RTC_REG_DAY);
-        datetime->weekday = rtc_read_reg(RTC_REG_WDY);
-        datetime->hour = rtc_read_reg(RTC_REG_HRS);
-        datetime->minute = rtc_read_reg(RTC_REG_MIN);
-        datetime->second = rtc_read_reg(RTC_REG_SEC);
-    } while (!rtc_date_same(datetime, &current));
-
-    uint8_t regbv = rtc_read_reg(RTC_REG_B);
-
-    // Convert from bcd to binary when needed
-    if (!RTC_BIN_ENCODED(regbv)) {
-        datetime->year = bcd2dec(datetime->year);
-        datetime->month = bcd2dec(datetime->month);
-        datetime->day = bcd2dec(datetime->day);
-        datetime->hour = bcd2dec(datetime->hour);
-        datetime->minute = bcd2dec(datetime->minute);
-        datetime->second = bcd2dec(datetime->second);
-    }
-
-
-    // To 24 hour format
-    if (!RTC_24HRS_ENCODED(regbv) && (datetime->hour >> 7)) {
-        datetime->hour = (12 + datetime->hour & 0x80);
-    }
-
-    datetime->year += RTC_CURRENT_CENTRY * 100;
-}
 
 void
 rtc_enable_timer() {
index 4ffc86fe2b28920e19a334369f44718ce2e8cc73..2c93c3901be393c9aa97437a6fe727feb82bdb10 100644 (file)
 #define APIC_TIMER_IV                   202
 #define APIC_SPIV_IV                    203
 
+// Keyboard
+#define PC_KBD_IV                       204
+
 #define RTC_TIMER_IV                    210
 
 
 #define PC_AT_IRQ_RTC                   8
-#define PC_AT_IRQ_KBD_BUF_FULL          1
+#define PC_AT_IRQ_KBD                   1
 
 #ifndef __ASM__
 #include <hal/cpu.h>
@@ -138,6 +141,9 @@ _asm_isr202();
 void
 _asm_isr203();
 
+void
+_asm_isr204();
+
 void
 _asm_isr210();
 
index f4ab92c1378050073aed9656b02c76eddf3f2f8a..42a211e0f5638a11f0d3363ebcfa494fca2a4d37 100644 (file)
@@ -6,7 +6,7 @@
 #define APIC_BASE_VADDR 0x1000
 #define __APIC_BASE_PADDR 0xFEE00000
 
-#define IA32_APIC_BASE_MSR 0x1B
+#define IA32_MSR_APIC_BASE 0x1B
 #define IA32_APIC_ENABLE   0x800
 
 /*
diff --git a/lunaix-os/includes/lunaix/clock.h b/lunaix-os/includes/lunaix/clock.h
new file mode 100644 (file)
index 0000000..dbfdfe5
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __LUNAIX_CLOCK_H
+#define __LUNAIX_CLOCK_H
+
+#include <stdint.h>
+
+typedef uint32_t time_t;
+
+typedef struct
+{
+    uint32_t year;      // use int32 as we need to store the 4-digit year
+    uint8_t month;
+    uint8_t day;
+    uint8_t weekday;
+    uint8_t hour;
+    uint8_t minute;
+    uint8_t second;
+} datetime_t;
+
+void
+clock_init();
+
+void 
+clock_walltime(datetime_t* datetime);
+
+int
+clock_datatime_eq(datetime_t* a, datetime_t* b);
+
+/**
+ * @brief 返回当前系统时间,即自从开机到当前时刻的毫秒时。
+ * 
+ * @return time_t 
+ */
+time_t 
+clock_systime();
+
+#endif /* __LUNAIX_CLOCK_H */
diff --git a/lunaix-os/includes/lunaix/keyboard.h b/lunaix-os/includes/lunaix/keyboard.h
new file mode 100644 (file)
index 0000000..f573316
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef __LUNAIX_KEYBOARD_H
+#define __LUNAIX_KEYBOARD_H
+
+//      Lunaix Keycode
+//       15        7         0
+// key = |xxxx xxxx|xxxx xxxx|
+// key[0:7] = sequence
+// key[8:15] = category
+//   0x0: ASCII codes
+//   0x1: Function keys
+//   0x2: keypad keys
+//   0x3: Cursor keys (arrow keys)
+//   0x4: Modifier keys
+//   0xff: Other keys (Un-categorized)
+
+typedef unsigned short kbd_keycode;
+
+#define FN_KEY  0x0100
+#define KEYPAD  0x0200
+#define CURSOR  0x0300
+#define MODIFR  0x0400
+#define OTHERS  0xff00
+
+#define ON_KEYPAD(x)    ((x & 0xff) | KEYPAD)
+
+// backspace key
+#define KEY_BS  (0x08)
+
+// enter/return key
+#define KEY_LF  (0x0a)
+
+#define KEY_HTAB (0x9)
+#define KEY_SPACE (0x20)
+#define KEY_ESC (0x1b)
+
+#define KEY_F1  (0x00 | FN_KEY)
+#define KEY_F2  (0x01 | FN_KEY)
+#define KEY_F3  (0x02 | FN_KEY)
+#define KEY_F4  (0x03 | FN_KEY)
+#define KEY_F5  (0x04 | FN_KEY)
+#define KEY_F6  (0x05 | FN_KEY)
+#define KEY_F7  (0x06 | FN_KEY)
+#define KEY_F8  (0x07 | FN_KEY)
+#define KEY_F9  (0x08 | FN_KEY)
+#define KEY_F10 (0x09 | FN_KEY)
+#define KEY_F11 (0x0a | FN_KEY)
+#define KEY_F12 (0x0b | FN_KEY)
+#define KEY_CAPSLK (0x0c | FN_KEY)
+#define KEY_NUMSLK (0x0d | FN_KEY)
+#define KEY_SCRLLK (0x0e | FN_KEY)
+
+#define KEY_PG_UP       (0x0 | OTHERS)
+#define KEY_PG_DOWN     (0x1 | OTHERS)
+#define KEY_INSERT      (0x2 | OTHERS)
+#define KEY_DELETE      (0x3 | OTHERS)
+#define KEY_HOME        (0x4 | OTHERS)
+#define KEY_END         (0x5 | OTHERS)
+#define KEY_PAUSE       (0x6 | OTHERS)
+
+#define KEY_LEFT        (0x0 | CURSOR)
+#define KEY_RIGHT       (0x1 | CURSOR)
+#define KEY_UP          (0x2 | CURSOR)
+#define KEY_DOWN        (0x3 | CURSOR)
+
+#define KEY_LSHIFT       (0x0 | MODIFR)
+#define KEY_RSHIFT       (0x1 | MODIFR)
+#define KEY_LCTRL        (0x2 | MODIFR)
+#define KEY_RCTRL        (0x3 | MODIFR)
+#define KEY_LALT         (0x4 | MODIFR)
+#define KEY_RALT         (0x5 | MODIFR)
+
+#endif /* __LUNAIX_KEYBOARD_H */
index 844eb0ec31c61430c099e928da29e61f7141fb4f..3e124fc9923a12249f35b8267013876b4e3eb8fe 100644 (file)
@@ -22,7 +22,7 @@ vmm_init_pd();
 
 /**
  * @brief 尝试建立一个映射关系。映射指定的物理页地址至虚拟页地址,如果指定的虚拟页地址已被占用
- * 则尝试寻找新的可用地址(地址总是大于指定的地址)。
+ * 则尝试寻找新的可用地址(地址总是大于指定的地址)。
  *
  * @param vpn 虚拟页地址
  * @param pa 物理页地址
diff --git a/lunaix-os/includes/lunaix/peripheral/ps2kbd.h b/lunaix-os/includes/lunaix/peripheral/ps2kbd.h
new file mode 100644 (file)
index 0000000..ca49cb7
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef __LUNAIX_PS2KBD_H
+#define __LUNAIX_PS2KBD_H
+
+#include <hal/io.h>
+#include <lunaix/keyboard.h>
+#include <lunaix/clock.h>
+
+#define PS2_PORT_DATA 0x60
+#define PS2_PORT_STATUS 0x64
+#define PS2_PORT_CMDREG 0x64
+
+#define PS2_STATUS_OFULL   0x1
+#define PS2_STATUS_IFULL   0x2
+
+#define PS2_RESULT_ACK  0xfa
+#define PS2_RESULT_NAK  0xfe    //resend
+#define PS2_RESULT_ECHO 0xee    
+#define PS2_RESULT_TEST_OK 0x55    
+
+// PS/2 keyboard device related commands
+#define PS2_KBD_CMD_SETLED  0xed
+#define PS2_KBD_CMD_ECHO  0xee
+#define PS2_KBD_CMD_SCANCODE_SET  0xf0
+#define PS2_KBD_CMD_IDENTIFY  0xf2
+#define PS2_KBD_CMD_SCAN_ENABLE  0xf4
+#define PS2_KBD_CMD_SCAN_DISABLE  0xf5
+
+// PS/2 *controller* related commands
+#define PS2_CMD_PORT1_DISABLE  0xad
+#define PS2_CMD_PORT1_ENABLE  0xae
+#define PS2_CMD_PORT2_DISABLE  0xa7
+#define PS2_CMD_PORT2_ENABLE  0xa8
+#define PS2_CMD_SELFTEST      0xaa
+#define PS2_CMD_SELFTEST_PORT1      0xab
+
+#define PS2_CMD_READ_CFG       0x20
+#define PS2_CMD_WRITE_CFG       0x60
+
+#define PS2_CFG_P1INT             0x1
+#define PS2_CFG_P2INT             0x2
+#define PS2_CFG_TRANSLATION       0x40
+
+#define PS2_DELAY       1000
+
+#define PS2_CMD_QUEUE_SIZE 8
+#define PS2_KBD_RECV_BUFFER_SIZE 8
+
+#define PS2_NO_ARG 0xff00
+
+
+#define KBD_KEY_RELEASED 0x0
+#define KBD_KEY_PRESSED 0x1
+#define KBD_KEY_SCRLLKED 0x2
+#define KBD_KEY_NUMBLKED 0x4
+#define KBD_KEY_CAPSLKED 0x8
+
+typedef unsigned char kbd_kstate_t;
+
+struct kdb_keyinfo_pkt {
+    char key;
+    kbd_keycode code;
+    kbd_kstate_t state;
+    time_t timestamp;
+};
+
+struct ps2_cmd {
+    char cmd;
+    char arg;
+};
+
+struct ps2_kbd_state {
+    char state;
+    kbd_keycode* translation_table;
+    kbd_kstate_t key_state;
+};
+
+struct ps2_cmd_queue {
+    struct ps2_cmd cmd_queue[PS2_CMD_QUEUE_SIZE];
+    int queue_ptr;
+    int queue_len;
+};
+
+struct ps2_key_buffer {
+    struct kdb_keyinfo_pkt key_buff[PS2_KBD_RECV_BUFFER_SIZE];
+    int buffer_ptr;
+    // We don't bother whether the buff is full or not, just override.
+};
+
+/**
+ * @brief 向PS/2控制器发送指令并等待返回代码。注意,对于没有返回代码的命令请使用`ps2_post_cmd`,否则会造成死锁。
+ * 
+ * @param cmd 
+ * @param args
+ */
+static uint8_t ps2_issue_cmd(char cmd, uint16_t arg);
+
+/**
+ * @brief 向PS/2控制器发送指令,不等待返回代码。
+ * 
+ * @param cmd 
+ * @param args 
+ * @return char 
+ */
+static void ps2_post_cmd(char cmd, uint16_t arg);
+
+void ps2_device_post_cmd(char cmd, char arg);
+
+void ps2_kbd_init();
+
+void ps2_process_cmd(void* arg);
+
+
+
+
+#endif /* __LUNAIX_PS2KBD_H */
index 9cf4b7fee0e442873e7a39498ca8252d1ff568f1..8fd47b59b710d766afa0dc78429ca564bde2737d 100644 (file)
@@ -27,7 +27,7 @@ inline static void spin() {
 
 #define assert_msg(cond, msg)                         \
     if (!(cond)) {                                    \
-        __assert_fail(msg, __FILE__, __LINE__);   \
+        __assert_fail(msg, __FILE__, __LINE__);       \
     }
 void __assert_fail(const char* expr, const char* file, unsigned int line) __attribute__((noinline, noreturn));
 #else
index 91e20036461e712cbfd10c83a3cecf1f9fcfb5ef..545a803b78dde1d1b53b11899de5013b73efabbd 100644 (file)
@@ -6,10 +6,12 @@
 #define _LEVEL_INFO  "0"
 #define _LEVEL_WARN  "1"
 #define _LEVEL_ERROR "2"
+#define _LEVEL_DEBUG "3"
 
 #define KINFO    "\x1b" _LEVEL_INFO
 #define KWARN    "\x1b" _LEVEL_WARN
 #define KERROR   "\x1b" _LEVEL_ERROR
+#define KDEBUG   "\x1b" _LEVEL_DEBUG
 
 #define LOG_MODULE(module)                  \
     static void kprintf(const char* fmt, ...) {    \
diff --git a/lunaix-os/includes/lunaix/time.h b/lunaix-os/includes/lunaix/time.h
deleted file mode 100644 (file)
index 522cc1f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __LUNAIX_TIME_H
-#define __LUNAIX_TIME_H
-
-#include <stdint.h>
-
-typedef struct
-{
-    uint32_t year;      // use int32 as we need to store the 4-digit year
-    uint8_t month;
-    uint8_t day;
-    uint8_t weekday;
-    uint8_t hour;
-    uint8_t minute;
-    uint8_t second;
-} datetime_t;
-
-void 
-time_getdatetime(datetime_t* datetime);
-
-#endif /* __LUNAIX_TIME_H */
index 0c65ffd0205dff61a319cc763c369a48d9389039..1b36db5cdfa0d91a94412cb6cd67d8b9e5b2c0a1 100644 (file)
@@ -8,17 +8,31 @@
 
 #define TIMER_MODE_PERIODIC   0x1
 
+typedef uint32_t ticks_t;
+
 struct lx_timer_context {
     struct lx_timer *active_timers;
-    uint32_t base_frequency;
+    /**
+     * @brief APIC timer base frequency (ticks per seconds)
+     * 
+     */
+    ticks_t base_frequency;
+    /**
+     * @brief Desired system running frequency
+     * 
+     */
     uint32_t running_frequency;
-    uint32_t tick_interval;
+    /**
+     * @brief Ticks per second relative to desired system running frequency
+     * 
+     */
+    ticks_t tps;
 };
 
 struct lx_timer {
     struct llist_header link;
-    uint32_t deadline;
-    uint32_t counter;
+    ticks_t deadline;
+    ticks_t counter;
     void* payload;
     void (*callback)(void*);
     uint8_t flags;
@@ -35,8 +49,12 @@ timer_init(uint32_t frequency);
 
 int
 timer_run_second(uint32_t second, void (*callback)(void*), void* payload, uint8_t flags);
+timer_run_ms(uint32_t millisecond, void (*callback)(void*), void* payload, uint8_t flags);
 
 int
-timer_run(uint32_t ticks, void (*callback)(void*), void* payload, uint8_t flags);
+timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags);
+
+struct lx_timer_context* 
+timer_context();
 
 #endif /* __LUNAIX_TIMER_H */
index d11d6ed0969a820d8d0ee3f75e4ac765c627f638..5474743467670e4173d8424d973941522024da78 100644 (file)
@@ -26,6 +26,7 @@ _init_idt() {
     _set_idt_entry(APIC_LINT0_IV, 0x08, _asm_isr201, 0);
     _set_idt_entry(APIC_TIMER_IV, 0x08, _asm_isr202, 0);
     _set_idt_entry(APIC_SPIV_IV,  0x08, _asm_isr203, 0);
+    _set_idt_entry(PC_KBD_IV,  0x08, _asm_isr204, 0);
 
     _set_idt_entry(RTC_TIMER_IV,  0x08, _asm_isr210, 0);
 
index 11fe3fd505f54af8a0b68e5fbef73483dd41d6c0..f05c3b80fa4e134df079101abfe785b6b5a96c71 100644 (file)
@@ -24,6 +24,7 @@
     isr_template APIC_TIMER_IV
     isr_template APIC_SPIV_IV
     isr_template RTC_TIMER_IV
+    isr_template PC_KBD_IV
 
     interrupt_wrapper:
         pushl %esp
index ce97b6ef7c20edb8872b59e30540a29eb449da1a..74e3534fbacac48a5a6941ecac4af30298ba0cd8 100644 (file)
@@ -8,6 +8,8 @@
 #include <lunaix/spike.h>
 #include <lunaix/syslog.h>
 #include <lunaix/timer.h>
+#include <lunaix/clock.h>
+#include <lunaix/peripheral/ps2kbd.h>
 
 #include <hal/rtc.h>
 #include <hal/apic.h>
@@ -98,6 +100,8 @@ _kernel_post_init() {
     apic_init();
     ioapic_init();
     timer_init(SYS_TIMER_FREQUENCY_HZ);
+    clock_init();
+    ps2_kbd_init();
 
     for (size_t i = 256; i < hhk_init_pg_count; i++) {
         vmm_unmap_page((void*)(i << PG_SIZE_BITS));
index a78562a822550f9f2d107d0f5b5d1c3b6cd0886a..b3b11031600f09744ac9300d123bfaa03cf9b77e 100644 (file)
@@ -3,7 +3,7 @@
 #include <lunaix/mm/kalloc.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/spike.h>
-#include <lunaix/time.h>
+#include <lunaix/clock.h>
 #include <lunaix/timer.h>
 #include <stdint.h>
 
@@ -59,7 +59,7 @@ _kernel_main()
 static datetime_t datetime;
 
 void test_timer(void* payload) {
-    time_getdatetime(&datetime);
+    clock_walltime(&datetime);
 
     kprintf(KWARN "%u/%02u/%02u %02u:%02u:%02u\r",
            datetime.year,
index 425fc2236ed78b72583f5f6cc5f5c92d90b99c09..a862bcc7db97a873d0735348ac99aaa3a74cff79 100644 (file)
@@ -32,6 +32,10 @@ __kprintf(const char* component, const char* fmt, va_list args) {
         tty_set_theme(VGA_COLOR_LIGHT_RED, current_theme >> 12);
         snprintf(expanded_fmt, MAX_XFMT_SIZE, "[%s] (%s) %s", "EROR", component, fmt);
         break;
+    case '3':
+        tty_set_theme(VGA_COLOR_LIGHT_BLUE, current_theme >> 12);
+        snprintf(expanded_fmt, MAX_XFMT_SIZE, "[%s] (%s) %s", "DEBG", component, fmt);
+        break;
     default:
         snprintf(expanded_fmt, MAX_XFMT_SIZE, "[%s] (%s) %s", "LOG", component, fmt);
         break;
diff --git a/lunaix-os/kernel/peripheral/ps2kbd.c b/lunaix-os/kernel/peripheral/ps2kbd.c
new file mode 100644 (file)
index 0000000..4301fed
--- /dev/null
@@ -0,0 +1,259 @@
+#include <lunaix/peripheral/ps2kbd.h>
+#include <lunaix/clock.h>
+#include <lunaix/timer.h>
+#include <lunaix/common.h>
+#include <lunaix/syslog.h>
+
+#include <hal/cpu.h>
+#include <hal/ioapic.h>
+
+#include <arch/x86/interrupts.h>
+#include <stdint.h>
+#include <klibc/string.h>
+
+#define PS2_DEV_CMD_MAX_ATTEMPTS 5
+
+LOG_MODULE("PS2KBD");
+
+static struct ps2_cmd_queue cmd_q;
+static struct ps2_key_buffer key_buf;
+static struct ps2_kbd_state kbd_state;
+
+#define KEY_NUM(x)      (x + 0x30)
+#define KEY_NPAD(x)      ON_KEYPAD(KEY_NUM(x))
+
+// 我们使用 Scancode Set 2
+
+// 大部分的扫描码(键码)
+static kbd_keycode scancode_set2[] = {
+    0, KEY_F9, 0, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F12, 0, KEY_F10, KEY_F8, KEY_F6,
+    KEY_F4, KEY_HTAB, '`', 0, 0, KEY_LALT, KEY_LSHIFT, 0, KEY_LCTRL, 'q', KEY_NUM(1), 
+    0, 0, 0, 'z', 's', 'a', 'w', KEY_NUM(2), 0, 0, 'c', 'x', 'd', 'e', KEY_NUM(4), KEY_NUM(3), 
+    0, 0, KEY_SPACE, 'v', 'f', 't', 'r', KEY_NUM(5),
+    0, 0, 'n', 'b', 'h', 'g', 'y', KEY_NUM(6), 0, 0, 0, 'm', 'j', 'u', KEY_NUM(7), KEY_NUM(8),
+    0, 0, ',', 'k', 'i', 'o', KEY_NUM(0), KEY_NUM(9), 0, 0, '.', '/', 'l', ';', 'p', '-', 0, 0,
+    0, '\'', 0, '[', '=', 0, 0, KEY_CAPSLK, KEY_RSHIFT, KEY_LF, ']', 0, '\\', 0, 0, 0, 0, 0, 0, 0,
+    0, KEY_BS, 0, 0, KEY_NPAD(1), 0, KEY_NPAD(4), KEY_NPAD(7), 0, 0, 0, KEY_NPAD(0), ON_KEYPAD('.'),
+    KEY_NPAD(2), KEY_NPAD(5), KEY_NPAD(6), KEY_NPAD(8), KEY_ESC, KEY_NUMSLK, KEY_F11, ON_KEYPAD('+'),
+    KEY_NPAD(3), ON_KEYPAD('-'), ON_KEYPAD('*'), KEY_NPAD(9), KEY_SCRLLK, 0, 0, 0, 0, KEY_F7
+};
+
+// 一些特殊的键码(以 0xe0 位前缀的)
+static kbd_keycode scancode_set2_ex[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RALT, 0, 0,
+    KEY_RCTRL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ON_KEYPAD('/'), 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, ON_KEYPAD(KEY_LF), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    KEY_END, 0, KEY_LEFT, KEY_HOME,
+    0, 0, 0, KEY_INSERT, KEY_DELETE, KEY_DOWN, 0, KEY_RIGHT, KEY_UP, 0, 0,
+    0, 0, KEY_PG_DOWN, 0, 0, KEY_PG_UP
+};
+
+// 用于处理 Shift+<key> 的情况
+static kbd_keycode scancode_set2_shift[] = {
+    0, KEY_F9, 0, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F12, 0, KEY_F10, KEY_F8, KEY_F6,
+    KEY_F4, KEY_HTAB, '~', 0, 0, KEY_LALT, KEY_LSHIFT, 0, KEY_LCTRL, 'Q', '!', 
+    0, 0, 0, 'Z', 'S', 'A', 'W', '@', 0, 0, 'C', 'X', 'D', 'E', '$', '#', 
+    0, 0, KEY_SPACE, 'V', 'F', 'T', 'R', '%',
+    0, 0, 'N', 'B', 'H', 'G', 'Y', '^', 0, 0, 0, 'M', 'J', 'U', '&', '*',
+    0, 0, '<', 'K', 'I', 'O', ')', '(', 0, 0, '>', '?', 'L', ':', 'P', '_', 0, 0,
+    0, '"', '{', '+', 0, 0, KEY_CAPSLK, KEY_RSHIFT, KEY_LF, '}', 0, '|', 0, 0, 0, 0, 0, 0, 0,
+    0, KEY_BS, 0, 0, KEY_NPAD(1), 0, KEY_NPAD(4), KEY_NPAD(7), 0, 0, 0, KEY_NPAD(0), ON_KEYPAD('.'),
+    KEY_NPAD(2), KEY_NPAD(5), KEY_NPAD(6), KEY_NPAD(8), KEY_ESC, KEY_NUMSLK, KEY_F11, ON_KEYPAD('+'),
+    KEY_NPAD(3), ON_KEYPAD('-'), ON_KEYPAD('*'), KEY_SCRLLK, 0, 0, 0, 0, KEY_F7
+};
+
+
+#define KBD_STATE_WAIT_KEY 0
+#define KBD_STATE_SPECIAL 1
+#define KBD_STATE_RELEASED 2
+
+void intr_ps2_kbd_handler(const isr_param* param);
+
+void ps2_device_post_cmd(char cmd, char arg) {
+    // FIXME: Need a mutex lock on this.
+    int index = (cmd_q.queue_ptr + cmd_q.queue_len) % PS2_CMD_QUEUE_SIZE;
+    int diff = index - cmd_q.queue_ptr;
+    if (diff > 0 && diff != cmd_q.queue_len) {
+        // 队列已满!
+        return;
+    }
+
+    struct ps2_cmd *container = &cmd_q.cmd_queue[index];
+    container->cmd = cmd;
+    container->arg = arg;
+    cmd_q.queue_len++;
+}
+
+void ps2_kbd_init() {
+
+    memset(&cmd_q, 0, sizeof(cmd_q));
+    memset(&key_buf, 0, sizeof(key_buf));
+    memset(&kbd_state, 0, sizeof(kbd_state));
+    kbd_state.translation_table = scancode_set2;
+    kbd_state.state = KBD_STATE_WAIT_KEY;
+
+    cpu_disable_interrupt();
+
+    // XXX: 是否需要使用FADT探测PS/2控制器的存在?
+
+    // 1、禁用任何的PS/2设备
+    ps2_post_cmd(PS2_CMD_PORT1_DISABLE, PS2_NO_ARG);
+    ps2_post_cmd(PS2_CMD_PORT2_DISABLE, PS2_NO_ARG);
+    
+    // 2、清空控制器缓冲区
+    io_inb(PS2_PORT_DATA);
+
+    char result;
+
+    // 3、屏蔽所有PS/2设备(端口1&2)IRQ,并且禁用键盘键码转换功能
+    result = ps2_issue_cmd(PS2_CMD_READ_CFG, PS2_NO_ARG);
+    result = result & ~(PS2_CFG_P1INT | PS2_CFG_P2INT | PS2_CFG_TRANSLATION);
+    ps2_post_cmd(PS2_CMD_WRITE_CFG, result);
+
+    // 4、控制器自检
+    result = ps2_issue_cmd(PS2_CMD_SELFTEST, PS2_NO_ARG);
+    if (result != PS2_RESULT_TEST_OK) {
+        kprintf(KERROR "Controller self-test failed.");
+        goto done;
+    }
+
+    // 5、设备自检(端口1自检,通常是我们的键盘)
+    result = ps2_issue_cmd(PS2_CMD_SELFTEST_PORT1, PS2_NO_ARG);
+    if (result != 0) {
+        kprintf(KERROR "Interface test on port 1 failed.");
+        goto done;
+    }
+
+    // 6、开启位于端口1的 IRQ,并启用端口1。不用理会端口2,那儿一般是鼠标。
+    ps2_post_cmd(PS2_CMD_PORT1_ENABLE, PS2_NO_ARG);
+    result = ps2_issue_cmd(PS2_CMD_READ_CFG, PS2_NO_ARG);
+    result = result | PS2_CFG_P1INT;
+    ps2_post_cmd(PS2_CMD_WRITE_CFG, result);
+
+    // 至此,PS/2控制器和设备已完成初始化,可以正常使用。
+
+    // 将我们的键盘驱动挂载到第204号中断上(已由IOAPIC映射至IRQ#1),
+    intr_subscribe(PC_KBD_IV, intr_ps2_kbd_handler);
+
+    // 搞一个计时器,将我们的 ps2_process_cmd 挂上去。每隔5毫秒执行排在队头的命令。
+    //  为什么只执行队头的命令,而不是全部的命令?
+    //      因为我们需要保证isr尽量的简短,运行起来快速。而发送这些命令非常的耗时。
+    timer_run_ms(5, ps2_process_cmd, NULL, TIMER_MODE_PERIODIC);
+
+done:
+    cpu_enable_interrupt();
+}
+
+void ps2_process_cmd(void* arg) {
+    // FIXME: Need a mutex lock on this.
+    // if lock is hold by other, then it just simply return (not wait! as we are in isr).
+    if (!cmd_q.queue_len) {
+        return;
+    }
+
+    // 处理队列排头的指令
+    struct ps2_cmd *pending_cmd = &cmd_q.cmd_queue[cmd_q.queue_ptr];
+    char result;
+    int attempts = 0;
+
+    // 尝试将命令发送至PS/2键盘(通过PS/2控制器)
+    // 如果不成功(0x60 IO口返回 0xfe,即 NAK 或 Resend)
+    // 则尝试最多五次
+    do {
+        result = ps2_issue_cmd(pending_cmd->cmd, pending_cmd->arg);
+        attempts++;
+    } while(result == PS2_RESULT_NAK && attempts < PS2_DEV_CMD_MAX_ATTEMPTS);
+    
+    // TODO: 是否需要处理不成功的指令?
+
+    cmd_q.queue_ptr = (cmd_q.queue_ptr + 1) % PS2_CMD_QUEUE_SIZE;
+    cmd_q.queue_len--;
+}
+
+void kbd_buffer_key_event(kbd_keycode key, uint8_t scancode, kbd_kstate_t state) {
+    if (key == KEY_CAPSLK) {
+        kbd_state.key_state = kbd_state.key_state ^ (KBD_KEY_CAPSLKED & -state);
+    } else if (key == KEY_NUMSLK) {
+        kbd_state.key_state = kbd_state.key_state ^ (KBD_KEY_NUMBLKED & -state);
+    } else if (key == KEY_SCRLLK) {
+        kbd_state.key_state = kbd_state.key_state ^ (KBD_KEY_SCRLLKED & -state);
+    } else {
+        state = state | kbd_state.key_state;
+        time_t timestamp = clock_systime();
+        // TODO: Construct the packet.
+        kprintf(KDEBUG "%c (t=%d, s=%x, c=%d)\n", key & 0x00ff, timestamp, state, (key & 0xff00) >> 8);
+        return; // do not delete this return
+    }
+
+    ps2_device_post_cmd(PS2_KBD_CMD_SETLED, kbd_state.key_state >> 1);
+}
+
+void intr_ps2_kbd_handler(const isr_param* param) {
+    uint8_t scancode = io_inb(PS2_PORT_DATA) & 0xff;
+    kbd_keycode key;
+
+    kprintf(KINFO "%x\n", scancode & 0xff);
+    
+    // FIXME: 实现 Shift+<key> 
+    switch (kbd_state.state)
+    {
+    case KBD_STATE_WAIT_KEY:
+        if (scancode == 0xf0) { // release code
+            kbd_state.state = KBD_STATE_RELEASED;       
+        } else if (scancode == 0xe0) {
+            kbd_state.state = KBD_STATE_SPECIAL;
+            kbd_state.translation_table = scancode_set2_ex;
+        } else {
+            key = kbd_state.translation_table[scancode];
+            kbd_buffer_key_event(key, scancode, KBD_KEY_PRESSED);
+        }
+        break;
+    case KBD_STATE_SPECIAL:
+        if (scancode == 0xf0) { //release code
+            kbd_state.state = KBD_STATE_RELEASED;       
+        } else {
+            key = kbd_state.translation_table[scancode];
+            kbd_buffer_key_event(key, scancode, KBD_KEY_PRESSED);
+
+            kbd_state.state = KBD_STATE_WAIT_KEY;
+            kbd_state.translation_table = scancode_set2;
+        }
+        break;
+    case KBD_STATE_RELEASED:
+        key = kbd_state.translation_table[scancode];
+        kbd_buffer_key_event(key, scancode, KBD_KEY_RELEASED);
+        
+        // reset the translation table to scancode_set2
+        kbd_state.translation_table = scancode_set2;
+        kbd_state.state = KBD_STATE_WAIT_KEY;   
+        break;
+    
+    default:
+        break;
+    }
+}
+
+static uint8_t ps2_issue_cmd(char cmd, uint16_t arg) {
+    ps2_post_cmd(cmd, arg);
+
+    char result;
+    
+    // 等待PS/2控制器返回。通过轮询(polling)状态寄存器的 bit 0
+    // 如置位,则表明返回代码此时就在 0x60 IO口上等待读取。
+    while(!((result = io_inb(PS2_PORT_STATUS)) & PS2_STATUS_OFULL));
+
+    return io_inb(PS2_PORT_DATA);
+}
+
+static void ps2_post_cmd(char cmd, uint16_t arg) {
+    char result;
+    // 等待PS/2输入缓冲区清空,这样我们才可以写入命令
+    while((result = io_inb(PS2_PORT_STATUS)) & PS2_STATUS_IFULL);
+
+    io_outb(PS2_PORT_CMDREG, cmd);
+    if (!(arg & PS2_NO_ARG)) {
+        io_outb(PS2_PORT_DATA, (uint8_t)(arg & 0x00ff));
+    }
+}
diff --git a/lunaix-os/kernel/time/clock.c b/lunaix-os/kernel/time/clock.c
new file mode 100644 (file)
index 0000000..e862f79
--- /dev/null
@@ -0,0 +1,78 @@
+#include <lunaix/clock.h>
+#include <lunaix/timer.h>
+#include <hal/rtc.h>
+#include <lunaix/spike.h>
+
+static volatile time_t sys_time;
+
+void clock_systime_counter(void* arg);
+
+void
+clock_init() {
+    if (!timer_context()) {
+        panick("Systimer not initialized");
+    }
+    
+    // 系统计时器每毫秒累加。
+    timer_run_ms(1, clock_systime_counter, NULL, TIMER_MODE_PERIODIC);
+}
+
+void clock_systime_counter(void* arg) {
+    sys_time++;
+}
+
+int
+clock_datatime_eq(datetime_t* a, datetime_t* b) {
+    return a->year == b->year &&
+           a->month == b->month &&
+           a->day == b->day &&
+           a->weekday == b->weekday &&
+           a->minute == b->minute &&
+           a->second == b->second;
+}
+
+void
+clock_walltime(datetime_t* datetime)
+{
+    datetime_t current;
+    
+    do
+    {
+        while (rtc_read_reg(RTC_REG_A) & 0x80);
+        memcpy(&current, datetime, sizeof(datetime_t));
+
+        datetime->year = rtc_read_reg(RTC_REG_YRS);
+        datetime->month = rtc_read_reg(RTC_REG_MTH);
+        datetime->day = rtc_read_reg(RTC_REG_DAY);
+        datetime->weekday = rtc_read_reg(RTC_REG_WDY);
+        datetime->hour = rtc_read_reg(RTC_REG_HRS);
+        datetime->minute = rtc_read_reg(RTC_REG_MIN);
+        datetime->second = rtc_read_reg(RTC_REG_SEC);
+    } while (!clock_datatime_eq(datetime, &current));
+
+    uint8_t regbv = rtc_read_reg(RTC_REG_B);
+
+    // Convert from bcd to binary when needed
+    if (!RTC_BIN_ENCODED(regbv)) {
+        datetime->year = bcd2dec(datetime->year);
+        datetime->month = bcd2dec(datetime->month);
+        datetime->day = bcd2dec(datetime->day);
+        datetime->hour = bcd2dec(datetime->hour);
+        datetime->minute = bcd2dec(datetime->minute);
+        datetime->second = bcd2dec(datetime->second);
+    }
+
+
+    // To 24 hour format
+    if (!RTC_24HRS_ENCODED(regbv) && (datetime->hour >> 7)) {
+        datetime->hour = (12 + datetime->hour & 0x80);
+    }
+
+    datetime->year += RTC_CURRENT_CENTRY * 100;
+}
+
+
+time_t 
+clock_systime() {
+    return sys_time;
+}
\ No newline at end of file
similarity index 90%
rename from lunaix-os/kernel/timer.c
rename to lunaix-os/kernel/time/timer.c
index 3a261ac7360c083d3545098dc0aca157a8a2544d..73bc0d5b8f25fdab712ae0be0c5b81b573da3cab 100644 (file)
@@ -15,7 +15,6 @@
 #include <lunaix/mm/kalloc.h>
 #include <lunaix/spike.h>
 #include <lunaix/syslog.h>
-#include <lunaix/time.h>
 #include <lunaix/timer.h>
 
 #define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector)
@@ -32,7 +31,7 @@ temp_intr_routine_apic_timer(const isr_param* param);
 static void
 timer_update(const isr_param* param);
 
-static volatile struct lx_timer_context* timer_ctx;
+static volatile struct lx_timer_context* timer_ctx = NULL;
 
 // Don't optimize them! Took me an half hour to figure that out...
 
@@ -117,7 +116,7 @@ timer_init(uint32_t frequency)
     kprintf(KINFO "Base frequency: %u Hz\n", timer_ctx->base_frequency);
 
     timer_ctx->running_frequency = frequency;
-    timer_ctx->tick_interval = timer_ctx->base_frequency / frequency;
+    timer_ctx->tps = timer_ctx->base_frequency / frequency;
 
     // cleanup
     intr_unsubscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer);
@@ -127,7 +126,7 @@ timer_init(uint32_t frequency)
                    LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_PERIODIC));
     intr_subscribe(APIC_TIMER_IV, timer_update);
 
-    apic_write_reg(APIC_TIMER_ICR, timer_ctx->tick_interval);
+    apic_write_reg(APIC_TIMER_ICR, timer_ctx->tps);
 }
 
 int
@@ -137,7 +136,13 @@ timer_run_second(uint32_t second, void (*callback)(void*), void* payload, uint8_
 }
 
 int
-timer_run(uint32_t ticks, void (*callback)(void*), void* payload, uint8_t flags)
+timer_run_ms(uint32_t millisecond, void (*callback)(void*), void* payload, uint8_t flags)
+{
+    return timer_run(timer_ctx->running_frequency / 1000 * millisecond, callback, payload, flags);
+}
+
+int
+timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags)
 {
     struct lx_timer* timer = (struct lx_timer*)lxmalloc(sizeof(struct lx_timer));
 
@@ -195,4 +200,9 @@ temp_intr_routine_apic_timer(const isr_param* param)
     apic_timer_done = 1;
 
     rtc_disable_timer();
+}
+
+struct lx_timer_context* 
+timer_context() {
+    return timer_ctx;
 }
\ No newline at end of file