| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3747 人关注过本帖
标题:一步步写操作系统之第五步:进一步完善域结构并根据域结构重新编写键盘驱动
只看楼主 加入收藏
miaowangjian
Rank: 2
等 级:论坛游民
帖 子:34
专家分:30
注 册:2010-1-29
结帖率:100%
收藏
 问题点数:0 回复次数:4 
一步步写操作系统之第五步:进一步完善域结构并根据域结构重新编写键盘驱动
    此次,对域结构进行了进一步完善,除了“子域”的概念没有出来外,域结构的最基本特性已经展现出来了。下面就对“域”的一些特点进行一下简单总结。然后利用“域”来重新实现键盘驱动程序。
一个域,包含以下几个基本要素:
    1.生命值
    2.(主动)动作函数      //action 函数
    3.(被动)动作函数      //on 事件(函数)
    4.子域                //未实现

域结构的操作(相当于域结构的系统调用函数):
    1.运行域结构          //yu.c 中的run()函数
       (1)执行动作双向循环链表中的一个动作
       (2)执行.(被动)动作函数(on事件)列表里的所有函数
       (3)指向下一个(主动)动作
    2.加载(主动)动作函数  //向动作双向循环链表添加一个动作,见yu.c 中的AddAction(struct action_s *newAction)函数
    3.移除(主动)动作函数  //从动作双向循环链表移除一个动作,见yu.c 中的DelAction(struct action_s *delAction)函数
    4.注册一个on 事件     //可重复性的向on事件列表添加函数(p.s:(主动)动作函数具有唯一性)

域结构运行特点:
    动作周期:执行一遍run()函数,形成一个动作周期,在这个过程里,只有一个(主动)动作和以及执行此周期前的所有on 事件被执行,在此过程中,向on事件列表添加的函数,会在下一个动作周期执行。
    域周期:动作双向循环链表中所有的(主动)动作都被执行了一遍,形成一个域周期,在一个域周期内一个(主动)动作最多执行一遍,若在一个域周期内添加了新的(主动)动作,将会在周期结束时,或者说下各个域周期开始时被执行(若没有在此域周期内又被移除掉的话)。

    之所以要花费精力来将“域”的情况进行如上总结,是因为我以后将会完全利用域结构来实现这个操作系统,若不理解域的特性,就无法理解程序的内在逻辑。

    此次实现键盘驱动,我将键盘的字符输入功能和键盘作为控制器的控制功能分离开来,利用域结构的结构特点分别实现。主要实现的是将所有可显示字符的提取部分,控制部分,根据当前需要简单实现了几个。其他的控制功能,可以随时随意的添加,而不会对以实现部分有什么影响。

为了便于理解,先使用“域语言”伪代码描述一遍:
程序代码:
键盘域:
    数据:
        生命值:int kb_life = 0;
        shift状态:t_bool shift;
        CapsLock状态:t_bool capsLock;
        NumLock状态:t_bool numLock; 
        0xE0扫描码:t_bool on0xE0Flag;
        0xE1扫描码:t_bool on0xE1Flag;
        键码双缓冲池:struct keyBuf_s keyBuf[2];等…… //为了减少对键盘中断的影响,建立了一个双缓冲池结构,轮流提供给键盘中断保存键码
        键码字符映射表:t_32 keymap[NR_SCAN_CODES * 2];//用于将扫描码转换为相应字符
        按键动作映射表:struct on_s *keyOntable[0x100];//用于动态实现某个按钮的控制性功能

    主动函数:
        键码转字符:void ScanCodeToCharFun();          //读取键码缓冲池里的扫描码,提取与转换成对应的字符
        {
            交换键码双缓冲池,若缓冲池中无记录,退出函数。
            循环提取缓冲池中的扫描码:
                从缓冲池取得扫描码。
                若按下shift,从键码字符映射表的第二列中获取对应的字符,否则从第一列获取。
                若CapsLock键被按下且是字母,将大小写互换,
                   (否则)若扫描码是小键盘区的且NumLock键按下,重新获取在第二列中获取对应的字符。
                若获取的字符值为零,跳入下一循环。
                已经取得字符了,根据需要处理吧,这里就简单打印出来。
         }

    被动函数:
         键盘中断处理:void OnKeyEvent();  //这个是一个特殊的(被动)动作函数,它是由操作系统外部中断调用,与域的on事件区别在于,在任何时候都有可能发生,所以要编写得尽可能简练。
         {
             取得扫描码。
             根据扫描码,查找按键动作映射表中对应的被动函数,注册到on事件列表上。
             若键码转字符动作被禁止,或是中断码,不进行进一步处理,退出函数
             若缓冲池未满,将扫描码记录到缓冲池
         }
         Shift按下:void OnShiftDownFun();
         {
             标记Shift被按下,注册自身Shift松开
         }
         Shift松开:void OnShiftUpFun()
         {
             标记Shift松开,注册Shift按下
         }
         CapsLock点击:void OnCapsLockFun()
         {
             置反CapsLock状态值,重新注册自身
         }
         NumLock点击:void OnNumLockFun()
         {
             置反NumLock状态值,重新注册自身
         }
         ……
         ……

     当键码转字符执行时,生命值长,若生命值过大,生命值归零,注销键码转字符动作。
     当生命值为零时,若键盘中断处理执行时,加载键码转字符动作,生命值设为一。


    除了键盘驱动程序以外,此次,还对显示器(视频)的端口进行了简单的操控,实现上下移动显示区域,以防止屏幕显示超出时,看不到新新的显示内容。
在下一步里,将进一步完善它,并争取实现一个简单的tty。

    下面是此次新添加或有过修改的代码。

    在print.c中添加了一个换行函数,函数代码如下
程序代码:
void disp_next()//换行
{
asm{
  mov   eax, disp_pos         //求出下一行起始位置坐标
  mov   bl, 160
  div   bl
  and   eax, 0FFh
  inc   eax
  mov   bl, 160
  mul   bl
  mov   disp_pos, eax
}
}

code:kernel.c(改)
程序代码:
//文件:kernel.c
//功能:内核程序,先初始化各个模块驱动,然后循环调用域执行函数,运行域结构
//运行:run.exe自动会编译boot.c与生成img并调用Bochs运行此程序。
//作者:miao
//时间:2010-5-30

#define YCBIT 32  //告诉编译器,以32位格式编译程序
#define YCORG 0x0 //此值会对在编译时对变量函数等产生地址基址偏移量,简单起便,设置为0
#include "global.h"
#include "kernel.h"
#include "print.h"
#include "klib.h"
#include "i8259.h"
#include "yu.h"
#include "console.h"//要在keyboard.h之前,因为keyboard.h里用到了console.h的一些变量
#include "keyboard.h"

void init();

//内核入口点
asm void main()
{
  lgdt  cs:GdtPtr           //加载新的GDTR

  mov   eax, SelectorVideo
  mov   gs, ax              //视频段选择子(目的)
  mov   eax, SelectorData32 //令32位代码段的变量(printPlace)可以读写
  mov   ds, ax

  call  init        //初始化函数

  sti    //开中断
  jmp  kernel_main
}

void init()
{
  disp_str("================ init start =================\n");
 
  disp_str(" init idt -------------------------------- ");
  init_prot(); //初始化IDT
  disp_str("ok\n");
 
  disp_str(" init keyboard --------------------------- ");
  init_keyboard();//初始化键盘
  disp_str("ok\n");

  disp_str(" init yu\n");
  life = 100;//初始化根域生命值
 
  disp_str("----- init action ------------------------ ");
  AddAction(&nullAction);//测试action函数用,模拟光标的功能
  disp_str("ok\n");
 
  disp_str("----- init on ---------------------------- ");
  on_list.idx = 0;
  on_list.total = 0;
  on_list.flag = 1;

  AddOn(&nullOn2);//测试on事件用,打印一个等边三角形
  disp_str("ok\n");
 
  disp_str("================ init end ===================\n");
}

int kernel_main()
{
  while(life)
  {
    Run();
  }
  disp_str("================ yu end =====================\n");
  disp_str("died");
  while(1);
  return 0;
}

#include "print.c"
#include "klib.c"
#include "i8259.c"
#include "yu.c"
#include "keyboard.c"
#include "console.c"


code:yu.h(改)
程序代码:
//文件:yu.h
//功能:yu头文件,域结构需要用到的公共函数的声明等
//作者:miao
//时间:2010-5-30

#define NULL 0
#define NAME_MAX  32

typedef void (*action_fun)();
typedef void (*on_fun)();

//根域生命值(为零,退出域动作链表循环)
int life = 0;

//动作结构
struct action_s
{
  char name[NAME_MAX];    //动作名称
  action_fun run;         //动作调用的函数
  struct action_s *last;  //上一动作
  struct action_s *next;  //下一动作
};

//动作链表
struct actionList_s
{
  unsigned int count;    //动作计数器
  struct action_s *seek;  //当前动作
}actionList = {0,NULL};

//添加一个动作到动作链表表里
void AddAction(struct action_s *newAction);
//从动作链表里删除一个动作
void DelAction(struct action_s *delAction);
void Run(); //执行当前动作

void NullActionFun();//空动作,限制链表执行速度或将来用于管理动作链表
struct action_s nullAction = {"NullFun",&NullActionFun,NULL,NULL};

//on事件结构
struct on_s
{
  char name[NAME_MAX];    //on事件名称
  on_fun run;             //on调用的函数
  struct on_s *next;      //下一个on事件,暂时没有特别用处
  char state;             //保留,暂时没有特别用处
};

#define ON_LIST_MAX  100
//on事件表结构,双向向内增长堆栈
struct on_list_s
{
  struct on_s *list[ON_LIST_MAX]; //on事件堆栈(on事件可以重复)
  int idx;                        //指向lish空的地方
  int total;                      //堆栈中on事件的总数
  t_bool flag;                    //增长标记
}on_list;

//添加一个on事件到on队列(在on队列中on事件可重复添加)
void AddOn(struct on_s *newOn);

void NullOnFun1();//空on事件1
struct on_s nullOn1 = {"NullOn1",&NullOnFun1,NULL,1};
void NullOnFun2();//空on事件2
struct on_s nullOn2 = {"NullOn2",&NullOnFun2,NULL,2};


code:yu.c(改)
程序代码:
//文件:yu.c
//功能:域结构,管理一个动作双向链表,循环执行链表上的动作函数
//作者:miao
//时间:2010-5-30

//添加一个动作到动作链表里
void AddAction(struct action_s *newAction)
{
  disp_color_str("add:",MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH);
  disp_color_str((*newAction).name,MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH);

  if((*newAction).next != NULL)
  {
    disp_color_str("**add fail!!**",MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH);
    return;
  }
 
  if(actionList.count == 0)//若链表里没有元素
  {
    actionList.seek = newAction;
    (*newAction).next = newAction;
    (*newAction).last = newAction;
  }
  else//向动链表表添加一个动作到seek动作指针前
  {
    (*newAction).last = (*actionList.seek).last;
    (*newAction).next = actionList.seek;
   
    (*(*actionList.seek).last).next = newAction;
    (*actionList.seek).last = newAction;
  }
  actionList.count++;
  

}
//从动作链表里删除一个动作
void DelAction(struct action_s *delAction)
{
  disp_color_str(" del:",MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH);
  disp_color_str((*delAction).name,MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH);
  //disp_int(actionList.count);
 
  if((*delAction).next == NULL)
  {
    disp_color_str("**del fail!!**",MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH);
    return;
  }
 
  if(actionList.count == 0) return;//若链表里没有元素
 
  if(actionList.count == 1)
    actionList.seek = NULL;
  else  //将此动作从链表里移除
  {  
    (*(*delAction).last).next =(*delAction).next;
    (*(*delAction).next).last =(*delAction).last;
   
    actionList.seek = (*delAction).last;
  }
 
  (*delAction).next = NULL;
  (*delAction).last = NULL;
  actionList.count--;
}

//添加一个on函数到on队列
void AddOn(struct on_s *newOn)
{
  //disp_str("AddOn\n");
  if(on_list.total == ON_LIST_MAX)
  {
    disp_color_str("**on list full!!**",MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH);
    return;
  }
  on_list.list[on_list.idx] = newOn;
  on_list.idx += on_list.flag;
  on_list.total++;
}

int on_idx;
void Run()
{
  //执行当前动作
  if(actionList.seek != NULL)
  {
    (*actionList.seek).run();
  }

  //处理on事件的控制结构
  on_idx = on_list.idx;
  asm{cli}
  on_list.flag = -on_list.flag;//改变堆栈增长方向
  on_list.total=(on_list.idx+ON_LIST_MAX)%ON_LIST_MAX;
  on_list.idx=(on_list.flag == 1) ? 0 : ON_LIST_MAX -1;
  asm{sti}

  //一次性的执行on堆栈中的on事件
  for(int i = ((on_list.flag == 1)?ON_LIST_MAX -1:0); i != on_idx; i-=on_list.flag)
  {
    (*on_list.list[i]).run();
  }
 
  //指向下一个动作
  if(actionList.seek != NULL)
    actionList.seek = (*actionList.seek).next;
}

void sleep(int i);
//使用下面两个on函数打印一个等边三角形
//空on函数1
int testCount = 11;//testCount-2 == 等边三角形边长
void NullOnFun1()
{
  if(!testCount)  //停止存活
    return;

  disp_str("* ");
  AddOn(&nullOn1);//存活
}
//空on函数2
void NullOnFun2()
{
  if(testCount <= 0)  //停止存活
    return;
  disp_next();
  for(int i=0;i<testCount;i++)
    disp_str(" ");
  AddOn(&nullOn2);//存活
  AddOn(&nullOn1);//繁殖
  testCount--;
}

//空动作,限制链表执行速度或将来用于管理动作链表
void NullActionFun()
{
  disp_color_str(" ",MAKE_COLOR(WHITE,RED)| BRIGHT | FLASH);
  disp_pos-=2;
  sleep(100);
  disp_color_str(" ",MAKE_COLOR(BLUE,RED));
  disp_pos-=2;
  sleep(50);
}
void sleep(int i)
{
  while(i--)
  for(int i=0;i<100;i++)
  for(int j=0;j<100;j++);
}


code:keyboard.h(改)
程序代码:
//文件:keyboard.h
//功能:keyboard头文件,内核需要用到的公共函数的声明等
//作者:miao
//时间:2010-5-30

//AT(大口)键盘 8042端口
//键盘数据端口 读:读取输出缓冲器 写:写入输入缓冲器(8042 Data&8048 Command)
#define  KB_DATA   0x60
//键盘命令端口 读:读取状态寄存器 写:写入输入缓冲器(8042 Command)
#define  KB_CMD    0x64

#define  LED_CODE  0xED
#define  KB_ACK    0xFA

#define NR_SCAN_CODES  0x54  //扫描码的数目(keymap的行数)除去最后面的不可显示字符的部分

t_32 keymap[NR_SCAN_CODES * 2] = {
//shift未按下   shift按下    扫描码
//!Shift        Shift        scan code
  0,            0,           //0x00 - none
  0,            0,           //0x01 - ESC
  '1',          '!',         //0x02 - '1'
  '2',          '@',         //0x03 - '2'
  '3',          '#',         //0x04 - '3'
  '4',          '$',         //0x05 - '4'
  '5',          '%',         //0x06 - '5'
  '6',          '^',         //0x07 - '6'
  '7',          '&',         //0x08 - '7'
  '8',          '*',         //0x09 - '8'
  '9',          '(',         //0x0A - '9'
  '0',          ')',         //0x0B - '0'
  '-',          '_',         //0x0C - '-'
  '=',          '+',         //0x0D - '='
  0,            0,           //0x0E - BS 
  0,            0,           //0x0F - TAB
  'q',          'Q',         //0x10 - 'q'
  'w',          'W',         //0x11 - 'w'
  'e',          'E',         //0x12 - 'e'
  'r',          'R',         //0x13 - 'r'
  't',          'T',         //0x14 - 't'
  'y',          'Y',         //0x15 - 'y'
  'u',          'U',         //0x16 - 'u'
  'i',          'I',         //0x17 - 'i'
  'o',          'O',         //0x18 - 'o'
  'p',          'P',         //0x19 - 'p'
  '[',          '{',         //0x1A - '['
  ']',          '}',         //0x1B - ']'
  0,            0,           //0x1C - CR/LF
  0,            0,           //0x1D - l. Ctrl
  'a',          'A',         //0x1E - 'a'
  's',          'S',         //0x1F - 's'
  'd',          'D',         //0x20 - 'd'
  'f',          'F',         //0x21 - 'f'
  'g',          'G',         //0x22 - 'g'
  'h',          'H',         //0x23 - 'h'
  'j',          'J',         //0x24 - 'j'
  'k',          'K',         //0x25 - 'k'
  'l',          'L',         //0x26 - 'l'
  ';',          ':',         //0x27 - ';'
  '\'',         '"',         //0x28 - '\''
  '`',          '~',         //0x29 - '`'
  0,            0,           //0x2A - l. SHIFT
  '\\',         '|',         //0x2B - '\'
  'z',          'Z',         //0x2C - 'z'
  'x',          'X',         //0x2D - 'x'
  'c',          'C',         //0x2E - 'c'
  'v',          'V',         //0x2F - 'v'
  'b',          'B',         //0x30 - 'b'
  'n',          'N',         //0x31 - 'n'
  'm',          'M',         //0x32 - 'm'
  ',',          '<',         //0x33 - ','
  '.',          '>',         //0x34 - '.'
  '/',          '?',         //0x35 - '/'
  0,            0,           //0x36 - r. SHIFT 
  '*',          '*',         //0x37 - '*'
  0,            0,           //0x38 - ALT
  ' ',          ' ',         //0x39 - ' '
  0,            0,           //0x3A - CapsLock
  0,            0,           //0x3B - F1
  0,            0,           //0x3C - F2
  0,            0,           //0x3D - F3
  0,            0,           //0x3E - F4
  0,            0,           //0x3F - F5
  0,            0,           //0x40 - F6
  0,            0,           //0x41 - F7
  0,            0,           //0x42 - F8
  0,            0,           //0x43 - F9
  0,            0,           //0x44 - F10
  0,            0,           //0x45 - NumLock
  0,            0,           //0x46 - ScrLock
  0,            '7',         //0x47 - Home
  0,            '8',         //0x48 - CurUp
  0,            '9',         //0x49 - PgUp
  0,            '-',         //0x4A - '-'
  0,            '4',         //0x4B - Left
  0,            '5',         //0x4C - MID
  0,            '6',         //0x4D - Right
  0,            '+',         //0x4E - '+'
  0,            '1',         //0x4F - End
  0,            '2',         //0x50 - Down
  0,            '3',         //0x51 - PgDown 
  0,            '0',         //0x52 - Insert
  0,            '.',         //0x53 - Delete
};

#define KEY_BUF_MAX    32  //键盘输入缓冲区大小
struct keyBuf_s
{
  int idx;               //缓冲区中共有多少字节
  char buf[KEY_BUF_MAX];  //缓冲区
};

void OnKeyEvent();  //键盘中断处理函数

//键盘服务系统相关
int kb_life = 0;
struct keyBuf_s keyBuf[2]; //为了减少对键盘中断的影响,采用双缓冲方式
struct keyBuf_s *busyKeyBuf=&keyBuf[0];//指向键盘中断正在使用的缓冲区
struct keyBuf_s *freeKeyBuf=&keyBuf[1];//指向空闲(待处理)的缓冲区
struct keyBuf_s *keyBufPoint = busyKeyBuf;//键盘中断使用这个缓冲区

t_bool   shift;                  // shift 状态
t_bool   capsLock;               // Caps Lock 状态
t_bool   numLock;                // Num Lock 状态
t_bool   on0xE0Flag;             // 收到0xE0扫描码
t_bool   on0xE1Flag;             // 收到0xE1扫描码

void init_keyboard();//初始化键盘

void ScanCodeToCharFun();//键码转字符动作函数
struct action_s scanCodeToChar = {"scanCodeToChar",&ScanCodeToCharFun,NULL,NULL};

//和字符处理结合的键盘事件
void OnShiftDownFun();
struct on_s onShiftDown = {"onShiftDown",&OnShiftDownFun,NULL,NULL};
void OnShiftUpFun();
struct on_s onShiftUp = {"onShiftUp",&OnShiftUpFun,NULL,NULL};
void OnCapsLockFun();
struct on_s onCapsLock = {"OnLineDown",&OnCapsLockFun,NULL,NULL};
void OnNumLockFun();
struct on_s onNumLock = {"OnPageUp",&OnNumLockFun,NULL,NULL};

//若碰到E0和E1组合的功能键必须处理,否则可显示字符处理程序会被锁住
void On0xE0Fun();
struct on_s on0xE0 = {"On0xE0",&On0xE0Fun,NULL,NULL};
void On0xE1Fun();
struct on_s on0xE1 = {"On0xE1",&On0xE1Fun,NULL,NULL};

//为所有扫描码或中断码建立一个on事件指针表,根据需要动态管理此表来实现键盘控制功能
struct on_s *keyOntable[0x100] = {
  //前 0x80个都是扫描码(键盘按下)
  NULL,         //0x00 - none
  NULL,         //0x01 - ESC
  NULL,         //0x02 - '1'
  NULL,         //0x03 - '2'
  NULL,         //0x04 - '3'
  NULL,         //0x05 - '4'
  NULL,         //0x06 - '5'
  NULL,         //0x07 - '6'
  NULL,         //0x08 - '7'
  NULL,         //0x09 - '8'
  NULL,         //0x0A - '9'
  NULL,         //0x0B - '0'
  NULL,         //0x0C - '-'
  NULL,         //0x0D - '='
  NULL,         //0x0E - BS 
  NULL,         //0x0F - TAB
  NULL,         //0x10 - 'q'
  NULL,         //0x11 - 'w'
  NULL,         //0x12 - 'e'
  NULL,         //0x13 - 'r'
  NULL,         //0x14 - 't'
  NULL,         //0x15 - 'y'
  NULL,         //0x16 - 'u'
  NULL,         //0x17 - 'i'
  NULL,         //0x18 - 'o'
  NULL,         //0x19 - 'p'
  NULL,         //0x1A - '['
  NULL,         //0x1B - ']'
  NULL,         //0x1C - CR/LF
  NULL,         //0x1D - l. Ctrl
  NULL,         //0x1E - 'a'
  NULL,         //0x1F - 's'
  NULL,         //0x20 - 'd'
  NULL,         //0x21 - 'f'
  NULL,         //0x22 - 'g'
  NULL,         //0x23 - 'h'
  NULL,         //0x24 - 'j'
  NULL,         //0x25 - 'k'
  NULL,         //0x26 - 'l'
  NULL,         //0x27 - ';'
  NULL,         //0x28 - '\''
  NULL,         //0x29 - '`'
  &onShiftDown, //0x2A - l. SHIFT
  NULL,         //0x2B - '\'
  NULL,         //0x2C - 'z'
  NULL,         //0x2D - 'x'
  NULL,         //0x2E - 'c'
  NULL,         //0x2F - 'v'
  NULL,         //0x30 - 'b'
  NULL,         //0x31 - 'n'
  NULL,         //0x32 - 'm'
  NULL,         //0x33 - ','
  NULL,         //0x34 - '.'
  NULL,         //0x35 - '/'
  &onShiftDown, //0x36 - r. SHIFT 
  NULL,         //0x37 - '*'
  NULL,         //0x38 - ALT
  NULL,         //0x39 - ' '
  &onCapsLock,  //0x3A - CapsLock
  NULL,         //0x3B - F1
  NULL,         //0x3C - F2
  NULL,         //0x3D - F3
  NULL,         //0x3E - F4
  NULL,         //0x3F - F5
  NULL,         //0x40 - F6
  NULL,         //0x41 - F7
  NULL,         //0x42 - F8
  NULL,         //0x43 - F9
  NULL,         //0x44 - F10
  &onNumLock,   //0x45 - NumLock
  NULL,         //0x46 - ScrLock
  NULL,         //0x47 - Home
  &onLineUp,    //0x48 - CurUp
  &onPageUp,    //0x49 - PgUp
  NULL,         //0x4A - '-'
  NULL,         //0x4B - Left
  NULL,         //0x4C - MID
  NULL,         //0x4D - Right
  NULL,         //0x4E - '+'
  NULL,         //0x4F - End
  &onLineDown,  //0x50 - Down
  &onPageDown,  //0x51 - PgDown
  NULL,         //0x52 - Insert
  NULL,         //0x53 - Delete
  NULL,         //0x54 - Enter
  NULL,         //0x55 - ???
  NULL,         //0x56 - ???
  NULL,         //0x57 - F11
  NULL,         //0x58 - F12
  NULL,         //0x59 - ???
  NULL,         //0x5A - ???
  NULL,         //0x5B - ???
  NULL,         //0x5C - ???
  NULL,         //0x5D - ???
  NULL,         //0x5E - ???
  NULL,         //0x5F - ???
  NULL,         //0x60 - ???
  NULL,         //0x61 - ???
  NULL,         //0x62 - ???
  NULL,         //0x63 - ???
  NULL,         //0x64 - ???
  NULL,         //0x65 - ???
  NULL,         //0x66 - ???
  NULL,         //0x67 - ???
  NULL,         //0x68 - ???
  NULL,         //0x69 - ???
  NULL,         //0x6A - ???
  NULL,         //0x6B - ???
  NULL,         //0x6C - ???
  NULL,         //0x6D - ???
  NULL,         //0x6E - ???
  NULL,         //0x6F - ???
  NULL,         //0x70 - ???
  NULL,         //0x71 - ???
  NULL,         //0x72 - ???
  NULL,         //0x73 - ???
  NULL,         //0x74 - ???
  NULL,         //0x75 - ???
  NULL,         //0x76 - ???
  NULL,         //0x77 - ???
  NULL,         //0x78 - ???
  NULL,         //0x79 - ???
  NULL,         //0x7A - ???
  NULL,         //0x7B - ???
  NULL,         //0x7C - ???
  NULL,         //0x7D - ???
  NULL,         //0x7E - ???
  NULL,         //0x7F - ???
  //后面 0x80个都是中断码(键盘按键放开)
  NULL,         //0x80 - none
  NULL,         //0x81 - ESC
  NULL,         //0x82 - '1'
  NULL,         //0x83 - '2'
  NULL,         //0x84 - '3' 
  NULL,         //0x85 - '4'
  NULL,         //0x86 - '5'
  NULL,         //0x87 - '6'
  NULL,         //0x88 - '7'
  NULL,         //0x89 - '8'
  NULL,         //0x8A - '9'
  NULL,         //0x8B - '0'
  NULL,         //0x8C - '-'
  NULL,         //0x8D - '='
  NULL,         //0x8E - BS
  NULL,         //0x8F - TAB
  NULL,         //0x90 - 'q'
  NULL,         //0x91 - 'w'
  NULL,         //0x92 - 'e'
  NULL,         //0x93 - 'r'
  NULL,         //0x94 - 't'
  NULL,         //0x95 - 'y'
  NULL,         //0x96 - 'u'
  NULL,         //0x97 - 'i'
  NULL,         //0x98 - 'o'
  NULL,         //0x99 - 'p'
  NULL,         //0x9A - '['
  NULL,         //0x9B - ']'
  NULL,         //0x9C - CR/LF
  NULL,         //0x9D - l. Ctrl
  NULL,         //0x9E - 'a'
  NULL,         //0x9F - 's'
  NULL,         //0xA0 - 'd' 
  NULL,         //0xA1 - 'f'
  NULL,         //0xA2 - 'g'
  NULL,         //0xA3 - 'r'
  NULL,         //0xA4 - 'j'
  NULL,         //0xA5 - 'k'
  NULL,         //0xA6 - 'l'
  NULL,         //0xA7 - ';'
  NULL,         //0xA8 - '\''
  NULL,         //0xA9 - '`'
  &onShiftUp,   //0xAA - l. SHIFT
  NULL,         //0xAB - '\'
  NULL,         //0xAC - 'z'
  NULL,         //0xAD - 'x'
  NULL,         //0xAE - 'c'
  NULL,         //0xAF - 'v'
  NULL,         //0xB0 - 'b'
  NULL,         //0xB1 - 'n'
  NULL,         //0xB2 - 'm'
  NULL,         //0xB3 - ','
  NULL,         //0xB4 - '.'
  NULL,         //0xB5 - '/'
  &onShiftUp,   //0xB6 - r. SHIFT 
  NULL,         //0xB7 - '*'
  NULL,         //0xB8 - ALT
  NULL,         //0xB9 - ' '
  NULL,         //0xBA - CapsLock
  NULL,         //0xBB - F1
  NULL,         //0xBC - F2
  NULL,         //0xBD - F3
  NULL,         //0xBE - F4
  NULL,         //0xBF - F5
  NULL,         //0xC0 - F6
  NULL,         //0xC1 - F7
  NULL,         //0xC2 - F8
  NULL,         //0xC3 - F9
  NULL,         //0xC4 - F10
  NULL,         //0xC5 - NumLock
  NULL,         //0xC6 - ScrLock
  NULL,         //0xC7 - Home
  NULL,         //0xC8 - CurUp
  NULL,         //0xC9 - PgUp
  NULL,         //0xCA - '-'
  NULL,         //0xCB - Left
  NULL,         //0xCC - MID
  NULL,         //0xCD - Right
  NULL,         //0xCE - '+'
  NULL,         //0xCF - End
  &on0xE0,      //0xE0 - Down
  &on0xE1,      //0xE1 - PgDown
  NULL,         //0xE2 - Insert
  NULL,         //0xE3 - Delete
  NULL,         //0xE4 - Enter
  NULL,         //0xE5 - ???
  NULL,         //0xE6 - ???
  NULL,         //0xE7 - F11
  NULL,         //0xE8 - F12
  NULL,         //0xE9 - ???
  NULL,         //0xEA - ???
  NULL,         //0xEB - ???
  NULL,         //0xEC - ???
  NULL,         //0xED - ???
  NULL,         //0xEE - ???
  NULL,         //0xEF - ???
  NULL,         //0xF0 - ???
  NULL,         //0xF1 - ???
  NULL,         //0xF2 - ???
  NULL,         //0xF3 - ???
  NULL,         //0xF4 - ???
  NULL,         //0xF5 - ???
  NULL,         //0xF6 - ???
  NULL,         //0xF7 - ???
  NULL,         //0xF8 - ???
  NULL,         //0xF9 - ???
  NULL,         //0xFA - ???
  NULL,         //0xFB - ???
  NULL,         //0xFC - ???
  NULL,         //0xFD - ???
  NULL,         //0xFE - ???
  NULL,         //0xFF - ???
  NULL,         //0xF0 - ???
  NULL,         //0xF1 - ???
  NULL,         //0xF2 - ???
  NULL,         //0xF3 - ???
  NULL,         //0xF4 - ???
  NULL,         //0xF5 - ???
  NULL,         //0xF6 - ???
  NULL,         //0xF7 - ???
  NULL,         //0xF8 - ???
  NULL,         //0xF9 - ???
  NULL,         //0xFA - ???
  NULL,         //0xFB - ???
  NULL,         //0xFC - ???
  NULL,         //0xFD - ???
  NULL,         //0xFE - ???
  NULL,         //0xFF - ???
};


code:keyboard.c(改)
程序代码:
//文件:keyboard.c
//功能:初始化键盘、以及设置中断相关的函数
//作者:miao
//时间:2010-5-30

//键盘中断处理函数
void OnKeyEvent()
{
  t_8 scan_code = in_byte(KB_DATA); //获取扫描码
  //disp_int(scan_code);
  //disp_str(" ");
  //return;
 
  //处理属于控制性质的按键扫描码
  struct on_s *keyOnPoin = keyOntable[scan_code];
  if(keyOnPoin != NULL)
  {
    AddOn(keyOnPoin);  //加入On事件队列
    keyOntable[scan_code]=NULL;
  }

  //处理属于字符扫描码
  //键盘域生命值为负,表示不需要对字符扫描码,同时排除中断码
  if(kb_life<0 || scan_code >= 0x80 )//|| on0xE0Flag || on0xE1Flag)
    return ;            //在实现所有E0,E1的功能键时,需要过滤掉功能键对应的可显示字符
 
  //将扫描法放入缓冲区
  if(keyBufPoint->idx < KEY_BUF_MAX)     //若缓冲区未满,记录信息
  {
    keyBufPoint->buf[keyBufPoint->idx++] = scan_code;  //记录扫描码
  }
  else
    disp_color_str("**keyBuf full!!**",MAKE_COLOR(BLUE,RED)|BRIGHT|FLASH);

  if(kb_life==0)//当键盘生命值为零,表示键盘字符处理动作不在执行链表里
  {
    kb_life=1;
    AddAction(&scanCodeToChar);//加载键盘服务域
  }
}

void InitKeyOnEvent(struct on_s *newOn,  t_8 scan_code)
{
  (*newOn).next = keyOntable[scan_code];
  keyOntable[scan_code]=newOn;
}

void OnShiftDownFun()
{
  if(shift==1)
    return;

  shift = 1;
  InitKeyOnEvent(onShiftUp,0xAA);
  return;
}
void OnShiftUpFun()
{
  shift = 0;
  InitKeyOnEvent(onShiftDown,0x2A);
  return;
}

void OnCapsLockFun()
{
  capsLock = !capsLock;
  InitKeyOnEvent(onCapsLock,0x3A);
  return;
}
void OnNumLockFun()
{
  numLock = !numLock;
  InitKeyOnEvent(onNumLock,0x45);
  return;
}

void On0xE0Fun()
{
  disp_str("On0xE0Fun ");
  on0xE0Flag = 1;
  return;
}
void On0xE1Fun()
{
  disp_str("On0xE1Fun ");
  on0xE1Flag = 1;
  return;
}

//键盘中断初始化函数
void init_keyboard()
{
  kb_life = 0;//键盘域的生命值

  //初始化键盘缓冲区
  keyBuf[0].idx=0;
  keyBuf[1].idx=0;
  busyKeyBuf=&keyBuf[0];//指向键盘中断正在使用的缓冲区
  freeKeyBuf=&keyBuf[1];//指向空闲(待处理)的缓冲区
  keyBufPoint = busyKeyBuf;//键盘中断使用这个缓冲区

  //初始化键盘标记
  capsLock = 0;
  numLock = 1;
  shift = 0;

  enable_irq(KEYBOARD_IRQ);  //开键盘中断
}

//将缓冲区里扫描码转换成相应的字符,然后进行后续处理
t_bool make;  //TRUE:make FALSE:break
t_32 *keyrow; //指向 keymap[] 的某一行
t_32 key = 0; //用一个整型来表示一个键。
char moutput[2]=" ";

//键盘字符处理动作
void ScanCodeToCharFun()
{
  //交换双缓冲区
  asm{cli}
  keyBufPoint = freeKeyBuf;
  freeKeyBuf = busyKeyBuf;
  busyKeyBuf = keyBufPoint;
  asm{sti}

  if(freeKeyBuf->idx == 0) //若没有记录,不处理
  {
    kb_life++;

    if(kb_life>=20)//当空闲次数多时,撤销键盘字符处理动作
    {
      kb_life = 0;
      DelAction(&scanCodeToChar);
    }
    return;
  }

  //提取缓冲区中扫描码对应的可显示字符
  for(int i = 0;i<freeKeyBuf->idx;i++)
  {
    make = freeKeyBuf->buf[i];//取得扫描码
    //先定位到 keymap 中的行
    keyrow = &keymap[make * 2];

    if(shift)//根据是否按下shift,取不同的值
      key = keyrow[1];
    else
      key = keyrow[0];

    //若 Caps Lock 键被按下 字符大小写要互换
    if(capsLock && ((key >='a' && key<='z') || (key >='A'&& key<='Z')))
      key^=0x20;
    //不是字母,若是小键盘区的扫描码且 Num Lock 按下,要显示小键盘的字符
    else if( make >= 0x47 && numLock)
      key = keyrow[1];

    if (key == 0)//排除非可显示字符
      continue;

    //此时,key已经是可显示字符的ASCII码了,下面根据需要进行处理
    moutput[0]= key;// key & 0xFF;

    disp_str(moutput);//简单显示出来
  }
  freeKeyBuf->idx = 0;
}



搜索更多相关主题的帖子: 操作系统 结构 键盘 编写 驱动 
2010-05-30 09:54
miaowangjian
Rank: 2
等 级:论坛游民
帖 子:34
专家分:30
注 册:2010-1-29
收藏
得分:0 
code:console.h(新)
程序代码:
//文件:console.h
//功能:console头文件,控制台需要用到的公共函数的声明等
//作者:miao
//时间:2010-5-30

//VGA
#define CRTC_ADDR_REG              0x3D4   // CRT 控制寄存器 - 地址(索引)存器
#define CRTC_DATA_REG              0x3D5   // CRT 控制寄存器 - 数据(I/O)寄存器
#define CRTC_DATA_IDX_START_ADDR_H 0xC     // 寄存器索引:显存使用的起始地址 (头)
#define CRTC_DATA_IDX_START_ADDR_L 0xD     // 寄存器索引:显存使用的起始地址 (尾)
#define CRTC_DATA_IDX_CURSOR_H     0xE     // 寄存器索引:光标位置 (头)
#define CRTC_DATA_IDX_CURSOR_L     0xF     // 寄存器索引:光标位置 (尾)
#define V_MEM_BASE                 0xB8000 // 显存在内存的起始地址
#define V_MEM_SIZE                 0x8000  // 显存大小 = 32K = 0xbffff - 0xb8000

//颜色
#define BLACK   0x0  //0000:黑色
#define WHITE   0x7  //0111:白色
#define RED     0x4  //0100:红色
#define GREEN   0x2  //0010:绿色
#define BLUE    0x1  //0001:蓝色
#define FLASH   0x80 //1000 0000:闪烁
#define BRIGHT  0x08 //0000 1000:高亮
#define MAKE_COLOR(x,y) ((x<<4) | y) //MAKE_COLOR(背景颜色,字符颜色)
// 使用MAKE_COLOR宏示例:MAKE_COLOR(BLUE, RED)  //蓝底红字
// MAKE_COLOR(BLACK, RED) | BRIGHT              //黑底红字+字体高亮
// MAKE_COLOR(BLACK, RED) | BRIGHT | FLASH      //黑底红字+字体高亮+字体闪烁

// void printChar(char ch);
// void printString(char * info);
// asm void printColorString(char * info, int color);
// void printNumber(int num);

void OnLineUpFun();
struct on_s onLineUp = {"OnLineUp",&OnLineUpFun,NULL};
void OnLineDownFun();
struct on_s onLineDown = {"OnLineDown",&OnLineDownFun,NULL};
void OnPageUpFun();
struct on_s onPageUp = {"OnPageUp",&OnPageUpFun,NULL};
void OnPageDownFun();
struct on_s onPageDown = {"NullOn",&OnPageDownFun,NULL};

code:console.c(新)
程序代码:
//文件:console.c
//功能:控制台,管理CRT,设置窗口尺寸位置、前景色、背景色、光标等
//作者:miao
//时间:2010-5-25

char lineNum=0;
void SetLine()
{
  asm{cli}
  out_byte(CRTC_ADDR_REG, CRTC_DATA_IDX_START_ADDR_H);
  out_byte(CRTC_DATA_REG, ((80*lineNum)>>8)&0xff);
  out_byte(CRTC_ADDR_REG, CRTC_DATA_IDX_START_ADDR_L);
  out_byte(CRTC_DATA_REG, ((80*lineNum))&0xff);
  asm{sti}
}
void OnLineDownFun()
{
  lineNum++;
  if(lineNum>100)
    lineNum=100;
  SetLine();
  InitKeyOnEvent(onLineDown,0x50);
}
void OnLineUpFun()
{
  lineNum--;
  if(lineNum<0)
    lineNum=0;
  SetLine();
  InitKeyOnEvent(onLineUp,0x48);
}
void OnPageDownFun()
{
  lineNum+=25;
  if(lineNum>100)
    lineNum=100;
  SetLine();
  InitKeyOnEvent(onPageDown,0x51);
}
void OnPageUpFun()
{
  lineNum-=25;
  if(lineNum<0)
    lineNum=0;
  SetLine();
  InitKeyOnEvent(onPageUp,0x49);
}

2010-05-30 09:55
chengstone
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
帖 子:562
专家分:226
注 册:2004-4-3
收藏
得分:0 
这周太忙 还没找出时间看代码 不过刚刚运行了一下  感觉不错   只是在使用中发现键盘响应有点慢  
 过几天我再看看代码跟你探讨一下

qq:69558139
2010-06-02 13:48
miaowangjian
Rank: 2
等 级:论坛游民
帖 子:34
专家分:30
注 册:2010-1-29
收藏
得分:0 
    键盘响应慢是因为我使用了“限速器”,为的是测试系统在超负荷运行下,域结构 的动作函数与on函数配合是否正常,中断对系统的干扰情况。
要提高速度,调整“限速器”值,只要修改 “yu.c”文件里的下面两个函数的参数就行了。
程序代码:
//空动作,限制链表执行速度或将来用于管理动作链表
void NullActionFun()
{
  disp_color_str(" ",MAKE_COLOR(WHITE,RED)| BRIGHT | FLASH);
  disp_pos-=2;
  sleep(100);
  disp_color_str(" ",MAKE_COLOR(BLUE,RED));
  disp_pos-=2;
  sleep(50);
}
void sleep(int i)
{
  while(i--)
  for(int i=0;i<100;i++)
  for(int j=0;j<100;j++);
}
非常期待chengstone老大的意见建议
2010-06-02 15:14
asus2019
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2018-10-23
收藏
得分:0 
2018-10-23 18:57
快速回复:一步步写操作系统之第五步:进一步完善域结构并根据域结构重新编写键盘 ...
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.032767 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved