iPXE
pc_kbd.c
Go to the documentation of this file.
00001 /* Minimal polling PC keyboard driver
00002  * - No interrupt
00003  * - No LED
00004  * - No special keys
00005  *
00006  * still Enough For Me to type a filename.
00007  *
00008  * 2003-07 by SONE Takesh
00009  * 2004-04 moved by LYH From filo to Etherboot
00010  *              yhlu@tyan.com
00011  */
00012 
00013 #include <ipxe/io.h>
00014 #include <ipxe/console.h>
00015 
00016 static char key_map[][128] = {
00017     {
00018         "\0\x1b""1234567890-=\b\t"
00019         "qwertyuiop[]\r\0as"
00020         "dfghjkl;'`\0\\zxcv"
00021         "bnm,./\0*\0 \0\0\0\0\0\0"
00022         "\0\0\0\0\0\0\0""789-456+1"
00023         "230."
00024     },{
00025         "\0\x1b""!@#$%^&*()_+\b\t"
00026         "QWERTYUIOP{}\r\0AS"
00027         "DFGHJKL:\"~\0|ZXCV"
00028         "BNM<>?\0\0\0 \0\0\0\0\0\0"
00029         "\0\0\0\0\0\0\0""789-456+1"
00030         "230."
00031     }
00032 };
00033 
00034 static int cur_scan;
00035 static unsigned int shift_state;
00036 #define SHIFT 1
00037 #define CONTROL 2
00038 #define CAPS 4
00039 
00040 static int get_scancode(void)
00041 {
00042     int scan;
00043 
00044     if ((inb(0x64) & 1) == 0)
00045         return 0;
00046     scan = inb(0x60);
00047 
00048     switch (scan) {
00049     case 0x2a:
00050     case 0x36:
00051         shift_state |= SHIFT;
00052         break;
00053     case 0xaa:
00054     case 0xb6:
00055         shift_state &= ~SHIFT;
00056         break;
00057     case 0x1d:
00058         shift_state |= CONTROL;
00059         break;
00060     case 0x9d:
00061         shift_state &= ~CONTROL;
00062         break;
00063     case 0x3a:
00064         shift_state ^= CAPS;
00065         break;
00066     }
00067 
00068     if (scan & 0x80)
00069         return 0; /* ignore break code or 0xe0 etc! */
00070     return scan;
00071 }
00072 
00073 static int kbd_havekey(void)
00074 {
00075     if (!cur_scan)
00076         cur_scan = get_scancode();
00077     return cur_scan != 0;
00078 }
00079 
00080 static int kbd_ischar(void)
00081 {
00082     if (!kbd_havekey())
00083         return 0;
00084     if (!key_map[shift_state & SHIFT][cur_scan]) {
00085         cur_scan = 0;
00086         return 0;
00087     }
00088     return 1;
00089 }
00090 
00091 static int kbd_getc(void)
00092 {
00093     int c;
00094 
00095     while (!kbd_ischar())
00096         ;
00097     c = key_map[shift_state & SHIFT][cur_scan];
00098     if (shift_state & (CONTROL | CAPS)) {
00099         if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
00100             if (shift_state & CONTROL)
00101                 c &= 0x1f;
00102             else if (shift_state & CAPS)
00103                 c ^= ('A' ^ 'a');
00104         }
00105     }
00106     cur_scan = 0;
00107     return c;
00108 }
00109 
00110 struct console_driver pc_kbd_console __console_driver = {
00111         .getchar = kbd_getc,
00112 };