📄 usb.c
字号:
ep_info[ep].data0_tx ^= BDT_CTL_DATA;
//计算好发送的状态
ep_info[ep].tlength -= length;
ep_info[ep].address = (hcc_u8*)ep_info[ep].address + length;
//数据阶段的最后一个数据包的长度等于控制端点的最大数据包长度,则设备要向主机
//发送0长度的数据包以结束数据阶段
if (ep_info[ep].tlength == 0)
{
if ((length == ep_info[ep].psize) && (ep_info[ep].flags & EPFL_ZPACKET))
{
ep_info[ep].state=EPST_TX_STOP;
}
else
{
ep_info[ep].state=EPST_DATA_TX_LAST;
}
break;
}
break;
case EPST_DATA_TX_WAIT_DB:
/* Let second buffer get empty while waiting for a new buffer. */
ep_info[ep].state=EPST_DATA_TX_EMPTY_DB;
break;
case EPST_ABORT_TX:
tx_abort:
case EPST_TX_STOP:
//发送0长度的数据包以结束数据阶段
ep_info[ep].state=EPST_DATA_TX_LAST;
send_zero_packet(ep);
break;
case EPST_DATA_TX_LAST:
//等待该端点的缓冲区发关完成
if ((RD_LE32(&BDT_CTL_TX(ep, 0)) & BDT_CTL_OWN) == 0
&& (RD_LE32(&BDT_CTL_TX(ep, 1)) & BDT_CTL_OWN) == 0)
{
ep_info[ep].state=EPST_IDLE;
}
break;
default:
CMX_ASSERT(0);
}
}
//usb_send: USB数据发送----------------------------------------------------*
//功 能: *
// USB数据发送 *
//参 数: *
// ep: 端点号 *
// f : *
// * data: 数据缓冲区 *
// tr_length: 从机准备发送的字节数 *
// req_length: 主机要求接收的字节数 *
//返 回:无 *
//说 明: *
// USB数据传输都是由主机发起,因此主机需告诉从机发送多少数据(req_length)*
// 而从机发送的数据(tr_length)不能超过主机要求的数据 *
//-------------------------------------------------------------------------*
void usb_send(hcc_u8 ep, usb_callback_t f, hcc_u8* data, hcc_u32 tr_length, hcc_u32 req_length)
{
hcc_imask itst;
ep_info[ep].tlength = MIN(tr_length,req_length);
ep_info[ep].maxlength = ep_info[ep].tlength;
ep_info[ep].data_func = f;
ep_info[ep].address = data;
ep_info[ep].flags = req_length > tr_length ? (hcc_u8)EPFL_ZPACKET : (hcc_u8)0;
ep_info[ep].error = USBEPERR_NONE;
ep_info[ep].state = EPST_DATA_TX;
itst=_irq_disable();
_usb_send(ep);
_irq_restore(itst);
}
/*****************************************************************************
* Name:
* _usb_receive
* In:
* ep - endpoint number
* Out:
* N/A
* Description:
* This fucntion inmplements the basic state machine for receive (OUT)
* endpoints. It will
* - call user callback functions if neccessary,
* - set endpoint specific error codes
* - reassemble packets into the specified buffer
* Note: it is called from the interrupt handler routine and from "user
* space" too. The function needs to be reentrant!
*****************************************************************************/
//_usb_receive: USB数据接收------------------------------------------------*
//功 能: *
// USB数据接收 *
//参 数: *
// ep: 端点号 *
//返 回:无 *
//说 明: *
// *
//-------------------------------------------------------------------------*
void _usb_receive(hcc_u8 ep)
{
hcc_u8 loops=0;
hcc_u8* buf;
int x;
do
{
//查找BD的相应字段
hcc_u8 this_buf = (hcc_u8)((MCF_USB_STAT & MCF_USB_STAT_ODD) ? 1 : 0);
hcc_u16 plength = (hcc_u16)(RD_LE32(&BDT_CTL_RX(ep, this_buf)) >> 16);
//检查接收到的数据是否OK
if (ep_info[ep].tlength < plength)
{ //主机发送的数据过多,协议错误
usb_stop_ep_rx(ep);
ep_info[ep].error = USBEPERR_TO_MANY_DATA;
return;
}
//将该端点接收到的数据从BD指向的入口存放到用户的缓冲区
buf=(hcc_u8*)RD_LE32(&BDT_ADR_RX(ep, (MCF_USB_STAT & MCF_USB_STAT_ODD) ? 1 : 0));
for(x=0; x < plength; x++)
{
((hcc_u8*)(ep_info[ep].address))[x]=buf[x];
}
ep_info[ep].tlength -= plength;
ep_info[ep].address = ((hcc_u8 *)ep_info[ep].address) + plength;
//如果是最后一个数据包
if ((ep_info[ep].tlength == 0) || (ep_info[ep].psize != plength))
{
/* Uuuupps: at this point there sall be no RX buffer enabled. But
if the hosts terminates the transfer early (by sending a short
packet) then one buffer may remain enabled. So we may have an
unexpected interrupt and an unexpected packet.
We try to disable the buffer, but this is not safe. There is a
race. If the host already sent additional data to this endpoint,
then the first transfer will be dropped as a spurious packet.
Note: control endpoints are not affected because befor enabling RX
these don't need to know how much data will be transfered (setup
transfer will tell this).
Note1: we don't know if "aborting" the reception was succesfull or
not. */
WR_LE32(&BDT_CTL_RX(ep, ep_info[ep].next_rx ? 0 : 1), 0);
ep_info[ep].state=EPST_IDLE;
/* Control endpoints will execute the callback after the status stage. */
/* Check if control endpoint. (Note: both ENDPT registers will have
the same content, so we check reg0. )*/
if (! MCF_USB_ENDPT(ep) & MCF_USB_ENDPT_EP_CTL_DIS)
{
/* Tell application transfer ended. */
if (ep_info[ep].data_func != (void *) 0)
{
/* We don't care about the return valus since the transfer is already
finished and we can do nothing in case of an error. */
(void)(*ep_info[ep].data_func)();
}
/* Disable callbacks. */
ep_info[ep].data_func = (void *)0;
}
}
else
{
//数据还未完全接收完成,则处理完当前令牌后继续接收数据
if (ep_info[ep].tlength > ep_info[ep].psize)
{
ready_ep_rx(ep, this_buf);
}
}
}while(loops);
}
//usb_receive: USB数据接收-------------------------------------------------*
//功 能: *
// USB数据接收 *
//参 数: *
// ep: 端点号 *
// f : *
// * data: 数据缓冲区 *
// tr_length: 从机准备发送的字节数 *
// req_length: 主机要求接收的字节数 *
//返 回:无 *
//说 明: *
//-------------------------------------------------------------------------*
void usb_receive(hcc_u8 ep, usb_callback_t f, hcc_u8* data, hcc_u32 tr_length, hcc_u32 req_length)
{
ep_info[ep].tlength = MIN(tr_length, req_length);
ep_info[ep].maxlength = ep_info[ep].tlength;
ep_info[ep].data_func = f;
ep_info[ep].address=data;
ep_info[ep].state = EPST_DATA_RX;
ep_info[ep].error = USBEPERR_NONE;
ep_info[ep].flags = 0;
//准备好rx缓冲区(最多只有两个接收缓冲区)
ready_ep_rx(ep, ep_info[ep].next_rx);
if (ep_info[ep].tlength > ep_info[ep].psize)
{
ready_ep_rx(ep, (hcc_u8)(ep_info[ep].next_rx ^ 0x1));
}
}
//cb_set_address:设置USB设备的地址-----------------------------------------*
//功 能: *
// 设置USB设备的地址 *
//参 数:无 *
//返 回:状态机的值 *
//说 明:状态机使用该函数处理标准请求(set address),设定设备的地址 *
//-------------------------------------------------------------------------*
static callback_state_t cb_set_address()
{
if (new_address != 0)
usb_state = USBST_ADDRESSED;
else
enter_default_state();
//设置设备的地址
MCF_USB_ADDR = new_address;
new_address = 0;
return(clbst_ok);
}
//usb_stm_ctrl0:对SETUP包解包----------------------------------------------*
//功 能: *
// 对SETUP包解包和处理 *
//参 数:无 *
//返 回:状态机的值 *
//说 明: *
// (1)只有接收到SETUP包才调用该函数 *
// (2)SETUP包中8字节数据 *
// bmRequestType:1 *
// bRequest:1 *
// wValue.H:1 :描述符的类型 *
// wValue.L:1 :描述符的索引 *
// wIndex:2 *
// wLength:2 *
//-------------------------------------------------------------------------*
static callback_state_t usb_stm_ctrl0()
{
hcc_u8 *pdata=(hcc_u8 *)usb_get_rx_pptr(0); //指向SETUP包
callback_state_t r=(STP_REQU_TYPE(pdata) & 0x80) ? clbst_in: clbst_out; //传输的方向
//USB设备的11个标准请求
switch (STP_REQUEST(pdata))
{
//1.设置地址请求
case USBRQ_SET_ADDRESS:
new_address=(hcc_u8)(STP_VALUE(pdata) & (0x7f));
ep_info[0].data_func=cb_set_address;
break;
//2.读取描述符请求
case USBRQ_GET_DESCRIPTOR:
switch(STP_VALUE(pdata) & 0xff00u)
{
//2.1 设备描述符
case STDD_DEVICE << 8:
{
hcc_u8 *p=(hcc_u8*)get_device_descriptor();
usb_send(0, (void *) 0, p, p[0], STP_LENGTH(pdata));
}
break;
//2.2 配置描述符
case STDD_CONFIG << 8:
{
//目前只支持一个配置描述符
hcc_u8 cfg=(hcc_u8)(STP_VALUE(pdata) & 0xffu);
//对于索引0返回第一个配置描述符
if (cfg == 0)
{
cfg++;
}
//该字符串描述符存在
if (is_cfgd_index(cfg))
{
const hcc_u8 *cd;
cd=get_cfg_descriptor(cfg);
usb_send(0, (void *) 0, (void*)cd, RD_LE16(&cd[2])
, STP_LENGTH(pdata));
break;
}
}
//该字符串描述符不存在
r=clbst_error;
break;
//2.3 字符串描述符
case STDD_STRING << 8:
//该字符串描述符存在
if (is_str_index((hcc_u8)(STP_VALUE(pdata) & 0xffu)))
{
usb_send(0, (void *) 0, (void *)get_str_descriptor((hcc_u8)(STP_VALUE(pdata) & 0xffu))
, *(hcc_u8*)get_str_descriptor((hcc_u8)(STP_VALUE(pdata) & 0xffu))
, STP_LENGTH(pdata));
break;
}
//该字符串描述符不存在
r=clbst_error;
break;
default:
goto call_usercb;
}
break;
//3.读取配置请求
case USBRQ_GET_CONFIGURATION:
usb_send(0, (void *) 0, (void *)&usb_current_config
, 1
, STP_LENGTH(pdata));
break;
//4.设置配置请求
case USBRQ_SET_CONFIGURATION:
if (STP_VALUE(pdata) == 0)
{
set_config(0);
break;
}
else if (is_cfgd_index(STP_VALUE(pdata)))
{
set_config((hcc_u8)STP_VALUE(pdata));
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -