fastboot源码稍加注释(usb协议部分)

时间:2021-12-02 16:50:14
//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
 );