/* Copyright (C) 2005 Thomas Petazzoni This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include "tty.h" /* * Keyboard ports and commands. * * @see Ralf Brown's interrupt (and port) list * http://www-2.cs.cmu.edu/~ralf/files.html */ #define KBD_DATA_PORT 0x60 #define KBD_BREAKCODE_LIMIT 0x80 #define KBD_EXTENDED_SCANCODE 0xE0 #define KBD_IS_MAKECODE(c) ((c) < KBD_BREAKCODE_LIMIT) #define KBD_IS_BREAKCODE(c) ((c) >= KBD_BREAKCODE_LIMIT) #define KBD_BREAKCODE_2_MAKECODE(c) ((c) ^ KBD_BREAKCODE_LIMIT) #define KBD_LEFTSHIFT_SCANCODE 0x2a #define KBD_RIGHTSHIFT_SCANCODE 0x36 typedef sos_ui8_t scancode_t; extern const char *kbd_regular_translate_table []; extern const char *kbd_shift_translate_table []; static const char **kbd_current_translate_table = kbd_regular_translate_table; static int is_ext = FALSE; static struct tty_device *tty; static void kbd_irq_handler (int irq_level) { scancode_t scancode; const char *key = NULL; scancode = inb (KBD_DATA_PORT); /* Mark that next interrupt wil give an extended scancode */ if (scancode == KBD_EXTENDED_SCANCODE) { is_ext = TRUE; } /* Handle extended scancode */ else if (is_ext) { is_ext = FALSE; } /* Normal scancode */ else { /* Keypressed */ if (KBD_IS_MAKECODE(scancode)) { /* If shift, change translation table */ if ((scancode == KBD_LEFTSHIFT_SCANCODE) || (scancode == KBD_RIGHTSHIFT_SCANCODE)) kbd_current_translate_table = kbd_shift_translate_table; /* If normal key, compute the result using the translation tables and the booleans */ else if (kbd_current_translate_table[scancode]) { key = kbd_current_translate_table[scancode]; } } /* Key released */ else { scancode_t makecode = KBD_BREAKCODE_2_MAKECODE(scancode); if ((makecode == KBD_LEFTSHIFT_SCANCODE) || (makecode == KBD_RIGHTSHIFT_SCANCODE)) kbd_current_translate_table = kbd_regular_translate_table; } } if (key) tty_add_chars (tty, key); } sos_ret_t sos_kbd_subsystem_setup(struct tty_device *t) { tty = t; sos_irq_set_routine (SOS_IRQ_KEYBOARD, kbd_irq_handler); return SOS_OK; }