字符设备驱动笔记——中断方式按键驱动之linux中断处理结构(五)

一、单片机下的中断处理   1)分辨是哪一个中断

  2)调用处理函数

  3)清中断

二、linux下的中断处理 1)/arch/arm/kernel/irq.c

asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)

{

    struct pt_regs *old_regs = set_irq_regs(regs);

    struct irq_desc *desc = irq_desc + irq;



    /*

     * Some hardware gives randomly wrong interrupts.  Rather

     * than crashing, do something sensible.

     */

    if (irq >= NR_IRQS)

        desc = &bad_irq_desc;



    irq_enter();



    desc_handle_irq(irq, desc); /* AT91 specific workaround */

    irq_finish(irq);



    irq_exit();

    set_irq_regs(old_regs);

}



2)/kernel/irq/handle.c

static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc)

{

    desc->handle_irq(irq, desc);

}



3)/kernel/irq/chip.c

__set_irq_handler{

    ...

    desc->handle_irq = handle;

    ...

}



4)/include/linux/irq.h

static inline void set_irq_handler(unsigned int irq, irq_flow_handler_t handle)

{

    __set_irq_handler(irq, handle, 0, NULL);

}



5)/arch/arm/plat-s3c24xx/irq.c

void __init s3c24xx_init_irq(void)



6)/arch/arm/plat-s3c24xx/irq.c

set_irq_handler(irqno, handle_edge_irq);



7)/kernel/irq/chip.c

  调用4)

  调用3)

8)在s3c24xx_init_irq这个函数里面,初始化irq_desc结构体

struct irq_desc {

 irq_flow_handler_t handle_irq;  //set_irq_handler(irqno, handle_edge_irq);

    struct irq_chip        *chip;               //set_irq_chip(irqno, &s3c_irq_eint0t4);

    struct msi_desc        *msi_desc;

    void            *handler_data;

    void            *chip_data;

    struct irqaction    *action;    /* IRQ action list */

    unsigned int        status;        /* IRQ status */



....

9)/kernel/irq/chip.c

分析handle_edge_irq: void fastcall

handle_edge_irq(unsigned int irq, struct irq_desc *desc)

{

    const unsigned int cpu = smp_processor_id();



    spin_lock(&desc->lock);



    desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);



    /*

     * If we're currently running this IRQ, or its disabled,

     * we shouldn't process the IRQ. Mark it pending, handle

     * the necessary masking and go out

     */

    if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) ||

            !desc->action)) {

        desc->status |= (IRQ_PENDING | IRQ_MASKED);

        mask_ack_irq(desc, irq);

        goto out_unlock;

    }



    kstat_cpu(cpu).irqs[irq]++;            //发生中断的次数



    /* Start handling the irq */        //开始处理中断

    desc->chip->ack(irq);        //desc->chip chip是之前初始化的s3c_irqext_chip



    /* Mark the IRQ currently in progress.*/

    desc->status |= IRQ_INPROGRESS;



    do {

        struct irqaction *action = desc->action;

        irqreturn_t action_ret;



        if (unlikely(!action)) {    //判断链表是否为空

            desc->chip->mask(irq);

            goto out_unlock;

        }



        /*

         * When another irq arrived while we were handling

         * one, we could have masked the irq.

         * Renable it, if it was not disabled in meantime.

         */

        if (unlikely((desc->status &

                   (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==

                  (IRQ_PENDING | IRQ_MASKED))) {

            desc->chip->unmask(irq);

            desc->status &= ~IRQ_MASKED;

        }



        desc->status &= ~IRQ_PENDING;

        spin_unlock(&desc->lock);

        action_ret = handle_IRQ_event(irq, action);//真正的处理过程

        if (!noirqdebug)

            note_interrupt(irq, desc, action_ret);

        ......

}



10)

/arch/arm/plat-s3c24xx/irq.c

s3c_irqext_chip中的.ack

static struct irq_chip s3c_irqext_chip = {

    .name        = "s3c-ext",

    .mask        = s3c_irqext_mask,

    .unmask        = s3c_irqext_unmask,

    .ack = s3c_irqext_ack,

    .set_type    = s3c_irqext_type,

    .set_wake    = s3c_irqext_wake

};

s3c_irqext_ack分析: static void s3c_irqext_ack(unsigned int irqno)

{

    unsigned long req;

    unsigned long bit;

    unsigned long mask;



    bit = 1UL << (irqno - EXTINT_OFF);



    mask = __raw_readl(S3C24XX_EINTMASK);



    __raw_writel(bit, S3C24XX_EINTPEND);



    req = __raw_readl(S3C24XX_EINTPEND);

    req &= ~mask;



    /* not sure if we should be acking the parent irq... */



    if (irqno <= IRQ_EINT7 ) {

        if ((req & 0xf0) == 0)

            s3c_irq_ack(IRQ_EINT4t7);

    } else {

        if ((req >> 8) == 0)

            s3c_irq_ack(IRQ_EINT8t23);

    }

}



static inline void s3c_irq_ack(unsigned int irqno)

{

    unsigned long bitval = 1UL << (irqno - IRQ_EINT0);



    __raw_writel(bitval, S3C2410_SRCPND);

    __raw_writel(bitval, S3C2410_INTPND);

}

 ①desc->chip->ack(irq);//上面是清理中断 ============================================================ ②handle_edge_irq取出action链表中的成员,执行action->handler



irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)

{

    irqreturn_t ret, retval = IRQ_NONE;

    unsigned int status = 0;



    handle_dynamic_tick(action);



    if (!(action->flags & IRQF_DISABLED))

        local_irq_enable_in_hardirq();



    do {

        ret = action->handler(irq, action->dev_id);

        if (ret == IRQ_HANDLED)

            status |= action->flags;

        retval |= ret;

        action = action->next;

    } while (action);



    if (status & IRQF_SAMPLE_RANDOM)

        add_interrupt_randomness(irq);

    local_irq_disable();



    return retval;

}



总结: 按下按键 1>cup进入异常处理模式 b vector_irq + ... 2>__irq_user 3>asm_do_IRQ 4>irq_des[irq]以中断号为下标取出一项 ->handle_irq struct irq_desc { irq_flow_handler_t handle_irq; //set_irq_handler(irqno, handle_edge_irq); //handle_edge_irq取出action链表中的成员, //执行action->handler(自定义实现) struct irq_chip *chip; //set_irq_chip(irqno, &s3c_irq_eint0t4); //芯片相关的一些操作 ... } 5>handle_irq = handle_edge_irq 6>handle_edge_irq的操作: (1)desc->chip->ack(irq); (2)handle_IRQ_event(irq, action); =========================================================================================== 自定义异常处理函数action->handler,注册进内核



request_irq 1./kernel/irq/manage.c

int request_irq(unsigned int irq, irq_handler_t handler,

        unsigned long irqflags, const char *devname, void *dev_id)

{

    //1)分配了一个结构,结构中的成员指向传递进来的参数

    action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);

    //2)设置irq

    retval = setup_irq(irq, action);

}



2.setup_irq()函数分析:

  1)irq_des[irq] 已irq为下标找到数组项

  2)在irq_des[irq]链表里面加入传递进来的参数action

  3)desc->chip->settype()设置为中断引脚                        

  4)desc->chip->startup / desc->chip->enable 使能中断

  

free_irq(irq, dev_id) 1)从链表中除去

  2)禁止中断

  

  

  

  

  

  

  

  

 

你可能感兴趣的:(linux)