Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6269325
  • 博文数量: 2759
  • 博客积分: 1021
  • 博客等级: 中士
  • 技术积分: 4091
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-11 14:14
文章分类

全部博文(2759)

文章存档

2019年(1)

2017年(84)

2016年(196)

2015年(204)

2014年(636)

2013年(1176)

2012年(463)

分类: 嵌入式

2013-07-24 00:45:14

6.2.2 函数库usbdLib

USBD层是一个抽象层,如同USB规范里所示,USBD层将USB设备抽象为一个node,从而将系统与USB设备的交互变成了clientUSB node的交互。USBD层的实现可以两个子层:接口子层和实现子层。接口子层为上层提供了一系列的通用的接口,主要由函数库usbdLib来完成;而实现子层则是实现了通用的接口函数的功能,主要由函数库usbdCoreLib来实现。

其实在函数库usbdCoreLib层已经实现了一个通用的接口函数urbExecBlock,只是这个接口函数过于复杂,不利于上层的调用,因此usbdLib通过调用函数urbExecBlock实现了一系列通用的接口,从而避开了应用层与usbd层隔离开来。

这个函数库比较简单,大概描述一下。

1. LOCAL VOID urbInit

    (

    pURB_HEADER pUrb,

    USBD_CLIENT_HANDLE clientHandle,

    UINT16 function,

    URB_CALLBACK callback,

    pVOID userPtr,

    UINT16 totalLen

)

这个函数是利用参数来初始化一个URB结构。URB结构的将被用于通用接口函数的参数。

urbInit函数的参数有:

clientHandle:指明一个client

function:需要完成的功能;

callbackURB结束时调用;

userPtr:用户指定的指针;

totalLenURB结构的长度,通常是sizeofUSBD_URB

2. LOCAL VOID urbCallback

    (

    pVOID pUrb

)

该函数被urbExecBlock()函数指定为URB结构的回调函数去调用函数usbdCoreEntry,函数usbdCoreEntry在结束前调用该函数,用于同步。

3. LOCAL STATUS urbExecBlock

    (

    pURB_HEADER pUrb

)

这个函数也就是usbdLib函数库的核心。它负责初始化参数pUrb并以该参数调用函数usbdCoreEntry进行底层处理。

该函数有几个需要注意的地方:

l 信号量队列semPoolQueue是一个FIFO队列,只有从FIFO队列中取到msg才可能调用usbdCoreEntry函数,调用完毕后将信号量再重新存入FIFO中,这也就保证了系统中同时执行函数usbdCoreEntry的任务数不能超过MAX_SYNCH_SEM个(参见函数usbdInitialize)。

l 队列中的每个元素是一个信号量,这个信号量的作用是什么呢?但从代码上理解仅仅是为了确保URB执行完成,由于函数urbExecBlock直接调用函数usbdCoreEntry因此而这必然在同一个任务中,不存在调用之后函数还没有执行完毕的情况。个人感觉这段功能并无必要。

l 代码中我们看到,如果usbdCoreEntry (pUrb) = OK这时候不能确定函数usbdCoreEntry 是否调用函数OSS_SEM_GIVE ((SEM_HANDLE) ((pURB_HEADER) pUrb)->userPtr),因此需要调用函数OSS_SEM_TAKE ((SEM_HANDLE) msg.lParam, OSS_DONT_BLOCK)以确保在归还该信号量之前要把它恢复为原来使用前的状态(注意最后一个参数OSS_DONT_BLOCKusbdCoreEntry成功执行时调用的参数OSS_BLOCK不同)。

4. STATUS usbdInitialize (void)

初始化函数库usbdLib

初始化过程包括:

l 创建队列semPoolQueue(如图);

l 调用urbInit (&urb.header, NULL, USBD_FNC_INITIALIZE, NULL, NULL,sizeof (urb))urbExecBlock (&urb.header)完成usbdCoreLib的初始化

图6.12 函数usbdInitialize对变量semPoolQueue的初始化

5. STATUS usbdShutdown (void)

usbdInitialize函数的逆过程。先关闭usbdCoreLib层,然后再释放初始化函数分配的信号量队列空间,最后是关闭OSS函数库

注意:在释放信号量队列semPoolQueue的时候,首先要取得一个信号量,才能删除该信号量;删除所有的信号量后才能删除semPoolQueue指向的USB_QUEUE结构。而代码usbQueueGet (semPoolQueue, &msg, SYNCH_SEM_TIMEOUT) == OK这个条件容易造成内存的泄露。

6. STATUS usbdClientRegister 

    (

    pCHAR pClientName,

    pUSBD_CLIENT_HANDLE pClientHandle

)

调用urbExecBlock函数(参数USBD_FNC_CLIENT_REG)根据参数提供的pClientName生成一个USBD_CLIENT结构,并返回该结构的handle

7. STATUS usbdClientUnregister

    (

    USBD_CLIENT_HANDLE clientHandle

    )

调用urbExecBlock(参数USBD_FNC_CLIENT_UNREG,)删除一个clientHandle指定的USBD_CLIENT结构。

8. STATUS usbdMngmtCallbackSet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_MNGMT_CALLBACK mngmtCallback

    pVOID mngmtCallbackParam

)

为一个client设定一个management回调函数。

Management回调函数为USBD提供了一种手段来通知USB上的异步管理事件。比如如果USB处于SUSPEND状态时,有一个USB设备发出了RESUME信号,那么这个事件将会通过management 回调函数通知client

9. STATUS usbdBusStateSet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT16 busState

)

该函数允许一个client设置bus的状态(SUSPEND/RESUME),该总线由参数node指定(pNode->pBus)。

当设定一条busSUSPEND状态,必须清楚USBD不会自动将该bus恢复为RESUME状态,要想恢复为RESUME状态,还必须再次调用该函数(使用RESUME参数)。这对于一个USB remote wakeup”特性来说是很重要的,该特性允许一个远端设备驱动总线上的RESUME信号。Client正是通过management callback监控到该信号,并调用usbdBusStateSet函数来完成的。

同样,这个函数还是调用了urbExecBlock(实际上是usbdCoreLib)来完成的。

注意:client必须小心使用该函数,因为它会影响到一个bus的所有USB设备,从而影响到和这些设备通信的所有clients

10. STATUS usbdBusCountGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    pUINT16 pBusCount

)

该函数是为了获取链接到系统中的所有USB host 控制器的数目。根据USB规范,每个host controller都有自己的root hub

系统中的HC的数目不是固定的,它可以通过usbdHcdAttach()函数和usbdHcdDetach()函数来修改。

11. STATUS usbdRootNodeIdGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    UINT16 busIndex,

    pUSBD_NODE_ID pRootId

)

该函数是为了找到一个HCroot  hub 对应的nodeIDbusIndex指的是hcdList链上USBD_HCD结构的下标。

12. STATUS usbdHubPortCountGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID hubId,

    pUINT16 pPortCount

)

通过urbExecBlock接口调用usbdCoreLib库的fncHubPortCountGet函数。该函数可以得到一个hub设备的port数目。

13. STATUS usbdNodeIdGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID hubId,

    UINT16 portIndex,

    pUINT16 pNodeType,

    pUSBD_NODE_ID pNodeId

)

获取一个hub的指定端口连接的设备的nodeId

14. STATUS usbdNodeInfoGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    pUSBD_NODE_INFO pNodeInfo,

    UINT16 infoLen

)

获取一个node的信息。该信息保存在USBD_NODE结构的nodeInfo元素当中。

15. STATUS usbdDynamicAttachRegister

    (

    USBD_CLIENT_HANDLE clientHandle,

UINT16 deviceClass,

    UINT16 deviceSubClass,

    UINT16 deviceProtocol

    USBD_ATTACH_CALLBACK attachCallback

)

该函数由client来调用执行,目的是告诉USBD:当USBD发现一个deviceClass/deviceSubClass/deviceProtocol的设备插拔时,通知该client

16. STATUS usbdDynamicAttachUnRegister

    (

    USBD_CLIENT_HANDLE clientHandle,

    UINT16 deviceClass,

    UINT16 deviceSubClass,

    UINT16 deviceProtocol,

    USBD_ATTACH_CALLBACK attachCallback

)

通知USBD当有deviceClass/deviceSubClass/deviceProtocol类型的设备插拔的时候不再通知该client

17. STATUS usbdFeatureClear

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT16 requestType,

    UINT16 feature,

    UINT16 index

)

清除USB feature

18. STATUS usbdFeatureSet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT16 requestType,

    UINT16 feature,

    UINT16 index

)

设定USB  feature

19. STATUS usbdConfigurationGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    pUINT16 pConfiguration

)

获取USB设备的配置信息,配置信息保存在pConfiguration地址当中。

20. STATUS usbdConfigurationSet

    (

    USBD_CLIENT_HANDLE clientHandle, /* Client handle */

    USBD_NODE_ID nodeId, /* Node Id of device/hub */

    UINT16 configuration, /* New configuration to be set */

    UINT16 maxPower /* max power this config will draw */

)

设定一个USB设备的配置信息。

21. STATUS usbdDescriptorGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT8 requestType,

    UINT8 descriptorType,

    UINT8 descriptorIndex,

    UINT16 languageId,

    UINT16 bfrLen,

    pUINT8 pBfr,

    pUINT16 pActLen

)

获取一个USB设备(nodeId)的描述符信息。

22. STATUS usbdDescriptorSet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT8 requestType,

    UINT8 descriptorType,

    UINT8 descriptorIndex,

    UINT16 languageId,

    UINT16 bfrLen,

    pUINT8 pBfr

)

设置USB设备的描述符信息。

23. STATUS usbdInterfaceGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT16 interfaceIndex,

    pUINT16 pAlternateSetting

)

获取一个USB设备的interface信息。

24. STATUS usbdInterfaceSet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT16 interfaceIndex,

    UINT16 alternateSetting

)

设置一个USB设备的interface信息。

25. STATUS usbdStatusGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT16 requestType,

    UINT16 index,

    UINT16 bfrLen,

    pUINT8 pBfr,

    pUINT16 pActLen

)

询问一个USB设备的状态。

26. STATUS usbdAddressGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    pUINT16 pDeviceAddress

)

获取一个设备的地址。

27. STATUS usbdAddressSet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT16 deviceAddress

)

设置一个USB设备的地址。

28. STATUS usbdVendorSpecific

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT8 requestType,

    UINT8 request,

    UINT16 value,

    UINT16 index,

    UINT16 length,

    pUINT8 pBfr,

    pUINT16 pActLen

)

该函数允许设备发出设备特殊的USB请求。

特定的USB设备会有一些特殊的USB请求,这些请求不能用标准的USB功能来完成,因此就需要为client提供一个函数向该USB设备的控制pipe直接发送请求。

29. STATUS usbdPipeCreate

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT16 endpoint,

    UINT16 configuration,

    UINT16 interface,

    UINT16 transferType,

    UINT16 direction,

    UINT16 maxPayload,

    UINT32 bandwidth,

    UINT16 serviceInterval,

    pUSBD_PIPE_HANDLE pPipeHandle

)

创建一个USBD_PIPE

nodeId:指明了设备

endpoint:指明了设备的endpoint,而pipe正是在client和一个设备的endpoint之间建立的。而configurationinterface正指定了设备的配置和接口。

transferType:传输类型:controlBULK

direction:指明pipe传输的方向:IN/OUT/INOUT。一个pipe的方向特性是不会改变的。INOUT仅仅用于control Pipe

maxPayload:该endpoint支持的最大payload。这个数值通常在设备的配置描述符中都标明了,因此这个参数是USBD首先从USB设备读取了配置描述符之后才直接将这个数值作为参数传递。

bandwidth:对controlbulk pipe来说,bandwidth0;对interrupt pipe来说该数值为每frame要传输的字节数;对isochronous pipebandwidth指的是每秒钟传输的字节数。

serviceInterval:仅适用于中断传输pipe,标明该pipe的最大潜伏期(latency,单位毫秒)。如果一个设备的serviceInterval数值为20,说明该设备没20毫秒需要服务一次。

pPipeHandle:创建的PIPEhandle

30. STATUS usbdPipeDestroy

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_PIPE_HANDLE pipeHandle

)

Destroys 一个USB传输pipe

31. STATUS usbdTransfer

    (

    USBD_CLIENT_HANDLE clientHandle, /* Client handle */

    USBD_PIPE_HANDLE pipeHandle, /* Pipe handle */

    pUSB_IRP pIrp /* ptr to I/O request packet */

    )

client使用该函数来启动一个指定pipe上的传输。传输是由一个IRP结构或一个I/O request packet来描述的,该IRP结构或者I/O request packet必须在调用usbdTransfer()函数前被分配并初始化。

32. STATUS usbdTransferAbort

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_PIPE_HANDLE pipeHandle,

    pUSB_IRP pIrp

)

终止一个USB传输。

33. STATUS usbdSynchFrameGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT16 endpoint,

    pUINT16 pFrameNo

)

获取一个设备的isochronous同步帧。当client和一个USB设备之间利用isochronous pipe进行数据传输的时候,USB设备会记录本次传输开始的帧号,如果出现了错误,client需要调用此函数恢复帧号,以方便重新传输。这个函数通过一个control request实现。参见USB规范9.4.11

34. STATUS usbdCurrentFrameGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    pUINT32 pFrameNo,

    pUINT32 pFrameWindow

)

获取一个USB设备(nodeId)所在的USB总线上的当前帧的帧号。

如果参数pFrameWindow有效,USBD也会返回指定host controller的最大帧调度窗口。帧调度窗口是由USB host controller跟踪的,多数USB host controller维护了一个10bit或者11bit的内部帧计数器。当我们进行isochronous传输时,一个client有时需要明确此次传输是从那个帧号开始的。对给定的USB host controller来说,起始帧号应该是介于当前帧号和frameWindow 帧之间的一个数值。

注意:USBD能够同时管理多个USB host controller,每个host controller都是独立的。因此指定正确的nodeId是很重要的。nodeId确定了所在的总线,也确定了host controller

35. STATUS usbdSofMasterTake

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId

)

isochronous传输中,有时候client需要调整usb frame的时间长度,这时候只有当client成为master client的时候才能够进行调整,一个usb总线只能有一个master client,别的client只有当当前的master client释放master权利的时候才能够成功申请成为新的masterclient

36. STATUS usbdSofMasterRelease

    (

    USBD_CLIENT_HANDLE clientHandle, /* Client handle */

    USBD_NODE_ID nodeId  /* Node Id of node on desired USB */

)

一个client放弃自己对USB总线的master地位,之后其他client就可以申请成为一个新的master

37. STATUS usbdSofIntervalGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    pUINT16 pSofInterval

)

获取总线的SOF间隔,也就是帧的长度。这个数值保存在nodeId所在总线的USBD_BUS结构的sofInterval元素当中。

38. STATUS usbdSofIntervalSet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    UINT16 sofInterval

)

设定总线的SOF间隔,也就是帧的长度。这个数值保存在nodeId所在总线的USBD_BUS结构的sofInterval元素当中。

39. STATUS usbdVersionGet

    (

    pUINT16 pVersion,

    pCHAR pMfg

)

返回USBD的版本,及相关的说明字符串。和USBD有关,宏定义。

40. STATUS usbdHcdAttach

    (

    HCD_EXEC_FUNC hcdExecFunc,

    pVOID param,

    pGENERIC_HANDLE pAttachToken

)

多数系统在系统初始化的时候调用此函数,以便register一个或者多个HCD

usbdHcdAttach函数是usbdLib函数库中为数不多的不需要首先调用usbdClientRegister()函数就可以使用的一个函数,因此也就不需要向该函数传输一个USBD_CLIENT_HANDLE参数。

41. STATUS usbdHcdDetach

    (

    GENERIC_HANDLE attachToken

)

USBDdetach一个HCD

42. STATUS usbdStatisticsGet

    (

    USBD_CLIENT_HANDLE clientHandle,

    USBD_NODE_ID nodeId,

    pUSBD_STATS pStatistics,

    UINT16 statLen

)

获取指定USBD_BUS上的统计数据。在pBus->stats数据结构中保存。

阅读(821) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~