sos-code-article10/drivers/kbd.c

119 lines
3.0 KiB
C

/* 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 <sos/types.h>
#include <sos/errno.h>
#include <sos/assert.h>
#include <hwcore/irq.h>
#include <hwcore/ioports.h>
#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;
}