Reputation: 21
I write a simple kernel module example about how to use interrupt handler. The module services keyboard interrupts. It reads the relevant information from the keyboard and then puts information about Key that pressed. It successfully insmod module into the kernel, and interrupt work well.
However, when I do rmmod module, the LED on Caps Lock blinking and my PC is frozen (I run it on Vmware machine). I think I have the bugs in __exit function. But I do not know how to fix. Can anyone help me? Thank you so much.
The code:
/*
* An interrupt handler
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <asm/io.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Hai Dang Hoang");
/*
* This function services keyboard interrupts. It reads the relevant
* information from the keyboard and then puts information about Key that pressed
* This example only has 3 key: ESC, F1, and F2
*/
irqreturn_t irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
/*
* This variables are static because they need to be
* accessible (through pointers) to the bottom half routine.
*/
static unsigned char scancode;
unsigned char status;
/*
* Read keyboard status
*/
status = inb(0x64);
scancode = inb(0x60);
switch (scancode)
{
case 0x01: printk (KERN_INFO "! You pressed Esc ...\n");
break;
case 0x3B: printk (KERN_INFO "! You pressed F1 ...\n");
break;
case 0x3C: printk (KERN_INFO "! You pressed F2 ...\n");
break;
default:
break;
}
return IRQ_HANDLED;
}
/*
* Initialize the module - register the IRQ handler
*/
static int __init irq_ex_init(void)
{
/* Free interrupt*/
free_irq(1,NULL);
return request_irq (1, (irq_handler_t) irq_handler,IRQF_SHARED, "test_keyboard_irq_handler",(void *)(irq_handler));
}
static void __exit irq_ex_exit(void)
{
free_irq(1,NULL);
}
module_init(irq_ex_init);
module_exit(irq_ex_exit);
Or you can see my code on my link GitHub: Example interrupt handler
Upvotes: 2
Views: 4745
Reputation: 1
Please change the code:
static void __exitrq_ex_exit(void)
{
free_irq(1, NULL);
}
into:
static void __exitrq_ex_exit(void)
{
free_irq(1, (void*)irq_handler);
}
You need to let the kernel know which handler you want to remove. Since you use the function irq_handler()
as the dev_id
, you need to use it again to remove the mode without remove the original keyboard interrupt handler.
Upvotes: 0
Reputation: 8563
Your example does not handle some random IRQ. It handles an interrupt critical for working with the machine.
At the beginning of your registration you remove the previous interrupt handler. Your problem is that you failed to re-install it once you remove your own.
The result is that, when you rmmod
your module, no one is handling the keyboard interrupt.
Upvotes: 2