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

快乐虾

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

[email protected]

本文适用于

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);

}

你可能感兴趣的:(.net,Blog)