基于VxWorks的VxBus字符设备驱动

基于VxWorks的VxBus字符设备驱动
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

{undefined

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;

};

参数解释:

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

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
{undefined
DEV_HDR devHdr;
int ix; /设备驱动号/
SEL_WAKEUP_LIST selWakeupList;
BOOL Opened;
Bool ReadyToRead;
Bool ReadyToWrite;
}xxx_DEV

/DEV_HDR 是用于创建设备链表的系统定义结构,如下所示/
typedef struvcr /设备头数据结构/

{undefined
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 文件,提供建立驱动的编译规则。
helloWorld驱动实例
vxb335xHello.c

/**
 *  @file       vxb335xHello.c
 *  
 *  @brief      GPIO控制按键驱动
 *
 *  @version    1.00
 *  
 *  @author     liwanneng
 *          
 *  @date       2017.7.24
 *  
 *  @copyright  liwanneng
 *
 *  @details    
 *
 *  @history    2017.7.24 liwanneng 创建
 *  @todo
 *     
 *  @attention
 *      
 *  @see        
 */


/******************************************************************************
**                                  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 不需要虚拟内存物理内存的映射,所以实现起来简单多了

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值