1116 lines
38 KiB
C
1116 lines
38 KiB
C
/*
|
|
Copyright 2023 Quectel Wireless Solutions Co.,Ltd
|
|
|
|
Quectel hereby grants customers of Quectel a license to use, modify,
|
|
distribute and publish the Software in binary form provided that
|
|
customers shall have no right to reverse engineer, reverse assemble,
|
|
decompile or reduce to source code form any portion of the Software.
|
|
Under no circumstances may customers modify, demonstrate, use, deliver
|
|
or disclose any portion of the Software in source code form.
|
|
*/
|
|
|
|
#include <getopt.h>
|
|
#include <grp.h>
|
|
#include <sys/types.h>
|
|
#include <pwd.h>
|
|
#ifdef USE_IPC_MSG
|
|
#include <sys/msg.h>
|
|
#include <sys/ipc.h>
|
|
#endif
|
|
|
|
#include "usb_linux.h"
|
|
#include "md5.h"
|
|
|
|
/*
|
|
[PATCH 3.10 27/54] usb: xhci: Add support for URB_ZERO_PACKET to bulk/sg transfers
|
|
https://www.spinics.net/lists/kernel/msg2100618.html
|
|
|
|
commit 4758dcd19a7d9ba9610b38fecb93f65f56f86346
|
|
Author: Reyad Attiyat <reyad.attiyat@gmail.com>
|
|
Date: Thu Aug 6 19:23:58 2015 +0300
|
|
|
|
usb: xhci: Add support for URB_ZERO_PACKET to bulk/sg transfers
|
|
|
|
This commit checks for the URB_ZERO_PACKET flag and creates an extra
|
|
zero-length td if the urb transfer length is a multiple of the endpoint's
|
|
max packet length.
|
|
*/
|
|
unsigned qusb_zlp_mode = 1; // MT7621 donot support USB ZERO PACKET
|
|
unsigned q_erase_all_before_download = 0;
|
|
unsigned q_module_packet_sign = 0;
|
|
unsigned int g_from_ecm_to_rndis = 0;
|
|
const char *q_device_type = "nand"; // nand/emmc/ufs
|
|
int sahara_main(const char *firehose_dir, const char *firehose_mbn, void *usb_handle, int edl_mode_05c69008);
|
|
int firehose_main(const char *firehose_dir, void *usb_handle, unsigned qusb_zlp_mode);
|
|
int stream_download(const char *firehose_dir, void *usb_handle, unsigned qusb_zlp_mode);
|
|
int retrieve_soft_revision(void *usb_handle, uint8_t *mobile_software_revision, unsigned length);
|
|
int usb2tcp_main(const void *usb_handle, int tcp_port, unsigned qusb_zlp_mode);
|
|
int ql_capture_usbmon_log(const char *usbmon_logfile);
|
|
void ql_stop_usbmon_log();
|
|
|
|
// process vals
|
|
static long long all_bytes_to_transfer = 0; // need transfered
|
|
static long long transfer_bytes = 0; // transfered bytes;
|
|
|
|
char zip_cmd_buf[512] = {0}; // zip cmd buf
|
|
char firehose_zip_name[80] = {0};
|
|
char firehose_unzip_full_dir[256] = {0};
|
|
file_name_backup file_name_b;
|
|
int is_upgrade_fimeware_zip_7z = 0;
|
|
int is_firehose_zip_7z_name_exit = 0;
|
|
int is_upgrade_fimeware_only_zip = 0;
|
|
int g_is_module_adb_entry_edl = 0;
|
|
|
|
int g_is2mdn_path = 0;
|
|
|
|
int switch_to_edl_mode(void *usb_handle)
|
|
{
|
|
// DIAG commands used to switch the Qualcomm devices to EDL (Emergency download mode)
|
|
unsigned char edl_cmd[] = {0x4b, 0x65, 0x01, 0x00, 0x54, 0x0f, 0x7e};
|
|
// unsigned char edl_cmd[] = {0x3a, 0xa1, 0x6e, 0x7e}; //DL (download mode)
|
|
unsigned char *pbuf = malloc(512);
|
|
if (pbuf == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int rx_len;
|
|
int rx_count = 0;
|
|
|
|
do
|
|
{
|
|
rx_len = qusb_noblock_read(usb_handle, pbuf, 512, 0, 1000);
|
|
if (rx_count++ > 100) break;
|
|
} while (rx_len > 0);
|
|
|
|
dbg_time("switch to 'Emergency download mode'\n");
|
|
rx_len = qusb_noblock_write(usb_handle, edl_cmd, sizeof(edl_cmd), sizeof(edl_cmd), 3000, 0);
|
|
if (rx_len < 0) return 0;
|
|
|
|
rx_count = 0;
|
|
|
|
do
|
|
{
|
|
rx_len = qusb_noblock_read(usb_handle, pbuf, 512, 0, 3000);
|
|
if (rx_len == sizeof(edl_cmd) && memcmp(pbuf, edl_cmd, sizeof(edl_cmd)) == 0)
|
|
{
|
|
dbg_time("successful, wait module reboot\n");
|
|
safe_free(pbuf);
|
|
return 1;
|
|
}
|
|
|
|
if (rx_count++ > 50) break;
|
|
|
|
} while (rx_len > 0);
|
|
|
|
safe_free(pbuf);
|
|
return 0;
|
|
}
|
|
|
|
int switch_to_edl_mode_in_adb_way()
|
|
{
|
|
printf("entry switch_to_edl_mode_in_adb_way \r\n");
|
|
int res = -1;
|
|
res = system("adb shell lxc-power1 adb host");
|
|
// if (res == 127)
|
|
// {
|
|
// printf("call /bin/sh return error \r\n");
|
|
// return res;
|
|
// }
|
|
// else if (res == -1)
|
|
// {
|
|
// printf("just return: error \r\n");
|
|
// return res;
|
|
// }
|
|
// else if (res == 0)
|
|
// {
|
|
// printf("no child pid create: error \r\n");
|
|
// return res;
|
|
// }
|
|
|
|
printf("send lxc power1 success res=[%d] \r\n", res);
|
|
sleep(20);
|
|
res = system("adb reboot edl");
|
|
// if (res == 127)
|
|
// {
|
|
// printf("call /bin/sh return error \r\n");
|
|
// return res;
|
|
// }
|
|
// else if (res == -1)
|
|
// {
|
|
// printf("just return: error \r\n");
|
|
// return res;
|
|
// }
|
|
// else if (res == 0)
|
|
// {
|
|
// printf("no child pid create: error \r\n");
|
|
// return res;
|
|
// }
|
|
|
|
printf("send reboot edl success res=[%d] \r\n", res);
|
|
return 0;
|
|
}
|
|
|
|
static void usage(int status, const char *program_name)
|
|
{
|
|
if (status != EXIT_SUCCESS)
|
|
{
|
|
printf("Try '%s --help' for more information.\n", program_name);
|
|
}
|
|
else
|
|
{
|
|
dbg_time("Upgrade Quectel's modules with Qualcomm's firehose protocol.\n");
|
|
dbg_time("Usage: %s [options...]\n", program_name);
|
|
dbg_time(" -f [package_dir] Upgrade package directory path\n");
|
|
dbg_time(" -p [/dev/ttyUSBx] Diagnose port, will auto-detect if not "
|
|
"specified\n");
|
|
dbg_time(" -s [/sys/bus/usb/devices/xx] When multiple modules exist on the board, use "
|
|
"-s specify which module you want to upgrade\n");
|
|
dbg_time(" -l [dir_name] Sync log into a file(will create "
|
|
"qfirehose_timestamp.log)\n");
|
|
dbg_time(" -u [usbmon_log] Catch usbmon log and save to file (need "
|
|
"debugfs and usbmon driver)\n");
|
|
dbg_time(" -n Skip MD5 check\n");
|
|
dbg_time(" -d Device Type, default nand, support emmc/ufs\n");
|
|
dbg_time(" -v For AG215S-GLR signed firmware packages\n");
|
|
}
|
|
exit(status);
|
|
}
|
|
|
|
/*
|
|
1. enum dir, fix up dirhose_dir
|
|
2. md5 examine
|
|
3. furture
|
|
*/
|
|
static char *find_firehose_mbn(char **firehose_dir, size_t size)
|
|
{
|
|
char *firehose_mbn = NULL;
|
|
|
|
if (is_upgrade_fimeware_zip_7z)
|
|
{
|
|
int i;
|
|
char file_name_prog[128] = {0};
|
|
char file_name_prog_dir[256] = {0};
|
|
|
|
firehose_mbn = (char *)malloc(256);
|
|
if (firehose_mbn == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < file_name_b.file_name_count; i++)
|
|
{
|
|
if ((strstr(file_name_b.file_backup_c[i].zip_file_name_backup, "prog_nand_firehose_") && strstr(file_name_b.file_backup_c[i].zip_file_name_backup, ".mbn")) ||
|
|
(strstr(file_name_b.file_backup_c[i].zip_file_name_backup, "prog_emmc_firehose_") && strstr(file_name_b.file_backup_c[i].zip_file_name_backup, ".mbn")) ||
|
|
(strstr(file_name_b.file_backup_c[i].zip_file_name_backup, "prog_firehose_") && strstr(file_name_b.file_backup_c[i].zip_file_name_backup, ".mbn")) ||
|
|
(strstr(file_name_b.file_backup_c[i].zip_file_name_backup, "prog_firehose_") && strstr(file_name_b.file_backup_c[i].zip_file_name_backup, ".elf")) ||
|
|
(strstr(file_name_b.file_backup_c[i].zip_file_name_backup, "firehose-prog") && strstr(file_name_b.file_backup_c[i].zip_file_name_backup, ".mbn")) ||
|
|
(strstr(file_name_b.file_backup_c[i].zip_file_name_backup, "prog_") && strstr(file_name_b.file_backup_c[i].zip_file_name_backup, ".mbn")) ||
|
|
(strstr(file_name_b.file_backup_c[i].zip_file_name_backup, "xbl_s_devprg_Qcm8550_ns") && strstr(file_name_b.file_backup_c[i].zip_file_name_backup, ".melf")) ||
|
|
(strstr(file_name_b.file_backup_c[i].zip_file_name_backup, "xbl_s_devprg_ns_SA52X") && strstr(file_name_b.file_backup_c[i].zip_file_name_backup, ".melf")))
|
|
{
|
|
printf("file_name_b.file_backup_c[i].zip_file_name_backup:%s\n", file_name_b.file_backup_c[i].zip_file_name_backup);
|
|
printf("file_name_b.file_backup_c[i].zip_file_dir_backup:%s\n", file_name_b.file_backup_c[i].zip_file_dir_backup);
|
|
|
|
if (strstr(file_name_b.file_backup_c[i].zip_file_dir_backup, "update/firehose"))
|
|
{
|
|
memmove(file_name_prog, file_name_b.file_backup_c[i].zip_file_name_backup, strlen(file_name_b.file_backup_c[i].zip_file_name_backup));
|
|
memmove(file_name_prog_dir, file_name_b.file_backup_c[i].zip_file_dir_backup, strlen(file_name_b.file_backup_c[i].zip_file_dir_backup));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (file_name_prog[0] != '\0')
|
|
{
|
|
memset(zip_cmd_buf, 0, sizeof(zip_cmd_buf));
|
|
if (is_upgrade_fimeware_only_zip)
|
|
{
|
|
snprintf(zip_cmd_buf, sizeof(zip_cmd_buf), "unzip -o -q %.240s '*%.200s' -d /tmp/ > %s", *firehose_dir, file_name_prog_dir, ZIP_PROCESS_INFO);
|
|
}
|
|
else
|
|
{
|
|
snprintf(zip_cmd_buf, sizeof(zip_cmd_buf), "7z x %.240s -o/tmp/ %.200s > %s", *firehose_dir, file_name_prog_dir, ZIP_PROCESS_INFO);
|
|
}
|
|
printf("%s zip_cmd_buf:%s\n", __func__, zip_cmd_buf);
|
|
if (-1 == system(zip_cmd_buf))
|
|
{
|
|
printf("%s system return error\n", __func__);
|
|
return NULL;
|
|
}
|
|
usleep(1000);
|
|
|
|
memmove(firehose_mbn, file_name_prog_dir, 240);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strstr(*firehose_dir, "/update/firehose") == NULL)
|
|
{
|
|
size_t len = strlen(*firehose_dir);
|
|
|
|
strncat(*firehose_dir, "/update/firehose", size);
|
|
if (access(*firehose_dir, R_OK))
|
|
{
|
|
(*firehose_dir)[len] = '\0'; // for smart module
|
|
}
|
|
}
|
|
|
|
if (access(*firehose_dir, R_OK))
|
|
{
|
|
dbg_time("%s access(%s fail), errno: %d (%s)\n", __func__, *firehose_dir, errno, strerror(errno));
|
|
return NULL;
|
|
}
|
|
|
|
if (!qfile_find_file(*firehose_dir, "prog_nand_firehose_", ".mbn", &firehose_mbn) && !qfile_find_file(*firehose_dir, "prog_emmc_firehose_", ".mbn", &firehose_mbn) &&
|
|
!qfile_find_file(*firehose_dir, "prog_firehose_", ".mbn", &firehose_mbn) && !qfile_find_file(*firehose_dir, "prog_firehose_", ".elf", &firehose_mbn) &&
|
|
!qfile_find_file(*firehose_dir, "firehose-prog", ".mbn", &firehose_mbn) && !qfile_find_file(*firehose_dir, "prog_", ".mbn", &firehose_mbn) &&
|
|
!qfile_find_file(*firehose_dir, "xbl_s_devprg_Qcm8550_ns", ".melf",
|
|
&firehose_mbn) // smart SA885GAPNA
|
|
&& !qfile_find_file(*firehose_dir, "xbl_s_devprg_ns_SA52X", ".melf",
|
|
&firehose_mbn) // AG590ECNABR01A01M8G_OCPU_01.001.01
|
|
)
|
|
{
|
|
dbg_time("%s fail to find firehose mbn file in %s\n", __func__, *firehose_dir);
|
|
safe_free(firehose_mbn);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
dbg_time("%s %s\n", __func__, firehose_mbn);
|
|
return firehose_mbn;
|
|
}
|
|
|
|
#if 0
|
|
static int detect_and_judge_module_version(void *usb_handle) {
|
|
static uint8_t version[64] = {'\0'};
|
|
|
|
if (usb_handle && version[0] == '\0') {
|
|
retrieve_soft_revision(usb_handle, version, sizeof(version));
|
|
if (version[0]) {
|
|
size_t i = 0;
|
|
size_t length = strlen((const char *)version) - strlen("R00A00");
|
|
dbg_time("old software version: %s\n", version);
|
|
for (i = 0; i < length; i++) {
|
|
if (version[i] == 'R' && isdigit(version[i+1]) && isdigit(version[i+2])
|
|
&& version[i+3] == 'A' && isdigit(version[i+4]) && isdigit(version[i+5]))
|
|
{
|
|
version[i] = '\0';
|
|
//dbg_time("old hardware version: %s\n", mobile_software_revision);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (version[0])
|
|
return 0;
|
|
|
|
error_return();
|
|
}
|
|
#endif
|
|
|
|
FILE *loghandler = NULL;
|
|
#ifdef FIREHOSE_ENABLE
|
|
int firehose_main_entry(int argc, char *argv[])
|
|
#else
|
|
int main(int argc, char *argv[])
|
|
#endif
|
|
{
|
|
int opt;
|
|
int check_hash = 1;
|
|
int retval;
|
|
void *usb_handle = NULL;
|
|
int idVendor = 0, idProduct = 0, interfaceNum = 0;
|
|
int edl_retry = 30; // SDX55 require long time by now 20190412
|
|
double start;
|
|
|
|
// char *firehose_mbn = NULL;
|
|
int usb3_speed;
|
|
struct timespec usb3_atime;
|
|
int usb2tcp_port = 0;
|
|
char filename[128] = {'\0'};
|
|
char *usbmon_logfile = NULL;
|
|
|
|
char *file_message = malloc(MAX_PATH);
|
|
if (file_message == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
char *firehose_mbn = malloc(MAX_PATH);
|
|
if (firehose_mbn == NULL)
|
|
{
|
|
safe_free(file_message);
|
|
return -1;
|
|
}
|
|
|
|
char *firehose_dir = malloc(MAX_PATH);
|
|
if (firehose_dir == NULL)
|
|
{
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
return -1;
|
|
}
|
|
|
|
char *module_port_name = malloc(MAX_PATH);
|
|
if (module_port_name == NULL)
|
|
{
|
|
safe_free(file_message);
|
|
safe_free(firehose_dir);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
return -1;
|
|
}
|
|
|
|
char *module_sys_path = malloc(MAX_PATH);
|
|
if (module_sys_path == NULL)
|
|
{
|
|
safe_free(file_message);
|
|
safe_free(module_port_name);
|
|
safe_free(firehose_dir);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
return -1;
|
|
}
|
|
|
|
memset(firehose_dir, 0, MAX_PATH);
|
|
memset(module_port_name, 0, MAX_PATH);
|
|
memset(module_sys_path, 0, MAX_PATH);
|
|
|
|
// firehose_dir[0] = module_port_name[0] = module_sys_path[0] = '\0';
|
|
|
|
/* set file priviledge mask 0 */
|
|
umask(0);
|
|
/*build V1.0.8*/
|
|
dbg_time("Version: QFirehose_Linux_Android_V1.4.21\n"); // when release,
|
|
// rename to V1.X
|
|
#ifndef __clang__
|
|
dbg_time("Builded: %s %s\n", __DATE__, __TIME__);
|
|
#endif
|
|
|
|
#ifdef ANDROID
|
|
struct passwd *pd;
|
|
pd = getpwuid(getuid());
|
|
dbg_time("------------------\n");
|
|
dbg_time("User:\t %s\n", pd->pw_name);
|
|
struct group *group;
|
|
group = getgrgid(pd->pw_gid);
|
|
dbg_time("Group:\t %s\n", group->gr_name);
|
|
dbg_time("------------------\n");
|
|
#if 0 // not all customers need this function
|
|
loghandler = fopen("/data/upgrade.log", "w+");
|
|
#endif
|
|
if (loghandler) dbg_time("upgrade log will be sync to /data/upgrade.log\n");
|
|
#endif
|
|
|
|
optind = 1;
|
|
while (-1 != (opt = getopt(argc, argv, "f:p:z:s:l:u:d:nevhr")))
|
|
{
|
|
switch (opt)
|
|
{
|
|
case 'n': check_hash = 0; break;
|
|
case 'l':
|
|
if (loghandler) fclose(loghandler);
|
|
snprintf(filename, sizeof(filename), "%.80s/qfirehose_%lu.log", optarg, time(NULL));
|
|
loghandler = fopen(filename, "w+");
|
|
if (loghandler) dbg_time("upgrade log will be sync to %s\n", filename);
|
|
break;
|
|
case 'f': {
|
|
strncpy(file_message, optarg, MAX_PATH - 1);
|
|
if (strstr(file_message, ".mbn") != NULL || strstr(file_message, ".elf") != NULL)
|
|
{
|
|
g_is2mdn_path = 1;
|
|
char *tmp = strrchr(file_message, '/');
|
|
strncpy(firehose_mbn, tmp + 1, strlen(tmp) - 1);
|
|
strncpy(firehose_dir, file_message, strlen(file_message) - strlen(tmp));
|
|
dbg_time("f pargram: "
|
|
"g_is2mdn_path=[%d],file_message=[%s],firehose_mbn=[%s],"
|
|
"firehose_dir=[%s]\n",
|
|
g_is2mdn_path, file_message, firehose_mbn, firehose_dir);
|
|
break;
|
|
}
|
|
strncpy(firehose_dir, file_message, strlen(file_message));
|
|
break;
|
|
}
|
|
case 'p':
|
|
strncpy(module_port_name, optarg, MAX_PATH - 1);
|
|
if (!strcmp(module_port_name, "9008"))
|
|
{
|
|
usb2tcp_port = atoi(module_port_name);
|
|
module_port_name[0] = '\0';
|
|
}
|
|
break;
|
|
case 's':
|
|
strncpy(module_sys_path, optarg, MAX_PATH - 1);
|
|
int len = strlen(optarg);
|
|
if (len > 256)
|
|
{
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(usbmon_logfile);
|
|
safe_free(firehose_dir);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
printf("optarg length is longer than 256\n");
|
|
return -1;
|
|
}
|
|
|
|
if (module_sys_path[strlen(optarg) - 1] == '/') module_sys_path[strlen(optarg) - 1] = '\0';
|
|
break;
|
|
case 'z': qusb_zlp_mode = !!atoi(optarg); break;
|
|
case 'e': q_erase_all_before_download = 1; break;
|
|
case 'u':
|
|
usbmon_logfile = strdup(optarg);
|
|
if (usbmon_logfile == NULL)
|
|
{
|
|
printf("usbmon_logfile is NULL\n");
|
|
return -1;
|
|
}
|
|
break;
|
|
case 'd':
|
|
q_device_type = strdup(optarg);
|
|
if (q_device_type == NULL)
|
|
{
|
|
printf("q_device_type is NULL\n");
|
|
return -1;
|
|
}
|
|
break;
|
|
case 'v': q_module_packet_sign = 1; break;
|
|
case 'r':
|
|
g_from_ecm_to_rndis = 1;
|
|
printf("will use rndis mode [%d]\r\n", g_from_ecm_to_rndis);
|
|
break;
|
|
case 'h': usage(EXIT_SUCCESS, argv[0]); break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
if (usbmon_logfile) ql_capture_usbmon_log(usbmon_logfile);
|
|
|
|
update_transfer_bytes(0);
|
|
if (usb2tcp_port) goto _usb2tcp_start;
|
|
|
|
if (firehose_dir[0] == '\0')
|
|
{
|
|
usage(EXIT_SUCCESS, argv[0]);
|
|
update_transfer_bytes(-1);
|
|
error_return();
|
|
}
|
|
|
|
if (access(firehose_dir, R_OK))
|
|
{
|
|
dbg_time("fail to access %s, errno: %d (%s)\n", firehose_dir, errno, strerror(errno));
|
|
update_transfer_bytes(-1);
|
|
safe_free(firehose_dir);
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(usbmon_logfile);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
error_return();
|
|
}
|
|
|
|
opt = strlen(firehose_dir);
|
|
if (firehose_dir[opt - 1] == '/')
|
|
{
|
|
firehose_dir[opt - 1] = '\0';
|
|
}
|
|
|
|
char buff[256] = {0};
|
|
int file_name_count = 0;
|
|
|
|
if (strstr(firehose_dir, ".zip") || strstr(firehose_dir, ".7z"))
|
|
{
|
|
if (strstr(firehose_dir, ".zip"))
|
|
{
|
|
is_upgrade_fimeware_only_zip = 1;
|
|
}
|
|
|
|
unlink(ZIP_INFO);
|
|
memset(zip_cmd_buf, 0, sizeof(zip_cmd_buf));
|
|
if (is_upgrade_fimeware_only_zip)
|
|
{
|
|
snprintf(zip_cmd_buf, sizeof(zip_cmd_buf), "unzip -l -q %.240s > %s", firehose_dir, ZIP_INFO);
|
|
}
|
|
else
|
|
{
|
|
snprintf(zip_cmd_buf, sizeof(zip_cmd_buf), "7z l %.240s > %s", firehose_dir, ZIP_INFO);
|
|
}
|
|
if (-1 == system(zip_cmd_buf))
|
|
{
|
|
dbg_time("%s system return error\n", __func__);
|
|
return -1;
|
|
}
|
|
usleep(1000);
|
|
|
|
char *p = strrchr(firehose_dir, '/'); // firehose_dir is the absolute path of the zip/7z
|
|
// file
|
|
if (p)
|
|
{
|
|
if (strstr(firehose_dir, ".zip"))
|
|
{
|
|
strncpy(firehose_zip_name, p + 1, strlen(p) - 4 - 1); // 4(.zip); 1(/)
|
|
}
|
|
else
|
|
{
|
|
strncpy(firehose_zip_name, p + 1, strlen(p) - 3 - 1); // 3(.7z); 1(/)
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strstr(firehose_dir, ".zip"))
|
|
{
|
|
strncpy(firehose_zip_name, firehose_dir,
|
|
strlen(firehose_dir) - 4); // QFirehose -f RG520NEUDCR01A01M4G_01.001.01.001.zip
|
|
}
|
|
else
|
|
{
|
|
strncpy(firehose_zip_name, firehose_dir,
|
|
strlen(firehose_dir) - 3); // QFirehose -f RG520NEUDCR01A01M4G_01.001.01.001.7z
|
|
}
|
|
}
|
|
|
|
dbg_time("firehose_zip_name:%s\n", firehose_zip_name); // RG520NEUDCR01A01M4G_01.001.01.001
|
|
is_upgrade_fimeware_zip_7z = 1; // Judging as a zip/7z package upgrade
|
|
|
|
if (!access(ZIP_INFO, F_OK))
|
|
{
|
|
char *p0 = NULL;
|
|
char *p01 = NULL;
|
|
char *p1 = NULL;
|
|
char *p2 = NULL;
|
|
char *p3 = NULL;
|
|
char *p4 = NULL;
|
|
FILE *fp = fopen(ZIP_INFO, "rb");
|
|
if (fp == NULL)
|
|
{
|
|
dbg_time("fail to fopen(%s), error: %d (%s)\n", ZIP_INFO, errno, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
while (fgets(buff, sizeof(buff), fp))
|
|
{
|
|
p0 = strstr(buff, firehose_zip_name);
|
|
if (p0)
|
|
{
|
|
int length_debug1 = strlen(p0);
|
|
if (p0[length_debug1 - 1] == 0x0a) length_debug1 -= 1;
|
|
|
|
memmove(file_name_b.file_backup_c[file_name_count].zip_file_dir_backup, p0, length_debug1);
|
|
|
|
p01 = strrchr(p0, '/');
|
|
if (p01 == NULL) continue;
|
|
|
|
if (p01[0] == '/' && p01[1] == '\0')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
is_firehose_zip_7z_name_exit = 1; // Determine which type of package it is and whether it should be placed
|
|
// in one folder or several files or folders after decompression
|
|
|
|
int length_debug = strlen(p01);
|
|
if (p01[length_debug - 1] == 0x0a) length_debug -= 1;
|
|
|
|
memmove(file_name_b.file_backup_c[file_name_count].zip_file_name_backup, p01 + 1, length_debug - 1);
|
|
|
|
file_name_count++;
|
|
file_name_b.file_name_count = file_name_count;
|
|
}
|
|
else
|
|
{
|
|
p1 = strstr(buff, "contents.xml");
|
|
p2 = strstr(buff, "md5.txt");
|
|
p3 = strstr(buff, "update");
|
|
|
|
if (p1)
|
|
{
|
|
int length_debug1 = strlen(p1);
|
|
if (p1[length_debug1 - 1] == 0x0a) length_debug1 -= 1;
|
|
|
|
memmove(file_name_b.file_backup_c[file_name_count].zip_file_dir_backup, p1, length_debug1);
|
|
|
|
int length_debug = strlen(p1);
|
|
if (p1[length_debug - 1] == 0x0a) length_debug -= 1;
|
|
|
|
memmove(file_name_b.file_backup_c[file_name_count].zip_file_name_backup, p1 + 1, length_debug - 1);
|
|
|
|
file_name_count++;
|
|
file_name_b.file_name_count = file_name_count;
|
|
}
|
|
else if (p2)
|
|
{
|
|
int length_debug1 = strlen(p2);
|
|
if (p2[length_debug1 - 1] == 0x0a) length_debug1 -= 1;
|
|
|
|
memmove(file_name_b.file_backup_c[file_name_count].zip_file_dir_backup, p2, length_debug1);
|
|
|
|
int length_debug = strlen(p2);
|
|
if (p2[length_debug - 1] == 0x0a) length_debug -= 1;
|
|
|
|
memmove(file_name_b.file_backup_c[file_name_count].zip_file_name_backup, p2 + 1, length_debug - 1);
|
|
|
|
file_name_count++;
|
|
file_name_b.file_name_count = file_name_count;
|
|
}
|
|
else if (p3)
|
|
{
|
|
int length_debug1 = strlen(p3);
|
|
if (p3[length_debug1 - 1] == 0x0a) length_debug1 -= 1;
|
|
|
|
memmove(file_name_b.file_backup_c[file_name_count].zip_file_dir_backup, p3, length_debug1);
|
|
|
|
p4 = strrchr(p3, '/');
|
|
if (p4 == NULL) continue;
|
|
|
|
if (p4[0] == '/' && p4[1] == '\0')
|
|
{
|
|
dbg_time("continue..\n");
|
|
continue;
|
|
}
|
|
|
|
int length_debug = strlen(p4);
|
|
if (p4[length_debug - 1] == 0x0a) length_debug -= 1;
|
|
|
|
memmove(file_name_b.file_backup_c[file_name_count].zip_file_name_backup, p4 + 1, length_debug - 1);
|
|
|
|
file_name_count++;
|
|
file_name_b.file_name_count = file_name_count;
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
unlink(ZIP_INFO);
|
|
|
|
if (!is_firehose_zip_7z_name_exit)
|
|
{
|
|
memset(firehose_zip_name, 0, sizeof(firehose_zip_name));
|
|
}
|
|
|
|
if (firehose_zip_name[0] == '\0')
|
|
{
|
|
strcpy(firehose_unzip_full_dir, "/tmp");
|
|
}
|
|
else
|
|
{
|
|
snprintf(firehose_unzip_full_dir, sizeof(firehose_unzip_full_dir), "/tmp/%.76s", firehose_zip_name);
|
|
}
|
|
|
|
dbg_time("%s firehose_unzip_full_dir:%s\n", __func__, firehose_unzip_full_dir);
|
|
}
|
|
}
|
|
|
|
if (check_hash && md5_check(firehose_dir))
|
|
{
|
|
update_transfer_bytes(-1);
|
|
safe_free(firehose_dir);
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(usbmon_logfile);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
error_return();
|
|
}
|
|
|
|
if (!g_is2mdn_path) firehose_mbn = find_firehose_mbn(&firehose_dir, MAX_PATH);
|
|
dbg_time("%s %s\n", __func__, firehose_mbn);
|
|
if (!firehose_mbn)
|
|
{
|
|
update_transfer_bytes(-1);
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(usbmon_logfile);
|
|
safe_free(firehose_dir);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
error_return();
|
|
}
|
|
|
|
if (module_port_name[0] && !strncmp(module_port_name, "/dev/mhi", strlen("/dev/mhi")))
|
|
{
|
|
if (qpcie_open(firehose_dir, firehose_mbn, module_port_name))
|
|
{
|
|
update_transfer_bytes(-1);
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(usbmon_logfile);
|
|
safe_free(firehose_dir);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
error_return();
|
|
}
|
|
|
|
usb_handle = &edl_pcie_mhifd;
|
|
start = get_now();
|
|
goto __firehose_main;
|
|
}
|
|
else if (module_port_name[0] && strstr(module_port_name, ":9008"))
|
|
{
|
|
strcpy(module_sys_path, module_port_name);
|
|
goto __edl_retry;
|
|
}
|
|
|
|
_usb2tcp_start:
|
|
if (module_sys_path[0] && access(module_sys_path, R_OK))
|
|
{
|
|
dbg_time("fail to access %s, errno: %d (%s)\n", module_sys_path, errno, strerror(errno));
|
|
update_transfer_bytes(-1);
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(usbmon_logfile);
|
|
safe_free(firehose_dir);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
error_return();
|
|
}
|
|
|
|
if (module_port_name[0] && access(module_port_name, R_OK | W_OK))
|
|
{
|
|
dbg_time("fail to access %s, errno: %d (%s)\n", module_port_name, errno, strerror(errno));
|
|
update_transfer_bytes(-1);
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(usbmon_logfile);
|
|
safe_free(firehose_dir);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
error_return();
|
|
}
|
|
|
|
if (module_sys_path[0] == '\0' && module_port_name[0] != '\0')
|
|
{
|
|
// get sys path by port name
|
|
quectel_get_syspath_name_by_ttyport(module_port_name, module_sys_path, MAX_PATH);
|
|
}
|
|
|
|
g_is_module_adb_entry_edl = 0;
|
|
|
|
if (module_sys_path[0] == '\0')
|
|
{
|
|
int module_count = auto_find_quectel_modules(module_sys_path, MAX_PATH, NULL, NULL);
|
|
if (module_count <= 0)
|
|
{
|
|
dbg_time("Quectel module not found\n");
|
|
update_transfer_bytes(-1);
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(usbmon_logfile);
|
|
safe_free(firehose_dir);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
error_return();
|
|
}
|
|
else if (module_count == 1)
|
|
{
|
|
if (g_is_module_adb_entry_edl > 0)
|
|
{
|
|
switch_to_edl_mode_in_adb_way();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dbg_time("There are multiple quectel modules in system, Please use <-s "
|
|
"/sys/bus/usb/devices/xx> specify which module you want to "
|
|
"upgrade!\n");
|
|
dbg_time("The module's </sys/bus/usb/devices/xx> path was printed in the "
|
|
"previous log!\n");
|
|
update_transfer_bytes(-1);
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(usbmon_logfile);
|
|
safe_free(firehose_dir);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
error_return();
|
|
}
|
|
}
|
|
|
|
__edl_retry:
|
|
qusb_read_speed_atime(module_sys_path, &usb3_atime, &usb3_speed);
|
|
while (edl_retry-- > 0)
|
|
{
|
|
usb_handle = qusb_noblock_open(module_sys_path, &idVendor, &idProduct, &interfaceNum);
|
|
|
|
if (usb_handle)
|
|
{
|
|
clock_gettime(CLOCK_REALTIME, &usb3_atime);
|
|
}
|
|
else
|
|
{
|
|
sleep(1); // in reset sate, wait connect
|
|
if (usb3_speed >= 5000 && access(module_sys_path, R_OK) && errno_nodev())
|
|
{
|
|
if (auto_find_quectel_modules(module_sys_path, MAX_PATH, "5c6/9008/", &usb3_atime) > 1)
|
|
{
|
|
dbg_time("There are multiple quectel EDL modules in system!\n");
|
|
update_transfer_bytes(-1);
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(usbmon_logfile);
|
|
safe_free(firehose_dir);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
error_return();
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
#if 0
|
|
if (idVendor == 0x2c7c && interfaceNum > 1) {
|
|
if (detect_and_judge_module_version(usb_handle)) {
|
|
// update_transfer_bytes(-1);
|
|
/* do not return here, this command will fail when modem is not ready */
|
|
// error_return();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (interfaceNum == 1)
|
|
{
|
|
if ((idVendor == 0x2C7C) && (idProduct == 0x0800))
|
|
{
|
|
// although 5G module stay in dump mode, after send edl command, it also
|
|
// can enter edl mode
|
|
dbg_time("5G module stay in dump mode!\n");
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
dbg_time("something went wrong???, why only one interface left\n");
|
|
}
|
|
|
|
switch_to_edl_mode(usb_handle);
|
|
qusb_noblock_close(usb_handle);
|
|
usb_handle = NULL;
|
|
sleep(1); // wait usb disconnect and re-connect
|
|
}
|
|
|
|
if (usb_handle == NULL)
|
|
{
|
|
update_transfer_bytes(-1);
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(usbmon_logfile);
|
|
safe_free(firehose_dir);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
error_return();
|
|
}
|
|
|
|
if (usb2tcp_port)
|
|
{
|
|
retval = usb2tcp_main(usb_handle, usb2tcp_port, qusb_zlp_mode);
|
|
qusb_noblock_close(usb_handle);
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(usbmon_logfile);
|
|
safe_free(firehose_dir);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
return retval;
|
|
}
|
|
|
|
start = get_now();
|
|
retval = sahara_main(firehose_dir, firehose_mbn, usb_handle, idVendor == 0x05c6);
|
|
|
|
if (!retval)
|
|
{
|
|
if (idVendor != 0x05C6)
|
|
{
|
|
sleep(1);
|
|
stream_download(firehose_dir, usb_handle, qusb_zlp_mode);
|
|
qusb_noblock_close(usb_handle);
|
|
sleep(10); // EM05-G switching to download mode is slow and increases the waiting time
|
|
// to 10 seconds
|
|
goto __edl_retry;
|
|
}
|
|
|
|
__firehose_main:
|
|
retval = firehose_main(firehose_dir, usb_handle, qusb_zlp_mode);
|
|
if (retval == 0)
|
|
{
|
|
get_duration(start);
|
|
}
|
|
}
|
|
|
|
qusb_noblock_close(usb_handle);
|
|
|
|
safe_free(firehose_dir);
|
|
safe_free(module_port_name);
|
|
safe_free(module_sys_path);
|
|
safe_free(file_message);
|
|
safe_free(firehose_mbn);
|
|
|
|
dbg_time("Upgrade module %s.\n", retval == 0 ? "successfully" : "failed");
|
|
if (loghandler) fclose(loghandler);
|
|
if (retval) update_transfer_bytes(-1);
|
|
if (usbmon_logfile) ql_stop_usbmon_log();
|
|
unlink(ZIP_PROCESS_INFO);
|
|
|
|
return retval;
|
|
}
|
|
|
|
double get_now()
|
|
{
|
|
struct timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
|
|
}
|
|
|
|
void get_duration(double start) { dbg_time("THE TOTAL DOWNLOAD TIME IS %.3f s\n", (get_now() - start)); }
|
|
|
|
void set_transfer_allbytes(long long bytes)
|
|
{
|
|
transfer_bytes = 0;
|
|
all_bytes_to_transfer = bytes;
|
|
}
|
|
|
|
int update_progress_msg(int percent);
|
|
int update_progress_file(int percent);
|
|
/*
|
|
return percent
|
|
*/
|
|
int update_transfer_bytes(long long bytes_cur)
|
|
{
|
|
static int last_percent = -1;
|
|
int percent = 0;
|
|
|
|
if (bytes_cur == -1 || bytes_cur == 0)
|
|
{
|
|
percent = bytes_cur;
|
|
}
|
|
else
|
|
{
|
|
transfer_bytes += bytes_cur;
|
|
percent = (transfer_bytes * 100) / all_bytes_to_transfer;
|
|
}
|
|
|
|
if (percent != last_percent)
|
|
{
|
|
last_percent = percent;
|
|
#ifdef USE_IPC_FILE
|
|
update_progress_file(percent);
|
|
#endif
|
|
#ifdef USE_IPC_MSG
|
|
update_progress_msg(percent);
|
|
#endif
|
|
}
|
|
|
|
return percent;
|
|
}
|
|
|
|
void show_progress()
|
|
{
|
|
static int percent = 0;
|
|
|
|
if (all_bytes_to_transfer) percent = (transfer_bytes * 100) / all_bytes_to_transfer;
|
|
dbg_time("upgrade progress %d%% %lld/%lld\n", percent, transfer_bytes, all_bytes_to_transfer);
|
|
}
|
|
|
|
#ifdef USE_IPC_FILE
|
|
#define IPC_FILE_ANDROID "/data/update.conf"
|
|
#define IPC_FILE_LINUX "/tmp/update.conf"
|
|
int update_progress_file(int percent)
|
|
{
|
|
static int ipcfd = -1;
|
|
char buff[16];
|
|
|
|
if (ipcfd < 0)
|
|
{
|
|
#ifdef ANDROID
|
|
const char *ipc_file = IPC_FILE_ANDROID;
|
|
#else
|
|
const char *ipc_file = IPC_FILE_LINUX;
|
|
#endif
|
|
/* Have set umask previous, no need to call fchmod */
|
|
ipcfd = open(ipc_file, O_TRUNC | O_CREAT | O_WRONLY | O_NONBLOCK, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
|
if (ipcfd < 0)
|
|
{
|
|
dbg_time("Fail to open(O_WRONLY) %s: %s\n", ipc_file, strerror(errno));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
lseek(ipcfd, 0, SEEK_SET);
|
|
snprintf(buff, sizeof(buff), "%d", percent);
|
|
if (write(ipcfd, buff, strlen(buff)) < 0) dbg_time("fail to write upgrade progress into %s: %s\n", ipc_file, strerror(errno));
|
|
|
|
if (percent == 100 || percent < 0) close(ipcfd);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_IPC_MSG
|
|
#define MSGBUFFSZ 16
|
|
struct message
|
|
{
|
|
long mtype;
|
|
char mtext[MSGBUFFSZ];
|
|
};
|
|
|
|
#define MSG_FILE "/etc/passwd"
|
|
#define MSG_TYPE_IPC 1
|
|
static int msg_get()
|
|
{
|
|
key_t key = ftok(MSG_FILE, 'a');
|
|
int msgid = msgget(key, IPC_CREAT | 0644);
|
|
|
|
if (msgid < 0)
|
|
{
|
|
dbg_time("msgget fail: key %d, %s\n", key, strerror(errno));
|
|
return -1;
|
|
}
|
|
return msgid;
|
|
}
|
|
|
|
static int msg_rm(int msgid) { return msgctl(msgid, IPC_RMID, 0); }
|
|
|
|
static int msg_send(int msgid, long type, const char *msg)
|
|
{
|
|
struct message info;
|
|
info.mtype = type;
|
|
snprintf(info.mtext, MSGBUFFSZ, "%s", msg);
|
|
if (msgsnd(msgid, (void *)&info, MSGBUFFSZ, IPC_NOWAIT) < 0)
|
|
{
|
|
dbg_time("msgsnd faild: msg %s, %s\n", msg, strerror(errno));
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int msg_recv(int msgid, struct message *info)
|
|
{
|
|
if (msgrcv(msgid, (void *)info, MSGBUFFSZ, info->mtype, IPC_NOWAIT) < 0)
|
|
{
|
|
dbg_time("msgrcv faild: type %ld, %s\n", info->mtype, strerror(errno));
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* this function will not delete the msg queue
|
|
*/
|
|
int update_progress_msg(int percent)
|
|
{
|
|
char buff[MSGBUFFSZ];
|
|
int msgid = msg_get();
|
|
if (msgid < 0) return -1;
|
|
snprintf(buff, sizeof(buff), "%d", percent);
|
|
|
|
#ifndef IPC_TEST
|
|
return msg_send(msgid, MSG_TYPE_IPC, buff);
|
|
#else
|
|
msg_send(msgid, MSG_TYPE_IPC, buff);
|
|
struct message info;
|
|
info.mtype = MSG_TYPE_IPC;
|
|
msg_recv(msgid, &info);
|
|
printf("msg queue read: %s\n", info.mtext);
|
|
#endif
|
|
}
|
|
#endif
|