专栏中心

EEPW首页 > 专栏 > Linux-2.6.21 S3c6400中断剖析之一(原创)-上海嵌入式索漫科技培训教材

Linux-2.6.21 S3c6400中断剖析之一(原创)-上海嵌入式索漫科技培训教材

发布人:xiajiashan 时间:2012-10-10 来源:工程师 发布文章
作者:下家山(请尊重原创,转载请注明 上海索漫  http://www.xiajiashan.com  一:为什么写这篇文章

        这是我曾经做产品开发时的一个案例!我做研发有个特点就是每做完一个项目习惯写些总结,这是90%搞技术的不能做到的,也许是我记性太差,怕自己忘了曾经解决问题的思路,所以要把她记录下来吧!可以我这一习惯为我研发工作积累了非常宝贵的经验,也为我日后教学准备了非常宝贵的案例教学!

        如果你深入的去想想Linux kernel  中断问题,你会有一系列的疑问。按照常人,或者说自然规律的思考方式(不同的人有不同的头脑,就有不同的思维方式,也就有不同的解决问题的方法,这其中的效率完全不一样。虽然大部分人是常规思维方式,但是千万不要认为你的朋友,对手,同事的思维方式与你一样。),你会有下列疑问:

1.1:中断注册到什么地方去了? 1.2:CPU发生了中断后,kernel是怎么知道的?也就是kernel 是怎么响应到cpu的中断的? 1.3:kernel 响应CPU中断后又怎么回调到当初注册的中断里面去的?

       我们通常在驱动里面要注册中断,都是调用reguest_irq。因为,觉得Linux已经很成熟了,而且各大CPU的BSP也支持得很好。况且我们调试的驱动都是基于当今热门的sumsang ARM MCU。所以,更本就没有去怀疑其BSP。

可是,“最终出问题的地方往往是最先否定的地方”。

我们客户提供的kernel及sumsang 提供的bsp竟然有问题。

二:Linux中断机制流程

言归正传,我带着疑问顺滕摸瓜,揭开Linux-2.6.21-s3c6400中断机制。

2.1 调用的第一个函数request_irq()

我们在写驱动时往往要调用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

专栏文章内容及配图由作者撰写发布,仅供工程师学习之用,如有侵权或者其他违规问题,请联系本站处理。 联系我们

关键词:

相关推荐

如何使用Microchip MAPS选择适合你的PIC® MCU

利用Flash实现DSP对多个程序有选择的加载

MCP3903六通道模拟前端采样芯片

艾迈斯欧司朗推出超紧凑绿光ChipLED,以极小体积实现入耳式设备精准心率监测

瑞萨RA0单片机连载之―面向对象之I2C驱动OLED

如何建立中游领域性KG(知识图)

全球水资源可持续发展的技术驱动型解决方案

瑞萨RA0单片机连载⸺OLED面向对象显示字符串

利用51LPC系列单片机内部比较器实现AD键盘的方法

英飞凌微控制器:以全新实惠套件和强大开发环境为开发者提供支持

论AGI与人形机器人

机器人 2025-04-19

OpenCV行人检测--米尔基于全志T527核心板开发板

利用VB实现PC机与多单片机通讯

基于STM32的避障小车

运算放大器简介

利用P87LPC762 单片机设计绕线计数器的方法

【瑞萨RA2E1开发板】使用ADC功能实现位移传感器采集方案

利用串口与并口实现51内核单片机的在线编程

迷你七位数字电位器MCP40D17/8/9

运算放大器产品组合

更多 培训课堂
更多 焦点
更多 视频

技术专区