姓名:頓皓 學(xué)號:19020100178 學(xué)院:丁香2號書院
轉(zhuǎn)自:linux設(shè)備驅(qū)動編寫入門 - 澆筑菜鳥 - 博客園 (cnblogs.com)
【嵌牛導(dǎo)讀】Linux設(shè)備驅(qū)動是什么?我個人的理解是Linux有用戶態(tài)和內(nèi)核態(tài)泥耀,用戶空間中是不能直接對設(shè)備的外設(shè)進行使用而內(nèi)核態(tài)中卻可以,這時我們需要在內(nèi)核空間中將需要的外設(shè)驅(qū)動起來供用戶空間使用。Linux的驅(qū)動主要分為字符設(shè)備、塊設(shè)備、和網(wǎng)絡(luò)設(shè)備三類宵凌,在分別驅(qū)動時需要注意一下,其中驅(qū)動不一定單屬于哪一類契邀,一個驅(qū)動可能屬于多種分類摆寄。
【嵌牛鼻子】Linux? ?驅(qū)動編寫
【嵌牛提問】如何編寫Linux設(shè)備驅(qū)動?
【嵌牛正文】
一坯门、準(zhǔn)備材料
可以根據(jù)自己的需要準(zhǔn)備相應(yīng)材料:
開發(fā)環(huán)境:VMware
操作系統(tǒng):ubuntu
開發(fā)板:湃兔i2S-6UB
二微饥、下載linux內(nèi)核源碼
1.ubuntu內(nèi)核源碼的下載方式,直接通過命令下載即可古戴,下載后源碼存放的地址在/usr/src路徑下
sudo apt-getinstalllinux-source
經(jīng)過的測試好像ubuntu不需要下載源碼也是可以編寫驅(qū)動的欠橘,具體教程見后面內(nèi)容。
2.湃兔核的內(nèi)核源碼下載地址:http://i2som-zh.oss-cn-beijing.aliyuncs.com/i2SOM-iMX-Linux-706035a.tar.gz现恼。
下載完成后解壓到開發(fā)環(huán)境的路徑下肃续,具體路徑根據(jù)個人愛好。
三叉袍、編寫驅(qū)動
1.入口函數(shù)和出口函數(shù)
學(xué)習(xí)編程語言時始锚,代碼都會有開始運行的位置,也就是我們所知的入口函數(shù)'mian()',同樣的原理linux驅(qū)動編寫也是有入口函數(shù)的喳逛,只是linux驅(qū)動比較特殊瞧捌,函數(shù)基本都是成對存在的,有入口便有出口,所以linux存在入口函數(shù)和出口函數(shù)姐呐,如下所示
module_init(x)//入口函數(shù)
module_exit(x)//出口函數(shù)
留意過內(nèi)核源碼的小伙伴都知道殿怜,入口和出口函數(shù)的定義是在liunx內(nèi)核源碼中的include/linux/init.h文件中,如下圖所示:
2.打印函數(shù)
linux的驅(qū)動中打印日志到控制臺的函數(shù)和用戶空間的打印函數(shù)函數(shù)名不一樣曙砂,但是功能和使用方法差不多头谜,linux內(nèi)核的打印函數(shù)是printk()。
打印函數(shù)的定義是在liunx內(nèi)核源碼中的include/linux/printk.h文件中鸠澈,如下圖所示:
3.編寫hello.文件
創(chuàng)建一個hello的驅(qū)動文件夾柱告,然后創(chuàng)建hello.c文件,文件內(nèi)容如下
#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");
}/*
*模塊入口與出口函數(shù)
*/
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jiaozhu");
4.編寫Makefile文件
編寫完驅(qū)動程序后款侵,需要創(chuàng)建Makefile文件末荐,在這里需要注意x86和arm架構(gòu)環(huán)境下的內(nèi)容有所不同
x86架構(gòu)下的Makefile內(nèi)容如下所示
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的所需的內(nèi)核源碼路徑在/lib/modules/5.8.0-59-generic/build下
arm架構(gòu)下的Makefile內(nèi)容如下所示
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架構(gòu)的驅(qū)動是需要設(shè)置交叉編譯器,這里沒在Makefile文件中設(shè)置交叉編譯器的原因是我已經(jīng)在源碼的頂層路徑Makefile文件中設(shè)置了新锈。
5.編譯
完成hello.c文件和Makefile文件的編寫后甲脏,就可以進行編譯了,使用make命令進行編譯妹笆,編譯完成完成后會生成.ko文件块请,如下圖所示:
到此驅(qū)動的編寫已經(jīng)完成了,細(xì)心的小伙伴可能已經(jīng)注意到我加載和卸載驅(qū)動時沒有日志輸出拳缠,具體原因我也不知道墩新,在arm開發(fā)板中測試時是有日志輸出的。
四窟坐、測試
編譯完成后生成的hello.ko驅(qū)動模塊可以通過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開發(fā)板中使用modprobe命令加載模塊時需要將.ko文件拷貝到/lib/modules/路徑下,如果路徑不存在直接創(chuàng)建相應(yīng)的路徑即可徙菠,arm一般測試方式都是通過nfs掛載根文件系統(tǒng)的形式進行測試讯沈。
在開發(fā)環(huán)境中將.ko文件拷貝至rootfs跟文件系統(tǒng)的/lib/modules路徑下
sudocp hello.ko /home/rootfs/lib/modules/4.1.43-f
注意:文件4.1.43是開發(fā)板內(nèi)核的文件版本,不問版本的內(nèi)核對應(yīng)的文件不同
然后啟動開發(fā)板婿奔,執(zhí)行加載命令
depmod
modprobe hello
3.查看加載的驅(qū)動和卸載驅(qū)動
在任意路徑下使用lsmod命令即可查看驅(qū)動模塊缺狠,如下圖所示:
完成后可以通過rmmod hello卸載驅(qū)動模塊,注意在ubuntu下可能需要通過root權(quán)限才能卸載萍摊。