VxWorks驱动开发原理 USB驱动 5

6.2.4 函数库usrUsbHcdOhciInit

HCD层主要用于HC的管理控制,并为USBD层提供了统一的函数控制接口。

从硬件结构来数,HC是一种PCI设备,类似于PCI网卡。与PCI网卡相比,除了USB接口与网线的区别之外,还存在一个区别:PCI网卡的硬件接口都随着生产商的不同而不同,而HC设备的生产商生产的产品都必须严格遵照OHCI或者UHCI规范,因此从软件上来说只需要提供了OHCI和UHCI规范的软件接口,就可以为所有的HC提供驱动。本章将以OHCI为例对HCD层详细加以分析。

因此HCD主要包括以下几个部分:PCI配置部分、OHCI实现部分以及为USBD层提供的标准接口部分。

PCI接口的配置主要有函数库usrUsbHcdOhciInit来完成,函数库usrUsbHcdOhciInit中只有一个函数usrUsbHcdOhciAttach,这个函数库比较简单:首先在所有以经探测到的PCI设备中检查有没有OHCI类型的设备(OHCI_CLASS、OHCI_SUBCLASS、OHCI_PGMIF),一旦找到符合的设备就会调用usbPciConfigHeaderGet函数读取该设备的配置头以获取该设备的内存映射等信息,并调用函数usbdHcdAttach加载HC层的驱动。

6.2.5 函数库usbHcdLib

USBD通过HCD实现了对HC的控制,HCD主要为USBD提供了11个通用函数接口,从而使得USBD层不需要了解底层的细节,只需要直接调用这些函数就能完成对HC的控制。这11个函数接口分别为usbHcdAttach、usbHcdDetach、usbHcdSetBusState、usbHcdIrpSubmit、usbHcdIrpCancel、usbHcdCurrentFrameGet、usbHcdPipeCreate、usbHcdPipeDestroy、usbHcdPipeModify、usbHcdSofIntervalGet、usbHcdSofIntervalSet。这些函数从实现上来说都比较简单,它只是提供了简单的封装,而真正底层的实现则是由usbHcdOhciLib.c库来完成的。其层次结构如图6.27所示。

图6.27 HCD层函数库的层次关系

下面是hcdLib.c库中各个函数的简单分析。


1. LOCAL VOID hrbInit 
    (
    pHRB_HEADER pHrb, 

    pHCD_NEXUS pNexus, 

    UINT16 function,

    UINT16 totalLen
    )

初始化一个HRB_HEADER结构变量,通过设置HRB_HEADER结构变量可以调用HCD_NEXUS.hcdExecFunc函数完成不同的功能。


2. STATUS usbHcdAttach
    (
    HCD_EXEC_FUNC hcdExecFunc,

    pVOID param,

    USB_HCD_MNGMT_CALLBACK callback,

    pVOID callbackParam,

    pHCD_NEXUS pNexus,

    pUINT16 pBusCount
    )

这个函数指定了一个USB总线的HCD函数入口hcdExecFunc,通过调该函数完成attach,同时也将该函数及hrb.header.handle作为参数初始化了变量HCD_NEXUS。


3. STATUS usbHcdDetach
    (
    pHCD_NEXUS pNexus
    )

通过调用函数pNexus->hcdExecFunc完成了dettach,它的执行过程与usbHcdAttach相反。


4. STATUS usbHcdSetBusState
    (
    pHCD_NEXUS pNexus,

    UINT16 busNo,

    UINT16 busState
    )

通过调用函数pNexus->hcdExecFunc来设定USB总线busNo的状态:USB_BUS_SUSPEND或者USB_BUS_RESUME。


5. STATUS usbHcdCurrentFrameGet
    (
    pHCD_NEXUS pNexus,

    UINT16 busNo,

    pUINT32 pFrameNo,

    pUINT32 pFrameWindow
    )

返回当前帧号和帧窗口。


6. STATUS usbHcdIrpSubmit
    (
    pHCD_NEXUS pNexus,

    HCD_PIPE_HANDLE pipeHandle,

    pUSB_IRP pIrp
    )

该函数向HCD提交一个IRP。


7. STATUS usbHcdIrpCancel
    (
    pHCD_NEXUS pNexus,

    pUSB_IRP pIrp
    )

通知HCD取消一个IRP。当然,并不能保证一个IRP在提交给HCD后还能够在正常执行前取消。


8. STATUS usbHcdPipeCreate
    (
    pHCD_NEXUS pNexus,

    UINT16 busNo,

    UINT16 busAddress,

    UINT16 endpoint,

    UINT16 transferType,

    UINT16 direction,

    UINT16 speed,

    UINT16 maxPacketSize,

    UINT32 bandwidth,

    UINT16 interval,

    pUINT32 pTime,

    pHCD_PIPE_HANDLE pPipeHandle
    )

创建一个HCD层pipe,其结构为HCD_PIPE。如果是interrupt或者isochronous pipe,HCD需要计算传输给定的字节数的数据需要的时间(纳秒),计算公式参见usb1.1规范5.9.3。

如果有足够的带宽可用,则这段带宽将会被HCD保留给该pipe,并在usbHcdPipeDestory函数执行的时候释放。

对interrupt pipe来说,bandwidth指的是每帧数据要发送的字节数;对于isochronous pipe来说,bandwidth指的是每秒传输的字节数;而对control和bulk来说,该数值为0。

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

最坏条件下packet的传输时间在pTime中被返回。


9. STATUS usbHcdPipeDestroy
    (
    pHCD_NEXUS pNexus,

    HCD_PIPE_HANDLE pipeHandle
    )

删除pipeHandle指定的HCD层的HCD_PIPE结构变量以及分配的资源。


10. STATUS usbHcdPipeModify
    (
    pHCD_NEXUS pNexus,

    HCD_PIPE_HANDLE pipeHandle,

    UINT16 busAddress,

    UINT16 maxPacketSize
    )

修改pipe属性。一个pipe的两个特性:device address和maxPacketSize,有可能在pipe被创建之后被修改。这主要发生在一个设备默认的控制pipe上,这是因为起初host并不知道一个设备的deviceAddress和maxPacketSize,它需要首先通过默认的deviceAddress和maxPacketSize通过默认控制pipe对设备进行讯问后才能得到设备真正的maxPacketSize并对设备分配地址。那么这时候USBD层、HCD层的deviceAddress和maxPacketSize都需要重新修改。


11. STATUS usbHcdSofIntervalGet
    (
    pHCD_NEXUS pNexus,

    UINT16 busNo,

    pUINT16 pSofInterval
    )

获取SOF间隔。所谓帧间隔就是连续两个SOF信号之间的时间差。这里的帧间隔的描述单位为高速(high speed)总线上的发送1bit数据所用的时间。SOF典型的时间间隔为1ms,那么对高速设备来说数据率为12Mbps,1ms传输12kb,因此典型的SOF间隔的数值为12000。


12. STATUS usbHcdSofIntervalSet
    (
    pHCD_NEXUS pNexus,

    UINT16 busNo,

    UINT16 sofInterval
    )

设置SOF间隔。