Ejemplo n.º 1
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((!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;
}
int do_sunxi_boot_signature(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
	int ret;
	int m_ok = 1;

	ret = signature_verify("boot");
	if(!ret)
	{
		ret = signature_verify("system");
	}
    if(ret)
    {
    	printf("signature verify failed\n");

        __u32 private_start;
        __u32 private_size;
        __u32 erase_block_once=SIG_ERASE_BUFFER_SIZE;
        char  last_back[SIG_SMALL_BUFFER_SIZE];
        char* private_data = NULL;

		private_start = sunxi_partition_get_offset_byname("private");
		private_size  = sunxi_partition_get_size_byname("private") * 512;

		private_data = malloc(SIG_ERASE_BUFFER_SIZE);
		if(!private_data)
		{
			printf("not enough memory for sig erase\n");

			private_data = last_back;
			erase_block_once = SIG_SMALL_BUFFER_SIZE;
			m_ok = 0;
		}
        memset(private_data,0xff,erase_block_once);
        while(private_size>=erase_block_once)
        {
             sunxi_flash_write(private_start,erase_block_once/512,private_data);
             private_start += erase_block_once/512;
             private_size -= erase_block_once;
        }
        if(private_size)
        {
            sunxi_flash_write(private_start,private_size/512,private_data);
        }
        if(m_ok)
        {
        	free(private_data);
    	}
    }

    return 0;

}
Ejemplo n.º 3
0
int sunxi_flash_read_bootlogo(u32 start, int buf, const char *part_name)
{
	int ret;
	u32 rblock;
	u32 start_block = start;
	void *addr;
	
	addr = (void *)buf;
	start_block = sunxi_partition_get_offset_byname((const char *)part_name);
	rblock = sunxi_partition_get_size_byname((const char *)part_name);
    ret = sunxi_flash_read(start_block, rblock, (void *)addr);
	if(ret != 0) {
		printf("read bootlogo partition successful,start_block=0x%x,rblock=0x%x ,ret=%d\n",start_block,rblock,ret);
	}
	else {
		printf("read bootlogo partition fail,start_block=0x%x,rblock=0x%x ,ret=%d\n",start_block,rblock,ret);
	}

	return ret;
}
Ejemplo n.º 4
0
int sunxi_keydata_burn_by_usb(void)
{
	char buffer[512];
#ifdef   CONFIG_SUNXI_SECURE_STORAGE
#ifndef  SUNXI_SECURESTORAGE_TEST_ERASE
	int  data_len;
#endif
#endif
	int  ret;
	uint burn_private_start, burn_private_len;
	int workmode = uboot_spare_head.boot_data.work_mode;

	int if_need_burn_key=0;

	ret = script_parser_fetch("target", "burn_key", &if_need_burn_key, 1);
	if((ret) || (if_need_burn_key != 1))
	{
		return 0;
	}

	if(workmode != WORK_MODE_BOOT)		//非启动模式,不执行
	{
		puts("out of usb burn from boot: not boot mode\n");

		return 0;
	}
	if(gd->vbus_status == SUNXI_VBUS_NOT_EXIST)	//vbus不存在,不执行
	{
		puts("out of usb burn from boot: without usb\n");

		return 0;
	}
	if(gd->power_step_level == BATTERY_RATIO_TOO_LOW_WITH_DCIN)
	{
		puts("out of usb burn from boot: not enough energy\n");

		return 0;
	}
	memset(buffer, 0, 512);
#ifdef CONFIG_SUNXI_SECURE_STORAGE
	if(sunxi_secure_storage_init())
#endif
	{
		printf("sunxi secure storage is not supported\n");
		burn_private_start = sunxi_partition_get_offset_byname("private");
		burn_private_len   = sunxi_partition_get_size_byname("private");

		if(!burn_private_start)
		{
			printf("private partition is not exist\n");

			return -1;
		}
		else
		{
			ret = sunxi_flash_read(burn_private_start + burn_private_len - (8192+512)/512, 1, buffer);
			if(ret != 1)
			{
				printf("cant read private part\n");

				return -1;
			}
			if(!strcmp(buffer, "key_burned"))
			{
				printf("find key burned flag\n");

				return 0;
			}
		}
	}
#ifdef CONFIG_SUNXI_SECURE_STORAGE
	else
	{
#ifndef SUNXI_SECURESTORAGE_TEST_ERASE
		ret = sunxi_secure_storage_read("key_burned_flag", buffer, 512, &data_len);
		if(ret)
		{
			printf("sunxi secure storage has no flag\n");
		}
		else
		{
			if(!strcmp(buffer, "key_burned"))
			{
				printf("wrn: data has clean\n");
				return 0;
			}
		}
#else
		if(!sunxi_secure_storage_erase_data_only("key_burned_flag"))
			sunxi_secure_storage_exit();

		return 0;
#endif
	}
#endif
	return do_burn_from_boot(NULL, 0, 0, NULL);
}
Ejemplo n.º 5
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((!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;
}
Ejemplo n.º 6
0
/*
************************************************************************************************************
*
*                                             function
*
*    name          :
*
*    parmeters     :
*
*    return        :
*
*    note          :
*
*
************************************************************************************************************
*/
static int sunxi_pburn_state_loop(void  *buffer)
{
	static struct umass_bbb_cbw_t  *cbw;
	static struct umass_bbb_csw_t  csw;
	static uint pburn_flash_start = 0;
	//static uint pburn_flash_sectors = 0;
	int    ret;
	sunxi_ubuf_t *sunxi_ubuf = (sunxi_ubuf_t *)buffer;

	switch(sunxi_usb_pburn_status)
	{
		case SUNXI_USB_PBURN_IDLE:
			if(sunxi_ubuf->rx_ready_for_data == 1)
			{
				sunxi_usb_pburn_status = SUNXI_USB_PBURN_SETUP;
			}

			break;

		case SUNXI_USB_PBURN_SETUP:

			sunxi_usb_dbg("SUNXI_USB_PBURN_SETUP\n");

			if(sunxi_ubuf->rx_req_length != sizeof(struct umass_bbb_cbw_t))
			{
				printf("sunxi usb error: received bytes 0x%x is not equal cbw struct size 0x%zx\n", sunxi_ubuf->rx_req_length, sizeof(struct umass_bbb_cbw_t));

				sunxi_ubuf->rx_ready_for_data = 0;
				sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE;

				break;
			}

			cbw = (struct umass_bbb_cbw_t *)sunxi_ubuf->rx_req_buffer;
			if(CBWSIGNATURE != cbw->dCBWSignature)
			{
				printf("sunxi usb error: the cbw signature 0x%x is bad, need 0x%x\n", cbw->dCBWSignature, CBWSIGNATURE);

				sunxi_ubuf->rx_ready_for_data = 0;
				sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE;

				break;
			}

			csw.dCSWSignature = CSWSIGNATURE;
			csw.dCSWTag 	  = cbw->dCBWTag;

#if defined(SUNXI_USB_30)
			sunxi_usb_pburn_status_enable = 1;
#endif
			sunxi_usb_dbg("usb cbw command = 0x%x\n", cbw->CBWCDB[0]);

			switch(cbw->CBWCDB[0])
	  		{
#ifdef  CONFIG_SUNXI_SECURE_STORAGE
				case 0xf0:			//自定义命令,用于烧录用户数据
	  				sunxi_usb_dbg("usb burn secure storage data\n");
	  				printf("usb command = %d\n", cbw->CBWCDB[1]);
	  				switch(cbw->CBWCDB[1])
	  				{
	  					case 0:				//握手
	  					{
	  						__usb_handshake_sec_t  *handshake = (__usb_handshake_sec_t *)trans_data.base_send_buffer;

                            memset(handshake, 0, sizeof(__usb_handshake_sec_t));
							strcpy(handshake->magic, "usb_burn_handshake");
							sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;

		  					trans_data.act_send_buffer = trans_data.base_send_buffer;
		  					trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_sec_t));

							sunxi_usb_burn_from_boot_setup = 1;

							private_data_ext_buff = (u8 *)malloc(4 * 1024 * 1024);
							if(private_data_ext_buff == NULL)
							{
								printf("there is no memorfy to store all user key data\n");

								csw.bCSWStatus = -1;
							}
							else
		  					{
		  						csw.bCSWStatus = 0;
		  						sunxi_usb_burn_from_boot_handshake = 1;
		  					}
		  					private_data_ext_buff_step = private_data_ext_buff;
						}
						break;

						case 1:				//小机端接收数据
						{
							trans_data.recv_size = cbw->dCBWDataTransferLength;

                            sunxi_usb_pburn_write_enable = 0;
							sunxi_udc_start_recv_by_dma(private_data_ext_buff_step, trans_data.recv_size);	//start dma to receive data

							printf("recv_size=%d\n", trans_data.recv_size);
							sunxi_dump(private_data_ext_buff, trans_data.recv_size);

					        sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_NULL;
						}
						break;

						case 2:             //工具端声明数据传输已经完毕,要求获取烧录状态
						{
							__usb_handshake_ext_t  *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer;

							memset(handshake, 0, sizeof(__usb_handshake_ext_t));
							//strcpy(handshake->magic, "usb_burn_receive_data_all");
							sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;

							printf("recv_size=%d\n", trans_data.recv_size);
							sunxi_dump(private_data_ext_buff, trans_data.recv_size);

							int ret = __sunxi_burn_key(private_data_ext_buff, trans_data.recv_size);

		  					trans_data.act_send_buffer = trans_data.base_send_buffer;
		  					trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t));
		  					//开始根据数据类型进行烧录动作

		  					if(!ret)	//数据烧写成功
		  					{
		  						strcpy(handshake->magic, "usb_burn_success");
		  						csw.bCSWStatus = 0;
		  					}
		  					else	//数据烧写失败
		  					{
		  						strcpy(handshake->magic, "usb_burn_error");
		  						csw.bCSWStatus = -1;
		  					}
		  					if(private_data_ext_buff)
		  					{
		  						free(private_data_ext_buff);
		  					}
						}
						break;

//						case 3:             //小机端读取每个key
//						{
//							uint start, sectors;
//							uint offset;
//
//							start   = *(int *)(cbw->CBWCDB + 4);		//读数据的偏移量
//							sectors = *(int *)(cbw->CBWCDB + 8);		//扇区数;
//
//							trans_data.send_size 	   = min(cbw->dCBWDataTransferLength, sectors * 512);
//							trans_data.act_send_buffer = (uint)trans_data.base_send_buffer;
//
//							offset = burn_private_start;
//							ret = sunxi_flash_read(start + offset, sectors, trans_data.base_send_buffer);
//							if(!ret)
//							{
//								printf("sunxi flash read err: start,0x%x sectors 0x%x\n", start, sectors);
//
//								csw.bCSWStatus = 1;
//							}
//							else
//							{
//								csw.bCSWStatus = 0;
//							}
//
//							sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
//						}
//						break;

						case 4:				//关闭usb
						{
							__usb_handshake_ext_t  *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer;

                            memset(handshake, 0, sizeof(__usb_handshake_ext_t));
							strcpy(handshake->magic, "usb_burn_finish");

							trans_data.act_send_buffer = trans_data.base_send_buffer;
		  					trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t));

							sunxi_udc_send_data((void *)trans_data.act_send_buffer, trans_data.send_size);

		  					csw.bCSWStatus = 0;

		  					sunxi_usb_pburn_status = SUNXI_USB_PBURN_EXIT;

						}
						break;

						case 5:
						{
							__usb_handshake_ext_t  *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer;

							memset(handshake, 0, sizeof(__usb_handshake_ext_t));
							strcpy(handshake->magic, "usb_burn_saved");

							trans_data.act_send_buffer = trans_data.base_send_buffer;
		  					trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t));

		  					csw.bCSWStatus = 0;

		  					sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
		  					if(sunxi_secure_storage_write("key_burned_flag", "key_burned", strlen("key_burned")))
		  					{
		  						printf("save burned flag err\n");

		  						csw.bCSWStatus = -1;
		  					}
		  					sunxi_secure_storage_exit();
						}
						break;

					default:
						break;
	  			}
	  			break;
#endif

	  			case 0xf3:			//自定义命令,用于烧录用户数据
	  				sunxi_usb_dbg("usb burn private\n");
	  				printf("usb command = %d\n", cbw->CBWCDB[1]);
	  				switch(cbw->CBWCDB[1])
	  				{
	  					case 0:				//握手
	  					{
	  						__usb_handshake_t  *handshake = (__usb_handshake_t *)trans_data.base_send_buffer;

							burn_private_start = sunxi_partition_get_offset_byname("private");
							burn_private_len   = sunxi_partition_get_size_byname("private");

							if(!burn_private_start)
							{
								printf("private partition is not exist\n");

								csw.bCSWStatus = -1;
							}
							else
							{
								csw.bCSWStatus = 0;
							}

                            memset(handshake, 0, sizeof(__usb_handshake_t));
							strcpy(handshake->magic, "usb_burn_handshake");
							handshake->sizelo = burn_private_len;
							handshake->sizehi = 0;
							sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;

							sunxi_usb_burn_from_boot_setup = 1;
							sunxi_usb_burn_from_boot_handshake = 1;

		  					trans_data.act_send_buffer = trans_data.base_send_buffer;
		  					trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_t));
						}
						break;

						case 1:				//小机端接收数据
						{
							//pburn_flash_sectors  = *(int *)(cbw->CBWCDB + 8);
							//pburn_flash_start    = *(int *)(cbw->CBWCDB + 4);
							memcpy(&pburn_flash_start,(cbw->CBWCDB + 4),4);

							trans_data.recv_size = cbw->dCBWDataTransferLength;
							trans_data.act_recv_buffer = trans_data.base_recv_buffer;

                            pburn_flash_start += burn_private_start;
                            sunxi_usb_pburn_write_enable = 0;
							sunxi_udc_start_recv_by_dma(trans_data.act_recv_buffer, trans_data.recv_size);	//start dma to receive data

					        sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_DATA;
						}
						break;

						case 3:             //小机端发送数据
						{
							uint start, sectors;

							//start   = *(int *)(cbw->CBWCDB + 4);		//读数据的偏移量
							//sectors = *(int *)(cbw->CBWCDB + 8);		//扇区数;
							memcpy(&start,(cbw->CBWCDB + 4),4);
							memcpy(&sectors,(cbw->CBWCDB + 8),4);

							printf("start=%d, sectors=%d\n", start, sectors);

							trans_data.send_size 	   = min(cbw->dCBWDataTransferLength, sectors * 512);
							trans_data.act_send_buffer = trans_data.base_send_buffer;

							printf("send size=%d\n", trans_data.send_size);

							ret = sunxi_flash_read(start + burn_private_start, sectors, trans_data.base_send_buffer);
							if(!ret)
							{
								printf("sunxi flash read err: start,0x%x sectors 0x%x\n", start, sectors);

								csw.bCSWStatus = 1;
							}
							else
							{
								csw.bCSWStatus = 0;
							}

							sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
						}
						break;

						case 4:				//关闭usb
						{
							__usb_handshake_ext_t  *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer;

                            memset(handshake, 0, sizeof(__usb_handshake_ext_t));
							strcpy(handshake->magic, "usb_burn_finish");

							trans_data.act_send_buffer = trans_data.base_send_buffer;
		  					trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t));

							sunxi_udc_send_data((void *)trans_data.act_send_buffer, trans_data.send_size);

		  					csw.bCSWStatus = 0;

							sunxi_flash_flush();
		  					sunxi_usb_pburn_status = SUNXI_USB_PBURN_EXIT;

						}
						break;

						case 5:
						{
							__usb_handshake_ext_t  *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer;
							char buffer[512];

							memset(handshake, 0, sizeof(__usb_handshake_ext_t));
							strcpy(handshake->magic, "usb_burn_saved");

							trans_data.act_send_buffer = trans_data.base_send_buffer;
		  					trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t));

		  					csw.bCSWStatus = 0;

		  					sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;

		  					memset(buffer, 0, 512);
							strcpy(buffer, "key_burned");

		  					if(!sunxi_flash_write(burn_private_start + burn_private_len - (8192+512)/512, 1, buffer))
		  					{
		  						printf("save burned flag err\n");

		  						csw.bCSWStatus = -1;
		  					}
		  					sunxi_flash_flush();
#ifdef CONFIG_SUNXI_SECURE_STORAGE
							if(sunxi_secure_storage_init())
							{
								printf("init secure storage failed\n");

								csw.bCSWStatus = -1;
							}
		  					else
		  					{
		  						if(sunxi_secure_storage_write("key_burned_flag", "key_burned", strlen("key_burned")))
		  						{
		  							printf("save burned flag err\n");

		  							csw.bCSWStatus = -1;
		  						}
		  					}
		  					sunxi_secure_storage_exit();
#endif
						}
						break;

					default:
						break;
	  				}

	  			break;

	  			default:
	  				sunxi_usb_dbg("not supported command 0x%x now\n", cbw->CBWCDB[0]);
	  				sunxi_usb_dbg("asked size 0x%x\n", cbw->dCBWDataTransferLength);

	  				csw.bCSWStatus = 1;

	  				sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS;

	  				break;
	  		}

	  		break;

	  	case SUNXI_USB_PBURN_SEND_DATA:

	  		sunxi_usb_dbg("SUNXI_USB_SEND_DATA\n");

			sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS;
			printf("SUNXI_USB_SEND_DATA=%d\n", trans_data.send_size);
			sunxi_udc_send_data((void *)trans_data.act_send_buffer, trans_data.send_size);
#if defined(SUNXI_USB_30)
			sunxi_usb_pburn_status_enable = 0;
#endif
	  		break;

	  	case SUNXI_USB_PBURN_RECEIVE_DATA:

	  		sunxi_usb_dbg("SUNXI_USB_RECEIVE_DATA\n");

			if(sunxi_usb_pburn_write_enable == 1)
			{
				sunxi_usb_dbg("write flash, start 0x%x, sectors 0x%x\n", pburn_flash_start, trans_data.recv_size/512);
				ret = sunxi_flash_write(pburn_flash_start, (trans_data.recv_size+511)/512, (void *)trans_data.act_recv_buffer);
				if(!ret)
				{
					printf("sunxi flash write err: start,0x%x sectors 0x%x\n", pburn_flash_start, (trans_data.recv_size+511)/512);

					csw.bCSWStatus = 1;
				}
				else
				{
					csw.bCSWStatus = 0;
  				}
				sunxi_usb_pburn_write_enable = 0;

  				sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS;
			}

	  		break;

		case SUNXI_USB_PBURN_STATUS:

			sunxi_usb_dbg("SUNXI_USB_PBURN_STATUS\n");
#if defined(SUNXI_USB_30)
			if(sunxi_usb_pburn_status_enable)
#endif
			{
				sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE;
				sunxi_ubuf->rx_ready_for_data = 0;
				__sunxi_pburn_send_status(&csw, sizeof(struct umass_bbb_csw_t));
			}

			break;

		case SUNXI_USB_PBURN_EXIT:

			printf("SUNXI_USB_PBURN_EXIT\n");

			sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE;
			sunxi_ubuf->rx_ready_for_data = 0;
			__sunxi_pburn_send_status(&csw, sizeof(struct umass_bbb_csw_t));

			printf("Device will shutdown in 3 Secends...\n");
			__msdelay(3000);

			return SUNXI_UPDATE_NEXT_ACTION_SHUTDOWN;

	  	case SUNXI_USB_PBURN_RECEIVE_NULL:

	  		sunxi_usb_dbg("SUNXI_USB_PBURN_RECEIVE_NULL\n");

			if(sunxi_usb_pburn_write_enable == 1)
			{
				csw.bCSWStatus = 0;
				sunxi_usb_pburn_write_enable = 0;
  				sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS;
			}

	  		break;

	  	default:
	  		break;
	}

	return 0;
}