一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

深入分析request_irq的dev_id參數(shù)作用

 bingfeng1210 2011-10-14

深入分析request_irqdev_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 */
int request_irq(unsigned int irq,
irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id);

我們知道,當(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)
{
struct irq_desc *desc;
struct irqaction **p;
unsigned long flags;
WARN_ON(in_interrupt());
if (irq >= NR_IRQS)
return;
desc = irq_desc + irq; /* 獲取該中斷號(hào)對(duì)應(yīng)的irq_desc */
spin_lock_irqsave(&desc->lock, flags);
p = &desc->action; /* 找到該irq的irqaction鏈表 */
for (;;) {
struct irqaction *action = *p;
if (action) {
struct irqaction **pp = p;
p = &action->next;
if (action->dev_id != dev_id)
continue; /* 這兩句進(jìn)行循環(huán)判斷,直到找到相應(yīng)dev_id設(shè)備的irqaction */
/* Found it - now remove it from the list of entries */
*pp = action->next; /* 指向下一個(gè)irqaction */
/* Currently used only by UML, might disappear one day.*/
#ifdef CONFIG_IRQ_RELEASE_METHOD
if (desc->chip->release)
desc->chip->release(irq, dev_id);
#endif
if (!desc->action) {
desc->status |= IRQ_DISABLED;
if (desc->chip->shutdown)
desc->chip->shutdown(irq);
else
desc->chip->disable(irq);
}
recalculate_desc_flags(desc);
spin_unlock_irqrestore(&desc->lock, flags);
unregister_handler_proc(irq, action);
/* Make sure it's not being used on another CPU */
synchronize_irq(irq);
kfree(action); /* 刪除該設(shè)備(dev_id)的irqaction */
return;
}
printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);
spin_unlock_irqrestore(&desc->lock, flags);
return;
}
}

二.將使用該中斷處理程序的設(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 */
int s3c2410_dma_request(unsigned int channel, struct s3c2410_dma_client *client,void *dev)
{
err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
client->name, (void *)chan);
……
}

目的是中斷處理函數(shù)s3c2410_dma_irq內(nèi)需要用到chan結(jié)構(gòu)體的duf成員和load_state成員等。

使用方法如下:

/* arch/arm/mach-s3c2410/dma.c */
static irqreturn_t
s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
{
struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw; /* 這里強(qiáng)制轉(zhuǎn)化成request_irq時(shí)傳給dev_id的設(shè)備類型,此處即s3c2410_dma_chan ,下面便可以使用它*/
struct s3c2410_dma_buf *buf;
buf = chan->curr;
……
}

因此,我們可以通過將設(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)行判斷。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    99久久免费中文字幕| 免费高清欧美一区二区视频| 精品国产亚洲av久一区二区三区 | 内射精品欧美一区二区三区久久久| 日韩av亚洲一区二区三区| 日韩成人高清免费在线| 丝袜av一区二区三区四区五区| 午夜精品国产精品久久久| 久草精品视频精品视频精品| 国产亚洲成av人在线观看| 久久亚洲成熟女人毛片| 成人精品日韩专区在线观看| av一区二区三区天堂| 欧美国产日产在线观看| 精品人妻av区波多野结依| 亚洲国产91精品视频| 国产午夜精品在线免费看| 精品国产丝袜一区二区| 女厕偷窥一区二区三区在线| 东京不热免费观看日本| 日韩中文无线码在线视频| 久久天堂夜夜一本婷婷| 欧美日韩国产的另类视频| 狠色婷婷久久一区二区三区| 深夜视频成人在线观看| 日本加勒比在线观看不卡| 国产精品白丝一区二区| 人妻亚洲一区二区三区| 成年午夜在线免费视频| 在线观看中文字幕91| 久热这里只有精品九九| 亚洲免费黄色高清在线观看| 91免费精品国自产拍偷拍| 亚洲国产欧美久久精品| 亚洲妇女作爱一区二区三区| 国产老女人性生活视频| 又色又爽又无遮挡的视频| 国产免费无遮挡精品视频| 亚洲熟女诱惑一区二区| 人妻一区二区三区在线| 日韩aa一区二区三区|