376 lines
15 KiB
C
376 lines
15 KiB
C
/******************************************************************************
|
|
@file sahara_protocol.c
|
|
@brief sahara protocol.
|
|
|
|
DESCRIPTION
|
|
QFirehoe Tool for USB and PCIE of Quectel wireless cellular modules.
|
|
|
|
INITIALIZATION AND SEQUENCING REQUIREMENTS
|
|
None.
|
|
|
|
---------------------------------------------------------------------------
|
|
Copyright (c) 2016 - 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
|
|
Quectel Wireless Solution Proprietary and Confidential.
|
|
---------------------------------------------------------------------------
|
|
******************************************************************************/
|
|
#include "usb_linux.h"
|
|
#include "sahara_protocol.h"
|
|
|
|
int g_is_sc600y_chip = 0;
|
|
|
|
static uint32_t le_uint32(uint32_t v32) {
|
|
const int is_bigendian = 1;
|
|
uint32_t tmp = v32;
|
|
if ((*(char*)&is_bigendian) == 0) {
|
|
unsigned char *s = (unsigned char *)(&v32);
|
|
unsigned char *d = (unsigned char *)(&tmp);
|
|
d[0] = s[3];
|
|
d[1] = s[2];
|
|
d[2] = s[1];
|
|
d[3] = s[0];
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
#define dbg( log_level, fmt, arg... ) do {dbg_time(fmt "\n", ## arg);} while (0)
|
|
|
|
static int sahara_tx_data (void *usb_handle, void *tx_buffer, size_t bytes_to_send) {
|
|
int need_zlp = 0; //zlp is not mandatory
|
|
return qusb_noblock_write(usb_handle, tx_buffer, bytes_to_send, bytes_to_send, 3000, need_zlp);
|
|
}
|
|
|
|
int qusb_use_usbfs_interface(const void *handle);
|
|
static int sahara_rx_data(void *usb_handle, void *rx_buffer, size_t bytes_to_read) {
|
|
sahara_packet_header* command_packet_header = NULL;
|
|
size_t bytes_read = 0;
|
|
|
|
const char *boot_sahara_cmd_id_str[SAHARA_LAST_CMD_ID] = {
|
|
"SAHARA_NO_CMD_ID", // = 0x00,
|
|
" SAHARA_HELLO_ID", // = 0x01, // sent from target to host
|
|
"SAHARA_HELLO_RESP_ID", // = 0x02, // sent from host to target
|
|
"SAHARA_READ_DATA_ID", // = 0x03, // sent from target to host
|
|
"SAHARA_END_IMAGE_TX_ID", // = 0x04, // sent from target to host
|
|
"SAHARA_DONE_ID", // = 0x05, // sent from host to target
|
|
"SAHARA_DONE_RESP_ID", // = 0x06, // sent from target to host
|
|
"SAHARA_RESET_ID", // = 0x07, // sent from host to target
|
|
"SAHARA_RESET_RESP_ID", // = 0x08, // sent from target to host
|
|
"SAHARA_MEMORY_DEBUG_ID", // = 0x09, // sent from target to host
|
|
"SAHARA_MEMORY_READ_ID", // = 0x0A, // sent from host to target
|
|
"SAHARA_CMD_READY_ID", // = 0x0B, // sent from target to host
|
|
"SAHARA_CMD_SWITCH_MODE_ID", // = 0x0C, // sent from host to target
|
|
"SAHARA_CMD_EXEC_ID", // = 0x0D, // sent from host to target
|
|
"SAHARA_CMD_EXEC_RESP_ID", // = 0x0E, // sent from target to host
|
|
"SAHARA_CMD_EXEC_DATA_ID", // = 0x0F, // sent from host to target
|
|
"SAHARA_64_BITS_MEMORY_DEBUG_ID", // = 0x10, // sent from target to host
|
|
"SAHARA_64_BITS_MEMORY_READ_ID", // = 0x11, // sent from host to target
|
|
"SAHARA_64_BITS_READ_DATA_ID", // = 0x12,
|
|
};
|
|
|
|
if (0 == bytes_to_read) {
|
|
if (qusb_use_usbfs_interface(usb_handle)) {
|
|
bytes_read = qusb_noblock_read(usb_handle, rx_buffer, SAHARA_RAW_BUFFER_SIZE, 0, 5000);
|
|
if (bytes_read < sizeof(sahara_packet_header))
|
|
return 0;
|
|
}
|
|
else {
|
|
bytes_read = qusb_noblock_read(usb_handle, rx_buffer, sizeof(sahara_packet_header), 0, 5000);
|
|
if (bytes_read != sizeof(sahara_packet_header))
|
|
return 0;
|
|
}
|
|
|
|
command_packet_header = (sahara_packet_header *) rx_buffer;
|
|
if (le_uint32(command_packet_header->command) < SAHARA_LAST_CMD_ID) {
|
|
dbg(LOG_EVENT, "RECEIVED <-- %s", boot_sahara_cmd_id_str[le_uint32(command_packet_header->command)]);
|
|
|
|
if (!qusb_use_usbfs_interface(usb_handle)) {
|
|
bytes_read += qusb_noblock_read(usb_handle, (uint8_t *)rx_buffer + sizeof(sahara_packet_header),
|
|
le_uint32(command_packet_header->length) - sizeof(sahara_packet_header), 0, 5000);
|
|
}
|
|
|
|
if (bytes_read != (le_uint32(command_packet_header->length))) {
|
|
dbg(LOG_INFO, "Read %zd bytes, Header indicates command %d and packet length %d bytes",
|
|
bytes_read, le_uint32(command_packet_header->command), le_uint32(command_packet_header->length));
|
|
return 0;
|
|
}
|
|
} else {
|
|
dbg(LOG_EVENT, "RECEIVED <-- SAHARA_CMD_UNKONOW_%d", le_uint32(command_packet_header->command));
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
bytes_read = qusb_noblock_read(usb_handle, rx_buffer, bytes_to_read, bytes_to_read, 5000);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int send_reset_command (void *usb_handle, void *tx_buffer) {
|
|
#if 0
|
|
unsigned char edl_cmd[] = {0x4b, 0x65, 0x01, 0x00, 0x54, 0x0f, 0x7e};
|
|
sahara_tx_data(usb_handle, edl_cmd, sizeof(edl_cmd));
|
|
return 1;
|
|
#else
|
|
sahara_packet_reset *sahara_reset = (sahara_packet_reset *)tx_buffer;
|
|
sahara_reset->header.command = le_uint32(SAHARA_RESET_ID);
|
|
sahara_reset->header.length = le_uint32(sizeof(sahara_packet_reset));
|
|
|
|
/* Send the Reset Request */
|
|
dbg(LOG_EVENT, "SENDING --> SAHARA_RESET");
|
|
if (0 == sahara_tx_data (usb_handle, tx_buffer, sizeof(sahara_packet_reset))) {
|
|
dbg(LOG_ERROR, "Sending RESET packet failed");
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
static int send_done_packet (void *usb_handle, void *tx_buffer) {
|
|
sahara_packet_done *sahara_done = (sahara_packet_done *)tx_buffer;
|
|
|
|
sahara_done->header.command = le_uint32(SAHARA_DONE_ID);
|
|
sahara_done->header.length = le_uint32(sizeof(sahara_packet_done));
|
|
// Send the image data
|
|
dbg(LOG_EVENT, "SENDING --> SAHARA_DONE");
|
|
if (0 == sahara_tx_data (usb_handle, tx_buffer, sizeof(sahara_packet_done))) {
|
|
dbg(LOG_ERROR, "Sending DONE packet failed");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int start_image_transfer(void *usb_handle, void *tx_buffer, const sahara_packet_read_data *sahara_read_data, FILE *file_handle)
|
|
{
|
|
int retval = 0;
|
|
uint32_t bytes_read = 0, bytes_to_read_next;
|
|
uint32_t DataOffset = le_uint32(sahara_read_data->data_offset);
|
|
uint32_t DataLength = le_uint32(sahara_read_data->data_length);
|
|
|
|
dbg(LOG_INFO, "0x%08x 0x%08x 0x%08x", le_uint32(sahara_read_data->image_id), DataOffset, DataLength);
|
|
|
|
if (fseek(file_handle, (long)DataOffset, SEEK_SET)) {
|
|
dbg(LOG_INFO, "%d errno: %d (%s)", __LINE__, errno, strerror(errno));
|
|
return 0;
|
|
}
|
|
|
|
while (bytes_read < DataLength) {
|
|
bytes_to_read_next = MIN((uint32_t)DataLength - bytes_read, SAHARA_RAW_BUFFER_SIZE);
|
|
retval = fread(tx_buffer, 1, bytes_to_read_next, file_handle);
|
|
|
|
if (retval < 0) {
|
|
dbg(LOG_ERROR, "file read failed: %s", strerror(errno));
|
|
return 0;
|
|
}
|
|
|
|
if ((uint32_t) retval != bytes_to_read_next) {
|
|
dbg(LOG_ERROR, "Read %d bytes, but was asked for 0x%08x bytes", retval, DataLength);
|
|
return 0;
|
|
}
|
|
|
|
/*send the image data*/
|
|
if (0 == sahara_tx_data (usb_handle, tx_buffer, bytes_to_read_next)) {
|
|
dbg(LOG_ERROR, "Tx Sahara Image Failed");
|
|
return 0;
|
|
}
|
|
|
|
bytes_read += bytes_to_read_next;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int sahara_start(void *usb_handle, void *tx_buffer, void *rx_buffer, FILE *file_handle) {
|
|
uint32_t image_id = 0;
|
|
sahara_packet_header* sahara_cmd = (sahara_packet_header *)rx_buffer;
|
|
sahara_packet_hello *sahara_hello = (sahara_packet_hello *)rx_buffer;
|
|
sahara_packet_read_data *sahara_read_data = (sahara_packet_read_data *)rx_buffer;
|
|
sahara_packet_done_resp *sahara_done_resp = (sahara_packet_done_resp *)rx_buffer;
|
|
sahara_packet_end_image_tx *sahara_end_image_tx = (sahara_packet_end_image_tx *)rx_buffer;
|
|
|
|
sahara_packet_hello_resp *sahara_hello_resp = (sahara_packet_hello_resp *)tx_buffer;
|
|
|
|
dbg(LOG_EVENT, "STATE <-- SAHARA_WAIT_HELLO");
|
|
if (0 == sahara_rx_data(usb_handle, rx_buffer, 0)) {
|
|
#if 0
|
|
unsigned char edl_cmd[] = {0x4b, 0x65, 0x01, 0x00, 0x54, 0x0f, 0x7e};
|
|
sahara_tx_data(usb_handle, edl_cmd, sizeof(edl_cmd));
|
|
#else
|
|
sahara_tx_data(usb_handle, tx_buffer, 1);
|
|
#endif
|
|
if (0 == sahara_rx_data(usb_handle, rx_buffer, 0))
|
|
return 0;
|
|
}
|
|
|
|
//Check if the received command is a hello command
|
|
if (le_uint32(sahara_cmd->command) != SAHARA_HELLO_ID) {
|
|
dbg(LOG_ERROR, "Received a different command: %x while waiting for hello packet", sahara_hello->header.command);
|
|
send_reset_command(usb_handle, rx_buffer);
|
|
return 0;
|
|
}
|
|
|
|
// Recieved hello, send the hello response
|
|
//Create a Hello request
|
|
sahara_hello_resp->header.command = le_uint32(SAHARA_HELLO_RESP_ID);
|
|
sahara_hello_resp->header.length = le_uint32(sizeof(sahara_packet_hello_resp));
|
|
sahara_hello_resp->version = sahara_hello->version; //SAHARA_VERSION;
|
|
sahara_hello_resp->version_supported = sahara_hello->version_supported; //SAHARA_VERSION_SUPPORTED;
|
|
sahara_hello_resp->status = le_uint32(SAHARA_STATUS_SUCCESS);
|
|
sahara_hello_resp->mode = sahara_hello->mode;
|
|
sahara_hello_resp->reserved0 = le_uint32(1);
|
|
sahara_hello_resp->reserved1 = le_uint32(2);
|
|
sahara_hello_resp->reserved2 = le_uint32(3);
|
|
sahara_hello_resp->reserved3 = le_uint32(4);
|
|
sahara_hello_resp->reserved4 = le_uint32(5);
|
|
sahara_hello_resp->reserved5 = le_uint32(6);
|
|
|
|
switch (le_uint32(sahara_hello->mode)) {
|
|
case SAHARA_MODE_IMAGE_TX_PENDING:
|
|
dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_IMAGE_TX_PENDING");
|
|
break;
|
|
case SAHARA_MODE_IMAGE_TX_COMPLETE:
|
|
dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_IMAGE_TX_COMPLETE");
|
|
break;
|
|
case SAHARA_MODE_MEMORY_DEBUG:
|
|
dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_MEMORY_DEBUG");
|
|
break;
|
|
case SAHARA_MODE_COMMAND:
|
|
dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_COMMAND");
|
|
break;
|
|
default:
|
|
dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_0x%x", le_uint32(sahara_hello->mode));
|
|
break;
|
|
}
|
|
|
|
if (le_uint32(sahara_hello->mode) != SAHARA_MODE_IMAGE_TX_PENDING) {
|
|
dbg(LOG_ERROR, "ERROR NOT SAHARA_MODE_IMAGE_TX_PENDING");
|
|
sahara_hello_resp->mode = SAHARA_MODE_IMAGE_TX_PENDING;
|
|
}
|
|
|
|
/*Send the Hello Resonse Request*/
|
|
dbg(LOG_EVENT, "SENDING --> SAHARA_HELLO_RESPONSE");
|
|
if (0 == sahara_tx_data (usb_handle, tx_buffer, sizeof(sahara_packet_hello_resp))) {
|
|
dbg(LOG_ERROR, "Tx Sahara Data Failed ");
|
|
return 0;
|
|
}
|
|
|
|
while (1) {
|
|
dbg(LOG_INFO, "STATE <-- SAHARA_WAIT_COMMAND");
|
|
if (0 == sahara_rx_data(usb_handle, rx_buffer, 0))
|
|
return 0;
|
|
|
|
if (le_uint32(sahara_cmd->command) == SAHARA_READ_DATA_ID) {
|
|
start_image_transfer(usb_handle, tx_buffer, sahara_read_data, file_handle);
|
|
}
|
|
else if (le_uint32(sahara_cmd->command) == SAHARA_END_IMAGE_TX_ID) {
|
|
dbg(LOG_EVENT, "image_id = %d, status = %d", le_uint32(sahara_end_image_tx->image_id), le_uint32(sahara_end_image_tx->status));
|
|
if (le_uint32(sahara_end_image_tx->status) == SAHARA_STATUS_SUCCESS) {
|
|
image_id = le_uint32(sahara_end_image_tx->image_id);
|
|
send_done_packet (usb_handle, tx_buffer);
|
|
break;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
else if (le_uint32(sahara_cmd->command) == SAHARA_HELLO_ID) {
|
|
continue;
|
|
}
|
|
else {
|
|
dbg(LOG_ERROR, "Received an unknown command: %d ", le_uint32(sahara_cmd->command));
|
|
send_reset_command (usb_handle, tx_buffer);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
dbg(LOG_EVENT, "STATE <-- SAHARA_WAIT_DONE_RESP");
|
|
if (0 == sahara_rx_data(usb_handle, rx_buffer, 0))
|
|
return 0;
|
|
|
|
dbg(LOG_INFO, "image_tx_status = %d", le_uint32(sahara_done_resp->image_tx_status));
|
|
|
|
if (SAHARA_MODE_IMAGE_TX_PENDING == le_uint32(sahara_done_resp->image_tx_status)) {
|
|
if (image_id == 13) //prog_nand_firehose_9x07.mbn
|
|
return 1;
|
|
if (image_id == 7) //NPRG9x55.mbn
|
|
return 1;
|
|
if (image_id == 21) //sbl1.mbn, October 22 2020 2:12 PM, AG35CEVAR05A07T4G
|
|
return 1;
|
|
}
|
|
else if (SAHARA_MODE_IMAGE_TX_COMPLETE == le_uint32(sahara_done_resp->image_tx_status)) {
|
|
dbg(LOG_EVENT,"Successfully uploaded all images");
|
|
return 1;
|
|
}
|
|
else {
|
|
dbg(LOG_ERROR, "Received unrecognized status %d at SAHARA_WAIT_DONE_RESP state",
|
|
le_uint32(sahara_done_resp->image_tx_status));
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int sahara_main(const char *firehose_dir, void *usb_handle, int edl_mode_05c69008) {
|
|
int retval = 0;
|
|
char* prog_nand_firehose_filename = NULL;
|
|
char full_path[512];
|
|
FILE *file_handle;
|
|
void *tx_buffer;
|
|
void *rx_buffer;
|
|
|
|
if (edl_mode_05c69008) {
|
|
if(qfile_find_xmlfile(firehose_dir, "prog", &prog_nand_firehose_filename) != 0
|
|
&& qfile_find_xmlfile(firehose_dir, "prog_firehose", &prog_nand_firehose_filename) != 0) {
|
|
dbg(LOG_ERROR, "retrieve prog nand firehose failed.");
|
|
return ENOENT;
|
|
}
|
|
dbg(LOG_INFO, "prog_nand_firehose_filename = %s", prog_nand_firehose_filename);
|
|
|
|
if (!strncmp(prog_nand_firehose_filename, "prog_emmc_firehose_8953_ddr.mbn", strlen(prog_nand_firehose_filename)))
|
|
g_is_sc600y_chip = 1;
|
|
|
|
snprintf(full_path, sizeof(full_path), "%.255s/%.240s", firehose_dir, prog_nand_firehose_filename);
|
|
}
|
|
else {
|
|
snprintf(full_path, sizeof(full_path), "%.255s/..", firehose_dir);
|
|
if(qfile_find_xmlfile(full_path, "NPRG9x", &prog_nand_firehose_filename) != 0
|
|
&& qfile_find_xmlfile(full_path, "NPRG9x", &prog_nand_firehose_filename) != 0) {
|
|
dbg(LOG_ERROR, "retrieve NPRG MBN failed.");
|
|
return ENOENT;
|
|
}
|
|
dbg(LOG_INFO, "prog_nand_firehose_filename = %s", prog_nand_firehose_filename);
|
|
|
|
snprintf(full_path, sizeof(full_path), "%.255s/../%.240s", firehose_dir, prog_nand_firehose_filename);
|
|
}
|
|
|
|
free(prog_nand_firehose_filename);
|
|
file_handle = fopen(full_path, "rb");
|
|
if (file_handle == NULL) {
|
|
dbg(LOG_INFO, "%s %d %s errno: %d (%s)", __func__, __LINE__, full_path, errno, strerror(errno));
|
|
return ENOENT;
|
|
}
|
|
|
|
rx_buffer = malloc (SAHARA_RAW_BUFFER_SIZE);
|
|
tx_buffer = malloc (SAHARA_RAW_BUFFER_SIZE);
|
|
|
|
if (NULL == rx_buffer || NULL == tx_buffer) {
|
|
dbg(LOG_ERROR, "Failed to allocate sahara buffers");
|
|
return ENOMEM;
|
|
}
|
|
|
|
retval = sahara_start(usb_handle, tx_buffer, rx_buffer, file_handle);
|
|
if (0 == retval) {
|
|
dbg(LOG_ERROR, "Sahara protocol error");
|
|
}
|
|
else {
|
|
dbg(LOG_STATUS, "Sahara protocol completed");
|
|
}
|
|
|
|
free(rx_buffer);
|
|
free(tx_buffer);
|
|
fclose(file_handle);
|
|
|
|
if (retval)
|
|
return 0;
|
|
|
|
return __LINE__;
|
|
}
|