696 lines
22 KiB
C
696 lines
22 KiB
C
/********************************** (C) COPYRIGHT *******************************
|
||
* File Name : CH59x_usbhost.c
|
||
* Author : WCH
|
||
* Version : V1.2
|
||
* Date : 2021/11/17
|
||
* Description
|
||
*********************************************************************************
|
||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||
* Attention: This software (modified or not) and binary are used for
|
||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||
*******************************************************************************/
|
||
|
||
#include "CH59x_common.h"
|
||
#if DISK_LIB_ENABLE
|
||
#include "CHRV3UFI.H"
|
||
#endif
|
||
|
||
uint8_t UsbDevEndp0Size; // USB设备的端点0的最大包尺寸
|
||
uint8_t FoundNewDev;
|
||
_RootHubDev ThisUsbDev; //ROOT口
|
||
_DevOnHubPort DevOnHubPort[HUB_MAX_PORTS]; // 假定:不超过1个外部HUB,每个外部HUB不超过HUB_MAX_PORTS个端口(多了不管)
|
||
|
||
uint8_t *pHOST_RX_RAM_Addr;
|
||
uint8_t *pHOST_TX_RAM_Addr;
|
||
|
||
/*获取设备描述符*/
|
||
__attribute__((aligned(4))) const uint8_t SetupGetDevDescr[] = {USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00,
|
||
USB_DESCR_TYP_DEVICE, 0x00, 0x00, sizeof(USB_DEV_DESCR), 0x00};
|
||
/*获取配置描述符*/
|
||
__attribute__((aligned(4))) const uint8_t SetupGetCfgDescr[] = {USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00,
|
||
USB_DESCR_TYP_CONFIG, 0x00, 0x00, 0x04, 0x00};
|
||
/*设置USB地址*/
|
||
__attribute__((aligned(4))) const uint8_t SetupSetUsbAddr[] = {USB_REQ_TYP_OUT, USB_SET_ADDRESS, USB_DEVICE_ADDR, 0x00,
|
||
0x00, 0x00, 0x00, 0x00};
|
||
/*设置USB配置*/
|
||
__attribute__((aligned(4))) const uint8_t SetupSetUsbConfig[] = {USB_REQ_TYP_OUT, USB_SET_CONFIGURATION, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00};
|
||
/*设置USB接口配置*/
|
||
__attribute__((aligned(4))) const uint8_t SetupSetUsbInterface[] = {USB_REQ_RECIP_INTERF, USB_SET_INTERFACE, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00};
|
||
/*清除端点STALL*/
|
||
__attribute__((aligned(4))) const uint8_t SetupClrEndpStall[] = {USB_REQ_TYP_OUT | USB_REQ_RECIP_ENDP, USB_CLEAR_FEATURE,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||
|
||
/*********************************************************************
|
||
* @fn DisableRootHubPort
|
||
*
|
||
* @brief 关闭ROOT-HUB端口,实际上硬件已经自动关闭,此处只是清除一些结构状态
|
||
*
|
||
* @param none
|
||
*
|
||
* @return none
|
||
*/
|
||
void DisableRootHubPort(void)
|
||
{
|
||
#ifdef FOR_ROOT_UDISK_ONLY
|
||
CHRV3DiskStatus = DISK_DISCONNECT;
|
||
#endif
|
||
#ifndef DISK_BASE_BUF_LEN
|
||
ThisUsbDev.DeviceStatus = ROOT_DEV_DISCONNECT;
|
||
ThisUsbDev.DeviceAddress = 0x00;
|
||
#endif
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn AnalyzeRootHub
|
||
*
|
||
* @brief 分析ROOT-HUB状态,处理ROOT-HUB端口的设备插拔事件
|
||
* 如果设备拔出,函数中调用DisableRootHubPort()函数,将端口关闭,插入事件,置相应端口的状态位
|
||
*
|
||
* @param none
|
||
*
|
||
* @return 返回ERR_SUCCESS为没有情况,返回ERR_USB_CONNECT为检测到新连接,返回ERR_USB_DISCON为检测到断开
|
||
*/
|
||
uint8_t AnalyzeRootHub(void)
|
||
{
|
||
uint8_t s;
|
||
|
||
s = ERR_SUCCESS;
|
||
|
||
if(R8_USB_MIS_ST & RB_UMS_DEV_ATTACH)
|
||
{ // 设备存在
|
||
#ifdef DISK_BASE_BUF_LEN
|
||
if(CHRV3DiskStatus == DISK_DISCONNECT
|
||
#else
|
||
if(ThisUsbDev.DeviceStatus == ROOT_DEV_DISCONNECT // 检测到有设备插入
|
||
#endif
|
||
|| (R8_UHOST_CTRL & RB_UH_PORT_EN) == 0x00)
|
||
{ // 检测到有设备插入,但尚未允许,说明是刚插入
|
||
DisableRootHubPort(); // 关闭端口
|
||
#ifdef DISK_BASE_BUF_LEN
|
||
CHRV3DiskStatus = DISK_CONNECT;
|
||
#else
|
||
ThisUsbDev.DeviceSpeed = R8_USB_MIS_ST & RB_UMS_DM_LEVEL ? 0 : 1;
|
||
ThisUsbDev.DeviceStatus = ROOT_DEV_CONNECTED; //置连接标志
|
||
#endif
|
||
PRINT("USB dev in\n");
|
||
s = ERR_USB_CONNECT;
|
||
}
|
||
}
|
||
|
||
#ifdef DISK_BASE_BUF_LEN
|
||
else if(CHRV3DiskStatus >= DISK_CONNECT)
|
||
{
|
||
#else
|
||
else if(ThisUsbDev.DeviceStatus >= ROOT_DEV_CONNECTED)
|
||
{ //检测到设备拔出
|
||
#endif
|
||
DisableRootHubPort(); // 关闭端口
|
||
PRINT("USB dev out\n");
|
||
if(s == ERR_SUCCESS)
|
||
{
|
||
s = ERR_USB_DISCON;
|
||
}
|
||
}
|
||
// R8_USB_INT_FG = RB_UIF_DETECT; // 清中断标志
|
||
return (s);
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn SetHostUsbAddr
|
||
*
|
||
* @brief 设置USB主机当前操作的USB设备地址
|
||
*
|
||
* @param addr - USB设备地址
|
||
*
|
||
* @return none
|
||
*/
|
||
void SetHostUsbAddr(uint8_t addr)
|
||
{
|
||
R8_USB_DEV_AD = (R8_USB_DEV_AD & RB_UDA_GP_BIT) | (addr & MASK_USB_ADDR);
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn SetUsbSpeed
|
||
*
|
||
* @brief 设置当前USB速度
|
||
*
|
||
* @param FullSpeed - USB速度
|
||
*
|
||
* @return none
|
||
*/
|
||
void SetUsbSpeed(uint8_t FullSpeed)
|
||
{
|
||
#ifndef DISK_BASE_BUF_LEN
|
||
if(FullSpeed) // 全速
|
||
{
|
||
R8_USB_CTRL &= ~RB_UC_LOW_SPEED; // 全速
|
||
R8_UH_SETUP &= ~RB_UH_PRE_PID_EN; // 禁止PRE PID
|
||
}
|
||
else
|
||
{
|
||
R8_USB_CTRL |= RB_UC_LOW_SPEED; // 低速
|
||
}
|
||
#endif
|
||
(void)FullSpeed;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn ResetRootHubPort
|
||
*
|
||
* @brief 检测到设备后,复位总线,为枚举设备准备,设置为默认为全速
|
||
*
|
||
* @param none
|
||
*
|
||
* @return none
|
||
*/
|
||
void ResetRootHubPort(void)
|
||
{
|
||
UsbDevEndp0Size = DEFAULT_ENDP0_SIZE; //USB设备的端点0的最大包尺寸
|
||
SetHostUsbAddr(0x00);
|
||
R8_UHOST_CTRL &= ~RB_UH_PORT_EN; // 关掉端口
|
||
SetUsbSpeed(1); // 默认为全速
|
||
R8_UHOST_CTRL = (R8_UHOST_CTRL & ~RB_UH_LOW_SPEED) | RB_UH_BUS_RESET; // 默认为全速,开始复位
|
||
mDelaymS(15); // 复位时间10mS到20mS
|
||
R8_UHOST_CTRL = R8_UHOST_CTRL & ~RB_UH_BUS_RESET; // 结束复位
|
||
mDelayuS(250);
|
||
R8_USB_INT_FG = RB_UIF_DETECT; // 清中断标志
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn EnableRootHubPort
|
||
*
|
||
* @brief 使能ROOT-HUB端口,相应的bUH_PORT_EN置1开启端口,设备断开可能导致返回失败
|
||
*
|
||
* @param none
|
||
*
|
||
* @return 返回ERR_SUCCESS为检测到新连接,返回ERR_USB_DISCON为无连接
|
||
*/
|
||
uint8_t EnableRootHubPort(void)
|
||
{
|
||
#ifdef DISK_BASE_BUF_LEN
|
||
if(CHRV3DiskStatus < DISK_CONNECT)
|
||
CHRV3DiskStatus = DISK_CONNECT;
|
||
#else
|
||
if(ThisUsbDev.DeviceStatus < ROOT_DEV_CONNECTED)
|
||
ThisUsbDev.DeviceStatus = ROOT_DEV_CONNECTED;
|
||
#endif
|
||
if(R8_USB_MIS_ST & RB_UMS_DEV_ATTACH)
|
||
{ // 有设备
|
||
#ifndef DISK_BASE_BUF_LEN
|
||
if((R8_UHOST_CTRL & RB_UH_PORT_EN) == 0x00)
|
||
{ // 尚未使能
|
||
ThisUsbDev.DeviceSpeed = (R8_USB_MIS_ST & RB_UMS_DM_LEVEL) ? 0 : 1;
|
||
if(ThisUsbDev.DeviceSpeed == 0)
|
||
{
|
||
R8_UHOST_CTRL |= RB_UH_LOW_SPEED; // 低速
|
||
}
|
||
}
|
||
#endif
|
||
R8_UHOST_CTRL |= RB_UH_PORT_EN; //使能HUB端口
|
||
return (ERR_SUCCESS);
|
||
}
|
||
return (ERR_USB_DISCON);
|
||
}
|
||
|
||
#ifndef DISK_BASE_BUF_LEN
|
||
/*********************************************************************
|
||
* @fn SelectHubPort
|
||
*
|
||
* @brief 选定需要操作的HUB口
|
||
*
|
||
* @param HubPortIndex - 选择操作指定的ROOT-HUB端口的外部HUB的指定端口
|
||
*
|
||
* @return None
|
||
*/
|
||
void SelectHubPort(uint8_t HubPortIndex)
|
||
{
|
||
if(HubPortIndex) // 选择操作指定的ROOT-HUB端口的外部HUB的指定端口
|
||
{
|
||
SetHostUsbAddr(DevOnHubPort[HubPortIndex - 1].DeviceAddress); // 设置USB主机当前操作的USB设备地址
|
||
SetUsbSpeed(DevOnHubPort[HubPortIndex - 1].DeviceSpeed); // 设置当前USB速度
|
||
if(DevOnHubPort[HubPortIndex - 1].DeviceSpeed == 0) // 通过外部HUB与低速USB设备通讯需要前置ID
|
||
{
|
||
R8_UEP1_CTRL |= RB_UH_PRE_PID_EN; // 启用PRE PID
|
||
mDelayuS(100);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SetHostUsbAddr(ThisUsbDev.DeviceAddress); // 设置USB主机当前操作的USB设备地址
|
||
SetUsbSpeed(ThisUsbDev.DeviceSpeed); // 设置USB设备的速度
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/*********************************************************************
|
||
* @fn WaitUSB_Interrupt
|
||
*
|
||
* @brief 等待USB中断
|
||
*
|
||
* @param none
|
||
*
|
||
* @return 返回ERR_SUCCESS 数据接收或者发送成功,返回ERR_USB_UNKNOWN 数据接收或者发送失败
|
||
*/
|
||
uint8_t WaitUSB_Interrupt(void)
|
||
{
|
||
uint16_t i;
|
||
for(i = WAIT_USB_TOUT_200US; i != 0 && (R8_USB_INT_FG & RB_UIF_TRANSFER) == 0; i--)
|
||
{
|
||
;
|
||
}
|
||
return ((R8_USB_INT_FG & RB_UIF_TRANSFER) ? ERR_SUCCESS : ERR_USB_UNKNOWN);
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn USBHostTransact
|
||
*
|
||
* @brief 传输事务,输入目的端点地址/PID令牌,同步标志,以20uS为单位的NAK重试总时间(0则不重试,0xFFFF无限重试),返回0成功,超时/出错重试
|
||
* 本子程序着重于易理解,而在实际应用中,为了提供运行速度,应该对本子程序代码进行优化
|
||
*
|
||
* @param endp_pid - 令牌和地址, 高4位是token_pid令牌, 低4位是端点地址
|
||
* @param tog - 同步标志
|
||
* @param timeout - 超时时间
|
||
*
|
||
* @return ERR_USB_UNKNOWN 超时,可能硬件异常
|
||
* ERR_USB_DISCON 设备断开
|
||
* ERR_USB_CONNECT 设备连接
|
||
* ERR_SUCCESS 传输完成
|
||
*/
|
||
uint8_t USBHostTransact(uint8_t endp_pid, uint8_t tog, uint32_t timeout)
|
||
{
|
||
uint8_t TransRetry;
|
||
|
||
uint8_t s, r;
|
||
uint16_t i;
|
||
|
||
R8_UH_RX_CTRL = R8_UH_TX_CTRL = tog;
|
||
TransRetry = 0;
|
||
|
||
do
|
||
{
|
||
R8_UH_EP_PID = endp_pid; // 指定令牌PID和目的端点号
|
||
R8_USB_INT_FG = RB_UIF_TRANSFER;
|
||
for(i = WAIT_USB_TOUT_200US; i != 0 && (R8_USB_INT_FG & RB_UIF_TRANSFER) == 0; i--)
|
||
{
|
||
;
|
||
}
|
||
R8_UH_EP_PID = 0x00; // 停止USB传输
|
||
if((R8_USB_INT_FG & RB_UIF_TRANSFER) == 0)
|
||
{
|
||
return (ERR_USB_UNKNOWN);
|
||
}
|
||
|
||
if(R8_USB_INT_FG & RB_UIF_DETECT)
|
||
{ // USB设备插拔事件
|
||
// mDelayuS( 200 ); // 等待传输完成
|
||
R8_USB_INT_FG = RB_UIF_DETECT;
|
||
s = AnalyzeRootHub(); // 分析ROOT-HUB状态
|
||
|
||
if(s == ERR_USB_CONNECT)
|
||
FoundNewDev = 1;
|
||
#ifdef DISK_BASE_BUF_LEN
|
||
if(CHRV3DiskStatus == DISK_DISCONNECT)
|
||
{
|
||
return (ERR_USB_DISCON);
|
||
} // USB设备断开事件
|
||
if(CHRV3DiskStatus == DISK_CONNECT)
|
||
{
|
||
return (ERR_USB_CONNECT);
|
||
} // USB设备连接事件
|
||
#else
|
||
if(ThisUsbDev.DeviceStatus == ROOT_DEV_DISCONNECT)
|
||
{
|
||
return (ERR_USB_DISCON);
|
||
} // USB设备断开事件
|
||
if(ThisUsbDev.DeviceStatus == ROOT_DEV_CONNECTED)
|
||
{
|
||
return (ERR_USB_CONNECT);
|
||
} // USB设备连接事件
|
||
#endif
|
||
mDelayuS(200); // 等待传输完成
|
||
}
|
||
|
||
if(R8_USB_INT_FG & RB_UIF_TRANSFER) // 传输完成事件
|
||
{
|
||
if(R8_USB_INT_ST & RB_UIS_TOG_OK)
|
||
{
|
||
return (ERR_SUCCESS);
|
||
}
|
||
r = R8_USB_INT_ST & MASK_UIS_H_RES; // USB设备应答状态
|
||
if(r == USB_PID_STALL)
|
||
{
|
||
return (r | ERR_USB_TRANSFER);
|
||
}
|
||
if(r == USB_PID_NAK)
|
||
{
|
||
if(timeout == 0)
|
||
{
|
||
return (r | ERR_USB_TRANSFER);
|
||
}
|
||
if(timeout < 0xFFFFFFFF)
|
||
{
|
||
timeout--;
|
||
}
|
||
--TransRetry;
|
||
}
|
||
else
|
||
switch(endp_pid >> 4)
|
||
{
|
||
case USB_PID_SETUP:
|
||
case USB_PID_OUT:
|
||
if(r)
|
||
{
|
||
return (r | ERR_USB_TRANSFER);
|
||
} // 不是超时/出错,意外应答
|
||
break; // 超时重试
|
||
case USB_PID_IN:
|
||
if(r == USB_PID_DATA0 || r == USB_PID_DATA1)
|
||
{ // 不同步则需丢弃后重试
|
||
} // 不同步重试
|
||
else if(r)
|
||
{
|
||
return (r | ERR_USB_TRANSFER);
|
||
} // 不是超时/出错,意外应答
|
||
break; // 超时重试
|
||
default:
|
||
return (ERR_USB_UNKNOWN); // 不可能的情况
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{ // 其它中断,不应该发生的情况
|
||
R8_USB_INT_FG = 0xFF; /* 清中断标志 */
|
||
}
|
||
mDelayuS(15);
|
||
} while(++TransRetry < 3);
|
||
return (ERR_USB_TRANSFER); // 应答超时
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn HostCtrlTransfer
|
||
*
|
||
* @brief 执行控制传输,8字节请求码在pSetupReq中,DataBuf为可选的收发缓冲区
|
||
*
|
||
* @param DataBuf - 如果需要接收和发送数据,那么DataBuf需指向有效缓冲区用于存放后续数据
|
||
* @param RetLen - 实际成功收发的总长度保存在RetLen指向的字节变量中
|
||
*
|
||
* @return ERR_USB_BUF_OVER IN状态阶段出错
|
||
* ERR_SUCCESS 数据交换成功
|
||
*/
|
||
uint8_t HostCtrlTransfer(uint8_t *DataBuf, uint8_t *RetLen)
|
||
{
|
||
uint16_t RemLen = 0;
|
||
uint8_t s, RxLen, RxCnt, TxCnt;
|
||
uint8_t *pBuf;
|
||
uint8_t *pLen;
|
||
|
||
pBuf = DataBuf;
|
||
pLen = RetLen;
|
||
mDelayuS(200);
|
||
if(pLen)
|
||
{
|
||
*pLen = 0; // 实际成功收发的总长度
|
||
}
|
||
|
||
R8_UH_TX_LEN = sizeof(USB_SETUP_REQ);
|
||
s = USBHostTransact(USB_PID_SETUP << 4 | 0x00, 0x00, 200000 / 20); // SETUP阶段,200mS超时
|
||
if(s != ERR_SUCCESS)
|
||
{
|
||
return (s);
|
||
}
|
||
R8_UH_RX_CTRL = R8_UH_TX_CTRL = RB_UH_R_TOG | RB_UH_R_AUTO_TOG | RB_UH_T_TOG | RB_UH_T_AUTO_TOG; // 默认DATA1
|
||
R8_UH_TX_LEN = 0x01; // 默认无数据故状态阶段为IN
|
||
RemLen = pSetupReq->wLength;
|
||
PRINT("wLength: %x\n", RemLen);
|
||
if(RemLen && pBuf) // 需要收发数据
|
||
{
|
||
PRINT("bRequestType: %x\n", pSetupReq->bRequestType);
|
||
if(pSetupReq->bRequestType & USB_REQ_TYP_IN) // 收
|
||
{
|
||
while(RemLen)
|
||
{
|
||
mDelayuS(200);
|
||
s = USBHostTransact(USB_PID_IN << 4 | 0x00, R8_UH_RX_CTRL, 200000 / 20); // IN数据
|
||
if(s != ERR_SUCCESS)
|
||
{
|
||
return (s);
|
||
}
|
||
RxLen = R8_USB_RX_LEN < RemLen ? R8_USB_RX_LEN : RemLen;
|
||
RemLen -= RxLen;
|
||
if(pLen)
|
||
{
|
||
*pLen += RxLen; // 实际成功收发的总长度
|
||
}
|
||
for(RxCnt = 0; RxCnt != RxLen; RxCnt++)
|
||
{
|
||
*pBuf = pHOST_RX_RAM_Addr[RxCnt];
|
||
pBuf++;
|
||
}
|
||
if(R8_USB_RX_LEN == 0 || (R8_USB_RX_LEN & (UsbDevEndp0Size - 1)))
|
||
{
|
||
break; // 短包
|
||
}
|
||
}
|
||
R8_UH_TX_LEN = 0x00; // 状态阶段为OUT
|
||
}
|
||
else // 发
|
||
{
|
||
while(RemLen)
|
||
{
|
||
mDelayuS(200);
|
||
R8_UH_TX_LEN = RemLen >= UsbDevEndp0Size ? UsbDevEndp0Size : RemLen;
|
||
for(TxCnt = 0; TxCnt != R8_UH_TX_LEN; TxCnt++)
|
||
{
|
||
pHOST_TX_RAM_Addr[TxCnt] = *pBuf;
|
||
pBuf++;
|
||
}
|
||
s = USBHostTransact(USB_PID_OUT << 4 | 0x00, R8_UH_TX_CTRL, 200000 / 20); // OUT数据
|
||
if(s != ERR_SUCCESS)
|
||
{
|
||
return (s);
|
||
}
|
||
RemLen -= R8_UH_TX_LEN;
|
||
if(pLen)
|
||
{
|
||
*pLen += R8_UH_TX_LEN; // 实际成功收发的总长度
|
||
}
|
||
}
|
||
PRINT("Send: %d\n", *pLen);
|
||
// R8_UH_TX_LEN = 0x01; // 状态阶段为IN
|
||
}
|
||
}
|
||
mDelayuS(200);
|
||
s = USBHostTransact((R8_UH_TX_LEN ? USB_PID_IN << 4 | 0x00 : USB_PID_OUT << 4 | 0x00), RB_UH_R_TOG | RB_UH_T_TOG, 200000 / 20); // STATUS阶段
|
||
if(s != ERR_SUCCESS)
|
||
{
|
||
return (s);
|
||
}
|
||
if(R8_UH_TX_LEN == 0)
|
||
{
|
||
return (ERR_SUCCESS); // 状态OUT
|
||
}
|
||
if(R8_USB_RX_LEN == 0)
|
||
{
|
||
return (ERR_SUCCESS); // 状态IN,检查IN状态返回数据长度
|
||
}
|
||
return (ERR_USB_BUF_OVER); // IN状态阶段错误
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn CopySetupReqPkg
|
||
*
|
||
* @brief 复制控制传输的请求包
|
||
*
|
||
* @param pReqPkt - 控制请求包地址
|
||
*
|
||
* @return none
|
||
*/
|
||
void CopySetupReqPkg(const uint8_t *pReqPkt) // 复制控制传输的请求包
|
||
{
|
||
uint8_t i;
|
||
for(i = 0; i != sizeof(USB_SETUP_REQ); i++)
|
||
{
|
||
((uint8_t *)pSetupReq)[i] = *pReqPkt;
|
||
pReqPkt++;
|
||
}
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn CtrlGetDeviceDescr
|
||
*
|
||
* @brief 获取设备描述符,返回在 pHOST_TX_RAM_Addr 中
|
||
*
|
||
* @param none
|
||
*
|
||
* @return ERR_USB_BUF_OVER 描述符长度错误
|
||
* ERR_SUCCESS 成功
|
||
*/
|
||
uint8_t CtrlGetDeviceDescr(void)
|
||
{
|
||
uint8_t s;
|
||
uint8_t len;
|
||
|
||
UsbDevEndp0Size = DEFAULT_ENDP0_SIZE;
|
||
CopySetupReqPkg(SetupGetDevDescr);
|
||
s = HostCtrlTransfer(Com_Buffer, &len); // 执行控制传输
|
||
if(s != ERR_SUCCESS)
|
||
{
|
||
return (s);
|
||
}
|
||
UsbDevEndp0Size = ((PUSB_DEV_DESCR)Com_Buffer)->bMaxPacketSize0; // 端点0最大包长度,这是简化处理,正常应该先获取前8字节后立即更新UsbDevEndp0Size再继续
|
||
if(len < ((PUSB_SETUP_REQ)SetupGetDevDescr)->wLength)
|
||
{
|
||
return (ERR_USB_BUF_OVER); // 描述符长度错误
|
||
}
|
||
return (ERR_SUCCESS);
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn CtrlGetConfigDescr
|
||
*
|
||
* @brief 获取配置描述符,返回在 pHOST_TX_RAM_Addr 中
|
||
*
|
||
* @param none
|
||
*
|
||
* @return ERR_USB_BUF_OVER 描述符长度错误
|
||
* ERR_SUCCESS 成功
|
||
*/
|
||
uint8_t CtrlGetConfigDescr(void)
|
||
{
|
||
uint8_t s;
|
||
uint8_t len;
|
||
|
||
CopySetupReqPkg(SetupGetCfgDescr);
|
||
s = HostCtrlTransfer(Com_Buffer, &len); // 执行控制传输
|
||
if(s != ERR_SUCCESS)
|
||
{
|
||
return (s);
|
||
}
|
||
if(len < ((PUSB_SETUP_REQ)SetupGetCfgDescr)->wLength)
|
||
{
|
||
return (ERR_USB_BUF_OVER); // 返回长度错误
|
||
}
|
||
|
||
len = ((PUSB_CFG_DESCR)Com_Buffer)->wTotalLength;
|
||
CopySetupReqPkg(SetupGetCfgDescr);
|
||
pSetupReq->wLength = len; // 完整配置描述符的总长度
|
||
s = HostCtrlTransfer(Com_Buffer, &len); // 执行控制传输
|
||
if(s != ERR_SUCCESS)
|
||
{
|
||
return (s);
|
||
}
|
||
|
||
#ifdef DISK_BASE_BUF_LEN
|
||
if(len > 64)
|
||
len = 64;
|
||
memcpy(TxBuffer, Com_Buffer, len); //U盘操作时,需要拷贝到TxBuffer
|
||
#endif
|
||
|
||
return (ERR_SUCCESS);
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn CtrlSetUsbAddress
|
||
*
|
||
* @brief 设置USB设备地址
|
||
*
|
||
* @param addr - 设备地址
|
||
*
|
||
* @return ERR_SUCCESS 成功
|
||
*/
|
||
uint8_t CtrlSetUsbAddress(uint8_t addr)
|
||
{
|
||
uint8_t s;
|
||
|
||
CopySetupReqPkg(SetupSetUsbAddr);
|
||
pSetupReq->wValue = addr; // USB设备地址
|
||
s = HostCtrlTransfer(NULL, NULL); // 执行控制传输
|
||
if(s != ERR_SUCCESS)
|
||
{
|
||
return (s);
|
||
}
|
||
SetHostUsbAddr(addr); // 设置USB主机当前操作的USB设备地址
|
||
mDelaymS(10); // 等待USB设备完成操作
|
||
return (ERR_SUCCESS);
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn CtrlSetUsbConfig
|
||
*
|
||
* @brief 设置USB设备配置
|
||
*
|
||
* @param cfg - 配置值
|
||
*
|
||
* @return ERR_SUCCESS 成功
|
||
*/
|
||
uint8_t CtrlSetUsbConfig(uint8_t cfg)
|
||
{
|
||
CopySetupReqPkg(SetupSetUsbConfig);
|
||
pSetupReq->wValue = cfg; // USB设备配置
|
||
return (HostCtrlTransfer(NULL, NULL)); // 执行控制传输
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn CtrlClearEndpStall
|
||
*
|
||
* @brief 清除端点STALL
|
||
*
|
||
* @param endp - 端点地址
|
||
*
|
||
* @return ERR_SUCCESS 成功
|
||
*/
|
||
uint8_t CtrlClearEndpStall(uint8_t endp)
|
||
{
|
||
CopySetupReqPkg(SetupClrEndpStall); // 清除端点的错误
|
||
pSetupReq->wIndex = endp; // 端点地址
|
||
return (HostCtrlTransfer(NULL, NULL)); // 执行控制传输
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn CtrlSetUsbIntercace
|
||
*
|
||
* @brief 设置USB设备接口
|
||
*
|
||
* @param cfg - 配置值
|
||
*
|
||
* @return ERR_SUCCESS 成功
|
||
*/
|
||
uint8_t CtrlSetUsbIntercace(uint8_t cfg)
|
||
{
|
||
CopySetupReqPkg(SetupSetUsbInterface);
|
||
pSetupReq->wValue = cfg; // USB设备配置
|
||
return (HostCtrlTransfer(NULL, NULL)); // 执行控制传输
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn USB_HostInit
|
||
*
|
||
* @brief USB主机功能初始化
|
||
*
|
||
* @param none
|
||
*
|
||
* @return none
|
||
*/
|
||
void USB_HostInit(void)
|
||
{
|
||
R8_USB_CTRL = RB_UC_HOST_MODE;
|
||
R8_UHOST_CTRL = 0;
|
||
R8_USB_DEV_AD = 0x00;
|
||
|
||
R8_UH_EP_MOD = RB_UH_EP_TX_EN | RB_UH_EP_RX_EN;
|
||
R16_UH_RX_DMA = (uint16_t)(uint32_t)pHOST_RX_RAM_Addr;
|
||
R16_UH_TX_DMA = (uint16_t)(uint32_t)pHOST_TX_RAM_Addr;
|
||
|
||
R8_UH_RX_CTRL = 0x00;
|
||
R8_UH_TX_CTRL = 0x00;
|
||
R8_USB_CTRL = RB_UC_HOST_MODE | RB_UC_INT_BUSY | RB_UC_DMA_EN;
|
||
R8_UH_SETUP = RB_UH_SOF_EN;
|
||
R8_USB_INT_FG = 0xFF;
|
||
DisableRootHubPort();
|
||
R8_USB_INT_EN = RB_UIE_TRANSFER | RB_UIE_DETECT;
|
||
|
||
FoundNewDev = 0;
|
||
}
|