linux裝置驅動編寫入門

澆築菜鳥發表於2021-07-08

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驅動模組可以通過insmodmodprobe命令載入模組。
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 -f

然後啟動開發板,執行載入命令

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

相關文章