SmartAudio/lichee/brandy/u-boot-2011.09/usb_sunxi/usb_burn.c

1876 lines
53 KiB
C
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (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 <asm/arch/timer.h>
#include <sys_partition.h>
#include <boot_type.h>
#include "usb_burn.h"
#include "usb_efex.h"
#include <smc.h>
#include <securestorage.h>
#include "key_deal.h"
#ifdef CONFIG_SUNXI_SECURE_SYSTEM
#include <sunxi_efuse.h>
#include <asm/arch/efuse.h>
DECLARE_GLOBAL_DATA_PTR;
#endif
int smc_set_sst_crypt_name(char *name);
static int sunxi_usb_pburn_write_enable = 0;
#if defined(SUNXI_USB_30)
static int sunxi_usb_pburn_status_enable = 1;
#endif
static int sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE;
static pburn_trans_set_t trans_data;
#define DATA_BUFFER_MAX_SIZE (4*1024*1024)
#ifdef CONFIG_SUNXI_SECURE_STORAGE
static u8 *private_data_ext_buff_step = NULL;
static u8 *private_data_ext_buff = NULL;
#endif
static int burn_part_result_state=ERR_NO_SUCCESS;
long long burn_part_bytes = 0;
extern volatile int sunxi_usb_burn_from_boot_handshake;
extern volatile int sunxi_usb_probe_update_action;
extern volatile int sunxi_usb_burn_from_boot_setup;
static uint burn_private_start, burn_private_len;
static uint burn_part_start, burn_part_len;
static int fel_verify = 0;
/*
*******************************************************************************
* 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);
__usdelay(10);
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;
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
switch(req->wValue >> 8)
{
case USB_DT_DEVICE: //<2F><EFBFBD><E8B1B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
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 = 0;
dev_dscrptr->bDeviceSubClass = 0;
dev_dscrptr->bDeviceProtocol = 0;
dev_dscrptr->bMaxPacketSize0 = 0x40;
dev_dscrptr->idVendor = DRIVER_VENDOR_ID;
dev_dscrptr->idProduct = DRIVER_PRODUCT_ID;
dev_dscrptr->bcdDevice = 0xffff;
//ignored
//dev_dscrptr->iManufacturer = SUNXI_USB_STRING_IMANUFACTURER;
//dev_dscrptr->iProduct = SUNXI_USB_STRING_IPRODUCT;
//dev_dscrptr->iSerialNumber = SUNXI_USB_STRING_ISERIALNUMBER;
dev_dscrptr->iManufacturer = 0;
dev_dscrptr->iProduct = 0;
dev_dscrptr->iSerialNumber = 0;
dev_dscrptr->bNumConfigurations = 1;
sunxi_udc_send_setup(dev_dscrptr->bLength, buffer);
}
break;
case USB_DT_CONFIG: //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
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 = 0;
config_dscrptr->bmAttributes = 0x80; //not self powered
config_dscrptr->bMaxPower = 0xFA; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>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;
inter_dscrptr->bInterfaceSubClass = 0xff;
inter_dscrptr->bInterfaceProtocol = 0xff;
inter_dscrptr->iInterface = 0;
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);
buffer[0] = bLength;
buffer[1] = USB_DT_STRING;
buffer[2] = 9;
buffer[3] = 4;
sunxi_udc_send_setup(bLength, (void *)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;
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;
}
/*
*******************************************************************************
* do_usb_req_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_pburn_send_status(void *buffer, unsigned int buffer_size)
{
return sunxi_udc_send_data((uchar *)buffer, buffer_size);
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
#ifdef CONFIG_SUNXI_SECURE_STORAGE
int __sunxi_burn_key(u8 *buff, uint buff_len)
{
sunxi_usb_burn_main_info_t *key_main = (sunxi_usb_burn_main_info_t *)buff;
sunxi_usb_burn_key_info_t *key_list;
#ifdef CONFIG_SUNXI_SECURE_SYSTEM
sunxi_efuse_key_info_t efuse_key_info;
#endif
int key_count;
int offset;
u8 *p_buff = (u8 *)&key_main->key_info;
//<2F>Ƚ<EFBFBD>key<65><79><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
if(strcmp((const char *)key_main->magic, "key-group-db"))
{
printf("key data magic unmatch, err\n");
return -1;
}
key_count = key_main->count;
printf("key_count=%d\n", key_count);
if(sunxi_secure_storage_init())
{
printf("%s secure storage init failed\n", __func__);
return -1;
}
for(;key_count>0;key_count--, key_list++)
{
key_list = (sunxi_usb_burn_key_info_t *)p_buff;
printf("^^^^^^^^^^^^^^^^^^^\n");
printf("key index=%d\n", key_main->count - key_count);
printf("key name=%s\n", key_list->name);
printf("key type=%d\n", key_list->type);
printf("key len=%d\n", key_list->len);
printf("key if_burn=%d\n", key_list->if_burn);
printf("key if_replace=%d\n", key_list->if_replace);
printf("key if_crypt=%d\n", key_list->if_crypt);
printf("key data:\n");
sunxi_dump(key_list->key_data, key_list->len);
printf("###################\n");
offset = (sizeof(sunxi_usb_burn_key_info_t)) + ((key_list->len + 15) & (~15));
printf("offset=%d\n", offset);
p_buff += offset;
#ifdef CONFIG_SUNXI_SECURE_SYSTEM
if(!key_list->type)
{
memset(&efuse_key_info, 0, sizeof(efuse_key_info));
strcpy(efuse_key_info.name, (const char *)key_list->name);
efuse_key_info.len = key_list->len;
efuse_key_info.key_data = (u8 *)key_list->key_data;
if(!strcmp(efuse_key_info.name, "rotpk"))
{
printf("ready to burn rootkey\n");
if(sunxi_verify_rotpk_hash(key_list->key_data, key_list->len))
{
printf("verity the rootkey failed, stop burn it\n");
return -1;
}
}
if(gd->securemode == SUNXI_SECURE_MODE_WITH_SECUREOS)
{
if(smc_efuse_writel(&efuse_key_info))
{
return -1;
}
}
else if(gd->securemode == SUNXI_SECURE_MODE)
{
if(sunxi_efuse_write(&efuse_key_info))
{
return -1;
}
}
}
else
#endif
{
#ifdef CONFIG_SUNXI_HDCP_IN_SECURESTORAGE
int ret;
if(!strcmp("hdcpkey", key_list->name))
{
ret = sunxi_deal_hdcp_key((char *)key_list->key_data, key_list->len);
if(ret)
{
printf("sunxi deal with hdcp key failed\n");
return -1;
}
}
else
#endif
{
sunxi_secure_object_set(key_list->name,
key_list->if_crypt,
key_list->if_replace,
0,0,0 ); /*set secure storage feature*/
if(sunxi_secure_object_write(key_list->name, (char *)key_list->key_data, key_list->len))
{
return -1;
}
}
}
}
if(sunxi_secure_storage_exit())
{
printf("sunxi_secure_storage_exit err\n");
return -1;
}
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name : __sunxi_read_key_by_name
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int __sunxi_read_key_by_name(void *buffer, uint buff_len, int *read_len)
{
sunxi_usb_burn_key_info_t *key_info = NULL;
int ret, key_data_len;
char data_buff[4096]={0};
#ifdef CONFIG_SUNXI_SECURE_SYSTEM
sunxi_efuse_key_info_t *efuse_key_temp;
#endif
if(buffer == NULL)
{
printf("the memory input or output is NULL\n");
return -1;
}
if(sunxi_secure_storage_init())
{
printf("%s secure storage init failed\n", __func__);
return -1;
}
key_info = (sunxi_usb_burn_key_info_t *)buffer;
printf("key name=%s\n", key_info->name);
printf("key type=%d\n", key_info->type);
printf("key len=%d\n", key_info->len);
printf("key if_burn=%d\n", key_info->if_burn);
printf("key if_replace=%d\n", key_info->if_replace);
printf("key if_crypt=%d\n", key_info->if_crypt);
*read_len = sizeof(sunxi_usb_burn_key_info_t);
#ifdef CONFIG_SUNXI_SECURE_SYSTEM
if(!key_info->type)
{
//read from efuse
if(gd->securemode == SUNXI_SECURE_MODE_WITH_SECUREOS)
{
if(smc_efuse_readl(key_info->name, (void *)data_buff))
{
printf("efuse read %s err\n", key_info->name);
return -1;
}
}
else if(gd->securemode == SUNXI_SECURE_MODE)
{
if(smc_efuse_readl(key_info->name, (void *)data_buff))
{
printf("efuse read %s err\n", key_info->name);
return -1;
}
}
efuse_key_temp = (sunxi_efuse_key_info_t *)data_buff;
key_info->len = efuse_key_temp->len;
memcpy((void *)(key_info->key_data), (void *)(efuse_key_temp->key_data), efuse_key_temp->len);
*read_len += efuse_key_temp->len;
}
else
#endif
{
ret = sunxi_secure_object_read(key_info->name, data_buff, sizeof(sunxi_usb_burn_key_info_t), &key_data_len);
if(ret < 0)
{
printf("read %s failed\n", key_info->name);
return -1;
}
//<2F><>װ<EFBFBD><D7B0>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>key<65><79><EFBFBD><EFBFBD>
key_info->len = key_data_len;
memcpy((void *)(key_info->key_data), (void *)data_buff, key_data_len);
*read_len += key_data_len;
}
return 0;
}
#endif
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int sunxi_burn_part_verify(void *veryfy_info, long long burn_bytes)
{
long long base_bytes = 0;
uint active_verify = 0;
uint origin_verify = 0;
uint part_start;
pburn_verify_part_set_t *temp_info = NULL;
temp_info = (pburn_verify_part_set_t *)veryfy_info;
part_start = sunxi_partition_get_offset_byname(temp_info->name);
if(!part_start)
{
printf("partition %s is not exist\n", temp_info->name);
return -1;
}
base_bytes = burn_bytes;
origin_verify = temp_info->check_sum;
active_verify = sunxi_sprite_part_rawdata_verify(part_start, base_bytes);
printf("origin checksum=%x, active checksum=%x\n", origin_verify, active_verify);
if(active_verify != origin_verify)
{
printf("sunxi burn: part %s verify error\n", temp_info->name);
return -1;
}
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int burn_part_probe(void *burn_part_info)
{
pburn_partition_set_t *part_info = NULL;
int burn_state = 0;
part_info = (pburn_partition_set_t *)(burn_part_info);
if(!strcmp(part_info->magic, "usbburnpart"))
{
burn_part_start = sunxi_partition_get_offset_byname(part_info->name);
burn_part_len = sunxi_partition_get_size_byname(part_info->name);
if(!burn_part_start)
{
printf("partition %s is not exist\n", part_info->name);
burn_state = ERR_NO_PART_NOEXIST;
}
else if(((!burn_part_len) || (burn_part_len < ((part_info->lenlo + 511))/512)) || (part_info->lenlo == 0))
{
printf("the burn data size 0x%x is large then 0x%x\n", part_info->lenlo, burn_part_len);
burn_state = ERR_NO_PART_SIZE_ERR;
}
else
{
printf("part info check success\n");
printf("part_info->lenhi=%d\n", part_info->lenhi);
printf("part_info->lenlo=%d\n", part_info->lenlo);
burn_part_bytes = part_info->lenhi;
burn_part_bytes = (burn_part_bytes << 32) + part_info->lenlo;
burn_state = ERR_NO_SUCCESS;
}
}
else
{
printf("part magic %s need equal usbburnpart\n", part_info->magic);
burn_state = ERR_NO_PART_MAGIC_ERR;
}
return burn_state;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int sunxi_pburn_init(void)
{
sunxi_usb_dbg("sunxi_pburn_init\n");
memset(&trans_data, 0, sizeof(pburn_trans_set_t));
sunxi_usb_pburn_write_enable = 0;
sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE;
trans_data.base_recv_buffer = (u8 *)malloc(SUNXI_PBURN_RECV_MEM_SIZE);
if(!trans_data.base_recv_buffer)
{
printf("sunxi usb pburn err: unable to malloc memory for pburn receive\n");
return -1;
}
trans_data.base_send_buffer = (u8 *)malloc(SUNXI_PBURN_SEND_MEM_SIZE);
if(!trans_data.base_send_buffer)
{
printf("sunxi usb pburn err: unable to malloc memory for pburn send\n");
free(trans_data.base_recv_buffer);
return -1;
}
sunxi_usb_dbg("recv addr 0x%x\n", (uint)trans_data.base_recv_buffer);
sunxi_usb_dbg("send addr 0x%x\n", (uint)trans_data.base_send_buffer);
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int sunxi_pburn_exit(void)
{
sunxi_usb_dbg("sunxi_pburn_exit\n");
if(trans_data.base_recv_buffer)
{
free(trans_data.base_recv_buffer);
}
if(trans_data.base_send_buffer)
{
free(trans_data.base_send_buffer);
}
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void sunxi_pburn_reset(void)
{
sunxi_usb_pburn_write_enable = 0;
sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void sunxi_pburn_usb_rx_dma_isr(void *p_arg)
{
sunxi_usb_dbg("dma int for usb rx occur\n");
//֪ͨ<CDA8><D6AA>ѭ<EFBFBD><D1AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
sunxi_usb_pburn_write_enable = 1;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void sunxi_pburn_usb_tx_dma_isr(void *p_arg)
{
sunxi_usb_dbg("dma int for usb tx occur\n");
#if defined(SUNXI_USB_30)
sunxi_usb_pburn_status_enable = 1;
#endif
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int sunxi_pburn_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:
{
printf("sunxi pburn 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_pburn_nonstandard_req_op(uint cmd, struct usb_device_request *req, uchar *buffer, uint data_status)
{
int ret = SUNXI_USB_REQ_SUCCESSED;
switch(req->bmRequestType) //PBURN <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
case 161:
if(req->bRequest == 0xFE)
{
sunxi_usb_dbg("pburn ask for max lun\n");
buffer[0] = 0;
sunxi_udc_send_setup(1, buffer);
}
else
{
printf("sunxi usb err: unknown ep0 req in pburn\n");
ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED;
}
break;
default:
printf("sunxi usb err: unknown non standard ep0 req\n");
ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED;
break;
}
return ret;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int sunxi_pburn_state_loop(void *buffer)
{
static struct umass_bbb_cbw_t *cbw;
static struct sunxi_efex_cbw_t *efex_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:
printf("SUNXI_USB_PBURN_SETUP\n");
if(sunxi_ubuf->rx_req_length == sizeof(struct sunxi_efex_cbw_t))
{
efex_cbw = (struct sunxi_efex_cbw_t *)sunxi_ubuf->rx_req_buffer;
if(efex_cbw->magic == CBW_MAGIC)
{
printf("try to update \n");
sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_DATA;
trans_data.recv_size = cbw->dCBWDataTransferLength;
trans_data.act_recv_buffer = (uint)trans_data.base_recv_buffer;
fel_verify = 1;
sunxi_usb_pburn_write_enable = 0;
printf("start to recv by dma \n");
sunxi_udc_start_recv_by_dma(trans_data.act_recv_buffer, 16);
printf("recv done \n");
break;
}
}
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%x\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
printf("usb cbw command = 0x%x\n", cbw->CBWCDB[0]);
switch(cbw->CBWCDB[0])
{
case 0xf8:
printf("usb update probe \n");
printf("usb command = %d\n", cbw->CBWCDB[1]);
switch(cbw->CBWCDB[1])
{
case 0: //<2F><><EFBFBD><EFBFBD>
{
__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_update_probe_ok");
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
trans_data.act_send_buffer = (uint)trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_sec_t));
csw.bCSWStatus = 0;
sunxi_usb_burn_from_boot_handshake = 1;
}
break;
case 1: //exit
{
__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_update_exit");
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
trans_data.act_send_buffer = (uint)trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_sec_t));
sunxi_usb_probe_update_action = 2;
csw.bCSWStatus = 0;
}
break;
case 2: //run efex
{
__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_update_efex");
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
trans_data.act_send_buffer = (uint)trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_sec_t));
sunxi_usb_probe_update_action = 1;
csw.bCSWStatus = 0;
}
break;
default:
printf("usb command = %d not support\n", cbw->CBWCDB[1]);
break;
}
break;
#ifdef CONFIG_SUNXI_SECURE_STORAGE
case 0xf0: //<2F>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EEA3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>
sunxi_usb_dbg("usb burn secure storage data\n");
printf("usb command = %d\n", cbw->CBWCDB[1]);
switch(cbw->CBWCDB[1])
{
case 0: //<2F><><EFBFBD><EFBFBD>
{
__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 = (uint)trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_sec_t));
sunxi_usb_burn_from_boot_setup = 1;
if(private_data_ext_buff == NULL)
{
printf("malloc memory\n");
private_data_ext_buff = (u8 *)malloc(DATA_BUFFER_MAX_SIZE);
if(private_data_ext_buff == NULL)
{
printf("there is no memory to store all user key data\n");
csw.bCSWStatus = -1;
}
else
{
csw.bCSWStatus = 0;
sunxi_usb_burn_from_boot_handshake = 1;
}
}
else
{
csw.bCSWStatus = 0;
sunxi_usb_burn_from_boot_handshake = 1;
}
private_data_ext_buff_step = private_data_ext_buff;
}
break;
case 1: //С<><D0A1><EFBFBD>˽<EFBFBD><CBBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
trans_data.recv_size = cbw->dCBWDataTransferLength;
sunxi_usb_pburn_write_enable = 0;
memset(private_data_ext_buff, 0, DATA_BUFFER_MAX_SIZE);
sunxi_udc_start_recv_by_dma((uint)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: //<2F><><EFBFBD>߶<EFBFBD><DFB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݴ<EFBFBD><DDB4><EFBFBD><EFBFBD>Ѿ<EFBFBD><D1BE><EFBFBD><EFBFBD>ϣ<EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1>¼״̬
{
__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 = (uint)trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t));
//<2F><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͽ<EFBFBD><CDBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>
if(!ret) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD>ɹ<EFBFBD>
{
strcpy(handshake->magic, "usb_burn_success");
csw.bCSWStatus = 0;
}
else //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>дʧ<D0B4><CAA7>
{
strcpy(handshake->magic, "usb_burn_error");
csw.bCSWStatus = -1;
}
}
break;
// case 3: //С<><D0A1><EFBFBD>˶<EFBFBD>ȡÿ<C8A1><C3BF>key
// {
// uint start, sectors;
// uint offset;
//
// start = *(int *)(cbw->CBWCDB + 4); //<2F><><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD>ƫ<EFBFBD><C6AB><EFBFBD><EFBFBD>
// sectors = *(int *)(cbw->CBWCDB + 8); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>;
//
// 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 = (uint)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;
if(private_data_ext_buff)
{
free(private_data_ext_buff);
}
sunxi_usb_pburn_status = SUNXI_USB_PBURN_EXIT;
}
break;
case 5: //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>дkey flag
{
int ret;
__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 = (uint)trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t));
csw.bCSWStatus = 0;
ret = sunxi_secure_storage_init();
if(ret < 0)
{
printf("secure storage init err\n");
csw.bCSWStatus = -1;
break;
}
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;
case 6: //huk
{
u8 huk[32];
int ret;
memset(huk, 0, 32);
ret = smc_create_huk(huk, 32);
csw.bCSWStatus = 0;
trans_data.act_send_buffer = (uint)trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, 32);
if(ret < 0)
{
printf("smc_create_huk failed\n");
csw.bCSWStatus = -1;
}
else
{
if(!ret)
printf("smc_create_huk successed\n");
else
printf("smc_create_huk already exist\n");
memcpy((void *)trans_data.act_send_buffer, huk, 32);
}
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
}
break;
case 7: //read key one by one
{
int ret;
int read_len = 0;
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
ret = __sunxi_read_key_by_name(private_data_ext_buff, DATA_BUFFER_MAX_SIZE, &read_len);
if(!ret)
{
printf("read key success\n");
csw.bCSWStatus = 0;
}
else
{
printf("read key failed\n");
csw.bCSWStatus = 1;
}
trans_data.act_send_buffer = (uint)trans_data.base_send_buffer;
trans_data.send_size = max(cbw->dCBWDataTransferLength, read_len);
memcpy((void *)trans_data.act_send_buffer, (void *)private_data_ext_buff, read_len);
printf("read_len=%d\n", read_len);
printf("the send data:\n");
sunxi_dump((void *)private_data_ext_buff, read_len);
}
break;
case 8: //erase all key in securestorage
{
int ret;
__usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer;
memset(handshake, 0, sizeof(__usb_handshake_ext_t));
csw.bCSWStatus = 0;
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
trans_data.act_send_buffer = (uint)trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t));
ret = sunxi_secure_storage_init();
if(ret < 0)
{
printf("secure storage init err\n");
strcpy(handshake->magic, "usb_erase_failed");
handshake->err_no = ERR_NO_ERASE_KEY_FAILED;
break;
}
ret = sunxi_secure_storage_erase_all();
if(ret < 0)
{
printf("erase secure storage failed\n");
strcpy(handshake->magic, "usb_erase_failed");
handshake->err_no = ERR_NO_ERASE_KEY_FAILED;
break;
}
strcpy(handshake->magic, "usb_erase_success");
handshake->err_no = ERR_NO_SUCCESS;
sunxi_secure_storage_exit();
printf("secure storage erase all success\n");
}
break;
default:
break;
}
break;
#endif
case 0xf3: //<2F>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EEA3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>
sunxi_usb_dbg("usb burn private\n");
printf("usb command = %d\n", cbw->CBWCDB[1]);
switch(cbw->CBWCDB[1])
{
case 0: //<2F><><EFBFBD><EFBFBD>
{
__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 = (uint)trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_t));
}
break;
case 1: //С<><D0A1><EFBFBD>˽<EFBFBD><CBBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
//pburn_flash_sectors = *(int *)(cbw->CBWCDB + 8);
pburn_flash_start = *(int *)(cbw->CBWCDB + 4);
trans_data.recv_size = cbw->dCBWDataTransferLength;
trans_data.act_recv_buffer = (uint)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: //С<><D0A1><EFBFBD>˷<EFBFBD><CBB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
uint start, sectors;
start = *(int *)(cbw->CBWCDB + 4); //<2F><><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD>ƫ<EFBFBD><C6AB><EFBFBD><EFBFBD>
sectors = *(int *)(cbw->CBWCDB + 8); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>;
printf("start=%d, sectors=%d\n", start, sectors);
trans_data.send_size = min(cbw->dCBWDataTransferLength, sectors * 512);
trans_data.act_send_buffer = (uint)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: //<2F>ر<EFBFBD>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 = (uint)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 = (uint)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;
case 0xf7: //<2F>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֣<EFBFBD><D6A3><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
sunxi_usb_dbg("usb burn partition\n");
sunxi_usb_dbg("usb command = %d\n", cbw->CBWCDB[1]);
switch (cbw->CBWCDB[1])
{
case 0: //<2F><><EFBFBD><EFBFBD>
{
printf("usb command = %d\n", cbw->CBWCDB[1]);
__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");
trans_data.act_send_buffer = (uint)trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_sec_t));
sunxi_usb_burn_from_boot_setup = 1;
csw.bCSWStatus = 0;
sunxi_usb_burn_from_boot_handshake = 1;
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
}
break;
case 1: //С<><D0A1><EFBFBD>˽<EFBFBD><CBBD>շ<EFBFBD><D5B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
//pburn_flash_start = *(int *)(cbw->CBWCDB + 4);
trans_data.recv_size = cbw->dCBWDataTransferLength;
trans_data.act_recv_buffer = (uint)trans_data.base_recv_buffer;
pburn_flash_start += pburn_flash_sectors;
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_dbg("recv_size=%d\n", trans_data.recv_size);
pburn_flash_sectors = (trans_data.recv_size + 511)/512;
sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_DATA;
}
break;
case 2: //<2F><>ѯ<EFBFBD><D1AF><EFBFBD><EFBFBD>
{
printf("usb command = %d\n", cbw->CBWCDB[1]);
__usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer;
memset(handshake, 0, sizeof(__usb_handshake_ext_t));
trans_data.act_send_buffer = (uint)trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t));
if(burn_part_result_state)
{
strcpy(handshake->magic, "usb_burn_error");
}
else
{
strcpy(handshake->magic, "usb_burn_success");
}
csw.bCSWStatus = 0;
handshake->err_no = burn_part_result_state;
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
}
break;
case 3: //С<><D0A1><EFBFBD>˽<EFBFBD><CBBD>շ<EFBFBD><D5B7><EFBFBD><EFBFBD><EFBFBD>Ϣ
{
printf("usb command = %d\n", cbw->CBWCDB[1]);
trans_data.recv_size = cbw->dCBWDataTransferLength;
trans_data.act_recv_buffer = (uint)trans_data.base_recv_buffer;
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_dbg("recv_size=%d\n", trans_data.recv_size);
sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_PART_INFO;
}
break;
case 4: //<2F>ر<EFBFBD>usb
{
printf("usb command = %d\n", cbw->CBWCDB[1]);
__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 = (uint)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;
#ifdef CONFIG_SUNXI_SECURE_STORAGE
case 5: //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>дkey flag
{
printf("usb command = %d\n", cbw->CBWCDB[1]);
__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 = (uint)trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t));
csw.bCSWStatus = 0;
if(sunxi_secure_storage_init())
{
printf("secure storage init err\n");
csw.bCSWStatus = -1;
break;
}
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;
#endif
case 7: //<2F><><EFBFBD>շ<EFBFBD><D5B7><EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
printf("usb command = %d\n", cbw->CBWCDB[1]);
trans_data.recv_size = cbw->dCBWDataTransferLength;
trans_data.act_recv_buffer = (uint)trans_data.base_recv_buffer;
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
printf("recv_size=%d\n", trans_data.recv_size);
sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_PART_VERIFY;
}
break;
default:
printf("usb command = %d not support\n", cbw->CBWCDB[1]);
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:
printf("SUNXI_USB_RECEIVE_DATA\n");
if((sunxi_usb_pburn_write_enable == 1) && (fel_verify == 0 ))
{
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;
}
if(sunxi_usb_pburn_write_enable == 1)
{
sunxi_usb_pburn_write_enable = 0;
sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS;
}
break;
case SUNXI_USB_PBURN_STATUS:
printf("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;
case SUNXI_USB_PBURN_RECEIVE_PART_INFO:
printf("SUNXI_USB_PBURN_RECEIVE_PART_INFO\n");
if(sunxi_usb_pburn_write_enable == 1)
{
//sunxi_dump((u8 *)(trans_data.act_recv_buffer), 1024);
burn_part_result_state = burn_part_probe((void*)trans_data.act_recv_buffer);
if(!burn_part_result_state)
{
pburn_flash_start = burn_part_start;
pburn_flash_sectors = 0;
}
csw.bCSWStatus = 0;
sunxi_usb_pburn_write_enable = 0;
sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS;
}
break;
case SUNXI_USB_PBURN_RECEIVE_PART_VERIFY:
printf("SUNXI_USB_PBURN_RECEIVE_PART_VERIFY\n");
if(sunxi_usb_pburn_write_enable == 1)
{
//<2F><><EFBFBD><EFBFBD>У<EFBFBD><D0A3>
//sunxi_dump((u8 *)(trans_data.act_recv_buffer), 1024);
printf("burn_part_bytes=%lld\n", burn_part_bytes);
ret = sunxi_burn_part_verify((void *)trans_data.act_recv_buffer, burn_part_bytes);
if(!ret) //<2F><><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD>ɹ<EFBFBD>
{
printf("data verify success\n");
burn_part_result_state = ERR_NO_SUCCESS;
}
else //<2F><><EFBFBD><EFBFBD>У<EFBFBD><D0A3>ʧ<EFBFBD><CAA7>
{
printf("data verify failed\n");
burn_part_result_state = ERR_NO_PART_VERIFY_ERR;
}
csw.bCSWStatus = 0;
sunxi_usb_pburn_write_enable = 0;
sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS;
}
break;
default:
break;
}
return 0;
}
sunxi_usb_module_init(SUNXI_USB_DEVICE_BURN, \
sunxi_pburn_init, \
sunxi_pburn_exit, \
sunxi_pburn_reset, \
sunxi_pburn_standard_req_op, \
sunxi_pburn_nonstandard_req_op, \
sunxi_pburn_state_loop, \
sunxi_pburn_usb_rx_dma_isr, \
sunxi_pburn_usb_tx_dma_isr \
);