Linux驅(qū)動(dòng)開發(fā)筆記(一):helloworld驅(qū)動(dòng)源碼編寫、makefile編寫以及驅(qū)動(dòng)編譯基本流
前言
??基于linux的驅(qū)動(dòng)開發(fā)學(xué)習(xí)筆記,本篇是描述了一個(gè)字符驅(qū)動(dòng)的基礎(chǔ)開發(fā)流程,以便做嵌入式開發(fā)多年的應(yīng)用或者系統(tǒng)學(xué)習(xí)驅(qū)動(dòng)開發(fā)。
筆者自身情況
??筆者擁有硬件基礎(chǔ),單片機(jī)軟硬基礎(chǔ),linux系統(tǒng)基礎(chǔ)等各種,就是沒(méi)有l(wèi)inux驅(qū)動(dòng)框架基礎(chǔ),未做過(guò)linux系統(tǒng)移植和驅(qū)動(dòng)移植開發(fā)了。所以補(bǔ)完linux系統(tǒng)移植和驅(qū)動(dòng)開發(fā)就基本可以打通嵌入式整套流程了,作為技術(shù)leader不一定親自動(dòng)手做,但是一定要對(duì)產(chǎn)品構(gòu)架中的每一塊業(yè)務(wù)和技術(shù)要基本清楚。
推薦
??建議參考xun為的視頻教程,教程整個(gè)過(guò)程非常清晰,直接給擁有很多知識(shí)基礎(chǔ)的資深研發(fā),可以不陷入某山的固有思維誤區(qū),也不用imx6的太過(guò)龐從匯報(bào)理解大而冗余,它能直接以最終實(shí)現(xiàn)目標(biāo)為目的,不用從什么裸機(jī)開始做開發(fā)學(xué)習(xí),怎么做也告訴你為什么都交代清楚,再結(jié)合多年相關(guān)從業(yè)工作經(jīng)驗(yàn),說(shuō)實(shí)在的,一通百通可以融會(huì)貫通。從業(yè)多年,第一次推薦,因?yàn)榇_實(shí)真的是好東西。
驅(qū)動(dòng)
驅(qū)動(dòng)分為四個(gè)部分
頭文件:宏定義等等
驅(qū)動(dòng)模塊的入口和出口宏:linux驅(qū)動(dòng)框架
聲明信息:linux內(nèi)核模塊的必要聲明
功能實(shí)現(xiàn):真正實(shí)現(xiàn)驅(qū)動(dòng)的實(shí)體代碼
第一個(gè)驅(qū)動(dòng)源碼:Hello world!
步驟一:包含頭文件
??包含宏定義的頭文件init.h,是一些初始化和宏頭文件,一些module_init,module_exit等。
#include <linux/init.h>
??包含了初始化加載模塊的頭文件
#include <linux/module.h>
步驟二:寫驅(qū)動(dòng)文件的入口和出口
??module_init()和module_exit()入口和出口宏。(PS:這里括號(hào)內(nèi)實(shí)際上需要填入入口出口函數(shù),后續(xù)再填入)
module_init();module_exit();
步驟三:聲明開源信息
??告訴內(nèi)核,本模塊驅(qū)動(dòng)有開源許可證。
MODULE_LICENSE(“GPL”);
步驟四:實(shí)現(xiàn)基礎(chǔ)功能
??入口函數(shù)
static int hello_init(void){
? ?// 在內(nèi)核里面無(wú)法使用基礎(chǔ)c庫(kù)printf,需要使用內(nèi)核庫(kù)printk
? ?printk(“Hello, I’m hongPangZi\n”);
? ?return 0;}
??出口函數(shù)
static void hello_exit(void){
? ?printk(“bye-bye!!!\n”);}
??此時(shí)可以修改,步驟二的出口入口宏了
module_init(hello_init);module_exit(hello_exit);
??總結(jié),按部就班四步法,搭建了基礎(chǔ)的驅(qū)動(dòng)代碼框架。
??

#include <linux/init.h>#include <linux/module.h>static int hello_init(void){
? ?// 在內(nèi)核里面無(wú)法使用基礎(chǔ)c庫(kù)printf,需要使用內(nèi)核庫(kù)printk
? ?printk(“Hello, I’m hongPangZi\n”);
? ?return 0;}static void hello_exit(void){
? ?printk(“bye-bye!!!\n”);}MODULE_LICENSE(“GPL”);module_init(hello_init);module_exit(hello_exit);
Linux驅(qū)動(dòng)編譯成模塊
??把驅(qū)動(dòng)編譯城模塊,然后加載到內(nèi)核里面。
??把驅(qū)動(dòng)直接編譯到內(nèi)核,運(yùn)行內(nèi)核則會(huì)直接加載驅(qū)動(dòng)。
步驟一:編寫makefle
1 生成中間文件的名稱
obj-m += helloworld.o
2 內(nèi)核的路徑
??內(nèi)核在哪,實(shí)際路徑在哪
KDIR:=
3 當(dāng)前路徑
PWD?=$(shell pwd)
4 總的編譯命令
all:
? ?make -C $(KDIR) M=$(PWD) modules
??make進(jìn)去KDIR路徑,當(dāng)前路徑編譯成模塊。
??

obj-m = helloworld.o
KDIR:=PWD?=$(shell pwd)all:
make -C $(KDIR) M=$(PWD) modules
步驟二:編譯驅(qū)動(dòng)
??編譯驅(qū)動(dòng)之前有幾點(diǎn)要注意:
1 內(nèi)核源碼要編譯通過(guò)
??與驅(qū)動(dòng)編譯成的目標(biāo)系統(tǒng),獲取對(duì)應(yīng)的內(nèi)核且需要編譯通過(guò)。
2 內(nèi)核源碼版本
??開發(fā)板或者系統(tǒng)跑的內(nèi)核版本需要與編譯內(nèi)核驅(qū)動(dòng)的內(nèi)核源碼版本一致。
注意3:編譯目標(biāo)環(huán)境要確認(rèn)是否是需要的構(gòu)架,在內(nèi)核目錄下:
make menu configureexport ARCH=arm
??修改構(gòu)架后,可使用menu configure查看標(biāo)題欄的內(nèi)核構(gòu)架
3 編譯器版本
??找到使用的arm編譯器(實(shí)際為arm-linux-gnueabihf-gcc,取gcc前綴)
export CROSS_COMPILE=arm-linux-gnueabihf-
4 編譯
??直接輸入make,編譯驅(qū)動(dòng),會(huì)生成hellowold.ko文件,ko文件就是編譯好的驅(qū)動(dòng)模塊。
步驟三:加載卸載驅(qū)動(dòng)
1加載驅(qū)動(dòng)
??將驅(qū)動(dòng)拷貝到開發(fā)板或者目標(biāo)系統(tǒng),然后使用加載指令:
insmod helloworld.ko
??會(huì)打印入口加載的printk輸出。
2 查看當(dāng)前加載的驅(qū)動(dòng)
lsmod
??可以查看到加載的驅(qū)動(dòng)模塊
3 卸載驅(qū)動(dòng)
rmmod helloworld
??可以移除指定驅(qū)動(dòng)模塊(PS:卸載驅(qū)動(dòng)不需要.ko后綴),卸載成功會(huì)打印之前的printk輸出。
總結(jié)
??學(xué)習(xí)了驅(qū)動(dòng)的基礎(chǔ)框架,那么為了方便很好的測(cè)試,讓大家都有基礎(chǔ)環(huán)境,下一篇,將使用ubuntu18.04,編譯ubuntu18.04的驅(qū)動(dòng),然后做好本篇文章的相關(guān)實(shí)戰(zhàn)測(cè)試。