基本固件框架的追踪研读之SETUP命令的处理2

来源:互联网 发布:单片机堆栈是什么意思 编辑:程序博客网 时间:2024/06/10 22:30

书接上回


我在《 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做基本固件框架时考虑的问题, 为了简化开发者的代码,开发者做后续开发时,可以直接在这里添加代码。赞!!!
1 0
原创粉丝点击