上一篇介紹了虛擬字符設(shè)備的驅(qū)動(dòng),這篇就深入學(xué)習(xí)字符驅(qū)動(dòng)的流程,看看字符驅(qū)動(dòng)和應(yīng)用層是怎么配合使用的!
1、備份原來的驅(qū)動(dòng)
2、修改原來的驅(qū)動(dòng)
在打印輸出時(shí),[BSP]開頭表示驅(qū)動(dòng),[APP]開頭表示應(yīng)用,Makefile不用修改;
chrdevbase.c
#include#include #include #include #include #include #define CHRDEVBASE_MAJOR 200 /* 主設(shè)備號(hào) */ #define CHRDEVBASE_NAME "chrdevbase" /* 設(shè)備名 */ static char readbuf[100]; /* 讀緩沖區(qū) */ static char writebuf[100]; /* 寫緩沖區(qū) */ static char kerneldata[] = {"kernel data!"}; /* * @description : 打開設(shè)備 * @param - inode : 傳遞給驅(qū)動(dòng)的inode * @param - filp : 設(shè)備文件,file結(jié)構(gòu)體有個(gè)叫做private_data的成員變量 * 一般在open的時(shí)候?qū)rivate_data指向設(shè)備結(jié)構(gòu)體。 * @return : 0 成功;其他 失敗 */ static int chrdevbase_open(struct inode *inode, struct file *filp) { //printk("chrdevbase open! "); return 0; } /* * @description : 從設(shè)備讀取數(shù)據(jù) * @param - filp : 要打開的設(shè)備文件(文件描述符) * @param - buf : 返回給用戶空間的數(shù)據(jù)緩沖區(qū) * @param - cnt : 要讀取的數(shù)據(jù)長度 * @param - offt : 相對于文件首地址的偏移 * @return : 讀取的字節(jié)數(shù),如果為負(fù)值,表示讀取失敗 */ static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { int retvalue = 0; /* 向用戶空間發(fā)送數(shù)據(jù) */ memcpy(readbuf, kerneldata, sizeof(kerneldata)); retvalue = copy_to_user(buf, readbuf, cnt); if(retvalue == 0){ printk("[BSP]kernel senddata ok! "); }else{ printk("[BSP]kernel senddata failed! "); } //printk("chrdevbase read! "); return 0; } /* * @description : 向設(shè)備寫數(shù)據(jù) * @param - filp : 設(shè)備文件,表示打開的文件描述符 * @param - buf : 要寫給設(shè)備寫入的數(shù)據(jù) * @param - cnt : 要寫入的數(shù)據(jù)長度 * @param - offt : 相對于文件首地址的偏移 * @return : 寫入的字節(jié)數(shù),如果為負(fù)值,表示寫入失敗 */ static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { int retvalue = 0; /* 接收用戶空間傳遞給內(nèi)核的數(shù)據(jù)并且打印出來 */ retvalue = copy_from_user(writebuf, buf, cnt); if(retvalue == 0){ printk("[BSP]kernel recevdata:%s ", writebuf); }else{ printk("[BSP]kernel recevdata failed! "); } //printk("chrdevbase write! "); return 0; } /* * @description : 關(guān)閉/釋放設(shè)備 * @param - filp : 要關(guān)閉的設(shè)備文件(文件描述符) * @return : 0 成功;其他 失敗 */ static int chrdevbase_release(struct inode *inode, struct file *filp) { //printk("chrdevbase release! "); return 0; } /* * 設(shè)備操作函數(shù)結(jié)構(gòu)體 */ static struct file_operations chrdevbase_fops = { .owner = THIS_MODULE, .open = chrdevbase_open, .read = chrdevbase_read, .write = chrdevbase_write, .release = chrdevbase_release, }; /* * @description : 驅(qū)動(dòng)入口函數(shù) * @param : 無 * @return : 0 成功;其他 失敗 */ static int __init chrdevbase_init(void) { int retvalue = 0; /* 注冊字符設(shè)備驅(qū)動(dòng) */ retvalue = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops); if(retvalue < 0){ printk("[BSP]chrdevbase driver register failed "); } printk("[BSP]chrdevbase init! "); return 0; } /* * @description : 驅(qū)動(dòng)出口函數(shù) * @param : 無 * @return : 無 */ static void __exit chrdevbase_exit(void) { /* 注銷字符設(shè)備驅(qū)動(dòng) */ unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME); printk("[BSP]chrdevbase exit! "); } /* * 將上面兩個(gè)函數(shù)指定為驅(qū)動(dòng)的入口和出口函數(shù) */ module_init(chrdevbase_init); module_exit(chrdevbase_exit); /* * LICENSE和作者信息 */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("zuozhongkai");
chrdevbaseApp.c
#include "stdio.h" #include "unistd.h" #include "sys/types.h" #include "sys/stat.h" #include "fcntl.h" #include "stdlib.h" #include "string.h" static char usrdata[] = {"usr data!"}; /* * @description : main主程序 * @param - argc : argv數(shù)組元素個(gè)數(shù) * @param - argv : 具體參數(shù) * @return : 0 成功;其他 失敗 */ int main(int argc, char *argv[]) { int fd, retvalue; char *filename; char readbuf[100], writebuf[100]; if(argc != 3){ printf("[APP]Error Usage! "); return -1; } filename = argv[1]; /* 打開驅(qū)動(dòng)文件 */ fd = open(filename, O_RDWR); if(fd < 0){ printf("[APP]Can't open file %s ", filename); return -1; } if(atoi(argv[2]) == 1){ /* 從驅(qū)動(dòng)文件讀取數(shù)據(jù) */ retvalue = read(fd, readbuf, 50); if(retvalue < 0){ printf("[APP]read file %s failed! ", filename); }else{ /* 讀取成功,打印出讀取成功的數(shù)據(jù) */ printf("[APP]read data:%s ",readbuf); } } if(atoi(argv[2]) == 2){ /* 向設(shè)備驅(qū)動(dòng)寫數(shù)據(jù) */ memcpy(writebuf, usrdata, sizeof(usrdata)); retvalue = write(fd, writebuf, 50); if(retvalue < 0){ printf("[APP]write file %s failed! ", filename); } } /* 關(guān)閉設(shè)備 */ retvalue = close(fd); if(retvalue < 0){ printf("[APP]Can't close file %s ", filename); return -1; } return 0; }
3、編譯驅(qū)動(dòng)和應(yīng)用
4、復(fù)制需要的文件到根文件系統(tǒng)中
將 chrdevbase.ko 和 chrdevbaseAPP 復(fù)制到 rootfs/lib/modules/4.1.15 目錄中:
5、啟動(dòng)內(nèi)核
在uboot界面輸入下面指令啟動(dòng)系統(tǒng),
tftp80800000zImage tftp 83000000 imx6ull-14x14-evk.dtb bootz 80800000 - 83000000
6、加載設(shè)備驅(qū)動(dòng)
需要進(jìn)入驅(qū)動(dòng)文件目錄才能加載設(shè)備驅(qū)動(dòng);
//加載驅(qū)動(dòng) insmod chrdevbase.ko // 查看驅(qū)動(dòng) lsmod // 指令查看devices 信息 cat /proc/devices
效果如圖:
7、創(chuàng)建設(shè)備節(jié)點(diǎn)文件
輸入如下命令創(chuàng)建/dev/chrdevbase 這個(gè)設(shè)備節(jié)點(diǎn)文件:
mknod /dev/chrdevbase c 200 0
8、驗(yàn)證讀寫
// 讀 ./chrdevbaseApp /dev/chrdevbase 1 // 寫 ./chrdevbaseApp /dev/chrdevbase 2 //可以使用下面這行輸出文件名稱,輸出/dev/chrdevbase printf("filename:%s ",argv[1]); //可以使用下面這行輸出參數(shù),輸出1或者 2 printf("dat:%d ",atoi(argv[2]);
讀的流程:
寫的流程:
注意事項(xiàng)
下面這個(gè)函數(shù)的打印輸出會(huì)印象到應(yīng)用層的輸出,看到應(yīng)用層輸出異常就把這個(gè)函數(shù)的輸出給屏蔽就好;
審核編輯:湯梓紅
-
字符
+關(guān)注
關(guān)注
0文章
232瀏覽量
25154 -
設(shè)備驅(qū)動(dòng)
+關(guān)注
關(guān)注
0文章
68瀏覽量
10872
原文標(biāo)題:i.MX6ULL|字符設(shè)備驅(qū)動(dòng)流程深究
文章出處:【微信號(hào):玩轉(zhuǎn)單片機(jī),微信公眾號(hào):玩轉(zhuǎn)單片機(jī)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論