| #include <string.h> |
| |
| #include "aboot-tiny.h" |
| #include "jacana_pvt.h" |
| |
| /*---------------------------------------------------------------------------*/ |
| static const char *jacana_pvt_cmd_resp[] = { |
| "getvar:max-download-size", /* 0 */ |
| "OKAY\t%08x", /* 1 */ |
| "download:%08x", /* 2 */ |
| "DATA%08x", /* 3 */ |
| "OKAY", /* 4 */ |
| "flash:pvt", /* 5 */ |
| "OKAY" /* 6 */ |
| }; |
| /*---------------------------------------------------------------------------*/ |
| static int |
| pvt_read_next_to_cache(firmware_handle_t *firmware) |
| { |
| size_t size = firmware->end_ptr - firmware->read_ptr; |
| memmove(firmware->read_ptr - firmware->read_sz, firmware->read_ptr, size); |
| firmware->read_ptr -= firmware->read_sz; |
| firmware->end_ptr -= firmware->read_sz; |
| size_t remainder = firmware->end - firmware->start; |
| if(remainder > 0) { |
| size_t size = remainder > firmware->read_sz ? firmware->read_sz : remainder; |
| int len = jacana_pvt_raw_read(firmware->priv, firmware->start, |
| (uint8_t *)firmware->middle_ptr, size); |
| if(len < 0) { |
| return -1; |
| } |
| firmware->start += len; |
| firmware->end_ptr += len; |
| } |
| |
| return 0; |
| } |
| /*---------------------------------------------------------------------------*/ |
| int |
| jacana_pvt_open(firmware_handle_t *firmware, void *priv) |
| { |
| firmware->priv = priv; |
| firmware->start = 0; |
| firmware->end = jacana_pvt_raw_get_total_size(priv); |
| |
| pvt_info_t *pvt_info = (pvt_info_t *)firmware->pvt_info; |
| pvt_info->max_download_size = aboot_tiny_get_max_download_size(); |
| if(pvt_info->max_download_size > 8192) { |
| pvt_info->max_download_size = 8192; |
| } |
| pvt_info->offset = 0; |
| pvt_info->state = 0; |
| |
| firmware->data = aboot_tiny_mem_alloc(MAX_READ_CACHE_SZ * 2); |
| if(!firmware->data) { |
| aboot_tiny_log_printf("Failed: can not alloc data buf\n"); |
| return -1; |
| } |
| |
| firmware->read_sz = MAX_READ_CACHE_SZ; |
| firmware->middle_ptr = (char *)firmware->data + firmware->read_sz; |
| firmware->end_ptr = firmware->middle_ptr + firmware->read_sz; |
| firmware->read_ptr = firmware->end_ptr; |
| if(pvt_read_next_to_cache(firmware) < 0) { |
| aboot_tiny_mem_free(firmware->data); |
| firmware->data = NULL; |
| return -1; |
| } |
| |
| sparse_file_t *sparse_file = &pvt_info->sparse_file; |
| size_t remainder = firmware->end - firmware->start; |
| size_t size = (pvt_info->max_download_size |
| - SPARSE_FILE_HEADER_SIZE |
| - SPARSE_FILE_FOOTER_SIZE) & ~(SPARSE_BLOCK_SZ - 1); |
| if(remainder < size) { |
| size = remainder; |
| } |
| |
| sparse_file_new(sparse_file, pvt_info->offset, size, firmware->end); |
| pvt_info->offset += size; |
| |
| return 0; |
| } |
| /*---------------------------------------------------------------------------*/ |
| int |
| jacana_pvt_read_line(firmware_handle_t *firmware, char *line) |
| { |
| pvt_info_t *pvt_info = (pvt_info_t *)firmware->pvt_info; |
| sparse_file_t *sparse_file = &pvt_info->sparse_file; |
| |
| switch(pvt_info->state) { |
| case 0: |
| case 4: |
| case 5: |
| case 6: |
| strcpy(line,jacana_pvt_cmd_resp[pvt_info->state]); |
| break; |
| |
| case 1: |
| sprintf(line, jacana_pvt_cmd_resp[pvt_info->state], |
| pvt_info->max_download_size); |
| break; |
| case 2: |
| case 3: |
| sprintf(line, jacana_pvt_cmd_resp[pvt_info->state], |
| sparse_file->header_size |
| + sparse_file->data_size |
| + sparse_file->fill_size |
| + sparse_file->footer_size); |
| break; |
| |
| case 7: /* pvt command sequence finished */ |
| if(firmware->start < firmware->end) { |
| pvt_info->state = 0; |
| |
| size_t remainder = firmware->end - firmware->start; |
| size_t size = (pvt_info->max_download_size |
| - SPARSE_FILE_HEADER_SIZE |
| - SPARSE_FILE_FOOTER_SIZE) & ~(SPARSE_BLOCK_SZ - 1); |
| if(remainder < size) { |
| size = remainder; |
| } |
| sparse_file_new(sparse_file, pvt_info->offset, size, firmware->end); |
| pvt_info->offset += size; |
| return jacana_pvt_read_line(firmware, line); |
| } else { |
| if(pvt_info->offset < firmware->end) { |
| /* remainder data in cache */ |
| pvt_info->state = 0; |
| size_t size = firmware->end - pvt_info->offset; |
| sparse_file_new(sparse_file, pvt_info->offset, size, firmware->end); |
| pvt_info->offset += size; |
| return jacana_pvt_read_line(firmware, line); |
| } else { |
| /* all finished */ |
| return 0; |
| } |
| } |
| |
| default: |
| return -1; |
| } |
| pvt_info->state++; |
| |
| return strlen(line); |
| } |
| /*---------------------------------------------------------------------------*/ |
| int |
| jacana_pvt_read_data(firmware_handle_t *firmware, uint8_t *data, size_t size) |
| { |
| pvt_info_t *pvt_info = (pvt_info_t *)firmware->pvt_info; |
| sparse_file_t *sparse_file = &pvt_info->sparse_file; |
| |
| if(sparse_file->header_size) { |
| if(sparse_file->header_size > size) { |
| /* should not happen */ |
| return -1; |
| } else { |
| size = sparse_file->header_size; |
| memcpy(data, sparse_file->header, size); |
| sparse_file->header_size = 0; |
| return size; |
| } |
| } |
| |
| if(sparse_file->footer_size == 0) { |
| /* should not happen */ |
| return -1; |
| } |
| |
| if(sparse_file->data_size == 0) { |
| if(sparse_file->fill_size) { |
| if(size > sparse_file->fill_size) { |
| size = sparse_file->fill_size; |
| } |
| memset(data, 0, size); |
| sparse_file->fill_size -= size; |
| return size; |
| } else if(sparse_file->footer_size > size) { |
| /* should not happen */ |
| return -1; |
| } else { |
| /* footer_size <= size */ |
| size = sparse_file->footer_size; |
| memcpy(data, sparse_file->footer, size); |
| sparse_file->footer_size = 0; |
| return size; |
| } |
| } |
| |
| if(sparse_file->data_size < size) { |
| size = sparse_file->data_size; |
| } |
| |
| while(1) { |
| if(firmware->read_ptr == firmware->end_ptr) { |
| /* should not happen */ |
| return -1; |
| } |
| if(firmware->read_ptr < firmware->middle_ptr) { |
| size_t remainder = firmware->middle_ptr - firmware->read_ptr; |
| if(remainder < size) { |
| size = remainder; |
| } |
| memcpy(data, firmware->read_ptr, size); |
| firmware->read_ptr += size; |
| break; |
| } else { |
| /* read_ptr >= middle_ptr */ |
| if(pvt_read_next_to_cache(firmware) < 0) { |
| return -1; |
| } |
| } |
| } |
| |
| sparse_file->data_size -= size; |
| |
| return size; |
| } |
| /*---------------------------------------------------------------------------*/ |
| void |
| jacana_pvt_close(firmware_handle_t *firmware) |
| { |
| firmware->priv = NULL; |
| firmware->start = 0; |
| firmware->end = 0; |
| |
| if(firmware->data) { |
| aboot_tiny_mem_free(firmware->data); |
| firmware->data = NULL; |
| } |
| firmware->read_sz = 0; |
| firmware->read_ptr = NULL; |
| firmware->middle_ptr = NULL; |
| firmware->end_ptr = NULL; |
| |
| pvt_info_t *pvt_info = (pvt_info_t *)firmware->pvt_info; |
| pvt_info->max_download_size = 0; |
| pvt_info->state = 0; |
| |
| sparse_file_t *sparse_file = &pvt_info->sparse_file; |
| memset(sparse_file->header, 0, SPARSE_FILE_HEADER_SIZE); |
| sparse_file->header_size = 0; |
| sparse_file->data_size = 0; |
| } |
| /*---------------------------------------------------------------------------*/ |