Browse Source

:new: 键盘驱动

fslongjin 3 years ago
parent
commit
1333afd703

+ 1 - 1
kernel/driver/acpi/acpi.c

@@ -58,7 +58,7 @@ bool acpi_get_MADT(const struct acpi_system_description_table_header_t *_iter_da
         return false;
     //*(struct acpi_Multiple_APIC_Description_Table_t *)_data = *(struct acpi_Multiple_APIC_Description_Table_t *)_iter_data;
     // 返回MADT的虚拟地址
-    *(ul*)_data = _iter_data;
+    *(ul*)_data = (ul)_iter_data;
     
     return true;
 }

+ 1 - 1
kernel/driver/interrupt/apic/apic.c

@@ -55,7 +55,7 @@ void apic_io_apic_init()
     apic_ioapic_map.virtual_EOI_addr = (uint *)(APIC_IO_APIC_VIRT_BASE_ADDR + 0x40);
 
     // 填写页表,完成地址映射
-    mm_map_phys_addr(apic_ioapic_map.virtual_index_addr, apic_ioapic_map.addr_phys, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+    mm_map_phys_addr((ul)apic_ioapic_map.virtual_index_addr, apic_ioapic_map.addr_phys, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
 
     // 设置IO APIC ID 为0x0f000000
     *apic_ioapic_map.virtual_index_addr = 0x00;

+ 269 - 11
kernel/driver/keyboard/keyboard.c

@@ -5,7 +5,12 @@
 #include "../../common/printk.h"
 
 static struct keyboard_input_buffer *kb_buf_ptr = NULL;
-static int shift_l, shift_r, ctrl_l, ctrl_r, alt_l, alt_r;
+
+// 功能键标志变量
+static bool shift_l, shift_r, ctrl_l, ctrl_r, alt_l, alt_r;
+static bool gui_l, gui_r, apps, insert, home, pgup, del, end, pgdn, arrow_u, arrow_l, arrow_d, arrow_r;
+static bool kp_forward_slash, kp_en;
+
 struct apic_IO_APIC_RTE_entry entry;
 
 hardware_intr_controller keyboard_intr_controller =
@@ -29,10 +34,10 @@ void keyboard_handler(ul irq_num, ul param, struct pt_regs *regs)
 {
     // 读取键盘输入的信息
     unsigned x = io_in8(0x60);
-    printk_color(ORANGE, BLACK, "key_pressed:%02x\n", x);
+    // printk_color(ORANGE, BLACK, "key_pressed:%02x\n", x);
 
     // 当头指针越过界时,恢复指向数组头部
-    if (kb_buf_ptr->ptr_head == kb_buf_ptr + keyboard_buffer_size)
+    if (kb_buf_ptr->ptr_head == kb_buf_ptr->buffer + keyboard_buffer_size)
         kb_buf_ptr->ptr_head = kb_buf_ptr->buffer;
 
     if (kb_buf_ptr->count >= keyboard_buffer_size)
@@ -56,8 +61,8 @@ void keyboard_init()
     // 申请键盘循环队列缓冲区的内存
     kb_buf_ptr = (struct keyboard_input_buffer *)kmalloc(sizeof(struct keyboard_input_buffer), 0);
 
-    kb_buf_ptr->ptr_head = kb_buf_ptr;
-    kb_buf_ptr->ptr_tail = kb_buf_ptr;
+    kb_buf_ptr->ptr_head = kb_buf_ptr->buffer;
+    kb_buf_ptr->ptr_tail = kb_buf_ptr->buffer;
     kb_buf_ptr->count = 0;
 
     memset(kb_buf_ptr->buffer, 0, keyboard_buffer_size);
@@ -89,12 +94,12 @@ void keyboard_init()
     for (int i = 0; i < 1000; ++i)
         for (int j = 0; j < 1000; ++j)
             nop();
-    shift_l = 0;
-    shift_r = 0;
-    ctrl_l = 0;
-    ctrl_r = 0;
-    alt_l = 0;
-    alt_r = 0;
+    shift_l = false;
+    shift_r = false;
+    ctrl_l = false;
+    ctrl_r = false;
+    alt_l = false;
+    alt_r = false;
 
     // 注册中断处理程序
     irq_register(0x21, &entry, &keyboard_handler, (ul)kb_buf_ptr, &keyboard_intr_controller, "ps/2 keyboard");
@@ -109,3 +114,256 @@ void keyboard_exit()
     irq_unregister(0x21);
     kfree((ul *)kb_buf_ptr);
 }
+
+/**
+ * @brief 解析键盘扫描码
+ *
+ */
+void keyboard_analyze_keycode()
+{
+    bool flag_make = false;
+
+    int c = keyboard_get_scancode();
+    // 循环队列为空
+    if (c == -1)
+        return;
+
+    unsigned char scancode = (unsigned char)c;
+
+    int key = 0;
+    if (scancode == 0xE1) // Pause Break
+    {
+        key = PAUSE_BREAK;
+        // 清除缓冲区中剩下的扫描码
+        for (int i = 1; i < 6; ++i)
+            if (keyboard_get_scancode() != pause_break_scan_code[i])
+            {
+                key = 0;
+                break;
+            }
+    }
+    else if (scancode == 0xE0) // 功能键, 有多个扫描码
+    {
+        // 获取下一个扫描码
+        scancode = keyboard_get_scancode();
+        switch (scancode)
+        {
+        case 0x2a: // print screen 按键被按下
+            if (keyboard_get_scancode() == 0xe0)
+                if (keyboard_get_scancode() == 0x37)
+                {
+                    key = PRINT_SCREEN;
+                    flag_make = true;
+                }
+            break;
+        case 0xb7: // print screen 按键被松开
+            if (keyboard_get_scancode() == 0xe0)
+                if (keyboard_get_scancode() == 0xaa)
+                {
+                    key = PRINT_SCREEN;
+                    flag_make = false;
+                }
+            break;
+        case 0x1d: // 按下右边的ctrl
+            ctrl_r = true;
+            key = OTHER_KEY;
+            break;
+        case 0x9d: // 松开右边的ctrl
+            ctrl_r = false;
+            key = OTHER_KEY;
+            break;
+        case 0x38: // 按下右边的alt
+            alt_r = true;
+            key = OTHER_KEY;
+            break;
+        case 0xb8: // 松开右边的alt
+            alt_r = false;
+            key = OTHER_KEY;
+            break;
+        case 0x5b:
+            gui_l = true;
+            key = OTHER_KEY;
+            break;
+        case 0xdb:
+            gui_l = false;
+            key = OTHER_KEY;
+            break;
+        case 0x5c:
+            gui_r = true;
+            key = OTHER_KEY;
+            break;
+        case 0xdc:
+            gui_r = false;
+            key = OTHER_KEY;
+            break;
+        case 0x5d:
+            apps = true;
+            key = OTHER_KEY;
+            break;
+        case 0xdd:
+            apps = false;
+            key = OTHER_KEY;
+            break;
+        case 0x52:
+            insert = true;
+            key = OTHER_KEY;
+            break;
+        case 0xd2:
+            insert = false;
+            key = OTHER_KEY;
+            break;
+        case 0x47:
+            home = true;
+            key = OTHER_KEY;
+            break;
+        case 0xc7:
+            home = false;
+            key = OTHER_KEY;
+            break;
+        case 0x49:
+            pgup = true;
+            key = OTHER_KEY;
+            break;
+        case 0xc9:
+            pgup = false;
+            key = OTHER_KEY;
+            break;
+        case 0x53:
+            del = true;
+            key = OTHER_KEY;
+            break;
+        case 0xd3:
+            del = false;
+            key = OTHER_KEY;
+            break;
+        case 0x4f:
+            end = true;
+            key = OTHER_KEY;
+            break;
+        case 0xcf:
+            end = false;
+            key = OTHER_KEY;
+            break;
+        case 0x51:
+            pgdn = true;
+            key = OTHER_KEY;
+            break;
+        case 0xd1:
+            pgdn = false;
+            key = OTHER_KEY;
+            break;
+        case 0x48:
+            arrow_u = true;
+            key = OTHER_KEY;
+            break;
+        case 0xc8:
+            arrow_u = false;
+            key = OTHER_KEY;
+            break;
+        case 0x4b:
+            arrow_l = true;
+            key = OTHER_KEY;
+            break;
+        case 0xcb:
+            arrow_l = false;
+            key = OTHER_KEY;
+            break;
+        case 0x50:
+            arrow_d = true;
+            key = OTHER_KEY;
+            break;
+        case 0xd0:
+            arrow_d = false;
+            key = OTHER_KEY;
+            break;
+        case 0x4d:
+            arrow_r = true;
+            key = OTHER_KEY;
+            break;
+        case 0xcd:
+            arrow_r = false;
+            key = OTHER_KEY;
+            break;
+
+        case 0x35: // 数字小键盘的 / 符号
+            kp_forward_slash = true;
+            key = OTHER_KEY;
+            break;
+        case 0xb5:
+            kp_forward_slash = false;
+            key = OTHER_KEY;
+            break;
+        case 0x1c:
+            kp_en = true;
+            key = OTHER_KEY;
+            break;
+        case 0x9c:
+            kp_en = false;
+            key = OTHER_KEY;
+            break;
+
+        default:
+            key = OTHER_KEY;
+            break;
+        }
+    }
+
+    if (key == 0) // 属于第三类扫描码
+    {
+        // 判断按键是被按下还是抬起
+        flag_make = ((scancode & FLAG_BREAK) ? 0 : 1);
+
+        // 计算扫描码位于码表的第几行
+        uint *key_row = &keycode_map_normal[(scancode & 0x7f) * MAP_COLS];
+        unsigned char col = 0;
+        // shift被按下
+        if (shift_l || shift_r)
+            col = 1;
+        key = key_row[col];
+
+        switch (scancode & 0x7f)
+        {
+        case 0x2a:
+            shift_l = flag_make;
+            key = 0;
+            break;
+        case 0x36:
+            shift_r = flag_make;
+            key = 0;
+            break;
+        case 0x1d:
+            ctrl_l = flag_make;
+            key = 0;
+            break;
+        case 0x38:
+            ctrl_r = flag_make;
+            key = 0;
+            break;
+        default:
+            if (!flag_make)
+                key = 0;
+            break;
+        }
+        if (key)
+            printk_color(ORANGE, WHITE, "(key:%c)\t", key);
+    }
+}
+
+/**
+ * @brief 从缓冲队列中获取键盘扫描码
+ *
+ */
+int keyboard_get_scancode()
+{
+    // 缓冲队列为空
+    if (kb_buf_ptr->count == 0)
+        return -1;
+
+    if (kb_buf_ptr->ptr_tail == kb_buf_ptr->buffer + keyboard_buffer_size)
+        kb_buf_ptr->ptr_tail = kb_buf_ptr->buffer;
+
+    int ret = (int)(*(kb_buf_ptr->ptr_tail));
+    --(kb_buf_ptr->count);
+    ++(kb_buf_ptr->ptr_tail);
+    return ret;
+}

+ 174 - 2
kernel/driver/keyboard/keyboard.h

@@ -34,14 +34,186 @@ struct keyboard_input_buffer
 // 等待从键盘控制器读取信息完成
 #define wait_keyboard_read() while (io_in8(PORT_KEYBOARD_STATUS) & KEYBOARD_FLAG_OUTBUF_FULL)
 
+// 128个按键, 每个按键包含普通按键和shift+普通按键两种状态
+#define NUM_SCAN_CODES 0x80
+#define MAP_COLS 2
+
+#define PAUSE_BREAK 1
+#define PRINT_SCREEN 2
+#define OTHER_KEY 4 // 除了上面两个按键以外的功能按键(不包括下面的第三类按键)
+#define FLAG_BREAK 0X80
+
+// 键盘扫描码有三种:
+// 0xE1开头的PauseBreak键
+// 0xE0开头的功能键
+// 1byte的普通按键
+
+// pause break键的扫描码,没错,它就是这么长
+unsigned char pause_break_scan_code[] = {0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5};
+
+// 第一套键盘扫描码 及其对应的字符
+uint keycode_map_normal[NUM_SCAN_CODES*MAP_COLS] = 
+{
+/*scan-code	unShift		Shift		*/
+/*--------------------------------------------------------------*/
+/*0x00*/	0,		0,
+/*0x01*/	0,		0,		//ESC
+/*0x02*/	'1',		'!',
+/*0x03*/	'2',		'@',
+/*0x04*/	'3',		'#',
+/*0x05*/	'4',		'$',
+/*0x06*/	'5',		'%',
+/*0x07*/	'6',		'^',
+/*0x08*/	'7',		'&',
+/*0x09*/	'8',		'*',
+/*0x0a*/	'9',		'(',
+/*0x0b*/	'0',		')',
+/*0x0c*/	'-',		'_',
+/*0x0d*/	'=',		'+',
+/*0x0e*/	0,		0,		//BACKSPACE	
+/*0x0f*/	0,		0,		//TAB
+
+/*0x10*/	'q',		'Q',
+/*0x11*/	'w',		'W',
+/*0x12*/	'e',		'E',
+/*0x13*/	'r',		'R',
+/*0x14*/	't',		'T',
+/*0x15*/	'y',		'Y',
+/*0x16*/	'u',		'U',
+/*0x17*/	'i',		'I',
+/*0x18*/	'o',		'O',
+/*0x19*/	'p',		'P',
+/*0x1a*/	'[',		'{',
+/*0x1b*/	']',		'}',
+/*0x1c*/	0,		0,		//ENTER
+/*0x1d*/	0x1d,		0x1d,		//CTRL Left
+/*0x1e*/	'a',		'A',
+/*0x1f*/	's',		'S',
+
+/*0x20*/	'd',		'D',
+/*0x21*/	'f',		'F',
+/*0x22*/	'g',		'G',
+/*0x23*/	'h',		'H',
+/*0x24*/	'j',		'J',
+/*0x25*/	'k',		'K',
+/*0x26*/	'l',		'L',
+/*0x27*/	';',		':',
+/*0x28*/	'\'',		'"',
+/*0x29*/	'`',		'~',
+/*0x2a*/	0x2a,		0x2a,		//SHIFT Left
+/*0x2b*/	'\\',		'|',
+/*0x2c*/	'z',		'Z',
+/*0x2d*/	'x',		'X',
+/*0x2e*/	'c',		'C',
+/*0x2f*/	'v',		'V',
+
+/*0x30*/	'b',		'B',
+/*0x31*/	'n',		'N',
+/*0x32*/	'm',		'M',
+/*0x33*/	',',		'<',
+/*0x34*/	'.',		'>',
+/*0x35*/	'/',		'?',
+/*0x36*/	0x36,		0x36,		//SHIFT Right
+/*0x37*/	'*',		'*',
+/*0x38*/	0x38,		0x38,		//ALT Left
+/*0x39*/	' ',		' ',
+/*0x3a*/	0,		0,		//CAPS LOCK
+/*0x3b*/	0,		0,		//F1
+/*0x3c*/	0,		0,		//F2
+/*0x3d*/	0,		0,		//F3
+/*0x3e*/	0,		0,		//F4
+/*0x3f*/	0,		0,		//F5
+
+/*0x40*/	0,		0,		//F6
+/*0x41*/	0,		0,		//F7
+/*0x42*/	0,		0,		//F8
+/*0x43*/	0,		0,		//F9
+/*0x44*/	0,		0,		//F10
+/*0x45*/	0,		0,		//NUM LOCK
+/*0x46*/	0,		0,		//SCROLL LOCK
+/*0x47*/	'7',		0,		/*PAD HONE*/
+/*0x48*/	'8',		0,		/*PAD UP*/
+/*0x49*/	'9',		0,		/*PAD PAGEUP*/
+/*0x4a*/	'-',		0,		/*PAD MINUS*/
+/*0x4b*/	'4',		0,		/*PAD LEFT*/
+/*0x4c*/	'5',		0,		/*PAD MID*/
+/*0x4d*/	'6',		0,		/*PAD RIGHT*/
+/*0x4e*/	'+',		0,		/*PAD PLUS*/
+/*0x4f*/	'1',		0,		/*PAD END*/
+
+/*0x50*/	'2',		0,		/*PAD DOWN*/
+/*0x51*/	'3',		0,		/*PAD PAGEDOWN*/
+/*0x52*/	'0',		0,		/*PAD INS*/
+/*0x53*/	'.',		0,		/*PAD DOT*/
+/*0x54*/	0,		0,
+/*0x55*/	0,		0,
+/*0x56*/	0,		0,
+/*0x57*/	0,		0,		//F11
+/*0x58*/	0,		0,		//F12
+/*0x59*/	0,		0,		
+/*0x5a*/	0,		0,
+/*0x5b*/	0,		0,
+/*0x5c*/	0,		0,
+/*0x5d*/	0,		0,
+/*0x5e*/	0,		0,
+/*0x5f*/	0,		0,
+
+/*0x60*/	0,		0,
+/*0x61*/	0,		0,
+/*0x62*/	0,		0,
+/*0x63*/	0,		0,
+/*0x64*/	0,		0,
+/*0x65*/	0,		0,
+/*0x66*/	0,		0,
+/*0x67*/	0,		0,
+/*0x68*/	0,		0,
+/*0x69*/	0,		0,
+/*0x6a*/	0,		0,
+/*0x6b*/	0,		0,
+/*0x6c*/	0,		0,
+/*0x6d*/	0,		0,
+/*0x6e*/	0,		0,
+/*0x6f*/	0,		0,
+
+/*0x70*/	0,		0,
+/*0x71*/	0,		0,
+/*0x72*/	0,		0,
+/*0x73*/	0,		0,
+/*0x74*/	0,		0,
+/*0x75*/	0,		0,
+/*0x76*/	0,		0,
+/*0x77*/	0,		0,
+/*0x78*/	0,		0,
+/*0x79*/	0,		0,
+/*0x7a*/	0,		0,
+/*0x7b*/	0,		0,
+/*0x7c*/	0,		0,
+/*0x7d*/	0,		0,
+/*0x7e*/	0,		0,
+/*0x7f*/	0,		0,
+};
+
 /**
  * @brief 初始化键盘驱动程序的函数
- * 
+ *
  */
 void keyboard_init();
 
 /**
  * @brief 键盘驱动卸载函数
+ *
+ */
+void keyboard_exit();
+
+/**
+ * @brief 解析键盘扫描码
  * 
  */
-void keyboard_exit();
+void keyboard_analyze_keycode();
+
+/**
+ * @brief 从缓冲队列中获取键盘扫描码
+ * @return 键盘扫描码
+ * 若缓冲队列为空则返回-1
+ */
+int keyboard_get_scancode();

+ 1 - 1
kernel/main.c

@@ -179,7 +179,7 @@ void Start_Kernel(void)
     // test_mm();
 
     while (1)
-        ;
+        keyboard_analyze_keycode();
 }
 
 void ignore_int()