B.Linux

灵魂构造师

导航

字符设备驱动(1)代码分析---之request_irq

err = request_irq(irq, button_interrupt, IRQ_TYPE_EDGE_BOTH, 
            buttons[i].name, (void *)&buttons[i]);
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_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*/
 
    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)
            return -EINVAL;

        desc = irq_to_desc(irq);
            ###
            #define NR_IRQS            (IRQ_EINT(31) + S5P_GPIOINT_COUNT + 1)
            //IRQ_EINT(31) = 160 +31-16 = 175
            #define S5P_GPIOINT_COUNT    (S5P_GPIOINT_GROUP_COUNT * S5P_GPIOINT_GROUP_SIZE)
            #define S5P_GPIOINT_GROUP_COUNT 4
            #define S5P_GPIOINT_GROUP_SIZE    8
            //#define S5P_GPIOINT_COUNT 12
            #define NR_IRQS            (175+12+ 1)
            //#define NR_IRQS            188
            ####
                #ifndef CONFIG_SPARSE_IRQ
                extern struct irq_desc irq_desc[NR_IRQS];
                #endif
            ####
            struct irq_desc *irq_to_desc(unsigned int irq)
            {
                return (irq < NR_IRQS) ? irq_desc + irq : NULL;
            }
            //desc = irq_desc[irq]
            //irqdesc.c
            #else /* !CONFIG_SPARSE_IRQ */

            struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
                [0 ... NR_IRQS-1] = {
                    .handle_irq    = handle_bad_irq,
                    .depth        = 1,
                    .lock        = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
                }
            }
            ###
        if (!desc)
            return -EINVAL;
        ###
            static inline bool irq_settings_can_request(struct irq_desc *desc)
            {
                return !(desc->status_use_accessors & _IRQ_NOREQUEST);
            }
        ###
        if (!irq_settings_can_request(desc))
            return -EINVAL;

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

        action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
        ###
        /**
         * struct irqaction - per interrupt action descriptor
         * @handler:    interrupt handler function
         * @flags:    flags (see IRQF_* above)
         * @name:    name of the device
         * @dev_id:    cookie to identify the device
         * @next:    pointer to the next irqaction for shared interrupts
         * @irq:    interrupt number
         * @dir:    pointer to the proc/irq/NN/name entry
         * @thread_fn:    interrupt handler function for threaded interrupts
         * @thread:    thread pointer for threaded interrupts
         * @thread_flags:    flags related to @thread
         * @thread_mask:    bitmask for keeping track of @thread activity
         */
         struct irqaction {
            irq_handler_t handler;
            unsigned long flags;
            void *dev_id;
            struct irqaction *next;
            int irq;
            irq_handler_t thread_fn;
            struct task_struct *thread;
            unsigned long thread_flags;
            unsigned long thread_mask;
            const char *name;
            struct proc_dir_entry *dir;
         } ____cacheline_internodealigned_in_smp;
        ###
        
        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);
        
        ###
            static int
            __setup_irq(unsigned int irq, struct irq_desc *desc, 
                                struct irqaction *new)
            {    
                register_irq_proc(irq, desc);
                new->dir = NULL;
                register_handler_proc(irq, new);
                free_cpumask_var(mask);
                return 0;
            }
        ###
        chip_bus_sync_unlock(desc);

        if (retval)
            kfree(action);

        return retval;
    }
    ##
}    

 

posted on 2019-06-21 12:49  B.Linux  阅读(328)  评论(0编辑  收藏  举报