Subversion Repositories HelenOS

Rev

Rev 1838 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (C) 2001-2004 Jakub Jermar
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup genarch
  30.  * @{
  31.  */
  32. /**
  33.  * @file
  34.  * @brief   i8042 processor driver.
  35.  *
  36.  * It takes care of low-level keyboard functions.
  37.  */
  38.  
  39. #include <genarch/i8042/i8042.h>
  40. #include <arch/drivers/i8042.h>
  41. #include <arch/interrupt.h>
  42. #include <cpu.h>
  43. #include <arch/asm.h>
  44. #include <arch.h>
  45. #include <synch/spinlock.h>
  46. #include <typedefs.h>
  47. #include <console/chardev.h>
  48. #include <console/console.h>
  49. #include <macros.h>
  50. #include <interrupt.h>
  51.  
  52. /* Keyboard commands. */
  53. #define KBD_ENABLE  0xf4
  54. #define KBD_DISABLE 0xf5
  55. #define KBD_ACK     0xfa
  56.  
  57. /*
  58.  * 60  Write 8042 Command Byte: next data byte written to port 60h is
  59.  *     placed in 8042 command register. Format:
  60.  *
  61.  *    |7|6|5|4|3|2|1|0|8042 Command Byte
  62.  *     | | | | | | | `---- 1=enable output register full interrupt
  63.  *     | | | | | | `----- should be 0
  64.  *     | | | | | `------ 1=set status register system, 0=clear
  65.  *     | | | | `------- 1=override keyboard inhibit, 0=allow inhibit
  66.  *     | | | `-------- disable keyboard I/O by driving clock line low
  67.  *     | | `--------- disable auxiliary device, drives clock line low
  68.  *     | `---------- IBM scancode translation 0=AT, 1=PC/XT
  69.  *     `----------- reserved, should be 0
  70.  */
  71.  
  72. #define i8042_SET_COMMAND   0x60
  73. #define i8042_COMMAND       0x69
  74.  
  75. #define i8042_BUFFER_FULL_MASK  0x01
  76. #define i8042_WAIT_MASK     0x02
  77. #define i8042_MOUSE_DATA        0x20
  78.  
  79. #define KEY_RELEASE 0x80
  80.  
  81. /**
  82.  * These codes read from i8042 data register are silently ignored.
  83.  */
  84. #define IGNORE_CODE 0x7f
  85.  
  86. static void key_released(uint8_t sc);
  87. static void key_pressed(uint8_t sc);
  88. static char key_read(chardev_t *d);
  89.  
  90. #define PRESSED_SHIFT       (1<<0)
  91. #define PRESSED_CAPSLOCK    (1<<1)
  92. #define LOCKED_CAPSLOCK     (1<<0)
  93.  
  94. #define ACTIVE_READ_BUFF_SIZE 16    /* Must be power of 2 */
  95.  
  96. static uint8_t active_read_buff[ACTIVE_READ_BUFF_SIZE];
  97.  
  98. SPINLOCK_INITIALIZE(keylock);       /**< keylock protects keyflags and lockflags. */
  99. static volatile int keyflags;       /**< Tracking of multiple keypresses. */
  100. static volatile int lockflags;      /**< Tracking of multiple keys lockings. */
  101.  
  102. static void i8042_suspend(chardev_t *);
  103. static void i8042_resume(chardev_t *);
  104.  
  105. static chardev_t kbrd;
  106. static chardev_operations_t ops = {
  107.     .suspend = i8042_suspend,
  108.     .resume = i8042_resume,
  109.     .read = key_read
  110. };
  111.  
  112. static void i8042_interrupt(int n, istate_t *istate);
  113. static void i8042_wait(void);
  114.  
  115. static iroutine oldvector;
  116. /** Initialize keyboard and service interrupts using kernel routine */
  117. void i8042_grab(void)
  118. {
  119.     oldvector = exc_register(VECTOR_KBD, "i8042_interrupt", (iroutine) i8042_interrupt);
  120.     i8042_wait();
  121.     i8042_command_write(i8042_SET_COMMAND);
  122.     i8042_wait();
  123.     i8042_data_write(i8042_COMMAND);
  124.     i8042_wait();
  125. }
  126. /** Resume the former interrupt vector */
  127. void i8042_release(void)
  128. {
  129.     if (oldvector)
  130.         exc_register(VECTOR_KBD, "user_interrupt", oldvector);
  131. }
  132.  
  133. /** Initialize i8042. */
  134. void i8042_init(void)
  135. {
  136.     int i;
  137.  
  138.     i8042_grab();
  139.         /* Prevent user from accidentaly releasing calling i8042_resume
  140.      * and disabling keyboard
  141.      */
  142.     oldvector = NULL;
  143.  
  144.     trap_virtual_enable_irqs(1<<IRQ_KBD);
  145.     chardev_initialize("i8042_kbd", &kbrd, &ops);
  146.     stdin = &kbrd;
  147.  
  148.     /*
  149.      * Clear input buffer.
  150.      * Number of iterations is limited to prevent infinite looping.
  151.      */
  152.     for (i = 0; (i8042_status_read() & i8042_BUFFER_FULL_MASK) && i < 100; i++) {
  153.         i8042_data_read();
  154.     }  
  155. }
  156.  
  157. /** Process i8042 interrupt.
  158.  *
  159.  * @param n Interrupt vector.
  160.  * @param istate Interrupted state.
  161.  */
  162. void i8042_interrupt(int n, istate_t *istate)
  163. {
  164.     uint8_t x;
  165.     uint8_t status;
  166.  
  167.     while (((status=i8042_status_read()) & i8042_BUFFER_FULL_MASK)) {
  168.         x = i8042_data_read();
  169.  
  170.         if ((status & i8042_MOUSE_DATA))
  171.             continue;
  172.  
  173.         if (x & KEY_RELEASE)
  174.             key_released(x ^ KEY_RELEASE);
  175.         else
  176.             key_pressed(x);
  177.     }
  178.     trap_virtual_eoi();
  179. }
  180.  
  181. /** Wait until the controller reads its data. */
  182. void i8042_wait(void) {
  183.     while (i8042_status_read() & i8042_WAIT_MASK) {
  184.         /* wait */
  185.     }
  186. }
  187.  
  188. /** Process release of key.
  189.  *
  190.  * @param sc Scancode of the key being released.
  191.  */
  192. void key_released(uint8_t sc)
  193. {
  194.     spinlock_lock(&keylock);
  195.     switch (sc) {
  196.         case SC_LSHIFT:
  197.         case SC_RSHIFT:
  198.         keyflags &= ~PRESSED_SHIFT;
  199.         break;
  200.         case SC_CAPSLOCK:
  201.         keyflags &= ~PRESSED_CAPSLOCK;
  202.         if (lockflags & LOCKED_CAPSLOCK)
  203.             lockflags &= ~LOCKED_CAPSLOCK;
  204.         else
  205.             lockflags |= LOCKED_CAPSLOCK;
  206.         break;
  207.         default:
  208.         break;
  209.     }
  210.     spinlock_unlock(&keylock);
  211. }
  212.  
  213. /** Process keypress.
  214.  *
  215.  * @param sc Scancode of the key being pressed.
  216.  */
  217. void key_pressed(uint8_t sc)
  218. {
  219.     char *map = sc_primary_map;
  220.     char ascii = sc_primary_map[sc];
  221.     bool shift, capslock;
  222.     bool letter = false;
  223.  
  224.     spinlock_lock(&keylock);
  225.     switch (sc) {
  226.     case SC_LSHIFT:
  227.     case SC_RSHIFT:
  228.             keyflags |= PRESSED_SHIFT;
  229.         break;
  230.     case SC_CAPSLOCK:
  231.         keyflags |= PRESSED_CAPSLOCK;
  232.         break;
  233.     case SC_SPEC_ESCAPE:
  234.         break;
  235.     case SC_LEFTARR:
  236.         chardev_push_character(&kbrd, 0x1b);
  237.         chardev_push_character(&kbrd, 0x5b);
  238.         chardev_push_character(&kbrd, 0x44);
  239.         break;
  240.     case SC_RIGHTARR:
  241.         chardev_push_character(&kbrd, 0x1b);
  242.         chardev_push_character(&kbrd, 0x5b);
  243.         chardev_push_character(&kbrd, 0x43);
  244.         break;
  245.     case SC_UPARR:
  246.         chardev_push_character(&kbrd, 0x1b);
  247.         chardev_push_character(&kbrd, 0x5b);
  248.         chardev_push_character(&kbrd, 0x41);
  249.         break;
  250.     case SC_DOWNARR:
  251.         chardev_push_character(&kbrd, 0x1b);
  252.         chardev_push_character(&kbrd, 0x5b);
  253.         chardev_push_character(&kbrd, 0x42);
  254.         break;
  255.     case SC_HOME:
  256.         chardev_push_character(&kbrd, 0x1b);
  257.         chardev_push_character(&kbrd, 0x4f);
  258.         chardev_push_character(&kbrd, 0x48);
  259.         break;
  260.     case SC_END:
  261.         chardev_push_character(&kbrd, 0x1b);
  262.         chardev_push_character(&kbrd, 0x4f);
  263.         chardev_push_character(&kbrd, 0x46);
  264.         break;
  265.     case SC_DELETE:
  266.         chardev_push_character(&kbrd, 0x1b);
  267.         chardev_push_character(&kbrd, 0x5b);
  268.         chardev_push_character(&kbrd, 0x33);
  269.         chardev_push_character(&kbrd, 0x7e);
  270.         break;
  271.     default:
  272.             letter = is_lower(ascii);
  273.         capslock = (keyflags & PRESSED_CAPSLOCK) || (lockflags & LOCKED_CAPSLOCK);
  274.         shift = keyflags & PRESSED_SHIFT;
  275.         if (letter && capslock)
  276.             shift = !shift;
  277.         if (shift)
  278.             map = sc_secondary_map;
  279.         chardev_push_character(&kbrd, map[sc]);
  280.         break;
  281.     }
  282.     spinlock_unlock(&keylock);
  283. }
  284.  
  285. /* Called from getc(). */
  286. void i8042_resume(chardev_t *d)
  287. {
  288. }
  289.  
  290. /* Called from getc(). */
  291. void i8042_suspend(chardev_t *d)
  292. {
  293. }
  294.  
  295. static uint8_t active_read_buff_read(void)
  296. {
  297.     static int i=0;
  298.     i &= (ACTIVE_READ_BUFF_SIZE-1);
  299.     if(!active_read_buff[i]) {
  300.         return 0;
  301.     }
  302.     return active_read_buff[i++];
  303. }
  304.  
  305. static void active_read_buff_write(uint8_t ch)
  306. {
  307.     static int i=0;
  308.     active_read_buff[i] = ch;
  309.     i++;
  310.     i &= (ACTIVE_READ_BUFF_SIZE-1);
  311.     active_read_buff[i]=0;
  312. }
  313.  
  314.  
  315. static void active_read_key_pressed(uint8_t sc)
  316. {
  317.     char *map = sc_primary_map;
  318.     char ascii = sc_primary_map[sc];
  319.     bool shift, capslock;
  320.     bool letter = false;
  321.  
  322.     /*spinlock_lock(&keylock);*/
  323.     switch (sc) {
  324.     case SC_LSHIFT:
  325.     case SC_RSHIFT:
  326.             keyflags |= PRESSED_SHIFT;
  327.         break;
  328.     case SC_CAPSLOCK:
  329.         keyflags |= PRESSED_CAPSLOCK;
  330.         break;
  331.     case SC_SPEC_ESCAPE:
  332.         break;
  333.     case SC_LEFTARR:
  334.         active_read_buff_write(0x1b);
  335.         active_read_buff_write(0x5b);
  336.         active_read_buff_write(0x44);
  337.         break;
  338.     case SC_RIGHTARR:
  339.         active_read_buff_write(0x1b);
  340.         active_read_buff_write(0x5b);
  341.         active_read_buff_write(0x43);
  342.         break;
  343.     case SC_UPARR:
  344.         active_read_buff_write(0x1b);
  345.         active_read_buff_write(0x5b);
  346.         active_read_buff_write(0x41);
  347.         break;
  348.     case SC_DOWNARR:
  349.         active_read_buff_write(0x1b);
  350.         active_read_buff_write(0x5b);
  351.         active_read_buff_write(0x42);
  352.         break;
  353.     case SC_HOME:
  354.         active_read_buff_write(0x1b);
  355.         active_read_buff_write(0x4f);
  356.         active_read_buff_write(0x48);
  357.         break;
  358.     case SC_END:
  359.         active_read_buff_write(0x1b);
  360.         active_read_buff_write(0x4f);
  361.         active_read_buff_write(0x46);
  362.         break;
  363.     case SC_DELETE:
  364.         active_read_buff_write(0x1b);
  365.         active_read_buff_write(0x5b);
  366.         active_read_buff_write(0x33);
  367.         active_read_buff_write(0x7e);
  368.         break;
  369.     default:
  370.             letter = is_lower(ascii);
  371.         capslock = (keyflags & PRESSED_CAPSLOCK) || (lockflags & LOCKED_CAPSLOCK);
  372.         shift = keyflags & PRESSED_SHIFT;
  373.         if (letter && capslock)
  374.             shift = !shift;
  375.         if (shift)
  376.             map = sc_secondary_map;
  377.         active_read_buff_write(map[sc]);
  378.         break;
  379.     }
  380.     /*spinlock_unlock(&keylock);*/
  381.  
  382. }
  383.  
  384. static char key_read(chardev_t *d)
  385. {
  386.     char ch;   
  387.  
  388.     while(!(ch = active_read_buff_read())) {
  389.         uint8_t x;
  390.         while (!(i8042_status_read() & i8042_BUFFER_FULL_MASK))
  391.             ;
  392.         x = i8042_data_read();
  393.         if (x != IGNORE_CODE) {
  394.             if (x & KEY_RELEASE)
  395.                 key_released(x ^ KEY_RELEASE);
  396.             else
  397.                 active_read_key_pressed(x);
  398.         }
  399.     }
  400.     return ch;
  401. }
  402.  
  403. /** Poll for key press and release events.
  404.  *
  405.  * This function can be used to implement keyboard polling.
  406.  */
  407. void i8042_poll(void)
  408. {
  409.     uint8_t x;
  410.  
  411.     while (((x = i8042_status_read() & i8042_BUFFER_FULL_MASK))) {
  412.         x = i8042_data_read();
  413.         if (x != IGNORE_CODE) {
  414.             if (x & KEY_RELEASE)
  415.                 key_released(x ^ KEY_RELEASE);
  416.             else
  417.                 key_pressed(x);
  418.         }
  419.     }
  420. }
  421.  
  422. /** @}
  423.  */
  424.  
  425.