kernel/keyboard.c

来源:互联网 发布:笔记本电池校正软件 编辑:程序博客网 时间:2024/06/17 03:52
Code:
  1. /*    
  2.     By Marcus Xing  
  3.     kernel/keyboard.c  
  4.     与键盘的输入输出有关的代码  
  5. */  
  6.   
  7. #include "type.h"   
  8. #include "const.h"   
  9. #include "ipc.h"   
  10. #include "protect.h"   
  11. #include "proc.h"   
  12. #include "console.h"   
  13. #include "tty.h"   
  14. #include "global.h"   
  15. #include "keyboard.h"   
  16. #include "keymap.h"   
  17. #include "proto.h"   
  18.   
  19. /* 内部函数和内部变量声明 */  
  20.   
  21. /* 键盘中断处理程序,只能由本文件调用 */  
  22. static void Keyboard_Handler(int int_vec_no);   
  23.   
  24. /* 从缓冲区中得到一个扫描码,只能由本文件调用*/  
  25. static u8   Get_Byte_From_Buffer();   
  26.   
  27. /* 缓冲区结构变量,只能由本文件使用 */  
  28. static KB_Input_Buffer  KB_Input_Buf;   
  29.   
  30. /* 状态变量,只能由本文件调用 */  
  31. static int Shift_L;         /* 是否按下左边的SHIFT键 */  
  32. static int Shift_R;         /* 是否按下右边的SHIFT键 */  
  33. static int Ctrl_L;          /* 是否按下左边的CTRL键 */  
  34. static int Ctrl_R;          /* 是否按下右边的CTRL键 */  
  35. static int Alt_L;           /* 是否按下左边的ALT键 */  
  36. static int Alt_R;           /* 是否按下右边的ALT键 */  
  37. static int With_E0;         /* 判断2扫描码并第一个码为E0的变量 */  
  38. static int Caps_Lock;       /* 是否按下Caps_Lock键 */  
  39. static int Num_Lock;        /* 是否按下Num Lock键 */  
  40. static int Scroll_Lock;     /* 是否按下Scroll Lock键 */  
  41.   
  42. /* 仅限于本文件调用的功能函数声明 */  
  43. static void Keyboard_Handler(int int_vec_no);   
  44. static u8   Get_Byte_From_Buffer();   
  45. static void KB_Wait();   
  46. static void KB_Ack();   
  47. static void Set_LED();   
  48.   
  49. /*-----------------------------------------------------------------Init_Keyboard  
  50.     初始化键盘  
  51. */  
  52. void Init_Keyboard()   
  53. {   
  54.     /* 三盏灯全灭 */  
  55.     Caps_Lock = Num_Lock = Scroll_Lock = 0;   
  56.     Set_LED();   
  57.        
  58.     /* 初始化缓冲区结构 */  
  59.     KB_Input_Buf.head = KB_Input_Buf.tail = KB_Input_Buf.buffer;   
  60.     KB_Input_Buf.size = 0;   
  61.        
  62.     /* 键盘中断的处理函数的填充 */  
  63.     IRQ_Handler_Table[1] = Keyboard_Handler;   
  64.        
  65.     /* 激活键盘中断 */  
  66.     Enable_IRQ(1);   
  67. }   
  68.   
  69. /*-----------------------------------------------------------------Keyboard_Read  
  70.     读键盘函数,由终端进程调用  
  71. */  
  72. void Keyboard_Read(TTY *tty)   
  73. {   
  74.     u8 scan_code = Get_Byte_From_Buffer();  /* 从缓冲区读取一个扫描码 */  
  75.     int make;           /* 判断是否按下,按下为1,不按下为0 */  
  76.     int col = 0;        /* 决定读取keymap表中当前行的列数 */  
  77.     u32 *row = 0;       /* 指向当前码的行的第一列 */  
  78.     u32 key = 0;        /* 存放当前码对应的表中的值 */  
  79.            
  80.     if(scan_code == 0xe0)   
  81.     {   
  82.         scan_code = Get_Byte_From_Buffer();   
  83.            
  84.         /*   
  85.             判断是否按下的是PRINTSCREEN键   
  86.             此键比较特殊,是惟一的按下弹起都是4个码的键  
  87.         */  
  88.         if(scan_code == 0x2a)   
  89.         {   
  90.             scan_code = Get_Byte_From_Buffer();   
  91.             if(scan_code == 0xe0)   
  92.             {   
  93.                 if(Get_Byte_From_Buffer() == 0x37)   
  94.                 {   
  95.                     key = PRINTSCREEN;   
  96.                     make = 1;   
  97.                 }   
  98.             }      
  99.         }   
  100.         /* 判断是否是PRINTSCREEN键弹起 */  
  101.         else if(scan_code == 0xb7)   
  102.         {   
  103.             if(Get_Byte_From_Buffer() == 0xe0)   
  104.             {   
  105.                 if(Get_Byte_From_Buffer() == 0xaa)   
  106.                 {   
  107.                     key = PRINTSCREEN;   
  108.                     make = 0;   
  109.                 }   
  110.             }   
  111.         }   
  112.         /* 否则是以0xe0开头的其它键,按下弹起均为2个码 */  
  113.         else  
  114.         {   
  115.             With_E0 = 1;    /* 定位到第2列的标志置1 */  
  116.         }   
  117.     }   
  118.        
  119.     /*   
  120.         判断是否按下了PAUSE键,此键是惟一以0xe1开头的键   
  121.         PAUSE键有6个扫描码,没有BREAK CODE  
  122.     */  
  123.     else if(scan_code == 0xe1)   
  124.     {   
  125.         int flag = 1;   
  126.         int i = 0;   
  127.         u32 pause_scan_code[6] = {0xe1,0x1d,0x45,0xe1,0x9d,0xc5};   
  128.            
  129.         for(;i < 6;i++)   
  130.         {   
  131.             /* 如果不匹配,标志置0,跳出 */  
  132.             if(Get_Byte_From_Buffer() != pause_scan_code[i])   
  133.             {   
  134.                 flag = 0;   
  135.                 break;   
  136.             }   
  137.         }   
  138.            
  139.         /* 如果匹配,key赋值 */  
  140.         if(flag)   
  141.         {   
  142.             key = PAUSEBREAK;   
  143.             make = 1;   
  144.         }   
  145.     }   
  146.        
  147.     /* 如果不是PRINTSCREEN和PAUSE键的话 */  
  148.     if((key != PRINTSCREEN) && (key != PAUSEBREAK))   
  149.     {   
  150.         /*   
  151.             是按下还是弹起,结果赋给make,MAKE CODE | FLAG_BREAK = BREAK CODE  
  152.             如果按下或弹起的是以0xe0开头的键,此时的scan_code为第2个码  
  153.         */  
  154.         make = (scan_code & FLAG_BREAK) ? 0 : 1;   
  155.                
  156.         /* 指向当前码的行的第一列 */  
  157.         row = &Key_Map[(scan_code & 0x7f) * MAP_COLS];   
  158.                
  159.         /* 如果Caps Lock灯亮着再按shift+字母键,则还是小写 */  
  160.         int caps;   
  161.         caps = Shift_L || Shift_R;   
  162.         if(Caps_Lock)   
  163.         {   
  164.             if(row[0] >= 'a' && row[0] <= 'z')   
  165.             {   
  166.                 caps = !caps;   
  167.             }   
  168.         }   
  169.            
  170.         /* 如果SHIFT键还没放开,读当前列的第2列 */  
  171.         if(caps)   
  172.         {   
  173.             col = 1;   
  174.         }   
  175.                
  176.         /* 判断是否在此前按下了以0xe0码开头的键 */  
  177.         if(With_E0)   
  178.         {   
  179.             col = 2;   
  180.             With_E0 = 0;   
  181.         }   
  182.                
  183.         key = row[col];     /* 从表中取出值 */  
  184.                
  185.         switch(key)   
  186.         {   
  187.             /* 按下或释放左SHIFT键 */  
  188.             case SHIFT_L:   
  189.                 /* 如果按下,Shift_L置1,否则置0 */  
  190.                 if(!With_E0)   
  191.                 {   
  192.                     Shift_L = make;   
  193.                 }   
  194.                 break;   
  195.                        
  196.             /* 如果按下,Shift_R置1,否则置0 */  
  197.             case SHIFT_R:   
  198.                 if(!With_E0)   
  199.                 {   
  200.                     Shift_R = make;   
  201.                 }   
  202.                 break;   
  203.                        
  204.             /* 如果按下,Ctrl_L置1,否则置0 */  
  205.             case CTRL_L:   
  206.                 Ctrl_L = make;   
  207.                 break;   
  208.                    
  209.             /* 按下或释放右CTRL键 */      
  210.             case CTRL_R:   
  211.             /* 如果按下,Ctrl_R置1,否则置0 */  
  212.             Ctrl_R = make;   
  213.             break;   
  214.                        
  215.             /* 按下或释放左ALT键 */  
  216.             case ALT_L:   
  217.             /* 如果按下,Alt_L置1,否则置0 */  
  218.                 Alt_L = make;   
  219.                 break;   
  220.                        
  221.             /* 按下或释放右ALT键 */  
  222.             case ALT_R:   
  223.                 /* 如果按下,Alt_R置1,否则置0 */  
  224.                 Alt_R = make;   
  225.                 break;   
  226.                    
  227.             /* 处理Caps Lock键 */  
  228.             case CAPS_LOCK:   
  229.                 /* 如果按下,则亮灭转换下 */  
  230.                 if(make)   
  231.                 {   
  232.                     Caps_Lock = !Caps_Lock;   
  233.                     Set_LED();   
  234.                 }   
  235.                 break;   
  236.                    
  237.             /* 处理Num Lock键 */  
  238.             case NUM_LOCK:   
  239.                 /* 如果按下,则亮灭转换下 */  
  240.                 if(make)   
  241.                 {   
  242.                     Num_Lock = !Num_Lock;   
  243.                     Set_LED();   
  244.                 }   
  245.                 break;   
  246.                    
  247.             /* 处理Scroll Lock键 */  
  248.             case SCROLL_LOCK:   
  249.                 /* 如果按下,则亮灭转换下 */  
  250.                 if(make)   
  251.                 {   
  252.                     Scroll_Lock = !Scroll_Lock;   
  253.                     Set_LED();   
  254.                 }   
  255.                 break;   
  256.                    
  257.             /* 处理其它键 */  
  258.             default:   
  259.                 break;   
  260.         }   
  261.     }   
  262.        
  263.     int pad = 0;   
  264.        
  265.     /* 如果按下 */  
  266.     if(make)   
  267.     {   
  268.         /* 按下的是小键盘上的键 */  
  269.         if(key >= PAD_SLASH && key <= PAD_9)   
  270.         {   
  271.             pad = 1;    /* 标志按下的是小键盘的键 */  
  272.                
  273.             /* 以下代码逻辑简单,不注释了 */  
  274.             switch(key)   
  275.             {   
  276.                 case PAD_SLASH:   
  277.                     key = '/';   
  278.                     break;   
  279.                    
  280.                 case PAD_STAR:   
  281.                     key = '*';   
  282.                     break;   
  283.                    
  284.                 case PAD_MINUS:   
  285.                     key = '-';   
  286.                     break;   
  287.                        
  288.                 case PAD_PLUS:   
  289.                     key = '+';   
  290.                     break;   
  291.                        
  292.                 case PAD_ENTER:   
  293.                     key = '/n';   
  294.                     break;   
  295.                        
  296.                 case PAD_DOT:   
  297.                     if(Num_Lock)   
  298.                     {   
  299.                         key = '.';   
  300.                     }   
  301.                     else  
  302.                     {   
  303.                         key = '/b';   
  304.                     }   
  305.                     break;   
  306.                        
  307.                 default:   
  308.                     if(Num_Lock && key >= PAD_0 && key <= PAD_9)   
  309.                     {   
  310.                         key = key - PAD_0 + '0';   
  311.                     }   
  312.                     else  
  313.                     {   
  314.                         switch(key)   
  315.                         {   
  316.                             case PAD_UP:   
  317.                                 key = UP;   
  318.                                 break;   
  319.                                    
  320.                             case PAD_DOWN:   
  321.                                 key = DOWN;   
  322.                                 break;   
  323.                                    
  324.                             case PAD_LEFT:   
  325.                                 key = LEFT;   
  326.                                 break;   
  327.                                    
  328.                             case PAD_RIGHT:   
  329.                                 key = RIGHT;   
  330.                                 break;   
  331.                                
  332.                             case PAD_HOME:   
  333.                                 key = HOME;   
  334.                                 break;   
  335.                                    
  336.                             case PAD_END:   
  337.                                 key = END;   
  338.                                 break;   
  339.                                    
  340.                             case PAD_PAGEUP:   
  341.                                 key = PAGEUP;   
  342.                                 break;   
  343.                                    
  344.                             case PAD_PAGEDOWN:   
  345.                                 key = PAGEDOWN;   
  346.                                 break;   
  347.                                    
  348.                             case PAD_INS:   
  349.                                 key = INSERT;   
  350.                                 break;   
  351.                                    
  352.                             default:   
  353.                                 break;   
  354.                         }   
  355.                     }   
  356.                     break;   
  357.             }   
  358.         }   
  359.     }   
  360.        
  361.     /*   
  362.         如果按下,把SHIFT,CTRL,ALT键的信息附在key后  
  363.         则把key交给tty.c中的函数处理,无论key是否可打印  
  364.     */  
  365.     if(make)   
  366.     {   
  367.         key |= (Shift_L ? FLAG_SHIFT_L : 0);   
  368.         key |= (Shift_R ? FLAG_SHIFT_R : 0);   
  369.         key |= (Ctrl_L ? FLAG_CTRL_L : 0);   
  370.         key |= (Ctrl_R ? FLAG_CTRL_R : 0);   
  371.         key |= (Alt_L ? FLAG_ALT_L : 0);   
  372.         key |= (Alt_R ? FLAG_ALT_R : 0);   
  373.         key |= (pad ? FLAG_PAD : 0);    /* 是否是小键盘按下的加以区分 */  
  374.            
  375.         /* 分离功能,此函数只负责解析,怎么处理交给In_Process */  
  376.         In_Process(tty,key);       
  377.     }   
  378. }   
  379.   
  380. /*--------------------------------------------------------------Keyboard_Handler  
  381.     键盘中断处理程序  
  382. */  
  383. static void Keyboard_Handler(int int_vec_no)   
  384. {   
  385.     u8 scan_code;   
  386.     scan_code = In_Byte(IN_BUFFER_8042);    /* 读取扫描码到scan_code中 */  
  387.        
  388.     /* 如果缓冲区还有空间,则把扫描码放入缓冲区队尾指示的位置 */      
  389.     if(KB_Input_Buf.size < BUFFER_SIZE)                                
  390.     {   
  391.         *KB_Input_Buf.tail = scan_code;     /* 放到队尾 */  
  392.         KB_Input_Buf.tail++;                /* 尾指针前进一个位置 */  
  393.            
  394.         /* 如果尾指针超出缓冲区,则回到缓冲区首地址 */  
  395.         if(KB_Input_Buf.tail == KB_Input_Buf.buffer + BUFFER_SIZE)   
  396.         {   
  397.             KB_Input_Buf.tail = KB_Input_Buf.buffer;   
  398.         }   
  399.         KB_Input_Buf.size++;                /* 缓冲区大小加1 */  
  400.     }   
  401.     else  
  402.     {   
  403.         /* 没有空间则直接忽略 */  
  404.     }   
  405. }   
  406.   
  407. /*----------------------------------------------------------Get_Byte_From_Buffer  
  408.     从缓冲区中得到一个扫描码   
  409. */  
  410. static u8   Get_Byte_From_Buffer()   
  411. {   
  412.     u8 scan_code;   
  413.   
  414.     /* 如果缓冲区没有扫描码,等待着 */  
  415.     while(KB_Input_Buf.size <= 0){}   
  416.   
  417.     /*   
  418.         下面的开中断和关中断是为了保证两个函数调用之间   
  419.         的代码保持原子性,一气呵成,因为可能会被键盘中  
  420.         断打断,而键盘中断处理程序又会操作缓冲区,造成  
  421.         混乱  
  422.     */  
  423.     Disable_Int();                              /* 关中断 */  
  424.     scan_code = *KB_Input_Buf.head;             /* 队首指针指示的码给scan_code */  
  425.     KB_Input_Buf.head++;                        /* 头指针前进一个位置 */  
  426.            
  427.     /* 如果队首指针超出缓冲区,则回到缓冲区首地址 */  
  428.     if(KB_Input_Buf.head == KB_Input_Buf.buffer + BUFFER_SIZE)   
  429.     {   
  430.         KB_Input_Buf.head = KB_Input_Buf.buffer;   
  431.     }   
  432.     KB_Input_Buf.size--;                        /* 缓冲区大小减1 */  
  433.     Enable_Int();                               /* 开中断 */  
  434.        
  435.     return  scan_code;   
  436. }   
  437.   
  438. /*-----------------------------------------------------------------------KB_Wait  
  439.     判断8042的输入缓冲区是否为空,不为空就死等到空为止  
  440.     向8042的输入缓冲区填数据是向8048发送命令  
  441. */  
  442. static void KB_Wait()   
  443. {   
  444.     u8 status;   
  445.     do  
  446.     {   
  447.         status = In_Byte(STATUS_REG_8042);  /* 从0x64端口读取8042的状态 */  
  448.     }while(status & 2);     /* 第1位如果为0,则可以向输入缓冲区写数据 */  
  449. }   
  450.   
  451. /*------------------------------------------------------------------------KB_Ack  
  452.     设置LED时是否收到8048的反馈,如果没有接收到则死等  
  453. */  
  454. void KB_Ack()   
  455. {   
  456.     u8 data;   
  457.     do  
  458.     {   
  459.         data = In_Byte(IN_BUFFER_8042); /* 从8042输出缓冲区中读取反馈 */  
  460.     }while(data != KB_ACK);     /* 如果不是8048的反馈KB_ACK则死等 */  
  461. }   
  462.   
  463. /*-----------------------------------------------------------------------Set_LED   
  464.     设置LED,设置LED的命令字中,0表示灭,1表示亮  
  465.     第0位表示Scroll Lock,第1位表示Num Lock,第2位表示Caps_Lock  
  466. */  
  467. static void Set_LED()   
  468. {   
  469.     u8 led = Scroll_Lock | (Num_Lock << 1) | (Caps_Lock << 2);  /* 组合命令字节 */  
  470.     KB_Wait();      /* 判断输入缓冲区是否空闲 */  
  471.     Out_Byte(OUT_BUFFER_8042,KB_SET_LED_COM);   /* 表明要控制LED了 */  
  472.     KB_Ack();       /* 等待回应 */  
  473.     KB_Wait();      /* 判断输入缓冲区是否空闲 */  
  474.     Out_Byte(OUT_BUFFER_8042,led);  /* 写命令 */  
  475.     KB_Ack();       /* 等待回应 */  
  476. }