Linux将中断处理分为上下两部分,上半部分主要处理紧急的,必须马上处理的事情,下半部分处理不那么紧急的事情,linux内核也提供了相应的机制,这里使用理论课中的tasklet机制来进行实验。
本节代码是在上节的基础上稍微增加一部分代码即可。
首先在中断服务例程,即上半部分中添加tasklet的init函数,即将下半部分函数进行注册。最主要的是要将下半部分处理函数挂载上去。最后调用tasklet_schedule函数进行调度
最后用到tasklet_kill,用来注销掉我们的tasklet
book@100ask:~/Mooc/CH06$ cat interrupt2.c
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
static int irq;
static char * devname;
module_param(irq,int,0644);
module_param(devname,charp,0644);
struct myirq
{
int devid;
};
struct myirq mydev={1119};
static struct tasklet_struct mytasklet;
static void mytasklet_handler(unsigned long data)
{
printk("I am mytasklet_handler");
}
static irqreturn_t myirq_handler(int irq,void * dev)
{
// struct myirq mydev;
// static int count=1;
static int count=0;
// mydev = *(struct myirq*)dev;
// printk("key: %d..\n",count);
// printk("devid:%d ISR is working..\n",mydev.devid);
// printk("ISR is leaving......\n");
printk("count:%d\n",count+1);
printk("I am myirq_handler\n");
printk("The most of the interrupt work will be done by folling tasks\n");
tasklet_init(&mytasklet,mytasklet_handler,0);
tasklet_schedule(&mytasklet);
count++;
return IRQ_HANDLED;
}
static int __init myirq_init(void)
{
printk("Module is working...\n");
if(request_irq(irq,myirq_handler,IRQF_SHARED,devname,&mydev)!=0)
{
printk("%s request IRQ: %d failed...\n",devname,irq);
return -1;
}
printk("%s request IRQ:%d success...\n",devname,irq);
return 0;
}
static void __exit myirq_exit(void)
{
printk("Module is leaving...\n");
free_irq(irq,&mydev);
tasklet_kill(&mytasklet);
printk("Free the irq: %d..\n",irq);
}
MODULE_LICENSE("GPL");
module_init(myirq_init);
module_exit(myirq_exit);
book@100ask:~/Mooc/CH06$ cat Makefile
# Makefile文件注意:加入前面的.c文件起名为first.c,那么这里的Makefile文件中的.o文件就要起名first.o
# # 只有root用户才能加载和卸载模块
obj-m:=interrupt2.o # 产生first模块的目标文件
# #目标文件 文件 要与模块名字相同
CURRENT_PATH:=$(shell pwd)
LINUX_KERNEL:=$(shell uname -r)
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
#
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules # 编译模块
# #[TAB] 内核的路径 当前目录编译完放哪里? 表明编译的是内核模块
#
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean # 清理模块
book@100ask:~/Mooc/CH06$ make
make -C /usr/src/linux-headers-5.4.0-42-generic M=/home/book/Mooc/CH06 modules # 编译模块
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-42-generic'
CC [M] /home/book/Mooc/CH06/interrupt2.o
Building modules, stage 2.
MODPOST 1 modules
CC [M] /home/book/Mooc/CH06/interrupt2.mod.o
LD [M] /home/book/Mooc/CH06/interrupt2.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-42-generic'
插入模块,还是使用1号中断线,
book@100ask:~/Mooc/CH06$ sudo insmod interrupt2.ko irq=1 devname=myirq
查看中断情况,发现设备已被正确插入
book@100ask:~/Mooc/CH06$ cat /proc/interrupts
CPU0 CPU1
0: 11 0 IO-APIC 2-edge timer
1: 0 226 IO-APIC 1-edge i8042, myirq
8: 1 0 IO-APIC 8-edge rtc0
9: 0 0 IO-APIC 9-fasteoi acpi
12: 3945 0 IO-APIC 12-edge i8042
14: 0 0 IO-APIC 14-edge ata_piix
15: 0 0 IO-APIC 15-edge ata_piix
16: 9386 2064 IO-APIC