From: Minep Date: Fri, 29 Apr 2022 23:29:02 +0000 (+0100) Subject: Basic PS/2 keyboard driver, and ... X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/80890b99fec2630ef0a1a0805d894c3d86c16506 Basic PS/2 keyboard driver, and ... A bit refactoring on timer related api; New clock api for accessing datatime & epoch stuff; New log level: debug, is implemented in kprintf. --- diff --git a/lunaix-os/hal/apic.c b/lunaix-os/hal/apic.c index 30951ef..0d427d1 100644 --- a/lunaix-os/hal/apic.c +++ b/lunaix-os/hal/apic.c @@ -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" ); diff --git a/lunaix-os/hal/ioapic.c b/lunaix-os/hal/ioapic.c index 80ab13b..de4be2a 100644 --- a/lunaix-os/hal/ioapic.c +++ b/lunaix-os/hal/ioapic.c @@ -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 diff --git a/lunaix-os/hal/rtc.c b/lunaix-os/hal/rtc.c index 0e3673c..2ffe76b 100644 --- a/lunaix-os/hal/rtc.c +++ b/lunaix-os/hal/rtc.c @@ -9,7 +9,6 @@ * */ #include -#include #include 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(¤t, 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, ¤t)); - - 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() { diff --git a/lunaix-os/includes/arch/x86/interrupts.h b/lunaix-os/includes/arch/x86/interrupts.h index 4ffc86f..2c93c39 100644 --- a/lunaix-os/includes/arch/x86/interrupts.h +++ b/lunaix-os/includes/arch/x86/interrupts.h @@ -35,11 +35,14 @@ #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 @@ -138,6 +141,9 @@ _asm_isr202(); void _asm_isr203(); +void +_asm_isr204(); + void _asm_isr210(); diff --git a/lunaix-os/includes/hal/apic.h b/lunaix-os/includes/hal/apic.h index f4ab92c..42a211e 100644 --- a/lunaix-os/includes/hal/apic.h +++ b/lunaix-os/includes/hal/apic.h @@ -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 index 0000000..dbfdfe5 --- /dev/null +++ b/lunaix-os/includes/lunaix/clock.h @@ -0,0 +1,36 @@ +#ifndef __LUNAIX_CLOCK_H +#define __LUNAIX_CLOCK_H + +#include + +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 index 0000000..f573316 --- /dev/null +++ b/lunaix-os/includes/lunaix/keyboard.h @@ -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 */ diff --git a/lunaix-os/includes/lunaix/mm/vmm.h b/lunaix-os/includes/lunaix/mm/vmm.h index 844eb0e..3e124fc 100644 --- a/lunaix-os/includes/lunaix/mm/vmm.h +++ b/lunaix-os/includes/lunaix/mm/vmm.h @@ -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 index 0000000..ca49cb7 --- /dev/null +++ b/lunaix-os/includes/lunaix/peripheral/ps2kbd.h @@ -0,0 +1,115 @@ +#ifndef __LUNAIX_PS2KBD_H +#define __LUNAIX_PS2KBD_H + +#include +#include +#include + +#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 */ diff --git a/lunaix-os/includes/lunaix/spike.h b/lunaix-os/includes/lunaix/spike.h index 9cf4b7f..8fd47b5 100644 --- a/lunaix-os/includes/lunaix/spike.h +++ b/lunaix-os/includes/lunaix/spike.h @@ -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 diff --git a/lunaix-os/includes/lunaix/syslog.h b/lunaix-os/includes/lunaix/syslog.h index 91e2003..545a803 100644 --- a/lunaix-os/includes/lunaix/syslog.h +++ b/lunaix-os/includes/lunaix/syslog.h @@ -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 index 522cc1f..0000000 --- a/lunaix-os/includes/lunaix/time.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __LUNAIX_TIME_H -#define __LUNAIX_TIME_H - -#include - -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 */ diff --git a/lunaix-os/includes/lunaix/timer.h b/lunaix-os/includes/lunaix/timer.h index 0c65ffd..1b36db5 100644 --- a/lunaix-os/includes/lunaix/timer.h +++ b/lunaix-os/includes/lunaix/timer.h @@ -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 */ diff --git a/lunaix-os/kernel/asm/x86/idt.c b/lunaix-os/kernel/asm/x86/idt.c index d11d6ed..5474743 100644 --- a/lunaix-os/kernel/asm/x86/idt.c +++ b/lunaix-os/kernel/asm/x86/idt.c @@ -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); diff --git a/lunaix-os/kernel/asm/x86/interrupt.S b/lunaix-os/kernel/asm/x86/interrupt.S index 11fe3fd..f05c3b8 100644 --- a/lunaix-os/kernel/asm/x86/interrupt.S +++ b/lunaix-os/kernel/asm/x86/interrupt.S @@ -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 diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index ce97b6e..74e3534 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include @@ -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)); diff --git a/lunaix-os/kernel/k_main.c b/lunaix-os/kernel/k_main.c index a78562a..b3b1103 100644 --- a/lunaix-os/kernel/k_main.c +++ b/lunaix-os/kernel/k_main.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include @@ -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, diff --git a/lunaix-os/kernel/kprintf.c b/lunaix-os/kernel/kprintf.c index 425fc22..a862bcc 100644 --- a/lunaix-os/kernel/kprintf.c +++ b/lunaix-os/kernel/kprintf.c @@ -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 index 0000000..4301fed --- /dev/null +++ b/lunaix-os/kernel/peripheral/ps2kbd.c @@ -0,0 +1,259 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#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+ 的情况 +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+ + 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 index 0000000..e862f79 --- /dev/null +++ b/lunaix-os/kernel/time/clock.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +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(¤t, 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, ¤t)); + + 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 diff --git a/lunaix-os/kernel/timer.c b/lunaix-os/kernel/time/timer.c similarity index 90% rename from lunaix-os/kernel/timer.c rename to lunaix-os/kernel/time/timer.c index 3a261ac..73bc0d5 100644 --- a/lunaix-os/kernel/timer.c +++ b/lunaix-os/kernel/time/timer.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #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