VxBus是风河公司新的设备驱动程序架构,是VxWorks新增的特性,它是在VxWorks6.2及以后版本被增加到VxWorks中的。

开发步骤

  1. 添加新模块(这里会告诉vxworks该模块的入口函数);
  2. 填充vxbDevRegInfo,并通过vxbDevRegister进程注册驱动程序;
  3. 通过向hcfDeviceList数组中添加记录,完成设备的注册;
  4. Vxworks启动是会实例化hcfDeviceList中的设备(不必人工干预);
  5. 在vxbDevRegInfo中注册的几个初始化函数中添加实际的设备驱动代码;

VxBus模块添加

Vxworks中采模块化的方式管理各个功能单元,驱动也是由一个或多个模块组成。

VxBus是vxworks中的模块化机制。类似于linux中的module。通过vxBus我们可以方便的裁剪或添加新的模块。

模块的裁剪通常是在vxworks的开发环境workbench中进行的。建立一个工程后,会得到一个config文件,通过鼠标操作就可以实现模块的裁剪。

添加新模块则复杂一些,需要添加几个新的文件,但内容很简单,只是用来设置一些必须的信息。添加完成后,就可以像标准模块一样裁剪了。添加模块的详细过程可以再workbench中的vxbus的pdf文档中得到,说的很详细。

vxBus驱动注册过程

vxbus驱动的注册通过vxbDevRegister实现。其原型如下:

STATUS vxbDevRegister
    (
    struct vxbDevRegInfo * pDevInfo /* per-bus recognition info */
    )

显然,我们唯一要做的就是填充结构体pDevInfo,其类型定义如下:

BSP用于初始化硬件、引导操作系统并提供软件和硬件之间的设备驱动接口,针对某类体系结构的处理器开发BSP时,了解其基本的体系结构和指令系统是必要的。一般来说,BSP的设计与开发可分为几个步骤:
  1. 建立开发环境,这个不用说了,就是装集成环境;
  2. 选择合适的BSP模板,要尽可能的与硬件平台相近;
  3. 修改或添加wind内核激活前的初始化代码,例如初始化CPU内核、MMU、Cache禁止/使能等;
  4. 内核激活后,连接系统中断、系统时钟,修改或添加所需的设备驱动程序;
  5. 测试与验证,BSP的正确性与稳定性对上层软件和整个系统的稳定起着至关重要的作用,因此BSP完成后要经过测试验证。

开发BSP过程中最主要的三个程序分别为:

  1. romInit.s中的romInit()函数,用于初始化CPU及内存;
  2. sysLib.c中的sysHwInit2()函数,用于将所有板上硬件初始化为静止状态;
  3. sysLib.c中的sysHwInit()函数,进一步初始化板件以使用vxWorks程序。

下面根据代码详细分析vxWorks的启动顺序:

一、执行romInit()

系统启动时,处理器首先会跳到ROM中的入口点_romInit()(位于romInit.s中),该处汇编代码如下:

_romInit:
Cold:
    MOV r0, #BOOT_COLD

warm:
    B   start
    .ascii   "Copyright …"
    .balign 4

start:
/*此处添加延迟可以有效解决部分板件在复位后无法启动的问题*/
    TEQ r0, #BOOT_COLD
    MOVEQ  r1, #INTEGRATOR_DELAY_VALUE
    MOVNE  r1, #1
delay_loop:
    SUBS   r1, r1, #1
    BNE delay_loop
...
此处即为vxWorks在ROM中的入口点,在此之前,sysLib.c中的函数sysToMonitor将检查指令的前三行,看他们是否发生改变,进而可判断是否为热启动,具体代码如下:
if (p[0] == 0xE3A00002 && p[2] == 0x79706F43)
    pRom = (FUNCPTR)(ROM_TEXT_ADRS + 4);   /* warm boot address */
    else
    pRom = (FUNCPTR)ROM_TEXT_ADRS;     /* start of ROM */
由上面代码可知,对于热启动,处理器在执行函数romInit的同时会先增加一个小的偏移量, romInit中的代码的需要用汇编语言实现,主要用于分配内存,初始化处理器状态字以及创建临时堆栈,另外,它还会初始化尽量最少的必需硬件、屏蔽中断、清空cache。如果romInit函数执行正确,从LOCAL_MEM_LOCAL_ADRS到LOCAL_MEM_LOCAL_ADRS+ LOCAL_MEM_SIZE的内存空间都将是可读写的,否则,说明此函数执行失败。romInit执行成功后,会确定启动类型并作为参数跳转到bootInit.c中的C函数romStart()中,跳转代码如下:
    LDR r12, L$_rStrtInRom
    ORR r12, r12, #1      /* in Thumb case */
    BX  r12
而L$_rStrtInRom就是函数romStart的地址:

L$_HiPosn:        
.long ROM_TEXT_ADRS + HiPosn - FUNC(romInit)
L$_rStrtInRom: 
.long ROM_TEXT_ADRS + FUNC(romStart) - FUNC(romInit)

romInit传递的参数(即上面定义的BOOT_COLD)决定了在romStart中是否清空(内存冷启动)。

作者:Escorpion

VxBus是指在 VxWorks 中用于支持设备驱动的特有的架构,这种架构包含对minimal BSP的支持。它包括以下功能:

  1. 允许设备驱动匹配对应设备
  2. 提供驱动程序访问硬件的机制
  3. 软件其他部分访问设备功能
  4. 在VxWorks系统中,实现设备驱动的模块化

VxBus是Vxworks的模块化机制,类似于linux中的module。通过VxBus可以对模块方便的裁剪或者添加。VxBus 在总线控制器驱动程序服务的支持下,能在总线上发现设备,并执行一些初始化工作,使驱动与硬件设备之间正常的通讯。

vxBus下对设备管理做了更为详细的划分,简单说来,硬件称为device,软件叫做driver。如果一个device出现在硬件列表中,启动时需要到driver的队列中去找相应的driver,如果找到,二者结合成一个instance,否则在vxBusShow里可以看到一个orphan。使用vxBusShow可以比较清晰的看到driver列表和device列表以及orphan列表。

相关参数

设备注册:vxbDevRegister(structure vxbDevRegInfo *pDevInfo)

显然,我们唯一要做的就是填充vxbDevRegIndo *pDevInfo结构体,其定义如下

struct vxbDevRegInfo

{

    struct vxbDevRegInfo * pNext;

    UINT32  devID;

    UINT32  busID;

    UINT32  vxbVersion;

    char    drvName[MAX_DRV_NAME_LEN+1];

    struct drvBusFuncs * pDrvBusFuncs;

    struct vxbDeviceMethod * pMethods;

    BOOL (*devProbe) ( struct vxbDev * pDevInfo);

    struct vxbParams * pParamDefaults;

};
参数解释:

1 VxBus下驱动的架构

1.1 WorkBench3.0的认识

Workbench3.0是VxWorks 6.x的集成开发环境,而VxWorks 5.5是采用Tornado2.2来进行开发的。Workbench3.0相比Tornado2.2来说提供了更为强大的功能,在Workbench3.0可以根据需要创建各种工程,常用的有以下几种VxWorks Image Projects,Boot Loader/BSP Projects,VxWorks Real-time Process Projects,VxWorks Downloadable Kernel ModuleProjects.

在进行驱动开发时需要创建VxWorks Image Projects。基于VxBus架构模型驱动在开发环境Workbench3.0中是以组件的形式体现的,这样的话就方便开发人员根据需要进行驱动的添加,重新编译VxWorks image后就可将驱动编进内核。开发人员只需将精力集中在驱动源码的编写上了。VxWorks5.5中没有VxBus架构,它的驱动的调用直接在BSP中的sysLIib.c中调用即可,这样开发的驱动可移植性不够好,当更换BSP时,又得重新移植。

关于Workbench3.0 的使用详见wr_workbench_vxworks_users_guide_3.0.pdf。

1.2 VxBus下驱动的结构以及编译

驱动源码结构

VxBus下驱源码主要由以下几个文件组成:
  • README
  • Makefile
  • driverName.cdf
  • driverName.dr
  • driverName.dc
  • driverName.c

1 README

关于驱动的说明文件

2 Makefile

驱动的编译规则

3 driverName.cdf

驱动的描述文件,里边包括的该驱动依赖的组件,驱动的位置,父目录以及子目录,在Workbench3.0下的说明信息等,很重要,若不正确,在Workbench3.0无法添加。

4 driverName.dr

向VxBus进行注册的函数。

5 driverName.dc

向VxBus进行注册的函数的声明。

6 driverName.c

驱动的核心文件,驱动源码基本结构如下(用CAN1000t.c来举例)

VxWorks 6.x引入了新的vxbus的驱动架构,对于用惯了VxWorks 5.x的朋友来说,确实有点不习惯,本文简单介绍如何在vxworks系统下使用vxbus,希望对于初学vxbus架构的朋友有所帮助!

开发步骤
  1. 添加新模块(这里会告诉vxworks该模块的入口函数)
  2. 填充vxbDevRegInfo,并通过vxbDevRegister进程注册驱动程序
  3. 通过向hcfDeviceList数组中添加记录,完成设备的注册
  4. Vxworks启动是会实例化hcfDeviceList中的设备(不必人工干预)
  5. 在vxbDevRegInfo中注册的几个初始化函数中添加实际的设备驱动代码

vxBus模块添加

VxVorks中采模块化的方式管理各个功能单元,驱动也是由一个或多个模块组成。VxBus是vxworks中的模块化机制。类似于linux中的module。通过vxBus我们可以方便的裁剪或添加新的模块。

模块的裁剪通常是在vxworks的开发环境workbench中进行的。建立一个工程后,会得到一个config文件,通过鼠标操作就可以实现模块的裁剪。

添加新模块则复杂一些,需要添加几个新的文件,但内容很简单,只是用来设置一些必须的信息。添加完成后,就可以像标准模块一样裁剪了。添加模块的详细过程可以再workbench中的vxbus的pdf文档中得到,说的很详细。

vxBus驱动注册过程

vxbus驱动的注册通过vxbDevRegister实现。其原型如下:

STATUS vxbDevRegister
    (
    struct vxbDevRegInfo * pDevInfo /* per-bus recognition info */
    )

显然,我们唯一要做的就是填充结构体pDevInfo,其类型定义如下:

struct vxbDevRegInfo
{
    struct vxbDevRegInfo * pNext;
    UINT32  devID;
    UINT32  busID;
    UINT32  vxbVersion;
    char    drvName[MAX_DRV_NAME_LEN+1];
    struct drvBusFuncs * pDrvBusFuncs;
    struct vxbDeviceMethod * pMethods;
    BOOL (*devProbe) ( struct vxbDev * pDevInfo);
    struct vxbParams * pParamDefaults;
};

devProbe用于设备probe设备。检测当前是否有该类型设备。如果不需要进行probe,则可以设为NULL。

pNext用于总线级联。如一个挂在网卡上的网卡,其phy通过mii与mac相间接。我们要访问phy,则需要先通过pci总线访问mac,在通过mii总线访问phy。有点类似先做汽车到县城,再转驴车到村子。这里的pNext就是告诉你下面该转驴车了。如果没有级联,则设为NULL。 pMethods用于提供了总线的各种方法,但实际上通常只提供该总线特有方法。因为通用方法,如open、read等,一般都是通过io层的system call调用的,他们需要单独注册。

pDrvBusFuncs提供了设备初始化需要的几个接口,一共有三个: