Linux字符設備驅動實例

globalmem
看 linux 設備驅動開發(fā)詳解時,字符設備驅動一章,寫的測試代碼和應用程序,加上自己的操作,對初學者我覺得非常有幫助。
寫這篇文章的原因是因為我看了我之前發(fā)表的文章,還沒有寫過字符設備相關的,至于里面提到的結構體的作用,有很多詳細的文章說明,我就不做更深的敘述。
代碼在github上,點擊下面閱讀原文可以直達
https://github.com/weiqifa0/globalmem/blob/main/README.md
把這部分放在github上也有好處,后續(xù)可以增加刪除一些東西,以后自己需要使用的時候也方便許多。
我們討論字符設備驅動,就有必要知道他的結構體和頭文件,像一些后來的封裝什么的,大部分還是脫離不了操作這個結構體里面的東西。
/*?SPDX-License-Identifier:?GPL-2.0?*/
#ifndef?_LINUX_CDEV_H
#define?_LINUX_CDEV_H
#include?
#include?
#include?
#include?
struct?file_operations;
struct?inode;
struct?module;
struct?cdev?{
?struct?kobject?kobj; /*內嵌kobject結構體,方便以后應用,也會在sys下生成相關設備文件*/
?struct?module?*owner;/*所屬于的模塊,正常就是本模塊THIS_MODULE*/
?const?struct?file_operations?*ops;/*文件的操作結構體,設備也是一個文件*/
?struct?list_head?list;/*字符設備的鏈表頭*/
?dev_t?dev;/*設備號*/
?unsigned?int?count;
}?__randomize_layout;/*初始化cdev,并建立和file_operation的聯(lián)系*/
void?cdev_init(struct?cdev?*,?const?struct?file_operations?*);
/*申請cdev內存*/
struct?cdev?*cdev_alloc(void);
void?cdev_put(struct?cdev?*p);
int?cdev_add(struct?cdev?*,?dev_t,?unsigned);
void?cdev_set_parent(struct?cdev?*p,?struct?kobject?*kobj);
int?cdev_device_add(struct?cdev?*cdev,?struct?device?*dev);
void?cdev_device_del(struct?cdev?*cdev,?struct?device?*dev);
void?cdev_del(struct?cdev?*);
void?cd_forget(struct?inode?*);
#endif
加載內核模塊insmod globalmem.ko 錯誤需要的修改。
insmod: can't insert 'globalmem.ko': Device or resource busy
出錯的原因:
模塊使用的是靜態(tài)分配設備號的方式,而這個設備號已經被系統(tǒng)中的其他設備所占用。查看未被占用的設備號,需要到pro/devices下面去查看。
查看設備號的方法:
# cat /proc/devices
編譯內核版本
#uname?-a
Linux?bsp-ubuntu1804?4.15.0-117-generic?#118-Ubuntu?SMP?Fri?Sep?4?20:02:41?UTC?2020?x86_64?x86_64?x86_64?GNU/Linux
加載模塊之后使用lsmod查看模塊
weiqifa@bsp-ubuntu1804:~/c/globalmem$?sudo?insmod?globalmem.koweiqifa@bsp-ubuntu1804:~/c/globalmem$?lsmod?|grep?global
globalmem??????????????16384??0
weiqifa@bsp-ubuntu1804:~/c/globalmem$
weiqifa@bsp-ubuntu1804:~/c/globalmem$?cat?/proc/devices?|grep?global
230?globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$
創(chuàng)建設備文件節(jié)點
使用mknod創(chuàng)建設備節(jié)點的時候,后面跟上的參數需要跟我們在/proc/devices下面看到的對應,也就是我們在驅動里面申請的主設備號。
weiqifa@bsp-ubuntu1804:~/c/globalmem$?sudo?mknod?/dev/globalmem?c?230?0
weiqifa@bsp-ubuntu1804:~/c/globalmem$?ls?/dev/globalmem?-al
crw-r--r--?1?root?root?230,?0?Dec?22?16:19?/dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$
使用命令讀寫設備文件
Linux 下的 echo 和cat 命令是十分有用,這兩個命令可以讓在不寫代碼的情況下就可以完成調試讀寫設備。
weiqifa@bsp-ubuntu1804:~/c/globalmem$?sudo?chmod?777?/dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$?sudo?echo?"linux"?>?/dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$?cat?/dev/globalmem
linux
cat:?/dev/globalmem:?No?such?device?or?address
weiqifa@bsp-ubuntu1804:~/c/globalmem$?cat?/dev/globalmem
linux
cat:?/dev/globalmem:?No?such?device?or?address
weiqifa@bsp-ubuntu1804:~/c/globalmem$?sudo?echo?"linuxgdb"?>?/dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$?cat?/dev/globalmem
linuxgdb
cat:?/dev/globalmem:?No?such?device?or?address
weiqifa@bsp-ubuntu1804:~/c/globalmem$
通過代碼來讀寫設備文件
代碼在下面閱讀原文的鏈接里面。
weiqifa@bsp-ubuntu1804:~/c/globalmem$?gcc?app-main.c?&&?./a.out
str:LINUX,GDB
weiqifa@bsp-ubuntu1804:~/c/globalmem$
使用傳入參數設置主設備號
內核模塊參數我覺得是一個比較冷門的知識點,冷門的原因是因為我們在做項目的時候很少使用這個參數,但是實際上這個參數非常有用。
我們可以把內核模塊當做main函數,main函數是可以接收傳參的,內核模塊也可以在加載的時候接收傳入的參數。
如下是把主設備號傳給內核模塊,但是需要注意,這個主設備號不能被占用了。
weiqifa@bsp-ubuntu1804:~/c/globalmem$?sudo?insmod?globalmem.ko?globalmem_major=231
weiqifa@bsp-ubuntu1804:~/c/globalmem$?cat?/proc/devices?|grep?globalmem
231?globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$
增加自動創(chuàng)建設備節(jié)點的驅動文件
每次手動創(chuàng)建設備文件節(jié)點總是很麻煩,而且在實際編寫設備驅動的時候,不會出現自己手動創(chuàng)建設備節(jié)點這種低端的操作。
當然了,聰明的內核提供了接口讓我們在注冊驅動的時候也把設備文件節(jié)點注冊上去。
具體代碼可以查看globalmem2.c里面的代碼。
weiqifa@bsp-ubuntu1804:~/c/globalmem$?chmod?777?globalmem.ko
weiqifa@bsp-ubuntu1804:~/c/globalmem$?sudo?insmod?globalmem.ko
[sudo]?password?for?weiqifa:
weiqifa@bsp-ubuntu1804:~/c/globalmem$?ls?/dev/globalmem
/dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$?ls?/dev/globalmem?-al
crw-------?1?root?root?238,?0?Dec?22?17:18?/dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$
/*修改權限后才可以正常進行獨寫操作*/
weiqifa@bsp-ubuntu1804:~/c/globalmem$?sudo?chmod?777?/dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$?gcc?app-main.c?&&?./a.out
write?data?ok!
str:LINUX,GDB
weiqifa@bsp-ubuntu1804:~/c/globalmem$
使用lseek操作文件位置
具體對應的文件是app-main2.c
weiqifa@bsp-ubuntu1804:~/c/globalmem$?gcc?app-main2.c?&&?./a.out
file?ret:0
write?data?ok!?fd:3
str:123456789ABCDEF10111213141516171819201617181920
lseek:1
str:23456789ABCDEF10111213141516171819201617181920
weiqifa@bsp-ubuntu1804:~/c/globalmem$

