首页 > 编程知识 正文

链路层拓扑发现映射器I/O驱动程序,java与数据库连接加载驱动

时间:2023-05-04 22:59:59 阅读:27510 作者:1057

本节简要介绍了如何使用设备树,而不要编写相应的驱动程序。 稍后将详细说明设备树。

上一节使用总线设备型号。 与设备树不同的是平台设备的构建

使用总线设备型号,驱动程序分为两部分:

dev :主要是平台_设备的分配/设置/注册; drv :主要是平台_驱动程序的分配/设置/注册; dev和drv在bus中匹配,如果bus检测到匹配的dev和drv,则会调用drv-probe函数,并在probe函数中分配、设置和注册file_operations结构。

在设备树中,驱动程序也分为两个部分。

dts文件:在dts文件中生成节点,并在节点中包含资源; drv :主要是平台_驱动程序的分配/设置/注册; 其中,drv-probe函数分配/设定/注册file_operations结构体。

在总线设备模型中,platform_device在dev.c中,dev是.c文件,每次修改需要重新编译。

在设备树中,dts文件被编译为dtb文件,并传递给内核。 内核处理分析的dtb文件,并检索每个device_node结构。 此device_node结构将转换为platform_device资源。 然后,该platform_device与drv链表中的platform_driver匹配,如果匹配成功,则调用相应的drv-probe函数来分配、设置、注册file_operations结构

所以,总线设备驱动模型和设备树的区别在于,之前的platform_device资源在dev.c文件中配置,而使用设备树,platform_device资源则来自于dts文件。

可以这么说,设备树是针对总线驱动模型的一种改进,使用设备树可以更方便的修改platform_device。

以下是百问网提供的设备树文件。

//spdx-license-identifier 3360 GPL-2.0/* *三星mdk 2440 boarddevicetreesource * * copyright (c 652018 Wei Dongshan @ ddshan defineS3C2410_GPA(NR ) ) 016 ) _nr ) ) defineS3C2410_GPA (216 ) _nr ) ) defineS3C2410_GPD ) ) ) ) _nr ) ) defineS3C2410_gph ) _nr ) ) ) ) defineS3C2410_ )。 (_nr ) )定义3c 2410 _ GPL (NR ) ) 1016 ) ) NR ) )定义3c 2410 _ gpm ) )0/{ 兼容性='三星,smdk2440 '; #地址-蜂窝=1; #size-cells=1; memory @ 3000000 { device _ type=' memory '; reg=0x300000000x4000000; (; /*cpus {cpu {compatible='arm,arm926ej-s '; (; (; */chosen { bootargs=' noinitrd root=/dev/MTD block4rw init=/linuxrc console=tty sac 0,115200 '; (; led {compatible='jz2440_led '; reg=S3C2410_GPF(5) 1; (; (;可以看到,它可以使用一些C语言的语法,使用 /* */ 和 // 来添加注释,使用#define来设置宏。

此节点设置内核的命令行参数。

查看led节点,它有两个属性。 一个是compatible,然后使用它在内核中找到可以支持此节点的驱动程序。 可以支持此节点的platform_driver; 另一个reg,本意是在register、寄存器、ARM系统

,寄存器和内存是同样对待的,因为寄存器的访问空间和内存的访问空间没什么差别。

在上节中,我们曾经使用一个platform_device,在resource中将flags设置成了mem,但实际上它并不是一个mem资源,我们也没有将它作为mem资源使用,而是将它转为一个led_pin来使用。

在这个设备树文件中,也是同样的做法,reg本来是寄存器的地址,但是在这个设备树文件中,将它设置为了某个引脚(S3C2410_GPF(5))。

在驱动程序中要将这个值/引脚读出来,将它作为一个引脚。

后面还有一个1,这是size,这次并没有使用,但是也需要提供一个size。

介绍完dts文件,将这个文件传入/home/book/code/linux-4.19-rc3/arch/arm/boot/dts目录下,然后重新编译设备树文件。

编译之前需要先设置工具链。

export PATH=/home/book/code/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/彪壮的石头/:$PATH

然后在内核目录下执行make dtbs编译设备树文件。

其中arch/arm/boot/dts/jz2440.dtb就是编译出来的dtb文件,将dtb文件拷贝到nfs挂载的路径下。

重启开发板,在uboot中执行命令,下载dtb文件,从虚拟机中下载dtb到0x32000000位置。

nfs 32000000 192.168.0.103:/work/nfs_root/003_led_device_tree/jz2440.dtb

 使用nfs挂载需要先连上虚拟机,ping虚拟机失败。

将ipaddr设为192.168.0.108,确保虚拟机和开发板处于同一个网段,再ping一次可以检测到虚拟机。

 再次下载,下载成功。

 然后将device_tree分区擦除,将刚刚下载的dtb文件载入。

 分区信息如下图所示,擦除的是第1个分区,device_tree分区。

 然后重启开发板,进入/sys/devices/platform目录,执行ls命令,可以看到有一个50005.led目录。

进入该目录,执行ls。

进入of_node(open firmware node)文件夹,可以看到里面有三个文件,compatible,name和reg。

 

正好对应dts文件中的name=led,compatible=jz2440_led,reg=<0050 00 0 1>。

 

也就是说,设备树文件中的节点node确实被转换成了platform_device,那么要怎么去写对应的platform_driver。

在之前的总线设备模型中说过,有一个平台总线,里面有一个match函数,用来匹配dev和drv,所以我们需要查看一下这个match函数,看看它是怎么去匹配平台设备和平台驱动的。

传统的方法是比较name,但是对于从设备树构造的平台设备时怎么匹配的呢?

这个问题需要看源码分析,在match函数中是使用of_driver_match_device函数来匹配dev和drv的。

点击进入of_driver_match_device函数,可以发现该函数直接return了of_match_device函数。

其中drv指向了结构体成员of_match_table,该变量包含了name,type,compatible。

可以猜测一下,这个compatible就会和从dts中得到的compatible属性进行比较,一样的话,就匹配成功。

了解了这些就可以开始写代码了,具体的研究下一节再展开。

在002的基础上进行修改,去掉dev相关的代码。

修改makefile,屏蔽led_dev.o。

然后修改led_drv.c,在led_drv.c中有一个led_drv结构体。

struct platform_driver led_drv = { .probe = led_probe, .remove = led_remove, .driver = { .name = "myled", }};

在led_drv.driver.name中添加.of_match_table = of_match_leds。

struct platform_driver led_drv = { .probe = led_probe, .remove = led_remove, .driver = { .name = "myled", .of_match_table = of_match_leds, /* 能支持哪些来自dts的platform_device */ }};

其中 of_match_leds 如下,.compatible = "jz2440_led"对应dts文件中led节点的compatible属性的值,data没有用上,设置为NULL。

static const struct of_device_id of_match_leds[] = {{ .compatible = "jz2440_led", .data = NULL },{ }};

.compatible = "jz2440_led"的值设置得并不符合规范,正常应该为.compatible = "jz2440,led",表示MPU为jz2440,控制的外设为led,但是目前先这样写,匹配dts文件。

代码修改完成,编译实验一下。

首先,设置环境变量。

export PATH=/home/book/code/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/彪壮的石头/:$PATH

然后编译将编译生成的led_drv.ko文件传到nfs挂载的路径下。

在开发板上insmod这个ko文件,然后lsmod可以看到,出现了一个led_drv模块,在dev目录下也出现了一个led设备。

此时执行测试程序,./ledtest on和off,可以看到led随着指令的控制亮灭。

如果要改变使用的引脚,只需要将dts文件中led节点的reg属性的值进行修改,然后重新编译下载即可,而不用编译任何.c文件。

在dts文件中,使用的是reg来指定led引脚,但是reg本意是寄存器,是否有更直接的表示方法?

答:有,可以将reg改为pin,在drv代码中获取这个pin值即可。

将dts修改完,重新编译下载到开发板上,然后还需要修改一下drv代码。

以前是获取IORESOURCE_MEM类型的资源,现在则是要获取名为pin的属性,把这个属性转换为led引脚。

为了兼容以前的程序,可以先获取IORESOURCE_MEM资源,获取不到的时候再获取pin属性。

问:怎么获取pin属性呢?

答:这些设备节点相关的函数,可以在of.h文件中查看。

使用of_property_read_s32函数就可以从dtb中获取某个指定的属性。

static inline int of_property_read_s32(const struct device_node *np, const char *propname, s32 *out_value){return of_property_read_u32(np, propname, (u32*) out_value);}

 修改后的led_probe函数如下。

static int led_probe(struct platform_device *pdev){ struct resource *res; /* 根据platform_device的资源进行ioremap */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) { led_pin = res->start; } else { /* 获得pin属性 */ of_property_read_s32(pdev->dev.of_node, "pin", &led_pin); } /* 如果都没有获取到led_pin值,返回错误 */ if (!led_pin) { printk("can not get pin for led!n"); return -EINVAL; } major = register_chrdev(0, "myled", &myled_oprs); led_class = class_create(THIS_MODULE, "myled"); device_create(led_class, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */ return 0;}

修改编译后试验,可以看到,小灯同样可以根据输入的指令亮灭,说明成功使用pin属性设置了led_pin。

最后,在总线设备模型中,有一个platform_device结构体,当使用设备树时,platform_device结构体的dev成员,它由一个成员叫of_node,of_node中则含有属性,含有的属性则取决于设备树,如compatible和pin属性,compatible属性会最先被用来匹配对应的drv程序。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。