Browse Source

:new: 用户态解析键盘扫描码

fslongjin 2 years ago
parent
commit
e6108602df

+ 0 - 1
kernel/common/glib.h

@@ -522,7 +522,6 @@ long strnlen_user(void *src, unsigned long maxlen)
 {
 
     unsigned long size = strlen(src);
-
     // 地址不合法
     if (!verify_area((uint64_t)src, size))
         return 0;

+ 17 - 270
kernel/driver/keyboard/ps2_keyboard.c

@@ -5,16 +5,15 @@
 #include "../../common/printk.h"
 #include <filesystem/VFS/VFS.h>
 #include <process/wait_queue.h>
+#include <process/spinlock.h>
 
 // 键盘输入缓冲区
 static struct ps2_keyboard_input_buffer *kb_buf_ptr = NULL;
 // 缓冲区等待队列
 static wait_queue_node_t ps2_keyboard_wait_queue;
 
-// 功能键标志变量
-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;
+// 缓冲区读写锁
+static spinlock_t ps2_kb_buf_rw_lock;
 
 /**
  * @brief 重置ps2键盘输入缓冲区
@@ -110,19 +109,25 @@ long ps2_keyboard_read(struct vfs_file_t *filp, char *buf, int64_t count, long *
     long counter = kb_buf_ptr->count >= count ? count : kb_buf_ptr->count;
 
     uint8_t *tail = kb_buf_ptr->ptr_tail;
+    int64_t tmp = (kb_buf_ptr->buffer + ps2_keyboard_buffer_size - tail);
 
     // 要读取的部分没有越过缓冲区末尾
-    if (counter <= (kb_buf_ptr->buffer + ps2_keyboard_buffer_size - tail))
+    if (counter <= tmp)
     {
         copy_to_user(buf, tail, counter);
         kb_buf_ptr->ptr_tail += counter;
+        // tail越界,则将其重新放置到起始位置
+        if (kb_buf_ptr->ptr_tail == kb_buf_ptr->buffer + ps2_keyboard_buffer_size)
+            kb_buf_ptr->ptr_tail = kb_buf_ptr->buffer;
     }
     else // 要读取的部分越过了缓冲区的末尾,进行循环
     {
-        uint64_t tmp = (kb_buf_ptr->buffer + ps2_keyboard_buffer_size - tail);
-        copy_to_user(buf, tail, tmp);
-        copy_to_user(buf, kb_buf_ptr->ptr_head, counter - tmp);
-        kb_buf_ptr->ptr_tail = kb_buf_ptr->ptr_head + (counter - tmp);
+
+        if (tmp > 0)
+            copy_to_user(buf, tail, tmp);
+        if (counter - tmp > 0)
+            copy_to_user(buf, kb_buf_ptr->buffer, counter - tmp);
+        kb_buf_ptr->ptr_tail = kb_buf_ptr->buffer + (counter - tmp);
     }
 
     kb_buf_ptr->count -= counter;
@@ -164,7 +169,6 @@ struct vfs_file_operations_t ps2_keyboard_fops =
  */
 void ps2_keyboard_handler(ul irq_num, ul param, struct pt_regs *regs)
 {
-    // 读取键盘输入的信息
     unsigned char x = io_in8(PORT_PS2_KEYBOARD_DATA);
     // printk_color(ORANGE, BLACK, "key_pressed:%02x\n", x);
 
@@ -229,15 +233,11 @@ void ps2_keyboard_init()
     for (int i = 0; i < 1000; ++i)
         for (int j = 0; j < 1000; ++j)
             nop();
-    shift_l = false;
-    shift_r = false;
-    ctrl_l = false;
-    ctrl_r = false;
-    alt_l = false;
-    alt_r = false;
 
     wait_queue_init(&ps2_keyboard_wait_queue, NULL);
-    
+    // 初始化键盘缓冲区的读写锁
+    spin_init(&ps2_kb_buf_rw_lock);
+
     // 注册中断处理程序
     irq_register(PS2_KEYBOARD_INTR_VECTOR, &entry, &ps2_keyboard_handler, (ul)kb_buf_ptr, &ps2_keyboard_intr_controller, "ps/2 keyboard");
     kdebug("kb registered.");
@@ -252,256 +252,3 @@ void ps2_keyboard_exit()
     irq_unregister(PS2_KEYBOARD_INTR_VECTOR);
     kfree((ul *)kb_buf_ptr);
 }
-
-/**
- * @brief 解析键盘扫描码
- *
- */
-void ps2_keyboard_analyze_keycode()
-{
-    bool flag_make = false;
-
-    int c = ps2_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 (ps2_keyboard_get_scancode() != pause_break_scan_code[i])
-            {
-                key = 0;
-                break;
-            }
-    }
-    else if (scancode == 0xE0) // 功能键, 有多个扫描码
-    {
-        // 获取下一个扫描码
-        scancode = ps2_keyboard_get_scancode();
-        switch (scancode)
-        {
-        case 0x2a: // print screen 按键被按下
-            if (ps2_keyboard_get_scancode() == 0xe0)
-                if (ps2_keyboard_get_scancode() == 0x37)
-                {
-                    key = PRINT_SCREEN;
-                    flag_make = true;
-                }
-            break;
-        case 0xb7: // print screen 按键被松开
-            if (ps2_keyboard_get_scancode() == 0xe0)
-                if (ps2_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, BLACK, "%c", key);
-    }
-}
-
-/**
- * @brief 从缓冲队列中获取键盘扫描码
- *
- */
-int ps2_keyboard_get_scancode()
-{
-    // 缓冲队列为空
-    if (kb_buf_ptr->count == 0)
-        return -1;
-
-    if (kb_buf_ptr->ptr_tail == kb_buf_ptr->buffer + ps2_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;
-}

+ 2 - 156
kernel/driver/keyboard/ps2_keyboard.h

@@ -5,7 +5,7 @@
 #define PS2_KEYBOARD_INTR_VECTOR 0x21   // 键盘的中断向量号
 
 // 定义键盘循环队列缓冲区大小为100bytes
-#define ps2_keyboard_buffer_size 100
+#define ps2_keyboard_buffer_size 8
 
 #define KEYBOARD_CMD_RESET_BUFFER 1
 
@@ -38,164 +38,10 @@ struct ps2_keyboard_input_buffer
 // 等待从键盘控制器读取信息完成
 #define wait_ps2_keyboard_read() while (io_in8(PORT_PS2_KEYBOARD_STATUS) & PS2_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
+extern struct vfs_file_operations_t ps2_keyboard_fops;
 
-// 键盘扫描码有三种:
-// 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*/	'\b',		'\b',		//BACKSPACE	
-/*0x0f*/	'\t',		'\t',		//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*/	'\n',		'\n',		//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 初始化键盘驱动程序的函数

+ 1 - 0
kernel/filesystem/VFS/VFS.h

@@ -28,6 +28,7 @@ struct vfs_superblock_t *vfs_root_sb = NULL;
  */
 #define VFS_ATTR_FILE (1UL << 0)
 #define VFS_ATTR_DIR (1UL << 1)
+#define VFS_ATTR_DEVICE (1UL << 2)
 
 struct vfs_super_block_operations_t;
 struct vfs_inode_operations_t;

+ 1 - 1
kernel/main.c

@@ -148,7 +148,7 @@ void system_initialize()
 
     smp_init();
     cpu_init();
-    // ps2_keyboard_init();
+    ps2_keyboard_init();
     // ps2_mouse_init();
     // ata_init();
     pci_init();

+ 25 - 4
kernel/syscall/syscall.c

@@ -7,6 +7,8 @@
 #include <common/errno.h>
 #include <common/fcntl.h>
 #include <filesystem/fat32/fat32.h>
+#include <filesystem/VFS/VFS.h>
+#include <driver/keyboard/ps2_keyboard.h>
 
 // 导出系统调用入口函数,定义在entry.S中
 extern void system_call(void);
@@ -108,8 +110,9 @@ uint64_t sys_open(struct pt_regs *regs)
 
     char *filename = (char *)(regs->r8);
     int flags = (int)(regs->r9);
+    kdebug("filename=%s", filename);
 
-    long path_len = strnlen_user(filename, PAGE_4K_SIZE);
+    long path_len = strnlen_user(filename, PAGE_4K_SIZE) + 1;
 
     if (path_len <= 0) // 地址空间错误
     {
@@ -130,20 +133,30 @@ uint64_t sys_open(struct pt_regs *regs)
 
     // 寻找文件
     struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0);
-    kfree(path);
 
     if (dentry != NULL)
         printk_color(ORANGE, BLACK, "Found %s\nDIR_FstClus:%#018lx\tDIR_FileSize:%#018lx\n", path, ((struct fat32_inode_info_t *)(dentry->dir_inode->private_inode_info))->first_clus, dentry->dir_inode->file_size);
     else
         printk_color(ORANGE, BLACK, "Can`t find file\n");
 
-    if (dentry == NULL)
+    kfree(path);
+    if (dentry == NULL) 
         return -ENOENT;
 
     // 暂时认为目标是目录是一种错误
     if (dentry->dir_inode->attribute == VFS_ATTR_DIR)
         return -EISDIR;
 
+    // todo: 引入devfs后删除这段代码
+    // 暂时遇到设备文件的话,就将其first clus设置为特定值
+    if (path_len >= 5 && filename[0] == '/' && filename[1] == 'd' && filename[2] == 'e' && filename[3] == 'v' && filename[4] == '/')
+    {
+        // 对于fat32文件系统上面的设备文件,设置其起始扇区
+        ((struct fat32_inode_info_t *)(dentry->dir_inode->private_inode_info))->first_clus |= 0xf0000000;
+        dentry->dir_inode->sb->sb_ops->write_inode(dentry->dir_inode);
+        dentry->dir_inode->attribute |= VFS_ATTR_DEVICE;
+    }
+
     // 创建文件描述符
     struct vfs_file_t *file_ptr = (struct vfs_file_t *)kmalloc(sizeof(struct vfs_file_t), 0);
     memset(file_ptr, 0, sizeof(struct vfs_file_t));
@@ -152,7 +165,15 @@ uint64_t sys_open(struct pt_regs *regs)
 
     file_ptr->dEntry = dentry;
     file_ptr->mode = flags;
-    file_ptr->file_ops = dentry->dir_inode->file_ops;
+
+    // todo: 接入devfs
+    // 特判一下是否为键盘文件
+    if (dentry->dir_inode->attribute & VFS_ATTR_DEVICE)
+    {
+        file_ptr->file_ops = &ps2_keyboard_fops; // 如果是设备文件,暂时认为它是键盘文件
+    }
+    else
+        file_ptr->file_ops = dentry->dir_inode->file_ops;
 
     // 如果文件系统实现了打开文件的函数
     if (file_ptr->file_ops && file_ptr->file_ops->open)

+ 1 - 2
user/Makefile

@@ -24,9 +24,8 @@ all:
 	objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O elf64-x86-64 sys_api_lib $(ROOT_PATH)/bin/user/init.bin
 
 sys_api_lib: init.o
-	
 
-	ld -b elf64-x86-64 -z muldefs -o sys_api_lib init.o  $(shell find . -name "*.o")
+	ld -b elf64-x86-64 -z muldefs -o sys_api_lib $(shell find . -name "*.o")
 #ld -b elf64-x86-64 -z muldefs -o sys_api_lib init.o $(shell find . -name "*.o") -T init.lds
 
 init.o: init.c 

+ 17 - 3
user/init.c

@@ -2,16 +2,28 @@
 #include <libc/stdio.h>
 #include <libc/fcntl.h>
 #include <libc/stdlib.h>
-
+#include <libKeyboard/keyboard.h>
 int main()
 {
 
-    char string[] = "333.txt";
+    char string[] = "/333.txt";
     uint8_t buf[128] = {0};
     char tips_str[] = "The first application 'init.bin' started successfully!\n";
     put_string(tips_str, COLOR_GREEN, COLOR_BLACK);
 
     printf("test printf: %s size: %d\n", string, sizeof(string));
+
+    char kb_file_path[] = "/dev/keyboard.dev";
+    int kb_fd = open(kb_file_path, 0);
+    printf("keyboard fd = %d\n", kb_fd);
+    while (true)
+    {
+        int key = keyboard_analyze_keycode(kb_fd);
+        if(key)
+            printf("%c", (char)key);
+    }
+    
+    
     /*
     int fd = open(string, 0);
     printf("fd=%d\n", fd);
@@ -31,7 +43,7 @@ int main()
     read(fd, buf, 128);
     put_string(buf, COLOR_YELLOW, COLOR_BLACK);
     close(fd);
-    */
+    
 
     void *ptr[256] = {0};
     for (int k = 0; k < 2; ++k)
@@ -57,6 +69,8 @@ int main()
         }
         printf("free done!\n");
     }
+    */
+    
 
     // *p = 'a';
     /*

+ 1 - 1
user/libs/Makefile

@@ -1,5 +1,5 @@
 
-user_libs_sub_dirs=libc libsystem
+user_libs_sub_dirs=libc libsystem libKeyboard
 
 
 all:

+ 7 - 0
user/libs/libKeyboard/Makefile

@@ -0,0 +1,7 @@
+all: keyboard.o
+
+CFLAGS += -I .
+
+
+keyboard.o: keyboard.c
+	gcc $(CFLAGS) -c keyboard.c -o keyboard.o

+ 530 - 0
user/libs/libKeyboard/keyboard.c

@@ -0,0 +1,530 @@
+#include "keyboard.h"
+#include <libc/unistd.h>
+// 功能键标志变量
+static bool shift_l = 0, shift_r = 0, ctrl_l = 0, ctrl_r = 0, alt_l = 0, alt_r = 0;
+static bool gui_l = 0, gui_r = 0, apps = 0, insert = 0, home = 0, pgup = 0, del = 0, end = 0, pgdn = 0, arrow_u = 0, arrow_l = 0, arrow_d = 0, arrow_r = 0;
+static bool kp_forward_slash = 0, kp_en = 0;
+
+// 键盘扫描码有三种:
+// 0xE1开头的PauseBreak键
+// 0xE0开头的功能键
+// 1byte的普通按键
+
+// pause break键的扫描码,没错,它就是这么长
+unsigned char pause_break_scan_code[] = {0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5};
+
+// 第一套键盘扫描码 及其对应的字符
+uint32_t 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*/ '\b',
+        '\b', // BACKSPACE
+        /*0x0f*/ '\t',
+        '\t', // 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*/ '\n',
+        '\n', // 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 解析键盘扫描码
+ *
+ */
+int keyboard_analyze_keycode(int fd)
+{
+    bool flag_make = false;
+
+    int c = keyboard_get_scancode(fd);
+    // 循环队列为空
+    if (c == -1)
+        return 0;
+
+    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(fd) != pause_break_scan_code[i])
+            {
+                key = 0;
+                break;
+            }
+    }
+    else if (scancode == 0xE0) // 功能键, 有多个扫描码
+    {
+        // 获取下一个扫描码
+        scancode = keyboard_get_scancode(fd);
+        switch (scancode)
+        {
+        case 0x2a: // print screen 按键被按下
+            if (keyboard_get_scancode(fd) == 0xe0)
+                if (keyboard_get_scancode(fd) == 0x37)
+                {
+                    key = PRINT_SCREEN;
+                    flag_make = true;
+                }
+            break;
+        case 0xb7: // print screen 按键被松开
+            if (keyboard_get_scancode(fd) == 0xe0)
+                if (keyboard_get_scancode(fd) == 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);
+
+        // 计算扫描码位于码表的第几行
+        uint32_t *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)
+            return key;
+    }
+    return 0;
+}
+
+/**
+ * @brief 从键盘设备文件中获取键盘扫描码
+ *
+ */
+int keyboard_get_scancode(int fd)
+{
+    unsigned int ret = 0;
+    read(fd, &ret, 1);
+    return ret;
+}

+ 22 - 0
user/libs/libKeyboard/keyboard.h

@@ -0,0 +1,22 @@
+#pragma once
+
+// 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
+
+/**
+ * @brief 从键盘设备文件中获取键盘扫描码
+ *
+ */
+int keyboard_get_scancode(int fd);
+
+/**
+ * @brief 解析键盘扫描码
+ *
+ */
+int keyboard_analyze_keycode(int fd);

+ 2 - 1
user/libs/libc/malloc.c

@@ -367,12 +367,13 @@ static void release_brk()
  *
  * @param ptr 堆内存的指针
  */
-void free(void *ptr)
+void free(void *ptr)    
 {
     // 找到结点(此时prev和next都处于未初始化的状态)
     malloc_mem_chunk_t *ck = (malloc_mem_chunk_t *)((uint64_t)ptr - sizeof(uint64_t));
     // printf("free(): addr = %#018lx\t len=%#018lx\n", (uint64_t)ck, ck->length);
     count_last_free_size += ck->length;
+    
     malloc_insert_free_list(ck);
 
     if (count_last_free_size > PAGE_2M_SIZE)