--- linux-2.6.21.5/drivers/char/keyboard.c	2007-06-11 20:37:06.000000000 +0200
+++ linux-2.6.21.5.patched/drivers/char/keyboard.c	2007-06-16 23:23:37.017237207 +0200
@@ -30,6 +30,7 @@
 #include <linux/tty_flip.h>
 #include <linux/mm.h>
 #include <linux/string.h>
+#include <linux/kbd_sniff.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/irq.h>
@@ -1135,6 +1136,8 @@
 	unsigned char type, raw_mode;
 	struct tty_struct *tty;
 	int shift_final;
+        int  filter;            /* If set to true, no keypresses are sent to */
+        /* user mode programs. Exception: The sniffing-ioctl (see kbd_sniff.h) */
 
 	tty = vc->vc_tty;
 
@@ -1185,6 +1188,9 @@
 		sun_do_break();
 	}
 #endif
+        filter = kbd_sniff_hook(vc_kbd_led(kbd, VC_CAPSLOCK)
+				? shift_state | SNIFF_CAPSLOCK : shift_state,
+				keycode + (!down << 7));
 
 	if (kbd->kbdmode == VC_MEDIUMRAW) {
 		/*
@@ -1196,6 +1202,8 @@
 		 * applications. This allows for 16384 different keycodes,
 		 * which should be enough.
 		 */
+		if (filter)
+			goto skipit;
 		if (keycode < 128) {
 			put_queue(vc, keycode | (!down << 7));
 		} else {
@@ -1203,6 +1211,7 @@
 			put_queue(vc, (keycode >> 7) | 0x80);
 			put_queue(vc, keycode | 0x80);
 		}
+skipit:
 		raw_mode = 1;
 	}
 
@@ -1261,7 +1270,8 @@
 		}
 	}
 
-	(*k_handler[type])(vc, keysym & 0xff, !down);
+	if (!filter || type == KT_SHIFT)
+		(*k_handler[type])(vc, keysym & 0xff, !down);
 
 	if (type != KT_SLOCK)
 		kbd->slockstate = 0;
--- linux-2.6.21.5/drivers/char/vc_screen.c	2007-06-11 20:37:06.000000000 +0200
+++ linux-2.6.21.5.patched/drivers/char/vc_screen.c	2007-06-16 23:25:41.114092383 +0200
@@ -19,6 +19,10 @@
  * machek@k332.feld.cvut.cz - modified not to send characters to wrong console
  *	 - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...)
  *	 - making it shorter - scr_readw are macros which expand in PRETTY long code
+ *
+ * butenuth@online.de - Added keyboard sniffing. (Used by brass: Braille and Speech Server)
+ *
+ * kai.ruemmler@gmx.net - Ported keyboard sniffing to kernel 2.6 
  */
 
 #include <linux/kernel.h>
@@ -27,6 +31,7 @@
 #include <linux/tty.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
+#include <linux/kbd_sniff.h>
 #include <linux/init.h>
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
@@ -455,6 +460,136 @@
 	return ret;
 }
 
+
+static int hot_key_enable = 0;
+static int nr_hot_keys;
+static int hot_key[SNIFF_NR_HOT_KEYS];
+static int hot_key_state[SNIFF_NR_HOT_KEYS]; /* 1 = pressed, 0 = released */
+static int disable_key;
+static int hot_mode = 0;
+static struct sniff_ioctl_get get_buf;
+static wait_queue_head_t sniff_wait_q;
+
+/*
+ * Intercept all keycodes, return 1 when keycode should not go 
+ * to other drivers/applications, 0 otherwise.
+ */
+int kbd_sniff_hook(int shift_state, int keycode)
+{
+	int i;
+	int all;
+        int ret_hot_mode = hot_mode;
+
+	if (hot_key_enable) {
+		for (i = 0; i < nr_hot_keys; i++)
+                	if ((keycode & 0x7f) == hot_key[i])
+                        	hot_key_state[i] = (keycode & 0x80) == 0;
+		for (i = 0, all = 1; i < nr_hot_keys; i++)
+			all = (all && hot_key_state[i]);
+		if (all) {
+			hot_mode = 1;
+                        ret_hot_mode = 1;
+                }
+                /*
+                 * Set only global hot_mode, ret_hot_mode stays on old value,
+                 * otherwise the disable key is returned to user.
+                 */
+		if ((keycode & 0x7f) == disable_key)
+			hot_mode = 0;
+
+		if (hot_mode)
+			shift_state |= SNIFF_HOT_MODE;
+		if (get_buf.count < SNIFF_EVENT_BUF_SIZE) {
+			get_buf.event[get_buf.count].shift_state = shift_state;
+			get_buf.event[get_buf.count].keycode     = keycode;
+			get_buf.count++;
+		}
+		wake_up_all(&sniff_wait_q);
+		
+	}
+	
+	return ret_hot_mode;
+}
+
+static int
+kbd_sniff_set(unsigned long arg)
+{
+	struct sniff_ioctl_set data;
+	int retval = 0;
+	int i;
+
+	retval = copy_from_user(&data, (void*)arg, sizeof(data));
+	if (retval)
+		return retval;
+	if (data.hot_key_enable) {
+		if (data.nr_hot_keys > SNIFF_NR_HOT_KEYS)
+			return -EINVAL;
+		for (i = 0; i < data.nr_hot_keys; i++) {
+			hot_key[i] = data.hot_key[i];
+			hot_key_state[i] = 0;
+		}
+		nr_hot_keys = data.nr_hot_keys;
+		disable_key = data.disable_key;
+		get_buf.count = 0;
+		hot_mode = 0;
+		hot_key_enable = 1;
+	} else {
+		get_buf.count = 0;
+		wake_up_all(&sniff_wait_q);
+                hot_mode = 0;
+		hot_key_enable = 0;
+	}
+
+	return retval;
+}
+
+static int
+kbd_sniff_get(unsigned long arg)
+{
+	struct sniff_ioctl_get data;
+	int retval = 0;
+
+	retval = copy_from_user(&data, (void*)arg, sizeof(data));
+	if (retval)
+		return retval;
+
+	if (get_buf.count == 0 && data.blocking)
+		interruptible_sleep_on(&sniff_wait_q);
+	
+	retval = copy_to_user((void*)arg, &get_buf, sizeof(get_buf));
+	if (retval)
+		return retval;
+
+	get_buf.count = 0;
+	
+	return retval;
+}
+
+static int 
+vcs_ioctl(struct inode *inode, struct file *file,
+          unsigned int cmd, unsigned long arg)
+{
+	int retval;
+
+	if (current->euid != 0)
+		return -EPERM;
+
+	switch (cmd) {
+	case KBD_SNIFF_SET:
+	case KBD_SNIFF_SET_OLD:
+		retval = kbd_sniff_set(arg);
+		break;
+	case KBD_SNIFF_GET:
+	case KBD_SNIFF_GET_OLD:
+		retval = kbd_sniff_get(arg);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int
 vcs_open(struct inode *inode, struct file *filp)
 {
@@ -468,6 +603,7 @@
 	.llseek		= vcs_lseek,
 	.read		= vcs_read,
 	.write		= vcs_write,
+        .ioctl          = vcs_ioctl,
 	.open		= vcs_open,
 };
 
@@ -479,6 +615,7 @@
 			"vcs%u", tty->index + 1);
 	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129),
 			"vcsa%u", tty->index + 1);
+	init_waitqueue_head(&sniff_wait_q);
 }
 
 void vcs_remove_sysfs(struct tty_struct *tty)
@@ -495,5 +632,6 @@
 
 	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), "vcs");
 	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), "vcsa");
+	init_waitqueue_head(&sniff_wait_q);
 	return 0;
 }
--- linux-2.6.21.5/include/linux/kbd_sniff.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.21.5.patched/include/linux/kbd_sniff.h	2007-06-16 23:21:56.006029354 +0200
@@ -0,0 +1,48 @@
+#ifndef _LINUX_KBD_SNIFF_H
+#define _LINUX_KBD_SNIFF_H
+
+#include <linux/ioctl.h>
+
+/*
+ * linux/include/kbd_sniff.h
+ * 
+ * Copyright 1998-2003: Roger Butenuth
+ * butenuth@online.de
+ */
+
+
+#define KBD_SNIFF_SET _IOW(0xFF, 1, struct sniff_ioctl_set)
+#define KBD_SNIFF_GET _IOWR(0xFF, 2, struct sniff_ioctl_get)
+ 
+/* For backwards compartibility to ioctl numbers generated prior kernel 2.6.
+ * We will promptly remove them when the interface changes */
+#define KBD_SNIFF_GET_OLD 0xC0044202
+#define KBD_SNIFF_SET_OLD 0x40044201
+
+#define SNIFF_NR_HOT_KEYS     4
+#define SNIFF_EVENT_BUF_SIZE 20
+
+#define SNIFF_HOT_MODE 0x0100
+#define SNIFF_CAPSLOCK 0x0200
+
+struct sniff_event {
+	unsigned short shift_state;
+	unsigned short keycode;
+};
+
+struct sniff_ioctl_set {
+	int hot_key_enable;
+	int nr_hot_keys;
+	int hot_key[SNIFF_NR_HOT_KEYS];
+	int disable_key;
+};
+
+struct sniff_ioctl_get {
+	int                blocking;
+	int                count;
+	struct sniff_event event[SNIFF_EVENT_BUF_SIZE];
+};
+
+int kbd_sniff_hook(int shift_state, int keycode);
+
+#endif /* _LINUX_KBD_SNIFF_H */
