• 从零开始操作系统-09:键盘实现


    这一节主要主要是键盘。

    所需要的文件在Github:https://github.com/yongkangluo/Ubuntu20.04OS/tree/main/Files/Lec7-ExternalInterrupt

    1. 初始化8042控制器
    2. 将键盘的硬件数据抽象封装
    3. 将封装好的键盘事件传送到上层

    在初始化8042时,不仅仅需要发送命令,同时要等待返回代码。

    static uint8_t ps2_issue_cmd(char cmd, uint16_t arg) {
    	// 发送命令
        ps2_post_cmd(PS2_PORT_CTRL_CMDREG, cmd, arg);
        char result;
        // 等待PS/2控制器返回。通过轮询(polling)状态寄存器的 bit 0
        // 如置位,则表明返回代码此时就在 0x60 IO口上等待读取。
        // 判断是否成功
        while(!((result = io_inb(PS2_PORT_CTRL_STATUS)) & PS2_STATUS_OFULL));
        return io_inb(PS2_PORT_ENC_CMDREG);
    }
    
    static void ps2_post_cmd(uint8_t port, char cmd, uint16_t arg) {
        char result;
        // 等待PS/2输入缓冲区清空,这样我们才可以写入命令
        while((result = io_inb(PS2_PORT_CTRL_STATUS)) & PS2_STATUS_IFULL);
        io_outb(port, cmd);
        if (!(arg & PS2_NO_ARG)) {
            // 所有参数一律通过0x60传入。
            io_outb(PS2_PORT_ENC_CMDREG, (uint8_t)(arg & 0x00ff));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    	//关中断
        cpu_disable_interrupt();
        // 1、禁用任何的PS/2设备
        // 读取20 读取配置字节
        ps2_post_cmd(PS2_PORT_CTRL_CMDREG, PS2_CMD_PORT1_DISABLE, PS2_NO_ARG);
        // 禁用0 1
        ps2_post_cmd(PS2_PORT_CTRL_CMDREG, PS2_CMD_PORT2_DISABLE, PS2_NO_ARG);
        // 2、清空控制器缓冲区
        io_inb(PS2_PORT_ENC_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_PORT_CTRL_CMDREG, 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_PORT_CTRL_CMDREG, 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_PORT_CTRL_CMDREG, PS2_CMD_WRITE_CFG, result);
        // 至此,PS/2控制器和设备已完成初始化,可以正常使用。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    键盘事件被封装成:

    struct kdb_keyinfo_pkt {
        kbd_scancode_t scancode;//扫描码
        kbd_keycode_t keycode;//键码
        kbd_kstate_t state;//键盘状态
        time_t timestamp;//时间戳
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注意:大小写锁定,shift、ctrl键等,不会被设置成信报,而是设置为状态。

    设计要点:

    1. 哪些键是按下的,哪些是释放的
    2. 一些开关状态,大小写锁定
    3. 一些短暂状态,识别组合键
    4. 跟踪shift
    5. 一些扫描码由两个字节构成

    向上层报告:

    利用一个有界的缓存队列。使用一个读指针和写指针。

  • 相关阅读:
    深度学习系列——“试错”发展直觉
    国际经济合作真题全集
    三维模型3DTile格式轻量化压缩文件大小的技术方法研究
    ubuntu 20.04.4+uWSGI+Nginx安装部署Django+Vue的web前后端全过程记录(2-Vue)
    IO 之 操作properties属性文件
    G. Good Key, Bad Key(思维)
    使用主成分分析进行模态分解(Matlab代码实现)
    【毕业设计】 python小游戏设计 -吃豆人小游戏
    右击图片出现Microsoft WinRT Storage API,点击提示找不到元素的解决思路
    Linux基础指令(一)
  • 原文地址:https://blog.csdn.net/lyk82698/article/details/128062390