Linux驅動簡介和開發流程
【學習筆記】
Linux 驅動的分類
Linux三大設備驅動
1、字符設備驅動
IO的傳輸程序是以字符為單位的,沒有緩沖,比如I2C,SPI都是字符設備
2、塊設備驅動
IO傳輸程序中是以塊為單位的,跟存盤相關的,都屬于塊設備,比如:tf卡
3、網路設備驅動
與前兩個不一樣,是以socket套接字來訪問的,
其中,理解和掌握字符設備驅動的概念最重要,因為在作業中我們遇到大部分都是字符設備
驅動的組成
驅動分為四個部分
(1)頭檔案
(2)驅動模塊的入口和出口
(3)宣告資訊
(4)功能實作
具體成分
第一步,包含頭檔案
include <linux/init.h> 包含了宏定義的頭檔案
include <linux/module.h> 包含了初始化加載模塊的頭檔案
第二步,驅動模塊的入口和出口
module_init();
module_exit();
第三步,生命模塊具有開源許可證
MODULE_LICENSE("GPL");
第四步,功能的實作
實體
簡單的helloworld驅動程式撰寫
/兩個必要的頭檔案
#include <linux/init.h>
#include <linux/module.h>
//內核加載的時候列印hello world,內核模塊卸載的時候列印bye bye
static int hello_init(void){
printk("hello world\n"); //內核里不能使用c語言庫,所以不能用printf
return 0;
}
static void hello_exit(void){
printk("bye bye\n");
}
//入口和出口
module_init(hello_init);
module_exit(hello_exit);
//宣告許可證
MODULE_LICENSE("GPL");
Linux驅動編譯成模塊
方法一
把驅動編譯成模塊,然后使用命令把驅動加載到內核里面,
步驟
1、編譯成模塊
(1)先寫一個makefile
在linux下
touch Makefile #創建Makefile檔案
obj-m +=HelloWorld.o #obj-m 意為把驅動編譯為模塊
KDIR:={core_path} #PATH根據開發板內核路徑來填寫
PWD?=$(shell pwd) #自動獲取當前位置路徑
all:
make -C $(KDIR) M=$(PWD) modules #切換到內核路徑,用make把代碼編譯成模塊
(2)編譯驅動
編譯驅動之前需要注意的問題:
-
內核原始碼一定要編譯通過
-
編譯驅動用的內核原始碼一定要和開發板上運行的內核鏡像是同一套
-
看一下開發代碼的ubuntu環境是不是arm,如果不是,要改成arm環境
查看環境的 方法
在內核原始碼的目錄下輸入
make menuconfig #顯示系統環境
#左上角如果顯示是X86,而不是arm,則輸入
export ARCH=arm #改為arm環境
為了以防萬一,編譯前,先命令列輸入兩行代碼,設定環境和編譯器
export ARCH=arm
export CROSS_COMPILE={編譯器名稱} #可以直接輸入arm查看
#如果查看到:arm-linux-gnueabihf-gcc-4.9.4
編譯成功后就可以看到 ko 檔案了,這個 ko 檔案就是編譯好的驅動,

在開發板上加載驅動用insmod
insmod HelloWorld.ko
查看加載的模塊,使用lsmod命令
lsmod
卸載驅動模塊
rmmod HelloWorld #注意這里沒有后綴
卸載時,如果提示沒有相應的目錄,直接在對應的目錄下創建就可以了
方法二
直接把驅動編譯到內核,
在下面有實際的例子,
移植
如果芯片的內核不支持設備的驅動,那么就需要把這個驅動移植到內核,
移植驅動需要驅動原始碼和makefile,
移植需求分析
(1)先去內核原始碼搜索,如果有的話,可以直接選擇這個驅動,然后直接使用,
(2)假如沒有這個驅動,則許喲啊自己編譯一個驅動,然后加載到內核里邊去運行,
make menuconfig 圖形化配置
1、如何進入make menuconfig圖形化配置
首先進入到內核原始碼的路徑下,然后輸入make menuconfig 即可打開這個界面,
2、make menuconfig圖形化界面的操作
(1)搜索功能
輸入“/”即可彈出搜索界面
(2)配置驅動狀態
-
把驅動編譯成模塊(用[ M ]來表示)
-
把驅動編譯到內核里(用[ * ]來表示)
-
不編譯(用[ ]來表示)
可以使用“空格”鍵來配置這三種不同的狀態
(3)如何退出
分為保存退出和不保存退出,按照提示選擇即可
(4)和make menuconfig 有關的檔案
Makefile:里邊是編譯規則,高速我們在make的時候需要如何編譯(相當于菜的做法)
Kconfig:內核配置的選項(相當于服務員給的選單)
.config:配置完內核以后生成的配置選項(相當于我門勾選的選單)
(5)make menuconfig會讀取不同環境目錄下的Kconfig檔案
會讀取Arch/$ARCH/目錄下(目錄下有很多不同的環境檔案夾)的Kconfig檔案(選擇不同的環境,和export ARCH=arm效果類似),
/arch/arm/configs 下面有很多組態檔(相當于特色菜,默認配置,在不知道如何配置的時候可以按照這個來),如果移植內核的時候,組態檔太多,就可以把這個檔案夾下面的配置復制成.config里邊(即默認系統的配置)【復制用cp命令】
(6)為什么要復制成.config,而不是其他名字
因為內核會默認讀取Linux內核根目錄下的.config作為默認的配置選項,所以不可以改名字
(7)如果復制的默認配置.config不滿足我們的要求,如何解決
直接輸入make menuconfig,進入Kconfig配置界面,來進行修改配置,保存退出,配置會自動更新到.config里面,
(8)組態檔選項怎樣和Makefile檔案建立聯系
當make menuconfig保存退出以后,Linux會將所有的配置選項以宏定義的形式保存在include/generated/下面的autoconf.h頭檔案中,
把驅動編譯到內核
Kconfig代碼例子
#例子
source "drivers/redled/Kconfig"
config LED_4412
tristate "Led Support for GPIO Led"
depends on LEDS_CLASS
help
This option enable support for led
#解讀
source "drivers/redled/Kconfig"#會讓config選單里邊包含drivers/redled/這個路徑下的驅動檔案,方便我們對選單進行管理
config LED_4412 #配置選項的名稱,全名是CONFIG_LED_4412,這里做了一些省略
tristate "Led Support for GPIO Led"
#tristate表示驅動的狀態:1.把驅動編譯成模塊 2.把驅動編譯到內核 3.不編譯,與之對用的還有bool關鍵字:表示編譯到內核,和不編譯兩種狀態,
#"Led Support for GPIO Led"是make menuconfig里邊的某個選單的名字
depends on LEDS_CLASS
# A depends on B表示只有在選擇B的時候才可以選擇A,即A依賴于B,
#比如想要去掉LED相關的驅動,我們雖然可以直接改.config檔案,但是不推薦這樣做,因為如果有依賴項的話,直接改.config檔案是不成功的,
#select:反向依賴,該選項被選中時,后面的定義也會被選中,
help
This option enable support for led #顯示幫助資訊
實體
把HelloWorld驅動編譯到內核,
(1)首先進入到內核原始碼的目錄下(內核根目錄)
(2)把HelloWorld.c驅動,復制到drivers/char/hello檔案夾【char一般就是放字符設備的檔案夾,hello檔案夾使用mkdir命令創建】
(3)寫Kconfig檔案
mkdir hello #創建hello檔案夾
cd hello/ #切換到hello檔案夾
cp /home/pyma/HelloWorld.c #把驅動檔案復制到hello檔案夾中
touch Kconfig #創建一個Kconfig檔案
vi Kconfig #打開Kconfig進行編輯
#寫程式
config HELLO #起個名字叫HELLO
tristate "hello world" #選擇三種狀態的方式,并把選單名字命名為hello world
#過于簡單沒有依賴,不用寫
help
hello help #幫助資訊為hello help
保存退出
(4)寫Makefile檔案
touch Makefile #創建Makefile檔案夾
vi Makefile #打開Makefile編輯
#寫程式
obj-$(CONFIG_HELLO)+=HelloWorld.o
CONFIG_HELLO這個變數名字來源:是剛剛在Kconfig中命名的,但是Kconfig中相當于省略了CONFIG_,在這里相當于補上,即:makfile中要寫全名,
$(CONFIG_HELLO)變數作用:會根據我們選擇的狀態來改變,(1)如果是選擇把它編譯到內核中,那么表示-y(即:obj-y)(2)如果選擇編譯成模塊,那么它表示-m(即:obj-m)
到此,所有的檔案都準備完成,接下來需要
(5)把hello驅動配置包,包含進去
需要修改上一級目錄的Makefile和Kconfig
cd .. #回傳上一級目錄,即路徑.../char/
vi Makefile #修改Makefile,如果沒有則需要自己創建,自己寫
#寫程式,在首行添加以下代碼
obj-y +=hello/ #這里注意hello是個檔案夾,因此最后要加"/"
... #原有的makefile代碼
#保存退出
vi Kconfig #打開Kconfig檔案,把剛才寫的驅動代碼的Konfig包含進config選單界面中
#在前面相應位置添加好Kconfig的路徑
source "drivers/char/hello/Kconfig" #Kconfig相對路徑
#保存退出
(6)回到內核根目錄下,打開選單,選擇不同狀態
make menuconfig #進入配置選單
在界面中選擇Device Drivers選項進入
再進入到Character devices目錄下
就會看到新添加的hello world驅動選單項(名字是在Kconfig中命名的)
用空格鍵選擇狀態:
(7)編譯進內核,選擇<*>(編譯到內核)
保存退出,然后確保配置正確與否
打開.config檔案,搜索
vi .config #打開組態檔
#搜索HELLO
#搜索命令
/HELLO
如果出現CONFIG_HELLO=y是編譯到內核中了,m是編譯成模塊
這里可以看出,如果沒有依賴項,也可以直接改.config檔案的CONFIG_HELLO項
(8)編譯前更改
這時還不能立馬編譯,因為編譯會呼叫默認的的編譯配置,需要做相應修改
這里為了理解的透徹,先看一下編譯腳本:vi create.sh
#!/bin/bash
export ARCH=arm
...
make imx_v7_defconfig #這個就是內核的默認用法,意思是在編譯的時候會自己去找arch/arm/configs下面的imx_v7_defconfig組態檔,作為.config來編譯內核,
...
雖然前面我們改了.config檔案,但不是直接用它來編譯的,而是使用默認的arch/arm/configs/imx_v7_defconfig檔案來編譯的,
因此還要再改一下
-
make distclean,清除所有的編譯檔案,也刪掉了.config檔案
-
把預設配置復制到.config中
cp arch/arm/configs/imx_v7_defconfig .config
- make menuconfig 配置選單選項
再進行第(6)步操作(這里感覺有點亂,步驟重復了?(6)、(7)兩步可以不要)
(9)鍵修改后的.config復制回默認編譯選單里
cd arch/arm/configs/ #切換到默認配置目錄
mv imx_v7_defconfig imx_v7_defconfig_noHELLO #更改默認配置的名字
cp ../../../.config imx_v7_defconfig #把修改好的配置,更改為默認的名稱
(10)運行腳本,等待編譯完成
./create.sh
(11)檢驗是否編譯成功
方法一:燒寫到開發板上,運行看看有沒有加載驅動
cp arch/arm/boot/zImage /home/pyma/ #把鏡像復制到好找的位置
方法二:進入到創建的驅動目錄,查看有沒有把.c檔案編譯成.o檔案
cd drivers/char/hello/
ls
如果沒有相應的.o檔案,則說明編譯出錯,檢查Makefile和其他檔案,
修改好,再回到根目錄編譯
.o檔案檢查沒有問題后,再回到根目錄檢查是否有zImage鏡像
ls arch/arm/boot/
整理自嵌入式學習之Linux驅動篇
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/285832.html
標籤:其他
上一篇:Shell編程
