📄 usb.c
字号:
// type: 端点传输类型 *
// ep : 端点号 *
// psize: 端点传输的数据字节数 *
//返 回:成功返回0,不成功返回非0 *
//说 明: *
// 对指定的端点进行配置,将端点信息写入缓冲区描述符表 *
//-------------------------------------------------------------------------*
static hcc_u8 usb_setup_ep(hcc_u8 addr, hcc_u8 type, hcc_u8 ep, hcc_u16 psize)
{
hcc_u8 endpt;
//禁止端点
disable_ep_tx(ep);
disable_ep_rx(ep);
if (ep_info[ep].state!=EPST_IDLE)
{
ep_info[ep].error=USBEPERR_HOST_ABORT;
}
else
{
ep_info[ep].error=USBEPERR_NONE;
}
ep_info[ep].state=EPST_IDLE;
ep_info[ep].flags=0;
ep_info[ep].data_func=(void*)0;
ep_info[ep].address=0;
ep_info[ep].tlength=0;
ep_info[ep].maxlength=0;
ep_info[ep].psize=psize;
ep_info[ep].data0_tx=0;
ep_info[ep].data0_rx=0;
if (type == EP_TYPE_DISABLE)
{
return(0);
}
endpt =0;
//该端点作为OUT
if (!(addr & DIR_TX) || type == EP_TYPE_CONTROL)
{
endpt |=MCF_USB_ENDPT_EP_RX_EN;
//设置BDT的BDT_CTL_RX为默认值,包的大小,CPU拥有,使能数据同步触发,data0
WR_LE32(&BDT_CTL_RX(ep, 0), (psize << 16) | BDT_CTL_DTS);
WR_LE32(&BDT_CTL_RX(ep, 1), (psize << 16) | BDT_CTL_DTS);
//设置RX缓冲区的地址
WR_LE32(&BDT_ADR_RX(ep, 0), (hcc_u32)get_ep_rx_buffer(ep, 0));
WR_LE32(&BDT_ADR_RX(ep, 1), (hcc_u32)get_ep_rx_buffer(ep, 1));
}
//该端点作为IN
if ((addr & DIR_TX) || type == EP_TYPE_CONTROL)
{
endpt |= MCF_USB_ENDPT_EP_TX_EN;
//设置BDT的BDT_CTL_RX为默认值,CPU拥有,其它位并不重要
WR_LE32(&BDT_CTL_TX(ep, 0), 0);
WR_LE32(&BDT_CTL_TX(ep, 1), 0);
}
//如果端点传输类型不是ISO,则在事务结束后握手,否则不要握手
if (type != EP_TYPE_ISO)
{
endpt |= MCF_USB_ENDPT_EP_HSHK;
}
/* If a non control endpoint uses both directions (e.g. two endpoint is
implemented in the same hardware slot), then CTL_DIS shall be set. */
if (type != EP_TYPE_CONTROL)
{
endpt |= MCF_USB_ENDPT_EP_CTL_DIS;
}
else
{ //默认允许控制端点接收数据
//如果为控制传输则设置端点允许的最大包长度
WR_LE32(&BDT_CTL_RX(ep, ep_info[ep].next_rx), (hcc_u32)ep_info[ep].psize<<16u);
ready_ep_rx(ep, ep_info[ep].next_rx);
}
MCF_USB_ENDPT(ep)=endpt;
return(0);
}
//set_config:完成配置描述符配置--------------------------------------------*
//功 能: *
// 完成配置描述符配置 *
//参 数: cfg_ndx: 配置描述符索引 *
//返 回: 无 *
//说 明: *
// 指定的配置必须存在 *
// 接口必须从0开始依次增加(0,1,2,3...) *
// 配置必须从0开始依次增加(0,1,2,3...) *
//-------------------------------------------------------------------------*
static void set_config(hcc_u8 cfg_ndx)
{
hcc_u8 cfg_ep=0;
usb_current_config=cfg_ndx;
if (cfg_ndx != 0)
{
//将配置描述符中的所有接口配置完成
hcc_u8 ifc=0;
while(is_ifc_ndx(cfg_ndx, ifc, 0))
{
//将接口描述符中的所有端点配置完成
hcc_u8 ifc_ep=0;
while(is_ep_ndx(cfg_ndx, ifc, 0, ifc_ep))
{
const hcc_u8 *epd=get_ep_descriptor(cfg_ndx, ifc, 0, ifc_ep);
usb_setup_ep(epd[2], epd[3], (hcc_u8)(epd[2] & 0x7fu), RD_LE16(&epd[4]));
ifc_ep++;
cfg_ep++;
}
ifc++;
}
usb_state = USBST_CONFIGURED;
}
else
{
//控制传输下,禁止除0号端点以外的所有端点
usb_state=USBST_ADDRESSED;
}
cfg_ep++;
//禁止其它的端点
while(cfg_ep < 16)
{
usb_setup_ep(0, EP_TYPE_DISABLE, cfg_ep++, 0);
}
}
//enter_default_state:USB模块进入默认状态----------------------------------*
//功 能: *
// 使USB模块进入默认状态 *
//参 数:无 *
//返 回:无 *
//说 明: *
// 只对端点0进行配置,禁止其它端点 *
//-------------------------------------------------------------------------*
static void enter_default_state(void)
{
int ep;
MCF_USB_CTL |= MCF_USB_CTL_ODD_RST;
for(ep=0; ep<sizeof(ep_info)/sizeof(ep_info[0]); ep++)
{
ep_info[ep].next_rx=0;
ep_info[ep].next_tx=0;
}
MCF_USB_CTL &= ~MCF_USB_CTL_ODD_RST;
//配置端点0
usb_setup_ep(0, EP_TYPE_CONTROL, 0, EP0_PACKET_SIZE);
//禁止其它所有的端点
set_config(0);
//设置为默认地址
MCF_USB_ADDR = 0;
usb_state=USBST_DEFAULT;
new_address=0;
}
//usb_stop_ep_tx:产生STALL握手包-------------------------------------------*
//功 能: *
// 产生STALL握手包 * *
//参 数: ep: 端点号 *
//返 回: 无 *
//说 明: 被STALL的端点将不再发送任何包,所有的IN请求被取消 *
//-------------------------------------------------------------------------*
void usb_stop_ep_tx(hcc_u8 ep)
{
/* This cal needs to be protected againt USB interrupts, to
make BDT_CTL assecc atomic. */
hcc_imask im=_irq_disable();
//强制产生STALL的握手包
WR_LE32(&BDT_CTL_TX(ep, 0), BDT_CTL_OWN | BDT_CTL_STALL);
WR_LE32(&BDT_CTL_TX(ep, 1), BDT_CTL_OWN | BDT_CTL_STALL);
_irq_restore(im);
}
//usb_stop_ep_rx:产生STALL握手包-------------------------------------------*
//功 能: *
// 产生STALL握手包 * *
//参 数: ep: 端点号 *
//返 回: 无 *
//说 明: 被STALL的端点将不再接收任何包,所有的OUT请求被取消 *
//-------------------------------------------------------------------------*
void usb_stop_ep_rx(hcc_u8 ep)
{
/* This cal needs to be protected againt USB interrupts, to
make BDT_CTL assecc atomic. */
hcc_imask im=_irq_disable();
//强制产生STALL的握手包
WR_LE32(&BDT_CTL_RX(ep, 0), BDT_CTL_OWN | BDT_CTL_STALL);
WR_LE32(&BDT_CTL_RX(ep, 1), BDT_CTL_OWN | BDT_CTL_STALL);
_irq_restore(im);
}
//ready_ep_tx:准备好端点发送-----------------------------------------------*
//功 能: *
// 准备好端点发送 *
//参 数: *
// ep: 端点号 *
// buf: 缓冲区(EVEN/BDD) *
//返 回:无 *
//说 明: *
// 修改该端点的BD,使得tx端点准备好发送 *
//-------------------------------------------------------------------------*
static void ready_ep_tx(hcc_u8 ep, hcc_u8 buf)
{
hcc_u32 ctl;
//设置USB-FS排它访问BD,DATA0/1,允许数据触发同步
ctl = RD_LE32(&BDT_CTL_TX(ep, buf)) & ~0xff;
ctl |= BDT_CTL_OWN | ep_info[ep].data0_tx | BDT_CTL_DTS;
WR_LE32(&BDT_CTL_TX(ep, buf), ctl);
}
//ready_ep_rx:准备好端点接收-----------------------------------------------*
//功 能: *
// 准备好端点接收 *
//参 数: *
// ep: 端点号 *
// buf: 缓冲区(EVEN/BDD) *
//返 回:无 *
//说 明: *
// 修改该端点的BD,使得rx端点准备好接收 *
//-------------------------------------------------------------------------*
static void ready_ep_rx(hcc_u8 ep, hcc_u8 buf)
{
hcc_u32 ctl;
//设置USB-FS排它访问BD,DATA0/1,允许数据触发同步,端点需要接收的字节数
ctl = (ep_info[ep].psize << 16) | BDT_CTL_OWN | ep_info[ep].data0_rx | BDT_CTL_DTS;
ep_info[ep].data0_rx ^= BDT_CTL_DATA;
WR_LE32(&BDT_CTL_RX(ep, buf), ctl);
}
//disable_ep_tx: 禁止端点发送----------------------------------------------*
//功 能: *
// 禁止端点发送 *
//参 数: *
// ep: 端点号 *
//返 回:无 *
//说 明: *
// 修改该端点的BD,使得发送的两个缓冲区地址都为0 *
//-------------------------------------------------------------------------*
static void disable_ep_tx(hcc_u8 ep)
{
MCF_USB_ENDPT(ep) &= ~MCF_USB_ENDPT_EP_TX_EN;
while(MCF_USB_ENDPT(ep) & MCF_USB_ENDPT_EP_TX_EN)
;
WR_LE32(&BDT_CTL_TX(ep, 0), 0);
WR_LE32(&BDT_CTL_TX(ep, 1), 0);
}
//disable_ep_rx: 禁止端点接收----------------------------------------------*
//功 能: *
// 禁止端点接收 *
//参 数: *
// ep: 端点号 *
//返 回:无 *
//-------------------------------------------------------------------------*
static void disable_ep_rx(hcc_u8 ep)
{
MCF_USB_ENDPT(ep) &= ~MCF_USB_ENDPT_EP_RX_EN;
}
/*****************************************************************************
* Name:
* _usb_send
* In:
* ep - endpoint number
* Out:
* N/A
* Description:
* This fucntion inmplements the basic state machine for transmit (IN)
* endpoints. It will
* - call user callback functions if neccessary,
* - set endpoint specific error codes
* - split data to be sent to packet sized pieces
* Note: it is called from the interrupt handler routine and from "user
* space" too. The function needs to be reentrant!
*****************************************************************************/
//_usb_send: USB数据发送---------------------------------------------------*
//功 能: *
// USB数据发送 *
//参 数: *
// ep: 端点号 *
//返 回:无 *
//说 明: *
// *
//-------------------------------------------------------------------------*
static void _usb_send(hcc_u8 ep)
{
hcc_u8 buf;
hcc_u32 length;
switch (ep_info[ep].state)
{
case EPST_DATA_TX:
length=MIN(ep_info[ep].tlength, ep_info[ep].psize);
CMX_ASSERT(length == ep_info[ep].psize || length==ep_info[ep].tlength);
//选择下一个端点的缓冲区
buf=select_tx_buf(ep);
WR_LE32(&BDT_ADR_TX(ep, buf), (hcc_u32)ep_info[ep].address);
//设置tx包的长度
WR_LE32(&BDT_CTL_TX(ep, buf), (hcc_u32)(length<<16u));
//准备好发送的缓冲区
ready_ep_tx(ep, buf);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -