Linux中断导读之一--注册部分<3>

前面介绍了中断的初始化代码,稍带着执行流程也过的差不多了

这里看下我们经常碰到的中断的注册,看看和前面是怎么关联起来的,

也就是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);
}

参数为中断号,中断处理函数,标志

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

    /*
     * 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)              //如果是shared那么需要dev_id用于区分
        return -EINVAL;

    desc = irq_to_desc(irq);                                               //得到描述结构
    if (!desc)
        return -EINVAL;

    if (!irq_settings_can_request(desc) ||
        WARN_ON(irq_settings_is_per_cpu_devid(desc)))
        return -EINVAL;

    if (!handler) {
        if (!thread_fn)
            return -EINVAL;
        handler = irq_default_primary_handler;
    }

    action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);    //分配一个action结构
    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(desc);
    retval = __setup_irq(irq, desc, action);                               //********
    chip_bus_sync_unlock(desc);

    if (retval)
        kfree(action);

#ifdef CONFIG_DEBUG_SHIRQ_FIXME
    if (!retval && (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;
}
EXPORT_SYMBOL(request_threaded_irq);

相关推荐