基于A40i嵌入式Linux内核的驱动移植应用
2022-03-21福建星海通信科技有限公司吴利生
福建星海通信科技有限公司 吴利生
近些年,伴随着科学技术的不断发展,计算机信息技术以及网络通信技术得到了前所未有的发展,Linux嵌入式系统因其源码开放、软件丰富、内核高效稳定,已经在各个领域内得到了大量应用。同时,国内的芯片设计技术也在不断发展追赶中,华为海思、全志、瑞芯微等芯片设计企业推出了很多优秀的芯片。在本文中,笔者将会基于全志的A40i平台对Linux系统内核做出简单分析,对Linux嵌入式系统驱动移植的各类场景做出初步的分析与探讨,借此希望可以有效推动Linux内核的嵌入式系统驱动的提升与发展。
对比各类系统内核,Linux内核有着较为明显的优势,其稳定性很强,且易于实施定制方案。Linux内核在网络通信与文件的模式与运行机制方面,有着自己完善而又健全的整套机制,并以此确立了其在计算机应用软件领域的稳固地位。Linux内核的发展速度非常快,几乎两三个月都会出一个新版本,功能也在不断丰富和完善。在Linux内核中,驱动代码占据了整个内核代码的绝大部分,如何快速高效的实现在指定的硬件平台的移植是本文需要探讨的课题。
1 Linux操作系统移植概述
在计算机领域中,计算机各个硬件之间的运行以及各个软件的管理与控制,均由操作系统来完成。操作系统为计算机规定了完善的运行流程与模式,并且其开放兼容的系统环境,让每一个人都可以利用计算机资源与信息实现更多的有效行为。Linux系统在互联网领域有着绝对重要的地位,其完全开放的环境,使之不断进行着自我完善,其优势也在这一进程中进一步凸显,对各类信息化平台的有效支持,以及高效稳定的运行体系,更是让众多从业人员青睐。Linux不是为了某一硬件而设计的操作系统,它可以广泛支持许多不同体系结构的硬件。如果想把一个Linux内核从一个硬件平台上移植到另外一个硬件平台,整个过程需要进行改动的内容极为繁杂。针对这一问题,相关人员需要对Linux内核驱动架构要有很深的了解,理解驱动软件分层设计思想,移植过程中只修改操作硬件的部分,而不用去管其他层级的结构,这样可以有效减小移植的工作量,也方便了移植后的调试工作,最终使得该移植后的系统能够高效稳定的运行。
2 基于A40i平台的Linux操作系统内核移植方法
Linux操作系统的特性之一就是它的网络协议栈,而且网络体系结构很完整。接下来,我会以A40i平台的网络体系中的PHY驱动移植为例来分析Linux驱动移植的基本流程。由于A40i的CPU本身支持MAC功能,且在厂商提供BSP包中已有源码支持。这里我们只是更换PHY芯片,而且该PHY芯片物理接口的MII接口是统一的,中断接口也采用板子预先定义的中断IO口。所以,设备树文件sun8iw11p1.dtsi中有关EMac的配置可以不用修改,我只需要对PHY驱动进行开发(我们以xx83848来命名该国产PHY芯片,且该PHY芯片对应的驱动代码也用xx83848相关的名称去定义函数及结构体)。PHY芯片驱动的开发总体上大致有三个工作需要做:(1)编写PHY芯片的驱动程序;(2)修改设备树文件;(3)加入内核及编译。
2.1 编写PHY芯片驱动程序
设备驱动程序是实现文件系统与硬件交互的有效桥梁,它自身是文件系统结构中的一个模块,在与硬件交互的同时,又可以与内核进行相关管理。
2.1.1 驱动加载及初始化程序
在a40i的Linux内核源码中,一部分的MAC驱动文件及PHY驱动文件的路径分别为:
硬件上,我们只改动了PHY的硬件。所以,这里我们只分析PHY驱动文件。通过入口函数module_init(xx83848_init)来引导对该驱动的注册操作,然后xx83848_init函数会把PHY驱动的注册上去。说到这里,可能有人会问,既然驱动已经注册上去了,那要什么时候才会加载这个驱动呢?下面的函数就至关重要了。
上面的xx83848_init(void)函数是该网卡驱动的初始化入口,在驱动初始化的时候就把xx83848_driver[]结构体进行初始化配置。上面的MODULE_DEVICE_TABLE(mdio, xx83848_tbl)函数的作用是把该PHY设备ID注册入类型为MDIO的设备表中,系统内核启动运行的过程中会加载MDIO设备驱动,而该MDIO设备驱动会搜索与该设备ID(即xx83848_PHY_ID)相匹配的设备驱动,匹配成功后,就动态加载该设备的PHY驱动。
2.1.2 设备的接口
Linux字符设备驱动一般是使用file_operations类似的结构访问驱动程序的函数来完成工作,这个结构的每个成员的名字都对应着一个调用。用户进程对设备文件进行读写操作的时候,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后,调用这个数据结构相应的函数指针,接着,执行该函数指针指向的驱动函数。但是,需要注意的是,在调用register_netdev之前,初始化工作必须完成。对于不同类型的设备,Linux内核提供的设备接口的结构体会有很大的差异。如,PHY设备驱动的接口结构体是struct phy_driver。其具体的结构体接口如下:
上面的函数指针需要填充相应的功能函数,这些功能函数需要开发人员自己去开发实现,各个功能实现函数最终都挂到核心层提供的统一的函数指针上。这种分层的网络驱动软件架构,完美的实现了MAC层和PHY层的分离,然后,通过核心层将MAC层和PHY层联系在一起。驱动这么分层模式的设计的好处是,PHY层的驱动不用去考虑MAC层的控制方式,而MAC层的驱动也不用去关心PHY层驱动的具体实现。在Linux内核中,无数的设备驱动都采用了类似的分层的思想。
2.2 修改设备树文件
设备树是一种描述硬件的数据结构,许多板级的硬件细节存在设备树文件中。Linux在启动过程中,加载并解析设备树文件,然后,把解析出来的设备资源信息传递给内核,内核会将这些资源绑定给相应的设备。而这里,我们需要做的是修改设备树文件中的MAC管脚配置。但是,A40i的硬件资源配置文件不仅有DTS设备树文件,还多了Fex配置文件,这里假设我们设置的屏幕分辨率是800x600。它们在开发工程中的路径都是固定的,分别为:
一般来说,外部设备的型号或类型发生了改变,相应的外设驱动对应的设备树文件也需要做相应的修改。下面,我截取一些A40i的GMac的设备树的一部分配置信息。
从上面的EMac的设备树中,我们可以看到有兼容属性、内存地址和大小、管脚分配定义、中断地址、时钟控制器等信息。设备树的源文件为.dts,编译后的文件为.dtb文件。Linux内核在展开设备树的过程中会创建并注册相关的设备。a40i的设备树文件除了.dts文件,还有.fex文件,该Fex文件绝大部分内容是对IO管脚的功能进行定义,而整个工程中,最终芯片IO功能就以这里的定义为准。这里,我截取了sys_config800x600.fex配置文件中一部分有关网卡驱动的内容。
从上面的.fex配置文件中,我们可以看到芯片的IO管脚大部分都可以复用,这里把PH0~PH27的多数管脚用于网卡相关功能,上面IO口的定义规则为:Port:<端口+组内序号>、<功能分配>、 <内部电阻状态> 、<驱动能力> 、<输出电平状态>。如果需要基于该平台对IO口的功能进行修改,就需要在遵照该规则的前提下操作。
2.3 加入内核及编译
在前面的相关驱动都开发完成之后,接下来的工作就是把驱动加入内核中编译。对此,在Linux上有一套标准的操作:(1)修改该驱动.c文件所在目录下的Kconfig及Makefile文件;(2)在工程的Linux源码根目录下,运行make ARCH=arm menuconfig,在菜单中找到该驱动的配置项,选中配置,然后保存。最终该配置信息会保存在内核工程目录下的.config文件中;(3)在A40i工程中,编译该内核的方法也比较简单,只要在Lichee目录下,运行./build.sh-m kernel指令即可实现对Linux内核的编译。
2.4 驱动开发小结
纵观整个Linux内核驱动开发,你会发现开发的难点在于芯片驱动程序的开发和驱动程序的调试,该工作的工作量占了整个内核驱动移植的四分之三。虽然Linux的整个驱动移植过程比较复杂,但是因为其开源的特点,使得很多驱动开发有类似的驱动可供参考借鉴。而且,在掌握理解了Linux各个驱动子系统的设计思想后,驱动开发工作完全可以事半功倍。
3 Linux内核在嵌入式系统中的应用展望
Linux系统的广泛应用,让人们的生活变得更为高效快捷,日常的工作方式与各类行为方式也变得更为智能。近些年,伴随着Linux核心技术的迅速发展,并在大量从业人员的努力下,Linux内核驱动的移植兼容性得到了极大的提高,整体技术愈发成熟,相关的设计理念以及移植方式更为先进。在可预见的未来,Linux内核必然会随着互联网与物联网的不断推进而迅速强大。
4 结语
随着嵌入式技术的不断发展与相关应用技术的逐渐成熟,采用Linux内核的各类设备也将不断被人们所熟知,其未来的发展前景也会迅猛扩张,而从事嵌入式Linux开发与研究也将会有更多的发展前景。