三读内核中断处理(4):几个特定的中断处理函数

来源:互联网 发布:ssm框架源码 编辑:程序博客网 时间:2024/05/17 13:39

快乐虾

http://blog.csdn.net/lights_joy/

lights@hb165.com

  

本文适用于

ADSP-BF561

优视BF561EVB开发板

uclinux-2008r1.5-rc3(smp patch)

Visual DSP++ 5.0(update 5)

  

欢迎转载,但请保留作者信息

 

1.1    handle_simple_irq

对于不同中断源的默认处理函数(irq_desc结构体中的handle_irq),内核将之分成了3类。除了PF0-PF47的中断和IRQ_PROG0_INTAIRQ_PROG1_INTAIRQ_PROG2_INTA这三个由PF口共享的中断外对于其它的中断源则使用handle_simple_irq进行处理。

handle_simple_irq函数位于kernel/irq/chip.c

/**

 *   handle_simple_irq - Simple and software-decoded IRQs.

 *   @irq:    the interrupt number

 *   @desc:   the interrupt description structure for this irq

 *

 *   Simple interrupts are either sent from a demultiplexing interrupt

 *   handler or come from hardware, where no interrupt hardware control

 *   is necessary.

 *

 *   Note: The caller is expected to handle the ack, clear, mask and

 *   unmask issues if necessary.

 */

void fastcall

handle_simple_irq(unsigned int irq, struct irq_desc *desc)

{

     struct irqaction *action;

     irqreturn_t action_ret;

     const unsigned int cpu = smp_processor_id();

 

     spin_lock(&desc->lock);

 

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

         goto out_unlock;

     kstat_cpu(cpu).irqs[irq]++;

 

     action = desc->action;

     if (unlikely(!action || (desc->status & IRQ_DISABLED))) {

         if (desc->chip->mask)

              desc->chip->mask(irq);

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

         desc->status |= IRQ_PENDING;

         goto out_unlock;

     }

 

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

     desc->status |= IRQ_INPROGRESS;

     spin_unlock(&desc->lock);

 

     action_ret = handle_IRQ_event(irq, action);

     if (!noirqdebug)

         note_interrupt(irq, desc, action_ret);

 

     spin_lock(&desc->lock);

     desc->status &= ~IRQ_INPROGRESS;

out_unlock:

     spin_unlock(&desc->lock);

}

从这个函数的代码可以看出,这个函数的作用就是调用handle_IRQ_event,并更新desc中的状态。在中断初始化完成的时候,除了EVT_TMR之外,其它的中断源的action都为NULL,因此对大部分中断源造成的中断此函数将直接返回。

下面看看handle_IRQ_event的实现:

/**

 * handle_IRQ_event - irq action chain handler

 * @irq: the interrupt number

 * @action:   the interrupt action chain for this irq

 *

 * Handles the action chain of an irq event

 */

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;

}

 

很简单,就是按顺序调用action链表中的处理函数。

1.2    handle_level_irq

这个函数用于处理PF0-PF47产生的中断。

/**

 *   handle_level_irq - Level type irq handler

 *   @irq:    the interrupt number

 *   @desc:   the interrupt description structure for this irq

 *

 *   Level type interrupts are active as long as the hardware line has

 *   the active level. This may require to mask the interrupt and unmask

 *   it after the associated handler has acknowledged the device, so the

 *   interrupt line is back to inactive.

 */

void fastcall

handle_level_irq(unsigned int irq, struct irq_desc *desc)

{

     unsigned int cpu = smp_processor_id();

     struct irqaction *action;

     irqreturn_t action_ret;

 

     spin_lock(&desc->lock);

     mask_ack_irq(desc, irq);

 

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

         goto out_unlock;

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

     kstat_cpu(cpu).irqs[irq]++;

 

     /*

      * If its disabled or no action available

      * keep it masked and get out of here

      */

     action = desc->action;

     if (unlikely(!action || (desc->status & IRQ_DISABLED)))

         goto out_unlock;

 

     desc->status |= IRQ_INPROGRESS;

     spin_unlock(&desc->lock);

 

     action_ret = handle_IRQ_event(irq, action);

     if (!noirqdebug)

         note_interrupt(irq, desc, action_ret);

 

     spin_lock(&desc->lock);

     desc->status &= ~IRQ_INPROGRESS;

     if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)

         desc->chip->unmask(irq);

out_unlock:

     spin_unlock(&desc->lock);

}

实际上这个函数仍将调用handle_IRQ_event进行后继的处理。

1.3    bf561_demux_gpio_irq

这个函数用于处理三个复用的PF中断。

static void bf561_demux_gpio_irq(unsigned int inta_irq,

                    struct irq_desc *intb_desc)

{

     int irq, flag_d, mask;

     u16 gpio;

 

     switch (inta_irq) {

     case IRQ_PROG0_INTA:

         irq = IRQ_PF0;

         break;

     case IRQ_PROG1_INTA:

         irq = IRQ_PF16;

         break;

     case IRQ_PROG2_INTA:

         irq = IRQ_PF32;

         break;

     default:

         dump_stack();

         return;

     }

 

     gpio = irq - IRQ_PF0;

 

         flag_d = get_gpiop_data(gpio);

         mask = flag_d & (gpio_enabled[gpio_bank(gpio)] &

                    get_gpiop_maska(gpio));

 

              do {

                   if (mask & 1) {

                       struct irq_desc *desc = irq_desc + irq;

                       desc->handle_irq(irq, desc);

                   }

                   irq++;

                   mask >>= 1;

              } while (mask);

 

 

}

 

 

 

 

 

 

 

 

原创粉丝点击