驅動開發時候,儘量選擇對應操作系統內核的Linux系統作爲上位機平臺
下載源碼與編譯
源碼的下載可以從網站:https://mirrors.edge.kernel.org/pub/linux/kernel/
找到對應的內核版本,然後下載,通過make menuconfig和make,進行編譯。
沒有編譯過的內核,驅動開發過程中進行編譯可能有錯誤,找不到文件等。
編寫一個最簡單的驅動
如下是hello.c文件的驅動程序。其中聲明瞭證書,和模塊加載後與退出時應該執行的函數。
#include<linux/module.h> #include<linux/kernel.h> MODULE_LICENSE("Dual BSD/GPL"); static int hello_init(void) { printk(KERN_ALERT "hello,world\n"); return 0; } static void hello_exit(void) { printk(KERN_ALERT "goodbye,world\n"); } module_init(hello_init); module_exit(hello_exit);
編寫Makefile文件
Makefile文件的編寫如下,主要是KERNELDIR,爲linux源碼的位置
ifeq ($(KERNELRELEASE),) KERNELDIR ?= /usr/src/linux-source-5.4.0 PWD := $(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions else obj-m := hello.o endif
修改部分信息和執行
當編譯的內核爲系統本身的內核,但是make以後生成的ko文件無法加載,即通過insmod xxx.ko無法加載,格式不對
查看dmesg信息,參考解決:https://www.cnblogs.com/blfbuaa/p/6907027.html
正常執行後再dmesg中會有相應的加載和卸載模塊的message信息。卸載命令爲rmmod xxx
模塊之間的依賴通信
以下爲add_sub.c
#include<linux/kernel.h> #include<linux/module.h> #include"add_sub.h" long add_integer(long a,long b) { printk(KERN_ALERT "add init"); return a+b; } long sub_integer(long a,long b) { printk(KERN_ALERT "sub init"); return a-b; } EXPORT_SYMBOL(add_integer); EXPORT_SYMBOL(sub_integer); MODULE_LICENSE("Dual BSD/GPL");
以下爲add_sub.h
#ifndef _ADD_SUB_H_ #define _ADD_SUB_H_ long add_integer(long a,long b); long sub_integer(long a,long b); #endif
以下爲Makefile,當執行完make後,則生成了符號表文件,其爲Module.symvers,該文件可以用於其他文件的函數引用
ifeq ($(KERNELRELEASE),) KERNELDIR ?= /usr/src/linux-source-5.4.0 PWD := $(shell pwd) PRINT_INC =$(PWD)/../include EXTRA_CFLAGS += -I $(PRINT_INC) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions else obj-m := add_sub.o endif
以下爲test.c
#include<linux/kernel.h> #include<linux/module.h> #include"../add_sub.h" static long a = 1; static long b = 1; static int AddOrSub = 1; static int test_init(void) { long result = 0; printk(KERN_ALERT "test init\n"); if (1 == AddOrSub) { result = add_integer(a,b); } else { result = sub_integer(a,b); } //printk(KERN_ALERT, "the %s result is %ld", AddOrSub==1?"Add":"Sub",result); return 0; } static void test_exit(void) { printk(KERN_ALERT, "test_exit"); } module_init(test_init); module_exit(test_exit); module_param(a,long,S_IRUGO); module_param(b,long,S_IRUGO); module_param(AddOrSub,int,S_IRUGO); MODULE_LICENSE("Dual BSD/GPL");
以下爲test.c的Makefile
ifeq ($(KERNELRELEASE),) KERNELDIR ?= /usr/src/linux-source-5.4.0 PWD := $(shell pwd) KBUILD_EXTRA_SYMBOLS=$(obj)/../print/Module.symvers modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions else obj-m := test.o endif
編譯完後,需要先掛載add_sub模塊,然後再掛載test模塊。
未得到預期的效果,主要是在順次加載後,並在加載過程添加a,b等參數,無法從dmesg中獲得一個調用輸出
將模塊編譯到內核中
如在drivers下建立add_sub_Kconfig文件夾,然後放入對應的源碼文件,對應的Makefile和Kconfig文件。其中Kconfig文件用於make menuconfig的索引,其和上層的Kconfig關聯
Makefile文件內容如下:
obj-$(CONFIG_ADD_SUB)+=add_sub.o obj-$(CONFIG_TEST)+=test.o
Kconfig文件內容如下:
# # add_sub configuration # menu "ADD_SUB" comment "ADD_SUB" config CONFIG_ADD_SUB tristate "ADD_SUB support" default y config CONFIG_TEST tristate "ADD_SUB test support" depends on CONFIG_ADD_SUB default y endmenu
然後修改上層的Kconfig文件,添加如下內容:
Source "drivers/add_sub_Kconfig/Kconfig"
然後修改上層的Makefile文件,添加如下內容:
obj-$(ADD_SUB) += add_sub_Kconfig/
就可以在主目錄下執行make menuconfig後,在驅動下找到對應的驅動和編譯信息了