
From: Dmitry Torokhov <dtor_core@ameritech.net>

> 	3) They light up a led on the keyboard,
	^^^^^^^^^^^^^^^^^^^^^^^^^^^^

atkbd tries to switch leds but one tasklet can not interrupt another so
it deadlocks...

You need to revert just the patch below, not entire bk-input


---

 25-akpm/drivers/input/serio/i8042.c |  140 ++++++++++++------------------------
 1 files changed, 49 insertions(+), 91 deletions(-)

diff -puN drivers/input/serio/i8042.c~revert-i8042-interrupt-handling drivers/input/serio/i8042.c
--- 25/drivers/input/serio/i8042.c~revert-i8042-interrupt-handling	2004-05-13 17:09:59.987912912 -0700
+++ 25-akpm/drivers/input/serio/i8042.c	2004-05-13 17:10:47.710657952 -0700
@@ -2,7 +2,6 @@
  *  i8042 keyboard and mouse controller driver for Linux
  *
  *  Copyright (c) 1999-2002 Vojtech Pavlik
- *  Copyright (c) 2004      Dmitry Torokhov
  */
 
 /*
@@ -75,14 +74,6 @@ struct i8042_values {
 	unsigned char *phys;
 };
 
-#define I8042_QUEUE_LEN		64
-struct {
-	unsigned char str[I8042_QUEUE_LEN];
-	unsigned char data[I8042_QUEUE_LEN];
-	unsigned int read_pos;
-	unsigned int write_pos;
-} i8042_buf;
-
 static struct serio i8042_kbd_port;
 static struct serio i8042_aux_port;
 static unsigned char i8042_initial_ctr;
@@ -91,7 +82,7 @@ static unsigned char i8042_mux_open;
 static unsigned char i8042_mux_present;
 static unsigned char i8042_sysdev_initialized;
 static struct pm_dev *i8042_pm_dev;
-static struct timer_list i8042_timer;
+struct timer_list i8042_timer;
 
 /*
  * Shared IRQ's require a device pointer, but this driver doesn't support
@@ -383,108 +374,76 @@ static char i8042_mux_short[4][16];
 static char i8042_mux_phys[4][32];
 
 /*
- * i8042_handle_data() is the most important function in this driver -
- * it processes data received by i8042_interrupt and sends it to the
- * upper layers.
+ * i8042_interrupt() is the most important function in this driver -
+ * it handles the interrupts from the i8042, and sends incoming bytes
+ * to the upper layers.
  */
 
-static void i8042_handle_data(unsigned long notused)
+static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+	unsigned long flags;
 	unsigned char str, data = 0;
 	unsigned int dfl;
+	int ret;
 
-	/*
-	 * No locking it required on i8042_buf as the tasklet is guaranteed
-	 * to be serialized and if write_pos changes while comparing it with
-	 * read_pos another run will be scheduled by i8042_interrupt.
-	 */
-	while (i8042_buf.read_pos != i8042_buf.write_pos) {
-
-		str = i8042_buf.str[i8042_buf.read_pos];
-		data = i8042_buf.data[i8042_buf.read_pos];
+	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
 
-		i8042_buf.read_pos++;
-		i8042_buf.read_pos %= I8042_QUEUE_LEN;
+	spin_lock_irqsave(&i8042_lock, flags);
+	str = i8042_read_status();
+	if (str & I8042_STR_OBF)
+		data = i8042_read_data();
+	spin_unlock_irqrestore(&i8042_lock, flags);
 
-		dfl = ((str & I8042_STR_PARITY)  ? SERIO_PARITY  : 0) |
-	      	      ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
-
-		if (i8042_mux_values[0].exists && (str & I8042_STR_AUXDATA)) {
-
-			if (str & I8042_STR_MUXERR) {
-				switch (data) {
-					case 0xfd:
-					case 0xfe: dfl = SERIO_TIMEOUT; break;
-					case 0xff: dfl = SERIO_PARITY; break;
-				}
-				data = 0xfe;
-			} else dfl = 0;
-
-			dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)",
-				data, (str >> 6), irq,
-				dfl & SERIO_PARITY ? ", bad parity" : "",
-				dfl & SERIO_TIMEOUT ? ", timeout" : "");
-
-			serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, NULL);
-		} else {
-
-			dbg("%02x <- i8042 (interrupt, %s, %d%s%s)",
-				data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq,
-				dfl & SERIO_PARITY ? ", bad parity" : "",
-				dfl & SERIO_TIMEOUT ? ", timeout" : "");
-
-			if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA))
-				serio_interrupt(&i8042_aux_port, data, dfl, NULL);
-			else if (i8042_kbd_values.exists)
-				serio_interrupt(&i8042_kbd_port, data, dfl, NULL);
-		}
+	if (~str & I8042_STR_OBF) {
+		if (irq) dbg("Interrupt %d, without any data", irq);
+		ret = 0;
+		goto out;
 	}
-}
 
-DECLARE_TASKLET(i8042_tasklet, i8042_handle_data, 0);
+	dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
+	      ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
 
-/*
- * i8042_interrupt() handles the interrupts from i8042 and schedules
- * i8042_handle_data to process and pass received bytes to the upper
- * layers.
- */
+	if (i8042_mux_values[0].exists && (str & I8042_STR_AUXDATA)) {
 
-static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	unsigned long flags;
-	unsigned char str;
-	unsigned int n_bytes = 0;
-
-	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
-
-	spin_lock_irqsave(&i8042_lock, flags);
-
-	while ((str = i8042_read_status()) & I8042_STR_OBF) {
-
-		n_bytes++;
+		if (str & I8042_STR_MUXERR) {
+			switch (data) {
+				case 0xfd:
+				case 0xfe: dfl = SERIO_TIMEOUT; break;
+				case 0xff: dfl = SERIO_PARITY; break;
+			}
+			data = 0xfe;
+		} else dfl = 0;
 
-		i8042_buf.str[i8042_buf.write_pos] = str;
-		i8042_buf.data[i8042_buf.write_pos] = i8042_read_data();
+		dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)",
+			data, (str >> 6), irq,
+			dfl & SERIO_PARITY ? ", bad parity" : "",
+			dfl & SERIO_TIMEOUT ? ", timeout" : "");
 
-		i8042_buf.write_pos++;
-		i8042_buf.write_pos %= I8042_QUEUE_LEN;
+		serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs);
 
-		if (unlikely(i8042_buf.write_pos == i8042_buf.read_pos))
-			printk(KERN_WARNING "i8042.c: ring buffer full\n");
+		goto irq_ret;
 	}
 
-	spin_unlock_irqrestore(&i8042_lock, flags);
+	dbg("%02x <- i8042 (interrupt, %s, %d%s%s)",
+		data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq,
+		dfl & SERIO_PARITY ? ", bad parity" : "",
+		dfl & SERIO_TIMEOUT ? ", timeout" : "");
 
-	if (unlikely(n_bytes == 0)) {
-		if (irq) dbg("Interrupt %d, without any data", irq);
-		return IRQ_NONE;
+	if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) {
+		serio_interrupt(&i8042_aux_port, data, dfl, regs);
+		goto irq_ret;
 	}
 
-	tasklet_schedule(&i8042_tasklet);
+	if (!i8042_kbd_values.exists)
+		goto irq_ret;
 
-	return IRQ_HANDLED;
-}
+	serio_interrupt(&i8042_kbd_port, data, dfl, regs);
 
+irq_ret:
+	ret = 1;
+out:
+	return IRQ_RETVAL(ret);
+}
 
 /*
  * i8042_enable_mux_mode checks whether the controller has an active
@@ -1060,7 +1019,6 @@ void __exit i8042_exit(void)
 			serio_unregister_port(i8042_mux_port + i);
 
 	del_timer_sync(&i8042_timer);
-	tasklet_kill(&i8042_tasklet);
 
 	i8042_platform_exit();
 }

_
