天天看點

LINUX中斷學習筆記【轉】

1.中斷的注冊與釋放:

在 , 實作中斷注冊接口:

int request_irq(unsigned int irq,irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *dev_name,void *dev_id); 

void free_irq(unsigned int irq, void *dev_id);

函數參數說明

unsigned int irq:所要注冊的中斷号

irqreturn_t (*handler)(int, void *, struct pt_regs *):中斷服務程式的入口位址。

unsigned long flags:與中斷管理有關的位掩碼選項,有三組值:

1. SA_INTERRUPT :快速中斷處理程式,當使用它的是後處理器上所有的其他中斷都被禁用。

2. SA_SHIRQ :該中斷是在裝置之間可共享的

3. SA_SAMPLE_RANDOM :這個位表示産生的中斷能夠有貢獻給 /dev/random 

和 /dev/urandom 使用的加密池.(此處不了解) 

const char *dev_name:裝置描述,表示那一個裝置在使用這個中斷。

void *dev_id:用作共享中斷線的指針. 它是一個獨特的辨別, 用在當釋放中斷線時以及可能還被驅動用來指向它自己的私有資料區(來辨別哪個裝置在中斷) 。這個參數在真正的驅動程式中一般是指向裝置資料結構的指針.在調用中斷處理程式的時候它就會傳遞給中斷處理程式的void *dev_id。(這是我的了解)如果中斷沒有被共享, dev_id 可以設定為 NULL, 但是使用這個項指向裝置結構不管如何是個好主意. 我們将在"實作一個處理"一節中看到 dev_id 的一個實際應用。

中斷号的檢視可以使用下面的指令:“cat /proc/interrupts”。

/proc/stat 記錄了幾個關于系統活動的低級統計量, 包括(但是不限于)自系統啟動以來收到的中斷數. stat 的每一行以一個文本字串開始, 是該行的關鍵詞; intr 标志是我們在找的.

第一個數是所有中斷的總數, 而其他每一個代表一個單個 IRQ 線, 從中斷 0 開始. 所有的計數跨系統中所有處理器而彙總的. 這個快照顯示, 中斷号 4 已使用 1 次, 盡管目前沒有安裝處理. 如果你在測試的驅動請求并釋放中斷在每個打開和關閉循環, 你可能發現 /proc/stat 比 /proc/interrupts 更加有用.

以下是一個統計中斷時間間隔的中斷服務程式。

irqreturn_t short_interrupt(int irq, void *dev_id, struct pt_regs *regs)

{

static long mytime=0;

static int i=0;

struct net_device *dev=(struct net_device *)dev_id;

if(i==0){

mytime=jiffies;

}else

if(i<20){ 

mytime =jiffies- mytime;

printk("Request on IRQ %d time %d\n",irq , mytime);

printk("Interrupt on %s -----%d \n",dev->name,dev->irq);

}

i++;

return IRQ_HANDLED;

這個函數實作的隻是對兩次發生中斷的時間間隔的統計,時間機關是毫秒

函數參數說明:int irq :在這裡很明顯傳遞過來的是中斷号 

void *dev_id :這個傳遞來的是裝置的id号,可以根據這個裝置id号得到相應裝置的資料結構,進而的到相應裝置的資訊和相關資料。下面以提取網路資料為例來說明一下。

struct net_device *dev=( struct net_device *)dev_id; (這裡的dev_id的值是注冊中斷的時候宏傳遞過來的,是注冊中斷函數的最後一個參數。特别說明)

在這之後就可以用dev->name; dev->irq;等得到網絡裝置的資訊了,當然提取ip資料報還得進行一些其它的工作。

struct pt_regs *regs :它指向一個資料結構,此結構儲存的是中斷之前處理器的寄存器和狀态。主要用在程式調試。

關于中斷處理函數的傳回值:中斷程式的傳回值是一個特殊類型—irqreturn_t。但是中斷程式的傳回值卻隻有兩個—IRQ_NONE和IRQ_HANDLED。

/* irqreturn.h */

#ifndef _LINUX_IRQRETURN_H

#define _LINUX_IRQRETURN_H

typedef int irqreturn_t;

/*

* For 2.4.x compatibility, 2.4.x can use

*

* typedef void irqreturn_t;

* #define IRQ_NONE

* #define IRQ_HANDLED

* #define IRQ_RETVAL(x)

*……此處我删去了部分關緊要的内容

* To mix old-style and new-style irq handler returns.

* IRQ_NONE means we didn't handle it. 

* 中斷程式接收到中斷信号後發現這并不是注冊時指定的中斷原發出的中斷信号.

*此時傳回次值

* IRQ_HANDLED means that we did have a valid interrupt and handled it.

* 接收到了準确的中斷信号,并且作了相應正确的處理

* IRQ_RETVAL(x) selects on the two depending on x being non-zero (for handled)

*/

#define IRQ_NONE (0)

#define IRQ_HANDLED (1)

#define IRQ_RETVAL(x) ((x) != 0) //這個宏隻是傳回0或非0

#endif

以上是在linux/irqreturn.h中的内容,我加了一定的注釋.我想是可以說明問題的

編寫中斷處理程式:

中斷處理程式聲明:

static irqreturn_t intr_handler(int irq, void *dev_id, struct pt_regs *regs)

說明:

該類型與request_irq()參數中的handler所要求的參數類型相比對。

int irq :中斷号;

void *dev_id :與request_irq()的參數dev_id一緻,可以根據這個裝置id号得到相應裝置的資料結構,進而的到相應裝置的資訊和相關資料;

struct pt_regs *regs :它指向一個資料結構,此結構儲存的是中斷之前處理器的寄存器和狀态。主要用在程式調試,一般忽略。

傳回值:中斷程式的傳回值是一個特殊類型——irqreturn_t。但是中斷程式的傳回值卻隻有兩個值IRQ_NONE和IRQ_HANDLED。

    IRQ_NONE:中斷程式接收到中斷信号後發現這并不是注冊時指定的中斷原發出的中斷信号;

    IRQ_HANDLED:接收到了準确的中斷信号,并且作了相應正确的處理。

亦可以使用宏IRQ_RETVAL(x),若x為非0值,該宏傳回IRQ_HANDLED,否則傳回IRQ_NONE。

檢視中斷号:

指令:cat /proc/interrupts

============================================================================

在 2.4 核心和 2.6核心中都使用 request_irq() 函數來注冊中斷服務函數。在 2.4 核心中,需要包含的頭檔案是 #include ,2.6 核心中需要包含的頭檔案則是

 #include 。函數原型如下:

2.4 核心

int request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long frags, const char *device, void *dev_id);

2.6 核心

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);

參數說明:

在發生對應于第 1個參數 irq 的中斷時,則調用第 2 個參數 handler 指定的中斷服務函數(也就是把 handler() 中斷服務函數注冊到核心中 )。

第 3 個參數 flags 指定了快速中斷或中斷共享等中斷處理屬性。在 2.6 教新的核心裡(我的是 2.6.27 ~ 2.6.31 ),在 linux/interrupt.h 中定義操作這個參數的宏如下:

引用 * These flags used only by the kernel as part of the * irq handling routines. * IRQF_DISABLED - keep irqs disabled when calling the action handler * IRQF_SAMPLE_RANDOM - irq is used to feed the random generator * IRQF_SHARED - allow sharing the irq among several devices * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur * IRQF_TIMER - Flag to mark this interrupt as timer interrupt * IRQF_PERCPU - Interrupt is per cpu * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is *                registered first in an shared interrupt is considered for *                performance reasons) #define IRQF_DISABLED           0x00000020 #define IRQF_SAMPLE_RANDOM      0x00000040 #define IRQF_SHARED             0x00000080 #define IRQF_PROBE_SHARED       0x00000100 #define IRQF_TIMER              0x00000200 #define IRQF_PERCPU             0x00000400 #define IRQF_NOBALANCING        0x00000800 #define IRQF_IRQPOLL            0x00001000

早期一點的 2.6 核心這裡一般以 SA_ 字首開頭,如:

SA_INTERRUPT   表示禁止其他中斷;(對應于 IRQF_DISABLED )

SA_SHIRQ             表示共享相同的中斷号 (對應于 IRQF_SHARED )

SA_SAMPLE_RANDOM   此宏會影響到 RANDOM 的處理( 對應于 IRQF_SAMPLE_RANDOM )。

第 4 個參數 name 通常是裝置驅動程式的名稱。改值用在 /proc/interrupt 系統 (虛拟) 檔案上,或核心發生中斷錯誤時使用。

第 5 個參數 dev_id 可作為共享中斷時的中斷差別參數,也可以用來指定中斷服務函數需要參考的資料位址。

傳回值:

函數運作正常時傳回 0 ,否則傳回對應錯誤的負值。

示例代碼片段:

irqreturn_t xxx_interrupt (int irq, void *dev_id)         ...         return (IRQ_HANDLED); int xxx_open (struct inode *inode, struct file *filp)         if (!request_irq (XXX_IRQ, xxx_interruppt, IRQF_DISABLED, "xxx", NULL)) {                 /*正常注冊*/         }         return (0); 本文轉自張昺華-sky部落格園部落格,原文連結:http://www.cnblogs.com/sky-heaven/p/8036880.html,如需轉載請自行聯系原作者

繼續閱讀