這裏主要是仿照《嵌入式Linux開發完全手冊》 上的例子寫的,下載見http://www.linuxidc.com/Linux/2011-01/31114.htm ,只是增加了別外兩個按按鍵。在我的mini2440開發板上有6個按鍵。在上兩篇文章中,主要分析了驅動中的整體的流程,現在來看一個具體的例子,是如何使用中斷的。
1. 模塊的初始化函數和卸載函數
/* 執行"insmod mini2440_buttons.ko"命令時就會調用這個函數*/ static int __init mini2440_buttons_init (void) {
int ret; /*這裏主要是註冊設備驅動程序,參數爲主設備號,如果BUTTON_MAJOR設爲0,表示由內核自動分配主設備號,設備的名字,file_operations結構,操作主調和號爲BUTTON_MAJOR的設備文件時,就會調用mini2440_buttons_fops中的相關成員函數*/
ret = register_chrdev(BUTTON_MAJOR,DEVICE_NAME,&mini2440_buttons_fops);
if(ret < 0)
{
printk(DEVICE_NAME "can't register major number\n");
return ret ;
}
printk(DEVICE_NAME"initialized\n");
return 0; } /* 執行 rmmod mini2440_buttons.ko0 命令時就會調用這個函數 */ static void __exit mini2440_buttons_exit(void) {//卸載驅動程序
unregister_chrdev(BUTTON_MAJOR,DEVICE_NAME); } //指定驅動程序的初始化函數和卸載函數
module_init(mini2440_buttons_init);
module_exit(mini2440_buttons_exit);
|
下面這個結構體是每一個字符驅動程序都是要用到的。這裏定義了應用程序可以使用的設備操作函數,只有在這個結構體中的函數,在應用程序中才可以使用,在下面的驅動程序中要實現下面的函數。
/* 這個結構是字符設備驅動程序的核心,當應用程序操作設備文件時所調用的open,read,write等函數,最終會調用這個結構中的對應函數*/ static struct file_operations mini2440_buttons_fops =
{
.owner = THIS_MODULE, //這是 個宏,指向編譯模塊時自動創建的_this_module變量
.open = mini2440_buttons_open,
.release = mini2440_buttons_close,
.read = mini2440_buttons_read,
};
|
2. mini2440_buttons_open函數
在應用程序執行“open("/dev/buttons",..)"系統調用時,mini2440_buttons_open函數將被調用。這用來註冊6個按鍵的中斷處理程序
static int mini2440_buttons_open(struct inode *inode,struct file *file) {
int i;
int err;
for (i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++)
{ //註冊中斷處理函數 一共六個
err = request_irq(button_irqs[i].irq,buttons_interrupt,button_irqs[i].flags,button_irqs[i].name,(void *)&press_cnt[i]);
if (err)
break;
}
if(err) //出錯處理函數,如果出錯釋放已經註冊的中斷
{
i--;
for(;i>=0;i--)
free_irq(button_irqs[i].irq,(void *)&press_cnt[i]);
return -EBUSY;
}
return 0; }
|
requst_irq函數執行成功後,這6個按鍵所用的GPIO引腳的功能被設爲外部中斷,觸發方式爲下降沿觸發,中斷處理函數爲buttons_interrupt.最後一個參數“(void *)&press_cnt[i]”將在buttons_interrupt函數中用到,它用來
存儲按鍵被按下的次數。參數button_irqs的定義如下:
struct button_irq_desc {
int irq;//中斷號
unsigned long flags; //中斷標誌,用來定義中斷的觸發方式
char *name; //中斷名稱 };
static struct button_irq_desc button_irqs[] =
{ //下面是按鍵對應的外部的中斷號,觸發方式,名稱
{IRQ_EINT8,IRQF_TRIGGER_FALLING,"KEY0"},
{IRQ_EINT11,IRQF_TRIGGER_FALLING,"KEY1"},
{IRQ_EINT13,IRQF_TRIGGER_FALLING,"KEY2"},
{IRQ_EINT14,IRQF_TRIGGER_FALLING,"KEY3"},
{IRQ_EINT15,IRQF_TRIGGER_FALLING,"KEY4"},
{IRQ_EINT19,IRQF_TRIGGER_FALLING,"KEY5"},
};
|
3. mini2440_buttons_close函數
mini2440_buttons_close函數的作用是用來卸載6個按鍵的中斷處理函數代碼如下:
/* 應用程序對設備文件/dev/buttons執行close(...)時。就會調用mini2440_buttons_close函數*/ static int mini2440_buttons_close(struct inode *inode,struct file *file) {
int i;
for(i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++)
{ //釋放已註冊的函數
free_irq(button_irqs[i].irq,(void *)&press_cnt[i]);
}
return 0; }
|
4. mini2440_buttons_read函數
中斷處理函數會在press_cnt數組中記錄按鍵被按下的次數。mini_buttons_read函數,首先判斷是否按鍵再次按下,如果沒有則休眠;否則讀取press_cnt數組的數據,
/*等待隊列:
當沒有按鍵被按下時,如果有進程調用mini2440_buttons_read函數,它將休眠*/ static DECLARE_WAIT_QUEUE_HEAD(button_waitq); /*中斷事件標誌,中斷服務程序將它置1,mini2440_buttons_read將它清0*/ static volatile int ev_press = 0; /*應用程序對設備文件/dev/buttons執行read(...)時,就會調用mini2440_buttons_read函數*/ static int mini2440_buttons_read(struct file *filp,char __user *buff,size_t count,loff_t *offp) {
unsigned long err;
//如果ev_press等於0,休眠
wait_event_interruptible(button_waitq,ev_press);
ev_press = 0;// 執行到這裏是ev_press肯定是1,將它清0
//將按鍵狀態複製給用戶,並清0
err = copy_to_user(buff,(const void *)press_cnt,min(sizeof(press_cnt),count));
memset((void *)press_cnt,0,sizeof(press_cnt));
return err ? -EFAULT:0; }
|