作者:Escorpion
VxBus是指在 VxWorks 中用于支持设备驱动的特有的架构,这种架构包含对minimal BSP的支持。它包括以下功能:
- 允许设备驱动匹配对应设备
 - 提供驱动程序访问硬件的机制
 - 软件其他部分访问设备功能
 - 在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;
};
参数解释:
struct drvBusFuncs
{
    void (*devInstanceInit) (struct vxbDev *);
    void (*devInstanceInit2) (struct vxbDev *);
    void (*devInstanceConnect) (struct vxbDev *);
};
devInstanceInit在kernel初始化前被调用,如果这个设备或它的一部分是kernel要用到的,就要放在这里。devInstanceInit2在kernel初始化后被调用,没有什么特别要求的话,初始化最好都放在这里。当然如果该设备特别重要,其他设备需要调用它,一般也会放到devInstanceInit中,因为各个设备之间的调用devInstanceInit时不保证前后顺序。devInstanceConnect用于设备的连接,通常可以不使用,但如果它依赖于其他设备,则可以把启动代码放在这里。如果实在不需要,可以都置为NULL。
系统接口函数
对于字符设备驱动来说,需要实现的仅为I/O系统所需要的接口,即 create, open, read, write, close, ioctl, delete 7个接口函数, I/O系统在与这些接口通信的时候都有规定的参数,其中最重要的就是设备的数据结构。这个数据结构会在设备打开时返回给系统,用于I/O系统与驱动之间的数据交换。
一个典型的设备的数据结构定义为:
typedef struct 
{
    DEV_HDR   devHdr;
    int ix; /*设备驱动号*/
    SEL_WAKEUP_LIST selWakeupList;
    BOOL Opened;
    Bool ReadyToRead;
    Bool ReadyToWrite;
}xxx_DEV
/*DEV_HDR 是用于创建设备链表的系统定义结构,如下所示*/
typedef struvcr /*设备头数据结构*/
{
    DL_NODE node; /*设备链表节点*/
    short drvNum; /*设备所对应的驱动索引号*/
    cha *name;  /*设备名称*/
}
用链表将设备管理起来,I/O系统只需要完成对链表的增删改查即可以完成对设备的添加和修改
heloWorld驱动实例
驱动程序的配置
采用VxBus驱动的一个主要优点是:设备的驱动程序可以被看成VxWorks 系统的一个组件,通过集成的Workbench开发环境来配置设备驱动。PCI1304数据采集卡需要有以下文件:
- 一个驱动源文件vxb335xHello.c,执行驱动运行逻辑,包括Hello驱动的实现代码
 - 一个组件描述文件vxb335xHello.cdf,允许集成驱动到VxWorks开发工具Workbench当中
 - 一个vxb335xHello.dc文件,提供驱动注册函数原型
 - 一个vxb335xHello.dr文件,提供一个调用注册函数的C语言代码段
 - 一个readme文件 ,提供版本信息
 - 一个makefile 文件,提供建立驱动的编译规则
 
vxb335xHello.c
 
 
 
/****************************************************************************** 
** includes 
******************************************************************************/ 
 
 
#include "vxWorks.h" 
#include "stdio.h" /* for printf() */ 
#include "logLib.h" /* for logMsg() */ 
#include "string.h" /* for strcmp() */ 
 
#include "vxBusLib.h" /* for VXB_DEVICE_ID */ 
#include "hwif/vxbus/vxBus.h" 
#include "hwif/util/hwMemLib.h" /* for hwMemAlloc() */ 
#include "hwif/vxbus/hwConf.h" /* for devResourceGet() and 
                                        * hcfDeviceGet() 
                                    */ 
#include "driverControl.h" /* for struct vxbDriverControl */ 
 
#include "../pmcConfig.h" 
#include "vxb335xHello.h" 
 
//extern void getUnixTime(UNIX_CLOCK_STRUCT *time); 
 
/********************************************************************************* 
** GLOBAL VARIABLE DEFINITIONS 
*********************************************************************************/ 
 
LOCAL int g_helDrvNum = 0; /* 驱动程序索引号 */ 
//LOCAL SEM_ID g_semLedM; /* gpioLed互斥信号量 */ 
 
 
/********************************************************************************* 
** MACRO DEFINITIONS 
*********************************************************************************/ 
 
#define HELLO_DEVICE_NAME "/hello"  
 
 
 
/********************************************************************************* 
** FUNCTION DECLARATIONS 
*********************************************************************************/ 
 
LOCAL void helInstInit(VXB_DEVICE_ID pInst); 
LOCAL void helInstInit2(VXB_DEVICE_ID pInst); 
LOCAL void helInstConnect(VXB_DEVICE_ID pInst); 
 
//void helAm335xShow( VXB_DEVICE_ID pDev); 
LOCAL int helDrvOpen(DEV_HDR *pHelDevHdr, int option, int flags); 
LOCAL int helDrvClose(int helDevId); 
LOCAL STATUS helDrvIoctl(int helDevId, int cmd, int arg); 
LOCAL STATUS helWrite(int helDevId, int *pBuf, int len); 
LOCAL STATUS helRead(int helDevId, int *pBuf, int len); 
 
/********************************************************************************* 
** VxBus 驱动框架  
*********************************************************************************/ 
 
 
/* VXB初始化设备调用程序 */ 
LOCAL struct drvBusFuncs helFuncs = 
{ 
    helInstInit, /* devInstanceInit */ 
    helInstInit2, /* devInstanceInit2 */ 
    helInstConnect /* devConnect */ 
}; 
 
LOCAL struct vxbDeviceMethod helMethods[ ] = 
{ 
    { 0, 0} 
}; 
 
/*diver rigister info*/ 
LOCAL struct vxbDevRegInfo helDevRegistration = 
{ 
    NULL, /* pNext */ 
    VXB_DEVID_DEVICE, /* devID */ 
    VXB_BUSID_PLB, /* busID = PLB */ 
    VXB_VER_5_0_0, /* vxbVersion */ 
    "hello", /* drvName */ 
    &helFuncs, /* pDrvBusFuncs */ 
    helMethods, /* pMethods */ 
    NULL, /* devProbe */ 
    NULL /* pParamDefaults */ 
}; 
 
 
/********************************************************************************* 
** DRIVER FUNCTIONS  
*********************************************************************************/ 
 
 
/******************************************************************************* 
* 
* gpioLedRegister - register GpioLed driver 
* 
* This routine registers the GpioLed driver and device recognition 
* data with the vxBus subsystem. 
* 
* RETURNS: N/A 
* 
* ERRNO 
*/ 
void am335xHelRegister(void) 
    { 
    vxbDevRegister((struct vxbDevRegInfo *)&helDevRegistration); 
    } 
 
/******************************************************************************* 
* 
* GpioLedInstInit - initialize GpioLed device 
* 
* This is the wrsample initialization routine. 
* 
* RETURNS: N/A 
* 
* ERRNO 
*/ 
 
LOCAL void helInstInit  
( 
    VXB_DEVICE_ID pInst 
) 
{ 
    return; 
} 
 
/******************************************************************************* 
* 
* GpioLedInstInit2 - initialize GpioLed device 
* 
* This is seconde phase initialize routine for VxBus driver.  
* 
* RETURNS: N/A 
* 
* ERRNO 
*/ 
LOCAL void helInstInit2 
 ( 
    VXB_DEVICE_ID pInst 
 ) 
 { 
    HEL_DEV * pDrvCtrl; 
 
    /* to store the HCF device */ 
    HCF_DEVICE * pHcf = NULL;  
 
    /* check for vaild parameter */ 
    if (pInst == NULL) 
        return; 
 
    /* allocate the memory for the structure */ 
    pDrvCtrl = (HEL_DEV *)malloc(sizeof(HEL_DEV)); 
 
    /* check if memory allocation is successful */ 
    if (pDrvCtrl == NULL) 
        return;  
 
    /* get the HCF device from vxBus device structure */ 
    pHcf = hcfDeviceGet (pInst); 
 
    /* if pHcf is NULL, no device is present */ 
    if (pHcf == NULL) 
        return; 
 
    /* per-device init */ 
    pInst->pDrvCtrl = pDrvCtrl; 
 } 
 
/******************************************************************************* 
* 
* gpioInstConnect - VxBus connect phase routine for Gpio driver 
* 
* This is connect phase routine. 
* 
* RETURNS: N/A 
* 
* ERRNO: not set 
*/ 
 
 
LOCAL void helInstConnect 
( 
    VXB_DEVICE_ID pInst 
) 
{ 
    HEL_DEV * pDrvCtrl; 
 
    pDrvCtrl = pInst->pDrvCtrl; 
 
    logMsg("debug:helInstConnect entered.\n",0,0,0,0,0,0); 
    if(pDrvCtrl == NULL) 
    { 
        // GPIO_DBG_MSG(2,"HelInstConnect: pDrvCtrl is NULL, pDev is 0x%x\n", pInst,1,2,3,4,5); 
        return; 
    } 
 
 
 
    /*注册驱动*/ 
    if((g_helDrvNum = iosDrvInstall( helDrvOpen, (FUNCPTR) NULL, helDrvOpen, 
                                    (FUNCPTR) helDrvClose, helRead, helWrite, helDrvIoctl )) < 0) 
    { 
        logMsg("debug:iosDrvInstall failed.\n",0,0,0,0,0,0); 
        return; 
    } 
 
 
    /* 添加设备 */ 
    if(iosDevAdd(&pDrvCtrl->devHdr, HELLO_DEVICE_NAME, g_helDrvNum)) 
    { 
        free((char *)pDrvCtrl); 
        return ; 
    } 
 
    return;  
} 
 
 
/******************************************************************************* 
* 
* gpioDrvOpen - open Gpio 
* 
*/  
LOCAL int helDrvOpen 
( 
    DEV_HDR *pHelDevHdr, 
    int option,  
    int flags 
) 
{ 
    HEL_DEV *pHelDev = (HEL_DEV *)pHelDevHdr; 
    if(pHelDev == NULL) 
    { 
        return ERROR; 
    } 
 
    return ((int)pHelDevHdr); 
} 
 
 
/******************************************************************************* 
* 
* gpioDrvClose - close Gpio 
* 
*/  
 
LOCAL int helDrvClose 
( 
    int helDevId 
) 
{ 
    HEL_DEV *pHelDev = (HEL_DEV *)helDevId; 
    if(pHelDev == NULL) 
    { 
        return ERROR; 
    } 
 
    return((int)helDevId); 
} 
 
/******************************************************************************* 
* 
* gpioRead -  
* 
*/ 
 
LOCAL STATUS helRead 
( 
    int helDevId, 
    int *pBuf,  
    int len 
) 
{ 
    return OK; 
} 
 
/******************************************************************************* 
* 
* gpioWrite -  
* 
*/ 
 
LOCAL STATUS helWrite 
( 
    int helDevId,  
    int *pBuf,  
    int len 
) 
{ 
    return OK; 
} 
 
/******************************************************************************* 
* 
* gpioDrvIoctl - special device control 
* 
* RETURNS: OK or ERROR. 
*/ 
 
LOCAL STATUS helDrvIoctl 
( 
    int helDevId,  
    int cmd,  
    int arg 
) 
{ 
    switch((HEL_CTL)cmd) 
    { 
        case HEL_WRITE:  
            logMsg("ioctl write in kernel.\n",0,0,0,0,0,0); 
            break; 
        case HEL_READ: 
            logMsg("ioctl read in kernel.\n",0,0,0,0,0,0); 
            break; 
        default: 
            return ERROR; 
    } 
 
    return OK; 
 
} 
 
 
vxb335xHello.cdf文件
/**********************************************************************
*
* sample 3rd-party VxBus driver provided by Wind River
*
*/
Component DRV_AM335X_HEL {
        NAME            AM335X HELLO VxBus driver
        SYNOPSIS        AM335X HELLO VxBus driver provided by ceiec
        REQUIRES        INCLUDE_VXBUS \
                        INCLUDE_PLB_BUS
        MODULES         vxb335xHello.o
        PROTOTYPE       void am335xHelRegister(void);
        INIT_RTN        am335xHelRegister();
        INIT_AFTER      INCLUDE_PLB_BUS
        _INIT_ORDER     hardWareInterFaceBusInit
        _CHILDREN       FOLDER_DRIVERS
}
vxb335xHello.dc文件
IMPORT void am335xHelRegister(void);
vxb335xHello.dr文件
#ifdef DRV_AM335X_HEL
    am335xHelRegister();
#endif /* DRV_AM335X_HEL */
hwconfig.c中添加设备列表
完成上述驱动之后,在hwconfig.c中添加设备列表以及硬件信息
如果需要增加一个设备,需要在hwconfig.c中的设备列表即hcfDeviceList数组添加设备信息,这个数组中列有本系统中所有需要初始化的硬件设备。例如:
 HCF_DEVICE hcfDeviceList[] = {
  #ifdef DRV_AM335X_HEL
    { "hello",           0, VXB_BUSID_PLB, 0, vxbHelNum,    vxbHelResources},
  #endif
在参数中指明了它的名字“hello”,初始化的时候根据这个名字去搜索驱动。它的unit是0,初始化结束以后,会在设备列表中看到这个unit number。vxbHelResources是前面定义的一组资源。 对于单核CPU,配置到这里就结束了。如果是多核,还需要修改一下sysDeviceFilter,这个函数决定一个设备在哪个核上初始化。如果还有hypervisor,还需要修改wrhvConfig.xml和vxworksX.xml,将特定的终端放开到指定的核。
我们这里只需要添加设备列表和硬件信息就可以了。如下:
/* Hello驱动硬件信息*/
#ifdef DRV_AM335X_HEL
const struct hcfResource vxbHelResources[] = {
    { "regBase",        HCF_RES_INT, { (void *)0} },
};
#define vxbHelNum NELEMENTS(vxbHelResources)
#endif
/*添加设备对设备链表*/
#ifdef DRV_AM335X_HEL
    { "hello",           0, VXB_BUSID_PLB, 0, vxbHelNum,    vxbHelResources},
#endif
VxBus的驱动相比 Linux 不需要虚拟内存物理内存的映射,所以实现起来简单多了。