/*
|
* (C) Copyright 2007-2013
|
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
|
* Jerry Wang <wangflord@allwinnertech.com>
|
*
|
* See file CREDITS for list of people who contributed to this
|
* project.
|
*
|
* This program is free software; you can redistribute it and/or
|
* modify it under the terms of the GNU General Public License as
|
* published by the Free Software Foundation; either version 2 of
|
* the License, or (at your option) any later version.
|
*
|
* This program is distributed in the hope that it will be useful,
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* GNU General Public License for more details.
|
*
|
* You should have received a copy of the GNU General Public License
|
* along with this program; if not, write to the Free Software
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
* MA 02111-1307 USA
|
*/
|
#include "usb_base.h"
|
#include <scsi.h>
|
#include <asm/arch/gic.h>
|
#include <asm/arch/timer.h>
|
//#include <sys_partition.h>
|
#include <sunxi_board.h>
|
#include <console.h>
|
#include "usb_dma_control.h"
|
|
#define SUNXI_USB_EP0_BUFFER_SIZE (512)
|
|
#define HIGH_SPEED_EP_MAX_PACKET_SIZE (512)
|
#define FULL_SPEED_EP_MAX_PACKET_SIZE (64)
|
|
#define BULK_FIFOSIZE (512)
|
|
#define SUNXI_USB_CTRL_EP_INDEX 0
|
#define SUNXI_USB_BULK_IN_EP_INDEX 1 /* tx */
|
#define SUNXI_USB_BULK_OUT_EP_INDEX 2 /* rx */
|
|
enum usb_device_speed {
|
USB_SPEED_UNKNOWN = 0, /* enumerating */
|
USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */
|
USB_SPEED_HIGH, /* usb 2.0 */
|
USB_SPEED_WIRELESS, /* wireless (usb 2.5) */
|
USB_SPEED_SUPER, /* usb 3.0 */
|
USB_SPEED_RESERVED
|
};
|
|
static uchar sunxi_usb_ep0_buffer[SUNXI_USB_EP0_BUFFER_SIZE];
|
|
sunxi_udc_t sunxi_udc_source;
|
static sunxi_ubuf_t sunxi_ubuf;
|
sunxi_usb_setup_req_t *sunxi_udev_active;
|
|
static uint usb_dma_trans_unaliged_bytes;
|
static uchar *usb_dma_trans_unaligned_buf;
|
|
static int __usb_read_ep0_data(void *buffer, uint data_type);
|
//static int __usb_read_fifo(void *buffer, unsigned int buffer_size);
|
static int __usb_write_fifo(uchar *buffer, unsigned int buffer_size);
|
static void __usb_bulk_ep_reset (void);
|
static void __usb_clear_all_irq(void);
|
|
static void __usb_writecomplete(__hdle hUSB, u32 ep_type, u32 complete);
|
static void __usb_readcomplete(__hdle hUSB, u32 ep_type, u32 complete);
|
|
static void __usb_recv_by_dma_isr(void *p_arg);
|
static void __usb_send_by_dma_isr(void *p_arg);
|
static int __sunxi_udc_set_address(uchar address);
|
|
|
static int eptx_send_op(void);
|
static int eprx_recv_op(void);
|
static int ep0_recv_op(void);
|
|
extern int fastboot_data_flag;
|
extern volatile int sunxi_usb_burn_from_boot_init;
|
#ifdef CONFIG_SUNXI_USB_DETECT
|
extern volatile int sunxi_usb_detect_flag;
|
#endif
|
|
/* for fastboot */
|
__weak int get_fastboot_data_flag(void)
|
{
|
return 0;
|
}
|
|
/* for usb burn */
|
__weak void set_usb_burn_boot_init_flag(int flag )
|
{
|
|
}
|
|
/* for usb config */
|
__weak void otg_phy_config(void)
|
{
|
printf("weak:otg_phy_config\n");
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
void sunxi_usb_irq(void *data)
|
{
|
u8 misc_irq = 0;
|
u16 tx_irq = 0;
|
u16 rx_irq = 0;
|
u32 dma_irq = 0;
|
u32 old_ep_idx = 0;
|
|
/* Save index */
|
old_ep_idx = USBC_GetActiveEp(sunxi_udc_source.usbc_hd);
|
|
/* Read status registers */
|
misc_irq = USBC_INT_MiscPending(sunxi_udc_source.usbc_hd);
|
tx_irq = USBC_INT_EpPending(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX);
|
rx_irq = USBC_INT_EpPending(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX);
|
dma_irq = usb_dma_int_query();
|
/* RESET */
|
if(misc_irq & USBC_INTUSB_RESET)
|
{
|
sunxi_usb_dbg("IRQ: reset\n");
|
|
USBC_INT_ClearMiscPending(sunxi_udc_source.usbc_hd, USBC_INTUSB_RESET);
|
__usb_clear_all_irq();
|
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, 0);
|
USBC_Dev_SetAddress_default(sunxi_udc_source.usbc_hd);
|
|
sunxi_udc_source.address = 0; //default value
|
sunxi_udc_source.speed = USB_SPEED_HIGH; //default value
|
|
usb_dma_stop(sunxi_udc_source.dma_recv_channal);
|
usb_dma_stop(sunxi_udc_source.dma_send_channal);
|
|
usb_dma_set_pktlen(sunxi_udc_source.dma_send_channal, HIGH_SPEED_EP_MAX_PACKET_SIZE);
|
usb_dma_set_pktlen(sunxi_udc_source.dma_recv_channal, HIGH_SPEED_EP_MAX_PACKET_SIZE);
|
|
sunxi_ubuf.rx_ready_for_data = 0;
|
sunxi_udev_active->state_reset();
|
|
return ;
|
}
|
/* RESUME 暂时不处理,仅仅清理中断*/
|
if (misc_irq & USBC_INTUSB_RESUME)
|
{
|
sunxi_usb_dbg("IRQ: resume\n");
|
/* clear interrupt */
|
USBC_INT_ClearMiscPending(sunxi_udc_source.usbc_hd, USBC_INTUSB_RESUME);
|
}
|
/* SUSPEND */
|
if (misc_irq & USBC_INTUSB_SUSPEND)
|
{
|
sunxi_usb_dbg("IRQ: suspend\n");
|
/* clear interrupt */
|
USBC_INT_ClearMiscPending(sunxi_udc_source.usbc_hd, USBC_INTUSB_SUSPEND);
|
}
|
/* DISCONNECT */
|
if(misc_irq & USBC_INTUSB_DISCONNECT)
|
{
|
sunxi_usb_dbg("IRQ: disconnect\n");
|
|
USBC_INT_ClearMiscPending(sunxi_udc_source.usbc_hd, USBC_INTUSB_DISCONNECT);
|
|
return ;
|
}
|
#if 1
|
/* SOF */
|
if(misc_irq & USBC_INTUSB_SOF)
|
{
|
sunxi_usb_dbg("IRQ: SOF\n");
|
|
#ifdef CONFIG_SUNXI_USB_DETECT
|
sunxi_usb_detect_flag = 1;
|
#endif
|
set_usb_burn_boot_init_flag(1);
|
USBC_INT_DisableUsbMiscUint(sunxi_udc_source.usbc_hd, USBC_INTUSB_SOF);
|
|
USBC_INT_ClearMiscPending(sunxi_udc_source.usbc_hd, USBC_INTUSB_SOF);
|
}
|
#endif
|
/* ep0 */
|
if (tx_irq & (1 << SUNXI_USB_CTRL_EP_INDEX) )
|
{
|
sunxi_usb_dbg("IRQ: EP0\n");
|
|
USBC_INT_ClearEpPending(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX, SUNXI_USB_CTRL_EP_INDEX);
|
//中断内完成ep0处理
|
ep0_recv_op();
|
}
|
/* tx endpoint data transfers */
|
if (tx_irq & (1 << SUNXI_USB_BULK_IN_EP_INDEX))
|
{
|
sunxi_usb_dbg("tx irq occur\n");
|
/* Clear the interrupt bit by setting it to 1 */
|
USBC_INT_ClearEpPending(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX, SUNXI_USB_BULK_IN_EP_INDEX);
|
eptx_send_op();
|
}
|
|
/* rx endpoint data transfers */
|
if (rx_irq & (1 << SUNXI_USB_BULK_OUT_EP_INDEX))
|
{
|
sunxi_usb_dbg("rx irq occur\n");
|
/* Clear the interrupt bit by setting it to 1 */
|
USBC_INT_ClearEpPending(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, SUNXI_USB_BULK_OUT_EP_INDEX);
|
eprx_recv_op();
|
}
|
|
if(dma_irq & (1 << SUNXI_USB_BULK_IN_EP_INDEX))
|
{
|
sunxi_usb_dbg("tx dma\n");
|
__usb_send_by_dma_isr(NULL);
|
}
|
|
if(dma_irq & (1 << SUNXI_USB_BULK_OUT_EP_INDEX))
|
{
|
sunxi_usb_dbg("rx dma\n");
|
__usb_recv_by_dma_isr(NULL);
|
}
|
usb_dma_int_clear();
|
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx);
|
|
return ;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note : usb初始化动作,完成后,即可开启中断后,使用中断处理程序
|
*
|
*
|
************************************************************************************************************
|
*/
|
int sunxi_usb_init(int delaytime)
|
{
|
uint reg_val = 0;
|
|
if(sunxi_udev_active->state_init())
|
{
|
printf("sunxi usb err: fail to init usb device\n");
|
|
return -1;
|
}
|
|
//预先关闭usb中断
|
irq_disable(AW_IRQ_USB_OTG);
|
//初始化 sunxi_udc用到的资源
|
memset(&sunxi_udc_source, 0, sizeof(sunxi_udc_t));
|
//获取控制器地址资源
|
sunxi_udc_source.usbc_hd = USBC_open_otg(0);
|
if(sunxi_udc_source.usbc_hd == 0)
|
{
|
printf("sunxi usb err : USBC_open_otg failed\n");
|
|
return -1;
|
}
|
usb_dma_init(sunxi_udc_source.usbc_hd);
|
//断开usb
|
USBC_Dev_ConectSwitch(sunxi_udc_source.usbc_hd, USBC_DEVICE_SWITCH_OFF);
|
//预先关闭usb时钟
|
usb_close_clock();
|
//延时 delaytime ms
|
printf("delay time %d\n", delaytime);
|
__msdelay(delaytime);
|
//申请DMA资源
|
sunxi_udc_source.dma_send_channal = usb_dma_request();
|
if(!sunxi_udc_source.dma_send_channal)
|
{
|
printf("sunxi usb err : unable to request dma for usb send data\n");
|
|
goto __sunxi_usb_init_fail;
|
}
|
sunxi_usb_dbg("dma send ch %d\n", sunxi_udc_source.dma_send_channal);
|
sunxi_udc_source.dma_recv_channal = usb_dma_request();
|
if(!sunxi_udc_source.dma_recv_channal)
|
{
|
printf("sunxi usb err : unable to request dma for usb receive data\n");
|
|
goto __sunxi_usb_init_fail;
|
}
|
sunxi_usb_dbg("dma recv ch %d\n", sunxi_udc_source.dma_recv_channal);
|
|
sunxi_udc_source.address = 0;
|
sunxi_udc_source.speed = USB_SPEED_HIGH;
|
sunxi_udc_source.bulk_ep_max = HIGH_SPEED_EP_MAX_PACKET_SIZE;
|
sunxi_udc_source.fifo_size = BULK_FIFOSIZE;
|
sunxi_udc_source.bulk_in_addr = 100;
|
sunxi_udc_source.bulk_out_addr = sunxi_udc_source.bulk_in_addr + sunxi_udc_source.fifo_size * 2;
|
//内存资源
|
memset(&sunxi_ubuf, 0, sizeof(sunxi_ubuf_t));
|
|
sunxi_ubuf.rx_base_buffer = (uchar *)memalign(CONFIG_SYS_CACHELINE_SIZE, 1024);
|
if(!sunxi_ubuf.rx_base_buffer)
|
{
|
printf("%s:alloc memory fail\n", __func__);
|
|
goto __sunxi_usb_init_fail;
|
}
|
sunxi_ubuf.rx_req_buffer = sunxi_ubuf.rx_base_buffer;
|
|
usb_open_clock();
|
//设置为device模式
|
USBC_ForceId(sunxi_udc_source.usbc_hd, USBC_ID_TYPE_DEVICE);
|
//设置VBUS为高
|
USBC_ForceVbusValid(sunxi_udc_source.usbc_hd, USBC_VBUS_TYPE_HIGH);
|
|
USBC_Dev_ConectSwitch(sunxi_udc_source.usbc_hd, USBC_DEVICE_SWITCH_OFF);
|
//soft connect
|
USBC_EnableDpDmPullUp(sunxi_udc_source.usbc_hd);
|
USBC_EnableIdPullUp(sunxi_udc_source.usbc_hd);
|
//选择使用PIO模式搬移数据
|
USBC_SelectBus(sunxi_udc_source.usbc_hd, USBC_IO_TYPE_PIO, 0, 0);
|
//映射SRAM buffer
|
USBC_ConfigFIFO_Base(sunxi_udc_source.usbc_hd, 0, 0);
|
//
|
USBC_EnhanceSignal(sunxi_udc_source.usbc_hd);
|
//默认采用高速模式传输
|
#ifdef CONFIG_USB_1_1_DEVICE
|
USBC_Dev_ConfigTransferMode(sunxi_udc_source.usbc_hd, USBC_TS_TYPE_BULK, USBC_TS_MODE_FS);
|
#else
|
USBC_Dev_ConfigTransferMode(sunxi_udc_source.usbc_hd, USBC_TS_TYPE_BULK, USBC_TS_MODE_HS);
|
#endif
|
//配置发送端dma资源
|
usb_dma_setting(sunxi_udc_source.dma_send_channal, USB_DMA_FROM_DRAM_TO_HOST, SUNXI_USB_BULK_IN_EP_INDEX);
|
usb_dma_set_pktlen(sunxi_udc_source.dma_send_channal, HIGH_SPEED_EP_MAX_PACKET_SIZE);
|
//配置接收端dma资源
|
usb_dma_setting(sunxi_udc_source.dma_recv_channal, USB_DMA_FROM_HOST_TO_DRAM, SUNXI_USB_BULK_OUT_EP_INDEX);
|
usb_dma_set_pktlen(sunxi_udc_source.dma_recv_channal, HIGH_SPEED_EP_MAX_PACKET_SIZE);
|
/* disable all interrupt */
|
USBC_INT_DisableUsbMiscAll(sunxi_udc_source.usbc_hd);
|
USBC_INT_DisableEpAll(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX);
|
USBC_INT_DisableEpAll(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX);
|
|
/* 开启 reset、resume、suspend中断 */
|
USBC_INT_EnableUsbMiscUint(sunxi_udc_source.usbc_hd, USBC_INTUSB_SUSPEND | USBC_INTUSB_RESUME \
|
| USBC_INTUSB_RESET | USBC_INTUSB_SOF);
|
|
/* enbale ep0_tx_irq */
|
USBC_INT_EnableEp(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX, SUNXI_USB_CTRL_EP_INDEX);
|
|
__usb_bulk_ep_reset();
|
|
USBC_Dev_ConectSwitch(sunxi_udc_source.usbc_hd, USBC_DEVICE_SWITCH_ON);
|
|
irq_install_handler(AW_IRQ_USB_OTG, sunxi_usb_irq, NULL);
|
irq_enable(AW_IRQ_USB_OTG);
|
/* sun8iw10p1 spec default value is not correct, bit 1 should be 0 */
|
reg_val = readl(SUNXI_USBOTG_BASE+USBC_REG_o_PHYCTL);
|
reg_val &= ~(0x01<<1);
|
writel(reg_val, SUNXI_USBOTG_BASE+USBC_REG_o_PHYCTL);
|
|
#if defined(CONFIG_SUNXI_NCAT)
|
reg_val = readl(SUNXI_USBOTG_BASE+USBC_REG_o_PHYCTL);
|
reg_val &= ~(0x01<<USBC_PHY_CTL_SIDDQ);
|
reg_val |= 0x01<<USBC_PHY_CTL_VBUSVLDEXT;
|
writel(reg_val, SUNXI_USBOTG_BASE+USBC_REG_o_PHYCTL);
|
#endif
|
otg_phy_config();
|
|
return 0;
|
|
__sunxi_usb_init_fail:
|
if(sunxi_udc_source.dma_send_channal)
|
{
|
usb_dma_release(sunxi_udc_source.dma_send_channal);
|
}
|
if(sunxi_udc_source.dma_recv_channal)
|
{
|
usb_dma_release(sunxi_udc_source.dma_recv_channal);
|
}
|
if(sunxi_udc_source.usbc_hd)
|
{
|
USBC_close_otg(sunxi_udc_source.usbc_hd);
|
}
|
if(sunxi_ubuf.rx_base_buffer)
|
{
|
free(sunxi_ubuf.rx_base_buffer);
|
}
|
|
return -1;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
int sunxi_usb_exit(void)
|
{
|
irq_disable(AW_IRQ_USB_OTG);
|
irq_free_handler(AW_IRQ_USB_OTG);
|
if(sunxi_udc_source.dma_send_channal)
|
{
|
usb_dma_stop(sunxi_udc_source.dma_send_channal);
|
usb_dma_release(sunxi_udc_source.dma_send_channal);
|
}
|
if(sunxi_udc_source.dma_recv_channal)
|
{
|
usb_dma_stop(sunxi_udc_source.dma_recv_channal);
|
usb_dma_release(sunxi_udc_source.dma_recv_channal);
|
}
|
if(sunxi_ubuf.rx_base_buffer)
|
{
|
free(sunxi_ubuf.rx_base_buffer);
|
}
|
USBC_close_otg(sunxi_udc_source.usbc_hd);
|
usb_close_clock();
|
sunxi_udev_active->state_exit();
|
memset(&sunxi_ubuf, 0, sizeof(sunxi_ubuf_t));
|
|
return 0;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
static void __usb_send_by_dma_isr(void *p_arg)
|
{
|
sunxi_udev_active->dma_tx_isr(p_arg);
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
static void __usb_recv_by_dma_isr(void *p_arg)
|
{
|
u32 old_ep_idx;
|
|
old_ep_idx = USBC_GetActiveEp(sunxi_udc_source.usbc_hd);
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); //选择RXEP
|
|
//选择使用IO方式搬运数据
|
sunxi_usb_dbg("select io mode to transfer data\n");
|
USBC_Dev_ClearEpDma(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX);
|
|
if(usb_dma_trans_unaliged_bytes)
|
{
|
uint fifo, this_len;
|
|
this_len = USBC_ReadLenFromFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX);
|
fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX);
|
USBC_ReadPacket(sunxi_udc_source.usbc_hd, fifo, this_len, usb_dma_trans_unaligned_buf);
|
__usb_readcomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1); //返回状态
|
usb_dma_trans_unaliged_bytes = 0;
|
}
|
//如果当前dma传输的不是完整包,则需要手动清除中断
|
if(sunxi_ubuf.request_size % sunxi_udc_source.bulk_ep_max)
|
{
|
USBC_Dev_ReadDataStatus(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1);
|
//printf("clear rx pending manually\n");
|
}
|
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx);
|
|
sunxi_udev_active->dma_rx_isr(p_arg);
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
static void __usb_clear_all_irq(void)
|
{
|
USBC_INT_ClearEpPendingAll(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX);
|
USBC_INT_ClearEpPendingAll(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX);
|
USBC_INT_ClearMiscPendingAll(sunxi_udc_source.usbc_hd);
|
}
|
/*
|
*******************************************************************************
|
* __usb_readcomplete
|
*
|
* Description:
|
* void
|
*
|
* Parameters:
|
* void
|
*
|
* Return value:
|
* void
|
*
|
* note:
|
* void
|
*
|
*******************************************************************************
|
*/
|
static void __usb_readcomplete(__hdle hUSB, u32 ep_type, u32 complete)
|
{
|
USBC_Dev_ReadDataStatus(hUSB, ep_type, complete);
|
|
if(ep_type == USBC_EP_TYPE_EP0)
|
{
|
/* clear data end */
|
if(complete)
|
{
|
USBC_Dev_Ctrl_ClearSetupEnd(hUSB);
|
}
|
|
/* clear irq */
|
USBC_INT_ClearEpPending(hUSB, USBC_EP_TYPE_TX, SUNXI_USB_CTRL_EP_INDEX);
|
}
|
|
return;
|
}
|
/*
|
*******************************************************************************
|
* __usb_writecomplete
|
*
|
* Description:
|
* void
|
*
|
* Parameters:
|
* void
|
*
|
* Return value:
|
* void
|
*
|
* note:
|
* void
|
*
|
*******************************************************************************
|
*/
|
static void __usb_writecomplete(__hdle hUSB, u32 ep_type, u32 complete)
|
{
|
USBC_Dev_WriteDataStatus(hUSB, ep_type, complete);
|
|
/* wait for tx packet sent out */
|
while(USBC_Dev_IsWriteDataReady(hUSB, ep_type));
|
|
if(ep_type == USBC_EP_TYPE_EP0)
|
{
|
/* clear data end */
|
if(complete)
|
{
|
USBC_Dev_Ctrl_ClearSetupEnd(hUSB);
|
}
|
|
/* clear irq */
|
USBC_INT_ClearEpPending(hUSB, USBC_EP_TYPE_TX, SUNXI_USB_CTRL_EP_INDEX);
|
}
|
|
return;
|
}
|
/*
|
*******************************************************************************
|
* __usb_bulk_ep_reset
|
*
|
* Description:
|
* void
|
*
|
* Parameters:
|
* void
|
*
|
* Return value:
|
* void
|
*
|
* note:
|
* void
|
*
|
*******************************************************************************
|
*/
|
static void __usb_bulk_ep_reset (void)
|
{
|
u8 old_ep_index = 0;
|
|
old_ep_index = USBC_GetActiveEp(sunxi_udc_source.usbc_hd);
|
/* tx */
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_IN_EP_INDEX);
|
USBC_Dev_ConfigEp(sunxi_udc_source.usbc_hd, USBC_TS_TYPE_BULK, USBC_EP_TYPE_TX, 1, sunxi_udc_source.bulk_ep_max & 0x7ff);
|
USBC_ConfigFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX, 1, sunxi_udc_source.fifo_size, (uint)sunxi_udc_source.bulk_out_addr);
|
USBC_INT_EnableEp(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX, SUNXI_USB_BULK_IN_EP_INDEX);
|
/* rx */
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX);
|
USBC_Dev_ConfigEp(sunxi_udc_source.usbc_hd, USBC_TS_TYPE_BULK, USBC_EP_TYPE_RX, 1, sunxi_udc_source.bulk_ep_max & 0x7ff);
|
USBC_ConfigFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1, sunxi_udc_source.fifo_size, (uint)sunxi_udc_source.bulk_in_addr);
|
USBC_INT_EnableEp(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, SUNXI_USB_BULK_OUT_EP_INDEX);
|
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_index);
|
|
return;
|
}
|
/*
|
*******************************************************************************
|
* __usb_read_ep0_data
|
*
|
* Description:
|
* void
|
*
|
* Parameters:
|
* void
|
*
|
* Return value:
|
* void
|
*
|
* note:
|
* void
|
*
|
*******************************************************************************
|
*/
|
static int __usb_read_ep0_data(void *buffer, uint data_type)
|
{
|
u32 fifo_count = 0;
|
u32 fifo = 0;
|
int ret = 0;
|
u32 old_ep_index = 0;
|
|
old_ep_index = USBC_GetActiveEp(sunxi_udc_source.usbc_hd);
|
fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_CTRL_EP_INDEX);
|
fifo_count = USBC_ReadLenFromFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0);
|
if(!data_type)
|
{
|
if(fifo_count != 8 )
|
{
|
printf("err: ep0 fifo_count %d is not 8\n", fifo_count);
|
return -1;
|
}
|
}
|
USBC_ReadPacket(sunxi_udc_source.usbc_hd, fifo, fifo_count, (void *)buffer);
|
__usb_readcomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0, 1);
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_index);
|
|
return ret;
|
}
|
/*
|
*******************************************************************************
|
* __sunxi_udc_set_address
|
*
|
* Description:
|
* void
|
*
|
* Parameters:
|
* void
|
*
|
* Return value:
|
* void
|
*
|
* note:
|
* void
|
*
|
*******************************************************************************
|
*/
|
static int __sunxi_udc_set_address(uchar address)
|
{
|
USBC_Dev_SetAddress(sunxi_udc_source.usbc_hd, address);
|
if(USBC_Dev_QueryTransferMode(sunxi_udc_source.usbc_hd) == USBC_TS_MODE_HS)
|
{
|
sunxi_udc_source.speed = USB_SPEED_HIGH;
|
sunxi_udc_source.fifo_size = HIGH_SPEED_EP_MAX_PACKET_SIZE;
|
sunxi_usb_dbg("usb speed: HIGH\n");
|
}
|
else
|
{
|
sunxi_udc_source.speed = USB_SPEED_FULL;
|
sunxi_udc_source.fifo_size = FULL_SPEED_EP_MAX_PACKET_SIZE;
|
sunxi_usb_dbg("usb speed: FULL\n");
|
}
|
|
return SUNXI_USB_REQ_SUCCESSED;
|
}
|
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
#if 0
|
static int __usb_read_fifo(void *buffer, unsigned int buffer_size)
|
{
|
u32 old_ep_idx = 0;
|
u32 fifo = 0;
|
u32 transfered = 0;
|
u32 left = 0;
|
u32 this_len;
|
|
old_ep_idx = USBC_GetActiveEp(sunxi_udc_source.usbc_hd);
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); //选择当前EP
|
|
fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); //选择fifo
|
|
left = buffer_size;
|
|
if(left)
|
{
|
while(left)
|
{
|
if(USBC_Dev_IsReadDataReady(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX))
|
{
|
this_len = USBC_ReadLenFromFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX);
|
this_len = USBC_ReadPacket(sunxi_udc_source.usbc_hd, fifo, this_len, buffer + transfered);
|
|
transfered += this_len;
|
left -= this_len;
|
|
__usb_readcomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1); //返回状态
|
}
|
}
|
USBC_INT_ClearEpPending(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, SUNXI_USB_BULK_OUT_EP_INDEX);
|
}
|
else
|
{
|
if(USBC_Dev_IsReadDataReady(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX))
|
{
|
this_len = USBC_ReadLenFromFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX);
|
this_len = USBC_ReadPacket(sunxi_udc_source.usbc_hd, fifo, this_len, buffer);
|
|
transfered = this_len;
|
__usb_readcomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1); //返回状态
|
}
|
else
|
{
|
sunxi_usb_dbg("sunxi usb rxdata not ready\n");
|
}
|
}
|
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx);
|
|
sunxi_usb_dbg("read bytes 0x%x\n", transfered);
|
|
return transfered;
|
}
|
#endif
|
/*
|
*******************************************************************************
|
* fastboot_tx_status
|
*
|
* Description:
|
* void
|
*
|
* Parameters:
|
* void
|
*
|
* Return value:
|
* void
|
*
|
* note:
|
* void
|
*
|
*******************************************************************************
|
*/
|
static int __usb_write_fifo(uchar *buffer, unsigned int buffer_size)
|
{
|
u32 old_ep_idx = 0;
|
u32 fifo = 0;
|
u32 transfered = 0;
|
u32 left = 0;
|
u32 this_len;
|
|
/* Save index */
|
old_ep_idx = USBC_GetActiveEp(sunxi_udc_source.usbc_hd);
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_IN_EP_INDEX);
|
|
left = buffer_size;
|
fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_IN_EP_INDEX);
|
|
while(left)
|
{
|
this_len = MIN(sunxi_udc_source.fifo_size, left);
|
this_len = USBC_WritePacket(sunxi_udc_source.usbc_hd, fifo, this_len, buffer + transfered);
|
|
transfered += this_len;
|
left -= this_len;
|
|
__usb_writecomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX, 1);
|
}
|
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx);
|
|
return 0;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
void sunxi_udc_ep_reset(void)
|
{
|
__usb_bulk_ep_reset();
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
int sunxi_udc_start_recv_by_dma(void* mem_base, uint length)
|
{
|
uint old_ep_idx;
|
ulong mem_buf = (ulong)mem_base;
|
usb_dma_trans_unaliged_bytes = length & (sizeof(int) - 1);
|
length &= ~(sizeof(int) - 1);
|
usb_dma_trans_unaligned_buf = (uchar *)mem_buf + length;
|
|
old_ep_idx = USBC_GetActiveEp(sunxi_udc_source.usbc_hd);
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); //选择当前EP
|
//usb控制器选择dma传输方式
|
USBC_Dev_ConfigEpDma(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX);
|
|
//刷掉cache
|
flush_cache(mem_buf, ALIGN(length, 64));
|
//使能dma传输
|
sunxi_ubuf.request_size = length;
|
sunxi_usb_dbg("dma start 0x%lx, length 0x%x\n", mem_buf, length);
|
usb_dma_start(sunxi_udc_source.dma_recv_channal, mem_buf, length);
|
//恢复EP
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx); //恢复原有EP
|
|
return 0;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
void sunxi_udc_send_setup(uint bLength, void *buffer)
|
{
|
u32 fifo = 0;
|
|
if(!bLength)
|
{
|
/* sent zero packet */
|
__usb_writecomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0, 1);
|
}
|
else
|
{
|
fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_CTRL_EP_INDEX);
|
USBC_WritePacket(sunxi_udc_source.usbc_hd, fifo, bLength, (void *)buffer);
|
__usb_writecomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0, 1);
|
}
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
int sunxi_udc_set_configuration(int config_param)
|
{
|
return 0;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
int sunxi_udc_set_address(uchar address)
|
{
|
sunxi_udc_source.address = address;
|
USBC_Dev_ReadDataStatus(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0, 1);
|
return SUNXI_USB_REQ_SUCCESSED;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
int sunxi_udc_send_data(void *buffer, unsigned int buffer_size)
|
{
|
sunxi_ubuf.rx_ready_for_data = 0;
|
|
return __usb_write_fifo((uchar *)buffer, buffer_size);
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
int sunxi_udc_get_ep_max(void)
|
{
|
return sunxi_udc_source.bulk_ep_max;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
int sunxi_udc_get_ep_in_type(void)
|
{
|
return (0x80 | SUNXI_USB_BULK_IN_EP_INDEX);
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
int sunxi_udc_get_ep_out_type(void)
|
{
|
return SUNXI_USB_BULK_OUT_EP_INDEX;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
static int ep0_recv_op(void)
|
{
|
u32 old_ep_index = 0;
|
int ret = 0;
|
static uint ep0_stage = 0;
|
|
if(!ep0_stage)
|
{
|
memset(&sunxi_udc_source.standard_reg, 0, sizeof(struct usb_device_request));
|
}
|
|
old_ep_index = USBC_GetActiveEp(sunxi_udc_source.usbc_hd);
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_CTRL_EP_INDEX);
|
//clear stall status
|
if(USBC_Dev_IsEpStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0))
|
{
|
printf("ERR: handle_ep0: ep0 stall\n");
|
|
USBC_Dev_EpClearStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0);
|
ret = -1;
|
|
goto __ep0_recv_op_err;
|
}
|
|
//clear setup end
|
if (USBC_Dev_Ctrl_IsSetupEnd(sunxi_udc_source.usbc_hd))
|
{
|
USBC_Dev_Ctrl_ClearSetupEnd(sunxi_udc_source.usbc_hd);
|
}
|
//检查读ep0数据是否完成
|
if(USBC_Dev_IsReadDataReady(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0))
|
{
|
uint status;
|
|
if(!ep0_stage)
|
{
|
status = __usb_read_ep0_data(&sunxi_udc_source.standard_reg, ep0_stage);
|
}
|
else
|
{
|
status = __usb_read_ep0_data(sunxi_usb_ep0_buffer, ep0_stage);
|
}
|
if(status!= 0)
|
{
|
printf("sunxi usb err: read_request failed\n");
|
ret = -1;
|
|
goto __ep0_recv_op_err;
|
}
|
}
|
else //此情况通常由于ep0发送空包引起,可以不处理
|
{
|
sunxi_usb_dbg("sunxi usb msg: ep0 rx data is not ready\n");
|
if(sunxi_udc_source.address)
|
{
|
__sunxi_udc_set_address(sunxi_udc_source.address&0xff);
|
printf("set address 0x%x ok\n", sunxi_udc_source.address);
|
sunxi_udc_source.address = 0;
|
}
|
goto __ep0_recv_op_err;
|
}
|
/* Check data */
|
if(USB_REQ_TYPE_STANDARD == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_TYPE_MASK))
|
{
|
ret = SUNXI_USB_REQ_UNMATCHED_COMMAND;
|
|
/* standard */
|
switch(sunxi_udc_source.standard_reg.bRequest)
|
{
|
case USB_REQ_GET_STATUS: // 0x00
|
{
|
/* device-to-host */
|
if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK))
|
{
|
ret = sunxi_udev_active->standard_req_op(USB_REQ_GET_STATUS, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer);
|
}
|
|
break;
|
}
|
case USB_REQ_CLEAR_FEATURE: // 0x01
|
{
|
/* host-to-device */
|
if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK))
|
{
|
ret = sunxi_udev_active->standard_req_op(USB_REQ_CLEAR_FEATURE, &sunxi_udc_source.standard_reg, NULL);
|
}
|
|
break;
|
}
|
case USB_REQ_SET_FEATURE: // 0x03
|
{
|
/* host-to-device */
|
if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK))
|
{
|
ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_FEATURE, &sunxi_udc_source.standard_reg, NULL);
|
}
|
|
break;
|
}
|
case USB_REQ_SET_ADDRESS: // 0x05
|
{
|
/* host-to-device */
|
if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK))
|
{
|
if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK))
|
{
|
/* receiver is device */
|
ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_ADDRESS, &sunxi_udc_source.standard_reg, NULL);
|
}
|
}
|
|
break;
|
}
|
case USB_REQ_GET_DESCRIPTOR: // 0x06
|
{
|
/* device-to-host */
|
if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK))
|
{
|
if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK))
|
{
|
ret = sunxi_udev_active->standard_req_op(USB_REQ_GET_DESCRIPTOR, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer);
|
}
|
}
|
|
break;
|
}
|
case USB_REQ_SET_DESCRIPTOR: // 0x07
|
{
|
/* host-to-device */
|
if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK))
|
{
|
if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK))
|
{
|
//there is some problem
|
ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_DESCRIPTOR, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer);
|
}
|
}
|
|
break;
|
}
|
case USB_REQ_GET_CONFIGURATION: // 0x08
|
{
|
/* device-to-host */
|
if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK))
|
{
|
if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK))
|
{
|
ret = sunxi_udev_active->standard_req_op(USB_REQ_GET_CONFIGURATION, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer);
|
}
|
}
|
|
break;
|
}
|
case USB_REQ_SET_CONFIGURATION: // 0x09
|
{
|
/* host-to-device */
|
if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK))
|
{
|
if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK))
|
{
|
ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_CONFIGURATION, &sunxi_udc_source.standard_reg, NULL);
|
}
|
}
|
|
break;
|
}
|
case USB_REQ_GET_INTERFACE: // 0x0a
|
{
|
/* device-to-host */
|
if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK))
|
{
|
if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK))
|
{
|
ret = sunxi_udev_active->standard_req_op(USB_REQ_GET_INTERFACE, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer);
|
}
|
}
|
|
break;
|
}
|
case USB_REQ_SET_INTERFACE: // 0x0b
|
{
|
/* host-to-device */
|
if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK))
|
{
|
if(USB_RECIP_INTERFACE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK))
|
{
|
ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_INTERFACE, &sunxi_udc_source.standard_reg, NULL);
|
}
|
}
|
|
break;
|
}
|
case USB_REQ_SYNCH_FRAME: // 0x0b
|
{
|
/* device-to-host */
|
if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK))
|
{
|
if(USB_RECIP_INTERFACE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK))
|
{
|
//there is some problem
|
if(!ep0_stage)
|
{
|
ep0_stage = 1;
|
}
|
else
|
{
|
ret = sunxi_udev_active->standard_req_op(USB_REQ_SYNCH_FRAME, &sunxi_udc_source.standard_reg, NULL);
|
ep0_stage = 0;
|
}
|
}
|
}
|
|
break;
|
}
|
default:
|
{
|
printf("sunxi usb err: unknown usb out request to device\n");
|
|
USBC_Dev_EpSendStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0);
|
ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED;
|
ep0_stage = 0;
|
|
break;
|
}
|
}
|
}
|
else
|
{
|
/* Non-Standard Req */
|
printf("non standard req\n");
|
ret = sunxi_udev_active->nonstandard_req_op(USB_REQ_GET_STATUS, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer, ep0_stage);
|
if(ret == SUNXI_USB_REQ_DATA_HUNGRY)
|
{
|
ep0_stage = 1;
|
}
|
else if(ret == SUNXI_USB_REQ_SUCCESSED)
|
{
|
ep0_stage = 0;
|
}
|
else if(ret < 0)
|
{
|
ep0_stage = 0;
|
printf("err: unkown bmRequestType(%d)\n", sunxi_udc_source.standard_reg.bmRequestType);
|
USBC_Dev_EpSendStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0);
|
}
|
}
|
|
__ep0_recv_op_err:
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_index);
|
|
return ret;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
static int eprx_recv_op(void)
|
{
|
uint old_ep_index;
|
uint this_len;
|
uint fifo;
|
|
old_ep_index = USBC_GetActiveEp(sunxi_udc_source.usbc_hd);
|
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX);
|
|
if (USBC_Dev_IsEpStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX))
|
{
|
USBC_Dev_EpClearStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX);
|
|
printf("sunxi ubs read error: usb rx ep is busy already\n");
|
}
|
else
|
{
|
if(USBC_Dev_IsReadDataReady(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX))
|
{
|
this_len = USBC_ReadLenFromFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX);
|
if(get_fastboot_data_flag() == 1)
|
{
|
fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX);
|
|
sunxi_ubuf.rx_req_length = USBC_ReadPacket(sunxi_udc_source.usbc_hd, fifo, this_len, sunxi_ubuf.rx_req_buffer);
|
sunxi_ubuf.rx_req_buffer += this_len;
|
|
sunxi_usb_dbg("special read ep bytes 0x%x\n", sunxi_ubuf.rx_req_length);
|
__usb_readcomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1); //返回状态
|
}
|
else if(!sunxi_ubuf.rx_ready_for_data)
|
{
|
fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX);
|
|
memset(sunxi_ubuf.rx_req_buffer, 0, 64);
|
sunxi_ubuf.rx_req_length = USBC_ReadPacket(sunxi_udc_source.usbc_hd, fifo, this_len, sunxi_ubuf.rx_req_buffer);
|
sunxi_ubuf.rx_ready_for_data = 1;
|
|
sunxi_usb_dbg("read ep bytes 0x%x\n", sunxi_ubuf.rx_req_length);
|
__usb_readcomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1); //返回状态
|
}
|
else
|
{
|
sunxi_usb_dbg("eprx do nothing and left it to dma\n");
|
}
|
}
|
else
|
{
|
sunxi_usb_dbg("sunxi usb rxdata not ready\n");
|
}
|
}
|
|
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_index);
|
|
return 0;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
static int eptx_send_op(void)
|
{
|
return 0;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
void sunxi_usb_main_loop(int delaytime)
|
{
|
int ret;
|
|
if(sunxi_usb_init(delaytime))
|
{
|
printf("usb init fail\n");
|
|
sunxi_usb_exit();
|
|
return ;
|
}
|
printf("usb init ok\n");
|
|
while(1)
|
{
|
ret = sunxi_udev_active->state_loop(&sunxi_ubuf);
|
if(ret)
|
{
|
break;
|
}
|
|
if(ctrlc())
|
{
|
break;
|
}
|
}
|
|
printf("exit usb\n");
|
sunxi_usb_exit();
|
sunxi_update_subsequent_processing(ret);
|
|
return ;
|
}
|
/*
|
************************************************************************************************************
|
*
|
* function
|
*
|
* name :
|
*
|
* parmeters :
|
*
|
* return :
|
*
|
* note :
|
*
|
*
|
************************************************************************************************************
|
*/
|
int sunxi_usb_extern_loop(void)
|
{
|
return sunxi_udev_active->state_loop(&sunxi_ubuf);
|
}
|