书接上回
我在《 DvkUsersGuide.pdf》文档里面找到了库文件EZUSB.LIB的说明:
说的是,这个函数根据常量“StrIdx”返回返回一个字符串描述符的指针,
如果字符串描述符表中不包含这个常量,则函数返回NULL。
我决定先不看这个函数的源代码,但是还是先把源代码贴出来,以备以后查看,在我电脑的C:\Cypress\USB\Target\Lib\LP目录下的get_strd.c文件里:
#include <stdio.h>
#include <fx2.h>
STRINGDSCR xdata * EZUSB_GetStringDscr(BYTE StrIdx)
{
STRINGDSCR xdata * dscr;
dscr = (STRINGDSCR xdata *) pStringDscr;
while(dscr->type == STRING_DSCR)
{
if(!StrIdx--)
return(dscr);
dscr = (STRINGDSCR xdata *)((WORD)dscr + dscr->length);
}
return(NULL);
}
再来看一下“SETUPDAT[2]”
在lpregs.h里找到了SETUPDAT的声明:
EXTERN xdata volatile BYTE SETUPDAT[8] _AT_ 0xE6B8; // 8 bytes of SETUP data
是一个8字节的数组,用于保存SETUP数据,在文档里找到:
可以看出SETUPDAT[2]是wValueL,而在文档《EZ-USB(R) Technical Reference Manual.pdf》的2.3.4节,可以得出wValueL用于表明Host所请求的字符串描述符的String Number,鉴于这个函数的名字是EZUSB_GetStringDscr,推断是用于获取固件中字符串描述符的首地址,所以这里先将文档中,Cypress推荐的固件应对Host发来的Get Descriptor-String请求应该做出的响应贴出来:
现在,指针dscr_ptr指向的正式字符串描述符的地址,在LP.h文件中搜索到:
#define MSB(word) (BYTE)(((WORD)(word) >> 8) & 0xff)
#define LSB(word) (BYTE)((WORD)(word) & 0xff)
可见,MSB和LSB分别用于提取提取“字符串描述符”的地址高八位和低八位,再分别赋给SUDPTRH和SUDPTRL:
{
SUDPTRH = MSB(dscr_ptr);
SUDPTRL = LSB(dscr_ptr);
}
这符合文档里的描述:
文档上写着:The EZ-USB dose the rest !!!哈哈哈
如果if语句的条件不成立,使EndPoint0进入Stall状态:
else
EZUSB_STALL_EP0(); // Stall End Point 0
而文档里说:
STALL说明“发生了一些没有料到的事情”。
再来看EZUSB_STALL_EP0(),在LP.H文件中找到:
#define EZUSB_STALL_EP0() EP0CS |= bmEPSTALL
找到:
#define bmEPSTALL bmBIT0
#define bmBIT0 0x01
还有:
EXTERN xdata volatile BYTE EP0CS _AT_ 0xE6A0; // Endpoint Control and Status
可以看出函数EZUSB_STALL_EP0()是将寄存器EP0CS的BIT0位置1,再来看文档中寄存器EP0CS的描述:
不过这里说,需要将STALL and HSNAK两位都置1,难道这里有坑??先忽略了
回过头来,继续看SetupCommand函数,可以看到其实剩下的就是一条switch语句:
switch(SETUPDAT[1])
那么SETUPDAT[1]又是啥呢?为啥他这么重要呢?追踪一下,哈哈
可以看到,它指明了控制请求的请求号:
请求号有以下几种:
所以,这个switch语句的所有case语句所指的就是这些设备请求。
先来看第一个case语句:
case SC_GET_DESCRIPTOR: // *** Get Descriptor
if(DR_GetDescriptor())
switch(SETUPDAT[3])
{
case GD_DEVICE: // Device
SUDPTRH = MSB(pDeviceDscr);
SUDPTRL = LSB(pDeviceDscr);
break;
case GD_DEVICE_QUALIFIER: // Device Qualifier
// only retuen a device qualifier if this is a high speed
// capable chip.
if (HighSpeedCapable())
{
SUDPTRH = MSB(pDeviceQualDscr);
SUDPTRL = LSB(pDeviceQualDscr);
}
else
{
EZUSB_STALL_EP0();
}
break;
case GD_CONFIGURATION: // Configuration
SUDPTRH = MSB(pConfigDscr);
SUDPTRL = LSB(pConfigDscr);
break;
case GD_OTHER_SPEED_CONFIGURATION: // Other Speed Configuration
SUDPTRH = MSB(pOtherConfigDscr);
SUDPTRL = LSB(pOtherConfigDscr);
break;
case GD_STRING: // String
if(dscr_ptr = (void *)EZUSB_GetStringDscr(SETUPDAT[2]))
{
SUDPTRH = MSB(dscr_ptr);
SUDPTRL = LSB(dscr_ptr);
}
else
EZUSB_STALL_EP0(); // Stall End Point 0
break;
default: // Invalid request
EZUSB_STALL_EP0(); // Stall End Point 0
}
break;
这个case对应的是Get Descriptor设备请求,查看文档可知,Get Descriptor的请求号是0x06,所以猜测SC_GET_DESCRIPTOR就应该是0x06,追踪验证一下:
#define SC_GET_DESCRIPTOR 0x06 // Setup command: Get Descriptor
猜测正确!!!
而Get Descriptor设备请求又细分成五个子类:
所以,固件中也会有对应的5个case语句。
switch(SETUPDAT[3])
SETUPDAT[3]就是wValueH,所代表的就是这五种Descriptor Type。
可是这里为啥要有这么一条if语句呢?
if(DR_GetDescriptor())
我追踪到了DR_GetDescriptor()这个函数的定义:
//-----------------------------------------------------------------------------
// Device Request hooks
// The following hooks are called by the end point 0 device request parser.
//-----------------------------------------------------------------------------
BOOL DR_GetDescriptor(void)
{
return(TRUE);
}
其实,这相当于说这个if语句没有起作用,不过我注意到了“hooks”这个词,汉语的意思是“钩子”,又好像在《DvkUsersGuide.pdf》这份文档里看到过它的踪影,于是接着追踪:
大意是说,这是Cypress做基本固件框架时考虑的问题, 为了简化开发者的代码,开发者做后续开发时,可以直接在这里添加代码。赞!!!