i8042.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2004 Jakub Jermar
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00035 #include <genarch/i8042/i8042.h>
00036 #include <arch/drivers/i8042.h>
00037 #include <arch/interrupt.h>
00038 #include <cpu.h>
00039 #include <arch/asm.h>
00040 #include <arch.h>
00041 #include <synch/spinlock.h>
00042 #include <typedefs.h>
00043 #include <console/chardev.h>
00044 #include <console/console.h>
00045 #include <macros.h>
00046 #include <interrupt.h>
00047 
00054 #define KBD_ENABLE      0xf4
00055 #define KBD_DISABLE     0xf5
00056 #define KBD_ACK         0xfa
00057 
00058 /*
00059  * 60  Write 8042 Command Byte: next data byte written to port 60h is
00060  *     placed in 8042 command register. Format:
00061  *
00062  *    |7|6|5|4|3|2|1|0|8042 Command Byte
00063  *     | | | | | | | `---- 1=enable output register full interrupt
00064  *     | | | | | | `----- should be 0
00065  *     | | | | | `------ 1=set status register system, 0=clear
00066  *     | | | | `------- 1=override keyboard inhibit, 0=allow inhibit
00067  *     | | | `-------- disable keyboard I/O by driving clock line low
00068  *     | | `--------- disable auxiliary device, drives clock line low
00069  *     | `---------- IBM scancode translation 0=AT, 1=PC/XT
00070  *     `----------- reserved, should be 0
00071  */
00072 
00073 #define i8042_SET_COMMAND       0x60
00074 #define i8042_COMMAND           0x49
00075 
00076 #define i8042_BUFFER_FULL_MASK  0x01
00077 #define i8042_WAIT_MASK         0x02
00078 
00079 #define SPECIAL         '?'
00080 #define KEY_RELEASE     0x80
00081 
00085 #define IGNORE_CODE     0x7f
00086 
00087 static void key_released(__u8 sc);
00088 static void key_pressed(__u8 sc);
00089 static char key_read(chardev_t *d);
00090 
00091 #define PRESSED_SHIFT           (1<<0)
00092 #define PRESSED_CAPSLOCK        (1<<1)
00093 #define LOCKED_CAPSLOCK         (1<<0)
00094 
00095 #define ACTIVE_READ_BUFF_SIZE 16        /* Must be power of 2 */
00096 
00097 static __u8 active_read_buff[ACTIVE_READ_BUFF_SIZE];
00098 
00099 SPINLOCK_INITIALIZE(keylock);           
00100 static volatile int keyflags;           
00101 static volatile int lockflags;          
00103 static void i8042_suspend(chardev_t *);
00104 static void i8042_resume(chardev_t *);
00105 
00106 static chardev_t kbrd;
00107 static chardev_operations_t ops = {
00108         .suspend = i8042_suspend,
00109         .resume = i8042_resume,
00110         .read = key_read
00111 };
00112 
00114 static char sc_primary_map[] = {
00115         SPECIAL, /* 0x00 */
00116         SPECIAL, /* 0x01 - Esc */
00117         '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',
00118         '\b', /* 0x0e - Backspace */
00119         '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
00120         SPECIAL, /* 0x1d - LCtrl */
00121         'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'',
00122         '`',
00123         SPECIAL, /* 0x2a - LShift */ 
00124         '\\',
00125         'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
00126         SPECIAL, /* 0x36 - RShift */
00127         '*',
00128         SPECIAL, /* 0x38 - LAlt */
00129         ' ',
00130         SPECIAL, /* 0x3a - CapsLock */
00131         SPECIAL, /* 0x3b - F1 */
00132         SPECIAL, /* 0x3c - F2 */
00133         SPECIAL, /* 0x3d - F3 */
00134         SPECIAL, /* 0x3e - F4 */
00135         SPECIAL, /* 0x3f - F5 */
00136         SPECIAL, /* 0x40 - F6 */
00137         SPECIAL, /* 0x41 - F7 */
00138         SPECIAL, /* 0x42 - F8 */
00139         SPECIAL, /* 0x43 - F9 */
00140         SPECIAL, /* 0x44 - F10 */
00141         SPECIAL, /* 0x45 - NumLock */
00142         SPECIAL, /* 0x46 - ScrollLock */
00143         '7', '8', '9', '-',
00144         '4', '5', '6', '+',
00145         '1', '2', '3',
00146         '0', '.',
00147         SPECIAL, /* 0x54 - Alt-SysRq */
00148         SPECIAL, /* 0x55 - F11/F12/PF1/FN */
00149         SPECIAL, /* 0x56 - unlabelled key next to LAlt */
00150         SPECIAL, /* 0x57 - F11 */
00151         SPECIAL, /* 0x58 - F12 */
00152         SPECIAL, /* 0x59 */
00153         SPECIAL, /* 0x5a */
00154         SPECIAL, /* 0x5b */
00155         SPECIAL, /* 0x5c */
00156         SPECIAL, /* 0x5d */
00157         SPECIAL, /* 0x5e */
00158         SPECIAL, /* 0x5f */
00159         SPECIAL, /* 0x60 */
00160         SPECIAL, /* 0x61 */
00161         SPECIAL, /* 0x62 */
00162         SPECIAL, /* 0x63 */
00163         SPECIAL, /* 0x64 */
00164         SPECIAL, /* 0x65 */
00165         SPECIAL, /* 0x66 */
00166         SPECIAL, /* 0x67 */
00167         SPECIAL, /* 0x68 */
00168         SPECIAL, /* 0x69 */
00169         SPECIAL, /* 0x6a */
00170         SPECIAL, /* 0x6b */
00171         SPECIAL, /* 0x6c */
00172         SPECIAL, /* 0x6d */
00173         SPECIAL, /* 0x6e */
00174         SPECIAL, /* 0x6f */
00175         SPECIAL, /* 0x70 */
00176         SPECIAL, /* 0x71 */
00177         SPECIAL, /* 0x72 */
00178         SPECIAL, /* 0x73 */
00179         SPECIAL, /* 0x74 */
00180         SPECIAL, /* 0x75 */
00181         SPECIAL, /* 0x76 */
00182         SPECIAL, /* 0x77 */
00183         SPECIAL, /* 0x78 */
00184         SPECIAL, /* 0x79 */
00185         SPECIAL, /* 0x7a */
00186         SPECIAL, /* 0x7b */
00187         SPECIAL, /* 0x7c */
00188         SPECIAL, /* 0x7d */
00189         SPECIAL, /* 0x7e */
00190         SPECIAL, /* 0x7f */
00191 };
00192 
00194 static char sc_secondary_map[] = {
00195         SPECIAL, /* 0x00 */
00196         SPECIAL, /* 0x01 - Esc */
00197         '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+',
00198         SPECIAL, /* 0x0e - Backspace */
00199         '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
00200         SPECIAL, /* 0x1d - LCtrl */
00201         'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"',
00202         '~',
00203         SPECIAL, /* 0x2a - LShift */ 
00204         '|',
00205         'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
00206         SPECIAL, /* 0x36 - RShift */
00207         '*',
00208         SPECIAL, /* 0x38 - LAlt */
00209         ' ',
00210         SPECIAL, /* 0x3a - CapsLock */
00211         SPECIAL, /* 0x3b - F1 */
00212         SPECIAL, /* 0x3c - F2 */
00213         SPECIAL, /* 0x3d - F3 */
00214         SPECIAL, /* 0x3e - F4 */
00215         SPECIAL, /* 0x3f - F5 */
00216         SPECIAL, /* 0x40 - F6 */
00217         SPECIAL, /* 0x41 - F7 */
00218         SPECIAL, /* 0x42 - F8 */
00219         SPECIAL, /* 0x43 - F9 */
00220         SPECIAL, /* 0x44 - F10 */
00221         SPECIAL, /* 0x45 - NumLock */
00222         SPECIAL, /* 0x46 - ScrollLock */
00223         '7', '8', '9', '-',
00224         '4', '5', '6', '+',
00225         '1', '2', '3',
00226         '0', '.',
00227         SPECIAL, /* 0x54 - Alt-SysRq */
00228         SPECIAL, /* 0x55 - F11/F12/PF1/FN */
00229         SPECIAL, /* 0x56 - unlabelled key next to LAlt */
00230         SPECIAL, /* 0x57 - F11 */
00231         SPECIAL, /* 0x58 - F12 */
00232         SPECIAL, /* 0x59 */
00233         SPECIAL, /* 0x5a */
00234         SPECIAL, /* 0x5b */
00235         SPECIAL, /* 0x5c */
00236         SPECIAL, /* 0x5d */
00237         SPECIAL, /* 0x5e */
00238         SPECIAL, /* 0x5f */
00239         SPECIAL, /* 0x60 */
00240         SPECIAL, /* 0x61 */
00241         SPECIAL, /* 0x62 */
00242         SPECIAL, /* 0x63 */
00243         SPECIAL, /* 0x64 */
00244         SPECIAL, /* 0x65 */
00245         SPECIAL, /* 0x66 */
00246         SPECIAL, /* 0x67 */
00247         SPECIAL, /* 0x68 */
00248         SPECIAL, /* 0x69 */
00249         SPECIAL, /* 0x6a */
00250         SPECIAL, /* 0x6b */
00251         SPECIAL, /* 0x6c */
00252         SPECIAL, /* 0x6d */
00253         SPECIAL, /* 0x6e */
00254         SPECIAL, /* 0x6f */
00255         SPECIAL, /* 0x70 */
00256         SPECIAL, /* 0x71 */
00257         SPECIAL, /* 0x72 */
00258         SPECIAL, /* 0x73 */
00259         SPECIAL, /* 0x74 */
00260         SPECIAL, /* 0x75 */
00261         SPECIAL, /* 0x76 */
00262         SPECIAL, /* 0x77 */
00263         SPECIAL, /* 0x78 */
00264         SPECIAL, /* 0x79 */
00265         SPECIAL, /* 0x7a */
00266         SPECIAL, /* 0x7b */
00267         SPECIAL, /* 0x7c */
00268         SPECIAL, /* 0x7d */
00269         SPECIAL, /* 0x7e */
00270         SPECIAL, /* 0x7f */     
00271 };
00272 
00273 static void i8042_interrupt(int n, istate_t *istate);
00274 static void i8042_wait(void);
00275 
00276 static iroutine oldvector;
00278 void i8042_grab(void)
00279 {
00280         oldvector = exc_register(VECTOR_KBD, "i8042_interrupt", (iroutine) i8042_interrupt);
00281         i8042_wait();
00282         i8042_command_write(i8042_SET_COMMAND);
00283         i8042_wait();
00284         i8042_data_write(i8042_COMMAND);
00285         i8042_wait();
00286 }
00288 void i8042_release(void)
00289 {
00290         if (oldvector)
00291                 exc_register(VECTOR_KBD, "user_interrupt", oldvector);
00292 }
00293 
00295 void i8042_init(void)
00296 {
00297         int i;
00298 
00299         i8042_grab();
00300         /* Prevent user from accidentaly releasing calling i8042_resume
00301          * and disabling keyboard 
00302          */
00303         oldvector = NULL; 
00304 
00305         trap_virtual_enable_irqs(1<<IRQ_KBD);
00306         chardev_initialize("i8042_kbd", &kbrd, &ops);
00307         stdin = &kbrd;
00308 
00309         /*
00310          * Clear input buffer.
00311          * Number of iterations is limited to prevent infinite looping.
00312          */
00313         for (i = 0; (i8042_status_read() & i8042_BUFFER_FULL_MASK) && i < 100; i++) {
00314                 i8042_data_read();
00315         }  
00316 }
00317 
00323 void i8042_interrupt(int n, istate_t *istate)
00324 {
00325         __u8 x;
00326 
00327         trap_virtual_eoi();
00328         x = i8042_data_read();
00329         if (x & KEY_RELEASE)
00330                 key_released(x ^ KEY_RELEASE);
00331         else
00332                 key_pressed(x);
00333 }
00334 
00336 void i8042_wait(void) {
00337         while (i8042_status_read() & i8042_WAIT_MASK) {
00338                 /* wait */
00339         }
00340 }
00341 
00346 void key_released(__u8 sc)
00347 {
00348         spinlock_lock(&keylock);
00349         switch (sc) {
00350             case SC_LSHIFT:
00351             case SC_RSHIFT:
00352                 keyflags &= ~PRESSED_SHIFT;
00353                 break;
00354             case SC_CAPSLOCK:
00355                 keyflags &= ~PRESSED_CAPSLOCK;
00356                 if (lockflags & LOCKED_CAPSLOCK)
00357                         lockflags &= ~LOCKED_CAPSLOCK;
00358                 else
00359                         lockflags |= LOCKED_CAPSLOCK;
00360                 break;
00361             default:
00362                 break;
00363         }
00364         spinlock_unlock(&keylock);
00365 }
00366 
00371 void key_pressed(__u8 sc)
00372 {
00373         char *map = sc_primary_map;
00374         char ascii = sc_primary_map[sc];
00375         bool shift, capslock;
00376         bool letter = false;
00377 
00378         spinlock_lock(&keylock);
00379         switch (sc) {
00380         case SC_LSHIFT:
00381         case SC_RSHIFT:
00382                 keyflags |= PRESSED_SHIFT;
00383                 break;
00384         case SC_CAPSLOCK:
00385                 keyflags |= PRESSED_CAPSLOCK;
00386                 break;
00387         case SC_SPEC_ESCAPE:
00388                 break;
00389         case SC_LEFTARR:
00390                 chardev_push_character(&kbrd, 0x1b);
00391                 chardev_push_character(&kbrd, 0x5b);
00392                 chardev_push_character(&kbrd, 0x44);
00393                 break;
00394         case SC_RIGHTARR:
00395                 chardev_push_character(&kbrd, 0x1b);
00396                 chardev_push_character(&kbrd, 0x5b);
00397                 chardev_push_character(&kbrd, 0x43);
00398                 break;
00399         case SC_UPARR:
00400                 chardev_push_character(&kbrd, 0x1b);
00401                 chardev_push_character(&kbrd, 0x5b);
00402                 chardev_push_character(&kbrd, 0x41);
00403                 break;
00404         case SC_DOWNARR:
00405                 chardev_push_character(&kbrd, 0x1b);
00406                 chardev_push_character(&kbrd, 0x5b);
00407                 chardev_push_character(&kbrd, 0x42);
00408                 break;
00409         case SC_HOME:
00410                 chardev_push_character(&kbrd, 0x1b);
00411                 chardev_push_character(&kbrd, 0x4f);
00412                 chardev_push_character(&kbrd, 0x48);
00413                 break;
00414         case SC_END:
00415                 chardev_push_character(&kbrd, 0x1b);
00416                 chardev_push_character(&kbrd, 0x4f);
00417                 chardev_push_character(&kbrd, 0x46);
00418                 break;
00419         case SC_DELETE:
00420                 chardev_push_character(&kbrd, 0x1b);
00421                 chardev_push_character(&kbrd, 0x5b);
00422                 chardev_push_character(&kbrd, 0x33);
00423                 chardev_push_character(&kbrd, 0x7e);
00424                 break;
00425         default:
00426                 letter = is_lower(ascii);
00427                 capslock = (keyflags & PRESSED_CAPSLOCK) || (lockflags & LOCKED_CAPSLOCK);
00428                 shift = keyflags & PRESSED_SHIFT;
00429                 if (letter && capslock)
00430                         shift = !shift;
00431                 if (shift)
00432                         map = sc_secondary_map;
00433                 chardev_push_character(&kbrd, map[sc]);
00434                 break;
00435         }
00436         spinlock_unlock(&keylock);
00437 }
00438 
00439 /* Called from getc(). */
00440 void i8042_resume(chardev_t *d)
00441 {
00442 }
00443 
00444 /* Called from getc(). */
00445 void i8042_suspend(chardev_t *d)
00446 {
00447 }
00448 
00449 static __u8 active_read_buff_read(void)
00450 {
00451         static int i=0;
00452         i &= (ACTIVE_READ_BUFF_SIZE-1);
00453         if(!active_read_buff[i]) {
00454                 return 0;
00455         }
00456         return active_read_buff[i++];
00457 }
00458 
00459 static void active_read_buff_write(__u8 ch)
00460 {
00461         static int i=0;
00462         active_read_buff[i] = ch;
00463         i++;
00464         i &= (ACTIVE_READ_BUFF_SIZE-1);
00465         active_read_buff[i]=0;
00466 }
00467 
00468 
00469 static void active_read_key_pressed(__u8 sc)
00470 {
00471         char *map = sc_primary_map;
00472         char ascii = sc_primary_map[sc];
00473         bool shift, capslock;
00474         bool letter = false;
00475 
00476         /*spinlock_lock(&keylock);*/
00477         switch (sc) {
00478         case SC_LSHIFT:
00479         case SC_RSHIFT:
00480                 keyflags |= PRESSED_SHIFT;
00481                 break;
00482         case SC_CAPSLOCK:
00483                 keyflags |= PRESSED_CAPSLOCK;
00484                 break;
00485         case SC_SPEC_ESCAPE:
00486                 break;
00487         case SC_LEFTARR:
00488                 active_read_buff_write(0x1b);
00489                 active_read_buff_write(0x5b);
00490                 active_read_buff_write(0x44);
00491                 break;
00492         case SC_RIGHTARR:
00493                 active_read_buff_write(0x1b);
00494                 active_read_buff_write(0x5b);
00495                 active_read_buff_write(0x43);
00496                 break;
00497         case SC_UPARR:
00498                 active_read_buff_write(0x1b);
00499                 active_read_buff_write(0x5b);
00500                 active_read_buff_write(0x41);
00501                 break;
00502         case SC_DOWNARR:
00503                 active_read_buff_write(0x1b);
00504                 active_read_buff_write(0x5b);
00505                 active_read_buff_write(0x42);
00506                 break;
00507         case SC_HOME:
00508                 active_read_buff_write(0x1b);
00509                 active_read_buff_write(0x4f);
00510                 active_read_buff_write(0x48);
00511                 break;
00512         case SC_END:
00513                 active_read_buff_write(0x1b);
00514                 active_read_buff_write(0x4f);
00515                 active_read_buff_write(0x46);
00516                 break;
00517         case SC_DELETE:
00518                 active_read_buff_write(0x1b);
00519                 active_read_buff_write(0x5b);
00520                 active_read_buff_write(0x33);
00521                 active_read_buff_write(0x7e);
00522                 break;
00523         default:
00524                 letter = is_lower(ascii);
00525                 capslock = (keyflags & PRESSED_CAPSLOCK) || (lockflags & LOCKED_CAPSLOCK);
00526                 shift = keyflags & PRESSED_SHIFT;
00527                 if (letter && capslock)
00528                         shift = !shift;
00529                 if (shift)
00530                         map = sc_secondary_map;
00531                 active_read_buff_write(map[sc]);
00532                 break;
00533         }
00534         /*spinlock_unlock(&keylock);*/
00535 
00536 }
00537 
00538 static char key_read(chardev_t *d)
00539 {
00540         char ch;        
00541 
00542         while(!(ch = active_read_buff_read())) {
00543                 __u8 x;
00544                 while (!((x=i8042_status_read() & i8042_BUFFER_FULL_MASK)))
00545                         ;
00546                 x = i8042_data_read();
00547                 if (x != IGNORE_CODE) {
00548                         if (x & KEY_RELEASE)
00549                                 key_released(x ^ KEY_RELEASE);
00550                         else
00551                                 active_read_key_pressed(x);
00552                 }
00553         }
00554         return ch;
00555 }
00556 
00561 void i8042_poll(void)
00562 {
00563         __u8 x;
00564 
00565         while (((x = i8042_status_read() & i8042_BUFFER_FULL_MASK))) {
00566                 x = i8042_data_read();
00567                 if (x != IGNORE_CODE) {
00568                         if (x & KEY_RELEASE)
00569                                 key_released(x ^ KEY_RELEASE);
00570                         else
00571                                 key_pressed(x);
00572                 }
00573         }
00574 }
00575 

Generated on Sun Jun 18 16:26:57 2006 for HelenOS Kernel (amd64) by  doxygen 1.4.6