1432 lines
38 KiB
C
Executable File
1432 lines
38 KiB
C
Executable File
/*
|
||
* (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/intc.h>
|
||
#include <sys_partition.h>
|
||
#include "usb_dma_control.h"
|
||
#include <sunxi_board.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 */
|
||
|
||
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 eptx_send_op(void);
|
||
static int eprx_recv_op(void);
|
||
static int ep0_recv_op(void);
|
||
|
||
extern int fastboot_data_flag;
|
||
/*
|
||
************************************************************************************************************
|
||
*
|
||
* 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 <20><>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>*/
|
||
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 0
|
||
/* SOF */
|
||
if(misc_irq & USBC_INTUSB_SOF)
|
||
{
|
||
sunxi_usb_dbg("IRQ: SOF\n");
|
||
|
||
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);
|
||
//<2F>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ep0<70><30><EFBFBD><EFBFBD>
|
||
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<73><62>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɺ<C9BA><F3A3ACBC>ɿ<EFBFBD><C9BF><EFBFBD><EFBFBD>жϺ<D0B6><CFBA><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD>жϴ<D0B6><CFB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
*
|
||
*
|
||
************************************************************************************************************
|
||
*/
|
||
int sunxi_usb_init(int delaytime)
|
||
{
|
||
if(sunxi_udev_active->state_init())
|
||
{
|
||
printf("sunxi usb err: fail to init usb device\n");
|
||
|
||
return -1;
|
||
}
|
||
//Ԥ<>ȹر<C8B9>usb<73>ж<EFBFBD>
|
||
irq_disable(AW_IRQ_USB_OTG);
|
||
//<2F><>ʼ<EFBFBD><CABC> sunxi_udc<64>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD>Դ
|
||
memset(&sunxi_udc_source, 0, sizeof(sunxi_udc_t));
|
||
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7>Դ
|
||
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);
|
||
//<2F>Ͽ<EFBFBD>usb
|
||
USBC_Dev_ConectSwitch(sunxi_udc_source.usbc_hd, USBC_DEVICE_SWITCH_OFF);
|
||
//Ԥ<>ȹر<C8B9>usbʱ<62><CAB1>
|
||
usb_close_clock();
|
||
//<2F><>ʱ delaytime ms
|
||
printf("delay time %d\n", delaytime);
|
||
__msdelay(delaytime);
|
||
//<2F><><EFBFBD><EFBFBD>DMA<4D><41>Դ
|
||
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;
|
||
//<2F>ڴ<EFBFBD><DAB4><EFBFBD>Դ
|
||
memset(&sunxi_ubuf, 0, sizeof(sunxi_ubuf_t));
|
||
|
||
sunxi_ubuf.rx_base_buffer = (uchar *)malloc(1024);
|
||
if(!sunxi_ubuf.rx_base_buffer)
|
||
{
|
||
printf("sunxi usb err: fail to malloc memory for rx command buffer\n");
|
||
|
||
goto __sunxi_usb_init_fail;
|
||
}
|
||
sunxi_ubuf.rx_req_buffer = sunxi_ubuf.rx_base_buffer;
|
||
|
||
usb_open_clock();
|
||
//<2F><><EFBFBD><EFBFBD>Ϊdeviceģʽ
|
||
USBC_ForceId(sunxi_udc_source.usbc_hd, USBC_ID_TYPE_DEVICE);
|
||
//<2F><><EFBFBD><EFBFBD>VBUSΪ<53><CEAA>
|
||
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);
|
||
//ѡ<><D1A1>ʹ<EFBFBD><CAB9>PIOģʽ<C4A3><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
USBC_SelectBus(sunxi_udc_source.usbc_hd, USBC_IO_TYPE_PIO, 0, 0);
|
||
//ӳ<><D3B3>SRAM buffer
|
||
USBC_ConfigFIFO_Base(sunxi_udc_source.usbc_hd, 0, 0);
|
||
//
|
||
USBC_EnhanceSignal(sunxi_udc_source.usbc_hd);
|
||
//Ĭ<>ϲ<EFBFBD><CFB2>ø<EFBFBD><C3B8><EFBFBD>ģʽ<C4A3><CABD><EFBFBD><EFBFBD>
|
||
#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
|
||
//<2F><><EFBFBD>÷<EFBFBD><C3B7>Ͷ<EFBFBD>dma<6D><61>Դ
|
||
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);
|
||
//<2F><><EFBFBD>ý<EFBFBD><C3BD>ն<EFBFBD>dma<6D><61>Դ
|
||
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);
|
||
|
||
/* <20><><EFBFBD><EFBFBD> reset<65><74>resume<6D><65>suspend<6E>ж<EFBFBD> */
|
||
USBC_INT_EnableUsbMiscUint(sunxi_udc_source.usbc_hd, USBC_INTUSB_SUSPEND | USBC_INTUSB_RESUME \
|
||
| USBC_INTUSB_RESET);
|
||
|
||
/* 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);
|
||
|
||
//67 spec default value is not correct, bit 1 should be 0
|
||
//OTG_BASE is 0x1c19000
|
||
*(volatile unsigned int *)(0x1c19000+USBC_REG_o_PHYCTL) = 0;
|
||
|
||
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); //ѡ<><D1A1>RXEP
|
||
|
||
//ѡ<><D1A1>ʹ<EFBFBD><CAB9>IO<49><4F>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
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); //<2F><><EFBFBD><EFBFBD>״̬
|
||
usb_dma_trans_unaliged_bytes = 0;
|
||
}
|
||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰdma<6D><61><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
|
||
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;
|
||
}
|
||
/*
|
||
************************************************************************************************************
|
||
*
|
||
* 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); //ѡ<><D1A1><EFBFBD><EFBFBD>ǰEP
|
||
|
||
fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); //ѡ<><D1A1>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); //<2F><><EFBFBD><EFBFBD>״̬
|
||
}
|
||
}
|
||
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); //<2F><><EFBFBD><EFBFBD>״̬
|
||
}
|
||
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_buf, uint length)
|
||
{
|
||
uint old_ep_idx;
|
||
|
||
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); //ѡ<><D1A1><EFBFBD><EFBFBD>ǰEP
|
||
//usb<73><62><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1>dma<6D><61><EFBFBD>䷽ʽ
|
||
USBC_Dev_ConfigEpDma(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX);
|
||
|
||
//ˢ<><CBA2>cache
|
||
flush_cache((uint)mem_buf, length);
|
||
//ʹ<><CAB9>dma<6D><61><EFBFBD><EFBFBD>
|
||
sunxi_ubuf.request_size = length;
|
||
sunxi_usb_dbg("dma start 0x%x, length 0x%x\n", mem_buf, length);
|
||
usb_dma_start(sunxi_udc_source.dma_recv_channal, (uint)mem_buf, length);
|
||
//<2F>ָ<EFBFBD>EP
|
||
USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx); //<2F>ָ<EFBFBD>ԭ<EFBFBD><D4AD>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)
|
||
{
|
||
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 :
|
||
*
|
||
*
|
||
************************************************************************************************************
|
||
*/
|
||
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);
|
||
}
|
||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ep0<70><30><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>
|
||
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 //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ep0<70><30><EFBFBD>Ϳհ<CDBF><D5B0><EFBFBD><EFBFBD>𣬿<EFBFBD><F0A3ACBF>Բ<EFBFBD><D4B2><EFBFBD><EFBFBD><EFBFBD>
|
||
{
|
||
sunxi_usb_dbg("sunxi usb msg: ep0 rx data is not ready\n");
|
||
|
||
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(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); //<2F><><EFBFBD><EFBFBD>״̬
|
||
}
|
||
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); //<2F><><EFBFBD><EFBFBD>״̬
|
||
}
|
||
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);
|
||
}
|