1、關於裝置驅動中的中斷問題
作業系統為了使得快速裝置和慢速裝置合適工作,需要中斷來提高效率,乙個外設要使用乙個中斷就必須註冊中斷號,獲得跟這個中斷號相關的一些資源,並且在中斷發生的時候核心可以進行一些處理,例如:呼叫中斷處理例程來真正的處理裝置中斷。linux處理中斷的方式很大程度上與它在使用者空間處理訊號的方式是一樣的。
我們知道,從本質上講,中斷處理例程會和其他**併發執行,這就會涉及到競態和併發的問題。
接下來我們就來講講有關中斷的實現和使用:
首先,我們需要註冊乙個中斷,可如下註冊,在
[cpp]view plain
copy
"font-size:18px;">int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const
char *name, void *dev)
引數說明:
第乙個引數:要申請的中斷號,主要看硬體的連線方式決定;
第二個引數:中斷處理例程,自己實現,在發生中斷的時候呼叫,稍候詳細說明;
第三個引數:中斷管理的標誌,是乙個位掩碼選項,例如可設定乙個中斷號在幾個裝置間共享,常見的就 是開發板上的adc和touch screen共享adc中斷;
第四個引數:用來標示中斷擁有者的名稱,可自己設定;
第五個引數:用於共享的中斷訊號線,稍候詳細說明。
呼叫request_irq的正確位置應該是裝置第一次開啟、硬體被告知產生中斷之前。
接下來,註冊後怎麼登出呢?呼叫如下函式即可:
[cpp]view plain
copy
"font-size:18px;">void free_irq(unsigned int irq, void *dev);
這裡引數的意義和上面是一樣的。
呼叫free_irq的位置應該是最後一次關閉裝置、硬體被告知不用再中斷處理器後。
有關中斷處理例程:
首先看看irq_handler_t的定義,顯然它應該是乙個自定義型別,定義在:include/linux/interrupt.h中:
[cpp]view plain
copy
"font-size:18px;">typedef irqreturn_t (*irq_handler_t)(int, void *);
確實是乙個型別定義,是乙個函式指標型別,指向的函式有兩個引數,乙個irqreturn_t型別的返回值,這也是乙個自定義型別,定義在include/linux/irqreturn.h中:
[cpp]view plain
copy
"font-size:18px;">typedef
enum irqreturn irqreturn_t;
確實是乙個自定義型別,看看typedef就知道了,而且是乙個列舉型別,接著看看這個列舉型別
[cpp]view plain
copy
"font-size:18px;">/**
* enum irqreturn
* @irq_none interrupt was not from this device
* @irq_handled interrupt was handled by this device
* @irq_wake_thread handler requests to wake the handler thread
*/enum irqreturn ;
這個列舉型別裡面的值代表著中斷處理例程的處理結果,也就是中斷程式的返回值。ok,這下就清除多了!
2、中斷處理的示例
這裡是友善之臂的按鍵裝置驅動程式,做了一些注釋,對比這上面的理論部分就比較好理解了。
[cpp]view plain
copy
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define device_name "buttons"
/*用於描述每個按鍵中斷的結構體*/
struct button_irq_desc ;
static
struct button_irq_desc button_irqs = ,
, ,
, ,
, ,
, };
static
volatile
char key_values = ;
/*涉及到中斷處理例程,所以就需要注意竟態和併發問題*/
static declare_wait_queue_head(button_waitq);
/*喚醒等待佇列的條件,可以是任意的布林表示式*/
static
volatile
int ev_press = 0;
/*中斷處理例程*/
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
/*判斷是否有按鍵按下*/
if (down != (key_values[number] & 1))
/*該返回值代表中斷確實真的處理了該中斷*/
return irq_retval(irq_handled);
} static
int s3c64xx_buttons_open(struct inode *inode, struct file *file)
/*申請中斷號*/
err = request_irq(button_irqs[i].irq, buttons_interrupt, irq_type_edge_both,
button_irqs[i].name, (void *)&button_irqs[i]);
if (err)
break;
} /*如果在申請中斷的時候發生錯誤,那麼就釋放掉已申請的中斷號*/
if (err)
disable_irq(button_irqs[i].irq);
free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
} return -ebusy;
} ev_press = 1;
return 0;
} static
int s3c64xx_buttons_close(struct inode *inode, struct file *file)
free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
} return 0;
} static
int s3c64xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
ev_press = 0;
err = copy_to_user((void *)buff, (const
void *)(&key_values), min(sizeof(key_values), count));
return err ? -efault : min(sizeof(key_values), count);
} /*用於輪詢操作*/
static unsigned int s3c64xx_buttons_poll( struct file *file, struct poll_table_struct *wait)
static
struct file_operations dev_fops = ;
/*定義misc裝置*/
static
struct miscdevice misc = ;
static
int __init dev_init(void)
static
void __exit dev_exit(void)
module_init(dev_init);
module_exit(dev_exit);
module_license("gpl");
module_author("friendlyarm inc.");
Linux 裝置驅動 中斷處理
為什麼需要中斷 1,外設的處理速度一般慢於 cpu 2,cpu 不能一直等待外部事件 所以裝置必須有一種方法來通知 cpu 它 的工作進度,這種方法就是中斷.在 linux 驅動程式中,為裝置實現乙個中斷包含兩個步驟 1,向核心註冊中斷 2,實現中斷處理函式 request irq 用於實現中斷的註...
字元裝置驅動之Buttons 中斷
buttons.c include include include include include include include include include include include include include static int major 0 static struct cla...
Linux裝置驅動 中斷處理筆記
1 外設的處理速度一般慢於cpu 2 cpu不能一直等外部事件 所以裝置必須有一種方法來通知cpu它的工作進度,這就是中斷。步驟 1 向核心註冊中斷 2 實現中斷處理函式 intrequest irq unsignedintirq,void handler int,void structpt reg...