相关章节 linux设备驱动开发详解 p196 linux中断编程
-
int requset_irq(unsigned int irq,irq_handler_t handler,unsigned long irqflags,const char *devname ,void *dev_id)
irq:是要申请的中断号,中断号对应的就是中断控制器上IRQ线的编号
handler:向系统登记的中断处理函数(顶半部),是一个回调函数,中断发生时,系 统调用这个函数,dev_id参数将被传递给它。
irqflags:中断处理的属性。,可以指定中断的触发方式以及处理方式。
触发方式:IRQF_TRIGGER_RISING IRQF_TRIGGER_FAILLING等
处理方式:IRQF_DISABLED表明中断处理程序时快速处理程序,快速处 理程序将被调用时屏蔽所有中断,慢速处理程序则不会屏 蔽其他设备的驱动。
IRQF_SHARED:表示多个设备共享中断,dev_id在中断共享 时会用到,一般设置为这个设备的设备结构体或者NULL。
request_irq()返回0表示成功,返回-EINVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断已经被占用且不能共享。
*devname: 请求中断的设备的名称,可以在/proc/interrupts中查看到具体设备的 名称,与此同时也可以查看到这个设备对应的中断号已经请求次数,甚 至中断控制器的名称
顶半部handler的类型irq_handle_t
-
typedef irqreturn_t (*irq_handler_t)(int ,void *);
-
typedef int irqreturn_t
2. 释放IRQ
-
viod free_irq(unsigned int irq,void *dev_id)
参数的定义域request_irq相同
3. 使能和屏蔽中断
-
void disable_irq(int irq);
-
void disable_irq_nosync(int irq);
-
void enable_irq(int irq);
disable_irq_nosync()与disable_irq()区别是,nosync()立即返回,而disable_irq等待目前的中断处理完成。由于disable_irq()会等待指定的中断被处理完,因此如果在n号中断的顶半部调用disable_irq(n),会引起系统的死锁,这种情况下,只能调用disable_irq_nosync();
//屏蔽、使能本cpu中所有中断
void local_irq_disable();
void local_irq_enbale();
===================================================================
-
#include <linux/init.h>//init __init
-
#include <linux/kernel.h>
-
#include <linux/module.h>//MODULE_LICENSE
-
#include <linux/moduleparam.h>//module_param
-
#include <linux/interrupt.h>
-
#include <linux/stat.h>//S_IRUGO
-
#include <linux/slab.h>//kmalloc
-
-
static int irq = 1;//保存中断号irq
-
static char *devname = NULL;//保存中断名称*devname
-
module_param(irq,int,00644);//S_IRUGO=00444
-
module_param(devname,charp,00644);
-
-
//定义一个结构体,在request_irq函数中的 void *dev_id经常设置为结构体或NULL
-
struct dev_info{
-
int irq_id;
-
char *dev_name;
-
};
-
struct dev_info *mydev_info = NULL;
-
-
//声明中断处理函数(顶半部)
-
static irqreturn_t myirq_handler(int irq,void *dev);
-
-
static int __init myirq_init(void)
-
{
-
printk("Module is working...\n");
-
//分配struct dev_info 结构体内存
-
mydev_info = kmalloc(sizeof(struct dev_info),GFP_KERNEL);
-
if(!mydev_info)
-
{
-
printk("kmalloc failed..\n");
-
return -1;
-
}
-
memset(mydev_info,0,sizeof(struct dev_info));
-
mydev_info->irq_id = irq;
-
//分配结构体struct dev_info->char *dev_name 内存
-
mydev_info->dev_name = kmalloc(10,GFP_KERNEL);
-
if(!mydev_info->dev_name)
-
{
-
printk("kmalloc 1 failed..\n");
-
return -1;
-
}
-
mydev_info->dev_name = devname;
-
-
//return 0 == success
-
if(request_irq(irq,&myirq_handler,IRQF_SHARED,devname,mydev_info))
-
{
-
printk("%s request IRQ:%d failed\n",devname,irq);
-
return -1;
-
//return -EIO;
-
}
-
printk("%s request IRQ:%d success..\n",devname,irq);
-
return 0;
-
}
-
-
static void __exit myirq_exit(void)
-
{
-
printk("unloading my module..\n");
-
free_irq(irq,mydev_info);//
-
printk("freeing IRQ %d\n",irq);
-
}
-
static irqreturn_t myirq_handler(int irq, void *dev)
-
{
-
struct dev_info mydev;
-
static int count = 1;
-
mydev = *(struct dev_info *)dev;
-
-
printk("key:%d\n",count);
-
printk("devname:%s,devid:%d\n is working..\n",mydev.dev_name,mydev.irq_id);
-
printk("ISR is leaving\n");
-
count++;
-
return IRQ_HANDLED;
-
}
-
-
module_init(myirq_init);
-
module_exit(myirq_exit);
-
-
MODULE_LICENSE("GPL");
使用方法:
1.cat /proc/interrupts 查看中断号,以确定一个即将要共享的中断号。本程序因为是与键盘共享中断号,因此irq=1
2.插入内核
sudo insmod ./interrupt.ko irq=1 devname=ywxirq
3.再次 查看 /proc/interuppts cat /proc/interrupts | grep ywx
4. dmesg查看内核日志文件 dmesg | tail -20
5 sudo rmmod interrupt
可以看到,内核模块加载后,我们所写的中断处理程序时被自动调用的,主要是该中断线上有键盘所发出的中断请求,因此内核会执行该中断线上的所有中断处理程序,当然就包括我们上诉我们所写的那个中断处理程序。
=======================================================
参考资料:
显示如下:
-
root@ywx:/home/ywx/desktop/module/edi/interrupt/first_interrupt# dmesg | tail -10
-
[11966.016756] key:169
-
[11966.016764] devname:ywxirq,devid:1
-
[11966.016765] is working..
-
[11966.016767] ISR is leaving
-
[11967.111634] key:170
-
[11967.111643] devname:ywxirq,devid:1
-
[11967.111644] is working..
-
[11967.111646] ISR is leaving
-
[11967.119801] unloading my module..
-
[11967.119830] freeing IRQ 1
阅读(1741) | 评论(0) | 转发(0) |