arch/ia32/src/kbd.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2004 Jakub Jermar
00003  * Copyright (C) 2006 Josef Cejka
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * - Redistributions of source code must retain the above copyright
00011  *   notice, this list of conditions and the following disclaimer.
00012  * - Redistributions in binary form must reproduce the above copyright
00013  *   notice, this list of conditions and the following disclaimer in the
00014  *   documentation and/or other materials provided with the distribution.
00015  * - The name of the author may not be used to endorse or promote products
00016  *   derived from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00019  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00020  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00021  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00023  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00024  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00025  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00027  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00039 #include <arch/kbd.h>
00040 #include <ipc/ipc.h>
00041 #include <unistd.h>
00042 #include <kbd.h>
00043 #include <keys.h>
00044 
00045 /* Interesting bits for status register */
00046 #define i8042_OUTPUT_FULL  0x1
00047 #define i8042_INPUT_FULL   0x2
00048 #define i8042_MOUSE_DATA   0x20
00049 
00050 /* Command constants */
00051 #define i8042_CMD_KBD 0x60
00052 #define i8042_CMD_MOUSE  0xd4
00053 
00054 /* Keyboard cmd byte */
00055 #define i8042_KBD_IE        0x1
00056 #define i8042_MOUSE_IE      0x2
00057 #define i8042_KBD_DISABLE   0x10
00058 #define i8042_MOUSE_DISABLE 0x20
00059 #define i8042_KBD_TRANSLATE 0x40
00060 
00061 /* Mouse constants */
00062 #define MOUSE_OUT_INIT  0xf4
00063 #define MOUSE_ACK       0xfa
00064 
00065 
00066 #define SPECIAL         255
00067 #define KEY_RELEASE     0x80
00068 
00072 #define IGNORE_CODE     0x7f
00073 
00074 #define PRESSED_SHIFT           (1<<0)
00075 #define PRESSED_CAPSLOCK        (1<<1)
00076 #define LOCKED_CAPSLOCK         (1<<0)
00077 
00079 #define SC_ESC          0x01
00080 #define SC_BACKSPACE    0x0e
00081 #define SC_LSHIFT       0x2a
00082 #define SC_RSHIFT       0x36
00083 #define SC_CAPSLOCK     0x3a
00084 #define SC_SPEC_ESCAPE  0xe0
00085 #define SC_LEFTARR      0x4b
00086 #define SC_RIGHTARR     0x4d
00087 #define SC_UPARR        0x48
00088 #define SC_DOWNARR      0x50
00089 #define SC_DELETE       0x53
00090 #define SC_HOME         0x47
00091 #define SC_END          0x4f
00092 
00093 #define FUNCTION_KEYS 0x100
00094 
00095 static volatile int keyflags;           
00096 static volatile int lockflags;          
00099 static int sc_primary_map[] = {
00100         SPECIAL, /* 0x00 */
00101         SPECIAL, /* 0x01 - Esc */
00102         '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',
00103         '\b', /* 0x0e - Backspace */
00104         '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
00105         SPECIAL, /* 0x1d - LCtrl */
00106         'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'',
00107         '`',
00108         SPECIAL, /* 0x2a - LShift */ 
00109         '\\',
00110         'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
00111         SPECIAL, /* 0x36 - RShift */
00112         '*',
00113         SPECIAL, /* 0x38 - LAlt */
00114         ' ',
00115         SPECIAL, /* 0x3a - CapsLock */
00116         (FUNCTION_KEYS | 1), /* 0x3b - F1 */
00117         (FUNCTION_KEYS | 2), /* 0x3c - F2 */
00118         (FUNCTION_KEYS | 3), /* 0x3d - F3 */
00119         (FUNCTION_KEYS | 4), /* 0x3e - F4 */
00120         (FUNCTION_KEYS | 5), /* 0x3f - F5 */
00121         (FUNCTION_KEYS | 6), /* 0x40 - F6 */
00122         (FUNCTION_KEYS | 7), /* 0x41 - F7 */
00123         (FUNCTION_KEYS | 8), /* 0x42 - F8 */
00124         (FUNCTION_KEYS | 9), /* 0x43 - F9 */
00125         (FUNCTION_KEYS | 10), /* 0x44 - F10 */
00126         SPECIAL, /* 0x45 - NumLock */
00127         SPECIAL, /* 0x46 - ScrollLock */
00128         '7', '8', '9', '-',
00129         '4', '5', '6', '+',
00130         '1', '2', '3',
00131         '0', '.',
00132         SPECIAL, /* 0x54 - Alt-SysRq */
00133         SPECIAL, /* 0x55 - F11/F12/PF1/FN */
00134         SPECIAL, /* 0x56 - unlabelled key next to LAlt */
00135         (FUNCTION_KEYS | 11), /* 0x57 - F11 */
00136         (FUNCTION_KEYS | 12), /* 0x58 - F12 */
00137         SPECIAL, /* 0x59 */
00138         SPECIAL, /* 0x5a */
00139         SPECIAL, /* 0x5b */
00140         SPECIAL, /* 0x5c */
00141         SPECIAL, /* 0x5d */
00142         SPECIAL, /* 0x5e */
00143         SPECIAL, /* 0x5f */
00144         SPECIAL, /* 0x60 */
00145         SPECIAL, /* 0x61 */
00146         SPECIAL, /* 0x62 */
00147         SPECIAL, /* 0x63 */
00148         SPECIAL, /* 0x64 */
00149         SPECIAL, /* 0x65 */
00150         SPECIAL, /* 0x66 */
00151         SPECIAL, /* 0x67 */
00152         SPECIAL, /* 0x68 */
00153         SPECIAL, /* 0x69 */
00154         SPECIAL, /* 0x6a */
00155         SPECIAL, /* 0x6b */
00156         SPECIAL, /* 0x6c */
00157         SPECIAL, /* 0x6d */
00158         SPECIAL, /* 0x6e */
00159         SPECIAL, /* 0x6f */
00160         SPECIAL, /* 0x70 */
00161         SPECIAL, /* 0x71 */
00162         SPECIAL, /* 0x72 */
00163         SPECIAL, /* 0x73 */
00164         SPECIAL, /* 0x74 */
00165         SPECIAL, /* 0x75 */
00166         SPECIAL, /* 0x76 */
00167         SPECIAL, /* 0x77 */
00168         SPECIAL, /* 0x78 */
00169         SPECIAL, /* 0x79 */
00170         SPECIAL, /* 0x7a */
00171         SPECIAL, /* 0x7b */
00172         SPECIAL, /* 0x7c */
00173         SPECIAL, /* 0x7d */
00174         SPECIAL, /* 0x7e */
00175         SPECIAL, /* 0x7f */
00176 };
00177 
00179 static int sc_secondary_map[] = {
00180         SPECIAL, /* 0x00 */
00181         0x1b, /* 0x01 - Esc */
00182         '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+',
00183         SPECIAL, /* 0x0e - Backspace */
00184         '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
00185         SPECIAL, /* 0x1d - LCtrl */
00186         'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"',
00187         '~',
00188         SPECIAL, /* 0x2a - LShift */ 
00189         '|',
00190         'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
00191         SPECIAL, /* 0x36 - RShift */
00192         '*',
00193         SPECIAL, /* 0x38 - LAlt */
00194         ' ',
00195         SPECIAL, /* 0x3a - CapsLock */
00196         SPECIAL, /* 0x3b - F1 */
00197         SPECIAL, /* 0x3c - F2 */
00198         SPECIAL, /* 0x3d - F3 */
00199         SPECIAL, /* 0x3e - F4 */
00200         SPECIAL, /* 0x3f - F5 */
00201         SPECIAL, /* 0x40 - F6 */
00202         SPECIAL, /* 0x41 - F7 */
00203         SPECIAL, /* 0x42 - F8 */
00204         SPECIAL, /* 0x43 - F9 */
00205         SPECIAL, /* 0x44 - F10 */
00206         SPECIAL, /* 0x45 - NumLock */
00207         SPECIAL, /* 0x46 - ScrollLock */
00208         '7', '8', '9', '-',
00209         '4', '5', '6', '+',
00210         '1', '2', '3',
00211         '0', '.',
00212         SPECIAL, /* 0x54 - Alt-SysRq */
00213         SPECIAL, /* 0x55 - F11/F12/PF1/FN */
00214         SPECIAL, /* 0x56 - unlabelled key next to LAlt */
00215         SPECIAL, /* 0x57 - F11 */
00216         SPECIAL, /* 0x58 - F12 */
00217         SPECIAL, /* 0x59 */
00218         SPECIAL, /* 0x5a */
00219         SPECIAL, /* 0x5b */
00220         SPECIAL, /* 0x5c */
00221         SPECIAL, /* 0x5d */
00222         SPECIAL, /* 0x5e */
00223         SPECIAL, /* 0x5f */
00224         SPECIAL, /* 0x60 */
00225         SPECIAL, /* 0x61 */
00226         SPECIAL, /* 0x62 */
00227         SPECIAL, /* 0x63 */
00228         SPECIAL, /* 0x64 */
00229         SPECIAL, /* 0x65 */
00230         SPECIAL, /* 0x66 */
00231         SPECIAL, /* 0x67 */
00232         SPECIAL, /* 0x68 */
00233         SPECIAL, /* 0x69 */
00234         SPECIAL, /* 0x6a */
00235         SPECIAL, /* 0x6b */
00236         SPECIAL, /* 0x6c */
00237         SPECIAL, /* 0x6d */
00238         SPECIAL, /* 0x6e */
00239         SPECIAL, /* 0x6f */
00240         SPECIAL, /* 0x70 */
00241         SPECIAL, /* 0x71 */
00242         SPECIAL, /* 0x72 */
00243         SPECIAL, /* 0x73 */
00244         SPECIAL, /* 0x74 */
00245         SPECIAL, /* 0x75 */
00246         SPECIAL, /* 0x76 */
00247         SPECIAL, /* 0x77 */
00248         SPECIAL, /* 0x78 */
00249         SPECIAL, /* 0x79 */
00250         SPECIAL, /* 0x7a */
00251         SPECIAL, /* 0x7b */
00252         SPECIAL, /* 0x7c */
00253         SPECIAL, /* 0x7d */
00254         SPECIAL, /* 0x7e */
00255         SPECIAL, /* 0x7f */     
00256 };
00257 
00258 irq_cmd_t i8042_cmds[2] = {
00259         { CMD_PORT_READ_1, (void *)0x64, 0, 1 },
00260         { CMD_PORT_READ_1, (void *)0x60, 0, 2 }
00261 };
00262 
00263 irq_code_t i8042_kbd = {
00264         2,
00265         i8042_cmds
00266 };
00267 
00268 static void key_released(keybuffer_t *keybuffer, unsigned char key)
00269 {
00270         switch (key) {
00271                 case SC_LSHIFT:
00272                 case SC_RSHIFT:
00273                         keyflags &= ~PRESSED_SHIFT;
00274                         break;
00275                 case SC_CAPSLOCK:
00276                         keyflags &= ~PRESSED_CAPSLOCK;
00277                         if (lockflags & LOCKED_CAPSLOCK)
00278                                 lockflags &= ~LOCKED_CAPSLOCK;
00279                                 else
00280                                 lockflags |= LOCKED_CAPSLOCK;
00281                         break;
00282                 default:
00283                         break;
00284         }
00285 }
00286 
00287 static void key_pressed(keybuffer_t *keybuffer, unsigned char key)
00288 {
00289         int *map = sc_primary_map;
00290         int ascii = sc_primary_map[key];
00291         int shift, capslock;
00292         int letter = 0;
00293 
00294         static int esc_count=0;
00295 
00296         
00297         if ( key == SC_ESC ) {
00298                 esc_count++;
00299                 if ( esc_count == 3 ) {
00300                         __SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE);
00301                 }       
00302         } else {
00303                 esc_count=0;
00304         }
00305         
00306         
00307 
00308         switch (key) {
00309                 case SC_LSHIFT:
00310                 case SC_RSHIFT:
00311                         keyflags |= PRESSED_SHIFT;
00312                         break;
00313                 case SC_CAPSLOCK:
00314                         keyflags |= PRESSED_CAPSLOCK;
00315                         break;
00316                 case SC_SPEC_ESCAPE:
00317                         break;
00318         /*      case SC_LEFTARR:
00319                         if (keybuffer_available(keybuffer) >= 3) {
00320                                 keybuffer_push(keybuffer, 0x1b);        
00321                                 keybuffer_push(keybuffer, 0x5b);        
00322                                 keybuffer_push(keybuffer, 0x44);        
00323                         }
00324                         break;
00325                 case SC_RIGHTARR:
00326                         if (keybuffer_available(keybuffer) >= 3) {
00327                                 keybuffer_push(keybuffer, 0x1b);        
00328                                 keybuffer_push(keybuffer, 0x5b);        
00329                                 keybuffer_push(keybuffer, 0x43);        
00330                         }
00331                         break;
00332                 case SC_UPARR:
00333                         if (keybuffer_available(keybuffer) >= 3) {
00334                                 keybuffer_push(keybuffer, 0x1b);        
00335                                 keybuffer_push(keybuffer, 0x5b);        
00336                                 keybuffer_push(keybuffer, 0x41);        
00337                         }
00338                         break;
00339                 case SC_DOWNARR:
00340                         if (keybuffer_available(keybuffer) >= 3) {
00341                                 keybuffer_push(keybuffer, 0x1b);        
00342                                 keybuffer_push(keybuffer, 0x5b);        
00343                                 keybuffer_push(keybuffer, 0x42);        
00344                         }
00345                         break;
00346                 case SC_HOME:
00347                         if (keybuffer_available(keybuffer) >= 3) {
00348                                 keybuffer_push(keybuffer, 0x1b);        
00349                                 keybuffer_push(keybuffer, 0x4f);        
00350                                 keybuffer_push(keybuffer, 0x48);        
00351                         }
00352                         break;
00353                 case SC_END:
00354                         if (keybuffer_available(keybuffer) >= 3) {
00355                                 keybuffer_push(keybuffer, 0x1b);        
00356                                 keybuffer_push(keybuffer, 0x4f);        
00357                                 keybuffer_push(keybuffer, 0x46);        
00358                         }
00359                         break;
00360                 case SC_DELETE:
00361                         if (keybuffer_available(keybuffer) >= 4) {
00362                                 keybuffer_push(keybuffer, 0x1b);        
00363                                 keybuffer_push(keybuffer, 0x5b);        
00364                                 keybuffer_push(keybuffer, 0x33);        
00365                                 keybuffer_push(keybuffer, 0x7e);        
00366                         }
00367                         break;
00368         */      default:
00369                         letter = ((ascii >= 'a') && (ascii <= 'z'));
00370                         capslock = (keyflags & PRESSED_CAPSLOCK) || (lockflags & LOCKED_CAPSLOCK);
00371                         shift = keyflags & PRESSED_SHIFT;
00372                         if (letter && capslock)
00373                                 shift = !shift;
00374                         if (shift)
00375                                 map = sc_secondary_map;
00376                         if (map[key] != SPECIAL)
00377                                 keybuffer_push(keybuffer, map[key]);    
00378                         break;
00379         }
00380 }
00381 
00382 
00383 static void wait_ready(void) {
00384         while (i8042_status_read() & i8042_INPUT_FULL)
00385                 ;
00386 }
00387 
00391 int kbd_arch_init(void)
00392 {
00393         int i;
00394         int mouseenabled = 0;
00395 
00396         iospace_enable(task_get_id(),(void *)i8042_DATA, 5);
00397         /* Disable kbd, enable mouse */
00398         i8042_command_write(i8042_CMD_KBD);
00399         wait_ready();
00400         i8042_command_write(i8042_CMD_KBD);
00401         wait_ready();
00402         i8042_data_write(i8042_KBD_DISABLE);
00403         wait_ready();
00404 
00405         /* Flush all current IO */
00406         while (i8042_status_read() & i8042_OUTPUT_FULL)
00407                 i8042_data_read();
00408         /* Initialize mouse */
00409         i8042_command_write(i8042_CMD_MOUSE);
00410         wait_ready();
00411         i8042_data_write(MOUSE_OUT_INIT);
00412         wait_ready();
00413         
00414         int mouseanswer = 0;
00415         for (i=0;i < 1000; i++) {
00416                 int status = i8042_status_read();
00417                 if (status & i8042_OUTPUT_FULL) {
00418                         int data = i8042_data_read();
00419                         if (status & i8042_MOUSE_DATA) {
00420                                 mouseanswer = data;
00421                                 break;
00422                         }
00423                 }
00424                 usleep(1000);
00425         }
00426         if (mouseanswer == MOUSE_ACK) {
00427                 /* enable mouse */
00428                 mouseenabled = 1;
00429 
00430                 ipc_register_irq(MOUSE_IRQ, &i8042_kbd);
00431         }
00432         /* Enable kbd */
00433         ipc_register_irq(KBD_IRQ, &i8042_kbd);
00434         /* Register for irq restart */
00435         ipc_register_irq(IPC_IRQ_KBDRESTART, NULL);
00436 
00437         int newcontrol = i8042_KBD_IE | i8042_KBD_TRANSLATE;
00438         if (mouseenabled)
00439                 newcontrol |= i8042_MOUSE_IE;
00440         
00441         i8042_command_write(i8042_CMD_KBD);
00442         wait_ready();
00443         i8042_data_write(newcontrol);
00444         wait_ready();
00445         
00446         return 0;
00447 }
00448 
00450 int kbd_arch_process(keybuffer_t *keybuffer, ipc_call_t *call)
00451 {
00452         int status = IPC_GET_ARG1(*call);
00453 
00454         if (IPC_GET_METHOD(*call) == IPC_IRQ_KBDRESTART) {
00455                 kbd_arch_init();
00456                 return 1;
00457         }
00458 
00459         if ((status & i8042_MOUSE_DATA))
00460                 return 0;
00461         
00462         int scan_code = IPC_GET_ARG2(*call);
00463         
00464         if (scan_code != IGNORE_CODE) {
00465                 if (scan_code & KEY_RELEASE)
00466                         key_released(keybuffer, scan_code ^ KEY_RELEASE);
00467                 else
00468                         key_pressed(keybuffer, scan_code);
00469         }
00470         return  1;
00471 }
00472 

Generated on Sun Jun 18 17:54:21 2006 for HelenOS Userspace (ia32) by  doxygen 1.4.6