patch-2.1.43 linux/drivers/char/pc_keyb.c
Next file: linux/drivers/char/pc_keyb.h
Previous file: linux/drivers/char/misc.c
Back to the patch index
Back to the overall index
- Lines: 511
- Date:
Thu Jun 12 16:22:06 1997
- Orig file:
v2.1.42/linux/drivers/char/pc_keyb.c
- Orig date:
Thu May 29 21:53:05 1997
diff -u --recursive --new-file v2.1.42/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
@@ -1,20 +1,10 @@
/*
* linux/drivers/char/pc_keyb.c
*
- * Written for linux by Johan Myreen as a translation from
- * the assembly version by Linus (with diacriticals added)
- *
- * Some additional features added by Christoph Niemann (ChN), March 1993
- *
- * Loadable keymaps by Risto Kankkunen, May 1993
- *
- * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
- * Added decr/incr_console, dynamic keymaps, Unicode support,
- * dynamic function/string keys, led setting, Sept 1994
- * `Sticky' modifier keys, 951006.
- * 11-11-96: SAK should now work in the raw mode (Martin Mares)
- *
* Separation of the PC low-level part by Geert Uytterhoeven, May 1997
+ * See keyboard.c for the whole history.
+ *
+ * Major cleanup by Martin Mares, May 1997
*/
#include <linux/sched.h>
@@ -24,46 +14,181 @@
#include <linux/signal.h>
#include <linux/ioport.h>
#include <linux/init.h>
+#include <linux/kbd_ll.h>
#include <asm/keyboard.h>
#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+/* Some configuration switches are present in the include file... */
+
+#include "pc_keyb.h"
/*
- * On non-x86 hardware we do a full keyboard controller
- * initialization, in case the bootup software hasn't done
- * it. On a x86, the BIOS will already have initialized the
- * keyboard.
+ * In case we run on a non-x86 hardware we need to initialize both the keyboard
+ * controller and the keyboard. On a x86, the BIOS will already have initialized
+ * them.
*/
+
#ifdef INIT_KBD
-static int initialize_kbd(void);
-#endif
-#include <asm/io.h>
-#include <asm/system.h>
+__initfunc(static int kbd_wait_for_input(void))
+{
+ int n;
+ int status, data;
-unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
+ n = KBD_TIMEOUT;
+ do {
+ status = inb(KBD_STATUS_REG);
+ /*
+ * Wait for input data to become available. This bit will
+ * then be cleared by the following read of the DATA
+ * register.
+ */
+
+ if (!(status & KBD_STAT_OBF))
+ continue;
+
+ data = inb(KBD_DATA_REG);
+
+ /*
+ * Check to see if a timeout error has occurred. This means
+ * that transmission was started but did not complete in the
+ * normal time cycle. PERR is set when a parity error occurred
+ * in the last transmission.
+ */
+ if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) {
+ continue;
+ }
+ return (data & 0xff);
+ } while (--n);
+ return -1; /* timed-out if fell through to here... */
+}
+
+__initfunc(static void kbd_write(int address, int data))
+{
+ int status;
+
+ do {
+ status = inb(KBD_STATUS_REG);
+ } while (status & KBD_STAT_IBF);
+ outb(data, address);
+}
+
+__initfunc(static char *initialize_kbd2(void))
+{
+ /* Flush any pending input. */
+
+ while (kbd_wait_for_input() != -1)
+ ;
+
+ /*
+ * Test the keyboard interface.
+ * This seems to be the only way to get it going.
+ * If the test is successful a x55 is placed in the input buffer.
+ */
+
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST);
+ if (kbd_wait_for_input() != 0x55)
+ return "Keyboard failed self test";
+
+ /*
+ * Perform a keyboard interface test. This causes the controller
+ * to test the keyboard clock and data lines. The results of the
+ * test are placed in the input buffer.
+ */
+
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST);
+ if (kbd_wait_for_input() != 0x00)
+ return "Keyboard interface failed self test";
+
+ /* Enable the keyboard by allowing the keyboard clock to run. */
+
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE);
+
+ /*
+ * Reset keyboard. If the read times out
+ * then the assumption is that no keyboard is
+ * plugged into the machine.
+ * This defaults the keyboard to scan-code set 2.
+ */
+
+ kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Keyboard reset failed, no ACK";
+ if (kbd_wait_for_input() != KBD_REPLY_POR)
+ return "Keyboard reset failed, no POR";
+
+ /*
+ * Set keyboard controller mode. During this, the keyboard should be
+ * in the disabled state.
+ */
+
+ kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Disable keyboard: no ACK";
+
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);
+ kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT
+ | KBD_MODE_SYS
+ | KBD_MODE_DISABLE_MOUSE
+ | KBD_MODE_KCC);
+
+ kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Enable keyboard: no ACK";
+
+ /*
+ * Finally, set the typematic rate to maximum.
+ */
+
+ kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Set rate: no ACK";
+ kbd_write(KBD_DATA_REG, 0x00);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Set rate: no ACK";
+
+ return NULL;
+}
+
+__initfunc(static void initialize_kbd(void))
+{
+ unsigned long flags;
+ char *msg;
+
+ save_flags(flags); cli();
+ msg = initialize_kbd2();
+ restore_flags(flags);
+
+ if (msg)
+ printk(KERN_WARNING "initialize_kbd: %s\n", msg);
+}
+
+#endif /* INIT_KBD */
+
+unsigned char kbd_read_mask = KBD_STAT_OBF; /* Modified by psaux.c */
/* used only by send_data - set by keyboard_interrupt */
static volatile unsigned char reply_expected = 0;
static volatile unsigned char acknowledge = 0;
static volatile unsigned char resend = 0;
-/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
+/*
+ * Wait for keyboard controller input buffer is empty.
+ */
+
static inline void kb_wait(void)
{
int i;
- for (i=0; i<0x100000; i++)
- if ((inb_p(0x64) & 0x02) == 0)
+ for (i=0; i<KBD_TIMEOUT; i++)
+ if (! (inb_p(KBD_STATUS_REG) & KBD_STAT_IBF))
return;
printk(KERN_WARNING "Keyboard timed out\n");
}
-extern struct pt_regs *pt_regs;
-
-extern void handle_scancode(unsigned char scancode);
-
-
/*
* Translation of escaped scancodes to keycodes.
* This is now user-settable.
@@ -204,11 +329,11 @@
static inline void send_cmd(unsigned char c)
{
kb_wait();
- outb(c,0x64);
+ outb(c, KBD_CNTL_REG);
}
-#define disable_keyboard() do { send_cmd(0xAD); kb_wait(); } while (0)
-#define enable_keyboard() send_cmd(0xAE)
+#define disable_keyboard() do { send_cmd(KBD_CCMD_KBD_DISABLE); kb_wait(); } while (0)
+#define enable_keyboard() send_cmd(KBD_CCMD_KBD_ENABLE)
#else
#define disable_keyboard() /* nothing */
#define enable_keyboard() /* nothing */
@@ -217,18 +342,21 @@
static int do_acknowledge(unsigned char scancode)
{
if (reply_expected) {
- /* 0xfa, 0xfe only mean "acknowledge", "resend" for most keyboards */
- /* but they are the key-up scancodes for PF6, PF10 on a FOCUS 9000 */
- reply_expected = 0;
- if (scancode == 0xfa) {
+ /* Unfortunately, we must recognise these codes only if we know they
+ * are known to be valid (i.e., after sending a command), because there
+ * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have
+ * keys with such codes :(
+ */
+ if (scancode == KBD_REPLY_ACK) {
acknowledge = 1;
+ reply_expected = 0;
return 0;
- } else if (scancode == 0xfe) {
+ } else if (scancode == KBD_REPLY_RESEND) {
resend = 1;
+ reply_expected = 0;
return 0;
}
- /* strange ... */
- reply_expected = 1;
+ /* Should not happen... */
#if 0
printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
scancode);
@@ -359,23 +487,23 @@
{
unsigned char status;
- pt_regs = regs;
+ kbd_pt_regs = regs;
disable_keyboard();
- status = inb_p(0x64);
+ status = inb_p(KBD_STATUS_REG);
do {
unsigned char scancode;
/* mouse data? */
- if (status & kbd_read_mask & 0x20)
+ if (status & kbd_read_mask & KBD_STAT_MOUSE_OBF)
break;
- scancode = inb(0x60);
- if ((status & 0x01) && do_acknowledge(scancode))
+ scancode = inb(KBD_DATA_REG);
+ if ((status & KBD_STAT_OBF) && do_acknowledge(scancode))
handle_scancode(scancode);
- status = inb(0x64);
- } while (status & 0x01);
+ status = inb(KBD_STATUS_REG);
+ } while (status & (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF));
mark_bh(KEYBOARD_BH);
enable_keyboard();
@@ -396,9 +524,9 @@
acknowledge = 0;
resend = 0;
reply_expected = 1;
- outb_p(data, 0x60);
+ outb_p(data, KBD_DATA_REG);
for(i=0; i<0x200000; i++) {
- inb_p(0x64); /* just as a delay */
+ inb_p(KBD_STATUS_REG); /* just as a delay */
if (acknowledge)
return 1;
if (resend)
@@ -412,197 +540,15 @@
void pckbd_leds(unsigned char leds)
{
- if (!send_data(0xed) || !send_data(leds))
- send_data(0xf4); /* re-enable kbd if any errors */
+ if (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))
+ send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */
}
__initfunc(void pckbd_init_hw(void))
{
request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
- request_region(0x60,16,"keyboard");
+ request_region(0x60, 16, "keyboard");
#ifdef INIT_KBD
initialize_kbd();
#endif
}
-
-#ifdef INIT_KBD
-/*
- * keyboard controller registers
- */
-#define KBD_STATUS_REG (unsigned int) 0x64
-#define KBD_CNTL_REG (unsigned int) 0x64
-#define KBD_DATA_REG (unsigned int) 0x60
-/*
- * controller commands
- */
-#define KBD_READ_MODE (unsigned int) 0x20
-#define KBD_WRITE_MODE (unsigned int) 0x60
-#define KBD_SELF_TEST (unsigned int) 0xAA
-#define KBD_SELF_TEST2 (unsigned int) 0xAB
-#define KBD_CNTL_ENABLE (unsigned int) 0xAE
-/*
- * keyboard commands
- */
-#define KBD_ENABLE (unsigned int) 0xF4
-#define KBD_DISABLE (unsigned int) 0xF5
-#define KBD_RESET (unsigned int) 0xFF
-/*
- * keyboard replies
- */
-#define KBD_ACK (unsigned int) 0xFA
-#define KBD_POR (unsigned int) 0xAA
-/*
- * status register bits
- */
-#define KBD_OBF (unsigned int) 0x01
-#define KBD_IBF (unsigned int) 0x02
-#define KBD_GTO (unsigned int) 0x40
-#define KBD_PERR (unsigned int) 0x80
-/*
- * keyboard controller mode register bits
- */
-#define KBD_EKI (unsigned int) 0x01
-#define KBD_SYS (unsigned int) 0x04
-#define KBD_DMS (unsigned int) 0x20
-#define KBD_KCC (unsigned int) 0x40
-
-#define TIMEOUT_CONST 500000
-
-static int kbd_wait_for_input(void)
-{
- int n;
- int status, data;
-
- n = TIMEOUT_CONST;
- do {
- status = inb(KBD_STATUS_REG);
- /*
- * Wait for input data to become available. This bit will
- * then be cleared by the following read of the DATA
- * register.
- */
-
- if (!(status & KBD_OBF))
- continue;
-
- data = inb(KBD_DATA_REG);
-
- /*
- * Check to see if a timeout error has occurred. This means
- * that transmission was started but did not complete in the
- * normal time cycle. PERR is set when a parity error occurred
- * in the last transmission.
- */
- if (status & (KBD_GTO | KBD_PERR)) {
- continue;
- }
- return (data & 0xff);
- } while (--n);
- return (-1); /* timed-out if fell through to here... */
-}
-
-static void kbd_write(int address, int data)
-{
- int status;
-
- do {
- status = inb(KBD_STATUS_REG); /* spin until input buffer empty*/
- } while (status & KBD_IBF);
- outb(data, address); /* write out the data*/
-}
-
-__initfunc(static int initialize_kbd(void))
-{
- unsigned long flags;
-
- save_flags(flags); cli();
-
- /* Flush any pending input. */
- while (kbd_wait_for_input() != -1)
- continue;
-
- /*
- * Test the keyboard interface.
- * This seems to be the only way to get it going.
- * If the test is successful a x55 is placed in the input buffer.
- */
- kbd_write(KBD_CNTL_REG, KBD_SELF_TEST);
- if (kbd_wait_for_input() != 0x55) {
- printk(KERN_WARNING "initialize_kbd: "
- "keyboard failed self test.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * Perform a keyboard interface test. This causes the controller
- * to test the keyboard clock and data lines. The results of the
- * test are placed in the input buffer.
- */
- kbd_write(KBD_CNTL_REG, KBD_SELF_TEST2);
- if (kbd_wait_for_input() != 0x00) {
- printk(KERN_WARNING "initialize_kbd: "
- "keyboard failed self test 2.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /* Enable the keyboard by allowing the keyboard clock to run. */
- kbd_write(KBD_CNTL_REG, KBD_CNTL_ENABLE);
-
- /*
- * Reset keyboard. If the read times out
- * then the assumption is that no keyboard is
- * plugged into the machine.
- * This defaults the keyboard to scan-code set 2.
- */
- kbd_write(KBD_DATA_REG, KBD_RESET);
- if (kbd_wait_for_input() != KBD_ACK) {
- printk(KERN_WARNING "initialize_kbd: "
- "reset kbd failed, no ACK.\n");
- restore_flags(flags);
- return(-1);
- }
-
- if (kbd_wait_for_input() != KBD_POR) {
- printk(KERN_WARNING "initialize_kbd: "
- "reset kbd failed, not POR.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * now do a DEFAULTS_DISABLE always
- */
- kbd_write(KBD_DATA_REG, KBD_DISABLE);
- if (kbd_wait_for_input() != KBD_ACK) {
- printk(KERN_WARNING "initialize_kbd: "
- "disable kbd failed, no ACK.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * Enable keyboard interrupt, operate in "sys" mode,
- * enable keyboard (by clearing the disable keyboard bit),
- * disable mouse, do conversion of keycodes.
- */
- kbd_write(KBD_CNTL_REG, KBD_WRITE_MODE);
- kbd_write(KBD_DATA_REG, KBD_EKI|KBD_SYS|KBD_DMS|KBD_KCC);
-
- /*
- * now ENABLE the keyboard to set it scanning...
- */
- kbd_write(KBD_DATA_REG, KBD_ENABLE);
- if (kbd_wait_for_input() != KBD_ACK) {
- printk(KERN_WARNING "initialize_kbd: "
- "keyboard enable failed.\n");
- restore_flags(flags);
- return(-1);
- }
-
- restore_flags(flags);
-
- return (1);
-}
-#endif /* INIT_KBD */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov