/* * (C) Copyright 2007-2013 * Allwinner Technology Co., Ltd. * Jerry Wang * * 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 #include #include #include #include "usb_fastboot.h" #include #include #include #include #include #include #include "../sprite/sparse/sparse.h" #include "../sprite/sprite_download.h" DECLARE_GLOBAL_DATA_PTR; int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); static int sunxi_usb_fastboot_write_enable = 0; static int sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE; static fastboot_trans_set_t trans_data; static uint all_download_bytes; int fastboot_data_flag; extern int sunxi_usb_exit(void); /* ******************************************************************************* * do_usb_req_set_interface * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __usb_set_interface(struct usb_device_request *req) { sunxi_usb_dbg("set interface\n"); /* Only support interface 0, alternate 0 */ if((0 == req->wIndex) && (0 == req->wValue)) { sunxi_udc_ep_reset(); } else { printf("err: invalid wIndex and wValue, (0, %d), (0, %d)\n", req->wIndex, req->wValue); return SUNXI_USB_REQ_OP_ERR; } return SUNXI_USB_REQ_SUCCESSED; } /* ******************************************************************************* * do_usb_req_set_address * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __usb_set_address(struct usb_device_request *req) { uchar address; address = req->wValue & 0x7f; printf("set address 0x%x\n", address); sunxi_udc_set_address(address); return SUNXI_USB_REQ_SUCCESSED; } /* ******************************************************************************* * do_usb_req_set_configuration * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __usb_set_configuration(struct usb_device_request *req) { sunxi_usb_dbg("set configuration\n"); /* Only support 1 configuration so nak anything else */ if (1 == req->wValue) { sunxi_udc_ep_reset(); } else { printf("err: invalid wValue, (0, %d)\n", req->wValue); return SUNXI_USB_REQ_OP_ERR; } sunxi_udc_set_configuration(req->wValue); return SUNXI_USB_REQ_SUCCESSED; } /* ******************************************************************************* * do_usb_req_get_descriptor * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __usb_get_descriptor(struct usb_device_request *req, uchar *buffer) { int ret = SUNXI_USB_REQ_SUCCESSED; //获取描述符 switch(req->wValue >> 8) { case USB_DT_DEVICE: //设备描述符 { struct usb_device_descriptor *dev_dscrptr; sunxi_usb_dbg("get device descriptor\n"); dev_dscrptr = (struct usb_device_descriptor *)buffer; memset((void *)dev_dscrptr, 0, sizeof(struct usb_device_descriptor)); dev_dscrptr->bLength = MIN(req->wLength, sizeof (struct usb_device_descriptor)); dev_dscrptr->bDescriptorType = USB_DT_DEVICE; #ifdef CONFIG_USB_1_1_DEVICE dev_dscrptr->bcdUSB = 0x110; #else dev_dscrptr->bcdUSB = 0x200; #endif dev_dscrptr->bDeviceClass = 0xff; //设备类:大容量存储 dev_dscrptr->bDeviceSubClass = 0xff; dev_dscrptr->bDeviceProtocol = 0xff; dev_dscrptr->bMaxPacketSize0 = 0x40; dev_dscrptr->idVendor = DEVICE_VENDOR_ID; dev_dscrptr->idProduct = DEVICE_PRODUCT_ID; dev_dscrptr->bcdDevice = DEVICE_BCD; dev_dscrptr->iManufacturer = SUNXI_FASTBOOT_DEVICE_STRING_MANUFACTURER_INDEX; dev_dscrptr->iProduct = SUNXI_FASTBOOT_DEVICE_STRING_PRODUCT_INDEX; dev_dscrptr->iSerialNumber = SUNXI_FASTBOOT_DEVICE_STRING_SERIAL_NUMBER_INDEX; dev_dscrptr->bNumConfigurations = 1; sunxi_udc_send_setup(dev_dscrptr->bLength, buffer); } break; case USB_DT_CONFIG: //配置描述符 { struct usb_configuration_descriptor *config_dscrptr; struct usb_interface_descriptor *inter_dscrptr; struct usb_endpoint_descriptor *ep_in, *ep_out; unsigned char bytes_remaining = req->wLength; unsigned char bytes_total = 0; sunxi_usb_dbg("get config descriptor\n"); bytes_total = sizeof (struct usb_configuration_descriptor) + \ sizeof (struct usb_interface_descriptor) + \ sizeof (struct usb_endpoint_descriptor) + \ sizeof (struct usb_endpoint_descriptor); memset(buffer, 0, bytes_total); config_dscrptr = (struct usb_configuration_descriptor *)(buffer + 0); inter_dscrptr = (struct usb_interface_descriptor *)(buffer + \ sizeof(struct usb_configuration_descriptor)); ep_in = (struct usb_endpoint_descriptor *)(buffer + \ sizeof(struct usb_configuration_descriptor) + \ sizeof(struct usb_interface_descriptor)); ep_out = (struct usb_endpoint_descriptor *)(buffer + \ sizeof(struct usb_configuration_descriptor) + \ sizeof(struct usb_interface_descriptor) + \ sizeof(struct usb_endpoint_descriptor)); /* configuration */ config_dscrptr->bLength = MIN(bytes_remaining, sizeof (struct usb_configuration_descriptor)); config_dscrptr->bDescriptorType = USB_DT_CONFIG; config_dscrptr->wTotalLength = bytes_total; config_dscrptr->bNumInterfaces = 1; config_dscrptr->bConfigurationValue = 1; config_dscrptr->iConfiguration = SUNXI_FASTBOOT_DEVICE_STRING_CONFIG_INDEX; config_dscrptr->bmAttributes = 0xC0; config_dscrptr->bMaxPower = 0xFA; //最大电流500ms(0xfa * 2) bytes_remaining -= config_dscrptr->bLength; /* interface */ inter_dscrptr->bLength = MIN (bytes_remaining, sizeof(struct usb_interface_descriptor)); inter_dscrptr->bDescriptorType = USB_DT_INTERFACE; inter_dscrptr->bInterfaceNumber = 0x00; inter_dscrptr->bAlternateSetting = 0x00; inter_dscrptr->bNumEndpoints = 0x02; inter_dscrptr->bInterfaceClass = 0xff; //fastboot storage inter_dscrptr->bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS; inter_dscrptr->bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL; inter_dscrptr->iInterface = SUNXI_FASTBOOT_DEVICE_STRING_INTERFACE_INDEX; bytes_remaining -= inter_dscrptr->bLength; /* ep_in */ ep_in->bLength = MIN (bytes_remaining, sizeof (struct usb_endpoint_descriptor)); ep_in->bDescriptorType = USB_DT_ENDPOINT; ep_in->bEndpointAddress = sunxi_udc_get_ep_in_type(); /* IN */ ep_in->bmAttributes = USB_ENDPOINT_XFER_BULK; ep_in->wMaxPacketSize = sunxi_udc_get_ep_max(); ep_in->bInterval = 0x00; bytes_remaining -= ep_in->bLength; /* ep_out */ ep_out->bLength = MIN (bytes_remaining, sizeof (struct usb_endpoint_descriptor)); ep_out->bDescriptorType = USB_DT_ENDPOINT; ep_out->bEndpointAddress = sunxi_udc_get_ep_out_type(); /* OUT */ ep_out->bmAttributes = USB_ENDPOINT_XFER_BULK; ep_out->wMaxPacketSize = sunxi_udc_get_ep_max(); ep_out->bInterval = 0x00; bytes_remaining -= ep_out->bLength; sunxi_udc_send_setup(MIN(req->wLength, bytes_total), buffer); } break; case USB_DT_STRING: { unsigned char bLength = 0; unsigned char string_index = req->wValue & 0xff; sunxi_usb_dbg("get string descriptor\n"); /* Language ID */ if(string_index == 0) { bLength = MIN(4, req->wLength); sunxi_udc_send_setup(bLength, (void *)sunxi_usb_fastboot_dev[0]); } else if(string_index < SUNXI_USB_FASTBOOT_DEV_MAX) { /* Size of string in chars */ unsigned char i = 0; unsigned char str_length = strlen ((const char *)sunxi_usb_fastboot_dev[string_index]); unsigned char bLength = 2 + (2 * str_length); buffer[0] = bLength; /* length */ buffer[1] = USB_DT_STRING; /* descriptor = string */ /* Copy device string to fifo, expand to simple unicode */ for(i = 0; i < str_length; i++) { buffer[2+ 2*i + 0] = sunxi_usb_fastboot_dev[string_index][i]; buffer[2+ 2*i + 1] = 0; } bLength = MIN(bLength, req->wLength); sunxi_udc_send_setup(bLength, buffer); } else { printf("sunxi usb err: string line %d is not supported\n", string_index); } } break; case USB_DT_DEVICE_QUALIFIER: { #ifdef CONFIG_USB_1_1_DEVICE /* This is an invalid request for usb 1.1, nak it */ USBC_Dev_EpSendStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0); #else struct usb_qualifier_descriptor *qua_dscrpt; sunxi_usb_dbg("get qualifier descriptor\n"); qua_dscrpt = (struct usb_qualifier_descriptor *)buffer; memset(&buffer, 0, sizeof(struct usb_qualifier_descriptor)); qua_dscrpt->bLength = MIN(req->wLength, sizeof(sizeof(struct usb_qualifier_descriptor))); qua_dscrpt->bDescriptorType = USB_DT_DEVICE_QUALIFIER; qua_dscrpt->bcdUSB = 0x200; qua_dscrpt->bDeviceClass = 0xff; qua_dscrpt->bDeviceSubClass = 0xff; qua_dscrpt->bDeviceProtocol = 0xff; qua_dscrpt->bMaxPacketSize0 = 0x40; qua_dscrpt->bNumConfigurations = 1; //qua_dscrpt->bRESERVED = 0; qua_dscrpt->breserved = 0; sunxi_udc_send_setup(qua_dscrpt->bLength, buffer); #endif } break; default: printf("err: unkown wValue(%d)\n", req->wValue); ret = SUNXI_USB_REQ_OP_ERR; } return ret; } /* ******************************************************************************* * __usb_get_status * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __usb_get_status(struct usb_device_request *req, uchar *buffer) { unsigned char bLength = 0; sunxi_usb_dbg("get status\n"); if(0 == req->wLength) { /* sent zero packet */ sunxi_udc_send_setup(0, NULL); return SUNXI_USB_REQ_OP_ERR; } bLength = MIN(req->wValue, 2); buffer[0] = 1; buffer[1] = 0; sunxi_udc_send_setup(bLength, buffer); return SUNXI_USB_REQ_SUCCESSED; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int __sunxi_fastboot_send_status(void *buffer, unsigned int buffer_size) { return sunxi_udc_send_data((uchar *)buffer, buffer_size); } /* ******************************************************************************* * __fastboot_reboot * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __fastboot_reboot(int word_mode) { char response[8]; sprintf(response,"OKAY"); __sunxi_fastboot_send_status(response, strlen(response)); __msdelay(1000); /* 1 sec */ sunxi_board_restart(word_mode); return 0; } /* ******************************************************************************* * __erase_part * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __erase_part(char *name) { void *addr = (void *)FASTBOOT_ERASE_BUFFER; u32 start, unerased_sectors; u32 nblock = FASTBOOT_ERASE_BUFFER_SIZE/512; char response[68]; start = sunxi_partition_get_offset_byname(name); unerased_sectors = sunxi_partition_get_size_byname(name); if(gd->lockflag == SUNXI_LOCKING || gd->lockflag == SUNXI_RELOCKING) { printf("in lock state, sunxi fastboot erase is disabled\n"); __sunxi_fastboot_send_status(response, strlen(response)); return 0; } if((!start) || (!unerased_sectors)) { printf("sunxi fastboot erase FAIL: partition %s does not exist\n", name); sprintf(response, "FAILerase: partition %s does not exist", name); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } memset(addr, 0xff, FASTBOOT_ERASE_BUFFER_SIZE); while(unerased_sectors >= nblock) { if(!sunxi_flash_write(start, nblock, addr)) { printf("sunxi fastboot erase FAIL: failed to erase partition %s \n", name); sprintf(response,"FAILerase: failed to erase partition %s", name); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } start += nblock; unerased_sectors -= nblock; } if(unerased_sectors) { if(!sunxi_flash_write(start, unerased_sectors, addr)) { printf("sunxi fastboot erase FAIL: failed to erase partition %s \n", name); sprintf(response,"FAILerase: failed to erase partition %s", name); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } } printf("sunxi fastboot: partition '%s' erased\n", name); sprintf(response, "OKAY"); __sunxi_fastboot_send_status(response, strlen(response)); return 0; } /* ******************************************************************************* * __flash_to_part * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static void __flash_to_uboot(void) { struct spare_boot_head_t * temp_buf = (struct spare_boot_head_t *)trans_data.base_recv_buffer; char response[68]; u32 uboot_length = 0; u32 align_size = 0; u32 old_uboot_length = 0; u32 old_total_length = 0; if(strcmp((char*)temp_buf->boot_head.magic,"uboot")) { printf("sunxi fastboot error: there is not uboot file\n"); sprintf(response, "FAILdownload:there is not uboot file \n"); __sunxi_fastboot_send_status(response, strlen(response)); return ; } printf("ready to download bytes 0x%x\n", trans_data.try_to_recv); if(temp_buf->boot_head.uboot_length == 0) { printf("==== uboot.bin ====\n"); memcpy((char *)temp_buf , (char *)CONFIG_SYS_TEXT_BASE ,sizeof(struct spare_boot_head_t)); old_uboot_length = temp_buf->boot_head.uboot_length; old_total_length = temp_buf->boot_head.length ; debug("old_uboot_length = %x \n",old_uboot_length); debug("old_total_length = %x \n",old_total_length); //align uboot align_size = temp_buf->boot_head.align_size; printf("align_size is 0x%x \n",align_size); uboot_length = (trans_data.try_to_recv + align_size) & (~(align_size - 1)); temp_buf->boot_head.uboot_length = uboot_length; //copy sys_config from old uboot memcpy((char *)temp_buf + uboot_length , (char *)CONFIG_SYS_TEXT_BASE + old_uboot_length,old_total_length - old_uboot_length); //make check_sum again temp_buf->boot_head.check_sum = STAMP_VALUE; temp_buf->boot_head.length = uboot_length +old_total_length - old_uboot_length; temp_buf->boot_head.check_sum = add_sum((char *)temp_buf,temp_buf->boot_head.length); } printf("uboot checksum is 0x%x \n",temp_buf->boot_head.check_sum); printf("download uboot ing ....\n"); sunxi_sprite_download_uboot((char *)temp_buf,uboot_spare_head.boot_data.storage_type ,1); printf("sunxi fastboot: successed in downloading uboot \n"); sprintf(response, "OKAY"); __sunxi_fastboot_send_status(response, strlen(response)); return ; } static int __flash_to_part(char *name) { char *addr = trans_data.base_recv_buffer; u32 start, data_sectors; u32 part_sectors; u32 nblock = FASTBOOT_TRANSFER_BUFFER_SIZE/512; char response[68]; start = sunxi_partition_get_offset_byname(name); part_sectors = sunxi_partition_get_size_byname(name); if(gd->lockflag == SUNXI_LOCKING || gd->lockflag == SUNXI_RELOCKING) { printf("in lock state, sunxi fastboot flash is disabled\n"); __sunxi_fastboot_send_status(response, strlen(response)); return 0; } if((!start) || (!part_sectors)) { uint addr_in_hex; int ret; printf("sunxi fastboot download FAIL: partition %s does not exist\n", name); printf("probe it as a dram address\n"); ret = strict_strtoul((const char *)name, 16, (long unsigned int*)&addr_in_hex); if(ret) { printf("sunxi fatboot download FAIL: it is not a dram address\n"); sprintf(response, "FAILdownload: partition %s does not exist", name); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } else { printf("ready to move data to 0x%x, bytes 0x%x\n", addr_in_hex, trans_data.try_to_recv); memcpy((void *)(ulong)addr_in_hex, addr, trans_data.try_to_recv); } } else { int format; printf("ready to download bytes 0x%x\n", trans_data.try_to_recv); format = unsparse_probe(addr, trans_data.try_to_recv, start); if(ANDROID_FORMAT_DETECT == format) { if(unsparse_direct_write(addr, trans_data.try_to_recv)) { printf("sunxi fastboot download FAIL: failed to write partition %s \n", name); sprintf(response,"FAILdownload: write partition %s err", name); return -1; } } else { data_sectors = (trans_data.try_to_recv + 511)/512; if(data_sectors > part_sectors) { printf("sunxi fastboot download FAIL: partition %s size 0x%x is smaller than data size 0x%x\n", name, trans_data.act_recv, data_sectors * 512); sprintf(response, "FAILdownload: partition size < data size"); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } while(data_sectors >= nblock) { if(!sunxi_flash_write(start, nblock, addr)) { printf("sunxi fastboot download FAIL: failed to write partition %s \n", name); sprintf(response,"FAILdownload: write partition %s err", name); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } start += nblock; data_sectors -= nblock; addr += FASTBOOT_TRANSFER_BUFFER_SIZE; } if(data_sectors) { if(!sunxi_flash_write(start, data_sectors, addr)) { printf("sunxi fastboot download FAIL: failed to write partition %s \n", name); sprintf(response,"FAILdownload: write partition %s err", name); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } } } } printf("sunxi fastboot: successed in downloading partition '%s'\n", name); sprintf(response, "OKAY"); __sunxi_fastboot_send_status(response, strlen(response)); return 0; } /* ******************************************************************************* * __try_to_download * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __try_to_download(char *download_size, char *response) { int ret = -1; trans_data.try_to_recv = simple_strtoul (download_size, NULL, 16); all_download_bytes = trans_data.try_to_recv; printf("Starting download of %d BYTES\n", trans_data.try_to_recv); printf("Starting download of %d MB\n", trans_data.try_to_recv >> 20); if (0 == trans_data.try_to_recv) { /* bad user input */ sprintf(response, "FAILdownload: data size is 0"); } else if (trans_data.try_to_recv > SUNXI_USB_FASTBOOT_BUFFER_MAX) { sprintf(response, "FAILdownload: data > buffer"); } else { /* The default case, the transfer fits completely in the interface buffer */ sprintf(response, "DATA%08x", trans_data.try_to_recv); printf("download response: %s\n", response); ret = 0; } return ret; } /* ******************************************************************************* * __boot * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static void __boot(void) { char response[68]; if(all_download_bytes > CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE) { char start[32]; char *bootm[3] = { "bootm", NULL, NULL, }; char *go[3] = { "go", NULL, NULL, }; struct fastboot_boot_img_hdr *fb_hdr = (struct fastboot_boot_img_hdr *) trans_data.base_recv_buffer; /* Skip the mkbootimage header */ image_header_t *hdr = (image_header_t *) &trans_data.base_recv_buffer[CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE]; bootm[1] = go[1] = start; sprintf(start, "0x%lx", (ulong)hdr); printf("start addr %s\n", start); /* Execution should jump to kernel so send the response now and wait a bit. */ sprintf(response, "OKAY"); // fastboot_tx_status(response, strlen(response)); __msdelay (1000); /* 1 sec */ if (ntohl(hdr->ih_magic) == IH_MAGIC) { /* Looks like a kernel.. */ printf ("Booting kernel..\n"); /* * Check if the user sent a bootargs down. * If not, do not override what is already there */ if (strlen ((char *) &fb_hdr->cmdline[0])) { printf("Image has cmdline:"); printf("%s\n", &fb_hdr->cmdline[0]); setenv ("bootargs", (char *) &fb_hdr->cmdline[0]); } do_bootm (NULL, 0, 2, bootm); } else { /* Raw image, maybe another uboot */ printf ("Booting raw image..\n"); do_go (NULL, 0, 2, go); } printf ("ERROR : bootting failed\n"); printf ("You should reset the board\n"); } else { sprintf(response, "FAILinvalid boot image"); } } /* ******************************************************************************* * __get_var * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static void __get_var(char *ver_name) { char response[68]; memset(response, 0, 68); strcpy(response,"OKAY"); if(!strcmp(ver_name, "version")) { strcpy(response + 4, FASTBOOT_VERSION); } else if(!strcmp(ver_name, "product")) { strcpy(response + 4, SUNXI_FASTBOOT_DEVICE_PRODUCT); } else if(!strcmp(ver_name, "serialno")) { strcpy(response + 4, SUNXI_FASTBOOT_DEVICE_SERIAL_NUMBER); } else if(!strcmp(ver_name, "downloadsize")) { sprintf(response + 4, "0x%08x", SUNXI_USB_FASTBOOT_BUFFER_MAX); printf("response: %s\n", response); } else if(!strcmp(ver_name, "secure")) { strcpy(response + 4, "yes"); } else if(!strcmp(ver_name, "max-download-size")) { sprintf(response + 4, "0x%08x", SUNXI_USB_FASTBOOT_BUFFER_MAX); printf("response: %s\n", response); } else { strcpy(response + 4, "not supported"); } __sunxi_fastboot_send_status(response, strlen(response)); return ; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static void __oem_operation(char *operation) { #if 0 char response[68]; char lock_info[64]; int lockflag; int ret; memset(lock_info, 0, 64); memset(response, 0, 68); if(!strncmp(operation, "lock", 4)) { lockflag = SUNXI_RELOCKING; } else if(!strncmp(operation, "unlock", 6)) { lockflag = SUNXI_UNLOCK; } else { if(!strncmp(operation, "efex", 4)) { strcpy(response, "OKAY"); __sunxi_fastboot_send_status(response, strlen(response)); sunxi_board_run_fel(); } else { const char *info = "fastboot oem operation fail: unknown cmd"; printf("%s\n", info); strcpy(response, "FAIL"); strcat(response, info); __sunxi_fastboot_send_status(response, strlen(response)); } return ; } ret = sunxi_oem_op_lock(lockflag, lock_info, 0); if(!ret) { strcpy(response, "OKAY"); } else { strcpy(response, "FAIL"); } strcat(response, lock_info); printf("%s\n", response); __sunxi_fastboot_send_status(response, strlen(response)); return ; #endif printf("not implement yet \n"); } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static void __continue(void) { char response[32]; memset(response, 0, 32); strcpy(response,"OKAY"); __sunxi_fastboot_send_status(response, strlen(response)); sunxi_usb_exit(); if(uboot_spare_head.boot_data.storage_type) { setenv("bootcmd", "run setargs_mmc boot_normal"); } else { setenv("bootcmd", "run setargs_nand boot_normal"); } do_bootd(NULL, 0, 1, NULL); return; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static void __unsupported_cmd(void) { char response[32]; memset(response, 0, 32); strcpy(response,"FAIL"); __sunxi_fastboot_send_status(response, strlen(response)); return; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int sunxi_fastboot_init(void) { printf("sunxi_fastboot_init\n"); memset(&trans_data, 0, sizeof(fastboot_trans_set_t)); sunxi_usb_fastboot_write_enable = 0; sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE; all_download_bytes = 0; fastboot_data_flag = 0; trans_data.base_recv_buffer = (char *)FASTBOOT_TRANSFER_BUFFER; trans_data.base_send_buffer = (char *)malloc(SUNXI_FASTBOOT_SEND_MEM_SIZE); if(!trans_data.base_send_buffer) { printf("sunxi usb fastboot err: unable to malloc memory for fastboot send\n"); free(trans_data.base_recv_buffer); return -1; } printf("recv addr 0x%lx\n", (ulong)trans_data.base_recv_buffer); printf("send addr 0x%lx\n", (ulong)trans_data.base_send_buffer); return 0; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int sunxi_fastboot_exit(void) { printf("sunxi_fastboot_exit\n"); if(trans_data.base_send_buffer) { free(trans_data.base_send_buffer); } return 0; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static void sunxi_fastboot_reset(void) { sunxi_usb_fastboot_write_enable = 0; sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static void sunxi_fastboot_usb_rx_dma_isr(void *p_arg) { printf("dma int for usb rx occur\n"); //通知主循环,可以写入数据 sunxi_usb_fastboot_write_enable = 1; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static void sunxi_fastboot_usb_tx_dma_isr(void *p_arg) { printf("dma int for usb tx occur\n"); } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int sunxi_fastboot_standard_req_op(uint cmd, struct usb_device_request *req, uchar *buffer) { int ret = SUNXI_USB_REQ_OP_ERR; switch(cmd) { case USB_REQ_GET_STATUS: { ret = __usb_get_status(req, buffer); break; } //case USB_REQ_CLEAR_FEATURE: //case USB_REQ_SET_FEATURE: case USB_REQ_SET_ADDRESS: { ret = __usb_set_address(req); break; } case USB_REQ_GET_DESCRIPTOR: //case USB_REQ_SET_DESCRIPTOR: case USB_REQ_GET_CONFIGURATION: { ret = __usb_get_descriptor(req, buffer); break; } case USB_REQ_SET_CONFIGURATION: { ret = __usb_set_configuration(req); break; } //case USB_REQ_GET_INTERFACE: case USB_REQ_SET_INTERFACE: { ret = __usb_set_interface(req); break; } //case USB_REQ_SYNCH_FRAME: default: { tick_printf("sunxi fastboot error: standard req is not supported\n"); ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED; break; } } return ret; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int sunxi_fastboot_nonstandard_req_op(uint cmd, struct usb_device_request *req, uchar *buffer, uint data_status) { return SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int sunxi_fastboot_state_loop(void *buffer) { int ret; sunxi_ubuf_t *sunxi_ubuf = (sunxi_ubuf_t *)buffer; char response[68]; switch(sunxi_usb_fastboot_status) { case SUNXI_USB_FASTBOOT_IDLE: if(sunxi_ubuf->rx_ready_for_data == 1) { sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_SETUP; } break; case SUNXI_USB_FASTBOOT_SETUP: tick_printf("SUNXI_USB_FASTBOOT_SETUP\n"); tick_printf("fastboot command = %s\n", sunxi_ubuf->rx_req_buffer); sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE; sunxi_ubuf->rx_ready_for_data = 0; if(memcmp(sunxi_ubuf->rx_req_buffer, "reboot-bootloader", strlen("reboot-bootloader")) == 0) { tick_printf("reboot-bootloader\n"); __fastboot_reboot(PMU_PRE_FASTBOOT_MODE); } else if(memcmp(sunxi_ubuf->rx_req_buffer, "reboot", 6) == 0) { tick_printf("reboot\n"); __fastboot_reboot(0); } else if(memcmp(sunxi_ubuf->rx_req_buffer, "erase:", 6) == 0) { tick_printf("erase\n"); __erase_part((char *)(sunxi_ubuf->rx_req_buffer + 6)); } else if(memcmp(sunxi_ubuf->rx_req_buffer, "flash:", 6) == 0) { tick_printf("flash\n"); if(memcmp((char *)(sunxi_ubuf->rx_req_buffer + 6),"u-boot",6) == 0) __flash_to_uboot(); else __flash_to_part((char *)(sunxi_ubuf->rx_req_buffer + 6)); } else if(memcmp(sunxi_ubuf->rx_req_buffer, "download:", 9) == 0) { tick_printf("download\n"); ret = __try_to_download((char *)(sunxi_ubuf->rx_req_buffer + 9), response); if(ret >= 0) { fastboot_data_flag = 1; sunxi_ubuf->rx_req_buffer = (uchar *)trans_data.base_recv_buffer; sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_RECEIVE_DATA; } __sunxi_fastboot_send_status(response, strlen(response)); } else if(memcmp(sunxi_ubuf->rx_req_buffer, "boot", 4) == 0) { tick_printf("boot\n"); __boot(); } else if(memcmp(sunxi_ubuf->rx_req_buffer, "getvar:", 7) == 0) { tick_printf("getvar\n"); __get_var((char *)(sunxi_ubuf->rx_req_buffer + 7)); } else if(memcmp(sunxi_ubuf->rx_req_buffer, "oem", 3) == 0) { tick_printf("oem operations\n"); __oem_operation((char *)(sunxi_ubuf->rx_req_buffer + 4)); } else if(memcmp(sunxi_ubuf->rx_req_buffer, "continue", 8) == 0) { tick_printf("continue\n"); __continue(); } else { tick_printf("not supported fastboot cmd\n"); __unsupported_cmd(); } break; case SUNXI_USB_FASTBOOT_SEND_DATA: tick_printf("SUNXI_USB_FASTBOOT_SEND_DATA\n"); break; case SUNXI_USB_FASTBOOT_RECEIVE_DATA: //tick_printf("SUNXI_USB_FASTBOOT_RECEIVE_DATA\n"); if((fastboot_data_flag == 1) && ((char *)sunxi_ubuf->rx_req_buffer == all_download_bytes + trans_data.base_recv_buffer)) //传输完毕 { tick_printf("fastboot transfer finish\n"); fastboot_data_flag = 0; sunxi_usb_fastboot_status = SUNXI_USB_FASTBOOT_IDLE; sunxi_ubuf->rx_req_buffer = sunxi_ubuf->rx_base_buffer; sprintf(response,"OKAY"); __sunxi_fastboot_send_status(response, strlen(response)); } break; default: break; } return 0; } sunxi_usb_module_init(SUNXI_USB_DEVICE_FASTBOOT, \ sunxi_fastboot_init, \ sunxi_fastboot_exit, \ sunxi_fastboot_reset, \ sunxi_fastboot_standard_req_op, \ sunxi_fastboot_nonstandard_req_op, \ sunxi_fastboot_state_loop, \ sunxi_fastboot_usb_rx_dma_isr, \ sunxi_fastboot_usb_tx_dma_isr \ );