现在的位置: 首页 > 综合 > 正文

中断模块示例

2013年09月06日 ⁄ 综合 ⁄ 共 3156字 ⁄ 字号 评论关闭

 


申请和释放中断:

注册一个中断:request_irq()函数用来注册一个中断处理程序,这样做是因为真正的中断服务要等到具体设备的初始化程序将其中断服务程序通过该函数向系统注册后,并挂入某个中断请求队列中以后才可以真正的运行。源码如下:


 536int request_irq(unsigned int irq, irq_handler_t handler,
 537 unsigned long irqflags, const char *devname, void *dev_id)
 538{
 539 struct irqaction *action;/*创建一个此结构,并将其加入到相应irq号的struct irqaction队列中*/
 540 int retval;/*返回值*/
 541
//.....省略

 554 if ((irqflags & IRQF_SHARED) && !dev_id)
 555 return -EINVAL;
 556 if (irq >= NR_IRQS)
 557 return -EINVAL;
 558 if (irq_desc[irq].status & IRQ_NOREQUEST)
 559 return -EINVAL;
 560 if (!handler)
 561 return -EINVAL;
 562
 563 action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
 564 if (!action)
 565 return -ENOMEM;
 566
 567 action->handler = handler;
 568 action->flags = irqflags;
 569 cpus_clear(action->mask);
 570 action->name = devname;
 571 action->next = NULL;
 572 action->dev_id = dev_id;
 573
 574 select_smp_affinity(irq);
 575
 576#ifdef CONFIG_DEBUG_SHIRQ
 577 if (irqflags & IRQF_SHARED) {
//....

 584 unsigned long flags;
 585
 586 local_irq_save(flags);
 587 handler(irq, dev_id);
 588 local_irq_restore(flags);
 589 }
 590#endif
 591
 592 retval = setup_irq(irq, action);
 593 if (retval)
 594 kfree(action);
 595
 596 return retval;
 597}

数参数:
unsigned int irq:中断号,有些设备是预先指定的,大多数是自动检测获取或者动态确定。
handler:指向中断处理程序的指针,当相应的中断发生时,内核便会调用handler所指向处理程序。
irqflags:可以是0,或者是SA_INTERRUPT,SA_SAMPLE_RANDOM,SA_SHIRQ。
dev_name:产生中断的硬件的名字。
dev_id:该标志在共享中断号时用。
注意:使用此函数可能会睡眠,所以不能在中断上下文中用。
该函数相当于c++中的构造函数,成功返回0,否则返回非0。
前5个if语句是错误判断,作用依次为:
1 使用共享中断但没有提供dev_id则返回错误
2 中断号超出最大值
3 该中断号已被使用并且未共享
4 handler为空
5 未申请到内存
紧接着从566行开始根据函数传进来的相关参数初始化action结构,然后在调用setup_irq()注册该中断的irqaction结构体到irqactiona队列中。

释放void free()函数,原形:
void free_irq(unsigned int irq,void *dev_id);
释放时分两种情况:非共享时,将会在释放掉该处理程序的同时禁用该中断线。共享时,该函数将只会删除该中断线上由参数dev_id指定的那个中断处理程序。
注意:该函数应在进程上下文中调用。
当注册中断服务程序时,handler参数就是所要注册的中断服务程序,那么这个函数就是要自己编写的,定义如下:
static irqreturn_t my_handler(int irq,void *dev_id);
之所以将其定义为static是因为中断处理程序不会被其他文件中的代码直接调用。
然后再看返回值irqreturn_t,其实他就是int型,这样做为了和以前的版本兼容。
参数irq:中断线号,在没有dev_id之前,这个标志位很有用,现在只会在打印日志时用到他。
dev_id:设备唯一标识符,区分共享同一个中断处理程序的多个设备。
函数会返回两个值来通知用户是否真正处理了一个中断。分别是:
IRQ_NONE:当中断处理程序检测到一个中断后,发现该中断处理程序对应的设备并不是用request_irq()函数注册期间指定的那个设备时,则返回此值。
IRQ_HANDLER:当中断处理程序被正确调用,并且他检测到调用他的正是他所对应的那个设备时,则返回此值。
下面是一个例子:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>

static int irq;
static char *interface;

module_param(interface,charp,0644); //2.6内核中的宏,表示这个参数要在插入模块时给出值

module_param(irq,int,0644);
int dev_id = 127;//设备id

static irqreturn_t myinterrupt(int irq, void *dev_id)//中断服务程序,自己所写

{
        static int count = 0;
        if (count < 10) {
                printk("Interrupt %d, %d/n", irq, *(int *)dev_id);
                count++;
        }
        return IRQ_NONE;
}

static int __init myirqtest_init(void)
{
        printk ("My module worked!/n");
        if (request_irq(irq, &myinterrupt, IRQF_SHARED,interface, &dev_id)) {//注册中断,参数意义前面有讲

                printk(KERN_ERR "myirqtest: cannot register IRQ %d/n", irq);
                return -EIO;
        }
        printk("%s Request on IRQ %d succeede dev_id is:%d/n",interface, irq, dev_id);
    return 0;
}
static void __exit myirqtest_exit(void)
{
    printk ("Unloading my module./n");
    free_irq(irq, &irq);
    printk("Freeing IRQ %d/n", irq);
}
module_init(myirqtest_init);
module_exit(myirqtest_exit);
MODULE_LICENSE("GPL");

上面的例子牵扯到模块编程,可以参考这里:http://www.kerneltravel.net/?page_id=8

抱歉!评论已关闭.