I'm attempting to dabble with low level programming. My goal is to have a user type a key into the terminal, capture that and output another key. So for example, if the user types "a" I would type out "b", if he types in "b" I output "c", etc.
What would be the steps to do that? I'm already familiar with how to access the Linux kernel source code, compile it, and use it.
Thanks.
Consider next simple kernel module:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#define KBD_IRQ 1 /* IRQ number for keyboard (i8042) */
#define KBD_DATA_REG 0x60 /* I/O port for keyboard data */
#define KBD_SCANCODE_MASK 0x7f
#define KBD_STATUS_MASK 0x80
static irqreturn_t kbd2_isr(int irq, void *dev_id)
{
char scancode;
scancode = inb(KBD_DATA_REG);
/* NOTE: i/o ops take a lot of time thus must be avoided in HW ISRs */
pr_info("Scan Code %x %s\n",
scancode & KBD_SCANCODE_MASK,
scancode & KBD_STATUS_MASK ? "Released" : "Pressed");
return IRQ_HANDLED;
}
static int __init kbd2_init(void)
{
return request_irq(KBD_IRQ, kbd2_isr, IRQF_SHARED, "kbd2", (void *)kbd2_isr);
}
static void __exit kbd2_exit(void)
{
free_irq(KBD_IRQ, (void *)kbd2_isr);
}
module_init(kbd2_init);
module_exit(kbd2_exit);
MODULE_LICENSE("GPL");
This is most minimal and primitive key-logger. It can be easily reworked for replacing of scan code.
inb()
function)pr_info()
) in hardware IRQ handler, which should be avoided (ideally threaded IRQs should be used)).But I think it's good for educational purposes -- it's really small and demonstrates the idea pretty well (without messing with API like input_dev
, input_register_device()
, serio_write()
, input_event()
, input_report_key()
, etc).
Real interrupt handler (in keyboard driver) requested as shared interrupt, which allows us also request that interrupt and thus handle it also in our ISR (in addition to ISR in original keyboard driver). Interrupt requesting is done in kbd2_init()
.
This module works as follows:
kbd2_isr()
is called for each key press event)inb()
function)pr_info()
Now, you want to replace that scan code. I believe you can use outb()
function for this (on x86). So I leave it for you.
If you wonder why we are requesting IRQ with number 1, see at drivers/input/serio/i8042-io.h:
#else
# define I8042_KBD_IRQ 1
Also be sure to check that this IRQ is shared in drivers/input/serio/i8042.c:
error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
"i8042", i8042_platform_device);
Here is documentation for i8042 keyboard controller: AT keyboard controller.
To avoid magic numbers, you can use next definitions.
From drivers/input/serio/i8042-io.h:
/*
* Register numbers.
*/
#define I8042_COMMAND_REG 0x64
#define I8042_STATUS_REG 0x64
#define I8042_DATA_REG 0x60
From include/linux/i8042.h:
/*
* Status register bits.
*/
#define I8042_STR_PARITY 0x80
#define I8042_STR_TIMEOUT 0x40
#define I8042_STR_AUXDATA 0x20
#define I8042_STR_KEYLOCK 0x10
#define I8042_STR_CMDDAT 0x08
#define I8042_STR_MUXERR 0x04
#define I8042_STR_IBF 0x02
#define I8042_STR_OBF 0x01
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With