设备模拟与ISR
实验目的:
1. 编写一个内核模块,模拟设备产生中断
2. 编写另一个内核模块,处理第一个设备产生的中断
实验原理:
1. 设备模拟需要编写设备驱动,这就要实现file_operations接口
2. 在模拟设备中使用int指令产生软中断,由ISR模块处理中断
实验内容:
1. 模拟出两个字符设备
1) 分别实现字符设备devPK、devGL的驱动,字符设备由一个共享变量char myDeviceChar担当,这个变量在pkISR模块里面声明,其它模块将引用这个设备变量。
2) 实现过程:首先为两个设备创建file_operations变量如下,
struct file_operations char_GL_fops = {
.owner = THIS_MODULE,
.read = glRead,
.write = glWrite,
.open = glOpen,
.release = glRelease,
};
struct file_operations char_PK_fops = {
.owner = THIS_MODULE,
.read = pkRead,
.write = pkWrite,
.open = pkOpen,
.release = pkRelease,
};
这两个结构的接口函数应该分别在声明之前定义,具体实现参见代码。
3) 注册设备与IRQ
在模块初始化函数中注册,
register_chrdev(char_PK_MAJOR,dev_NAME,&char_PK_fops);
if(0 != request_irq(5,pkISR,SA_SHIRQ,dev_NAME,dev_NAME))…
相应释放设备与IRQ在模块存在于释放函数中,
free_irq(5,dev_NAME);
unregister_chrdev(char_PK_MAJOR,dev_NAME);
这里面有几个参数需要说明一下:
char_PK_MAJOR是自定义的主设备号,dev_NAME是设备名称,pkISR是设备发生中断时对应的ISR,SA_SA_SHIRQ代表两个字符设备共享同一个IRQ,这里使用的IRQ是5号IRQ。
4) 设备中断的产生:devPK设备的中断在pkRead、pkWrite操作里产生,当设备发生读写操作时即产生一个中断,实现如下,
__asm__ __volatile__("int $0x25"); //对应的IRQ是5号
2. 编写ISR模块
ISR模块处理设备发生的中断,在pkISR里,声明并且导出了几个其它模块用到的变量,
static int flag = -1;
EXPORT_SYMBOL(flag);
static char myDeviceChar = ' ';
EXPORT_SYMBOL(myDeviceChar);
这里的flag变量用于判断哪个设备发生了何种操作,这个是自定义的。实际应用中的情况不是这样的,但是在模拟情况下采用了这种方法。
相应的,在ISR处理函数里,会打印出相关信息,以显示具体是哪个设备发生了哪类操作,从而达到了处理模拟中断的目的。
3. 模块加载
每个内核模块都有如下注册和撤消函数,
module_init(init_name);
module_exit(clean_name);
实现编译模块到内核:(Makefile文件: obj-m := file.o)
make -C /usr/src/kernels/2.6.23.1-42.fc8-i686 M=$PWD modules
使用insmod 命令注册模块,相应卸载命令是rmmmod.
4. 编写测试模块
测试模块是用户态下的程序test.c,在这个程序里,首先打开设备,然后对设备进行读和写操作。
当然,首先需要注册设备节点,具体操作如下:
以root用户打开终端:
mknod /dev/char_devPK c 257 1
mknod /dev/char_devGL c256 1
这里的设备节点名称与设备驱动注册设备使用的名称一致。
当执行测试程序时,查看中断是否发生使用dmeg|tail命令即可。
实验结论:
实验发现,两个设备注册的ISR处于一条链上,因为它们注册的是同一个IRQ;当中断发生时,ISR会依次执行,直到得到正确处理,即执行了设备注册的相应的ISR。同时,实现演示出,当设备注册IRQ时,就会调用相应的ISR一次。