1、注册中断
1)static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
{
return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}
handler - 中断处理函数
flags - 中断属性
name - 用于线程名
dev - 设备结构体,传回给isr,用于区分不同设备
flags几个常见取值:
#define IRQF_TRIGGER_NONE 0x00000000
#define IRQF_TRIGGER_RISING 0x00000001
#define IRQF_TRIGGER_FALLING 0x00000002
#define IRQF_TRIGGER_HIGH 0x00000004
#define IRQF_TRIGGER_LOW 0x00000008
* IRQF_DISABLED - keep irqs disabled when calling the action handler.
* DEPRECATED. This flag is a NOOP and scheduled to be removed
* IRQF_SHARED - allow sharing the irq among several devices
* IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur
* IRQF_TIMER - Flag to mark this interrupt as timer interrupt
* IRQF_PERCPU - Interrupt is per cpu
* IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing
* IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
* registered first in an shared interrupt is considered for
* performance reasons)
* IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
* Used by threaded interrupts which need to keep the
* irq line disabled until the threaded handler has been run.
* IRQF_NO_SUSPEND - Do not disable this IRQ during suspend
* IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set
* IRQF_NO_THREAD - Interrupt cannot be threaded
* IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device
* resume time.
2)thread_fn为空,缺省不使用线程模式。
if (irq_settings_can_thread(desc))
irq_setup_forced_threading(new);
但不设置IRQF_NO_THREAD,又被设置为线程。
kthread_create(irq_thread, new, "irq/%d-%s", irq, new->name);
如果是第一次注册,创建了一个线程来处理当前irq,FIFO模式。
如果是线程模式,handle函数被置空,并返回IRQ_WAKE_THREAD
new->handler = irq_default_primary_handler;
3)不管哪种模式,通过下面代码保存action到irq_desc中。
desc = irq_to_desc(irq);
old_ptr = &desc->action;
new->irq = irq;
*old_ptr = new; //即新的action,保存有handler,name和dev
4)share模式要保证部分flags和以前设置的兼容,如触发方式等。
2、ISR的调用
1)IDT(Interrupt Descriptor Table)中断描述表
2)do_IRQ函数
3)handle_irq:指向了handle_level_irq,或者是handle_edge_irq
4)handle_level_irq:调用handle_irq_event
if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
if (!irq_check_poll(desc))
goto out_unlock;
5)handle_irq_event:遍历所有action,调用action->handler(irq, action->dev_id);
6)如果返回IRQ_WAKE_THREAD,说明是线程模式
irq_wake_thread(desc, action);
test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags)
wake_up_process(action->thread);
1)static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
{
return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}
handler - 中断处理函数
flags - 中断属性
name - 用于线程名
dev - 设备结构体,传回给isr,用于区分不同设备
flags几个常见取值:
#define IRQF_TRIGGER_NONE 0x00000000
#define IRQF_TRIGGER_RISING 0x00000001
#define IRQF_TRIGGER_FALLING 0x00000002
#define IRQF_TRIGGER_HIGH 0x00000004
#define IRQF_TRIGGER_LOW 0x00000008
* IRQF_DISABLED - keep irqs disabled when calling the action handler.
* DEPRECATED. This flag is a NOOP and scheduled to be removed
* IRQF_SHARED - allow sharing the irq among several devices
* IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur
* IRQF_TIMER - Flag to mark this interrupt as timer interrupt
* IRQF_PERCPU - Interrupt is per cpu
* IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing
* IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
* registered first in an shared interrupt is considered for
* performance reasons)
* IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
* Used by threaded interrupts which need to keep the
* irq line disabled until the threaded handler has been run.
* IRQF_NO_SUSPEND - Do not disable this IRQ during suspend
* IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set
* IRQF_NO_THREAD - Interrupt cannot be threaded
* IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device
* resume time.
2)thread_fn为空,缺省不使用线程模式。
if (irq_settings_can_thread(desc))
irq_setup_forced_threading(new);
但不设置IRQF_NO_THREAD,又被设置为线程。
kthread_create(irq_thread, new, "irq/%d-%s", irq, new->name);
如果是第一次注册,创建了一个线程来处理当前irq,FIFO模式。
如果是线程模式,handle函数被置空,并返回IRQ_WAKE_THREAD
new->handler = irq_default_primary_handler;
3)不管哪种模式,通过下面代码保存action到irq_desc中。
desc = irq_to_desc(irq);
old_ptr = &desc->action;
new->irq = irq;
*old_ptr = new; //即新的action,保存有handler,name和dev
4)share模式要保证部分flags和以前设置的兼容,如触发方式等。
2、ISR的调用
1)IDT(Interrupt Descriptor Table)中断描述表
2)do_IRQ函数
3)handle_irq:指向了handle_level_irq,或者是handle_edge_irq
4)handle_level_irq:调用handle_irq_event
if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
if (!irq_check_poll(desc))
goto out_unlock;
5)handle_irq_event:遍历所有action,调用action->handler(irq, action->dev_id);
6)如果返回IRQ_WAKE_THREAD,说明是线程模式
irq_wake_thread(desc, action);
test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags)
wake_up_process(action->thread);
通知线程开始处理