Skip to contentSkip to conversation

Input: resume support for i8042 (atkbd & psmouse)

PATCH In review Dmitry Torokhov 3 participants 6 messages Dec 1, 2003 – Dec 3, 2003 Input drivers

lore
Share & tools
lore
#0 lore raw

PATCH 1/3 Input: resume support for i8042 (atkbd & psmouse)

Hi,

Here is an attempt to implement resume for i8042 using serio_reconnect facility that can be found in -mm kernels. It also depends on bunch of other changes in input subsystem all of which can be found here:
http://www.geocities.com/dt_or/input

They should apply cleanly to -test11.

Dmitry

===================================================================

[email protected], 2003-12-01 01:41:05-05:00, [email protected]
Input: add i8042 to sysfs, implement resume methods using
serio_reconnect facility

 i8042.c |   90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 81 insertions(+), 9 deletions(-)

===================================================================

drivers/input/serio/i8042.c +81 -9
diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
@@ -17,6 +17,7 @@
 #include <linux/config.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
+#include <linux/sysdev.h>
 #include <linux/serio.h>
 
 #include <asm/io.h>
@@ -61,6 +62,8 @@
 static unsigned char i8042_mux_open;
 struct timer_list i8042_timer;
 
+static int i8042_sysdev_initialized;
+
 /*
  * Shared IRQ's require a device pointer, but this driver doesn't support
  * multiple devices
@@ -214,16 +217,35 @@
 }
 
 /*
- * i8042_open() is called when a port is open by the higher layer.
- * It allocates the interrupt and enables it in the chip.
+ * i8042_activate_port() enables port on a chip.
  */
 
-static int i8042_open(struct serio *port)
+static int i8042_activate_port(struct serio *port)
 {
 	struct i8042_values *values = port->driver;
 
 	i8042_flush();
 
+	i8042_ctr |= values->irqen;
+
+	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+		i8042_ctr &= ~values->irqen;
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+ * i8042_open() is called when a port is open by the higher layer.
+ * It allocates the interrupt and calls i8042_enable_port.
+ */
+
+static int i8042_open(struct serio *port)
+{
+	struct i8042_values *values = port->driver;
+
 	if (values->mux != -1)
 		if (i8042_mux_open++)
 			return 0;
@@ -234,10 +256,8 @@
 		goto irq_fail;
 	}
 
-	i8042_ctr |= values->irqen;
-
-	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
-		printk(KERN_ERR "i8042.c: Can't write CTR while opening %s, unregistering the port\n", values->name);
+	if (i8042_activate_port(port)) {
+		printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", values->name);
 		goto ctr_fail;
 	}
 
@@ -246,7 +266,6 @@
 	return 0;
 
 ctr_fail:
-	i8042_ctr &= ~values->irqen;
 	free_irq(values->irq, i8042_request_irq_cookie);
 
 irq_fail:
@@ -406,7 +425,7 @@
  * desired.
  */
 	
-static int __init i8042_controller_init(void)
+static int i8042_controller_init(void)
 {
 
 /*
@@ -541,6 +560,37 @@
 }
 
 /*
+ * Here we try to reset everything back to a state in which suspended
+ */
+
+static int i8042_controller_resume(struct sys_device *dev)
+{
+	int i;
+
+	if (i8042_controller_init()) {
+		printk(KERN_ERR "i8042: resume failed\n");
+		return -1;
+	}
+
+/*
+ * Reconnect anything that was connected to the ports.
+ */
+
+	if (i8042_kbd_values.exists && i8042_activate_port(&i8042_kbd_port) == 0)
+		serio_reconnect(&i8042_kbd_port);
+
+	if (i8042_aux_values.exists && i8042_activate_port(&i8042_aux_port) == 0)
+		serio_reconnect(&i8042_aux_port);
+
+	for (i = 0; i < 4; i++)
+		if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port + i) == 0)
+			serio_reconnect(i8042_mux_port + i);
+
+	return 0;
+}
+
+
+/*
  * i8042_check_mux() checks whether the controller supports the PS/2 Active
  * Multiplexing specification by Synaptics, Phoenix, Insyde and
  * LCS/Telegraphics.
@@ -791,6 +841,16 @@
 	values->mux = index;
 }
 
+static struct sysdev_class kbc_sysclass = {
+       set_kset_name("i8042"),
+       .resume = i8042_controller_resume,
+};
+
+static struct sys_device device_i8042 = {
+       .id     = 0,
+       .cls    = &kbc_sysclass,
+};
+
 int __init i8042_init(void)
 {
 	int i;
@@ -825,6 +885,13 @@
 	i8042_timer.function = i8042_timer_func;
 	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
 
+        if (sysdev_class_register(&kbc_sysclass) == 0) {
+                if (sys_device_register(&device_i8042) == 0)
+			i8042_sysdev_initialized = 1;
+		else
+			sysdev_class_unregister(&kbc_sysclass);
+        }
+
 	register_reboot_notifier(&i8042_notifier);
 
 	return 0;
@@ -835,6 +902,11 @@
 	int i;
 
 	unregister_reboot_notifier(&i8042_notifier);
+
+	if (i8042_sysdev_initialized) {
+		sys_device_unregister(&device_i8042);
+		sysdev_class_unregister(&kbc_sysclass);
+	}
 
 	del_timer(&i8042_timer);
 
#1 lore raw

PATCH 2/3 Input: resume support for i8042 (atkbd & psmouse)

===================================================================

[email protected], 2003-12-01 01:43:05-05:00, [email protected]
Input: Add reconnect method to atkbd to restore keyboard state
after suspend (to be called from i8042 resume function)

 atkbd.c |   50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 50 insertions(+)

===================================================================

drivers/input/keyboard/atkbd.c +50 -0
diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
@@ -686,10 +686,60 @@
 	printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
 }
 
+/*
+ * atkbd_reconnect() tries to restore keyboard in a sane state and is
+ * most likely called on resume.
+ */
+
+static int atkbd_reconnect(struct serio *serio)
+{
+	struct atkbd *atkbd = serio->private;
+	struct serio_dev *dev = serio->dev;
+	int i;
+
+        if (!dev) {
+                printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
+                return -1;
+        }
+
+	if (atkbd->write) {
+		if (atkbd_probe(atkbd))
+			return -1;
+		
+		atkbd->set = atkbd_set_3(atkbd);
+		atkbd_enable(atkbd);
+	} else {
+		atkbd->set = 2;
+		atkbd->id = 0xab00;
+	}
+
+	/* 
+	 * Here we probably should check if the keyboard has the same set that
+         * it had before and bail out if it's different. But this will most likely
+         * cause new keyboard device be created... and for the user it will look
+         * like keyboard is lost
+	 */
+
+	if (atkbd->set == 3)
+		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
+	else
+		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
+
+	for (i = 0; i < 512; i++)
+		if (atkbd->keycode[i] && atkbd->keycode[i] < 255)
+			set_bit(atkbd->keycode[i], atkbd->dev.keybit);
+
+	printk(KERN_INFO "input: %s on %s (reconnected)\n", atkbd->name, serio->phys);
+
+	return 0;
+}
+
+
 
 static struct serio_dev atkbd_dev = {
 	.interrupt =	atkbd_interrupt,
 	.connect =	atkbd_connect,
+	.reconnect = 	atkbd_reconnect,
 	.disconnect =	atkbd_disconnect,
 	.cleanup =	atkbd_cleanup,
 };
#2 lore raw

PATCH 3/3 Input: resume support for i8042 (atkbd & psmouse)

===================================================================

[email protected], 2003-12-01 01:44:41-05:00, [email protected]
Input: psmouse_reconnect() - do not close/open serop port
as i8042 should restore it for us already.

 psmouse-base.c |   10 ----------
 1 files changed, 10 deletions(-)

===================================================================

drivers/input/mouse/psmouse-base.c +0 -10
diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
@@ -638,16 +638,6 @@
 		return -1;
 	}
 	
-	/* We need to reopen the serio port to reinitialize the i8042 controller */
-	serio_close(serio);
-	if (serio_open(serio, dev)) {
-		/* do a disconnect here as serio_open leaves dev as NULL so disconnect 
-		 * will not be called automatically later
-		 */
-		psmouse_disconnect(serio);
-		return -1;
-	}
-	
 	psmouse->state = PSMOUSE_NEW_DEVICE;
 	psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0;
 	if (psmouse->reconnect) {
#3 lore raw

Re: [RFC/PATCH 4/3] Input: correctly activate i0842 ports on resume

===================================================================

[email protected], 2003-12-03 02:52:23-05:00, [email protected]
Input: fix i8042_activate_port() - the port is still disabled on
resume, need explicitely enable it (found by Brian Perkins)

 i8042.c |    6 ++++++
 1 files changed, 6 insertions(+)

===================================================================

drivers/input/serio/i8042.c +6 -0
diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
@@ -226,6 +226,12 @@
 
 	i8042_flush();
 
+	/* 
+	 * Enable port again here because it is disabled if we are
+	 * resuming (normally it is enabled already).
+	 */
+	i8042_ctr &= ~values->disable;
+
 	i8042_ctr |= values->irqen;
 
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
#4 lore raw
In reply to Dmitry Torokhov

Hi!

Quoted 6 lines

Here is an attempt to implement resume for i8042 using serio_reconnect facility that can be found in -mm kernels. It also depends on bunch of other changes in input subsystem all of which can be found here:
http://www.geocities.com/dt_or/input

They should apply cleanly to -test11.

It looks very reasonable to me... I'd like it to be in 2.6.1... or even better 2.6.0.
Pavel

Signature · 2 lines
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
#5 lore raw
In reply to Dmitry Torokhov

"Dmitry Torokhov" <[email protected]> schrieb im Newsbeitrag news:[email protected]...

Quoted 9 lines

Hi,

Here is an attempt to implement resume for i8042 using serio_reconnect facility that can be found in -mm kernels. It also depends on bunch of other changes in input subsystem all of which can be found here:
http://www.geocities.com/dt_or/input

They should apply cleanly to -test11.

I haven't looked at the patches,but after i applied all to the kernel, my ps/2 keyboard works again correctly.
it was broken in -test11,that i need to unplug it and then plug it again in to make it work,after booting.