vxWorks中USB驱动栈-2

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

vxWorks中USB驱动栈-2_第1张图片

    风河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的,并描述了目标层的内部组成:

 

vxWorks中USB驱动栈-2_第2张图片

 

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

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_FUNC	mngmtFunc; /* management callback */
/* Control pipe callbacks */
USB_TARG_FEATURE_CLEAR_FUNC		featureClear;	/* feature clear */
USB_TARG_FEATURE_SET_FUNC		featureSet;	/* feature set */
USB_TARG_CONFIGURATION_GET_FUNC	configurationGet; /*configuration get*/
USB_TARG_CONFIGURATION_SET_FUNC	configurationSet; /*configuration set*/
USB_TARG_DESCRIPTOR_GET_FUNC	descriptorGet;	/* descriptor get */
USB_TARG_DESCRIPTOR_SET_FUNC	descriptorSet;	/* descriptor set */
USB_TARG_INTERFACE_GET_FUNC		interfaceGet;	/* interface get */
USB_TARG_INTERFACE_SET_FUNC		interfaceSet;	/* interface set */
USB_TARG_STATUS_GET_FUNC		statusGet;	/* status get */
USB_TARG_ADDRESS_SET_FUNC		addressSet;	/* address set */
USB_TARG_SYNCH_FRAME_GET_FUNC	synchFrameGet;	/* frame get */
USB_TARG_VENDOR_SPECIFIC_FUNC	vendorSpecific;	/* 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_PIPE	pipeHandle;	/* pipe handle information */
    pVOID		pHalPipeHandle;	/* HAL specific pipe handle */
    pTARG_TCD		pTargTcd;       /* 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指向控制数据。

你可能感兴趣的:(callback,interface,Descriptor,Allocation,structure,Pointers)