深入分析request_irq的dev_id參數(shù)作用 注:若對(duì)kernel中斷處理模型不是很清楚的話(如:irqaction的作用)可以先參考一下這篇文檔: http://blog./u2/60011/showart.php?id=1079281 這里主要講request_irq的參數(shù)dev_id的作用,內(nèi)容會(huì)涉及到少許上面文檔提到的內(nèi)容。 Request_irq的作用是申請(qǐng)使用IRQ并注冊(cè)中斷處理程序。 request_irq()函數(shù)的原型如下:
/* kernel/irq/manage.c */ 我們知道,當(dāng)使用內(nèi)核共享中斷時(shí),request_irq必須要提供dev_id參數(shù),并且dev_id的值必須唯一。那么這里提供唯一的dev_id值的究竟是做什么用的? 起先我以為dev_id的值是提供給kernel進(jìn)行判斷共享中斷線上的哪一個(gè)設(shè)備產(chǎn)生了中斷(即哪個(gè)irqaction產(chǎn)生中斷),然后執(zhí)行相應(yīng)的中斷處理函數(shù)(irqaction->handler)。實(shí)際上不是的,我們來看看《Linux Kernel Development – Second Edition》第六章中Shared Handlers這一節(jié),其中有段總結(jié)性的文字如下: When the kernel receives an interrupt, it invokes sequentially each registered handler on the line. Therefore, it is important that the handler be capable of distinguishing whether it generated a given interrupt. The handler must quickly exit if its associated device did not generate the interrupt. This requires the hardware device to have a status register (or similar mechanism) that the handler can check. Most hardware does indeed have such a feature. 這段話的大概意思是,發(fā)生中斷時(shí),內(nèi)核并不判斷究竟是共享中斷線上的哪個(gè)設(shè)備產(chǎn)生了中斷,它會(huì)循環(huán)執(zhí)行所有該中斷線上注冊(cè)的中斷處理函數(shù)(即irqaction->handler函數(shù))。因此irqaction->handler函數(shù)有責(zé)任識(shí)別出是否是自己的硬件設(shè)備產(chǎn)生了中斷,然后再執(zhí)行該中斷處理函數(shù)。通常是通過讀取該硬件設(shè)備提供的中斷flag標(biāo)志位進(jìn)行判斷。 那既然kernel循環(huán)執(zhí)行該中斷線上注冊(cè)的所有irqaction->handler函數(shù),把識(shí)別究竟是哪個(gè)硬件設(shè)備產(chǎn)生了中斷這件事交給中斷處理函數(shù)本身去做,那request_irq的dev_id參數(shù)究竟是做什么用的? 我總結(jié)了一下,實(shí)際上dev_id作用主要有兩點(diǎn): 一.在中斷處理程序釋放時(shí)使用到dev_id When your driver unloads, you need to unregister your interrupt handler and potentially disable the interrupt line. To do this, call void free_irq(unsigned int irq, void *dev_id) …… The fifth parameter, dev_id, is used primarily for shared interrupt lines. When an interrupt handler is freed (discussed later), dev_id provides a unique cookie to allow the removal of only the desired interrupt handler from the interrupt line. Without this parameter, it would be impossible for the kernel to know which handler to remove on a given interrupt line. 這里《LKD2》講了很清楚,當(dāng)調(diào)用free_irq注銷中斷處理函數(shù)時(shí)(通常卸載驅(qū)動(dòng)時(shí)其中斷處理函數(shù)也會(huì)被注銷掉),因?yàn)閐ev_id是唯一的,所以可以通過它來判斷從共享中斷線上的多個(gè)中斷處理程序中刪除指定的一個(gè)。如果沒有這個(gè)參數(shù),那么kernel不可能知道給定的中斷線上到底要?jiǎng)h除哪一個(gè)處理程序。 下面我們來看一下free_irq的代碼: void free_irq(unsigned int irq, void *dev_id) 二.將使用該中斷處理程序的設(shè)備結(jié)構(gòu)體傳遞給該中斷處理程序 首先看兩個(gè)基礎(chǔ)條件: 1) 內(nèi)核中的各個(gè)設(shè)備結(jié)構(gòu)體肯定是唯一的,因此滿足dev_id唯一這個(gè)要求 2) dev_id參數(shù)會(huì)在發(fā)生中斷時(shí)傳遞給該中斷的服務(wù)程序。 典型的中斷服務(wù)程序定義如下: static irqreturn_t intr_handler(int irq, void *dev_id, struct pt_regs *regs); 即request_irq的dev_id參數(shù)會(huì)傳遞給該中斷服務(wù)程序的dev_id。因此也可以將驅(qū)動(dòng)程序的設(shè)備結(jié)構(gòu)體通過dev_id傳遞給中斷服務(wù)程序。 這樣做作用主要有兩個(gè): 1) 中斷服務(wù)程序可能使用到設(shè)備結(jié)構(gòu)體中的信息 如s3c2410的iis音頻驅(qū)動(dòng),它是將DMA Channel結(jié)構(gòu)體通過dev_id傳遞給中斷服務(wù)程序 /* arch/arm/mach-s3c2410/dma.c */ 目的是中斷處理函數(shù)s3c2410_dma_irq內(nèi)需要用到chan結(jié)構(gòu)體的duf成員和load_state成員等。 使用方法如下: /* arch/arm/mach-s3c2410/dma.c */ 因此,我們可以通過將設(shè)備結(jié)構(gòu)傳遞給request_irq的dev_id參數(shù)這種機(jī)制,在中斷處理函數(shù)中使用該設(shè)備結(jié)構(gòu)體,這是大部分驅(qū)動(dòng)程序通用的一種手法。 2)前面我們講了若使用共享中斷,那么中斷處理函數(shù)自身需要能識(shí)別是否是自己的設(shè)備產(chǎn) 生了中斷。通常這是通過讀取該硬件設(shè)備提供的中斷flag標(biāo)志位進(jìn)行判斷的。 而往往驅(qū)動(dòng)程序里定義的設(shè)備結(jié)構(gòu)體通常包含了該設(shè)備的IO地址,加上偏移就可以算出中斷狀態(tài)寄存器及中斷flag標(biāo)志位的IO地址信息。因此將設(shè)備結(jié)構(gòu)體通過dev_id傳遞給設(shè)備中斷處理程序的另一個(gè)作用就是使用共享中斷時(shí),可以在中斷處理函數(shù)內(nèi)通過讀取該設(shè)備結(jié)構(gòu) (dev_id) 中提供的中斷Flag標(biāo)志位地址信息進(jìn)行判斷,是否是該設(shè)備產(chǎn)生了中斷,然后再進(jìn)一步判斷是否繼續(xù)往下執(zhí)行還是跳到下一個(gè)irqaction->handler函數(shù)再判斷執(zhí)行。當(dāng)然,如果本來就知道該設(shè)備中斷狀態(tài)寄存器的IO地址,也可以選擇直接readl該地址信息進(jìn)行判斷。 |
|