Chinaunix首页 | 论坛 | 博客
  • 博客访问: 529758
  • 博文数量: 70
  • 博客积分: 3162
  • 博客等级: 中校
  • 技术积分: 850
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-23 13:30
文章分类
文章存档

2013年(1)

2012年(4)

2011年(1)

2010年(7)

2009年(9)

2008年(20)

2007年(3)

2006年(25)

分类: LINUX

2008-12-14 17:16:09

原文:

1 中断初始化
参见  arch\arm\mach-s3c2410\Irq.c
void __init s3c24xx_init_irq(void)
{
    …
    /* 1. 清除所有pending的中断 */
    last = 0;
    for (i = 0; i
        pend = __raw_readl(S3C24XX_EINTPEND);

        if (pend == 0 || pend == last)
            break;

        __raw_writel(pend, S3C24XX_EINTPEND);
        printk("irq: clearing pending ext status %08x\n", (int)pend);
        last = pend;
    }

    last = 0;
    for (i = 0; i
        pend = __raw_readl(S3C2410_INTPND);

        if (pend == 0 || pend == last)
            break;

        __raw_writel(pend, S3C2410_SRCPND);
        __raw_writel(pend, S3C2410_INTPND);
        printk("irq: clearing pending status %08x\n", (int)pend);
        last = pend;
    }

    last = 0;
    for (i = 0; i
        pend = __raw_readl(S3C2410_SUBSRCPND);

        if (pend == 0 || pend == last)
            break;

        printk("irq: clearing subpending status %08x\n", (int)pend);
        __raw_writel(pend, S3C2410_SUBSRCPND);
        last = pend;
    }

    /* 注册中断处理函数. */
    irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");

    for (irqno = IRQ_EINT4t7; irqno
        /* set all the s3c2410 internal irqs */

        switch (irqno) {
            /* 这几个中断是级联的,所以中断例程也不一样.*/
        case IRQ_EINT4t7:
        case IRQ_EINT8t23:
        case IRQ_UART0:
        case IRQ_UART1:
        case IRQ_UART2:
        case IRQ_ADCPARENT:
            set_irq_chip(irqno, &s3c_irq_level_chip);
            set_irq_handler(irqno, do_level_IRQ);  /*这个中断例程在后面会被重新设置*/
            break;

        case IRQ_RESERVED6:
        case IRQ_RESERVED24:
            /* no IRQ here */
            break;

        default:
            //irqdbf("registering irq %d (s3c irq)\n", irqno);
            set_irq_chip(irqno, &s3c_irq_chip);
            set_irq_handler(irqno, do_edge_IRQ);  /*对于不是级联的中断,这个就是中断例程.*/
            set_irq_flags(irqno, IRQF_VALID);
        }
    }

    /* 重新设置级联的中断例程*/
    set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint);  
    set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint);

    set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
    set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
    set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
    set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);

    /* 为外部中断设置中断例程*/
    for (irqno = IRQ_EINT0; irqno
        irqdbf("registering irq %d (ext int)\n", irqno);
        set_irq_chip(irqno, &s3c_irq_eint0t4);
        set_irq_handler(irqno, do_edge_IRQ);
        set_irq_flags(irqno, IRQF_VALID);
    }

    for (irqno = IRQ_EINT4; irqno
        irqdbf("registering irq %d (extended s3c irq)\n", irqno);
        set_irq_chip(irqno, &s3c_irqext_chip);
        set_irq_handler(irqno, do_edge_IRQ);
        set_irq_flags(irqno, IRQF_VALID);
    }

    /* 为UART设置中断例程,*/
    irqdbf("s3c2410: registering external interrupts\n");

    for (irqno = IRQ_S3CUART_RX0; irqno
        irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
        set_irq_chip(irqno, &s3c_irq_uart0);
        set_irq_handler(irqno, do_level_IRQ);
        set_irq_flags(irqno, IRQF_VALID);
    }

    for (irqno = IRQ_S3CUART_RX1; irqno
        irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
        set_irq_chip(irqno, &s3c_irq_uart1);
        set_irq_handler(irqno, do_level_IRQ);
        set_irq_flags(irqno, IRQF_VALID);
    }

    for (irqno = IRQ_S3CUART_RX2; irqno
        irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
        set_irq_chip(irqno, &s3c_irq_uart2);
        set_irq_handler(irqno, do_level_IRQ);
        set_irq_flags(irqno, IRQF_VALID);
    }

    for (irqno = IRQ_TC; irqno
        irqdbf("registering irq %d (s3c adc irq)\n", irqno);
        set_irq_chip(irqno, &s3c_irq_adc);
        set_irq_handler(irqno, do_edge_IRQ);
        set_irq_flags(irqno, IRQF_VALID);
    }
    irqdbf("s3c2410: registered interrupt handlers\n");
}
所谓级联的中断, 即指有几个中断共用同一个中断线, 比如EINT4-EINT7就共用一个中断线:EINT4_7. 假如现在系统产生一个EINT4的中断, 大致的中断流程顺序是: …-> s3c_irq_demux_extint -> do_edge_IRQ -> 我们注册的中断例程. 后面我们会详细讲解.
接下来我们主要set_irq_handle()函数, set_irq_chip()主要用来设置对这个中断mask, unmask等操作的函数, 它们会在适当的地方被调用.
static inline void
set_irq_handler(unsigned int irq,
        void fastcall (*handle)(unsigned int, struct irq_desc *,
                   struct pt_regs *))
{
    __set_irq_handler(irq, handle, 0);
}
void
__set_irq_handler(unsigned int irq,
          void fastcall (*handle)(unsigned int, irq_desc_t *,
                     struct pt_regs *),
          int is_chained)
{
    struct irq_desc *desc;
    unsigned long flags;

    if (irq >= NR_IRQS) {
        printk(KERN_ERR
               "Trying to install type control for IRQ%d\n", irq);
        return;
    }
   
    /* irq_desc 是一个静态数组,存放每个中断信息*/
    desc = irq_desc + irq;

    if (!handle)
        handle = handle_bad_irq;

    if (desc->chip == &no_irq_chip) {
        printk(KERN_WARNING "Trying to install %sinterrupt handler "
               "for IRQ%d\n", is_chained ? "chained " : " ", irq);
        /*
         * Some ARM implementations install a handler for really dumb
         * interrupt hardware without setting an irq_chip. This worked
         * with the ARM no_irq_chip but the check in setup_irq would
         * prevent us to setup the interrupt at all. Switch it to
         * dummy_irq_chip for easy transition.
         */
        desc->chip = &dummy_irq_chip;
    }

    spin_lock_irqsave(&desc->lock, flags);

    /* Uninstall? */
    if (handle == handle_bad_irq) {
        if (desc->chip != &no_irq_chip) {
            desc->chip->mask(irq);
            desc->chip->ack(irq);
        }
        desc->status |= IRQ_DISABLED;
        desc->depth = 1;
    }
    desc->handle_irq = handle;  /*保存中断例程*/

    if (handle != handle_bad_irq && is_chained) {
        desc->status &= ~IRQ_DISABLED;
        desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
        desc->depth = 0;
        desc->chip->unmask(irq);  /*对于级联的中断会先调用unmask来打开中断*/
    }
    spin_unlock_irqrestore(&desc->lock, flags);
}
每个中断都有一个irq_desc的对象来描述它,这里面保存了这个中断的状态,处理函数等信息.
当中断产生时比如EINT4, 大致的流程如下:
先调用在初始化里注册好的s3c_irq_demux_extint() (EINT4,EINT5,EINT6,EINT7都先调用它)
static void
s3c_irq_demux_extint(unsigned int irq,
             struct irqdesc *desc,
             struct pt_regs *regs)
{
    unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);  /*先获取具体是哪个EINT产生中断.*/
    unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);

    eintpnd &= ~eintmsk;  /*检查是否被屏蔽了*/

    if (eintpnd) {
        irq = fls(eintpnd);   /*获取相对于EINT0的中断号*/
        irq += (IRQ_EINT4 - (4 + 1));   /*算出在整个中断控制器下的中断号, 这里就是IRQ_EINT4*/

        desc_handle_irq(irq, irq_desc + irq, regs); /*以IRQ_EINT4调用这个函数.*/
    }
}
Static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
{
      /*这里的desc就代表的是EINT4, 所以这里实际调用了do_edge_IRQ(在初始化时注册的) */
        desc->handle_irq(irq, desc, regs);
}
#define do_edge_IRQ  handle_edge_irq
void fastcall
handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
{
    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);  /*清除中断标记*/

    /* Mark the IRQ currently in progress.*/
    desc->status |= IRQ_INPROGRESS;  /*设置状态*/

    do {
        struct irqaction *action = desc->action;  /*这个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, regs, action);  /*处理具体中断*/
        if (!noirqdebug)
            note_interrupt(irq, desc, action_ret, regs);
        spin_lock(&desc->lock);

    } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);

    desc->status &= ~IRQ_INPROGRESS;
out_unlock:
    spin_unlock(&desc->lock);
}
irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action)
{
      ….
      ret = action->handler(irq, action->dev_id, regs);  
      ….
}
其中action->handler就是我们用request_irq()注册的我们自己的中断例程. 具体原理可以参考这个函数的实现.
阅读(1793) | 评论(0) | 转发(0) |
0

上一篇:2410 中断系统

下一篇:FFT结果的物理意义

给主人留下些什么吧!~~