这是我曾经做产品开发时的一个案例!我做研发有个特点就是每做完一个项目习惯写些总结,这是90%搞技术的不能做到的,也许是我记性太差,怕自己忘了曾经解决问题的思路,所以要把她记录下来吧!可以我这一习惯为我研发工作积累了非常宝贵的经验,也为我日后教学准备了非常宝贵的案例教学!
如果你深入的去想想Linux kernel 中断问题,你会有一系列的疑问。按照常人,或者说自然规律的思考方式(不同的人有不同的头脑,就有不同的思维方式,也就有不同的解决问题的方法,这其中的效率完全不一样。虽然大部分人是常规思维方式,但是千万不要认为你的朋友,对手,同事的思维方式与你一样。),你会有下列疑问:
我们通常在驱动里面要注册中断,都是调用reguest_irq。因为,觉得Linux已经很成熟了,而且各大CPU的BSP也支持得很好。况且我们调试的驱动都是基于当今热门的sumsang ARM MCU。所以,更本就没有去怀疑其BSP。
可是,“最终出问题的地方往往是最先否定的地方”。
我们客户提供的kernel及sumsang 提供的bsp竟然有问题。
言归正传,我带着疑问顺滕摸瓜,揭开Linux-2.6.21-s3c6400中断机制。
我们在写驱动时往往要调用request_irq()函数。那么,我们从这里出发。Reguest_irq的函数原形为
/**见kernel/irq/manage.c
* request_irq - allocate an interrupt line
* @irq: Interrupt line to allocate
* @handler: Function to be called when the IRQ occurs
* @irqflags: Interrupt type flags
* @devname: An ascii name for the claiming device
* @dev_id: A cookie passed back to the handler function
*
* This call allocates interrupt resources and enables the
* interrupt line and IRQ handling. From the point this
* call is made your handler function may be invoked. Since
* your handler function must clear any interrupt the board
* raises, you must take care both to initialise your hardware
* and to set up the interrupt handler in the right order.
*
* Dev_id must be globally unique. Normally the address of the
* device data structure is used as the cookie. Since the handler
* receives this value it makes sense to use it.
*
* If your interrupt is shared you must pass a non NULL dev_id
* as this is required when freeing the interrupt.
*
* Flags:
*
* IRQF_SHARED Interrupt is shared
* IRQF_DISABLED Disable local interrupts while processing
* IRQF_SAMPLE_RANDOM The interrupt can be used for entropy
*
*/
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
{
struct irqaction *action;
int retval;
#ifdef CONFIG_LOCKDEP
/*
* Lockdep wants atomic interrupt handlers:
*/
irqflags |= IRQF_DISABLED;
#endif
/*
* Sanity-check: shared interrupts must pass in a real dev-ID,
* otherwise we'll have trouble later trying to figure out
* which interrupt is which (messes up the interrupt freeing
* logic etc).
*/
if ((irqflags & IRQF_SHARED) && !dev_id)
return -EINVAL;
if (irq >= NR_IRQS)
return -EINVAL;
if (irq_desc[irq].status & IRQ_NOREQUEST)
return -EINVAL;
if (!handler)
return -EINVAL;
action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
if (!action)
return -ENOMEM;
action->handler = handler;/*这一句要注意,我们注册的中断函数句柄就放在这里,当中断发生后,kernel就会调用到这里来,kernel怎么找到这里我后面会讲到*/
action->flags = irqflags;
cpus_clear(action->mask);
action->name = devname;
action->next = NULL;
action->dev_id = dev_id;
select_smp_affinity(irq);
#ifdef CONFIG_DEBUG_SHIRQ
if (irqflags & IRQF_SHARED) {
/*
* It's a shared IRQ -- the driver ought to be prepared for it
* to happen immediately, so let's make sure....
* We do this before actually registering it, to make sure that
* a 'real' IRQ doesn't run in parallel with our fake
*/
if (irqflags & IRQF_DISABLED) {
unsigned long flags;
local_irq_save(flags);
handler(irq, dev_id);
local_irq_restore(flags);
} else
handler(irq, dev_id);
}
#endif
retval = setup_irq(irq, action);
if (retval)
kfree(action);
return retval;
}
这个函数其实只做两件事情:
填充(增加)一个活动irq结构体(irqaction)
调用setup_irq函数
2009-2-13 下家山 写于上海.漕河泾
有什么问题可以给我邮件ximenpiaoxue4016@sina.com或加我群198204885