Linux驅動簡介和開發流程--Linux驅動學習(1)


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 文件就是編譯好的驅動。

image

在開發板上加載驅動用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驅動篇


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM