了解Linux裝置驅動程式異步通知應用和驅動的程式設計方法,優化按鍵中斷方式,使用異步通知方式編寫按鍵驅動程式。
一、實驗裝置與軟體環境
1、作業系統:Linux虛拟機、Red Hat Enterprise Linux 6.3。
2、硬體平台:FriendlyARM開發闆mini2440。
3、軟體:SecureCRT 8.1。
4、核心版本:linux 2.6.32.2。
二、具體操作過程
1.編寫代碼(分析代碼):button_fasync.c
(1)頭檔案
(2)open、write等函數
(3)file_operation結構體
(4)驅動函數初始化函數和解除安裝函數
流程:
(1)在/opt /shiyan目錄下建立lesson5_fasync檔案夾
①在/opt/shiyan目錄下右擊滑鼠打開終端;
②輸入“mkdir lesson5_fasync”,建立一個名為lesson5_fasync的檔案夾;
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyATN2EDOxETMxATOwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
(2)輸入“cd lesson5_fasync”指令,進入lesson5_fasync目錄下
(3)運作#gedit fasync.c
(4)編寫fasync.c代碼(源代碼見附錄1)
2. 進入lesson5_fasync目錄下執行gedit Makefile指令編寫Makefile檔案
3. 在lesson5_fasync目錄執行#make指令,生成fasync.ko檔案
4.将生成的fasync.ko檔案發送到開發闆上(注:fasync.ko檔案要複制到Windows上)
①打開window上的secureCRT軟體
②插上開發闆,與secureCRT連接配接(連接配接過程如圖所示)
③輸入“rz”指令,添加fasync.ko檔案
5. 在lesson5_fasync檔案夾下編寫測試應用程式(包括頭檔案、打開裝置、操作裝置等函數),命名為fasync_test.c(源代碼見附錄2)
6.運作#arm-linux-gcc fasync_test.c -o fasync_test生成名為fasync_test的檔案
7.将編譯生成的檔案fasync_test發送到開發闆上(流程與步驟4一樣)
8.在secureCRT上執行#chmod 777 fasync_test指令
9.加載驅動和解除安裝驅動
(1)加載驅動,運作#insmod fasync.ko
(2)檢視主裝置号 #cat /proc/devices
(3)創立節點 #mknod /dev/button_fasync c 253 0
10.執行./fasync_test指令,按下K5鍵,觀察實驗現象
三、操作過程中遇到的異常問題與解決方案
異常問題:在secureCRT上執行測試程式(./fasync_test)時,顯示該檔案無法找到,但是用ls指令可以看到該檔案存在。
解決方法:3.4.1的交叉編譯環境有問題,是以生成的test檔案是一個異常檔案,無法正常使用,我安裝了一個新的交叉編譯環境4.4.3後,所生成的test檔案就可以正常使用了,測試程式也可以正常執行。
異常問題:當執行./fasync_test指令之後,顯示“open error”(如圖所示),并沒有出現預期的效果。
解決方法:創立節點,執行mknod /dev/button_fasync c 253 0指令創立節點即可。
四、附錄
附錄1
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/device.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <mach/gpio-fns.h>
#include <mach/gpio-nrs.h>
#include<linux/sched.h>
#define DEVICE_NAME “button_fasync”
#define BUTTON_MAJOR 0
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static int press_cnt = 0;
static int ev_press = 0;
//static unsigned char key_val;
int major;
static struct fasync_struct *button_fasync;
static irqreturn_t button_interrupt(int irq, void *dev_id)
{
volatile int *press_cnt = (volatile int *)dev_id;
*press_cnt = *press_cnt + 1;
ev_press = 1;
wake_up_interruptible(&button_waitq);
kill_fasync(&button_fasync, SIGIO, POLL_IN); //發送信号SIGIO信号給fasync_struct 結構體所描述的PID,觸發應用程式的SIGIO信号處理函數
return IRQ_RETVAL(IRQ_HANDLED);
}
struct button_irq_desc {
int irq;
unsigned long flags;
char *name;
};
static struct button_irq_desc button_irqs = {
IRQ_EINT15, IRQF_TRIGGER_FALLING, “KEY5”
};
static int button_open(struct inode *inode, struct file *file)
{
int ret;
//request_irq(unsigned int irq,irq_handler_t handler,unsigned long flags,const char * name,void * dev);
ret=request_irq(button_irqs.irq,button_interrupt,button_irqs.flags,button_irqs.name,&press_cnt);
//if(ret)
if (ret)
{
free_irq(button_irqs.irq, &press_cnt);
return -EBUSY;
}
return 0;
}
static ssize_t
button_read(struct file *file, char __user *buf, size_t bytes, loff_t *off)
{
unsigned long err;
wait_event_interruptible(button_waitq, ev_press);
ev_press = 0;
err = copy_to_user(buf, &press_cnt,1);
memset(&press_cnt, 0, sizeof(press_cnt));
return err ? -EFAULT : 0;
//return 0;
}
static int button_close(struct inode *inode, struct file *file)
{
free_irq(button_irqs.irq, &press_cnt);
return 0;
}
static unsigned button_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
poll_wait(file, &button_waitq, wait);
if (ev_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}
static int button_fasync_function(int fd, struct file filp, int on)
{
return fasync_helper(fd, filp, on, &button_fasync);
}
/ File operations struct for character device */
static const struct file_operations buttons_fops = {
.owner = THIS_MODULE,
.open = button_open,
.read = button_read,
.release = button_close,
.poll = button_poll,
.fasync = button_fasync_function,
};
static int __init buttons_init(void)
{
int ret;
ret = register_chrdev(BUTTON_MAJOR, DEVICE_NAME, &buttons_fops);
if (ret < 0) {
printk(DEVICE_NAME " can’t register major number\n");
return ret;
}
printk(DEVICE_NAME " initialized\n");
return 0;
}
static void __exit buttons_exit(void)
{
unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME);
}
module_init(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE(“GPL”);
附錄2
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <signal.h>
#include <fcntl.h>
int fd;
void mysignal_fun(int signum)
{
unsigned char key_val;
read(fd,&key_val,1);
if(key_val)
printf(“K5 = %d\n”,key_val);
}
int main(int argc ,char *argv[])
{
int flag;
signal(SIGIO,mysignal_fun);
fd = open("/dev/button_fasync",O_RDWR);
if (fd < 0)
{
printf(“open error\n”);
}
fcntl(fd, F_SETOWN, getpid());
flag = fcntl(fd,F_GETFL);
fcntl(fd,F_SETFL,flag | FASYNC);
while(1)
{
sleep(1000);
}
return 0;
}