lkml.org 
[lkml]   [1998]   [Sep]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
SubjectRe: 2.1.120 breaks PC keyboard
Date
In article <006b01bdd9cc$c4c73fb0$fe01a8c0@speedo.foonet.ikea.com>,
ANOS <anders.ostling@neurope.ikea.com> wrote:
>
>I have also seen this with various versions. When I removed
>"vga=ask" in lilo.conf, it went away. Very reproducable on my
>Compaq Deskpro 6000 (PII).

Curiousier and curiousier.

So it definitely seems to be a question of some unexpected state for the
keyboard controller during the bootup sequence..

I have a patch that I'd like people with problems to try out. No
guarantees that it fixes anything, but the keyboard setup sequence was
definitely fairly strange, and this cleans it up.

This is completely untested, but I'd be very interested to hear whether
this makes any difference for you (please try both with and without the
"kbd-reset" kernel command line and tell me the results for both),

Linus

-----
diff -u --recursive --new-file v2.1.120/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.1.120/linux/drivers/char/pc_keyb.c Sat Sep 5 16:46:40 1998
+++ linux/drivers/char/pc_keyb.c Sun Sep 6 13:39:09 1998
@@ -43,194 +43,6 @@
"\r\000/"; /* 0x60 - 0x6f */
#endif

-/*
- * 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.
- */
-
-/*
- * Some x86 BIOSes do not correctly initialize the keyboard, so the
- * "kbd-reset" command line options can be given to force a reset.
- * [Ranger]
- */
-#ifdef __i386__
- int kbd_startup_reset __initdata = 0;
-#else
- int kbd_startup_reset __initdata = 1;
-#endif
-
-__initfunc(static int kbd_wait_for_input(void))
-{
- long timeout = KBD_INIT_TIMEOUT;
- int retval = -1;
-
- goto in_loop;
- for (;;) {
- unsigned char status, data;
- if (--timeout < 0)
- break;
- mdelay(1);
-in_loop:
- 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;
-
- retval = data;
- break;
- }
- return retval;
-}
-
-__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))
-{
- int status;
-
- /* 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.
- *
- * Set up to try again if the keyboard asks for RESEND.
- */
-
- do {
- kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
- status = kbd_wait_for_input();
- if (status == KBD_REPLY_ACK)
- break;
- else if (status != KBD_REPLY_RESEND)
- return "Keyboard reset failed, no ACK";
- } while (1);
-
- 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.
- *
- * Set up to try again if the keyboard asks for RESEND.
- */
-
- do {
- kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
- status = kbd_wait_for_input();
- if (status == KBD_REPLY_ACK)
- break;
- else if (status != KBD_REPLY_RESEND)
- return "Disable keyboard: no ACK";
- } while (1);
-
- 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);
-
- /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
- kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE);
- if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
- /*
- * If the controller does not support conversion,
- * Set the keyboard to scan-code set 1.
- */
- kbd_write(KBD_DATA_REG, 0xF0);
- kbd_wait_for_input();
- kbd_write(KBD_DATA_REG, 0x01);
- kbd_wait_for_input();
- }
-
-
- 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))
-{
- char *msg;
-
- disable_irq(KEYBOARD_IRQ);
- msg = initialize_kbd2();
- enable_irq(KEYBOARD_IRQ);
-
- if (msg)
- printk(KERN_WARNING "initialize_kbd: %s\n", msg);
-}
-
-
-
unsigned char pckbd_read_mask = KBD_STAT_OBF; /* Modified by psaux.c */

/* used only by send_data - set by keyboard_interrupt */
@@ -625,15 +437,189 @@
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");
- if (kbd_startup_reset) initialize_kbd();
-}
+/*
+ * 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.
+ *
+ * Some x86 BIOSes do not correctly initialize the keyboard, so the
+ * "kbd-reset" command line options can be given to force a reset.
+ * [Ranger]
+ */
+#ifdef __i386__
+ int kbd_startup_reset __initdata = 0;
+#else
+ int kbd_startup_reset __initdata = 1;
+#endif

/* for "kbd-reset" cmdline param */
-__initfunc(void kbd_reset_setup(char *str, int *ints))
+void __init kbd_reset_setup(char *str, int *ints)
{
kbd_startup_reset = 1;
+}
+
+#define KBD_NO_DATA (-1) /* No data */
+#define KBD_BAD_DATA (-2) /* Parity or other error */
+
+static int __init kbd_read_input(void)
+{
+ int retval = KBD_NO_DATA;
+ unsigned char status;
+
+ status = inb(KBD_STATUS_REG);
+ if (status & KBD_STAT_OBF) {
+ unsigned char data = inb(KBD_DATA_REG);
+
+ retval = data;
+ if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
+ retval = KBD_BAD_DATA;
+ }
+ return retval;
+}
+
+static void __init kbd_clear_input(void)
+{
+ int maxread = 100; /* Random number */
+
+ do {
+ if (kbd_read_input() == KBD_NO_DATA)
+ break;
+ } while (--maxread);
+}
+
+static int __init kbd_wait_for_input(void)
+{
+ long timeout = KBD_INIT_TIMEOUT;
+
+ do {
+ int retval = kbd_read_input();
+ if (retval >= 0)
+ return retval;
+ mdelay(1);
+ } while (--timeout);
+ return -1;
+}
+
+static void __init kbd_write(int address, int data)
+{
+ int status;
+
+ do {
+ status = inb(KBD_STATUS_REG);
+ } while (status & KBD_STAT_IBF);
+ outb(data, address);
+}
+
+static char * __init initialize_kbd(void)
+{
+ int status;
+
+ /*
+ * 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.
+ *
+ * Set up to try again if the keyboard asks for RESEND.
+ */
+ do {
+ kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
+ status = kbd_wait_for_input();
+ if (status == KBD_REPLY_ACK)
+ break;
+ if (status != KBD_REPLY_RESEND)
+ return "Keyboard reset failed, no ACK";
+ } while (1);
+
+ 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.
+ *
+ * Set up to try again if the keyboard asks for RESEND.
+ */
+ do {
+ kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
+ status = kbd_wait_for_input();
+ if (status == KBD_REPLY_ACK)
+ break;
+ if (status != KBD_REPLY_RESEND)
+ return "Disable keyboard: no ACK";
+ } while (1);
+
+ 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);
+
+ /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE);
+ if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
+ /*
+ * If the controller does not support conversion,
+ * Set the keyboard to scan-code set 1.
+ */
+ kbd_write(KBD_DATA_REG, 0xF0);
+ kbd_wait_for_input();
+ kbd_write(KBD_DATA_REG, 0x01);
+ kbd_wait_for_input();
+ }
+
+
+ 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;
+}
+
+void __init pckbd_init_hw(void)
+{
+ /* Flush any pending input. */
+ kbd_clear_input();
+
+ if (kbd_startup_reset) {
+ char *msg = initialize_kbd();
+ if (msg)
+ printk(KERN_WARNING "initialize_kbd: %s\n", msg);
+ }
+
+ request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
+ request_region(0x60, 16, "keyboard");
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/faq.html

\
 
 \ /
  Last update: 2005-03-22 13:44    [W:0.047 / U:0.108 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site