文章目录
添加虚拟设备结点
1.先了解设备驱动文件
设备某一类的设备驱动文件所在目录(这里的目录,下全是各类设备子目录):
cd /home/zhua/SDK/T113-i_v1.0/kernel/linux-5.4/drivers
比如在设备驱动目录下的,串口类驱动(tty),tty种类的设备目录里面还可以继续分类设备目录,如serial类的设备驱动目录:
cd /home/zhua/SDK/T113-i_v1.0/kernel/linux-5.4/drivers/tty/serial/
当然在serial设备驱动类目录下还有各类设备的区分,比如8250类设备。
驱动类文件,层层套娃,是有规律分类的。
这里要知道每一个类的设备驱动目录下面都有一个Kconfig和Makefile文件:
Kconfig是menuconfig来解析和配置的。
Makefile是内核编译链接,以及链接各种库,头文件,头文件路径等用的。
比如serial类设备目录下:
2.再看Kconfig被Menuconfig如何解析
首先利用menuconfig打开配置界面:
在目录:/home/zhua/SDK/T113-i_v1.0/kernel/linux-5.4 执行:
make menuconfig
进入 Device Drivers > Character devices > Serial drivers(先理解规则,最后一步步分析为什么是在这个菜单设备目录下)。
menuconfig工具配置以及使用可以参考:(二)编译原生SDK以及配置交叉编译链中的配置内核等选项等部分。
下面以串口类设备为例看Kconfig如何被解析的:
打开:/drivers/tty/serial/下的Kconfig,查看设备菜单名称以及设备名称。
注意:并不是每个Kconfig里面 都有menu这个生成Serial drivers设备菜单的指令,有的就没有,比如嵌套的8250的Kconfig就没有生成设备菜单目录,因此8250类设备里面的设备名称,直接生成在Serial drivers设备菜单目录下面。如果还有menu指令,那就在Serial drivers目录下在生成一层目录,如果目录下还有menu指令,则生成一层层的套娃目录。依此类推。
而且menu和endmenu是成对出现,并且包含在这俩句之间的才能包含在当前设备目录菜单内,否则就是和当前设备菜单是并行菜单。
另外:并不是设备名称一定是显示在menuconfig上面的,必须要满足depends on这个依赖,这个依赖其实,是因为一个设备树和驱动里面包含了各种平台,通过这个依赖进行区分哪个平台,比如A平台显示A的设备树名称和使用A的驱动,B平台显示就是B的设备树名称和使用B的驱动,以及设备是否支持这个总线,是否支持串口,是否支持iic啊等条件,支持就显示配置,不支持就不显示
比如Serial drivers设备菜单目录下面的config SERIAL_AMBA_PLP10这个设备 ,tristate后面的字符就是生成的设备名称,生成设备名称的前提是满足depends on ARM_AMBA,只有当这个设备在ARM_AMBA总线的支持情况才会在menuconfig上显示。如果没有依赖将直接显示,如果没有名称则肯定也是不显示的,比如第一个设备,config SERIAL_EARLYCON,bool后面就没有名称,因此不会显示。
这里看到生成了Serial drivers设备菜单目录。里面又嵌套一个8250类设备的Kconfig目录。
查看driver/tty/serial的子目录下/8250设备类目录的Kconfig
开头:
结尾:
可以看到并没有生成目录菜单,所以这个8250的设备没有自己的目录,直接就是在Serial drivers设备菜单目录内。
对应的menuconfig图形来查看:
大致的图形化理解:
Serial drivers
├── config SERIAL_EARLYCON (不显示名称,因为bool后面没有名称)
├── source "/serial/8250/Kconfig" (8250类设备,因为没有menu,里面的设备名称直接生成在Serial drivers下,如果有继续生成子目录)
└──"Non-8250 serial port support"(comment提示符)
├── config SERIAL_AMBA_PL010
│ └── tristate "ARM AMBA PL010 serial port support" (满足depends on ARM_AMBA时显示)
├── config SERIAL_AMBA_PL011
│ └── tristate "ARM AMBA PL011 serial port support" (满足depends on ARM_AMBA时显示)
└── menu "Other Serial Port Support"
├──.......
总结:
menuconfig根据Kconfig内容生成图像配置,如果有menu指令,则生成菜单目录。
包含在menu和endmenu之间的设备名称,如果在依赖满足的条件下,则生成设备名称在当前菜单目录下面。
包含在menu和endmenu之间有,source xx/Kconfig,这种嵌套其他目录Kconfig的指令,如果xx/Kconfig里面还有menu指令,则继续生成菜单目录,如果xx/Kconfig没有menu指令,当前设备在满足依赖的条件下,生成设备名称在包含source xx/Kconfig指令的菜单目录下。
最后解释为什么在Device Drivers > Character devices > Serial drivers目录下面:
从底往上推:
serial层菜单名称是 Serial drivers
再往上到tty层,发现tty层Kconfig并没有menu,没有生成目录,因为tty文件夹必然被其他的Kconfig包含。
并且再往上到drivers层,发现drivers层也没有加载tty文件夹的指令,此时看到drivers层生成了Device Drivers目录,并且包含了好多个不同目录的Kconfig,那就说明,tty被包含在drivers层包含的Kconfig里面了
直接在drivers目录下搜索 包含tty设备目录Kconfig 的文件所在。查找发现在drivers/char目录下面
grep -r "drivers/tty/Kconfig"
直接打开drivers/char目录下的Kconfig,可以发现里面包含 tty/Kconfig 和 serial/Kconfig,又因为当前目录生成了Character devices菜单,serial目录生成Serial drivers菜单,tty目录没有生成菜单,因此Character devices菜单下有Serial drivers菜单和tty/Kconfig内的设备。
大概结构:
Device Drivers
├── Character devices
│ ├── Serial drivers (from serial/Kconfig)
│ │ ├── [Serial driver options...]
│ │
│ └── [Devices from tty/Kconfig]
│ ├── tty devices
│ └── ...
3.最后看Makefile文件如何编写
最底层的Makefile(serial这一层)
所谓最底层(serial文件夹里)就是直接管理对应的驱动文件(如sunxi-uart.c)的那一层Makefile.(这里是因为我要用串口,驱动文件就在serial文件夹里面,所以这一层就是我认为的最底层,即要用的驱动代码所在的那一层,,,,当然serial下层也还是有8250类设备驱动文件夹)。
这一层的Makefile里面:
obj-$(CONFIG_SERIAL_SUNXI) += sunxi-uart.o
其中:
-$(CONFIG_SERIAL_SUNXI) 括号里面必须以大写CONFIG开头,后面的参数必须与Kconfig里面的保持一致,因为这个参数是可以通过图形界面配置的。
sunxi-uart.o 名称必须跟驱动文件sunxi-uart.c保持一致。
中间层的Makefile(tty以及除了顶层这一层)
不是顶层,就是下层还是有分类驱动设备文件夹,就比如tty这一层,它下层有serial类设备驱动文件夹(当然serial下层也还是有8250类设备驱动文件夹,也可以的哈,只是为了举例理解)。
那么这一层的Makefile就是管理serial这个文件夹了,而不是像直接管理sunxi-uart.c驱动文件一样的操作了。
一般Makefile管理,文件夹都是直接-y 直接编译进内核这个文件夹里面全部的驱动文件,当然也不一定比如上面说的管理8250文件夹的Makefile,它还是借助参数指定,通过图形界面配置的。
obj-y += serial/
这里段代码是直接将serial目录下全部驱动直接编译进内核。
为了消除顾虑,可以看到8250作为最底层,则上层Makefile管理8250文件夹,并且借助参数指定,通过图形界面配置。
顶层的Makefile(drivers层)
打开Makefile看到,顶层一般都是-y直接编译文件夹目录下全部驱动,不过也有通过参数指定,借助图形界面去设置,没有绝对的。这里也能看见 直接将tty目录下的全部驱动编译进内核。
obj-y += tty/
这里段代码是直接将tty目录下全部驱动直接编译进内核。虽然tty的设备目录 是在Character devices下面,但是所有的驱动是都要编译的。简单理解就目录排版随意,驱动代码必须全部编译。
至此Makefile和Kconfig文件全部理解完成。
4.在设备树直接添加虚拟设备节点
参考(八)简单修改设备树,直接添加一个设备节点。
//测试节点
myzhuazi{
compatible = "allwinner,sun8iw20p1-zhuazii";
status = "okay";
};
注意这里一定要注意这个compatible关键字,后面的sun8iw20p1-zhuazi,就是设备节点和设备驱动匹配的关键依据,前面那个sun8iw20p1是芯片型号,其本质就是通过名称匹配的。如果不一致,设备驱动不能将设备成功加载,前面的myzhuazi可以随便取。
状态一定要使能。
5.书写虚拟设备节点驱动
整体完整代码
说明:
#define DRIVER_NAME “zhuazi” 这里只是用于标识模块和日志输出简单的作用而已,可以理解为一个模块的名字,只是名字方便辨认的作用,跟设备树里面的那个用于比较的名字不一样,但是最好还是相近相似,方便代码调试,日志输出,以及在出错时候快速定位哪个模块。
#define DEVICE_NAME “zhuazidev” 这个名称是生成/dev下面的文件目录 可以任意设定。
// 匹配Device Tree中的compatible属性
static const struct of_device_id zhuazi_of_match[] = {
{
.compatible = "allwinner,sun8iw20p1-zhuazi" },
{
/* sentinel */ }
};
代码 { .compatible = “allwinner,sun8iw20p1-zhuazi” },中的sun8iw20p1-zhuazi必须与前面添加的设备树那边的名称保持一致。
注释的函数暂时用不到,为了代码的完整性而已。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/fs.h></