1. 程式人生 > >中斷處理程式與中斷服務例程

中斷處理程式與中斷服務例程

1. 什麼是中斷

簡單來說中斷就是硬體裝置與處理器的一種交流方式,比如當我按下一個鍵時,只有當處理器知道我按下了這個鍵並且做出相應的處理時,按鍵這個操作才是有效的。我們知道處理器的速度遠遠高於外圍裝置的速度,處理器與外設選擇合適的交流方式就格外重要。輪詢是一種方式,這種方式是核心週期性地對裝置狀態進行查詢並作出相應的的動作,但這種方式會讓核心做大量的無用功,這顯然是不明智的。更好的方式是讓外設在其需要的時候向核心傳送訊號,這就是中斷機制。

2.中斷處理程式

當一箇中斷髮生時,核心應該有相應的處理方法,這個方法就是中斷處理程式,一箇中斷處理程式對應一箇中斷號。中斷處理程式是管理硬體的驅動程式的一部分,如果裝置需要中斷,相應的裝置驅動程式就需註冊中斷處理程式。註冊方式:使用request_irq()函式

  1. int
  2. request_irq(unsignedint irq,irqreturn_t(*handler)(int,void*,struct pt_regs *),unsignedlong irqflags,constchar* devname,void*dev_id)

函式引數: 
irq:表示要分配的中斷號 
handler:函式指標,指向中斷的實際中斷處理函式 
irqflags:中斷處理程式的標誌,舉例來說: IRQF_DISABLED被設定後核心在處理中斷處理程式本身期間要禁止所有的其他中斷。 
devname:與中斷相關的裝置的ASCII文字表示 
dev_id:用於共享中斷線,當一箇中斷處理程式需要釋放時,dev_id提供唯一的標誌資訊。

3.中斷服務例程

一條中斷線對應一箇中斷一箇中斷處理程式,而多個裝置可能共享一條中斷線,那麼如何讓中斷處理程式為不同的裝置提供不同的處理方法。這就引出了中斷服務例程。一箇中斷處理程式對應若干個中斷服務例程。

中斷處理程式就相當於某個中斷向量的總的處理程式,比如IRQ0x09_interrupt()是中斷號為9的總處理程式,假如這個9號中斷由5個裝置共享,那麼這5個裝置都分別有其對應的中斷服務例程。也就是說當有多個裝置需要共享某個中斷線時,中斷處理程式必須要呼叫ISR,此時會呼叫handle_IRQ_event()

4.request_irq函式分析

  1. int
  2. request_irq(unsigned
    int irq,irqreturn_t(*handler)(int,void*,struct pt_regs *),
  3. unsignedlong irqflags,constchar* devname,void*dev_id)
  4. {
  5. int retval;
  6. struct irqaction * action;
  7. if(irq >= ACTUAL_NR_IRQS)//中斷號是否超過最大值
  8. return-EINVAL;
  9. if(!handler)//函式指標是否為空
  10. return-EINVAL;
  11. #if 1
  12. /*
  13. * Sanity-check: shared interrupts should REALLY pass in
  14. * a real dev-ID, otherwise we'll have trouble later trying
  15. * to figure out which interrupt is which (messes up the
  16. * interrupt freeing logic etc).
  17. */
  18. if((irqflags & SA_SHIRQ)&&!dev_id){//若中斷共享但dev_id為NULL則出錯
  19. printk(KERN_ERR
  20. "Bad boy: %s (at %p) called us without a dev_id!\n",
  21. devname, __builtin_return_address(0));
  22. }
  23. #endif
  24. action =(struct irqaction *)
  25. kmalloc(sizeof(struct irqaction), GFP_KERNEL);//建立irqaction結構體
  26. if(!action)
  27. return-ENOMEM;
  28. action->handler = handler;//將函式引數傳給結構體
  29. action->flags = irqflags;
  30. cpus_clear(action->mask);
  31. action->name = devname;
  32. action->next = NULL;
  33. action->dev_id = dev_id;
  34. #ifdef CONFIG_SMP
  35. select_smp_affinity(irq);
  36. #endif
  37. retval = setup_irq(irq, action);//註冊中斷irqaction結構體
  38. if(retval)
  39. kfree(action);
  40. return retval;
  41. }
  1. struct irqaction {
  2. irqreturn_t(*handler)(int,void*,struct pt_regs *);//具體的中斷服務例程
  3. unsignedlong flags;//一組中斷標誌
  4. cpumask_t mask;
  5. constchar*name;//中斷裝置名稱
  6. void*dev_id;指定裝置的主裝置號和次裝置號
  7. struct irqaction *next;//指向共享中斷線的下一個 irqaction結構體
  8. int irq;//申請的中斷號
  9. struct proc_dir_entry *dir;
  10. };