[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH] macintosh: mangle caps lock events on adb keyboards



Adds a proc entry, /proc/sys/dev/adbhid/mangle_caps_lock_events, to
enable translation of the bogus 0xFF keypresses emitted by the caps lock
on ADB keyboards into normal keyup/keydown events. This allows the caps
lock key to be remapped to a modifier, e.g. control.

The behavior is off by default because (1) the caps lock LED toggles on
every keydown, which can be irritating, and (2) because very
occasionally the code sees spurious 0xFF events that sometimes
leave the capslock "stuck". Tapping the key again fixes the problem.
These are known issues with the keyboard that also show up under Mac OS
Tiger when the capslock is remapped.

Patch (without sysctl) apparently written originally for 2.4 by Gregorio
Gervas, whose email I can't find. Ported to 2.6 by Hans Fugal
<hans@fugal.net>, and I added the /proc entry.

Signed-off-by: Andy Wingo <wingo@pobox.com>
---
Given the tradeoffs when enabling this patch I chose to make the
behavior configurable. Kinda sucks. I'd like it upstream so I can
go back to using stock kernels though.

 drivers/macintosh/adbhid.c |   91 ++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/sysctl.h     |    6 ++
 2 files changed, 96 insertions(+), 1 deletion(-)

diff -r -u linux-source-2.6.15-2.6.15/drivers/macintosh/adbhid.c linux-source-2.6.15-2.6.15-wingo/drivers/macintosh/adbhid.c
--- linux-source-2.6.15-2.6.15/drivers/macintosh/adbhid.c	2005-11-12 18:52:32.000000000 +0100
+++ linux-source-2.6.15-2.6.15-wingo/drivers/macintosh/adbhid.c	2005-12-08 19:51:45.000000000 +0100
@@ -41,6 +41,9 @@
 #include <linux/notifier.h>
 #include <linux/input.h>
 
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+
 #include <linux/adb.h>
 #include <linux/cuda.h>
 #include <linux/pmu.h>
@@ -56,6 +59,51 @@
 
 MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
 
+static int mangle_caps_lock_events = 0;
+
+#if defined(CONFIG_SYSCTL)
+
+/* file(s) in /proc/sys/dev/adbhid */
+ctl_table adbhid_files[] = {
+	{
+		.ctl_name	= DEV_ADBHID_MANGLE_CAPS_LOCK_EVENTS,
+		.procname	= "mangle_caps_lock_events",
+		.data		= &mangle_caps_lock_events,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{ .ctl_name = 0 }
+};
+
+/* dir in /proc/sys/dev */
+ctl_table adbhid_dir[] = {
+	{
+		.ctl_name	= DEV_ADBHID,
+		.procname	= "adbhid",
+		.maxlen		= 0,
+		.mode		= 0555,
+		.child		= adbhid_files,
+	},
+	{ .ctl_name = 0 }
+};
+
+/* /proc/sys/dev itself, in case that is not there yet */
+ctl_table adbhid_root_dir[] = {
+	{
+		.ctl_name	= CTL_DEV,
+		.procname	= "dev",
+		.maxlen		= 0,
+		.mode		= 0555,
+		.child		= adbhid_dir,
+	},
+	{ .ctl_name = 0 }
+};
+
+static struct ctl_table_header *adbhid_sysctl_header;
+
+#endif /* endif CONFIG_SYSCTL */
+
 #define KEYB_KEYREG	0	/* register # for key up/down data */
 #define KEYB_LEDREG	2	/* register # for leds on ADB keyboard */
 #define MOUSE_DATAREG	0	/* reg# for movement/button codes from mouse */
@@ -285,12 +333,49 @@
 {
 	struct adbhid *ahid = adbhid[id];
 	int up_flag;
+	static int caps_lock_state = 0x0;
+
+	if (mangle_caps_lock_events) {
+		switch (keycode) {
+		case ADB_KEY_CAPSLOCK: 
+			/* this is where the led transitions to on */
+			caps_lock_state = 0x3;
+			break;
+		case 0x80 | ADB_KEY_CAPSLOCK: 
+			/* this is where the led transitions to off */
+			caps_lock_state = 0x0;
+			break;
+		case 0xff:
+			switch (caps_lock_state) {
+			case 0x3: /* led on, key released */
+				caps_lock_state = 0x2;
+				keycode = 0x80 | ADB_KEY_CAPSLOCK;
+				break;
+			case 0x2: /* led on, key pressed */
+				caps_lock_state = 0x1;
+				keycode = ADB_KEY_CAPSLOCK;
+				break;
+                        /* these last two cases are spurious 0xff events.
+			 * log and ignore them.
+			 */
+			case 0x0: /* led off, key pressed */
+			case 0x1: /* led off, key released */
+				printk(KERN_INFO "Spurious caps lock event (scancode 0xff).");
+				break;
+			}
+			break;
+		}
+	}
 
 	up_flag = (keycode & 0x80);
 	keycode &= 0x7f;
 
 	switch (keycode) {
-	case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */
+	case ADB_KEY_CAPSLOCK:
+		if (mangle_caps_lock_events)
+			break;
+		
+		/* Generate down/up events for CapsLock everytime. */
 		input_regs(ahid->input, regs);
 		input_report_key(ahid->input, KEY_CAPSLOCK, 1);
 		input_report_key(ahid->input, KEY_CAPSLOCK, 0);
@@ -1210,6 +1295,10 @@
 	    return 0;
 #endif
 
+#if defined(CONFIG_SYSCTL)
+	adbhid_sysctl_header = register_sysctl_table(adbhid_root_dir, 1);
+#endif /* CONFIG_SYSCTL */
+
 	led_request.complete = 1;
 
 	adbhid_probe();
diff -r -u linux-source-2.6.15-2.6.15/include/linux/sysctl.h linux-source-2.6.15-2.6.15-wingo/include/linux/sysctl.h
--- linux-source-2.6.15-2.6.15/include/linux/sysctl.h	2005-11-16 05:06:43.000000000 +0100
+++ linux-source-2.6.15-2.6.15-wingo/include/linux/sysctl.h	2005-12-08 16:00:22.000000000 +0100
@@ -776,6 +776,7 @@
 	DEV_MAC_HID=5,
 	DEV_SCSI=6,
 	DEV_IPMI=7,
+	DEV_ADBHID=8,
 };
 
 /* /proc/sys/dev/cdrom */
@@ -846,6 +847,11 @@
 	DEV_IPMI_POWEROFF_POWERCYCLE=1,
 };
 
+/* /proc/sys/dev/adbhid */
+enum {
+	DEV_ADBHID_MANGLE_CAPS_LOCK_EVENTS=1,
+};
+
 /* /proc/sys/abi */
 enum
 {



Reply to: