//Copyright 2007-2013
//Allwinner Technology Co., Ltd. <www.allwinnertech.com>
//Jerry Wang <wangflord@allwinnertech.com>
#include "usb_base.h"
#include <scsi.h>
#include <asm/arch/dma.h>
#include <sys_partition.h>
#include <fastboot.h>
#include "usb_fastboot.h"
#include <android_misc.h>
#include <sunxi_board.h>
#include <pmu.h>
#include <sunxi_mbr.h>
#include "../sprite/sparse/sparse.h"
DECLARE_GLOBAL_DATA_PTR;
static int sunxi_usb_fastboot_write_enable = 0;
static int sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE;
static int sunxi_usb_fastboot_status_pre = -1;
static fastboot_trans_set_t trans_data;
static uint all_download_bytes;
int fastboot_data_flag;
extern int sunxi_usb_exit(void);
static int __usb_set_interface(struct usb_device_request *req)
{
sunxi_usb_dbg("set interface\n");
//Only support interface 0, alternate 0
if( 0==req->wIndex && 0==req->wValue ){
sunxi_udc_ep_reset();
}else{
printf("err: invalid wIndex and wValue, (0, %d), (0, %d)\n", req->wIndex, req->wValue);
return SUNXI_USB_REQ_OP_ERR;
}
return SUNXI_USB_REQ_SUCCESSED;
}
static int __usb_set_address(struct usb_device_request *req)
{
uchar address;
address = req->wValue & 0x7f;
printf("set address 0x%x\n", address);
sunxi_udc_set_address(address);
return SUNXI_USB_REQ_SUCCESSED;
}
static int __usb_set_configuration(struct usb_device_request *req)
{
printf("set configuration\n");
//Only support 1 configuration so nak anything else
if( 1 == req->wValue ){
sunxi_udc_ep_reset();
}else{
printf("err: invalid wValue, (0, %d)\n", req->wValue);
return SUNXI_USB_REQ_OP_ERR;
}
sunxi_udc_set_configuration(req->wValue);
return SUNXI_USB_REQ_SUCCESSED;
}
//获取描述符,获取配置处理
static int __usb_get_descriptor(struct usb_device_request *req, uchar *buffer)
{
int ret = SUNXI_USB_REQ_SUCCESSED;
//获取描述符
switch( req->wValue >> 8 ){
case USB_DT_DEVICE:
{
//设备描述符
struct usb_device_descriptor *dev_dscrptr;
//printf("get device descriptor\n" );
dev_dscrptr = (struct usb_device_descriptor *)buffer;
memset((void *)dev_dscrptr, 0, sizeof(struct usb_device_descriptor));
dev_dscrptr->bLength = MIN(req->wLength, sizeof (struct usb_device_descriptor));
//设备描述符的字节数大小
dev_dscrptr->bDescriptorType = USB_DT_DEVICE;
//设备描述符的类型编号
#ifdef CONFIG_USB_1_1_DEVICE
error!!!
dev_dscrptr->bcdUSB = 0x110;
#else
dev_dscrptr->bcdUSB = 0x200;
//USB版本号
#endif
dev_dscrptr->bDeviceClass = 0xff;
//设备类:大容量存储
//USB分配的设备类代码
dev_dscrptr->bDeviceSubClass = 0xff;
//USB分配的子类代码
dev_dscrptr->bDeviceProtocol = 0xff;
//USB分配的设备协议代码
dev_dscrptr->bMaxPacketSize0 = 0x40;
//端点0的最大包大小
dev_dscrptr->idVendor = DEVICE_VENDOR_ID;
//厂商编号
dev_dscrptr->idProduct = DEVICE_PRODUCT_ID;
//产品编号
dev_dscrptr->bcdDevice = DEVICE_BCD;
//设备出厂编号
dev_dscrptr->iManufacturer = SUNXI_FASTBOOT_DEVICE_STRING_MANUFACTURER_INDEX;
//设备厂商字符串的索引
dev_dscrptr->iProduct = SUNXI_FASTBOOT_DEVICE_STRING_PRODUCT_INDEX;
//描述产品字符串的索引
dev_dscrptr->iSerialNumber = SUNXI_FASTBOOT_DEVICE_STRING_SERIAL_NUMBER_INDEX;
//描述设备序列号字符串的索引
dev_dscrptr->bNumConfigurations = 1;
//可能的配置数量
sunxi_udc_send_setup(dev_dscrptr->bLength, buffer);
}
break;
case USB_DT_CONFIG:
{
//配置描述符
struct usb_configuration_descriptor *config_dscrptr;
struct usb_interface_descriptor *inter_dscrptr;
struct usb_endpoint_descriptor *ep_in, *ep_out;
unsigned char bytes_remaining = req->wLength;
unsigned char bytes_total = 0;
//printf("get config descriptor\n");
bytes_total = sizeof(struct usb_configuration_descriptor) +
sizeof(struct usb_interface_descriptor) +
sizeof(struct usb_endpoint_descriptor) +
sizeof(struct usb_endpoint_descriptor);
memset(buffer, 0, bytes_total);
config_dscrptr = (struct usb_configuration_descriptor *)(buffer + 0);
inter_dscrptr = (struct usb_interface_descriptor *)(buffer + sizeof(struct usb_configuration_descriptor));
ep_in = (struct usb_endpoint_descriptor *)(buffer + sizeof(struct usb_configuration_descriptor) +
sizeof(struct usb_interface_descriptor) );
ep_out = (struct usb_endpoint_descriptor *)(buffer + sizeof(struct usb_configuration_descriptor) +
sizeof(struct usb_interface_descriptor) +
sizeof(struct usb_endpoint_descriptor) );
//configuration
config_dscrptr->bLength = MIN(bytes_remaining, sizeof (struct usb_configuration_descriptor));
//配置描述符的字节数大小
config_dscrptr->bDescriptorType = USB_DT_CONFIG;
//配置描述符类型编号
config_dscrptr->wTotalLength = bytes_total;
//此配置返回的所有数据大小
config_dscrptr->bNumInterfaces = 1;
//此配置支持的接口数量
config_dscrptr->bConfigurationValue = 1;
//Set_Configuration命令所需要的参数值
config_dscrptr->iConfiguration = SUNXI_FASTBOOT_DEVICE_STRING_CONFIG_INDEX;
//描述该配置的字符串的索引值
config_dscrptr->bmAttributes = 0xC0;
//供电模式的选择
config_dscrptr->bMaxPower = 0xFA;
//最大电流500ms(0xfa * 2)
//设备从总线提取的最大电流
bytes_remaining -= config_dscrptr->bLength;
//interface
inter_dscrptr->bLength = MIN (bytes_remaining, sizeof(struct usb_interface_descriptor));
//接口描述符的字节数大小
inter_dscrptr->bDescriptorType = USB_DT_INTERFACE;
//接口描述符的类型编号
inter_dscrptr->bInterfaceNumber = 0x00;
//该接口的编号
inter_dscrptr->bAlternateSetting = 0x00;
//备用的接口描述符编号
inter_dscrptr->bNumEndpoints = 0x02;
//该接口使用的端点数,不包括端点0
inter_dscrptr->bInterfaceClass = 0xff;
//fastboot storage
//接口类型
inter_dscrptr->bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS;
//接口子类型
inter_dscrptr->bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL;
//接口遵循的协议
inter_dscrptr->iInterface = SUNXI_FASTBOOT_DEVICE_STRING_INTERFACE_INDEX;
//描述该接口的字符串索引值
bytes_remaining
-= inter_dscrptr->bLength;
//ep_in
ep_in->bLength = MIN (bytes_remaining, sizeof (struct usb_endpoint_descriptor));
//描述符大小,固定为0x07
ep_in->bDescriptorType = USB_DT_ENDPOINT;
//端点描述符类型,固定为0x05
ep_in->bEndpointAddress = sunxi_udc_get_ep_in_type();
//IN
//USB设备的端点地址
//Bit 7: 方向,对于控制端点可以忽略.1/0:IN/OUT.
//Bit 6-4: 保留.
//BIt 3-0: 端点号.
ep_in->bmAttributes = USB_ENDPOINT_XFER_BULK;
//端点属性.
//Bit 7-2: 保留.
//Bit 1-0: 00控制,01同步,02批量,03中断.
ep_in->wMaxPacketSize
= sunxi_udc_get_ep_max();
//本端点接收或发送的最大信息包大小.
ep_in->bInterval = 0x00;
//轮训数据传送端点的时间间隔.
//对于批量传送和控制传送的端点忽略.
//对于同步传送的端点,必须为1
//对于中断传送的端点,范围为1-255.
bytes_remaining
-= ep_in->bLength;
//ep_out
ep_out->bLength = MIN (bytes_remaining, sizeof (struct usb_endpoint_descriptor));
ep_out->bDescriptorType = USB_DT_ENDPOINT;
ep_out->bEndpointAddress = sunxi_udc_get_ep_out_type();
//OUT
ep_out->bmAttributes = USB_ENDPOINT_XFER_BULK;
ep_out->wMaxPacketSize = sunxi_udc_get_ep_max();
ep_out->bInterval = 0x00;
bytes_remaining -= ep_out->bLength;
sunxi_udc_send_setup(MIN(req->wLength, bytes_total), buffer);
}
break;
case USB_DT_STRING:
{
unsigned char bLength = 0;
unsigned char string_index = req->wValue & 0xff;
//sunxi_usb_dbg("get string descriptor\n");
//printf("get string descriptor\n");
//printf("string_index = %x\n", string_index);
//Language ID
if( string_index == 0 ){
bLength = MIN(4, req->wLength);
sunxi_udc_send_setup(bLength, (void *)sunxi_usb_fastboot_dev[0]);
}else if( string_index < SUNXI_USB_FASTBOOT_DEV_MAX ){
//Size of string in chars
unsigned char i = 0;
unsigned char str_length = strlen ((const char *)sunxi_usb_fastboot_dev[string_index]);
unsigned char bLength = 2 + (2 * str_length);
buffer[0] = bLength; /* length */
buffer[1] = USB_DT_STRING; /* descriptor = string */
/* Copy device string to fifo, expand to simple unicode */
for(i = 0; i < str_length; i++){
buffer[2+ 2*i + 0] = sunxi_usb_fastboot_dev[string_index][i];
buffer[2+ 2*i + 1] = 0;
}
bLength = MIN(bLength, req->wLength);
sunxi_udc_send_setup(bLength, buffer);
}else{
printf("fast boot sunxi usb err1: string line %d is not supported\n", string_index);
/* sent zero packet */
//sunxi_udc_send_setup(0, NULL);
}
}
break;
case USB_DT_DEVICE_QUALIFIER:
{
#ifdef CONFIG_USB_1_1_DEVICE
//This is an invalid request for usb 1.1, nak it
USBC_Dev_EpSendStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0);
#else
struct usb_qualifier_descriptor *qua_dscrpt;
sunxi_usb_dbg("get qualifier descriptor\n");
qua_dscrpt = (struct usb_qualifier_descriptor *)buffer;
memset(&buffer, 0, sizeof(struct usb_qualifier_descriptor));
qua_dscrpt->bLength = MIN(req->wLength, sizeof(sizeof(struct usb_qualifier_descriptor)));
//
qua_dscrpt->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
//
qua_dscrpt->bcdUSB = 0x200;
qua_dscrpt->bDeviceClass = 0xff;
qua_dscrpt->bDeviceSubClass = 0xff;
qua_dscrpt->bDeviceProtocol = 0xff;
qua_dscrpt->bMaxPacketSize0 = 0x40;
qua_dscrpt->bNumConfigurations = 1;
qua_dscrpt->bRESERVED = 0;
sunxi_udc_send_setup(qua_dscrpt->bLength, buffer);
#endif
}
break;
default:
printf("err: unkown wValue(%d)\n", req->wValue);
ret = SUNXI_USB_REQ_OP_ERR;
break;
}
return ret;
}
//字符串描述符:其中字符串描述符是可选的.
//如果不支持字符串描述符,其设备,配置,接口描述符内的所有字符串描述符索引都必须为0
//typedef struct _USB_STRING_DESCRIPTION_
//{
// BYTE bLength,
// BYTE bDescriptionType,
// BYTE bString[1];
//}USB_STRING_DESCRIPTION;
//bLength: 描述符大小.由整个字符串的长度加上bLength和bDescriptorType的长度决定.
//bDescriptorType: 接口描述符类型,固定为0x03.
//bString[1] : Unicode编码字符串.
static int __usb_get_status(struct usb_device_request *req, uchar *buffer)
{
unsigned char bLength = 0;
sunxi_usb_dbg("get status\n");
if(0 == req->wLength)
{
/* sent zero packet */
sunxi_udc_send_setup(0, NULL);
return SUNXI_USB_REQ_OP_ERR;
}
bLength = MIN(req->wValue, 2);
buffer[0] = 1;
buffer[1] = 0;
sunxi_udc_send_setup(bLength, buffer);
return SUNXI_USB_REQ_SUCCESSED;
}
static int __sunxi_fastboot_send_status(void *buffer, unsigned int buffer_size)
{
return sunxi_udc_send_data((uchar *)buffer, buffer_size);
}
static int __fastboot_reboot(int word_mode)
{
char response[8];
sprintf(response,"OKAY");
__sunxi_fastboot_send_status(response, strlen(response));
__msdelay(1000); /* 1 sec */
sunxi_board_restart(word_mode);
return 0;
}
static int __erase_part(char *name)
{
void *addr = (void *)FASTBOOT_ERASE_BUFFER;
u32 start, unerased_sectors;
u32 nblock = FASTBOOT_ERASE_BUFFER_SIZE/512;
char response[68];
start = sunxi_partition_get_offset_byname(name);
unerased_sectors = sunxi_partition_get_size_byname(name);
if(gd->lockflag == SUNXI_LOCKING || gd->lockflag == SUNXI_RELOCKING)
{
printf("in lock state, sunxi fastboot erase is disabled\n");
__sunxi_fastboot_send_status(response, strlen(response));
return 0;
}
if((!start) || (!unerased_sectors))
{
printf("sunxi fastboot erase FAIL: partition %s does not exist\n", name);
sprintf(response, "FAILerase: partition %s does not exist", name);
__sunxi_fastboot_send_status(response, strlen(response));
return -1;
}
memset(addr, 0xff, FASTBOOT_ERASE_BUFFER_SIZE);
while(unerased_sectors >= nblock)
{
if(!sunxi_flash_write(start, nblock, addr))
{
printf("sunxi fastboot erase FAIL: failed to erase partition %s \n", name);
sprintf(response,"FAILerase: failed to erase partition %s", name);
__sunxi_fastboot_send_status(response, strlen(response));
return -1;
}
start += nblock;
unerased_sectors -= nblock;
}
if(unerased_sectors)
{
if(!sunxi_flash_write(start, unerased_sectors, addr))
{
printf("sunxi fastboot erase FAIL: failed to erase partition %s \n", name);
sprintf(response,"FAILerase: failed to erase partition %s", name);
__sunxi_fastboot_send_status(response, strlen(response));
return -1;
}
}
printf("sunxi fastboot: partition '%s' erased\n", name);
sprintf(response, "OKAY");
__sunxi_fastboot_send_status(response, strlen(response));
return 0;
}
/*
*******************************************************************************
* __flash_to_part
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
static int __flash_to_part(char *name)
{
char *addr = trans_data.base_recv_buffer;
u32 start, data_sectors;
u32 part_sectors;
u32 nblock = FASTBOOT_TRANSFER_BUFFER_SIZE/512;
char response[68];
start = sunxi_partition_get_offset_byname(name);
part_sectors = sunxi_partition_get_size_byname(name);
if(gd->lockflag == SUNXI_LOCKING || gd->lockflag == SUNXI_RELOCKING)
{
printf("in lock state, sunxi fastboot flash is disabled\n");
__sunxi_fastboot_send_status(response, strlen(response));
return 0;
}
if((!start) || (!part_sectors))
{
uint addr_in_hex;
int ret;
printf("sunxi fastboot download FAIL: partition %s does not exist\n", name);
printf("probe it as a dram address\n");
ret = strict_strtoul((const char *)name, 16, (long unsigned int*)&addr_in_hex);
if(ret)
{
printf("sunxi fatboot download FAIL: it is not a dram address\n");
sprintf(response, "FAILdownload: partition %s does not exist", name);
__sunxi_fastboot_send_status(response, strlen(response));
return -1;
}
else
{
printf("ready to move data to 0x%x, bytes 0x%x\n", addr_in_hex, trans_data.try_to_recv);
memcpy((void *)addr_in_hex, addr, trans_data.try_to_recv);
}
}
else
{
int format;
printf("ready to download bytes 0x%x\n", trans_data.try_to_recv);
format = unsparse_probe(addr, trans_data.try_to_recv, start);
if(ANDROID_FORMAT_DETECT == format)
{
if(unsparse_direct_write(addr, trans_data.try_to_recv))
{
printf("sunxi fastboot download FAIL: failed to write partition %s \n", name);
sprintf(response,"FAILdownload: write partition %s err", name);
return -1;
}
}
else
{
data_sectors = (trans_data.try_to_recv + 511)/512;
if(data_sectors > part_sectors)
{
printf("sunxi fastboot download FAIL: partition %s size 0x%x is smaller than data size 0x%x\n", name, trans_data.act_recv, data_sectors * 512);
sprintf(response, "FAILdownload: partition size < data size");
__sunxi_fastboot_send_status(response, strlen(response));
return -1;
}
while(data_sectors >= nblock)
{
if(!sunxi_flash_write(start, nblock, addr))
{
printf("sunxi fastboot download FAIL: failed to write partition %s \n", name);
sprintf(response,"FAILdownload: write partition %s err", name);
__sunxi_fastboot_send_status(response, strlen(response));
return -1;
}
start += nblock;
data_sectors -= nblock;
addr += FASTBOOT_TRANSFER_BUFFER_SIZE;
}
if(data_sectors)
{
if(!sunxi_flash_write(start, data_sectors, addr))
{
printf("sunxi fastboot download FAIL: failed to write partition %s \n", name);
sprintf(response,"FAILdownload: write partition %s err", name);
__sunxi_fastboot_send_status(response, strlen(response));
return -1;
}
}
}
}
printf("sunxi fastboot: successed in downloading partition '%s'\n", name);
sprintf(response, "OKAY");
__sunxi_fastboot_send_status(response, strlen(response));
return 0;
}
/*
*******************************************************************************
* __try_to_download
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
static int __try_to_download(char *download_size, char *response)
{
int ret = -1;
trans_data.try_to_recv = simple_strtoul (download_size, NULL, 16);
all_download_bytes = trans_data.try_to_recv;
printf("Starting download of %d BYTES\n", trans_data.try_to_recv);
printf("Starting download of %d MB\n", trans_data.try_to_recv >> 20);
if (0 == trans_data.try_to_recv)
{
/* bad user input */
sprintf(response, "FAILdownload: data size is 0");
}
else if (trans_data.try_to_recv > SUNXI_USB_FASTBOOT_BUFFER_MAX)
{
sprintf(response, "FAILdownload: data > buffer");
}
else
{
/* The default case, the transfer fits
completely in the interface buffer */
sprintf(response, "DATA%08x", trans_data.try_to_recv);
printf("download response: %s\n", response);
ret = 0;
}
return ret;
}
/*
*******************************************************************************
* __boot
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
static void __boot(void)
{
char response[68];
if(all_download_bytes > CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE)
{
char start[32];
char *bootm[3] = { "bootm", NULL, NULL, };
char *go[3] = { "go", NULL, NULL, };
struct fastboot_boot_img_hdr *fb_hdr =
(struct fastboot_boot_img_hdr *) trans_data.base_recv_buffer;
/* Skip the mkbootimage header */
image_header_t *hdr =
(image_header_t *)
&trans_data.base_recv_buffer[CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE];
bootm[1] = go[1] = start;
sprintf(start, "0x%x", (uint)hdr);
printf("start addr %s\n", start);
/* Execution should jump to kernel so send the response
now and wait a bit. */
sprintf(response, "OKAY");
//
fastboot_tx_status(response, strlen(response));
__msdelay (1000); /* 1 sec */
if (ntohl(hdr->ih_magic) == IH_MAGIC) {
/* Looks like a kernel.. */
printf ("Booting kernel..\n");
/*
* Check if the user sent a bootargs down.
* If not, do not override what is already there
*/
if (strlen ((char *) &fb_hdr->cmdline[0])) {
printf("Image has cmdline:");
printf("%s\n", &fb_hdr->cmdline[0]);
setenv ("bootargs", (char *) &fb_hdr->cmdline[0]);
}
do_bootm (NULL, 0, 2, bootm);
} else {
/* Raw image, maybe another uboot */
printf ("Booting raw image..\n");
do_go (NULL, 0, 2, go);
}
printf ("ERROR : bootting failed\n");
printf ("You should reset the board\n");
}
else
{
sprintf(response, "FAILinvalid boot image");
}
}
/*
*******************************************************************************
* __get_var
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
static void __get_var(char *ver_name)
{
char response[68];
memset(response, 0, 68);
strcpy(response,"OKAY");
if(!strcmp(ver_name, "version"))
{
strcpy(response + 4, FASTBOOT_VERSION);
}
else if(!strcmp(ver_name, "product"))
{
strcpy(response + 4, SUNXI_FASTBOOT_DEVICE_PRODUCT);
}
else if(!strcmp(ver_name, "serialno"))
{
strcpy(response + 4, SUNXI_FASTBOOT_DEVICE_SERIAL_NUMBER);
}
else if(!strcmp(ver_name, "downloadsize"))
{
sprintf(response + 4, "0x%08x", SUNXI_USB_FASTBOOT_BUFFER_MAX);
printf("response: %s\n", response);
}
else if(!strcmp(ver_name, "secure"))
{
strcpy(response + 4, "yes");
}
else if(!strcmp(ver_name, "max-download-size"))
{
sprintf(response + 4, "0x%08x", SUNXI_USB_FASTBOOT_BUFFER_MAX);
printf("response: %s\n", response);
}
else
{
strcpy(response + 4, "not supported");
}
__sunxi_fastboot_send_status(response, strlen(response));
return ;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void __oem_operation(char *operation)
{
char response[68];
char lock_info[64];
int lockflag;
int ret;
memset(lock_info, 0, 64);
memset(response, 0, 68);
if(!strncmp(operation, "lock", 4))
{
lockflag = SUNXI_RELOCKING;
}
else if(!strncmp(operation, "unlock", 6))
{
lockflag = SUNXI_UNLOCK;
}
else
{
if(!strncmp(operation, "efex", 4))
{
strcpy(response, "OKAY");
__sunxi_fastboot_send_status(response, strlen(response));
sunxi_board_run_fel();
}
else
{
const char *info = "fastboot oem operation fail: unknown cmd";
printf("%s\n", info);
strcpy(response, "FAIL");
strcat(response, info);
__sunxi_fastboot_send_status(response, strlen(response));
}
return ;
}
ret = sunxi_oem_op_lock(lockflag, lock_info, 0);
if(!ret)
{
strcpy(response, "OKAY");
}
else
{
strcpy(response, "FAIL");
}
strcat(response, lock_info);
printf("%s\n", response);
__sunxi_fastboot_send_status(response, strlen(response));
return ;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void __continue(void)
{
char response[32];
memset(response, 0, 32);
strcpy(response,"OKAY");
__sunxi_fastboot_send_status(response, strlen(response));
sunxi_usb_exit();
if(uboot_spare_head.boot_data.storage_type)
{
setenv("bootcmd", "run setargs_mmc boot_normal");
}
else
{
setenv("bootcmd", "run setargs_nand boot_normal");
}
do_bootd(NULL, 0, 1, NULL);
return;
}
static void __unsupported_cmd(void)
{
char response[32];
memset(response, 0, 32);
strcpy(response,"FAIL");
__sunxi_fastboot_send_status(response, strlen(response));
return;
}
//fastboot初始化代码
static int sunxi_fastboot_init(void)
{
printf("sunxi_fastboot_init\n");
memset(&trans_data, 0, sizeof(fastboot_trans_set_t));
sunxi_usb_fastboot_write_enable = 0;
sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE;
all_download_bytes = 0;
fastboot_data_flag = 0;
trans_data.base_recv_buffer = (char *)FASTBOOT_TRANSFER_BUFFER;
trans_data.base_send_buffer = (char *)malloc(SUNXI_FASTBOOT_SEND_MEM_SIZE);
if( !trans_data.base_send_buffer){
printf("sunxi usb fastboot err: unable to malloc memory for fastboot send\n");
free(trans_data.base_recv_buffer);
return -1;
}
printf("recv addr 0x%x\n", (uint)trans_data.base_recv_buffer);
printf("send addr 0x%x\n", (uint)trans_data.base_send_buffer);
return 0;
}
static int sunxi_fastboot_exit(void)
{
printf("sunxi_fastboot_exit\n");
if( trans_data.base_send_buffer){
free(trans_data.base_send_buffer);
}
return 0;
}
static void sunxi_fastboot_reset(void)
{
sunxi_usb_fastboot_write_enable = 0;
sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE;
}
static void sunxi_fastboot_usb_rx_dma_isr(void *p_arg)
{
printf("dma int for usb rx occur\n");
//通知主循环,可以写入数据
sunxi_usb_fastboot_write_enable = 1;
}
static void sunxi_fastboot_usb_tx_dma_isr(void *p_arg)
{
printf("dma int for usb tx occur\n");
}
static int sunxi_fastboot_standard_req_op(uint cmd, struct usb_device_request *req, uchar *buffer)
{
int ret = SUNXI_USB_REQ_OP_ERR;
//printf("standard req cmd = %x\n", cmd);
switch( cmd ){
case USB_REQ_GET_STATUS:
ret = __usb_get_status(req, buffer);
break;
//case USB_REQ_CLEAR_FEATURE:
//case USB_REQ_SET_FEATURE:
case USB_REQ_SET_ADDRESS:
ret = __usb_set_address(req);
break;
case USB_REQ_GET_DESCRIPTOR:
//case USB_REQ_SET_DESCRIPTOR:
case USB_REQ_GET_CONFIGURATION:
ret = __usb_get_descriptor(req, buffer);
break;
case USB_REQ_SET_CONFIGURATION:
ret = __usb_set_configuration(req);
break;
//case USB_REQ_GET_INTERFACE:
case USB_REQ_SET_INTERFACE:
ret = __usb_set_interface(req);
break;
//case USB_REQ_SYNCH_FRAME:
default:
tick_printf("sunxi fastboot error: standard req is not supported\n");
ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED;
break;
}
return ret;
}
static int sunxi_fastboot_nonstandard_req_op(uint cmd, struct usb_device_request *req, uchar *buffer, uint data_status)
{
printf("no standard req cmd = %x\n", cmd);
return SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED;
}
//fastboot模式主循环状态机
static int sunxi_fastboot_state_loop(void *buffer)
{
int ret;
sunxi_ubuf_t *sunxi_ubuf = (sunxi_ubuf_t *)buffer;
char response[68];
if( sunxi_usb_fastboot_status_pre != sunxi_usb_fastboot_status ){
printf( "sunxi_usb_fastboot_status = %d\n", sunxi_usb_fastboot_status );
sunxi_usb_fastboot_status_pre = sunxi_usb_fastboot_status;
}
switch( sunxi_usb_fastboot_status ){
case SUNXI_USB_FASTBOOT_IDLE:
if( sunxi_ubuf->rx_ready_for_data == 1 ){
sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_SETUP;
}
break;
case SUNXI_USB_FASTBOOT_SETUP:
tick_printf("SUNXI_USB_FASTBOOT_SETUP\n");
tick_printf("fastboot command = %s\n", sunxi_ubuf->rx_req_buffer);
sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE;
sunxi_ubuf->rx_ready_for_data = 0;
if( memcmp(sunxi_ubuf->rx_req_buffer, "reboot-bootloader", strlen("reboot-bootloader")) == 0 ){
tick_printf("reboot-bootloader\n");
__fastboot_reboot(PMU_PRE_FASTBOOT_MODE);
}else if( memcmp(sunxi_ubuf->rx_req_buffer, "reboot", 6) == 0 ){
tick_printf("reboot\n");
__fastboot_reboot(0);
}else if(memcmp(sunxi_ubuf->rx_req_buffer, "erase:", 6) == 0){
tick_printf("erase\n");
__erase_part((char *)(sunxi_ubuf->rx_req_buffer + 6));
}else if( memcmp(sunxi_ubuf->rx_req_buffer, "flash:", 6) == 0){
tick_printf("flash\n");
__flash_to_part((char *)(sunxi_ubuf->rx_req_buffer + 6));
}else if(memcmp(sunxi_ubuf->rx_req_buffer, "download:", 9) == 0){
tick_printf("download\n");
ret = __try_to_download((char *)(sunxi_ubuf->rx_req_buffer + 9), response);
if( ret >= 0 ){
fastboot_data_flag = 1;
sunxi_ubuf->rx_req_buffer = (uchar *)trans_data.base_recv_buffer;
sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_RECEIVE_DATA;
}
__sunxi_fastboot_send_status(response, strlen(response));
}else if(memcmp(sunxi_ubuf->rx_req_buffer, "boot", 4) == 0){
tick_printf("boot\n");
__boot();
}else if( memcmp(sunxi_ubuf->rx_req_buffer, "getvar:", 7) == 0){
tick_printf("getvar\n");
__get_var((char *)(sunxi_ubuf->rx_req_buffer + 7));
}else if(memcmp(sunxi_ubuf->rx_req_buffer, "oem", 3) == 0){
tick_printf("oem operations\n");
__oem_operation((char *)(sunxi_ubuf->rx_req_buffer + 4));
}else if(memcmp(sunxi_ubuf->rx_req_buffer, "continue", 8) == 0){
tick_printf("continue\n");
__continue();
}else{
tick_printf("not supported fastboot cmd\n");
__unsupported_cmd();
}
break;
case SUNXI_USB_FASTBOOT_SEND_DATA:
tick_printf("SUNXI_USB_FASTBOOT_SEND_DATA\n");
break;
case SUNXI_USB_FASTBOOT_RECEIVE_DATA:
//tick_printf("SUNXI_USB_FASTBOOT_RECEIVE_DATA\n");
if( (fastboot_data_flag == 1) &&
((char *)sunxi_ubuf->rx_req_buffer == all_download_bytes + trans_data.base_recv_buffer) ){
//传输完毕
tick_printf("fastboot transfer finish\n");
fastboot_data_flag = 0;
sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE;
sunxi_ubuf->rx_req_buffer = sunxi_ubuf->rx_base_buffer;
sprintf(response,"OKAY");
__sunxi_fastboot_send_status(response, strlen(response));
}
break;
default:
break;
}
return 0;
}
sunxi_usb_module_init(SUNXI_USB_DEVICE_FASTBOOT,
sunxi_fastboot_init,
sunxi_fastboot_exit,
sunxi_fastboot_reset,
sunxi_fastboot_standard_req_op,
sunxi_fastboot_nonstandard_req_op,
sunxi_fastboot_state_loop,
sunxi_fastboot_usb_rx_dma_isr,
sunxi_fastboot_usb_tx_dma_isr
);