- 论坛徽章:
- 0
|
最近在做uclinux设备驱动实验时,涉及到I2c总线的驱动。程序主要采取中断方试读写I2c数据。而uclinux中中断主要采用函数 request_irqrequest_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
unsigned long irq_flags, const char * devname, void *dev_id)
申请获得中断号并注册中断函数。那么这个函数时到底如何管理中断的呢,它又是怎样管理ARM下的中断资源呢。本文将带你追踪如下:
首先,这个函数的源定义如下:
request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
unsigned long irq_flags, const char * devname, void *dev_id)
{
unsigned long retval;
struct irqaction *action;
if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler ||
(irq_flags & SA_SHIRQ && !dev_id))
return -EINVAL;
action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return -ENOMEM;
action->handler = handler;
action->flags = irq_flags;
action->mask = 0;
action->name = devname;
action->next = NULL;
action->dev_id = dev_id;
retval = setup_arm_irq(irq, action);
if (retval)
kfree(action);
return retval;
}
程序首先检查所要申请中断号是否越界,中断处理函数是否有效,并对中断标志和设备名称是否为空做出判断。注意还有irq_desc[irq].valid,关于这一项的意义,后面将给出解释。
接着,向内核申请一个irqaction结构,并且填充这个结构。最后调用函数setup_arm_irq()。
下面先来解释一下irqaction结构,其完整定义如下:
struct irqaction {
void (*handler)(int, void *, struct pt_regs *); //中断处理函数
unsigned long flags; //中断管理有关的位掩码
unsigned long mask;
const char *name; //中断拥有者名称
void *dev_id; //用于共享的中断信号线
struct irqaction *next; //构成链表
};
irqaction结构包含中断申请者的所有信息,而request_irq函数填充一个中断申请者结构,然后通过函数setup_arm_irq向系统申请中断。在解释函数setup_arm_irq之前先来解释一下irqdesc结构
struct irqdesc {
unsigned int nomask : 1; /* IRQ does not mask in IRQ */
unsigned int enabled : 1; /* IRQ is currently enabled */
unsigned int triggered: 1; /* IRQ has occurred */
unsigned int probing : 1; /* IRQ in use for a probe */
unsigned int probe_ok : 1; /* IRQ can be used for probe */
unsigned int valid : 1; /* IRQ claimable */
unsigned int noautoenable : 1; /* don't automatically enable IRQ */
unsigned int unused :25;
void (*mask_ack)(unsigned int irq); /* Mask and acknowledge IRQ */
void (*mask)(unsigned int irq); /* Mask IRQ */
void (*unmask)(unsigned int irq); /* Unmask IRQ */
struct irqaction *action;
/*
* IRQ lock detection
*/
unsigned int lck_cnt;
unsigned int lck_pc;
unsigned int lck_jif;
};
irqdesc包含了中断的基本信息,并且还包含了一个中段申请者的指针。程序在初始化时定义了一个全局的irqdesc数组
irqdesc irq_desc[];
下面来看函数
int setup_arm_irq(int irq, struct irqaction * new)
{
int shared = 0; //判断中断是否被共享
struct irqaction *old, **p;
unsigned long flags;
struct irqdesc *desc;
/*
* Some drivers like serial.c use request_irq() heavily,
* so we have to be careful not to interfere with a
* running system.
*/
if (new->flags & SA_SAMPLE_RANDOM) {
/*
* This function might sleep, we want to call it first,
* outside of the atomic block.
* Yes, this might clear the entropy pool if the wrong
* driver is attempted to be loaded, without actually
* installing a new handler, but is this really a problem,
* only the sysadmin is able to do this.
*/
rand_initialize_irq(irq);
}
/*
* The following block of code has to be executed atomically
*/
desc = irq_desc + irq; //desc就是irq_desc[irq]
spin_lock_irqsave(&irq_controller_lock, flags);
p = &desc->action;
if ((old = *p) != NULL) {
/* Can't share interrupts unless both agree to */
if (!(old->flags & new->flags & SA_SHIRQ)) {
spin_unlock_irqrestore(&irq_controller_lock, flags);
return -EBUSY;
}
/* add new interrupt at end of irq queue */
do {
p = &old->next;
old = *p;
} while (old);
shared = 1;
}
*p = new;
if (!shared) {
desc->probing = 0;
desc->running = 0;
desc->pending = 0;
desc->disable_depth = 1;
if (!desc->noautoenable) {
desc->disable_depth = 0;
desc->unmask(irq);
}
}
spin_unlock_irqrestore(&irq_controller_lock, flags);
return 0;
}
以上函数其本功能时根据irq中断号,来申请irq_desc[irq]这个中断结构,如果这个结构没被其他的设备占用,则申请成功,并且填充这个结构。这个结构是系统中断管理最重的结构。最后内核是如何利用这个结构来进行中断函数调用呢,我将继续追踪
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/15800/showart_86704.html |
|