TERES/SOFTWARE/A64-TERES/u-boot_new/usb_sunxi/usb_fastboot.c
Dimitar Gamishev 093685c7d8 u-boot
2017-10-13 14:02:55 +03:00

1399 lines
35 KiB
C

/*
* (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/dma.h>
#include <sys_partition.h>
#include <fastboot.h>
#include "usb_fastboot.h"
#include <android_misc.h>
#include <sunxi_board.h>
#include <power/sunxi/pmu.h>
#include <sunxi_mbr.h>
#include <sunxi_flash.h>
#include <private_uboot.h>
#include "../sprite/sparse/sparse.h"
#include "../sprite/sprite_download.h"
DECLARE_GLOBAL_DATA_PTR;
int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int sunxi_usb_fastboot_write_enable = 0;
static int sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE;
static fastboot_trans_set_t trans_data;
static uint all_download_bytes;
int fastboot_data_flag;
extern int sunxi_usb_exit(void);
/*
*******************************************************************************
* do_usb_req_set_interface
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* 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;
}
/*
*******************************************************************************
* do_usb_req_set_address
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
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;
}
/*
*******************************************************************************
* do_usb_req_set_configuration
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
static int __usb_set_configuration(struct usb_device_request *req)
{
sunxi_usb_dbg("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;
}
/*
*******************************************************************************
* do_usb_req_get_descriptor
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
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;
sunxi_usb_dbg("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
dev_dscrptr->bcdUSB = 0x110;
#else
dev_dscrptr->bcdUSB = 0x200;
#endif
dev_dscrptr->bDeviceClass = 0xff; //设备类:大容量存储
dev_dscrptr->bDeviceSubClass = 0xff;
dev_dscrptr->bDeviceProtocol = 0xff;
dev_dscrptr->bMaxPacketSize0 = 0x40;
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;
sunxi_usb_dbg("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;
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;
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));
ep_in->bDescriptorType = USB_DT_ENDPOINT;
ep_in->bEndpointAddress = sunxi_udc_get_ep_in_type(); /* IN */
ep_in->bmAttributes = USB_ENDPOINT_XFER_BULK;
ep_in->wMaxPacketSize = sunxi_udc_get_ep_max();
ep_in->bInterval = 0x00;
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");
/* 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("sunxi usb err: string line %d is not supported\n", string_index);
}
}
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;
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;
}
return ret;
}
/*
*******************************************************************************
* __usb_get_status
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
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;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int __sunxi_fastboot_send_status(void *buffer, unsigned int buffer_size)
{
return sunxi_udc_send_data((uchar *)buffer, buffer_size);
}
/*
*******************************************************************************
* __fastboot_reboot
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
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;
}
/*
*******************************************************************************
* __erase_part
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
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 void __flash_to_uboot(void)
{
struct spare_boot_head_t * temp_buf = (struct spare_boot_head_t *)trans_data.base_recv_buffer;
char response[68];
u32 uboot_length = 0;
u32 align_size = 0;
u32 old_uboot_length = 0;
u32 old_total_length = 0;
if(strcmp((char*)temp_buf->boot_head.magic,"uboot"))
{
printf("sunxi fastboot error: there is not uboot file\n");
sprintf(response, "FAILdownload:there is not uboot file \n");
__sunxi_fastboot_send_status(response, strlen(response));
return ;
}
printf("ready to download bytes 0x%x\n", trans_data.try_to_recv);
if(temp_buf->boot_head.uboot_length == 0)
{
printf("==== uboot.bin ====\n");
memcpy((char *)temp_buf , (char *)CONFIG_SYS_TEXT_BASE ,sizeof(struct spare_boot_head_t));
old_uboot_length = temp_buf->boot_head.uboot_length;
old_total_length = temp_buf->boot_head.length ;
debug("old_uboot_length = %x \n",old_uboot_length);
debug("old_total_length = %x \n",old_total_length);
//align uboot
align_size = temp_buf->boot_head.align_size;
printf("align_size is 0x%x \n",align_size);
uboot_length = (trans_data.try_to_recv + align_size) & (~(align_size - 1));
temp_buf->boot_head.uboot_length = uboot_length;
//copy sys_config from old uboot
memcpy((char *)temp_buf + uboot_length , (char *)CONFIG_SYS_TEXT_BASE + old_uboot_length,old_total_length - old_uboot_length);
//make check_sum again
temp_buf->boot_head.check_sum = STAMP_VALUE;
temp_buf->boot_head.length = uboot_length +old_total_length - old_uboot_length;
temp_buf->boot_head.check_sum = add_sum((char *)temp_buf,temp_buf->boot_head.length);
}
printf("uboot checksum is 0x%x \n",temp_buf->boot_head.check_sum);
printf("download uboot ing ....\n");
sunxi_sprite_download_uboot((char *)temp_buf,uboot_spare_head.boot_data.storage_type ,1);
printf("sunxi fastboot: successed in downloading uboot \n");
sprintf(response, "OKAY");
__sunxi_fastboot_send_status(response, strlen(response));
return ;
}
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 *)(ulong)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%lx", (ulong)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)
{
#if 0
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 ;
#endif
printf("not implement yet \n");
}
/*
************************************************************************************************************
*
* 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;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void __unsupported_cmd(void)
{
char response[32];
memset(response, 0, 32);
strcpy(response,"FAIL");
__sunxi_fastboot_send_status(response, strlen(response));
return;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
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%lx\n", (ulong)trans_data.base_recv_buffer);
printf("send addr 0x%lx\n", (ulong)trans_data.base_send_buffer);
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
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;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void sunxi_fastboot_reset(void)
{
sunxi_usb_fastboot_write_enable = 0;
sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
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;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void sunxi_fastboot_usb_tx_dma_isr(void *p_arg)
{
printf("dma int for usb tx occur\n");
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int sunxi_fastboot_standard_req_op(uint cmd, struct usb_device_request *req, uchar *buffer)
{
int ret = SUNXI_USB_REQ_OP_ERR;
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;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int sunxi_fastboot_nonstandard_req_op(uint cmd, struct usb_device_request *req, uchar *buffer, uint data_status)
{
return SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int sunxi_fastboot_state_loop(void *buffer)
{
int ret;
sunxi_ubuf_t *sunxi_ubuf = (sunxi_ubuf_t *)buffer;
char response[68];
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");
if(memcmp((char *)(sunxi_ubuf->rx_req_buffer + 6),"u-boot",6) == 0)
__flash_to_uboot();
else
__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 \
);