目录:
一.OHCI驱动框架
二.OHCI的数据结构
三.HCD的初始化
四.OHCI的相关代码
The purpose of OpenHCI(Open Host Controller Interface) is to accelerate the acceptance of USB in the marketplace by promoting the use of a common industry software/hareware interface.
一. OHCI驱动框架
下图说明了USB device driver,host controller driver 与硬件host controller,
usb device 之间的关系
在host controller 和 host controller driver之间,有两个通信通道。
一个通道为一系列的可操作的位于host controller上的寄存器,该通道的目标为
host controller。这一系列的寄存器包括控制,状态,和链表指针寄存器。
另一个通道为HCCA(host controller communication Area) HCCA为一片共享内存,
而该通道的数据通信是由host controller发起的,最终将数据传递给驱动。HCCA包括中断端点描述符链表头,结束队列的链表头,和与开始帧有关的状态信息。
下图为OHCI的经典通道图,
对于host controller driver而言,其职责包括host controller Management,
Bandwidth Allocation, List Management, Root Hub(root hub是集成在HC中的,所以可以通过HCD对其进行相应的设置)。在bandwidth Allocation中提到1ms的帧用于传输数据。每当产生一个SOF则HC开始传输一帧数据。
对于host controller而言,其职责包括,usb states,frame management,List processing(这里done queue 通过HCCA有HC to HCD)
二. OHCI的数据结构
OHCI中的数据结构包括TD(transfer descriptor)和ED(endpointer descriptor)
ED包含了HOST CONTROLLER与端点通信的必要信息,包括最大包长,端点地址,端点的传输速度,和数据流的方向。
ED的HeadP为TD链表的头指针,TailP为尾指针,NextED为下一个ED的指针(这些设置也可以从第二部分的图看出,均为Dword)
HwINFO由变量pipe进行传参,其中
FA: function Address
EN:EndpointNumber
D:direction IN OUT direction From TD
S: speed full-speed s=0 low-speed s=1
K:skip 当设置此位是,HC跳过此ED
F: 如果此位为0,表明使用general TD format否则使用isochronous TD format
MPS: maximunpacketsize
H: halted this bit is set by the HC to indicate that processing of the TD queue on the endpoint is halted
C: toggle carry this bit is the data toggle carrry bit
TD包含了数据包传输的必要信息,包括data toggle,shared memory buffer location和completion status codes.
general transfer descriptor format(bulk/control/interrupt)
CBP: CurrentBufferPointer contains the physical address of the next memory location that will be accessed for transfer to/from the endpoint
NextTD: next td
BE: buffer end contains physical address of the last byte in the buffer for this TD
CC: condition Code
EC: error count for each transmission error,this value is incremented
T: data toggle
对于bulk/control ED list ,其hptr位于HC上的寄存器中,中断 ED list ,hptr保存于HCCA中,而等时 ED hptr连接最后一个中断ED
三.HCD的初始化
There are a number of steps necessary for an OS to bring its Host Controller Driver to an operational state:
■Load Host Controller Driver and locate the Hc
■Verify the HC and allocate system resources
■Take control of HC(可以不要)
■Set up HC registers and HCCA
■Begin sending SOF tokens on the USB
前3步在hc_start中已经完成,第4步在将ED,TD相关寄存器填充好之后,可以
进行第五步。其中一些参数的配置,如帧频率设置为1ms,hc从suspend到resume时间至少2ms,中断使能SOF中断,hcPeriodicStart的值是90%*FrameInterval等。
ControlBulkServiceRatio
如果ControlBulkServiceRatio field被设置成4:1,则control ED和BULK ED在一帧
中发送的比例为4:1,同时,the host controller enforces the control Bulk Service Ratio regardless of the number of Control and Bulk Endpoint Descriptor present on their respective lists.If there is only 1 Control Endpoint Descriptor on the Control list and the control Bulk Ratio is 4:1,that control Endpoint Descriptor is serviced 4 times before a Bulk Ed is serviced.
List Enabled Check
If the list is enabled ,the host controller may service the list.If the list is disabled,the Host controller skips that list and moves on to the next list.而list的服务顺序可以通过OHCI文档得到.
四.OHCI的相关代码
对于OHCI而言,具体的到代码部分主要在函数submit_common_msg中,该函数由以下函数而最终调用
而usb_control_msg被大多的枚举过程相关函数所调用
具体的ROOT HUB的枚举过程在ohci_submit_rh_msg实现,与OHCI相关的在函
数submit_common_msg中。该函数主要调用两个函数,一个是sohci_submit_job,一个是hc_interrupt。
a) sohci_submit_job
sohci_submit_job的调用情况如下图所示,
aa) ep_add_ed
该函数就是初始化一个ed_t *ed,该ed存放于对应的ohci_dev.ed[]中,数组对应下标由传输类型决定。若第一次使用4中类型的某一种ED,则对其初始化(包括创建dummy TD,链接dummy TD),否则只设置ed的hwINFO(就是第一个双字)
ab) td_alloc
分配TD,根据传输类型决定TD数,如BULK传输为2TD,control传输为3TD(SETUP,IN,OUT),将分配好的TD放置于结构purb_priv->td[]中
purb_priv=&urb_priv;
purb_priv->pipe=pipe;
purb_priv->length=size;
purb_priv->ed=ed;(ep_add_ed所返回的ed指针)
ac) ep_link(举PIPE_CONTROL为例)
如果ed->state不为ED_OPER则调用ep_link。此时ed->state为ED_UNLINK,将调用ed_link。该函数主要是将ED链接到链中,状态设置为ED_OPER
对于PIPE_CONTROL,如果ohci->ed_controltail为空,则将上述的ed,写入ed_controlhead寄存器,作为ed_control的头ED,否则作为尾ED.使能OHCI_CTRL_CLE,重新定向ed_controltail尾指针
ad) td_submit_job(举PIPE_CONTROL为例)
对于control传输,至少有2个TD,第一个必然为setup包(对应长度为8),toggle=TD_T_DATA0,其余toggle=TD_T_DATA1,调用td_fill将这些TD连接到对应的ED中。这些TD可能是IN或OUT或者均有,由trans_len和pipe决定
同样第一个dword在代码中为hwINFO
根据第二部分的图,我们就能很好的编写td_fill函数,无非是链表的操作
最后,在该函数内如果OHCI没休眠,则
Writeln(OHCI_CLF,&ohci->regs->cmdstatus),start control list
(具体可以看cmdstatus寄存器)
b) hc_interrupt
等待传输结束,HCCA 相关中断
在函数hc_interrupt中主要处理三类中断,分别是writeback of done_head,start frame,overrun,对于后两者都是关闭中断后,重开中断(如果需要),而writeback of done_head则多添加了一个函数dl_done_list(&gohci,dl_reverse_done_list(&gohci))
由于TD是以一个FIFO基地址传输给don_head的,所以需要翻转td_list,这就是函数dl_reverse_done_list,而dl_done_list则是检查是否将所有的TD成功传输(依据传输的TD个数与接收的个数比较,如果一致则传输成功),最后调用ed_unlink将对应的ED从hptr上去除
五.总结
以上就是 U-BOOT 中的 OHCI 介绍,主要是对 control 传输有较详细的介绍,特别是 ISO 传输还不是特别了解,需要进一步学习。
转自:http://blog.csdn.net/am_111/article/details/6569002
另外一篇讲ohci的文章有关于数据传输的理解过程,有一定的参考意义:
转自:http://blog.csdn.net/zhaocj/article/details/6083162
s3c2440提供了USB主机接口,它与OHCI v1.0完全兼容。要使用该功能,就必须熟悉OHCI v1.0规范;而要熟悉OHCI v1.0规范,那么还必须先熟悉USB v1.1协议。因此涉及到该部分的内容较多,要想正确使用s3c2440所提供的USB主机接口也不是一件容易的事情。在这里,我主要介绍USB设备枚举过程中所涉及到的一些知识,并给出具体的实现程序。
OHCI(Open HCI)是目前使用比较广泛的三种USB主机控制器规范之一。USB体系结构是由四个主要部分组成:客户软件/USB驱动,主机控制器驱动(HCD),主机控制器(HC)和USB驱动。前两者由软件实现,后两者由硬件实现。而OHCI就是规范了主机控制器驱动和主机控制器之间的接口,以及它们的基本操作。在主机控制器驱动和主机控制器之间,有两个通信通道,第一个是应用位于HC的一套可操作寄存器,它们包括控制寄存器、状态寄存器和列表指针寄存器;另一个通道是应用称为主机控制器通信域(HCCA)的共享内存。
USB定义了四种数据传输类型:控制传输、批量传输、中断传输和同步传输。在OHCI规范中把数据传输类型分为两类:周期传输和非周期传输。同步传输和中断传输属于周期传输,控制传输和批量传输属于非周期传输。USB定义了每帧的周期为1.0毫秒,为了保证每一帧都能发生周期传输和非周期传输,一般地,OHCI把每一帧的带宽分为四个部分,首先是发送SOF,然后是非周期传输,紧接着是周期传输,如果周期传输完毕后,还有时间,则剩余的时间仍然留给非周期传输。
端点描述符(ED)和传输描述符(TD)是两个最基本的通信模块。ED包含了一个端点的信息,它被HC用来管理使用端点。ED的典型参数包括端点地址、传输速度、最大数据包大小,另外ED还提供了TD链表的停靠地(锚点)。TD是一个依赖于ED的内存缓存区,用于与端点之间进行数据传输。当HC存取一个ED,并且找到一个有效的TD地址时,则HC就完成了一个简单的与端点之间的传输任务,这个端点是由ED确定,而所存取的数据内存地址由TD指定。当所有的被TD所定义的数据传输完毕后,TD就从ED中解链出来,并链接到完成列表中。这个完成列表能够被HCD所处理,以提供一些完成信息。
ED的数据结构长度为16字节,它的数据域有:
FA:USB的功能地址;
EN:USB功能内的端点地址;
D:数据流的传输方向,是IN,OUT,还是有TD来决定传输方向;
S:速度,全速还是低速;
K:用于设置跳过当前ED;
F:链接于ED的TD的形式,是通用TD格式还是同步TD格式;
MPS:数据传输的最大字节大小;
TailP:TD列表的尾指针;
H:用于停止当前TD列表的处理;
C:数据翻转进位位;
HeadP:TD列表的头指针;
NextED:下一个要处理的ED指针。
根据上述说明,我们可以定义ED为下面的数据类型:
typedef struct _ED {
volatile unsigned int Control;
volatile unsigned int TailP;
volatile unsigned int HeadP;
volatile unsigned int NextEd;
} ED, *P_ED;
由于ED必须是16字节地址对齐形式,因此我们必须用下面的形式来声明它的变量:
__align(16) ED ed;
我们可以用下面的函数来创建一个ED:
__inline void CreateEd(
unsigned int EDAddr, //ED地址指针
unsigned int MaxPacket, //MPS
unsigned int TDFormat, //F
unsigned int Skip, //K
unsigned int Speed, //S
unsigned int Direction, //D
unsigned int EndPt, //EN
unsigned int FuncAddress, //FA
unsigned int TDQTailPntr, //TailP
unsigned int TDQHeadPntr, //HeadP
unsigned int ToggleCarry, //C
unsigned int NextED) //NextED
{
P_ED pED = (P_ED) EDAddr;
pED->Control = (MaxPacket << 16) | (TDFormat << 15) |(Skip << 14) | (Speed << 13)
| Direction << 11) | (EndPt << 7) | FuncAddress;
pED->TailP = (TDQTailPntr & 0xFFFFFFF0);
pED->HeadP = (TDQHeadPntr & 0xFFFFFFF0) | (ToggleCarry << 1);
pED->NextEd = (NextED & 0xFFFFFFF0);
}
TD共有两种类型:通用TD和同步TD。通用TD用于中断、控制和批量端点,同步TD用于同步传输。在这里,我们只给出通用TD的数据结构和定义。
通用TD的数据结构长度也是16字节,它的数据域有:
R:缓存凑整,用于设置是否需要最后一个数据包的长度与所定义的长度一致;
DP:方向,是IN,OUT,还是SETUP;
DI:延时中断;
T:数据翻转;
EC:传输错误计数;
CC:条件码,为上一次企图传输的状态;
CBP:将要被传输的数据内存物理地址;
NextTD:下一个TD;
BE:将要被传输的数据内存物理末字节地址;
根据上述说明,我们可以定义通用TD为下面的数据类型:
typedef struct _TD {
volatile unsigned int Control;
volatile unsigned int CBP;
volatile unsigned int NextTD;
volatile unsigned int BE;
} TD, *P_TD;
由于通用TD必须是16字节地址对齐形式,因此我们必须用下面的形式来声明它的变量:
__align(16) TD td[4];
我们可以用下面的函数来创建一个通用TD:
__inline void CreateGenTd(
unsigned int GenTdAddr, //TD地址指针
unsigned int DataToggle, //T
unsigned int DelayInterrupt, //DI
unsigned int Direction, //DP
unsigned int BufRnding, //R
unsigned int CurBufPtr, //CBP
unsigned int NextTD, //NextTD
unsigned int BuffLen) //被传输的数据长度,由该变量可以得到BE
{
P_TD pTD = (P_TD) GenTdAddr;
pTD->Control = (DataToggle << 24) | (DelayInterrupt << 21)
| (Direction << 19) | (BufRnding << 18);
pTD->CBP = CurBufPtr;
pTD->NextTD = (NextTD & 0xFFFFFFF0);
pTD->BE = (BuffLen) ? CurBufPtr + BuffLen - 1 : CurBufPtr;
}
下面我们给出HCCA的数据结构,它的长度为256字节,包括128字节的HCCA中断表,2字节的HCCA帧数,2字节的HCCA便签(表示HC是否正在更新HCCA帧数),4字节的HCCA完成队列头指针,以及116字节的保留区。根据上述说明,我们可以定义HCCA为下面的数据类型:
typedef struct _HCCA {
volatile unsigned int HccaInterruptTable[32];
volatile unsigned short HccaFrameNumber;
volatile unsigned short HccaPad1;
volatile unsigned int HccaDoneHead;
volatile unsigned char reserved[116];
} HCCA, *P_HCCA;
由于HCCA必须是256字节地址对齐形式,因此我们必须用下面的形式来声明它的变量:
__align(256) HCCA hcca;
OHCI是基于寄存器层描述的USB主机控制器的规范,因此HC包含了一些片内可操作寄存器,这些寄存器同样可以被HCD所使用。下面我们就简单介绍OHCI中的寄存器。
HcRevision:HCI规范版本;
HcControl:HC的操作模式,CBSR——在非周期队列中,被服务的控制ED与批量ED之间的比例;CLE——下一帧控制队列处理使能;HCFS——USB主机控制器功能状态,包括复位、重新开始、操作和中止;
HcCommandStatus:HC接收来至HCD的命令,也可反映HC的当前状态,HCR——软件复位HC;CLF——确定是否有控制队列TD;
HcInterruptStatus:提供各种能够触发硬件中断事件的状态;
HcInterruptEnable:使能用于控制产生硬件中断事件的位;
HcInterruptDisable:无效用于控制产生硬件中断事件的位
HcHCCA:HCCA的物理地址;
HcPeriodCurrentED:当前同步或中断ED的物理地址;
HcControlHeadED:控制队列的第一个ED的物理地址;
HcControlCurrentED:当前控制对立ED的物理地址;
HcBulkHeadED:批量队列的第一个ED的物理地址;
HcBulkCurrentED:当前批量对立ED的物理地址;
HcDoneHead:被添加在完成队列中的最近一个TD的物理地址;
HcFmInterval:包含一个14位的FI——用于表示一帧之内所占用的比特时间,2个连续的SOFs,和一个15位PSMPS——用于表示在没有引发调度溢出下可发送或接收全速最大包大小,FI,PSMPS的推荐值为 0x2EDF和0x2778。
HcFmRemaining:14位的倒计数器,以表示当前帧所剩时间;
HcFmNumber:16位计数器,以提供时序参考;
HcPeriodicStart:14位可编程数值,以确定HC在什么时间开始执行周期队列;
HcLSThreshold:11位数值,用于确定是否在EOF之前执行最大8位LS包传输;
HcRhDescriptorA:第一个对跟集线器进行描述的寄存器;
HcRhDescriptorB:第二个对跟集线器进行描述的寄存器;
HcRhStatus:包括集线器状态域和集线器状态更改域;
HcRhPortStstus[1:NDP]:用于控制和报告每个端口上的事件,在s3c2440中,NDP为2
下面给出OHCI的初始化,它都是基于寄存器的。根据OHCI规范,HCD应该完成下列初始化步骤:
● 初始化HCCA数据内存单元
● 初始化可操作寄存器,以匹配当前设备数据状态
● 设置HcHCCA
● 设置HcInterruptEnable
● 设置HcControl
● 设置HcPeriodicStart
结合本文所介绍的实际内容,OHCI的初始化函数为:
void OHCIInit( )
{
unsigned int fminterval;
//复位
rHcControl = 0;
//写HCCA
rHcHCCA = (volatile unsigned )&hcca;
//设置帧间隔
fminterval = 0x2edf;
rHcFmInterval =((((fminterval - 210) * 6) / 7) << 16)| fminterval;
rHcPeriodicStart= (fminterval * 9) / 10;
//初始化HcDoneHead
rHcDoneHead = 0x00;
hcca.HccaDoneHead = 0x0000;
//设置HC为运行状态
rHcControl = 0x80;
}
主机对USB设备的识别过程称为设备枚举,因此枚举对于USB至关重要。在本文,只进行下列简单的5步枚举过程:
1、主机要求得到设备描述符,SETUP数据包为:0x80, 0x06,0x00,0x01,0x00,0x00,0x40,0x00,得到的数据长度最大为0x40;
2、第二个SETUP包是为设备分配一个地址,内容一般为:0x00,0x05,0x02,0x00,0x00,0x00,0x00,0x00。其中的02表示为设备分配的地址为0x02,以后我们再对该设备操作时,就只能使用0x02这个地址值;
3、主机用新的地址再次获取设备描述符,SETUP包为:0x80,0x06,0x00,0x01,0x00,0x00,0x12,0x00,与上次不同,这次得到数据长度时实际的数据长度0x12;
4、主机读取设备全部配置描述符,SETUP包为:0x80,0x06,0x00,0x02,0x00,0x00,0x40,0x00,由于主机不知道设备描述符的长度,因此这里只要求得到0x40个字节;
5、主机发送SETUP数据包:0x00,0x09,0x01,0x00,0x00,0x00,0x00,0x00,用以设置配置,允许所有端点进入工作状态。
对USB设备枚举我们只做了简单的介绍,关于枚举的其他步骤以及SETUP数据包各个字节的具体含义,请阅读USB协议的第9章。
下面我们就主要介绍OHCI规范是如何完成USB设备枚举的。前面我们已经介绍过了,OHCI数据传输主要依靠ED和TD,其中TD是挂靠在ED上的。ED主要用来设置传输的各种参数,TD则主要负责具体的数据传输。根据USB协议,USB的设备枚举只涉及控制传输。控制传输最少有两个事务阶段:建立和状态,控制传输可以有选择性地包括建立和状态阶段之间的数据阶段。在这里,控制写传输不需要数据阶段,而控制读需要在建立和状态之间添加主机要读取到的数据。一般来说,完成一次控制写传输需要3个TD:第一个发送Setup包,第二个用于接收握手或零长度的数据包,第三个用于发送状态;而完成一次控制读传输需要4个TD:第一个发送Setup包,第二个用于接收数据,第三个用于发送一个零长度的数据包,,第四个用于接收状态。
下面给出具体的USB设备枚举的函数。在进行枚举之前,主机一定要确认有USB设备的存在。正确情况下,在确认过程中,如果在一段给定时间没有检测到设备,则主机认为没有USB设备。“一段给定的时间”应该由定时器来完成。在这里,为了简化程序,我们只用计数来代替定时。
int USB_Enum()
{
int i;
//判断有无USB设备
for(i=0;i<100000;i++)
{
if (rHcRhPortStatus1 & 0x01)
{
rHcRhPortStatus1 = (1 << 4); // 端口复位
while (rHcRhPortStatus1 & (1 << 4))
; // 等待复位结束
rHcRhPortStatus1 = (1 << 1); // 使能该端口
break;
}
else if (rHcRhPortStatus2 & 0x01)
{
rHcRhPortStatus2 = (1 << 4); // 端口复位
while (rHcRhPortStatus2 & (1 << 4))
; // 等待复位结束
rHcRhPortStatus2 = (1 << 1); // 使能该端口
break;
}
}
if (i>90000)
return 0x44;
//第一步,主机得到设备描述符
CreateEd(
(unsigned int) &ed, // ED Address
64, // Max packet
0, // TD format
0, // Skip
0, // Speed
0x0, // Direction
0x0, // Endpoint
0x0, // Func Address,初始为0
(unsigned int) &td[3], // TDQTailPointer
(unsigned int) &td[0], // TDQHeadPointer
0, // ToggleCarry
0x0); // NextED
// 建立PID
CreateGenTd(
(unsigned int) &td[0], // TD Address
2, // Data Toggle
0x2, // DelayInterrupt
0x0, // Direction
1, // Buffer Rounding
(unsigned int) pSetup1, // Current Buffer Pointer,定义的全局变量数组
//const char pSetup1[8] = {0x80,0x06,0x00,0x01,0x00,0x00,0x40,0x00};
(unsigned int) &td[1], // Next TD
8); // Buffer Length
// 接收数据
CreateGenTd(
(unsigned int) &td[1], // TD Address
0, // Data Toggle
0x2, // DelayInterrupt
0x2, // Direction
1, // Buffer Rounding
(unsigned int) pData1, // Current Buffer Pointer,定义的全局变量数组
// char pData1[0x40]; 通过读取该数组,可以获知设备描述符
(unsigned int) &td[2], // Next TD
0x40); // Buffer Length
// 零长度数据包
CreateGenTd(
(unsigned int) &td[2], // TD Address
3, // Data Toggle
0x2, // DelayInterrupt
0x1, // Direction
1, // Buffer Rounding
0x0, // Current Buffer Pointer
(unsigned int) &td[3], // Next TD
0x0); // Buffer Length
//接收状态
CreateGenTd(
(unsigned int) &td[3], // TD Address
3, // Data Toggle
0x2, // DelayInterrupt
0x2, // Direction
1, // Buffer Rounding
0x0, // Current Buffer Pointer
(unsigned int) 0, // Next TD
0x0); // Buffer Length
//设置寄存器
rHcControlHeadED = (unsigned int )& ed;
rHcControlCurrentED = (unsigned int )& ed;
// 控制列表处理使能,开始工作
rHcControl = 0x90;
//通知HC控制列表已填充
rHcCommandStatus = 0x02;
//第二步 为设备分配地址
CreateEd(
(unsigned int) &ed, // ED Address
64, // Max packet
0, // TD format
0, // Skip
0, // Speed
0x0, // Direction
0, // Endpoint
0, // Func Address
(unsigned int) &td[2], // TDQTailPointer
(unsigned int) &td[0], // TDQHeadPointer
0, // ToggleCarry
0x0); // NextED
//建立PID
CreateGenTd(
(unsigned int) &td[0], // TD Address
2, // Data Toggle
2, // DelayInterrupt
0, // Direction
1, // Buffer Rounding
(unsigned int) pSetup2, // Current Buffer Pointer,定义的全局变量数组
//const char pSetup2[8] = {0x00,0x05,0x02,0x00,0x00,0x00,0x00,0x00};
(unsigned int) &td[1], // Next TD
8); // Buffer Length
//接收零长度数据包
CreateGenTd(
(unsigned int) &td[1], // TD Address
0, // Data Toggle
2, // DelayInterrupt
2, // Direction
1, // Buffer Rounding
(unsigned int) 0, // Current Buffer Pointer
(unsigned int) &td[2], // Next TD
0); // Buffer Length
//发送状态
CreateGenTd(
(unsigned int) &td[2], // TD Address
3, // Data Toggle
2, // DelayInterrupt
1, // Direction
1, // Buffer Rounding
0x0, // Current Buffer Pointer
(unsigned int) 0, // Next TD
0x0); // Buffer Length
rHcControlHeadED = (unsigned int )& ed;
rHcControlCurrentED = (unsigned int )& ed;
rHcControl = 0x90;
rHcCommandStatus = 0x02;
//第三步,主机用新的地址再次获取设备描述符
CreateEd(
(unsigned int) &ed, // ED Address
64, // Max packet
0, // TD format
0, // Skip
0, // Speed
0x0, // Direction
0x0, // Endpoint
0x2, // Func Address,新的地址
(unsigned int) &td[3], // TDQTailPointer
(unsigned int) &td[0], // TDQHeadPointer
0, // ToggleCarry
0x0); // NextED
CreateGenTd(
(unsigned int) &td[0], // TD Address
2, // Data Toggle
0x2, // DelayInterrupt
0x0, // Direction
1, // Buffer Rounding
(unsigned int) pSetup3, // Current Buffer Pointer,定义的全局变量数组
//const char pSetup3[8] = {0x80,0x06,0x00,0x01,0x00,0x00,0x12,0x00};
(unsigned int) &td[1], // Next TD
8); // Buffer Length
CreateGenTd(
(unsigned int) &td[1], // TD Address
0, // Data Toggle
0x2, // DelayInterrupt
0x2, // Direction
1, // Buffer Rounding
(unsigned int) pData3, // Current Buffer Pointer,定义的全局变量数组
// char pData3[0x12]; 通过读取该数组,可以获知设备描述符
(unsigned int) &td[2], // Next TD
0x12); // Buffer Length
CreateGenTd(
(unsigned int) &td[2], // TD Address
3, // Data Toggle
0x2, // DelayInterrupt
0x1, // Direction
1, // Buffer Rounding
0x0, // Current Buffer Pointer
(unsigned int) &td[3], // Next TD
0x0); // Buffer Length
CreateGenTd(
(unsigned int) &td[3], // TD Address
3, // Data Toggle
0x2, // DelayInterrupt
0x2, // Direction
1, // Buffer Rounding
0x0, // Current Buffer Pointer
(unsigned int) 0, // Next TD
0x0); // Buffer Length
rHcControlHeadED = (unsigned int )& ed;
rHcControlCurrentED = (unsigned int )& ed;
rHcControl = 0x90;
rHcCommandStatus = 0x02;
//第四步,主机读取设备全部配置描述符
CreateEd(
(unsigned int) &ed, // ED Address
64, // Max packet
0, // TD format
0, // Skip
0, // Speed
0x0, // Direction
0x0, // Endpoint
0x2, // Func Address
(unsigned int) &td[3], // TDQTailPointer
(unsigned int) &td[0], // TDQHeadPointer
0, // ToggleCarry
0x0); // NextED
CreateGenTd(
(unsigned int) &td[0], // TD Address
2, // Data Toggle
0x2, // DelayInterrupt
0x0, // Direction
1, // Buffer Rounding
(unsigned int) pSetup4, // Current Buffer Pointer,定义的全局变量数组
//const char pSetup4[8] = {0x80,0x06,0x00,0x02,0x00,0x00,0x40,0x00};
(unsigned int) &td[1], // Next TD
8); // Buffer Length
CreateGenTd(
(unsigned int) &td[1], // TD Address
0, // Data Toggle
0x2, // DelayInterrupt
0x2, // Direction
1, // Buffer Rounding
(unsigned int) pData4, // Current Buffer Pointer,定义的全局变量数组
// char pData4[0x40]; 通过读取该数组,可以获知配置描述符
(unsigned int) &td[2], // Next TD
0x40); // Buffer Length
CreateGenTd(
(unsigned int) &td[2], // TD Address
3, // Data Toggle
0x2, // DelayInterrupt
0x1, // Direction
1, // Buffer Rounding
0x0, // Current Buffer Pointer
(unsigned int) &td[3], // Next TD
0x0); // Buffer Length
CreateGenTd(
(unsigned int) &td[3], // TD Address
3, // Data Toggle
0x2, // DelayInterrupt
0x2, // Direction
1, // Buffer Rounding
0x0, // Current Buffer Pointer
(unsigned int) 0, // Next TD
0x0); // Buffer Length
rHcControlHeadED = (unsigned int )& ed;
rHcControlCurrentED = (unsigned int )& ed;
rHcControl = 0x90;
rHcCommandStatus = 0x02;
//第五步,主机发送SETUP数据包,用以设置配置,允许所有端点进入工作状态。
CreateEd(
(unsigned int) &ed, // ED Address
64, // Max packet
0, // TD format
0, // Skip
0, // Speed
0x0, // Direction
0, // Endpoint
2, // Func Address
(unsigned int) &td[2], // TDQTailPointer
(unsigned int) &td[0], // TDQHeadPointer
0, // ToggleCarry
0x0); // NextED
CreateGenTd(
(unsigned int) &td[0], // TD Address
2, // Data Toggle
2, // DelayInterrupt
0, // Direction
1, // Buffer Rounding
(unsigned int) pSetup5, // Current Buffer Pointer,定义的全局变量数组
//const char pSetup5[8] = {0x00,0x09,0x01,0x00,0x00,0x00,0x00,0x00};
(unsigned int) &td[1], // Next TD
8); // Buffer Length
CreateGenTd(
(unsigned int) &td[1], // TD Address
0, // Data Toggle
2, // DelayInterrupt
2, // Direction
1, // Buffer Rounding
(unsigned int) 0, // Current Buffer Pointer
(unsigned int) &td[2], // Next TD
0); // Buffer Length
CreateGenTd(
(unsigned int) &td[2], // TD Address
3, // Data Toggle
2, // DelayInterrupt
1, // Direction
1, // Buffer Rounding
0x0, // Current Buffer Pointer
(unsigned int) 0, // Next TD
0x0); // Buffer Length
rHcControlHeadED = (unsigned int )& ed;
rHcControlCurrentED = (unsigned int )& ed;
rHcControl = 0x90;
rHcCommandStatus = 0x02;
return 0x88;
}