linux usb 主机控制器,s3c2440的USB主机控制器

下面我们给出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;

}0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值