linux設備驅動是什么,我個人的理解是liunx有用戶態和內核態,用戶空間中是不能直接對設備的外設進行使用而內核態中卻可以,這時我們需要在內核空間中將需要的外設驅動起來供用戶空間使用。linux的驅動主要分為字符設備、塊設備、和網絡設備三類,在分別驅動時需要注意一下,其中驅動不一定單屬於哪一類,一個驅動可能屬於多種分類。
一、准備材料
可以根據自己的需要准備相應材料,以下是我自己使用的:
開發環境:VMware
操作系統:ubuntu
開發版:湃兔i2S-6UB
二、下載linux內核源碼
1.ubuntu內核源碼的下載方式,直接通過命令下載即可,下載后源碼存放的地址在/usr/src
路徑下
sudo apt-get install linux-source
經過的測試好像ubuntu不需要下載源碼也是可以編寫驅動的,具體教程見后面內容。
2.湃兔核的內核源碼下載地址:http://i2som-zh.oss-cn-beijing.aliyuncs.com/i2SOM-iMX-Linux-706035a.tar.gz。
下載完成后解壓到開發環境的路徑下,具體路徑根據個人愛好。
三、編寫驅動
1.入口函數和出口函數
學習編程語言時,代碼都會有開始運行的位置,也就是我們所知的入口函數'mian()',同樣的原理linux驅動編寫也是有入口函數的,只是linux驅動比較特殊,函數基本都是成對存在的,有入口便有出口,所以linux存在入口函數和出口函數,如下所示
module_init(x) //入口函數
module_exit(x) //出口函數
留意過內核源碼的小伙伴都知道,入口和出口函數的定義是在liunx內核源碼中的include/linux/init.h
文件中,如下圖所示:
2.打印函數
linux的驅動中打印日志到控制台的函數和用戶空間的打印函數函數名不一樣,但是功能和使用方法差不多,linux內核的打印函數是printk()
。
打印函數的定義是在liunx內核源碼中的include/linux/printk.h
文件中,如下圖所示:
3.編寫hello.文件
創建一個hello的驅動文件夾,然后創建hello.c
文件,文件內容如下
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
static int __init hello_init(void)
{
printk("hello_init\r\n");
return 0;
}
static void __exit hello_exit(void)
{
printk("hello_exit\r\n");
}
/*
*模塊入口與出口函數
*/
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jiaozhu");
4.編寫Makefile文件
編寫完驅動程序后,需要創建Makefile文件,在這里需要注意x86和arm架構環境下的內容有所不同
x86架構下的Makefile內容如下所示
KERNELDIR := /lib/modules/5.8.0-59-generic/build
CURRENT_PATH := $(shell pwd)
obj-m := hello.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
注意:ubuntu的所需的內核源碼路徑在/lib/modules/5.8.0-59-generic/build
下
arm架構下的Makefile內容如下所示
KERNELDIR := /home/i2SOM-iMX-Linux
CURRENT_PATH := $(shell pwd)
obj-m := hello.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
注意:編寫arm架構的驅動是需要設置交叉編譯器,這里沒在Makefile文件中設置交叉編譯器的原因是我已經在源碼的頂層路徑Makefile文件中設置了。
5.編譯
完成hello.c文件和Makefile文件的編寫后,就可以進行編譯了,使用make
命令進行編譯,編譯完成完成后會生成.ko文件,如下圖所示:
到此驅動的編寫已經完成了,細心的小伙伴可能已經注意到我加載和卸載驅動時沒有日志輸出,具體原因我也不知道,在arm開發板中測試時是有日志輸出的。
四、測試
編譯完成后生成的hello.ko驅動模塊可以通過insmod
和modprobe
命令加載模塊。
1.ubuntu中使用modprobe
命令加載模塊時需要將.ko文件拷貝到/lib/modules/5.8.0-59-generic路徑下,然后在進行加載
sudo cp hello.ko /lib/modules/5.8.0-59-generic -f
sudo depmod
sudo modprobe hello
注意:/lib/modules/5.8.0-59-generic
具體的路路徑可能不一樣,可以進入/lib/modules/目錄下查看。
2.arm開發板中使用modprobe
命令加載模塊時需要將.ko文件拷貝到/lib/modules/路徑下,如果路徑不存在直接創建相應的路徑即可,arm一般測試方式都是通過nfs掛載根文件系統的形式進行測試。
在開發環境中將.ko文件拷貝至rootfs跟文件系統的/lib/modules路徑下
sudo cp hello.ko /home/rootfs/lib/modules/4.1.43 -f
注意:文件4.1.43是開發板內核的文件版本,不問版本的內核對應的文件不同
然后啟動開發板,執行加載命令
depmod
modprobe hello
3.查看加載的驅動和卸載驅動
在任意路徑下使用lsmod
命令即可查看驅動模塊,如下圖所示:
完成后可以通過rmmod hello
卸載驅動模塊,注意在ubuntu下可能需要通過root權限才能卸載。
到此我們簡單的驅動模塊已經編寫完成,有寫得不好的地方忘各位大佬支出。
參考文獻
【驅動】linux設備驅動·入門:https://www.cnblogs.com/lcw/p/3159386.html。
正點原子視屏教程:https://www.bilibili.com/video/BV1fJ411i7PB?p=3。