书接上回
接下来,是响应“读取状态请求”:
case SC_GET_STATUS: // *** Get Status
同样,if(DR_GetStatus())可以不予理会。
由文档可知,获取状态又可分为三部分:
1、获取设备状态:牵涉到远程唤醒和自供电位;
2、获取端口状态:牵涉到停止位;
3、获取接口状态:USB规格保留使用。
固件判断SETUPDAT[0],识别是哪一种获取状态请求,关于判断的依据,可以看下面的文档部分:
#define GS_DEVICE 0x80 // Get Status: Device
#define GS_INTERFACE 0x81 // Get Status: Interface
#define GS_ENDPOINT 0x82 // Get Status: End Point
case GS_DEVICE: // Device
EP0BUF[0] = ((BYTE)Rwuen << 1) | (BYTE)Selfpwr;
EP0BUF[1] = 0;
EP0BCH = 0;
EP0BCL = 2;
break;
固件返回的是:支持远程唤醒,USB供电。
case GS_INTERFACE: // Interface
EP0BUF[0] = 0;
EP0BUF[1] = 0;
EP0BCH = 0;
EP0BCL = 2;
break;
case GS_ENDPOINT: // End Point
EP0BUF[0] = *(BYTE xdata *) epcs(SETUPDAT[4]) & bmEPSTALL;
EP0BUF[1] = 0;
EP0BCH = 0;
EP0BCL = 2;
break;
文档中的说明如下:
SETUPDAT[4],用于说明是哪个端点,且其BIT7标明的端点的方向。
STALL位,在EPxCS寄存器里。
// macro for generating the address of an endpoint's control and status register (EPnCS)
#define epcs(EP) (EPCS_Offset_Lookup_Table[(EP & 0x7E) | (EP > 128)] + 0xE6A1)
这个宏用于产生EP所对应的端点的控制状态寄存器的地址(不包含EP0):
1、(EP & 0x7E):是哪个端点?
2、(EP > 128):是输入端点还是输入端点?
3、EPCS_Offset_Lookup_Table[(EP & 0x7E) | (EP > 128)],查找数组,这个数组是所有端点(不包含EP0)控制状态寄存器地址的偏离值:
// this table is used by the epcs macro
const char code EPCS_Offset_Lookup_Table[] =
{
0, // EP1OUT
1, // EP1IN
2, // EP2OUT
2, // EP2IN
3, // EP4OUT
3, // EP4IN
4, // EP6OUT
4, // EP6IN
5, // EP8OUT
5, // EP8IN
};
4、0xE6A1是端点控制状态寄存器地址的基数:
*(BYTE xdata *) epcs(SETUPDAT[4])则是提取对应地址的内容;*(BYTE xdata *) epcs(SETUPDAT[4]) & bmEPSTALL则是仅保留STALL的状态。
需要注意的是,一旦固件设置了STALL位,就只能由Host发送Clear Feature/Stall request来清除。不过,EP0是例外,为了防止在控制传输的时候设备锁死:
最后,别忘了default:
default: // Invalid Command
EZUSB_STALL_EP0(); // Stall End Point 0