patch-2.1.36 linux/arch/m68k/atari/atakeyb.c

Next file: linux/arch/m68k/atari/atari_ksyms.c
Previous file: linux/arch/m68k/atari/ataints.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.35/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c
@@ -14,6 +14,7 @@
  */
 
 #include <linux/sched.h>
+#include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/keyboard.h>
@@ -40,6 +41,15 @@
 /* Hook for mouse driver */
 void (*atari_mouse_interrupt_hook) (char *);
 
+/* variables for IKBD self test: */
+
+/* state: 0: off; >0: in progress; >1: 0xf1 received */
+static volatile int ikbd_self_test;
+/* timestamp when last received a char */
+static volatile unsigned long self_test_last_rcv;
+/* bitmap of keys reported as broken */
+static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, };
+
 #define BREAK_MASK	(0x80)
 
 /*
@@ -331,12 +341,15 @@
     {
 	/* a very fast typist or a slow system, give a warning */
 	/* ...happens often if interrupts were disabled for too long */
-	printk( "Keyboard overrun\n" );
+	printk( KERN_DEBUG "Keyboard overrun\n" );
 	scancode = acia.key_data;
 	/* Turn off autorepeating in case a break code has been lost */
 	del_timer( &atakeyb_rep_timer );
 	rep_scancode = 0;
-	if (IS_SYNC_CODE(scancode)) {
+	if (ikbd_self_test)
+	    /* During self test, don't do resyncing, just process the code */
+	    goto interpret_scancode;
+	else if (IS_SYNC_CODE(scancode)) {
 	    /* This code seem already to be the start of a new packet or a
 	     * single scancode */
 	    kb_state.state = KEYBOARD;
@@ -386,10 +399,47 @@
 		kb_state.buf[0] = scancode;
 		break;
 
+	      case 0xF1:
+		/* during self-test, note that 0xf1 received */
+		if (ikbd_self_test) {
+		    ++ikbd_self_test;
+		    self_test_last_rcv = jiffies;
+		    break;
+		}
+		/* FALL THROUGH */
+		
 	      default:
 		break_flag = scancode & BREAK_MASK;
 		scancode &= ~BREAK_MASK;
 
+		if (ikbd_self_test) {
+		    /* Scancodes sent during the self-test stand for broken
+		     * keys (keys being down). The code *should* be a break
+		     * code, but nevertheless some AT keyboard interfaces send
+		     * make codes instead. Therefore, simply ignore
+		     * break_flag...
+		     * */
+		    int keyval = ataplain_map[scancode], keytyp;
+		    
+		    set_bit( scancode, broken_keys );
+		    self_test_last_rcv = jiffies;
+		    keyval = ataplain_map[scancode];
+		    keytyp = KTYP(keyval) - 0xf0;
+		    keyval = KVAL(keyval);
+		    
+		    printk( KERN_WARNING "Key with scancode %d ", scancode );
+		    if (keytyp == KT_LATIN || keytyp == KT_LETTER) {
+			if (keyval < ' ')
+			    printk( "('^%c') ", keyval + '@' );
+			else
+			    printk( "('%c') ", keyval );
+		    }
+		    printk( "is broken -- will be ignored.\n" );
+		    break;
+		}
+		else if (test_bit( scancode, broken_keys ))
+		    break;
+		
 		if (break_flag) {
 		    del_timer( &atakeyb_rep_timer );
 		    rep_scancode = 0;
@@ -815,7 +865,18 @@
     mfp.active_edge &= ~0x10;
     atari_turnon_irq(IRQ_MFP_ACIA);
 
+    ikbd_self_test = 1;
     ikbd_reset();
+    /* wait for a period of inactivity (here: 0.25s), then assume the IKBD's
+     * self-test is finished */
+    self_test_last_rcv = jiffies;
+    while( jiffies < self_test_last_rcv + HZ/4 )
+	barrier();
+    /* if not incremented: no 0xf1 received */
+    if (ikbd_self_test == 1)
+	printk( KERN_ERR "WARNING: keyboard self test failed!\n" );
+    ikbd_self_test = 0;
+    
     ikbd_mouse_disable();
     ikbd_joystick_disable();
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov