前一段時間專案忙,中斷了更新。
要想提高能力,最重要的還是實際動手寫**,這樣才能遇到一些問題,解決問題增加經驗。
今天介紹的功能是: 在linux中新增乙個button驅動,按鍵控制led燈亮滅,並且支援應用程式讀取按鍵事件。
下面根據**來一點一點介紹:
1、列出我們定義的資料結構以及全域性變數:
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define device_name "my_buttons"
/*button 中斷描述*/
struct button_irq_dec;
/*事件結構,應用程式中要與此結構一致,上報按鍵訊息時直接把該結構體copy到使用者空間*/
struct uevent;
static list_head(button_list);// 訊息佇列
static declare_wait_queue_head(button_waitq); // 等待佇列頭
static define_mutex(button_mtx); // 鎖
/*中斷訊息,裡面包含上報應用程式的event,以及維護的鍊錶和工作佇列*/
struct message;
/*預先定義好的buttom中斷描述*/
struct button_irq_dec button_irqs = ,,,
,,,,
,};
2、模組初始化函式
static struct file_operations dev_fops = ;
static struct miscdevice misc = ;
static int __init dev_init(void)
/*irq_type_edge_both 邊沿觸發
中斷處理函式: buttons_interrupt 引數:&button_irqs[i]
*/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;
}ret = misc_register(&misc);
printk (device_name"\tinitialized\n");
return ret;
}
當中斷產生時,就會呼叫到button_interrupt函式。
3、button_interrupt函式
static irqreturn_t buttons_interrupt(int irq, void* pram)
//處理按鍵訊息,獲取按鍵號對應的狀態:down or up
switch(number)
/*申請乙個msg空間,並填充其中的event,然後呼叫工作佇列*/
msg = (struct message *)kmalloc(sizeof(struct message), gfp_atomic);
if(msg != null)
return irq_retval(irq_handled);
}
上面的中斷函式使用工作佇列的原因是:新建乙個message,填充好event後,要新增到button_list中,但是在read函式中要把該鍊錶的event返回到應用程式,所以要加鎖控制同步,在中斷程式中不能呼叫加鎖函式(因為會導致睡眠),所以此處使用工作佇列。
工作佇列的使用:init_work中只設定了函式位址,而函式的引數是work_struct物件位址。所以要把工作佇列定義在message結構體中,這樣在工作佇列的函式中可以通過contain_of來獲取我們要傳遞的引數。
add_message函式:
static void add_message(struct work_struct * pram)
到這裡,按鍵中斷的處理以及返回給應用程式的按鍵訊息已經封裝好了,下面來看read函式的實現。
4、read函式
static ssize_t button_message_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
else
/*返回整數個struct uevent結構體*/
number = count / (sizeof(struct uevent));
mutex_lock(&button_mtx);
/*遍歷鍊錶,獲取每個event*/
list_for_each_entry_reverse(msg, &button_list, list)
/*把event copy到使用者空間*/
counts = copy_to_user(buf + (i *(sizeof(struct uevent))), &msg->event, sizeof(struct uevent));
pre = msg;
i++;
if(i == number)
break;
}if(pre != null)
mutex_unlock(&button_mtx);
if(is_wait)
return number*(sizeof(struct uevent));
}
這樣,驅動的主要函式都已經實現了,下面就列出應用程式如何來完成。
5、應用程式**
#include #include #include #include #include #include #include struct uevent;
int main()
while(1)
close(fd);
}
6、**的編譯
驅動的makefile檔案:
kerneldir:=/work/tiny6410/linux/linux-2.6.38 //這是我的kernel**位置
pwd:=$(shell pwd)
obj-m:=button.o
all:
make -c $(kerneldir) m=$(pwd) modules
clean:
rm -rf *.o *.ko
應用程式的編譯:
arm-linux-gcc test.c -omain
本人所有文章目錄:
Tiny6410 buttons c 按鍵驅動程式
最近一直在找帶中斷的led驅動程式先貼出來方便自己複習。tiny6410 buttons xyl.c 引用的標頭檔案 include 模組有關的 include 核心有關的 include 檔案系統有關的 include include include include include 中斷 incl...
tiny6410 按鍵中斷驅動 poll機制
驅動程式key drv int.c include include include include include include include include include include include include include include include include incl...
Tiny6410學習 Linux命令
今天再來記錄一下一些非常常用的linux基礎命令知識,以備後期來查。1.新增使用者 useradd smb 新增名字為smb的使用者 2.修改密碼 passwd smb 修改smb使用者的密碼 3.切換使用者 su root 切換到root使用者,並將root環境變數同時帶入 就是管理員賬號了,也就...