From c49dce9cb9268cf6d19748d5304e00e0145f1e58 Mon Sep 17 00:00:00 2001 From: Robert Zaage Date: Sun, 3 Jul 2022 08:20:44 +0000 Subject: [PATCH] Fixed typo in WIN32 help --- balong-usbdload.c | 1220 ++++++++++++++++++++++----------------------- 1 file changed, 610 insertions(+), 610 deletions(-) diff --git a/balong-usbdload.c b/balong-usbdload.c index 20e7290..3d4d25a 100644 --- a/balong-usbdload.c +++ b/balong-usbdload.c @@ -1,610 +1,610 @@ -// -// Balong-usbdload is an emergency USB boot loader utility for Huawei LTE modems and routers with Balong V2R7, V7R11 and V7R22 chipsets. -// It loads external boot loader/firmware update tool file (usbloader.bin) via emergency serial port available if the firmware is corrupted or boot pin (test point) is shorted to the ground. -// -#include -#include - -#ifndef WIN32 -//%%%% -#include -#include -#include -#include -#include -#include -#include -#else -//%%%% -#include -#include -#include "getopt.h" -#include "printf.h" -#endif - -#include "parts.h" -#include "patcher.h" - - -#ifndef WIN32 -int siofd; -struct termios sioparm; -#else -static HANDLE hSerial; -#endif -FILE* ldr; - - -//************************************************* -//* HEX-dump of the memory area * -//************************************************* - -void dump(unsigned char buffer[],int len) { -int i,j; -unsigned char ch; - -printf("\n"); -for (i=0;i 0x7e)&&(ch<0xc0))) putchar('.'); - else putchar(ch); - } - // filling with spaces for incomplete lines - else printf(" "); - } - printf("*\n"); - } -} - - -//************************************************* -//* Calculating the checksum of a command packet * -//************************************************* -void csum(unsigned char* buf, int len) { - -unsigned int i,c,csum=0; -unsigned int cconst[]={0,0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF}; - -for (i=0;i<(len-2);i++) { - c=(buf[i]&0xff); - csum=((csum<<4)&0xffff)^cconst[(c>>4)^(csum>>12)]; - csum=((csum<<4)&0xffff)^cconst[(c&0xf)^(csum>>12)]; -} -buf[len-2]=(csum>>8)&0xff; -buf[len-1]=csum&0xff; - -} - -//************************************************* -//* Sending a command packet to a modem * -//************************************************* -int sendcmd(unsigned char* cmdbuf, int len) { - -unsigned char replybuf[1024]; -unsigned int replylen; - -#ifndef WIN32 -csum(cmdbuf,len); -write(siofd,cmdbuf,len); // sending a command -tcdrain(siofd); -replylen=read(siofd,replybuf,1024); -#else - DWORD bytes_written = 0; - DWORD t; - - csum(cmdbuf, len); - WriteFile(hSerial, cmdbuf, len, &bytes_written, NULL); - FlushFileBuffers(hSerial); - - t = GetTickCount(); - do { - ReadFile(hSerial, replybuf, 1024, (LPDWORD)&replylen, NULL); - } while (replylen == 0 && GetTickCount() - t < 1000); -#endif -if (replylen == 0) return 0; -if (replybuf[0] == 0xaa) return 1; -return 0; -} - -//************************************************* -// Opening and configuring the serial port * -//************************************************* - -int open_port(char* devname) { - -//============= Linux =============== -#ifndef WIN32 - -int i,dflag=1; -char devstr[200]={0}; - -// only the ttyUSB port number can be transmitted instead of the full device name. - -// check the device name for nonnumeric characters -for(i=0;i'9')) dflag=0; -} -// if there are only digits in the string, add the prefix /dev/ttyUSB -if (dflag) strcpy(devstr,"/dev/ttyUSB"); -// copy the device name -strcat(devstr,devname); - -siofd = open(devstr, O_RDWR | O_NOCTTY |O_SYNC); -if (siofd == -1) return 0; - -bzero(&sioparm, sizeof(sioparm)); // prepare the attribute block termios -sioparm.c_cflag = B115200 | CS8 | CLOCAL | CREAD ; -sioparm.c_iflag = 0; // INPCK; -sioparm.c_oflag = 0; -sioparm.c_lflag = 0; -sioparm.c_cc[VTIME]=30; // timeout -sioparm.c_cc[VMIN]=0; -tcsetattr(siofd, TCSANOW, &sioparm); -return 1; - -//============= Win32 =============== -#else - char device[20] = "\\\\.\\COM"; - DCB dcbSerialParams = {0}; - COMMTIMEOUTS CommTimeouts; - - strcat(device, devname); - - hSerial = CreateFileA(device, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (hSerial == INVALID_HANDLE_VALUE) - return 0; - - ZeroMemory(&dcbSerialParams, sizeof(dcbSerialParams)); - dcbSerialParams.DCBlength=sizeof(dcbSerialParams); - dcbSerialParams.BaudRate=CBR_115200; - dcbSerialParams.ByteSize=8; - dcbSerialParams.StopBits=ONESTOPBIT; - dcbSerialParams.Parity=NOPARITY; - dcbSerialParams.fBinary = TRUE; - dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; - dcbSerialParams.fRtsControl = RTS_CONTROL_ENABLE; - if(!SetCommState(hSerial, &dcbSerialParams)) - { - CloseHandle(hSerial); - return 0; - } - - CommTimeouts.ReadIntervalTimeout = MAXDWORD; - CommTimeouts.ReadTotalTimeoutConstant = 0; - CommTimeouts.ReadTotalTimeoutMultiplier = 0; - CommTimeouts.WriteTotalTimeoutConstant = 0; - CommTimeouts.WriteTotalTimeoutMultiplier = 0; - if (!SetCommTimeouts(hSerial, &CommTimeouts)) - { - CloseHandle(hSerial); - return 0; - } - - return 1; -#endif -} - -//******************************************************* -//* Searching for the linux core in the partition image * -//******************************************************* -int locate_kernel(char* pbuf, uint32_t size) { - -int off; - -for(off=(size-8);off>0;off--) { - if (strncmp(pbuf+off,"ANDROID!",8) == 0) return off; -} -return 0; -} - -#ifdef WIN32 - -DEFINE_GUID(GUID_DEVCLASS_PORTS, 0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18); - -static int find_port(int* port_no, char* port_name) -{ - HDEVINFO device_info_set; - DWORD member_index = 0; - SP_DEVINFO_DATA device_info_data; - DWORD reg_data_type; - char property_buffer[256]; - DWORD required_size; - char* p; - int result = 1; - - device_info_set = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, NULL, 0, DIGCF_PRESENT); - - if (device_info_set == INVALID_HANDLE_VALUE) - return result; - - while (TRUE) - { - ZeroMemory(&device_info_data, sizeof(SP_DEVINFO_DATA)); - device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); - - if (!SetupDiEnumDeviceInfo(device_info_set, member_index, &device_info_data)) - break; - - member_index++; - - if (!SetupDiGetDeviceRegistryPropertyA(device_info_set, &device_info_data, SPDRP_HARDWAREID, - ®_data_type, (PBYTE)property_buffer, sizeof(property_buffer), &required_size)) - continue; - - if (strstr(_strupr(property_buffer), "VID_12D1&PID_1443") != NULL) - { - if (SetupDiGetDeviceRegistryPropertyA(device_info_set, &device_info_data, SPDRP_FRIENDLYNAME, - ®_data_type, (PBYTE)property_buffer, sizeof(property_buffer), &required_size)) - { - p = strstr(property_buffer, " (COM"); - if (p != NULL) - { - *port_no = atoi(p + 5); - strcpy(port_name, property_buffer); - result = 0; - } - } - break; - } - } - - SetupDiDestroyDeviceInfoList(device_info_set); - - return result; -} - -#endif - -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - -void main(int argc, char* argv[]) { - -unsigned int i,res,opt,datasize,pktcount,adr; -int bl; // current block -unsigned char c; -int fbflag=0, tflag=0, mflag=0, bflag=0, cflag=0; -int koff; // offset to ANDROID header -char ptfile[100]; - -FILE* pt; -char ptbuf[2048]; -uint32_t ptoff; - -struct ptable_t* ptable; - -unsigned char cmdhead[14]={0xfe,0, 0xff}; -unsigned char cmddata[1040]={0xda,0,0}; -unsigned char cmdeod[5]={0xed,0,0,0,0}; - -// list of partitions to set the file flag -uint8_t fileflag[41]; - -struct { - int lmode; // loading mode: 1 - direct start, 2 - via restarting A-core - int size; // size of a component - int adr; // address of the component loading into memory - int offset; // offset to the component from the beginning of the file - char* pbuf; // buffer for loading the component image -} blk[10]; - - -#ifndef WIN32 -unsigned char devname[50]="/dev/ttyUSB0"; -#else -char devname[50]=""; -DWORD bytes_written, bytes_read; -int port_no; -char port_name[256]; -#endif - -#ifndef WIN32 -bzero(fileflag,sizeof(fileflag)); -#else -memset(fileflag, 0, sizeof(fileflag)); -#endif - -while ((opt = getopt(argc, argv, "hp:ft:ms:bc")) != -1) { - switch (opt) { - case 'h': - -printf("\n This utility is used for emergency USB loading of devices with a Balong V7 chip\n\n\ -%s [option] \n\n\ - Following options are allowed:\n\n" -#ifndef WIN32 -"-p - Serial port for communicating with the bootloader (by default /dev/ttyUSB0)\n" -#else -"-p # - Number of the serial port for communicating with the loader (e.g. -p8)\n" -" if the -p switch is not specified, the port is auto-detected\n" -#endif -"-f - Load usbloader only to fastboot (without starting Linux)\n\ --b - Similarly to -f, additionally disable check of defective blocks during wipeout\n\ --t - Take partition table from specified file\n\ --m - Show the loader partition table and exit\n\ --s - Set file flag for partition (option can be set multiple times)\n\ --c - Do not automatically patch partitions\n\ -\n",argv[0]); - return; - - case 'p': - strcpy(devname,optarg); - break; - - case 'f': - fbflag=1; - break; - - case 'c': - cflag=1; - break; - - case 'b': - fbflag=1; - bflag=1; - break; - - case 'm': - mflag=1; - break; - - case 't': - tflag=1; - strcpy(ptfile,optarg); - break; - - case 's': - i=atoi(optarg); - if (i>41) { - printf("\n Partition #%i does not exist\n",i); - return; - } - fileflag[i]=1; - break; - - case '?': - case ':': - return; - - } -} - -printf("\nBalong-chipset emergency USB loader, version 2.20, (c) forth32, 2015\n"); -printf("English Version (c) robertzaage, 2022\n"); -#ifdef WIN32 -printf("Windows Port 32bit (c) rust3028, 2016\n"); -#endif - -if (optind>=argc) { - printf("\n - File to upload is not specified\n"); - return; -} - -ldr=fopen(argv[optind],"rb"); -if (ldr == 0) { - printf("\n Opening error %s",argv[optind]); - return; -} - -// Checking the usloader signature -fread(&i,1,4,ldr); -if (i != 0x20000) { - printf("\n File %s is not a usbloader\n",argv[optind]); - return; -} - -fseek(ldr,36,SEEK_SET); // beginning of block descriptors to load - -// parsing the header - -fread(&blk[0],1,16,ldr); // raminit -fread(&blk[1],1,16,ldr); // usbldr - -//--------------------------------------------------------------------- -// reading components into memory -for(bl=0;bl<2;bl++) { - - // allocate memory for the full image of the partition - blk[bl].pbuf=(char*)malloc(blk[bl].size); - - // read partition image into memory - fseek(ldr,blk[bl].offset,SEEK_SET); - res=fread(blk[bl].pbuf,1,blk[bl].size,ldr); - if (res != blk[bl].size) { - printf("\n Unexpected end of file: read %i expected %i\n",res,blk[bl].size); - return; - } - if (bl == 0) continue; // nothing more needs to be done for raminit - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // fastboot patch - if (fbflag) { - koff=locate_kernel(blk[bl].pbuf,blk[bl].size); - if (koff != 0) { - blk[bl].pbuf[koff]=0x55; // patch the signature - blk[bl].size=koff+8; // trim the partition to the start of the kernel - } - else { - printf("\n There is no ANDROID component in the loader - fastboot-loading is not possible.\n"); - exit(0); - } - } - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // look for the partition table in the boot loader - ptoff=find_ptable_ram(blk[bl].pbuf,blk[bl].size); - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // patch partition table - if (tflag) { - pt=fopen(ptfile,"rb"); - if (pt == 0) { - printf("\n File %s is not found - partition table cannot be replaced\n",ptfile); - return; - } - fread(ptbuf,1,2048,pt); - fclose(pt); - if (memcmp(headmagic,ptbuf,sizeof(headmagic)) != 0) { - printf("\n The file %s is not a partition table\n",ptfile); - return; - } - if (ptoff == 0) { - printf("\n No partition table found in loader - cannot be replaced"); - return; - } - memcpy(blk[bl].pbuf+ptoff,ptbuf,2048); - } - ptable=(struct ptable_t*)(blk[bl].pbuf+ptoff); - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // patch file flags - for(i=0;i<41;i++) { - if (fileflag[i]) { - ptable->part[i].nproperty |= 1; - } - } - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // output partition table - if (mflag) { - if (ptoff == 0) { - printf("\n Partition table not found - mapping output not possible\n"); - return; - } - show_map(*ptable); - return; - } - - // patch the erase procedure to ignore deadlocks - if (bflag) { - res=perasebad(blk[bl].pbuf, blk[bl].size); - if (res == 0) { - printf("\n! No isbad signature found - cannot load\n"); - return; - } - } - // removing the flash_eraseall procedure - if (!cflag) { - res = pv7r1(blk[bl].pbuf, blk[bl].size); - if (res == 0) - res = pv7r2(blk[bl].pbuf, blk[bl].size); - if (res == 0) - res = pv7r11(blk[bl].pbuf, blk[bl].size); - if (res == 0) - res = pv7r22(blk[bl].pbuf, blk[bl].size); - if (res == 0) - res = pv7r22_2(blk[bl].pbuf, blk[bl].size); - if (res == 0) - res = pv7r22_3(blk[bl].pbuf, blk[bl].size); - if (res != 0) printf("\n\n * Removed flash_eraseall procedure at offset %08x", blk[bl].offset + res); - else { - printf("\n Procedure eraseall not found in the bootloader - use key -s to boot without patch!\n"); - return; - } - } - -} - -//--------------------------------------------------------------------- - -#ifdef WIN32 -if (*devname == '\0') -{ - printf("\n\nSearching for the emergency loading port...\n"); - - if (find_port(&port_no, port_name) == 0) - { - sprintf(devname, "%d", port_no); - printf("Port: \"%s\"\n", port_name); - } - else - { - printf("No port found!\n"); - return; - } -} -#endif - -if (!open_port(devname)) { - printf("\n Can't open serial port\n"); - return; -} - -// Check the boot port -c=0; -#ifndef WIN32 -write(siofd,"A",1); -res=read(siofd,&c,1); -#else - WriteFile(hSerial, "A", 1, &bytes_written, NULL); - FlushFileBuffers(hSerial); - Sleep(100); - ReadFile(hSerial, &c, 1, &bytes_read, NULL); -#endif -if (c != 0x55) { - printf("\n! Port is not in USB-Boot mode\n"); - return; -} - -//---------------------------------- -// main loading cycle - load all the blocks found in the header -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -printf("\n\n Component Address Size %% loaded\n------------------------------------------\n"); - -for(bl=0;bl<2;bl++) { - - datasize=1024; - pktcount=1; - - // create a package of the beginning of the block - *((unsigned int*)&cmdhead[4])=htonl(blk[bl].size); - *((unsigned int*)&cmdhead[8])=htonl(blk[bl].adr); - cmdhead[3]=blk[bl].lmode; - - // send a block start packet - res=sendcmd(cmdhead,14); - if (!res) { - printf("\nModem rejected the header packet\n"); - return; - } - - - // ---------- Block-by-block data loading cycle ------------ - for(adr=0;adr=blk[bl].size) datasize=blk[bl].size-adr; - - printf("\r %s %08x %8i %i%%",bl?"usbboot":"raminit",blk[bl].adr,blk[bl].size,(adr+datasize)*100/blk[bl].size); - - // prepare the data package - cmddata[1]=pktcount; - cmddata[2]=(~pktcount)&0xff; - memcpy(cmddata+3,blk[bl].pbuf+adr,datasize); - - pktcount++; - if (!sendcmd(cmddata,datasize+5)) { - printf("\nModem rejected the data packet"); - return; - } - } - free(blk[bl].pbuf); - - // prepare an end-of-data packet - cmdeod[1]=pktcount; - cmdeod[2]=(~pktcount)&0xff; - - if (!sendcmd(cmdeod,5)) { - printf("\nModem rejected the end of data packet"); - } -printf("\n"); -} -printf("\n Loading finished!\n"); -} +// +// Balong-usbdload is an emergency USB boot loader utility for Huawei LTE modems and routers with Balong V2R7, V7R11 and V7R22 chipsets. +// It loads external boot loader/firmware update tool file (usbloader.bin) via emergency serial port available if the firmware is corrupted or boot pin (test point) is shorted to the ground. +// +#include +#include + +#ifndef WIN32 +//%%%% +#include +#include +#include +#include +#include +#include +#include +#else +//%%%% +#include +#include +#include "getopt.h" +#include "printf.h" +#endif + +#include "parts.h" +#include "patcher.h" + + +#ifndef WIN32 +int siofd; +struct termios sioparm; +#else +static HANDLE hSerial; +#endif +FILE* ldr; + + +//************************************************* +//* HEX-dump of the memory area * +//************************************************* + +void dump(unsigned char buffer[],int len) { +int i,j; +unsigned char ch; + +printf("\n"); +for (i=0;i 0x7e)&&(ch<0xc0))) putchar('.'); + else putchar(ch); + } + // filling with spaces for incomplete lines + else printf(" "); + } + printf("*\n"); + } +} + + +//************************************************* +//* Calculating the checksum of a command packet * +//************************************************* +void csum(unsigned char* buf, int len) { + +unsigned int i,c,csum=0; +unsigned int cconst[]={0,0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF}; + +for (i=0;i<(len-2);i++) { + c=(buf[i]&0xff); + csum=((csum<<4)&0xffff)^cconst[(c>>4)^(csum>>12)]; + csum=((csum<<4)&0xffff)^cconst[(c&0xf)^(csum>>12)]; +} +buf[len-2]=(csum>>8)&0xff; +buf[len-1]=csum&0xff; + +} + +//************************************************* +//* Sending a command packet to a modem * +//************************************************* +int sendcmd(unsigned char* cmdbuf, int len) { + +unsigned char replybuf[1024]; +unsigned int replylen; + +#ifndef WIN32 +csum(cmdbuf,len); +write(siofd,cmdbuf,len); // sending a command +tcdrain(siofd); +replylen=read(siofd,replybuf,1024); +#else + DWORD bytes_written = 0; + DWORD t; + + csum(cmdbuf, len); + WriteFile(hSerial, cmdbuf, len, &bytes_written, NULL); + FlushFileBuffers(hSerial); + + t = GetTickCount(); + do { + ReadFile(hSerial, replybuf, 1024, (LPDWORD)&replylen, NULL); + } while (replylen == 0 && GetTickCount() - t < 1000); +#endif +if (replylen == 0) return 0; +if (replybuf[0] == 0xaa) return 1; +return 0; +} + +//************************************************* +// Opening and configuring the serial port * +//************************************************* + +int open_port(char* devname) { + +//============= Linux =============== +#ifndef WIN32 + +int i,dflag=1; +char devstr[200]={0}; + +// only the ttyUSB port number can be transmitted instead of the full device name. + +// check the device name for nonnumeric characters +for(i=0;i'9')) dflag=0; +} +// if there are only digits in the string, add the prefix /dev/ttyUSB +if (dflag) strcpy(devstr,"/dev/ttyUSB"); +// copy the device name +strcat(devstr,devname); + +siofd = open(devstr, O_RDWR | O_NOCTTY |O_SYNC); +if (siofd == -1) return 0; + +bzero(&sioparm, sizeof(sioparm)); // prepare the attribute block termios +sioparm.c_cflag = B115200 | CS8 | CLOCAL | CREAD ; +sioparm.c_iflag = 0; // INPCK; +sioparm.c_oflag = 0; +sioparm.c_lflag = 0; +sioparm.c_cc[VTIME]=30; // timeout +sioparm.c_cc[VMIN]=0; +tcsetattr(siofd, TCSANOW, &sioparm); +return 1; + +//============= Win32 =============== +#else + char device[20] = "\\\\.\\COM"; + DCB dcbSerialParams = {0}; + COMMTIMEOUTS CommTimeouts; + + strcat(device, devname); + + hSerial = CreateFileA(device, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (hSerial == INVALID_HANDLE_VALUE) + return 0; + + ZeroMemory(&dcbSerialParams, sizeof(dcbSerialParams)); + dcbSerialParams.DCBlength=sizeof(dcbSerialParams); + dcbSerialParams.BaudRate=CBR_115200; + dcbSerialParams.ByteSize=8; + dcbSerialParams.StopBits=ONESTOPBIT; + dcbSerialParams.Parity=NOPARITY; + dcbSerialParams.fBinary = TRUE; + dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; + dcbSerialParams.fRtsControl = RTS_CONTROL_ENABLE; + if(!SetCommState(hSerial, &dcbSerialParams)) + { + CloseHandle(hSerial); + return 0; + } + + CommTimeouts.ReadIntervalTimeout = MAXDWORD; + CommTimeouts.ReadTotalTimeoutConstant = 0; + CommTimeouts.ReadTotalTimeoutMultiplier = 0; + CommTimeouts.WriteTotalTimeoutConstant = 0; + CommTimeouts.WriteTotalTimeoutMultiplier = 0; + if (!SetCommTimeouts(hSerial, &CommTimeouts)) + { + CloseHandle(hSerial); + return 0; + } + + return 1; +#endif +} + +//******************************************************* +//* Searching for the linux core in the partition image * +//******************************************************* +int locate_kernel(char* pbuf, uint32_t size) { + +int off; + +for(off=(size-8);off>0;off--) { + if (strncmp(pbuf+off,"ANDROID!",8) == 0) return off; +} +return 0; +} + +#ifdef WIN32 + +DEFINE_GUID(GUID_DEVCLASS_PORTS, 0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18); + +static int find_port(int* port_no, char* port_name) +{ + HDEVINFO device_info_set; + DWORD member_index = 0; + SP_DEVINFO_DATA device_info_data; + DWORD reg_data_type; + char property_buffer[256]; + DWORD required_size; + char* p; + int result = 1; + + device_info_set = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, NULL, 0, DIGCF_PRESENT); + + if (device_info_set == INVALID_HANDLE_VALUE) + return result; + + while (TRUE) + { + ZeroMemory(&device_info_data, sizeof(SP_DEVINFO_DATA)); + device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); + + if (!SetupDiEnumDeviceInfo(device_info_set, member_index, &device_info_data)) + break; + + member_index++; + + if (!SetupDiGetDeviceRegistryPropertyA(device_info_set, &device_info_data, SPDRP_HARDWAREID, + ®_data_type, (PBYTE)property_buffer, sizeof(property_buffer), &required_size)) + continue; + + if (strstr(_strupr(property_buffer), "VID_12D1&PID_1443") != NULL) + { + if (SetupDiGetDeviceRegistryPropertyA(device_info_set, &device_info_data, SPDRP_FRIENDLYNAME, + ®_data_type, (PBYTE)property_buffer, sizeof(property_buffer), &required_size)) + { + p = strstr(property_buffer, " (COM"); + if (p != NULL) + { + *port_no = atoi(p + 5); + strcpy(port_name, property_buffer); + result = 0; + } + } + break; + } + } + + SetupDiDestroyDeviceInfoList(device_info_set); + + return result; +} + +#endif + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +void main(int argc, char* argv[]) { + +unsigned int i,res,opt,datasize,pktcount,adr; +int bl; // current block +unsigned char c; +int fbflag=0, tflag=0, mflag=0, bflag=0, cflag=0; +int koff; // offset to ANDROID header +char ptfile[100]; + +FILE* pt; +char ptbuf[2048]; +uint32_t ptoff; + +struct ptable_t* ptable; + +unsigned char cmdhead[14]={0xfe,0, 0xff}; +unsigned char cmddata[1040]={0xda,0,0}; +unsigned char cmdeod[5]={0xed,0,0,0,0}; + +// list of partitions to set the file flag +uint8_t fileflag[41]; + +struct { + int lmode; // loading mode: 1 - direct start, 2 - via restarting A-core + int size; // size of a component + int adr; // address of the component loading into memory + int offset; // offset to the component from the beginning of the file + char* pbuf; // buffer for loading the component image +} blk[10]; + + +#ifndef WIN32 +unsigned char devname[50]="/dev/ttyUSB0"; +#else +char devname[50]=""; +DWORD bytes_written, bytes_read; +int port_no; +char port_name[256]; +#endif + +#ifndef WIN32 +bzero(fileflag,sizeof(fileflag)); +#else +memset(fileflag, 0, sizeof(fileflag)); +#endif + +while ((opt = getopt(argc, argv, "hp:ft:ms:bc")) != -1) { + switch (opt) { + case 'h': + +printf("\n This utility is used for emergency USB loading of devices with a Balong V7 chip\n\n\ +%s [option] \n\n\ + Following options are allowed:\n\n" +#ifndef WIN32 +"-p - Serial port for communicating with the bootloader (by default /dev/ttyUSB0)\n" +#else +"-p # - Number of the serial port for communicating with the loader (e.g. -p8)\n" +" if the -p option is not specified, the port is auto-detected\n" +#endif +"-f - Load usbloader only to fastboot (without starting Linux)\n\ +-b - Similarly to -f, additionally disable check of defective blocks during wipeout\n\ +-t - Take partition table from specified file\n\ +-m - Show the loader partition table and exit\n\ +-s - Set file flag for partition (option can be set multiple times)\n\ +-c - Do not automatically patch partitions\n\ +\n",argv[0]); + return; + + case 'p': + strcpy(devname,optarg); + break; + + case 'f': + fbflag=1; + break; + + case 'c': + cflag=1; + break; + + case 'b': + fbflag=1; + bflag=1; + break; + + case 'm': + mflag=1; + break; + + case 't': + tflag=1; + strcpy(ptfile,optarg); + break; + + case 's': + i=atoi(optarg); + if (i>41) { + printf("\n Partition #%i does not exist\n",i); + return; + } + fileflag[i]=1; + break; + + case '?': + case ':': + return; + + } +} + +printf("\nBalong-chipset emergency USB loader, version 2.20, (c) forth32, 2015\n"); +printf("English Version (c) robertzaage, 2022\n"); +#ifdef WIN32 +printf("Windows Port 32bit (c) rust3028, 2016\n"); +#endif + +if (optind>=argc) { + printf("\n - File to upload is not specified\n"); + return; +} + +ldr=fopen(argv[optind],"rb"); +if (ldr == 0) { + printf("\n Opening error %s",argv[optind]); + return; +} + +// Checking the usloader signature +fread(&i,1,4,ldr); +if (i != 0x20000) { + printf("\n File %s is not a usbloader\n",argv[optind]); + return; +} + +fseek(ldr,36,SEEK_SET); // beginning of block descriptors to load + +// parsing the header + +fread(&blk[0],1,16,ldr); // raminit +fread(&blk[1],1,16,ldr); // usbldr + +//--------------------------------------------------------------------- +// reading components into memory +for(bl=0;bl<2;bl++) { + + // allocate memory for the full image of the partition + blk[bl].pbuf=(char*)malloc(blk[bl].size); + + // read partition image into memory + fseek(ldr,blk[bl].offset,SEEK_SET); + res=fread(blk[bl].pbuf,1,blk[bl].size,ldr); + if (res != blk[bl].size) { + printf("\n Unexpected end of file: read %i expected %i\n",res,blk[bl].size); + return; + } + if (bl == 0) continue; // nothing more needs to be done for raminit + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // fastboot patch + if (fbflag) { + koff=locate_kernel(blk[bl].pbuf,blk[bl].size); + if (koff != 0) { + blk[bl].pbuf[koff]=0x55; // patch the signature + blk[bl].size=koff+8; // trim the partition to the start of the kernel + } + else { + printf("\n There is no ANDROID component in the loader - fastboot-loading is not possible.\n"); + exit(0); + } + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // look for the partition table in the boot loader + ptoff=find_ptable_ram(blk[bl].pbuf,blk[bl].size); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // patch partition table + if (tflag) { + pt=fopen(ptfile,"rb"); + if (pt == 0) { + printf("\n File %s is not found - partition table cannot be replaced\n",ptfile); + return; + } + fread(ptbuf,1,2048,pt); + fclose(pt); + if (memcmp(headmagic,ptbuf,sizeof(headmagic)) != 0) { + printf("\n The file %s is not a partition table\n",ptfile); + return; + } + if (ptoff == 0) { + printf("\n No partition table found in loader - cannot be replaced"); + return; + } + memcpy(blk[bl].pbuf+ptoff,ptbuf,2048); + } + ptable=(struct ptable_t*)(blk[bl].pbuf+ptoff); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // patch file flags + for(i=0;i<41;i++) { + if (fileflag[i]) { + ptable->part[i].nproperty |= 1; + } + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // output partition table + if (mflag) { + if (ptoff == 0) { + printf("\n Partition table not found - mapping output not possible\n"); + return; + } + show_map(*ptable); + return; + } + + // patch the erase procedure to ignore deadlocks + if (bflag) { + res=perasebad(blk[bl].pbuf, blk[bl].size); + if (res == 0) { + printf("\n! No isbad signature found - cannot load\n"); + return; + } + } + // removing the flash_eraseall procedure + if (!cflag) { + res = pv7r1(blk[bl].pbuf, blk[bl].size); + if (res == 0) + res = pv7r2(blk[bl].pbuf, blk[bl].size); + if (res == 0) + res = pv7r11(blk[bl].pbuf, blk[bl].size); + if (res == 0) + res = pv7r22(blk[bl].pbuf, blk[bl].size); + if (res == 0) + res = pv7r22_2(blk[bl].pbuf, blk[bl].size); + if (res == 0) + res = pv7r22_3(blk[bl].pbuf, blk[bl].size); + if (res != 0) printf("\n\n * Removed flash_eraseall procedure at offset %08x", blk[bl].offset + res); + else { + printf("\n Procedure eraseall not found in the bootloader - use key -s to boot without patch!\n"); + return; + } + } + +} + +//--------------------------------------------------------------------- + +#ifdef WIN32 +if (*devname == '\0') +{ + printf("\n\nSearching for the emergency loading port...\n"); + + if (find_port(&port_no, port_name) == 0) + { + sprintf(devname, "%d", port_no); + printf("Port: \"%s\"\n", port_name); + } + else + { + printf("No port found!\n"); + return; + } +} +#endif + +if (!open_port(devname)) { + printf("\n Can't open serial port\n"); + return; +} + +// Check the boot port +c=0; +#ifndef WIN32 +write(siofd,"A",1); +res=read(siofd,&c,1); +#else + WriteFile(hSerial, "A", 1, &bytes_written, NULL); + FlushFileBuffers(hSerial); + Sleep(100); + ReadFile(hSerial, &c, 1, &bytes_read, NULL); +#endif +if (c != 0x55) { + printf("\n! Port is not in USB-Boot mode\n"); + return; +} + +//---------------------------------- +// main loading cycle - load all the blocks found in the header +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +printf("\n\n Component Address Size %% loaded\n------------------------------------------\n"); + +for(bl=0;bl<2;bl++) { + + datasize=1024; + pktcount=1; + + // create a package of the beginning of the block + *((unsigned int*)&cmdhead[4])=htonl(blk[bl].size); + *((unsigned int*)&cmdhead[8])=htonl(blk[bl].adr); + cmdhead[3]=blk[bl].lmode; + + // send a block start packet + res=sendcmd(cmdhead,14); + if (!res) { + printf("\nModem rejected the header packet\n"); + return; + } + + + // ---------- Block-by-block data loading cycle ------------ + for(adr=0;adr=blk[bl].size) datasize=blk[bl].size-adr; + + printf("\r %s %08x %8i %i%%",bl?"usbboot":"raminit",blk[bl].adr,blk[bl].size,(adr+datasize)*100/blk[bl].size); + + // prepare the data package + cmddata[1]=pktcount; + cmddata[2]=(~pktcount)&0xff; + memcpy(cmddata+3,blk[bl].pbuf+adr,datasize); + + pktcount++; + if (!sendcmd(cmddata,datasize+5)) { + printf("\nModem rejected the data packet"); + return; + } + } + free(blk[bl].pbuf); + + // prepare an end-of-data packet + cmdeod[1]=pktcount; + cmdeod[2]=(~pktcount)&0xff; + + if (!sendcmd(cmdeod,5)) { + printf("\nModem rejected the end of data packet"); + } +printf("\n"); +} +printf("\n Loading finished!\n"); +}