中斷處理程式與中斷服務例程
1. 什麼是中斷
簡單來說中斷就是硬體裝置與處理器的一種交流方式,比如當我按下一個鍵時,只有當處理器知道我按下了這個鍵並且做出相應的處理時,按鍵這個操作才是有效的。我們知道處理器的速度遠遠高於外圍裝置的速度,處理器與外設選擇合適的交流方式就格外重要。輪詢是一種方式,這種方式是核心週期性地對裝置狀態進行查詢並作出相應的的動作,但這種方式會讓核心做大量的無用功,這顯然是不明智的。更好的方式是讓外設在其需要的時候向核心傳送訊號,這就是中斷機制。
2.中斷處理程式
當一箇中斷髮生時,核心應該有相應的處理方法,這個方法就是中斷處理程式,一箇中斷處理程式對應一箇中斷號。中斷處理程式是管理硬體的驅動程式的一部分,如果裝置需要中斷,相應的裝置驅動程式就需註冊中斷處理程式。註冊方式:使用request_irq()函式
int
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函式分析
int
request_irq(unsigned
unsignedlong irqflags,constchar* devname,void*dev_id)
{
int retval;
struct irqaction * action;
if(irq >= ACTUAL_NR_IRQS)//中斷號是否超過最大值
return-EINVAL;
if(!handler)//函式指標是否為空
return-EINVAL;
#if 1
/*
* Sanity-check: shared interrupts should REALLY pass in
* a real dev-ID, otherwise we'll have trouble later trying
* to figure out which interrupt is which (messes up the
* interrupt freeing logic etc).
*/
if((irqflags & SA_SHIRQ)&&!dev_id){//若中斷共享但dev_id為NULL則出錯
printk(KERN_ERR
"Bad boy: %s (at %p) called us without a dev_id!\n",
devname, __builtin_return_address(0));
}
#endif
action =(struct irqaction *)
kmalloc(sizeof(struct irqaction), GFP_KERNEL);//建立irqaction結構體
if(!action)
return-ENOMEM;
action->handler = handler;//將函式引數傳給結構體
action->flags = irqflags;
cpus_clear(action->mask);
action->name = devname;
action->next = NULL;
action->dev_id = dev_id;
#ifdef CONFIG_SMP
select_smp_affinity(irq);
#endif
retval = setup_irq(irq, action);//註冊中斷irqaction結構體
if(retval)
kfree(action);
return retval;
}
struct irqaction {
irqreturn_t(*handler)(int,void*,struct pt_regs *);//具體的中斷服務例程
unsignedlong flags;//一組中斷標誌
cpumask_t mask;
constchar*name;//中斷裝置名稱
void*dev_id;指定裝置的主裝置號和次裝置號
struct irqaction *next;//指向共享中斷線的下一個 irqaction結構體
int irq;//申請的中斷號
struct proc_dir_entry *dir;
};