/* ************************************************************************************************************ * * 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 ; }
/* ******************************************************************************* * __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; }
/* ******************************************************************************* * __flash_to_part * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static void __flash_to_uboot(void) { struct spare_boot_head_t * temp_buf = (struct spare_boot_head_t *)trans_data.base_recv_buffer; char response[68]; u32 uboot_length = 0; u32 align_size = 0; u32 old_uboot_length = 0; u32 old_total_length = 0; if(strcmp((char*)temp_buf->boot_head.magic,"uboot")) { printf("sunxi fastboot error: there is not uboot file\n"); sprintf(response, "FAILdownload:there is not uboot file \n"); __sunxi_fastboot_send_status(response, strlen(response)); return ; } printf("ready to download bytes 0x%x\n", trans_data.try_to_recv); if(temp_buf->boot_head.uboot_length == 0) { printf("==== uboot.bin ====\n"); memcpy((char *)temp_buf , (char *)CONFIG_SYS_TEXT_BASE ,sizeof(struct spare_boot_head_t)); old_uboot_length = temp_buf->boot_head.uboot_length; old_total_length = temp_buf->boot_head.length ; debug("old_uboot_length = %x \n",old_uboot_length); debug("old_total_length = %x \n",old_total_length); //align uboot align_size = temp_buf->boot_head.align_size; printf("align_size is 0x%x \n",align_size); uboot_length = (trans_data.try_to_recv + align_size) & (~(align_size - 1)); temp_buf->boot_head.uboot_length = uboot_length; //copy sys_config from old uboot memcpy((char *)temp_buf + uboot_length , (char *)CONFIG_SYS_TEXT_BASE + old_uboot_length,old_total_length - old_uboot_length); //make check_sum again temp_buf->boot_head.check_sum = STAMP_VALUE; temp_buf->boot_head.length = uboot_length +old_total_length - old_uboot_length; temp_buf->boot_head.check_sum = add_sum((char *)temp_buf,temp_buf->boot_head.length); } printf("uboot checksum is 0x%x \n",temp_buf->boot_head.check_sum); printf("download uboot ing ....\n"); sunxi_sprite_download_uboot((char *)temp_buf,uboot_spare_head.boot_data.storage_type ,1); printf("sunxi fastboot: successed in downloading uboot \n"); sprintf(response, "OKAY"); __sunxi_fastboot_send_status(response, strlen(response)); return ; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static void __unsupported_cmd(void) { char response[32]; memset(response, 0, 32); strcpy(response,"FAIL"); __sunxi_fastboot_send_status(response, strlen(response)); return; }
/* ******************************************************************************* * __fastboot_reboot * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __fastboot_reboot(int word_mode) { char response[8]; sprintf(response,"OKAY"); __sunxi_fastboot_send_status(response, strlen(response)); __msdelay(1000); /* 1 sec */ sunxi_board_restart(word_mode); return 0; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static void __limited_fastboot(void) { char response[64]; memset(response, 0, 64); tick_printf("secure mode,fastboot limited used\n"); strcpy(response,"FAIL:secure mode,fastboot limited used"); __sunxi_fastboot_send_status(response, strlen(response)); return; }
/* ******************************************************************************* * __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 __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; }
/* ******************************************************************************* * __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; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int sunxi_fastboot_state_loop(void *buffer) { int ret; sunxi_ubuf_t *sunxi_ubuf = (sunxi_ubuf_t *)buffer; char response[68]; switch(sunxi_usb_fastboot_status) { case SUNXI_USB_FASTBOOT_IDLE: if(sunxi_ubuf->rx_ready_for_data == 1) { sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_SETUP; } break; case SUNXI_USB_FASTBOOT_SETUP: tick_printf("SUNXI_USB_FASTBOOT_SETUP\n"); tick_printf("fastboot command = %s\n", sunxi_ubuf->rx_req_buffer); sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE; sunxi_ubuf->rx_ready_for_data = 0; if(memcmp(sunxi_ubuf->rx_req_buffer, "reboot-bootloader", strlen("reboot-bootloader")) == 0) { tick_printf("reboot-bootloader\n"); __fastboot_reboot(PMU_PRE_FASTBOOT_MODE); } else if(memcmp(sunxi_ubuf->rx_req_buffer, "reboot", 6) == 0) { tick_printf("reboot\n"); __fastboot_reboot(0); } else if(memcmp(sunxi_ubuf->rx_req_buffer, "erase:", 6) == 0) { tick_printf("erase\n"); __erase_part((char *)(sunxi_ubuf->rx_req_buffer + 6)); } else if(memcmp(sunxi_ubuf->rx_req_buffer, "flash:", 6) == 0) { tick_printf("flash\n"); __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; }