一个操作系统的实现 -- IO

一个操作系统的实现

最好的输入是输出

输入

综述

这里面有两个核心函数,keyboard_handler()keyboard_read() 。其中,keyboard_handler() 是键盘中断的处理程序,作用是将扫描码加入到缓冲区中。这个缓冲区,其实就是一个 队列p_tail 指向下一个要被处理的字节, p_head 指向下一个空闲的空间。而 keyboard_read 是我们的 tty 进程的守护程序,功能是从缓冲区读取扫描码并解析。

代码解析

keyboard_read() 这个函数中有一句

make = (scan_code & FLAG_BREAK ? FALSE : TRUE) ;

这一句的作用是判断扫描码是 make code 还是 break code,至于 Why it works ? ,解释如下:

纵观 make code 的键盘扫描码,除去 0xE0 0xE1 开头的,没有一个可打印的扫描码是 0x8X 或者以上的,或者说,两位十六进制的扫描码化成 8 位二进制后最高位没有是 1 的。所以,与上 FLAG_BREAK : 0x80 或者 10000000 能够将 make code 清零。


之前我在看这一部分的内容的时候,有一个问题总是不能理解,就是程序究竟是如何处理 shift 被长按的呢?下载终于有了解答:

我们的 keyboard_read() 每一次都只从缓冲区里面读出一个扫描码,所以如果是按下 shift 然后按下其他的键的,第一次首先处理 shift ,标志变量 shift_l 或者 shift_r 被置位,然后读取下一个扫描码,注意由于此时 shift 键没有松手,所以下一个读到的扫描码是你按完 shift 之后按的那个讲的扫描码,而不是 shift 键的 break code。由于 shift_l 或者 shift_r 已经被置位,所以在 扫描数组读的是第二列。注意,虽然我们的扫描数组是一个一维数组,不过这个是为了方便,操作时我们还是将它视作一个二位数组,变量 column 就是用来控制列的。这样,就可以处理 shfit 键被按下了。

TTY

目前 TTY 的作用就是能够控制输出的位置,它将我们的可用的 32k 显存分成了 3 块,每一块就是一个 TTY 。因为多了这样的一层,所以,在处理上也就多了一层。之前我们是这样子处理的:

按下键盘 -> 触发中断 -> 调用 keyboard_handler() -> keyboard_handler() 函数不断地将 扫描码 加入到缓冲区中 -> 任务 TTY (注意,它现在只是名字叫 TTY 而已,还不具备 TTY 的功能)不断地调用 keyboard_read() ,解析扫描码并且输出。

现在,我们有了 TTY ,可以实现 多终端 了,由于每一个 终端 都有自己的显示区间,所以,在显示的时候,过程就是这样:

按下键盘 -> 触发中断 -> 调用 keyboard_handler() -> keyboard_handler() 函数不断地将 扫描码 加入到缓冲区中 -> 任务 task_tty 设置好当前的终端 console ,再进行一系列的初始化 -> 其实 task_tty() 的任务主线就是一个守护进程, 不断轮询所有的 console ,对每个 console 都进行tty_do_write() 还有 tty_do_read 不停地切换。tty_do_read() 的作用是如果轮询到的 console 是当前终端的话,那么就从键盘缓冲区中读取一个扫描码并且进行解析,然后交给 in_process() 函数进行处理,这里的处理跟我们没有 多终端 的时候有一点区别。我们之前是直接输出,现在的话,是将解析之后的 key 放在当前 console 自己的缓冲区。 tty_do_write() 的作用就是在当前 console 的缓冲区里面读取一个已经解析好的 key 值,然后交给 out_char() 进行相应的输出。

这样,这个 TTY 的过程应该就相当的清晰了~

遇到的问题

  1. 今天,在编译的时候遇到了一个很奇怪的问题,一直报下面的错误:

     static declaration of ‘tty_do_read’ follows non-static declaration
    

    一直无解,百度以后,发现了错误的根源:

    出这个问题是把实现放在调用后面了
    C 语言里面要么需要先申明函数,要么就必须把函数实现放到函数调用之前

经验

前几天在实现 printf 的时候,出现了一个问题,然后解决无果。因此懈怠了很多天,今天终于把问题解决了。我发现,解决问题的方法就是从问题本身出发,根据问题找到相应的出错点,在找到相应的代码,一点一点地找,总会找到的。不过,这需要你对你的代码相当地熟悉。

这一章总算是结束了,向 下篇 进军!!!

EOF

Author: simowce

Permalink: https://blog.simowce.com/chapter-7-input/

知识共享许可协议
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。