文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>ARM Linux对中断的处理--中断注册方法

ARM Linux对中断的处理--中断注册方法

时间:2010-06-11  来源:tq08g2z

中断注册方法

在通过request_irq()函数注册中断服务程序的时候,将会把中断向量和中断服务程序对应起来。我们来看一下request_irq的定义(在文件include/linux/interrupt.h中):

static inline int __must_check

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,

        const char *name, void *dev)

{

    return request_threaded_irq(irq, handler, NULL, flags, name, dev);

}

现在的内核里面,request_irq()主要调用request_threaded_irq()来完成工作,而request_threaded_irq()则主要是分配一个struct irqaction,并用传递给它的参数来初始化这个结构体,然后调用将这个struct irqaction挂接在对应于中断线的irq_desc的action链中__setup_irq()。

各个参数意义:

irq是要申请的硬件中断号。

  handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。

  irqflags是中断处理的属性,若设置了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版zhon已经不支持了),则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置了IRQF_SHARED(老版本中的SA_SHIRQ),则表示是多个设备共享同一个中断,若设置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示将对系统熵有贡献,对系统获取随机数有好处。(这几个flag是可以通过或的方式同时使用的)。

  dev_id在中断共享时会用到,一般设置为这个设备的设备中任何有效的地址值或者NULL。

  devname设置与中断号相关联的名称,在/proc/interrupts文件中可以看到此名称。

  request_irq()返回0表示成功,返回-EINVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断号已经被占用且不能共享。

  关于中断注册的例子,大家可在内核中搜索下request_irq。

函数request_threaded_irq()在文件kernel/irq/manage.c中定义:

/**

 *  request_threaded_irq - allocate an interrupt line

 *  @irq: Interrupt line to allocate

 *  @handler: Function to be called when the IRQ occurs.

 *       Primary handler for threaded interrupts

 *       If NULL and thread_fn != NULL the default

 *       primary handler is installed

 *  @thread_fn: Function called from the irq handler thread

 *         If NULL, no irq thread is created

 *  @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.

 *

 *  If you want to set up a threaded irq handler for your device

 *  then you need to supply @handler and @thread_fn. @handler ist

 *  still called in hard interrupt context and has to check

 *  whether the interrupt originates from the device. If yes it

 *  needs to disable the interrupt on the device and return

 *  IRQ_WAKE_THREAD which will wake up the handler thread and run

 *  @thread_fn. This split handler design is necessary to support

 *  shared interrupts.

 *

 *  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

 *  IRQF_TRIGGER_*       Specify active edge(s) or level

 *

 */

int request_threaded_irq(unsigned int irq, irq_handler_t handler,

            irq_handler_t thread_fn, unsigned long irqflags,

            const char *devname, void *dev_id)

{

    struct irqaction *action;

    struct irq_desc *desc;

    int retval;

 

    /*

     * handle_IRQ_event() always ignores IRQF_DISABLED except for

     * the _first_ irqaction (sigh).  That can cause oopsing, but

     * the behavior is classified as "will not fix" so we need to

     * start nudging drivers away from using that idiom.

     */

    if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) ==

                  (IRQF_SHARED|IRQF_DISABLED)) {

       pr_warning(

         "IRQ %d/%s: IRQF_DISABLED is not guaranteed on shared IRQs\n",

           irq, devname);

    }

 

#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;

 

    desc = irq_to_desc(irq);

    if (!desc)

       return -EINVAL;

 

    if (desc->status & IRQ_NOREQUEST)

       return -EINVAL;

 

    if (!handler) {

       if (!thread_fn)

           return -EINVAL;

       handler = irq_default_primary_handler;

    }

 

    action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);

    if (!action)

       return -ENOMEM;

 

    action->handler = handler;

    action->thread_fn = thread_fn;

    action->flags = irqflags;

    action->name = devname;

    action->dev_id = dev_id;

 

    chip_bus_lock(irq, desc);

    retval = __setup_irq(irq, desc, action);

    chip_bus_sync_unlock(irq, desc);

 

    if (retval)

       kfree(action);

 

#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 disable the irq to make sure that a 'real' IRQ doesn't

        * run in parallel with our fake.

        */

       unsigned long flags;

 

       disable_irq(irq);

       local_irq_save(flags);

 

       handler(irq, dev_id);

 

       local_irq_restore(flags);

       enable_irq(irq);

    }

#endif

    return retval;

}

相关阅读 更多 +
排行榜 更多 +
封仙之倚天记应用宝版本

封仙之倚天记应用宝版本

角色扮演 下载
阴阳师旧版本

阴阳师旧版本

棋牌卡牌 下载
仙境情缘变态高爆版

仙境情缘变态高爆版

角色扮演 下载