中斷

 

  1. /* *****************************************************************************  
  2.                 1.申請和釋放中斷  
  3.    ***************************************************************************** */ 
  4. //*----------------------------------------------------------------------------  
  5. //* \fn    request_irq()  
  6. //* \brief 該函數用來申請一個IRQ,其中irq是要申請的硬件中斷號,hander是向系統登記的中斷處理函數,  
  7. //*中斷髮生時系統調用這個函數,dev_id參數將被傳遞給它。irqflags是中斷處理的屬性,若設置爲  
  8. //* SA_INTERRUPT,則表示中斷處理程序爲快速處理程序,快速處理程序在調用時屏蔽所有中斷,慢速處理程  
  9. //*序不屏蔽;若設置爲SA_SHIRQ,則表示多個設備共享中斷,dev_id在中斷共享時會用到,一般設置爲這個設  
  10. //*備的設備結構體或者NULL.  
  11.  
  12. //* \return value:  
  13. //*     0 : 表示成功  
  14. //*     -INVAL: 表示中斷號無效或者是處理函數指針爲NULL  
  15. //*     -EBUSY : 表示中斷已經被佔用且不能共享  
  16. //*----------------------------------------------------------------------------  
  17.  
  18. int request_irq(unsigned int irq,void (*handler)(int irq,void *dev_id,struct pt_regs *regs),  
  19.                 unsigned long irqflags,const char *devname,void *dev_id);  
  20.     //*----------------------------------------------------------------------------  
  21. //* \fn    free_irq()  
  22. //* \brief 該函數用來釋放一個IRQ,參數與request_irq()相同  
  23.  
  24. //*----------------------------------------------------------------------------   
  25. void free_irq(unsigned int irq,void *dev_id);         
  26.  
  27. /* *****************************************************************************  
  28.                2.使能和屏蔽中斷  
  29.    ***************************************************************************** */  
  30. //*----------------------------------------------------------------------------  
  31. //* \fn    disable_irq(),disable_irq_nosync(),enable_irq()  
  32. //* \brief 這三個函數用於屏蔽一箇中斷源,其中disable_irq_nosync()立即返回;  
  33. //* disable_irq()等待目前的中斷處理完成後返回.說明:這三個函數作用於可編程控制器,因此  
  34. //*對系統內的所有CPU都生效。  
  35.  
  36. //*----------------------------------------------------------------------------   
  37. void disable_irq(int irq);  
  38. void disable_irq_nosync(int irq);  
  39. void enable_irq(int irq);  
  40. //*----------------------------------------------------------------------------  
  41. //* \fn    local_irq_save(),local_irq_disable()  
  42. //* \brief 這2個函數將屏蔽cpu內的所有中斷,其中local_irq_save()將目前的中斷狀態保存在  
  43. //* flags中.說明:flags被直接傳遞而不是通過指針傳遞;local_irq_disable()直接禁止中斷。  
  44. //*----------------------------------------------------------------------------   
  45. void local_irq_save(unsigned long flags);  
  46. void local_irq_disable(void);  
  47. //*----------------------------------------------------------------------------  
  48. //* \fn    local_irq_restore(),local_irq_restore()  
  49. //* \brief 這2個函數將上述倆函數(local_irq_save(),local_irq_disable())禁止的中斷恢復  
  50. //*----------------------------------------------------------------------------   
  51. void local_irq_restore(unsigned long flags);  
  52. void local_irq_restore(void);  
  53.  
  54. /* *****************************************************************************  
  55.                3.底半部機制  
  56.     Linux系統實現底半部機制主要有tasklet、工作隊列和軟中斷。  
  57. 3.1 tasklet  
  58.      tasklet的使用比較簡單,我們只需要定義tasklet及其處理函數並將二者關聯,例如  
  59. void my_tasklet_func(unsigned long);//定義一個處理函數  
  60. DECLARE_TASKLET(my_tasklet,my_tasklet_func,data);//定義一個tasklet結構my_tasklet,與  
  61. my_tasklet_func(data)函數相關聯。  
  62.     在需要調度tasklet的時候引用一個task_schedule()函數就能使系統在適當的時候進行調度運行,如下所示:  
  63. task_schedule(&my_tasklet);  
  64.     使用tasklet作爲底半部處理中斷的設備驅動程序模板如下:  
  65.    ***************************************************************************** */  
  66.    /*定義tasklet和底半部函數並關聯*/ 
  67.    void xxx_do_tasklet(unsigned long);  
  68.    DECLARE_TASKLET(xxx_tasklet,xxx_do_tasklet,0);  
  69.    /*中斷處理底半部*/ 
  70.    void xxx_do_tasklet(unsigned long)  
  71.    {  
  72.         ...  
  73.    }  
  74.    /*中斷處理頂半部*/ 
  75.    irqreturn_t xxx_interrupt(int irq,void *dev_id,struct pt_regs *regs)  
  76. {  
  77.     ...  
  78.     tasklet_schedule(&xxx_tasklet);  
  79.     ...  
  80. }     
  81. /*設備驅動加載模塊*/ 
  82. void _init xxx_init(void)  
  83. {  
  84.     ...  
  85.     //申請中斷  
  86.     result = request_irq(xxx_irq,xxx_interrupt,SA_INTERRUPT,"XXX",NULL);  
  87.     ...  
  88. }  
  89. /*設備驅動卸載模塊*/ 
  90. void _exit xxx_exit(void)  
  91. {  
  92.     ...  
  93.     //釋放中斷  
  94.     free_irq(xxx_irq,NULL);  
  95.     ...  
  96. }     
  97. /* *****************************************************************************  
  98. 3.2 工作隊列  
  99.      工作隊列與tasklet的使用非常類似,我們只需要定義工作隊列及其處理函數並將二者關聯,例如  
  100. struct work_struct my_wq;//定義一個工作隊列  
  101. void my_wq_func(unsigned long);//定義一個處理函數  
  102. INIT_WORK(&my_wq,(void(*)(void *))my_wq_func,NULL);//初始化工作隊列並將它與處理函數綁定。  
  103.     在需要調度tasklet的時候引用一個schedule_work()函數就能使系統在適當的時候進行調度運行,如下所示:  
  104. schedule_work(&my_wq);  
  105.     使用工作隊列作爲底半部處理中斷的設備驅動程序模板如下:  
  106.    ***************************************************************************** */ 
  107.    /*定義工作隊列和底半部函數*/ 
  108.    struct work_struct xxx_wq;  
  109.    void xxx_do_work(unsigned long);  
  110.   // DECLARE_TASKLET(xxx_tasklet,xxx_do_tasklet,0);  
  111.    /*中斷處理底半部*/ 
  112.    void xxx_do_work(unsigned long)  
  113.    {  
  114.         ...  
  115.    }  
  116.    /*中斷處理頂半部*/ 
  117.    irqreturn_t xxx_interrupt(int irq,void *dev_id,struct pt_regs *regs)  
  118. {  
  119.     ...  
  120.     schedule_work(&xxx_wq);  
  121.     ...  
  122. }     
  123. /*設備驅動加載模塊*/ 
  124. void _init xxx_init(void)  
  125. {  
  126.     ...  
  127.     //申請中斷  
  128.     result = request_irq(xxx_irq,xxx_interrupt,SA_INTERRUPT,"XXX",NULL);  
  129.     ...  
  130.     //初始化工作隊列  
  131.     INIT_WORK(&xxx_wq,void(*)(void *))xxx_do_work,NULL);  
  132.     ...  
  133. }  
  134. /*設備驅動卸載模塊*/ 
  135. void _exit xxx_exit(void)  
  136. {  
  137.     ...  
  138.     //釋放中斷  
  139.     free_irq(xxx_irq,NULL);  
  140.     ...  
  141. }   
  142. /* *****************************************************************************  
  143. 3.3 軟中斷  
  144.      軟中斷是用軟件方式模擬硬件中斷的概念,實現宏觀上的異步執行效果,tasklet也是基於軟中斷實現的  
  145. 基於信號的異步通知也類似於中斷。硬中斷是外部設備對CPU的中斷,軟中斷是硬中斷服務程序對內核的中斷。而信號  
  146. 是由內核給某個進程的中斷。  
  147.     linux內核中,用softirq_action結構體表徵一個軟中斷,這個結構體中包含軟中斷處理函數指針和傳遞給該函數的  
  148. 參數。使用open_softirq()函數可以註冊軟中斷對應的處理函數,使用raise_action()函數可以出發一個軟中斷。  
  149.     軟中斷和tasklet仍然運行於中斷上下文,而工作隊列運行於進程上下文。因此,軟中斷和tasklet處理函數中不能睡眠,  
  150. 而工作隊列處理函數中可以睡眠。  
  151.     local_bh_disable()和local_bh_enable()是內核中用於禁止和使能軟中斷和tasklet底半部機制的函數。  
  152.    ***************************************************************************** */ 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章