blob: 166128f73868743a8ca80f3ddbf34d538d662ff9 [file] [log] [blame]
#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;
}
/*---------------------------------------------------------------------------*/