中斷觸發流程


    在響應一個特定的中斷的時候,內核會執行一個函數,該函數叫做中斷處理程序(interrupt handler)或中斷服務例程(interrupt service routine ,ISP).產生中斷的每個設備都有一個相應的中斷處理程序,中斷處理程序通常不和特定的設備關聯,而是和特定的中斷關聯的,也就是說,如果一個設備可以 產生多種不同的中斷,那么該就可以對應多個中斷處理程序,相應的,該設備的驅動程序也就要准備多個這樣的函數。在Linux內核中處理中斷是分為上半部 (top half),和下半部(bottom half)之分的。上半部只做有嚴格時限的工作,例如對接收到的中斷進行應答或復位硬件,這些工作是在所有的中斷被禁止的情況下完成的,能夠被允許稍后完 成的工作會推遲到下半部去。

其實中斷的整個過程分為2個部分:

1 注冊

2 執行或者叫觸發

如上圖:首先中斷觸發,cpu響應,去執行IRQ中斷總的服務子程序(就是所有的IRQ中斷都經過這一步),去讀兩個寄存器,確定中斷號,再根據中斷號,在子程序鏈表中找到對應的中斷服務子程序,結束了。為了達到這樣的目的,把中斷號與中斷子程序聯系起來。request_irq()做的就只是這個工作。而GPIO與中斷號的聯系是定死的,或者這兩個中斷號還不一樣。后面講吧。

先說說request_irq(),就是把中斷例程添加到中斷子程序鏈表中去。

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);     
}
include/linux/interrupt.h
kernel/kernel/irq/manage.c
int request_threaded_irq(unsigned int irq, irq_handler_t handler,
                         irq_handler_t thread_fn, unsigned long irqflags,
                         const char *devname, void *dev_id)
{
        struct irqaction *action;//每一個action結構體中存放着一個中斷子程序的入口地址及相關信息
        struct irq_desc *desc;//每一個desc結構體中存放着一個中斷號的相關信息,一個中斷號可以有多個子程序,以鏈表形式存在,以dev_id名字區別
        int retval;
//IRQF_DISABLED:快速中斷標志,對應老版本中的SA_INTERRUPT標志,表明在處理本中斷時屏蔽CPU所有中斷(屏蔽其他中斷線上的中斷,本中斷線上本來就是屏蔽的),
//而在沒設置此標志位的程序中,都是開中斷處理的,可以進行中斷嵌套。嵌套與中斷線優先級有關,有中斷控制器控制。

  //  IRQF_SAMPLE_RANDOM:用於隨機數據產生;告訴內核,本中斷源可以用作隨機數生成器的熵池(這個不太理解)

  //  IRQF_SHARED:用於共享中斷,設置此標志時,request_irq最后一個參數dev不能為NULL,對應老版本內核的SA_SHIRQ;表示共享中斷線。

 
         

  //   IRQF_PROBE_SHARED:探測共享中斷;

 
         

  //  IRQF_TIMER:專用於定時中斷;


if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) == (IRQF_SHARED|IRQF_DISABLED)) {//共享中斷不能做快速中斷 pr_warning( "IRQ %d/%s: IRQF_DISABLED is not guaranteed on shared IRQs\n", irq, devname); } #ifdef CONFIG_LOCKDEP //若定義此宏,則禁止中斷嵌套,所有中斷都關中斷運行。 /* * Lockdep wants atomic interrupt handlers: */ irqflags |= IRQF_DISABLED; #endif if ((irqflags & IRQF_SHARED) && !dev_id)//如果狀態是共享,那么就必須要有dev_id,而且還不能與已經存在的重合,否則無法區別 return -EINVAL; desc = irq_to_desc(irq);//根據中斷號,找到對應的desc結構體,應該也包括創建新的desc結構體吧? if (!desc) //所有irq_desc在系統啟動時,通過init_IRQ初始化。 return -EINVAL; if (desc->status & IRQ_NOREQUEST) //若此中斷禁止響應,則返回。 return -EINVAL; if (!handler) { //沒有處理函數也不行 if (!thread_fn) return -EINVAL; handler = irq_default_primary_handler; } action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);//在內核空間分配一個action,用於存放一個中斷子程序的信息
//中斷的入口是irq_desc->handle_irq,這只是電平觸發或者邊沿觸發的處理,但我們注冊的中斷處理程序都是irq_desc下的一個action。 if (!action) return -ENOMEM; action->handler = handler; //我們定義的中斷處理子程序 action->thread_fn = thread_fn; action->flags = irqflags; //中斷的屬性 action->name = devname;//與該中斷相關聯的名稱,在/proc/interrupt中可看到。 action->dev_id = dev_id;//中斷服務程序的參數,可以為NULL,但在注冊共享中斷時,此參數不能為NULL。 chip_bus_lock(irq, desc); retval = __setup_irq(irq, desc, action); //添加進action鏈表,上下還鎖起來了。 chip_bus_sync_unlock(irq, desc); if (retval) kfree(action); #ifdef CONFIG_DEBUG_SHIRQ //調試用的 if (irqflags & IRQF_SHARED) { /* * It's a shared IRQ -- the driver ought to be prepared for it * to happen immediately, so let's make sure.... * We disable the irq to make sure that a 'real' IRQ doesn't * run in parallel with our fake.
*/ unsigned long flags; disable_irq(irq); local_irq_save(flags); handler(irq, dev_id); local_irq_restore(flags); enable_irq(irq); } #endif return retval; } EXPORT_SYMBOL(request_threaded_irq);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM