Main Page | Directories | File List | Globals

keyboard.c

Go to the documentation of this file.
00001 /*
00002  * kernel_drivers/adi_char/keyboard.c
00003  *
00004  * Copyright (c) 2003-2004 Lukasz Dembinski <dembol@nasa.com.pl>
00005  * All Rights Reserved
00006  * 
00007  * Date:        2004/01
00008  * Author:      Lukasz Dembinski
00009  * Info:        keyboard.c core file
00010  * Contact:     mailto: <dembol@nasa.com.pl>
00011  *
00012  */
00013 
00014 #include <agnix/agnix.h>
00015 #include <agnix/init.h>
00016 #include <agnix/ioport.h>
00017 #include <agnix/console.h>
00018 #include <agnix/terminal.h>
00019 #include <agnix/memory.h>
00020 #include <agnix/irq.h>
00021 #include <agnix/machine.h>
00022 
00023 #define MOD_NAME                "CHAR_KBD: \t"
00024 
00025 #define KBD_DTA_PORT            0x60
00026 #define KBD_CMD_PORT            0x64
00027 #define KBD_STS_PORT            0x64
00028 
00029 #define KBD_DCMD_READID         0xF2
00030 #define KBD_DCMD_SETDELAY       0xF3
00031 #define KBD_DCMD_ENABLE         0xF4
00032 #define KBD_DCMD_DISABLE        0xF5
00033 #define KBD_DCMD_RESET          0xFF
00034 
00035 #define KBD_CCMD_WRITEMODE      0x60
00036 #define KBD_CCMD_SELFTEST       0xAA
00037 #define KBD_CCMD_IFACETEST      0xAB
00038 #define KBD_CCMD_SETLEDS        0xED
00039 
00040 #define KBD_WAIT_LOOPS          10000000
00041 #define KBD_STS_OBF             0x01
00042 #define KBD_STS_IBF             0x02
00043 #define KBD_STS_PERR            0x80
00044 #define KBD_STS_GTMO            0x40
00045 
00046 #define KBD_IRQ                 1
00047 
00048 #define SPECIAL                 0
00049 #define KBD_CODE_ESC            0x01
00050 #define KBD_CODE_BACKSPACE      0x0E
00051 #define KBD_CODE_TAB            0x0F
00052 #define KBD_CODE_CTRL           0x1D
00053 #define KBD_CODE_SHIFTL         0x2A
00054 #define KBD_CODE_SHIFTR         0x36
00055 #define KBD_CODE_PRINT          0x37
00056 #define KBD_CODE_ALT            0x38
00057 #define KBD_CODE_CAPS           0x3A
00058 #define KBD_CODE_SCROLL         0x45
00059 #define KBD_CODE_NUM            0x46
00060 
00061 #define KBD_CODE_F1             0x3B
00062 #define KBD_CODE_F2             0x3C
00063 #define KBD_CODE_F3             0x3D
00064 #define KBD_CODE_F4             0x3E
00065 #define KBD_CODE_F5             0x3F
00066 #define KBD_CODE_F6             0x40
00067 #define KBD_CODE_F7             0x41
00068 #define KBD_CODE_F8             0x42
00069 #define KBD_CODE_F9             0x43
00070 #define KBD_CODE_F10            0x44
00071 //#define KBD_CODE_F11          0x3B
00072 //#define KBD_CODE_F12          0x3B
00073 
00074 #define ENTER                   10
00075 #define F1                      'A'
00076 #define F2                      'B'
00077 #define F3                      'C'
00078 #define F4                      'D'
00079 #define F5                      'E'
00080 #define F6                      'F'
00081 #define F7                      'G'
00082 #define F8                      'H'
00083 #define F9                      'I'
00084 #define F10                     'J'
00085 #define F11                     'K'
00086 #define F12                     'L'
00087 #define PAUSE                   'P'
00088 
00089 #define KBD_LED_SCROLL          0x01
00090 #define KBD_LED_NUM             0x02
00091 #define KBD_LED_CAPS            0x04
00092 
00093 #define KBD_FLG_SCROLL          KBD_LED_SCROLL
00094 #define KBD_FLG_NUM             KBD_LED_NUM
00095 #define KBD_FLG_CAPS            KBD_LED_CAPS
00096 #define KBD_FLG_SHIFT           0x08
00097 #define KBD_FLG_CNTRL           0x10
00098 #define KBD_FLG_ALT             0x20
00099 
00100 #define MAX_KBD_ACTIONS         16
00101 
00102 extern int term_cur;
00103 extern struct terminal_s term_sys[MAX_TERMINALS];
00104 
00105 u8 kbd_flags = 0;
00106 
00107 int kbd_action_count = 0;
00108 
00109 struct kbd_action_s {
00110     u8 active_flags;
00111     u8 passive_flags;
00112     u8 scancode;
00113     int (*kbd_action_routine)(int scancode);
00114 };
00115 
00116 struct kbd_action_s kbd_action[MAX_KBD_ACTIONS];
00117 
00118 char scancode_to_ascii[0x100] = {
00119     SPECIAL, SPECIAL, 
00120     '1','2','3','4','5','6','7','8','9','0','-','=',
00121     SPECIAL, SPECIAL, 
00122     'q','w','e','r','t','y','u','i','o','p','[',']',ENTER,SPECIAL,
00123     'a','s','d','f','g','h','j','k','l',';','\'',SPECIAL,'\\',
00124     '<','z','x','c','v','b','n','m',',','.','/',SPECIAL,SPECIAL,SPECIAL,
00125     ' ',SPECIAL,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,PAUSE,SPECIAL,SPECIAL,    
00126 };
00127 
00128 char scancode_to_ascii_shift[0x100] = {
00129     SPECIAL, SPECIAL, 
00130     '!','@','#','$','%','^','&','*','(',')','_','+',
00131     SPECIAL, SPECIAL, 
00132     'Q','W','E','R','T','Y','U','I','O','P','{','}',ENTER,SPECIAL,
00133     'A','S','D','F','G','H','J','K','L',':','"',SPECIAL,'|',
00134     '>','Z','X','C','V','B','N','M','<','>','?',SPECIAL,SPECIAL,SPECIAL,
00135     ' ',SPECIAL,'~','~','~','~','~','~','~','~','~','~','~','~',PAUSE,SPECIAL,SPECIAL,    
00136 };
00137 
00138 
00139 
00140 u8 kbd_status_read(void)
00141 {
00142     u8 status;
00143     
00144     status = inb(KBD_STS_PORT);
00145     
00146     return status;
00147 }
00148 
00149 int kbd_wait_for_bf(u8 which_bf, int neg)
00150 {
00151     u8 status;
00152     int wait_loops = KBD_WAIT_LOOPS;
00153     
00154     for (; wait_loops >= 0; wait_loops--) {
00155         status = kbd_status_read();
00156         
00157         if (neg) {
00158             if (!(status & which_bf))
00159                 return 1;
00160         }
00161         else {
00162             if (status & which_bf)
00163                 return 1;
00164         }
00165     }
00166 
00167     return 0;
00168 }
00169 
00170 int kbd_wait_for_notibf(void)
00171 {
00172     return kbd_wait_for_bf(KBD_STS_IBF, 1);
00173 }
00174 
00175 int kbd_wait_for_obf(void)
00176 {
00177     return kbd_wait_for_bf(KBD_STS_OBF, 0);
00178 }
00179 
00180 void kbd_data_write(u8 cmd)
00181 {
00182     kbd_wait_for_notibf();
00183     outb(cmd, KBD_DTA_PORT);
00184 }
00185 
00186 char kbd_data_read(void)
00187 {
00188     u8 status;
00189     char data = -1;
00190 
00191     status = kbd_status_read();
00192     
00193     if ((status & KBD_STS_OBF) && !(status & (KBD_STS_PERR | KBD_STS_GTMO))) {
00194 
00195         data = inb(KBD_DTA_PORT);
00196     }
00197     
00198     return data;
00199 }
00200 
00201 char kbd_data_read_wait(void)
00202 {
00203     char data = -1;
00204     
00205     if (kbd_wait_for_obf())
00206         data = kbd_data_read();
00207 
00208     return data;
00209 }
00210 
00211 void kbd_cmd_write(u8 cmd)
00212 {
00213     kbd_wait_for_notibf();
00214     outb(cmd, KBD_CMD_PORT);
00215 }
00216 
00217 void kbd_set_leds(u8 leds_mask)
00218 {
00219     kbd_data_write(KBD_CCMD_SETLEDS);
00220     kbd_data_write(leds_mask);
00221 }
00222 
00223 int kbd_change_led_flag(u8 led_flag)
00224 {
00225     if (kbd_flags & led_flag)
00226         kbd_flags &= ~led_flag;
00227     else
00228         kbd_flags |= led_flag;
00229         
00230     return 1;
00231 }
00232 
00233 void kbd_irq_handler(u32 data)
00234 {
00235     u8 status;
00236     u8 scancode;
00237     char asciicode;
00238     int leds_changed = 0;
00239     int i, k;
00240 
00241     for (k = 0; k < 20000; k++) {    
00242 
00243     status = kbd_status_read();
00244     if ((status & KBD_STS_OBF) && !(status & (KBD_STS_PERR | KBD_STS_GTMO))) {
00245 
00246         scancode = inb(KBD_DTA_PORT);
00247 
00248         switch(scancode) {
00249             case KBD_CODE_CTRL:
00250                     kbd_flags |= KBD_FLG_CNTRL;
00251                     break;
00252             case KBD_CODE_CTRL+128:
00253                     kbd_flags &= ~KBD_FLG_CNTRL;
00254                     break;
00255             case KBD_CODE_ALT:
00256                     kbd_flags |= KBD_FLG_ALT;
00257                     break;
00258             case KBD_CODE_ALT+128:
00259                     kbd_flags &= ~KBD_FLG_ALT;
00260                     break;
00261             case KBD_CODE_CAPS:
00262                     leds_changed = kbd_change_led_flag(KBD_FLG_CAPS);
00263                     break;
00264             case KBD_CODE_SCROLL:
00265                     leds_changed = kbd_change_led_flag(KBD_FLG_SCROLL);
00266                     break;
00267             case KBD_CODE_NUM:
00268                     leds_changed = kbd_change_led_flag(KBD_FLG_NUM);
00269                     break;
00270             case KBD_CODE_SHIFTR:
00271             case KBD_CODE_SHIFTL:
00272                     kbd_flags |= KBD_FLG_SHIFT;
00273                     break;
00274             case KBD_CODE_SHIFTR+128:
00275             case KBD_CODE_SHIFTL+128:
00276                     kbd_flags &= ~KBD_FLG_SHIFT;
00277                     break;
00278             default:
00279 
00280                 if ((scancode >= KBD_CODE_F1) && (scancode <= KBD_CODE_F10) &&
00281                      (kbd_flags & KBD_FLG_ALT)) {
00282                      terminal_switch(scancode - KBD_CODE_F1);
00283                      break; 
00284                 }
00285 
00286                 if (scancode < 128) {
00287 
00288                     if ((kbd_flags & KBD_FLG_SHIFT) || (kbd_flags & KBD_FLG_CAPS))
00289                             asciicode = scancode_to_ascii_shift[scancode];
00290                     else
00291                             asciicode = scancode_to_ascii[scancode];
00292 
00293                     if (asciicode != 0) {
00294                         if (term_sys[term_cur].ops && term_sys[term_cur].ops->write_char)
00295                             term_sys[term_cur].ops->write_char(&term_sys[term_cur], asciicode);
00296 //                          printk("%c", asciicode);
00297                     }
00298                 }
00299             }
00300 
00301         for (i = 0; i < kbd_action_count; i++) {
00302             if (((!kbd_action[i].scancode) || (kbd_action[i].scancode == scancode)) &&
00303                 ((kbd_action[i].active_flags & kbd_flags) == kbd_action[i].active_flags)) {
00304                 kbd_action[i].kbd_action_routine(scancode);
00305             }
00306         }
00307 
00308         if (leds_changed)
00309             kbd_set_leds(kbd_flags & 0x07);
00310 
00311         break;
00312     }
00313     }
00314 
00315     if (k == 20000) 
00316         printk("Keyboard interrupt error!\n");
00317 }
00318 
00319 int kbd_screen_scroll = 0;
00320 
00321 int kbd_screen_up(int scancode)
00322 {
00323     kbd_screen_scroll++;
00324 
00325     term_sys[term_cur].term_driver->ops->refresh(&term_sys[term_cur], kbd_screen_scroll);    
00326 
00327     return 0;
00328 }
00329 
00330 int kbd_screen_down(int scancode)
00331 {
00332     if (kbd_screen_scroll > 0) {
00333         kbd_screen_scroll--;
00334         term_sys[term_cur].term_driver->ops->refresh(&term_sys[term_cur], kbd_screen_scroll);    
00335     }
00336 
00337     return 0;
00338 }
00339 
00340 int cad_power_down(int scancode)
00341 {
00342     do_machine_reboot();
00343 //    do_machine_powerdown();
00344 
00345     return 0;
00346 }
00347 
00348 int kbd_set_actions(void)
00349 {
00350     memset(kbd_action, 0, sizeof(struct kbd_action_s) * MAX_KBD_ACTIONS);
00351     
00352     kbd_action[0].active_flags = 0;
00353     kbd_action[0].passive_flags = 0;
00354     kbd_action[0].scancode = 73;        /* PAGE_UP */
00355     kbd_action[0].kbd_action_routine = kbd_screen_up;
00356 
00357     kbd_action[1].active_flags = 0;
00358     kbd_action[1].passive_flags = 0;
00359     kbd_action[1].scancode = 81;        /* PAGE_DOWN */
00360     kbd_action[1].kbd_action_routine = kbd_screen_down;
00361 
00362     kbd_action[2].active_flags = KBD_FLG_ALT | KBD_FLG_CNTRL;
00363     kbd_action[2].passive_flags = 0;
00364     kbd_action[2].scancode = 0x53;      /* DEL */
00365     kbd_action[2].kbd_action_routine = cad_power_down;
00366 
00367     kbd_action_count = 3;
00368 
00369     return 0;
00370 }
00371 
00372 struct irq_routine_s kbd_irq_routine = {
00373     kbd_irq_handler, 0, IRQ_FLAG_RANDOM, 
00374 };
00375 
00376 int adi_chrdrv_kbd_init(void)
00377 {
00378     char data;
00379 
00380     printk(MOD_NAME "PC keyboard ... ");
00381 
00382     kbd_cmd_write(KBD_CCMD_SELFTEST);
00383     if ((data=kbd_data_read_wait()) != 0x55) {
00384         printk("Your keyboard is failed!\n");
00385         return -1;
00386     }
00387 
00388     kbd_cmd_write(KBD_CCMD_IFACETEST);
00389     if (kbd_data_read_wait() != 0x00) {
00390         printk("Your keyboard is failed!\n");
00391         return -1;
00392     }
00393 
00394     printk("ok\n");
00395 
00396     kbd_cmd_write(KBD_CCMD_WRITEMODE);
00397     kbd_data_write(0x40 | 0x20 | 0x04 | 0x01);
00398 
00399 //    kbd_data_write(KBD_DCMD_RESET);
00400     kbd_data_write(KBD_DCMD_ENABLE);
00401 
00402     kbd_set_leds(0x00);
00403 
00404     kbd_set_actions();
00405 
00406     install_irq(KBD_IRQ, &kbd_irq_routine);
00407 
00408     return 0;
00409 }
Dokumentacje wygenerowano programem Doxygen 1.4.2 dla projektu Agnix