Subversion Repositories HelenOS

Rev

Rev 1841 | 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   Zilog 8530 serial port / keyboard driver.
  35.  *
  36.  * Note that this file is derived from the i8042.c.
  37.  * The i8042 driver could be persuaded to control
  38.  * the z8530 at least in the polling mode.
  39.  * As a result, this file may contain inaccurate
  40.  * and z8530-irrelevant constants, code and comments.
  41.  * Still it miraculously works.
  42.  */
  43.  
  44. #include <genarch/kbd/z8530.h>
  45. #include <genarch/kbd/scanc.h>
  46. #include <genarch/kbd/scanc_sun.h>
  47. #include <arch/drivers/z8530.h>
  48. #include <arch/interrupt.h>
  49. #include <cpu.h>
  50. #include <arch/asm.h>
  51. #include <arch.h>
  52. #include <synch/spinlock.h>
  53. #include <typedefs.h>
  54. #include <console/chardev.h>
  55. #include <console/console.h>
  56. #include <macros.h>
  57. #include <interrupt.h>
  58.  
  59. /* Keyboard commands. */
  60. #define KBD_ENABLE  0xf4
  61. #define KBD_DISABLE 0xf5
  62. #define KBD_ACK     0xfa
  63.  
  64. /*
  65.  * 60  Write 8042 Command Byte: next data byte written to port 60h is
  66.  *     placed in 8042 command register. Format:
  67.  *
  68.  *    |7|6|5|4|3|2|1|0|8042 Command Byte
  69.  *     | | | | | | | `---- 1=enable output register full interrupt
  70.  *     | | | | | | `----- should be 0
  71.  *     | | | | | `------ 1=set status register system, 0=clear
  72.  *     | | | | `------- 1=override keyboard inhibit, 0=allow inhibit
  73.  *     | | | `-------- disable keyboard I/O by driving clock line low
  74.  *     | | `--------- disable auxiliary device, drives clock line low
  75.  *     | `---------- IBM scancode translation 0=AT, 1=PC/XT
  76.  *     `----------- reserved, should be 0
  77.  */
  78.  
  79. #define z8530_SET_COMMAND   0x60
  80. #define z8530_COMMAND       0x69
  81.  
  82. #define z8530_BUFFER_FULL_MASK  0x01
  83. #define z8530_WAIT_MASK     0x02
  84. #define z8530_MOUSE_DATA        0x20
  85.  
  86. #define KEY_RELEASE 0x80
  87.  
  88. /*
  89.  * These codes read from z8530 data register are silently ignored.
  90.  */
  91. #define IGNORE_CODE 0x7f        /* all keys up */
  92.  
  93. static void key_released(uint8_t sc);
  94. static void key_pressed(uint8_t sc);
  95. static char key_read(chardev_t *d);
  96.  
  97. #define PRESSED_SHIFT       (1<<0)
  98. #define PRESSED_CAPSLOCK    (1<<1)
  99. #define LOCKED_CAPSLOCK     (1<<0)
  100.  
  101. #define ACTIVE_READ_BUFF_SIZE 16    /* Must be power of 2 */
  102.  
  103. static uint8_t active_read_buff[ACTIVE_READ_BUFF_SIZE];
  104.  
  105. SPINLOCK_INITIALIZE(keylock);       /**< keylock protects keyflags and lockflags. */
  106. static volatile int keyflags;       /**< Tracking of multiple keypresses. */
  107. static volatile int lockflags;      /**< Tracking of multiple keys lockings. */
  108.  
  109. static void z8530_suspend(chardev_t *);
  110. static void z8530_resume(chardev_t *);
  111.  
  112. static chardev_t kbrd;
  113. static chardev_operations_t ops = {
  114.     .suspend = z8530_suspend,
  115.     .resume = z8530_resume,
  116.     .read = key_read
  117. };
  118.  
  119. static void z8530_interrupt(int n, istate_t *istate);
  120. static void z8530_wait(void);
  121.  
  122. static iroutine oldvector;
  123. /** Initialize keyboard and service interrupts using kernel routine */
  124. void z8530_grab(void)
  125. {
  126.     oldvector = exc_register(VECTOR_KBD, "z8530_interrupt", (iroutine) z8530_interrupt);
  127.     z8530_wait();
  128.     z8530_command_write(z8530_SET_COMMAND);
  129.     z8530_wait();
  130.     z8530_data_write(z8530_COMMAND);
  131.     z8530_wait();
  132. }
  133. /** Resume the former interrupt vector */
  134. void z8530_release(void)
  135. {
  136.     if (oldvector)
  137.         exc_register(VECTOR_KBD, "user_interrupt", oldvector);
  138. }
  139.  
  140. /** Initialize z8530. */
  141. void z8530_init(void)
  142. {
  143.     int i;
  144.  
  145.     z8530_grab();
  146.         /* Prevent user from accidentaly releasing calling z8530_resume
  147.      * and disabling keyboard
  148.      */
  149.     oldvector = NULL;
  150.  
  151.     trap_virtual_enable_irqs(1<<IRQ_KBD);
  152.     chardev_initialize("z8530_kbd", &kbrd, &ops);
  153.     stdin = &kbrd;
  154.  
  155.     /*
  156.      * Clear input buffer.
  157.      * Number of iterations is limited to prevent infinite looping.
  158.      */
  159.     for (i = 0; (z8530_status_read() & z8530_BUFFER_FULL_MASK) && i < 100; i++) {
  160.         z8530_data_read();
  161.     }  
  162. }
  163.  
  164. /** Process z8530 interrupt.
  165.  *
  166.  * @param n Interrupt vector.
  167.  * @param istate Interrupted state.
  168.  */
  169. void z8530_interrupt(int n, istate_t *istate)
  170. {
  171.     uint8_t x;
  172.     uint8_t status;
  173.  
  174.     while (((status=z8530_status_read()) & z8530_BUFFER_FULL_MASK)) {
  175.         x = z8530_data_read();
  176.  
  177.         if ((status & z8530_MOUSE_DATA))
  178.             continue;
  179.  
  180.         if (x & KEY_RELEASE)
  181.             key_released(x ^ KEY_RELEASE);
  182.         else
  183.             key_pressed(x);
  184.     }
  185.     trap_virtual_eoi();
  186. }
  187.  
  188. /** Wait until the controller reads its data. */
  189. void z8530_wait(void) {
  190.     while (z8530_status_read() & z8530_WAIT_MASK) {
  191.         /* wait */
  192.     }
  193. }
  194.  
  195. /** Process release of key.
  196.  *
  197.  * @param sc Scancode of the key being released.
  198.  */
  199. void key_released(uint8_t sc)
  200. {
  201.     spinlock_lock(&keylock);
  202.     switch (sc) {
  203.         case SC_LSHIFT:
  204.         case SC_RSHIFT:
  205.         keyflags &= ~PRESSED_SHIFT;
  206.         break;
  207.         case SC_CAPSLOCK:
  208.         keyflags &= ~PRESSED_CAPSLOCK;
  209.         if (lockflags & LOCKED_CAPSLOCK)
  210.             lockflags &= ~LOCKED_CAPSLOCK;
  211.         else
  212.             lockflags |= LOCKED_CAPSLOCK;
  213.         break;
  214.         default:
  215.         break;
  216.     }
  217.     spinlock_unlock(&keylock);
  218. }
  219.  
  220. /** Process keypress.
  221.  *
  222.  * @param sc Scancode of the key being pressed.
  223.  */
  224. void key_pressed(uint8_t sc)
  225. {
  226.     char *map = sc_primary_map;
  227.     char ascii = sc_primary_map[sc];
  228.     bool shift, capslock;
  229.     bool letter = false;
  230.  
  231.     spinlock_lock(&keylock);
  232.     switch (sc) {
  233.     case SC_LSHIFT:
  234.     case SC_RSHIFT:
  235.             keyflags |= PRESSED_SHIFT;
  236.         break;
  237.     case SC_CAPSLOCK:
  238.         keyflags |= PRESSED_CAPSLOCK;
  239.         break;
  240.     case SC_SPEC_ESCAPE:
  241.         break;
  242.     case SC_LEFTARR:
  243.         chardev_push_character(&kbrd, 0x1b);
  244.         chardev_push_character(&kbrd, 0x5b);
  245.         chardev_push_character(&kbrd, 0x44);
  246.         break;
  247.     case SC_RIGHTARR:
  248.         chardev_push_character(&kbrd, 0x1b);
  249.         chardev_push_character(&kbrd, 0x5b);
  250.         chardev_push_character(&kbrd, 0x43);
  251.         break;
  252.     case SC_UPARR:
  253.         chardev_push_character(&kbrd, 0x1b);
  254.         chardev_push_character(&kbrd, 0x5b);
  255.         chardev_push_character(&kbrd, 0x41);
  256.         break;
  257.     case SC_DOWNARR:
  258.         chardev_push_character(&kbrd, 0x1b);
  259.         chardev_push_character(&kbrd, 0x5b);
  260.         chardev_push_character(&kbrd, 0x42);
  261.         break;
  262.     case SC_HOME:
  263.         chardev_push_character(&kbrd, 0x1b);
  264.         chardev_push_character(&kbrd, 0x4f);
  265.         chardev_push_character(&kbrd, 0x48);
  266.         break;
  267.     case SC_END:
  268.         chardev_push_character(&kbrd, 0x1b);
  269.         chardev_push_character(&kbrd, 0x4f);
  270.         chardev_push_character(&kbrd, 0x46);
  271.         break;
  272.     case SC_DELETE:
  273.         chardev_push_character(&kbrd, 0x1b);
  274.         chardev_push_character(&kbrd, 0x5b);
  275.         chardev_push_character(&kbrd, 0x33);
  276.         chardev_push_character(&kbrd, 0x7e);
  277.         break;
  278.     default:
  279.             letter = is_lower(ascii);
  280.         capslock = (keyflags & PRESSED_CAPSLOCK) || (lockflags & LOCKED_CAPSLOCK);
  281.         shift = keyflags & PRESSED_SHIFT;
  282.         if (letter && capslock)
  283.             shift = !shift;
  284.         if (shift)
  285.             map = sc_secondary_map;
  286.         chardev_push_character(&kbrd, map[sc]);
  287.         break;
  288.     }
  289.     spinlock_unlock(&keylock);
  290. }
  291.  
  292. /* Called from getc(). */
  293. void z8530_resume(chardev_t *d)
  294. {
  295. }
  296.  
  297. /* Called from getc(). */
  298. void z8530_suspend(chardev_t *d)
  299. {
  300. }
  301.  
  302. static uint8_t active_read_buff_read(void)
  303. {
  304.     static int i=0;
  305.     i &= (ACTIVE_READ_BUFF_SIZE-1);
  306.     if(!active_read_buff[i]) {
  307.         return 0;
  308.     }
  309.     return active_read_buff[i++];
  310. }
  311.  
  312. static void active_read_buff_write(uint8_t ch)
  313. {
  314.     static int i=0;
  315.     active_read_buff[i] = ch;
  316.     i++;
  317.     i &= (ACTIVE_READ_BUFF_SIZE-1);
  318.     active_read_buff[i]=0;
  319. }
  320.  
  321.  
  322. static void active_read_key_pressed(uint8_t sc)
  323. {
  324.     char *map = sc_primary_map;
  325.     char ascii = sc_primary_map[sc];
  326.     bool shift, capslock;
  327.     bool letter = false;
  328.  
  329.     /*spinlock_lock(&keylock);*/
  330.     switch (sc) {
  331.     case SC_LSHIFT:
  332.     case SC_RSHIFT:
  333.             keyflags |= PRESSED_SHIFT;
  334.         break;
  335.     case SC_CAPSLOCK:
  336.         keyflags |= PRESSED_CAPSLOCK;
  337.         break;
  338.     case SC_SPEC_ESCAPE:
  339.         break;
  340.     case SC_LEFTARR:
  341.         active_read_buff_write(0x1b);
  342.         active_read_buff_write(0x5b);
  343.         active_read_buff_write(0x44);
  344.         break;
  345.     case SC_RIGHTARR:
  346.         active_read_buff_write(0x1b);
  347.         active_read_buff_write(0x5b);
  348.         active_read_buff_write(0x43);
  349.         break;
  350.     case SC_UPARR:
  351.         active_read_buff_write(0x1b);
  352.         active_read_buff_write(0x5b);
  353.         active_read_buff_write(0x41);
  354.         break;
  355.     case SC_DOWNARR:
  356.         active_read_buff_write(0x1b);
  357.         active_read_buff_write(0x5b);
  358.         active_read_buff_write(0x42);
  359.         break;
  360.     case SC_HOME:
  361.         active_read_buff_write(0x1b);
  362.         active_read_buff_write(0x4f);
  363.         active_read_buff_write(0x48);
  364.         break;
  365.     case SC_END:
  366.         active_read_buff_write(0x1b);
  367.         active_read_buff_write(0x4f);
  368.         active_read_buff_write(0x46);
  369.         break;
  370.     case SC_DELETE:
  371.         active_read_buff_write(0x1b);
  372.         active_read_buff_write(0x5b);
  373.         active_read_buff_write(0x33);
  374.         active_read_buff_write(0x7e);
  375.         break;
  376.     default:
  377.             letter = is_lower(ascii);
  378.         capslock = (keyflags & PRESSED_CAPSLOCK) || (lockflags & LOCKED_CAPSLOCK);
  379.         shift = keyflags & PRESSED_SHIFT;
  380.         if (letter && capslock)
  381.             shift = !shift;
  382.         if (shift)
  383.             map = sc_secondary_map;
  384.         active_read_buff_write(map[sc]);
  385.         break;
  386.     }
  387.     /*spinlock_unlock(&keylock);*/
  388.  
  389. }
  390.  
  391. static char key_read(chardev_t *d)
  392. {
  393.     char ch;   
  394.  
  395.     while(!(ch = active_read_buff_read())) {
  396.         uint8_t x;
  397.         while (!(z8530_status_read() & z8530_BUFFER_FULL_MASK))
  398.             ;
  399.         x = z8530_data_read();
  400.         if (x != IGNORE_CODE) {
  401.             if (x & KEY_RELEASE)
  402.                 key_released(x ^ KEY_RELEASE);
  403.             else
  404.                 active_read_key_pressed(x);
  405.         }
  406.     }
  407.     return ch;
  408. }
  409.  
  410. /** Poll for key press and release events.
  411.  *
  412.  * This function can be used to implement keyboard polling.
  413.  */
  414. void z8530_poll(void)
  415. {
  416.     uint8_t x;
  417.  
  418.     while (((x = z8530_status_read() & z8530_BUFFER_FULL_MASK))) {
  419.         x = z8530_data_read();
  420.         if (x != IGNORE_CODE) {
  421.             if (x & KEY_RELEASE)
  422.                 key_released(x ^ KEY_RELEASE);
  423.             else
  424.                 key_pressed(x);
  425.         }
  426.     }
  427. }
  428.  
  429. /** @}
  430.  */
  431.