前言
(1)
(2)前文我们说了,驱动程序有两种运行方式,一种是以内核模块(.ko)的形式体现出来,另外一种是直接编译进入Linux内核中。上文我们已经介绍了如何以内核模块的形式体现,现在我们将介绍如何讲驱动程序编译进入内核中。新手了解即可,甚至可以不看,因为新手写的驱动文件不建议编译进入内核。后续等你熟练了再回来看也不迟。
(3)如果按照本文的思路,将自己的驱动程序编译进入内核,之后再进行驱动装载,大概率会出现loading out-of-tree module taints kernel这个警告,意思就是说你的垃圾代码污染了内核。如果你依旧使用这个内核进行操作,并且产生了问题,而且你还不知好歹的向Linux内核研发大佬提交问题。那么大佬看到这个警告之后,就不会鸟你。因为Linux内核大佬只会对源码负责。
(4)这个警告一般是不会有啥问题的,但是你如果有强迫症,可以先把原来干净的.config文件复制一份到其他地方,做完实验之后再删除自己创建的文件,同时把干净的.config文件下载进入开发板。
理论
进入内核配置界面
(1)作为Linux驱动工程师,必须具备根据公司业务需求,增删Linux内核的能力。
(2)为了方便驱动工程师对内核进行修改我们可以使用如下四种命令:
<1>make config (基于文本的最为传统的配置界面, 不推荐使用)
<2>make menuconfig (基于文本菜单的配置界面)
<3>make xconfig (要求 QT 被安装)
<4>make gconfig (要求 GTK+ 被安装)
(3)一般来说,我们都是采用的make menuconfig 命令来对内核进行裁剪。
<1>如下图,我们进入Linux内核路径,我的内核路径是/home/book/100ask_imx6ull-sdk/Linux-4.9.88因此进入这个目录,内核路径需要根据你本人下载的位置定义,每个人都可能不一样。
<2>进入内核路径之后,输入make menuconfig 等待加载即可进入下图中的配置界面。
cd /home/book/100ask_imx6ull-sdk/Linux-4.9.88
make menuconfig
# make menuconfig' requires the ncurses libraries 报错
sudo apt-get installlibncurses5-dev
(4)对于刚使用的配置界面的同学,可能会出现如下三种错误
<1>如果提示错误“make menuconfig’ requires the ncurses libraries”,请使用命令sudo apt-get installlibncurses5-dev安装ncurses。
<2>提示“Your display is too small to run Menuconfig!”这个错误是因为控制终端的窗口太小,放大窗口或者全屏操作即可。
<3>提示"make:*** No rule to make target 'menucofnig.Stop"这个错误是没有在内核源码的顶层目录输入make menuconfig。
配置界面的操作
光标移动
(1)他这个操作真的很简单,就是简单上的上,下,左,右移动光标。
搜索界面
(1)如果需要搜索某一个驱动程序,只需要输入"/"键即可弹出搜索界面。
(2)menuconfig 的设计比较反人类,他不是按照从a到z顺序排列的,这个排列是乱序,所以想要找到目标,特别麻烦。
(3)不同的模块直接具有依赖关系,如果依赖条件不满足,就不会出现在menuconfig 中。
快捷键快速跳转到对应的选项
(1)上面我们说了,配置界面不是按照从a到z的顺序排列的,非常反人类。所以想要找到自己要配置的选项,是相当的麻烦。
(2)但是完全没救了吗?也没有,配置界面有一个快捷键跳转的功能。menuconfig 中的每一行的选项, 都有一个用特殊颜色标记出来的字母, 很明显,此字母, 就是该行的快捷字母。
驱动程序的三种状态以及图标的含义
(3)驱动程序有三种状态," M “表示将驱动编译成模块,” * “表示将驱动编译进入内核,空白则表示不进行编译。按空格键可以配置驱动程序的状态。
(4)在配置界面中,我们能够看到 [],<>,()这三种图标。
<1>[]只有两种状态,”“或者空白。
<2><>可以设置三种状态,“M”、”"或者空白。
<3>()表示用来存放字符串或者16进制数。
menuconfig添加目录语法介绍
(1)配置界面的基本操作我们会了,但是我们如何将自己的驱动加入到配置界面呢?
实操
Ubuntu中进行的操作
(1)进入内核目录的/drivers/char目录
(2)创建一个文件夹helloworld的文件夹,然后在这个文件夹中写入一些帮助信息。
cd /drivers/char
mkdir helloworld
cd helloworld
#————————————————————————
vi Kconfig
#Kconfig中写入下面这些
config helloworldbool "hello world support"default yhelphelloworld
#————————————————————————
vi Makefile
#Makefile中写入下面这些
obj-$(CONFIG_helloworld) := helloworld.o
#————————————————————————
vi hello_drv.c
hello_drv.c 中写入下面这些
/******************************************************************************** @文件名 : 驱动入门* @作者 : zhangyixu* @CSDN_ID : qq_63922192 * @CSDN_昵称 : 风正豪* @日期 : 2023年09月01日* @TABsize : 一个TAB为4空格* @编码格式 : UTF-8* @版权声明 : 仅供参考学习,未经允许禁止商用********************************************************************************/#include <linux/module.h>
#include <linux/init.h>//入口函数
static int hello_init(void)
{printk("hello world --- CSDN_qq_63922192\r\n");return 0;
}//出口函数
static void hello_exit(void)
{printk("good bye\r\n");
}module_init(hello_init); //确认驱动入口函数
module_exit(hello_exit); //确认驱动出口函数/*最后我们需要在驱动中加入 LICENSE 信息和作者信息,其中 LICENSE 是必须添加的,否则的话编译的时候会报错,作者信息可以添加也可以不添加*这个协议要求我们代码必须免费开源,Linux遵循GPL协议,他的源代码可以开放使用,那么你写的内核驱动程序也要遵循GPL协议才能使用内核函数*因为指定了这个协议,你的代码也需要开放给别人免费使用,同时可以根据这个协议要求很多厂商提供源代码*但是很多厂商为了规避这个协议,驱动源代码很简单,复杂的东西放在应用层
*/
MODULE_LICENSE("GPL"); //指定模块为GPL协议
MODULE_AUTHOR("CSDN:qq_63922192"); //表明作者,可以不写
MODULE_VERSION("1.0"); //驱动版本申明,可以不写
(3)退回上一级目录,并且修改Kconfig和Makefile文件。
cd ..
#————————————————————————
vi Kconfig
#Kconfig中写入下面这些,注意要写在menu "Character devices"下面,因为我们的模块是要放在"Character devices"菜单中
source "drivers/char/helloworld/Kconfig"
#————————————————————————
vi Makefile
#Makefile中写入下面这些
obj-y += helloworld/
(4)返回到Linux内核顶层目录,输入make menuconfig进入配置界面,确定模块的存放路径。
cd ../..
make menuconfig
(5)找到路径之后,确认我们所编写的模块为*,是要编译进入内核的。
(6)退出菜单界面,然后点击Yes,表示保存加进来的模块。
(7)输入vi .config,输入"/hello",如果CONFIG_helloworld=y,表示我们的模块成功被选中,最终会编译进入内核。
(8)
<1>在 uboot 中,通过“make xxx_defconfig”来配
置 uboot, xxx_defconfig 就是不同板子的配置文件。因为我这里是韦东山的i.mx6ull开发板,所以是输入的make 100ask_imx6ull_defconfig。如果是正点原子的开发板,则是输入的make mx6ull_alientek_emmc_defconfig。
<2>make zImage -j4是用于编译Linux内核镜像文件,后面的-j 用于设置主机使用多少个核编译uboot,设置的核越多,编译速度越快。因为我的这个VMware 分配了 4 个核,那么最多只能使用-j4。
<3>编译完成之后,最终将内核镜像文件拷贝到网络文件系统中
make 100ask_imx6ull_defconfig
make zImage -j4
cp arch/arm/boot/zImage ~/nfs_rootfs
开发板中进行的操作
(1)接下来的操作需要在开发板上进行,最终打印结果为hello world — CSDN_qq_63922192,表示我们的驱动程序成功加载进入了Linux内核中。
mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt
cp /mnt/zImage /boot
reboot
dmesg | grep "hello"