• 字符设备驱动笔记——中断方式按键驱动之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)禁止中断
      
      
      
      
      
      
      
      
  • 相关阅读:
    CSS Sprites技术
    js Event对象
    iphone上做webapp时总会识别一串数字为手机号码并变黑显示
    获得touch事件,jquery绑定事件监听器,ios设备上打开touch状态以响应focus,active等伪类
    访问局域网内数据库
    理解javascript的闭包,原型,和匿名函数及IIFE
    socket跟TCP/IP 的关系,单台服务器上的并发TCP连接数问题
    最详细的Log4j使用教程
    [Java IO]06_JSON操作
    mybatis一次执行多条SQL语句
  • 原文地址:https://www.cnblogs.com/liulipeng/p/3331424.html
Copyright © 2020-2023  润新知