Messages in this thread Patch in this message |  | | From | Genadz Batsyan <> | Subject | overriding keyboard driver in a module | Date | Thu, 7 Jul 2005 03:41:40 +0200 |
| |
I'm writing a little tool to allow intercepting keyboard events and substituting them with other events / swallowing events / emitting additional events on a low level before normal processing by kernel. http://kbd-mangler.sourceforge.net/
Currently to have precedense over the keyboard driver I'm using a patch against drivers/input/keyboard/atkbd.c
Well, I guess, patching kernel is unthinkable for most linux users, so I thought, maybe there is a way to do it without the kernel patch. Is it possible to write a kernel module to intercept keyboard events and have precedense over the kernel driver?
If anyone is interested, below is my patch. I know it's damn dirty (especially the last_dev thingy :-) but take it easy, it's my first kernel undertaking, a product of a few days, and most importantly - it works.
Any kind of suggestions would be appreciated a lot.
-----------------------
--- linux-2.6.11.6-orig/drivers/input/keyboard/atkbd.c 2005-03-26 04:28:48.000000000 +0100 +++ linux-2.6.11.6-patched/drivers/input/keyboard/atkbd.c 2005-07-01 22:15:52.000000000 +0200 @@ -34,6 +34,10 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); + +#define CONFIG_KBD_INTERCEPTOR 1 + + static int atkbd_set = 2; module_param_named(set, atkbd_set, int, 0); MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)"); @@ -229,18 +233,79 @@ ATKBD_DEFINE_ATTR(softraw); -static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) + + + +#ifdef CONFIG_KBD_INTERCEPTOR + +typedef int (*KBD_INTERCEPTOR)(int *, int *); + +static KBD_INTERCEPTOR kbd_interceptor; +static struct input_dev *last_dev; + +#endif + + + + +static void _atkbd_report_key(struct input_dev *dev, int code, int value) { - input_regs(dev, regs); if (value == 3) { input_report_key(dev, code, 1); input_sync(dev); input_report_key(dev, code, 0); } else input_event(dev, EV_KEY, code, value); +} + +static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) +{ + input_regs(dev, regs); + +#ifdef CONFIG_KBD_INTERCEPTOR + if (kbd_interceptor && kbd_interceptor(&code, &value)) + { + return; + } +#endif + _atkbd_report_key(dev, code, value); input_sync(dev); } +#ifdef CONFIG_KBD_INTERCEPTOR +KBD_INTERCEPTOR kbd_set_interceptor(KBD_INTERCEPTOR interceptor) +{ + KBD_INTERCEPTOR old = kbd_interceptor; + kbd_interceptor = interceptor; + return old; +} + +void kbd_emit_key(int code, int down) +{ + if (last_dev) + _atkbd_report_key(last_dev, code, down); + else + printk("kbd_emit_key: input_dev not set\n"); +} +void kbd_emit_sync() +{ + if (last_dev) + input_sync(last_dev); + else + printk("kbd_emit_key: input_dev not set\n"); +} + + +EXPORT_SYMBOL(kbd_set_interceptor); +EXPORT_SYMBOL(kbd_emit_key); +EXPORT_SYMBOL(kbd_emit_sync); + +#endif + + + + + /* * atkbd_interrupt(). Here takes place processing of data received from * the keyboard into events. @@ -660,6 +725,10 @@ { struct atkbd *atkbd = serio->private; +#ifdef CONFIG_KBD_INTERCEPTOR + last_dev = NULL; +#endif + atkbd_disable(atkbd); /* make sure we don't have a command in flight */ @@ -847,6 +916,10 @@ input_register_device(&atkbd->dev); +#ifdef CONFIG_KBD_INTERCEPTOR + last_dev = &atkbd->dev; +#endif + device_create_file(&serio->dev, &atkbd_attr_extra); device_create_file(&serio->dev, &atkbd_attr_scroll); device_create_file(&serio->dev, &atkbd_attr_set); @@ -1097,6 +1170,9 @@ int __init atkbd_init(void) { +#ifdef CONFIG_KBD_INTERCEPTOR + last_dev = NULL; +#endif serio_register_driver(&atkbd_drv); return 0; }
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
|  |