zoukankan      html  css  js  c++  java
  • 字符设备驱动笔记——中断方式按键驱动之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)禁止中断
      
      
      
      
      
      
      
      
  • 相关阅读:
    Python使用SMTP模块、email模块发送邮件
    harbor搭建及使用
    ELK搭建-windows
    ELK技术栈之-Logstash详解
    【leetcode】1078. Occurrences After Bigram
    【leetcode】1073. Adding Two Negabinary Numbers
    【leetcode】1071. Greatest Common Divisor of Strings
    【leetcode】449. Serialize and Deserialize BST
    【leetcode】1039. Minimum Score Triangulation of Polygon
    【leetcode】486. Predict the Winner
  • 原文地址:https://www.cnblogs.com/liulipeng/p/3331424.html
Copyright © 2011-2022 走看看