os-xv6分析-设备管理-kbd.c 代码分析
// kbd.c 此文件定义了键盘中断处理函数kbdintr()和读取键值的
//kbdgetc()函数,工作与默认模式下,无单独的初始化函数
// 导包
#include "types.h"
#include "x86.h"
#include "defs.h"
#include "kbd.h"
int
kbdgetc(void) // 键盘中断处理函数,读取的按键扫描码保存在data中,Shitf
//和Ctrl等按键状态保存在shift静态变量中并根据情况做不同处理
{
static uint shift;
static uchar *charcode[4] = { // 4种转换用的码表
normalmap, shiftmap, ctlmap, ctlmap
};
uint st, data, c;
st = inb(KBSTATP); // 读入端口,0x64,状态字
if((st & KBS_DIB) == 0) // IBF标志为0,表示无扫描码
return -1;
data = inb(KBDATAP); // 读入数据,0x60端口,
if(data == 0xE0){ // 接受到EO开始的双字节扫描码
shift |= E0ESC; // 只需标记EOESC
return 0; //无法指定按键动作,需等待下一个扫描码
} else if(data & 0x80){ // 最高位为1,是释放按键的break码
// Key released // 无需返回ASCII码,但需要记录Shift相关按键状态
data = (shift & E0ESC ? data : data & 0x7F); // 上次是否为EOESC而不同
shift &= ~(shiftcode[data] | E0ESC); // 清楚Shift/Ctrl/Alt和E0状态
return 0;
} else if(shift & E0ESC){ // 上一个字节为EOESC
// Last character was an E0 escape; or with 0x80
data |= 0x80;
shift &= ~E0ESC; // 清楚EOESC位
}
shift |= shiftcode[data]; // 记录Shift/Ctrl/Alt键状态
shift ^= togglecode[data]; // toggle按键状态反转(异或操作)
c = charcode[shift & (CTL | SHIFT)][data]; // 确定用哪个表,并完成转换
if(shift & CAPSLOCK){
if('a' <= c && c <= 'z') // 小写->大写
c += 'A' - 'a';
else if('A' <= c && c <= 'Z') // 大写->小写
c += 'a' - 'A';
}
return c;
}
void
kbdintr(void) //读取按键值
{
consoleintr(kbdgetc); //调用consoleintr()将按键的ASCII码写入//input.buf[],consoleintr函数是和串口共用的,因//此,将kbdgetc()函数指针作为参数传入。
}