(2)字元裝置驅動基本框架
阿新 • • 發佈:2021-02-09
技術標籤:Linux
- 參考正點原子視訊,做記錄以及簡單使用。
首先建立如下所示資料夾及檔案,檔案的內容如下三個所示。。。
/************************chrdevbase.c*****************/ #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #define MAJOR_NUMBER 200 const char* CHR_NAME = "chr_test"; static int chrtest_open(struct inode *inode,struct file *filp) { printk("chrtest_open !!!!\n"); return 0; } //filp:要開啟的裝置檔案(檔案描述符) //buf:返回給使用者空間的資料緩衝區 //cnt:要讀取的資料長度 //offt:相對於檔案首地址的偏移 //return:返回讀取到的位元組數 static ssize_t chrtest_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { printk("chrtest_read !!!!\n"); return 0; } static ssize_t chrtest_write(struct file *filp,const char __user *buf, size_t cnt, loff_t *offt) { printk("chrtest_write !!!!\n"); return 0; } static int chrtest_release(struct inode *inode, struct file *filp) { printk("chrtest_release !!!!\n"); return 0; } static struct file_operations test_fops = { //例項化一個函式結構體 .owner = THIS_MODULE, .open = chrtest_open, .read = chrtest_read, .write = chrtest_write, .release = chrtest_release, }; int xxx_init(void) //模組入口函式 { int retvalue = 0; retvalue = register_chrdev(MAJOR_NUMBER, CHR_NAME, &test_fops); //設備註冊 if(retvalue < 0){ printk("register failed!!!!\n"); //printf 執行在使用者態,printk 執行在核心態。 } else{ printk("register success!!!!\n"); } return 0; } void xxx_exit(void) //模組退出函式 { unregister_chrdev(200, CHR_NAME); //設備註銷 } module_init(xxx_init); module_exit(xxx_exit); MODULE_LICENSE("Dual BSD/GPL");
/************************Makefile*************************/ KERNELDIR := /usr/src/linux-headers-$(shell uname -r) #核心原始碼目錄 CURRENT_PATH := $(shell pwd) #shell指令碼執行pwd,得知當前位置 obj-m := chrdevbase.o #生成檔名 build: kernel_modules kernel_modules: $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules #表明編譯生成的是.ko模組檔案 clean: $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean #刪除生成檔案
/*********************chrdevApp.c*************************/ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int argc, char* argv[]) { int ret = 0; char* filename; char readbuf[10]; char writebuf[50]; int fd = 0; filename = argv[1]; //open(開啟的檔名,讀寫許可權); fd = open(filename,O_RDWR); //返回檔案描述符 O_RDWR表示讀寫模式 if(fd < 0){ //檔案開啟錯誤,返回<0 printf("canot open file %s \r\n", filename); return -1; } else{ printf(" open file %s sucess \r\n", filename); } ret = read (fd, readbuf, 50); //從open()開啟的fd檔案讀50個位元組 if(ret < 0){ printf("read file %s error !!!\n", filename); } else{ printf("read file %s success !!!\n", filename); } ret = write(fd,writebuf, 50);//將writebuf中的50個位元組寫到fd對應的檔案中 if(ret < 0){ printf("read file %s error !!!\n", filename); } else{ printf("read file %s success !!!\n", filename); } ret = close(fd);//關閉開啟的fd檔案 if(ret < 0){ printf("close file %s error !!!\n", filename); } else{ printf("close file %s success !!!\n", filename); } }
(https://mp.csdn.net/editor/html/113354613配合此連結的第一張圖起理解以下的4點)
- 首先第一個檔案chrdevbase.c, 此檔案通過make編譯生成chrdevbase.ko檔案,然後通過sudo insmod chrdevbase.ko載入模組,然後用lsmod即可看到載入了的chrdevbase模組,這個時候代表模組已經載入到核心空間,驅動載入成功。。可用dmesg看到在chrdevbase.c中列印的register success!!!!。然後用cat /proc/device即可看到一個名為200 chr_test的chardev裝置。
- 第二個檔案chrdevAPP.c,此檔案通過gcc chrdevApp.c -o chrdevApp生成可執行檔案chrdevApp。然後在手動建立一個裝置節點mknod /dev/chrdevbase c 200 0,(c:字元裝置 200:主裝置號 0:副裝置號)此時通過ls /dev/chrdevbase -l即可檢視裝置節點chrdevbase檔案。然後通過sudo ./chrdevApp /dev/chrdevbase代表執行chrdevApp,輸入引數/dev/chrdevbase.
- 執行之後,可看到列印的chrdevApp中的內容,表明對檔案的open file success等操作成功。而在用dmesg即可看到列印了chrtest_open等。。這表明chrdevbaseAPP 使用 read 函式從 chrdevbase 裝置讀取資料,因此chrdevbase_read 函式就會執行並列印chrtest_read。。。
- 按照圖來理解:使用者空間的程式呼叫open函式對chrdevbase裝置檔案進行操作,系統呼叫到核心,核心根據手動建立的裝置節點來找到chrdevbase裝置驅動程式,然後驅動程式根據我們在chrdevbase.c寫的read的函式來執行具體的操作。以上即為字元裝置從應用程式到驅動程式的基本框架。。