vxWorks中USB驱动栈-2

来源:互联网 发布:百度云盘网络证书无效 编辑:程序博客网 时间:2024/05/16 05:22

接上篇文章 介绍完了Host,再来看下Peripheral驱动栈,下图为Peripheral驱动栈的结构图:

    风河USB Peripheral驱动栈中,位于底层的是目标控制器TC,它是Peripheral栈中用于连接USB的硬件部分。对于每种类型的TC,都会有对应的TCD,风河提供了Freescale Dual Role、NetChip NET2280、PDIUSBD12和PhilipsIsp1582四种TCD,它们的功能主要包括:

1、实现任何硬件相关的功能;

2、实现寄存器访问,USB Peripheral栈的其它层都不允许实现寄存器访问;

3、为与栈中上层通讯提供entry point。

    在这之上就又是HAL(Hardware Adaptation Layer),该层为驱动栈中的更上层提供了硬件独立的访问方式,使得整个驱动栈更容易移植到新的TC硬件上。target layer的功能与之类似,也是一个抽象的中介物。在运行时,目标应用程序会命令目标层Attach一个TCD,之后目标层就负责TCD与目标应用程序间的请求及回应,它可以同时处理多个TCD与应用程序的通讯。所以,这部分的重点就分布在目标层和TCD上。

    先看目标层,下图显示了目标层是如何串联应用层和HAL的,并描述了目标层的内部组成:

 

 

    要通过该层实现通讯,初始化代码和应用程序需要经过以下几步:

1、初始化目标层:和USB Host栈类似,这里有一个初始化代码usbTargInitialize,主要功能也是初始化OS库、创建句柄和互斥访问量,同样的嵌套式调用,所以需要至少调用一次。

2、实现必须的callback函数:目标层有一个callback表,列举了应用程序中所有的功能入口函数。一但TCD与之attach成功,目标层会通过这些入口执行异步回调。所以在第3步开始前,应用程序会根据表中的入口函数将对应的功能函数指针与之对应。回调表的原型定义在usbTargLib.h中,定义如下:

typedef struct usbTargCallbackTable  /* USB_TARG_CALLBACK_TABLE */{/* device management callbacks */USB_TARG_MANAGEMENT_FUNCmngmtFunc; /* management callback *//* Control pipe callbacks */USB_TARG_FEATURE_CLEAR_FUNCfeatureClear;/* feature clear */USB_TARG_FEATURE_SET_FUNCfeatureSet;/* feature set */USB_TARG_CONFIGURATION_GET_FUNCconfigurationGet; /*configuration get*/USB_TARG_CONFIGURATION_SET_FUNCconfigurationSet; /*configuration set*/USB_TARG_DESCRIPTOR_GET_FUNCdescriptorGet;/* descriptor get */USB_TARG_DESCRIPTOR_SET_FUNCdescriptorSet;/* descriptor set */USB_TARG_INTERFACE_GET_FUNCinterfaceGet;/* interface get */USB_TARG_INTERFACE_SET_FUNCinterfaceSet;/* interface set */USB_TARG_STATUS_GET_FUNCstatusGet;/* status get */USB_TARG_ADDRESS_SET_FUNCaddressSet;/* address set */USB_TARG_SYNCH_FRAME_GET_FUNCsynchFrameGet;/* frame get */USB_TARG_VENDOR_SPECIFIC_FUNCvendorSpecific;/* vendor specific */} USB_TARG_CALLBACK_TABLE, *pUSB_TARG_CALLBACK_TABLE;

    具体各函数及其参数的介绍见《Wind River USB Programmer’s Guide》第5.5节。

3、Attach一个TCD:在目标程序能从host收发指令之前,初始化代码还必须将自己和TCD attach起来,使用函数usbTargTcdAttach,该函数原型如下:

usbTargTcdAttach (USB_TCD_EXEC_FUNC tcdExecFunc, pVOID tcdParam,

                                pUSB_TARG_CALLBACK_TABLE pCallbacks,

                                pVOID callbackParam,

                                pUSB_TARG_CHANNEL pTargChannel);

    需要传入的参数包括TCD的Single Entry Point指针,TCD-defined属性值,目标应用程序callback表的指针以及callback函数的参数。当目标控制器TC成功的attach到TCD后,TCD会返回自己的句柄,保存在USB_TARG_CHANNEL中,应用程序可以通过该句柄与TCD进行接下来的通讯。在HAL层,函数会调用usbHalTcdAttach真正与TCD连接上,该函数主要源码如下:

/* 初始化数据结构TRB (Target Request Block) - Start */trbHeaderInit((pTRB_HEADER)&trbAttach, NULL, TCD_FNC_ATTACH, sizeof(TRB_ATTACH));trbAttach.tcdParam = tcdParam;trbAttach.usbHalIsr = (USB_HAL_ISR_CALLBACK)usbHalIsr;trbAttach.usbHalIsrParam = pUsbHal;trbAttach.pHalDeviceInfo = &pUsbHal->halDeviceInfo;trbAttach.pDeviceInfo = pDeviceInfo;/*End *//* Call the single entry point for the TCD */status = (*tcdExecFunc)(&trbAttach);/* Check if the function is executed successfully */if (status != OK){/* WindView Instrumentation */ USB_HAL_LOG_EVENT(….);   USBHAL_ERR (….);/* Call the function to free the HAL TCD resources */usbHalFreeTCDResources(pUsbHal);return ERROR;}/* 将TCD句柄存在HAL 结构体中 */pUsbHal->pTCDHandle = trbAttach.header.handle;/* 为指针分配内存Allocate memory for the array of pointers */pUsbHal->pPipeInfo = (pUSBHAL_PIPE_INFO *)            OSS_CALLOC(sizeof(pUSBHAL_PIPE_INFO) *    pUsbHal->halDeviceInfo.uNumberEndpoints);/* Check if memory allocation is successful */if (pUsbHal->pPipeInfo == NULL){    /*处理内存分配失败的释放TCD代码,同上面的status != OK,略去*/……   }/* 下面向TCD中存数据*//*Store the single entry point in the TCD data structure */pUsbHal->tcdExecFunc = tcdExecFunc;/* Store the management callback in the TCD data structure */pUsbHal->mngmtCallback = mngmtCallback;/* Store the management callback parameter in the TCD data structure */pUsbHal->mngmtCallbackParam = mngmtCallbackParam;* Store the HAL TCD pointer in the pNexus data structure */pNexus->handle = pUsbHal;

4、使能该TCD:在attach成功后,应用程序会调用usbTargEnable使能TCD,和第三步的attach类似,此时TCD也会使能底层的目标控制器,HAL会通过TCD_FNC_ENABLE执行TCD的single entry point(usbHalTcdEnable)。

5、创建管道pipes:上层应用程序会调用函数usbTargPipeCreate创建管道,管道的信息存储在结构体TARG_PIPE中,定义如下:

typedef struct targPipe/* TARG_PIPE */{    USB_TARG_PIPEpipeHandle;/* pipe handle information */    pVOIDpHalPipeHandle;/* HAL specific pipe handle */    pTARG_TCDpTargTcd;       /* pointer to targ_tcd data structure*/} TARG_PIPE, *pTARG_PIPE;

    pipeHandle只是管道的标示符,用于应用程序执行USB传输到终端;pHalPipeHandle是HAL信息的指针,用于在目标层中的内部记录,只要管道创建成功,指向结构体USB_HAL_PIPE_INFO的指针就会被存在该句柄中;

6、传输数据:数据的传输有两种形式,通用的和控制的。前者使用目标层函数usbTargTransfer实现USB外围驱动栈与主机间的数据传输;而如果应用程序要通过默认控制管道与主机通信,即为后者,需调用usbTargControlResponseSendusbTargControlStatusSendusbTargControlPayloadRcv三个函数。usbTargTransfer函数通过pipeHandle初始化一个管道上的传输,需要传输的数据用结构体USB_ERP描述,结构体定义如下:

typedef struct usb_erp    {    LINK targLink;/* 应用程序用它存储通过将USB_ERP转换为LINK后的ERP列*/    pVOID targPtr;/*用于控制型传输,指定TARG_TCD的指针*/    LINK tcdLink;/*HAL用于保存传递给TCD的ERP列*/    pVOID tcdPtr;/*当HAL需发送一个零长度的包时需要,指向TCD */    pVOID userPtr;/* Ptr field for use by client */    UINT16 erpLen;/* ERP structure的长度*/    int result; /* ERP 完成结果: S_usbTcdLib_xxxx */    ERP_CALLBACK targCallback;/* usbTargLib completion callback routine */    ERP_CALLBACK userCallback;/* client's completion callback routine */    pVOID pPipeHandle; /* Pipe handle */    UINT16 transferType;/* Type of ERP: control, bulk, etc. */    UINT16 dataToggle;/* ERP should start with DATA0/DATA1. */    UINT16 bfrCount;/* Indicates count of buffers in BfrList */    UINT16 endpointId;/* device endpoint */     /* Added for complaince with the old stack */    USB_BFR_LIST bfrList [1];    } USB_ERP, *pUSB_ERP;

    至于后者,目标应用程序用usbTargControlResponseSend发送控制管道回应主机用usbTargControlResponseSend发出的请求,应用程序在处理主机发送的各种Control-IN请求时都会利用之前发送的数据。例如,一个GET_DESCRIPTOR请求,应用程序会调用API发送回应数据来响应主机的请求。usbTargControlStatusSend用于当控制传输没有数据段时向主机发送状态;usbTargControlPayloadRcv用于注册一个回调函数接收主机发来的控制管道回应,接收到回应后,回调函数就会被调用,pBfr指向控制数据。

原创粉丝点击