/* * mtd - simple memory technology device manipulation tool * * Copyright (c) 2006, 2007 Thorsten Glaser * Copyright (C) 2005 Waldemar Brodkorb , * Felix Fietkau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The code is based on the linux-mtd examples. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "trx/trx.h" #ifdef TCSUPPORT_MTD_ENCHANCEMENT #include "tc_partition.h" #endif // Zyxel don`t need this #if 0 //def TCSUPPORT_PRODUCTIONLINE #include "prolinecmd.h" #endif #if defined(TCSUPPORT_MT7570) && !defined(TC_SDK_7_3_235_200) #include "global_inc/modules/xpon_phy_global/mt7570.h" #endif #if KERNEL_VERSION(2,6,0) <= LINUX_VERSION_CODE #define IS_KERNEL26 1 #else #define IS_KERNEL26 0 #endif #if IS_KERNEL26 #include #else #include #endif #ifdef TCSUPPORT_INIC_HOST #include #endif //#define TRX_MAGIC 0x30524448 /* "HDR0" */ //#define TRX_MAGIC1 0x31524448 /* "HDR1" */ #define BUFSIZE (16 * 1024) #define MAX_ARGS 8 #define DEBUG #define SYSTYPE_UNKNOWN 0 #define SYSTYPE_BROADCOM 1 /* add for MTD bob cmd */ #define MTD_BOB_DEFAULT_FILE "/tmp/7570_bob.conf" #define MTD_BOB_DEVICE "reservearea" #ifndef TRENDCHIP /* to be continued */ struct trx_header { uint32_t magic; /* "HDR0" */ uint32_t len; /* Length of file including header */ uint32_t crc32; /* 32-bit CRC from flag_version to end of file */ uint32_t flag_version; /* 0:15 flags, 16:31 version */ uint32_t offsets[3]; /* Offsets of partitions from start of header */ }; #endif #ifndef TRENDCHIP int image_check_bcom(int, const char *); #else int image_check_tc(int, const char *); #endif int image_check(int, const char *); int mtd_check(char *); int mtd_unlock(const char *); int mtd_open(const char *, int); int mtd_erase(const char *); int mtd_write(int, const char *, int, int); void usage(void) __attribute__((noreturn)); typedef char char_aligned_32bit __attribute__((aligned (4), may_alias)); __attribute__((aligned (4), may_alias)) buf[BUFSIZE]; int buflen; #ifdef TRENDCHIP int n_bytes = 0; #endif #ifdef TCSUPPORT_MTD_ENCHANCEMENT int writeflash(int imagefd, const char *device,unsigned long tcoffset, unsigned long tclen, int quiet); int readflash(int imagefd, const char *device,unsigned long tcoffset,unsigned long tclen); #endif static int reboot_flag = 0; #ifndef TRENDCHIP int image_check_bcom(int imagefd, const char *mtd) { struct trx_header *trx = (struct trx_header *) buf; struct mtd_info_user mtdInfo; int fd; buflen = read(imagefd, buf, 32); if (buflen < 32) { fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", buflen); return 0; } switch(trx->magic) { case 0x47343557: /* W54G */ case 0x53343557: /* W54S */ case 0x73343557: /* W54s */ case 0x46343557: /* W54F */ case 0x55343557: /* W54U */ /* ignore the first 32 bytes */ buflen = read(imagefd, buf, sizeof(struct trx_header)); break; case 0x464c457f: /* ELF Netgear WGT634u */ fprintf(stderr, "found ELF header\n"); if (lseek(imagefd, 128*1024, SEEK_SET) == -1) { if (errno != ESPIPE) err(1, "lseek"); /* * the lseek failed because stdin is a pipe, * so fake it; we know we've already read * 32 bytes in the above call, so just read * in (128 * 1024 - 32) bytes now, modulo * sizeof (buf). why is this 128 KiB btw, * wouldn't it be better to parse the ELF * header? */ buflen = 128 * 1024 - 32; while (buflen) { ssize_t n; n = read(imagefd, buf, MIN((size_t)buflen, sizeof (buf))); if (n < 0) err(1, "read"); buflen -= n; } } buflen = read(imagefd, buf, sizeof(struct trx_header)); break; } if (trx->magic != TRX_MAGIC || trx->len < sizeof(struct trx_header)) { fprintf(stderr, "Bad trx header\n"); fprintf(stderr, "If this is a firmware in bin format, like some of the\n" "original firmware files are, use following command to convert to trx:\n" "dd if=firmware.bin of=firmware.trx bs=32 skip=1\n"); return 0; } /* check if image fits to mtd device */ fd = mtd_open(mtd, O_RDWR | O_SYNC); if(fd < 0) { fprintf(stderr, "Could not open mtd device: %s\n", mtd); exit(1); } if(ioctl(fd, MEMGETINFO, &mtdInfo)) { fprintf(stderr, "Could not get MTD device info from %s\n", mtd); exit(1); } if(mtdInfo.size < trx->len) { fprintf(stderr, "Image too big for partition: %s\n", mtd); close(fd); return 0; } close(fd); return 1; } #endif int image_check_tc(int imagefd, const char *mtd) { struct trx_header *trx = (struct trx_header *) buf; struct mtd_info_user mtdInfo; int fd; if((strncmp(mtd,"romfile",7) == 0) #ifdef TCSUPPORT_INIC_HOST || (strcmp(mtd, INIC_CLIENT_ROMFILE_NAME) == 0) #endif ) { return 1; } //buflen = read(imagefd, buf, 32); buflen = read(imagefd, buf, sizeof(struct trx_header)); if (buflen < sizeof(struct trx_header)) { fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", buflen); return 0; } if(strcmp(mtd, "kernel") == 0) { if (trx->magic != TRX_MAGIC || trx->len < sizeof(struct trx_header)) { fprintf(stderr, "Bad trx header\n"); fprintf(stderr, "If this is a firmware in bin format, like some of the\n" "original firmware files are, use following command to convert to trx:\n" "dd if=firmware.bin of=firmware.trx bs=32 skip=1\n"); return 0; } }else { if (trx->magic != TRX_MAGIC1 || trx->len < sizeof(struct trx_header)) { fprintf(stderr, "Bad trx header\n"); fprintf(stderr, "If this is a firmware in bin format, like some of the\n" "original firmware files are, use following command to convert to trx:\n" "dd if=firmware.bin of=firmware.trx bs=32 skip=1\n"); return 0; } } /* check if image fits to mtd device */ fd = mtd_open(mtd, O_RDWR | O_SYNC); if(fd < 0) { fprintf(stderr, "Could not open mtd device: %s\n", mtd); exit(1); } if(ioctl(fd, MEMGETINFO, &mtdInfo)) { fprintf(stderr, "Could not get MTD device info from %s\n", mtd); exit(1); } if(mtdInfo.size < trx->len) { fprintf(stderr, "Image too big for partition: %s\n", mtd); close(fd); return 0; } close(fd); return 1; } int image_check(int imagefd, const char *mtd) { #ifndef TRENDCHIP int systype; char *c; FILE *f; systype = SYSTYPE_UNKNOWN; f = fopen("/proc/cpuinfo", "r"); while (!feof(f) && (fgets((char *)buf, BUFSIZE - 1, f) != NULL)) { if ((memcmp(buf, "system type", 11) == 0) && (c = strchr((char *)buf, ':'))) { c += 2; if (strncmp(c, "Broadcom BCM947XX", 17) == 0) systype = SYSTYPE_BROADCOM; } } fclose(f); switch(systype) { case SYSTYPE_BROADCOM: return image_check_bcom(imagefd, mtd); default: return 1; } #else return image_check_tc(imagefd, mtd); #endif } int mtd_check(char *mtd) { struct mtd_info_user mtdInfo; int fd; fd = mtd_open(mtd, O_RDWR | O_SYNC); if(fd < 0) { fprintf(stderr, "Could not open mtd device: %s\n", mtd); return 0; } if(ioctl(fd, MEMGETINFO, &mtdInfo)) { fprintf(stderr, "Could not get MTD device info from %s\n", mtd); close(fd); return 0; } close(fd); return 1; } int mtd_unlock(const char *mtd) { int fd; struct mtd_info_user mtdInfo; struct erase_info_user mtdLockInfo; fd = mtd_open(mtd, O_RDWR | O_SYNC); if(fd < 0) { fprintf(stderr, "Could not open mtd device: %s\n", mtd); exit(1); } if(ioctl(fd, MEMGETINFO, &mtdInfo)) { fprintf(stderr, "Could not get MTD device info from %s\n", mtd); close(fd); exit(1); } mtdLockInfo.start = 0; mtdLockInfo.length = mtdInfo.size; if(ioctl(fd, MEMUNLOCK, &mtdLockInfo)) { close(fd); return 0; } close(fd); return 0; } int mtd_open(const char *mtd, int flags) { FILE *fp; char dev[PATH_MAX]; int i; if ((fp = fopen("/proc/mtd", "r"))) { while (fgets(dev, sizeof(dev), fp)) { if (sscanf(dev, "mtd%d:", &i) && strstr(dev, mtd)) { #ifndef TRENDCHIP snprintf(dev, sizeof(dev), "/dev/mtd/%d", i); #else snprintf(dev, sizeof(dev), "/dev/mtd%d", i); #endif fclose(fp); return open(dev, flags); } } fclose(fp); } return open(mtd, flags); } int mtd_erase(const char *mtd) { int fd; struct mtd_info_user mtdInfo; struct erase_info_user mtdEraseInfo; fd = mtd_open(mtd, O_RDWR | O_SYNC); if(fd < 0) { fprintf(stderr, "Could not open mtd device: %s\n", mtd); exit(1); } if(ioctl(fd, MEMGETINFO, &mtdInfo)) { fprintf(stderr, "Could not get MTD device info from %s\n", mtd); close(fd); exit(1); } mtdEraseInfo.length = mtdInfo.erasesize; for (mtdEraseInfo.start = 0; mtdEraseInfo.start < mtdInfo.size; mtdEraseInfo.start += mtdInfo.erasesize) { ioctl(fd, MEMUNLOCK, &mtdEraseInfo); if(ioctl(fd, MEMERASE, &mtdEraseInfo)) { fprintf(stderr, "Could not erase MTD device: %s\n", mtd); close(fd); exit(1); } } close(fd); return 0; } /* file lock for multi-thread */ void mtd_flock(int fd, const char *mtd) { if(flock(fd, LOCK_EX) != 0) { fprintf(stderr, "Could not lock mtd %s\n", mtd); close(fd); exit(1); } } /* file unlock for multi-thread */ void mtd_funlock(int fd, const char *mtd) { if(flock(fd, LOCK_UN) != 0) { fprintf(stderr, "Could not unlock mtd %s\n", mtd); } } #if defined(TCSUPPORT_START_TRAP) || defined(TCSUPPORT_SYSLOG_ENHANCE) #define SIGNAL_PATH "/var/tmp/signal_reboot" static int quit_signal(void) { int ret; FILE *fp = NULL; char buf[8]; memset(buf, 0, sizeof(buf)); fp = fopen(SIGNAL_PATH, "r"); if (fp == NULL) ret = 0; else { fgets(buf, 8, fp); if (buf[0] == '1') ret = 1; else ret = 0; fclose(fp); unlink(SIGNAL_PATH); } return ret; } #endif #if defined(TCSUPPORT_CT) #define CWMP_UPGRADE_ROMFILE_FILE_NAME "/tmp/tc_cwmp_upgrade_romfile.conf" int mtd_write2(int imagefd, const char *mtd){ int fd, result, r; //COV, CID 186792 size_t w, e; struct mtd_info_user mtdInfo; struct erase_info_user mtdEraseInfo; fd = mtd_open(mtd, O_RDWR | O_SYNC); if(fd < 0) { fprintf(stderr, "Could not open mtd device: %s\n", mtd); exit(1); } mtd_flock(fd, mtd); if(ioctl(fd, MEMGETINFO, &mtdInfo)) { fprintf(stderr, "Could not get MTD device info from %s\n", mtd); mtd_funlock(fd, mtd); close(fd); exit(1); } r = w = e = 0; for (;;) { r = 0; r +=read(imagefd, buf, BUFSIZE); w += r; /* EOF */ if (r <= 0) break; /* need to erase the next block before writing data to it */ while (w > e) { mtdEraseInfo.start = e; mtdEraseInfo.length = mtdInfo.erasesize; /* erase the chunk */ if (ioctl (fd,MEMERASE,&mtdEraseInfo) < 0) { fprintf(stderr, "Erasing mtd failed: %s\n", mtd); mtd_funlock(fd, mtd); close(fd); exit(1); } e += mtdInfo.erasesize; } if ((result = write(fd, buf, r)) < (ssize_t)r) { if (result < 0) { fprintf(stderr, "Error writing image.\n"); } else { fprintf(stderr, "Insufficient space.\n"); } mtd_funlock(fd, mtd); close(fd); exit(1); } } mtd_funlock(fd, mtd); close(fd); return 0; } int mtd_write_upgraderomfile(const char *mtd){ int tr069_romfile_fd; //COV, CID 186794 if(strcmp(mtd,"tclinux")!= 0){ fprintf(stderr, "not Error writing tclinux,mtd=%s.\n",mtd); return 0; } tr069_romfile_fd = open(CWMP_UPGRADE_ROMFILE_FILE_NAME,O_RDONLY); //COV, CID 186794 if(tr069_romfile_fd < 0){ return 0; } else { mtd_write2(tr069_romfile_fd,"romfile"); close(tr069_romfile_fd); } #if defined(TCSUPPORT_CT_E8B_ADSL) && defined(TCSUPPORT_CPU_MT7505) return 1; #else return 0; #endif } #endif int mtd_write(int imagefd, const char *mtd, int quiet, int do_erase) { int fd, result, r; //COV, CID 148971 size_t w, e; struct mtd_info_user mtdInfo; struct erase_info_user mtdEraseInfo; #if defined(TCSUPPORT_START_TRAP) || defined(TCSUPPORT_SYSLOG_ENHANCE) int count = 0; #endif #if defined(TCSUPPORT_CT) int flag = 0; #endif fd = mtd_open(mtd, O_RDWR | O_SYNC); if(fd < 0) { fprintf(stderr, "Could not open mtd device: %s\n", mtd); exit(1); } mtd_flock(fd, mtd); if(ioctl(fd, MEMGETINFO, &mtdInfo)) { fprintf(stderr, "Could not get MTD device info from %s\n", mtd); mtd_funlock(fd, mtd); close(fd); exit(1); } r = w = e = 0; if (!quiet) fprintf(stderr, " [ ]"); for (;;) { #ifndef TRENDCHIP /* buffer may contain data already (from trx check) */ r = buflen; r += read(imagefd, buf + buflen, BUFSIZE - buflen); #else r = 0; r +=read(imagefd, buf, BUFSIZE); #endif w += r; /* EOF */ if (r <= 0) break; /* need to erase the next block before writing data to it */ while (do_erase && w > e) { mtdEraseInfo.start = e; mtdEraseInfo.length = mtdInfo.erasesize; if (!quiet) fprintf(stderr, "\b\b\b[e]"); /* erase the chunk */ if (ioctl (fd,MEMERASE,&mtdEraseInfo) < 0) { fprintf(stderr, "Erasing mtd failed: %s\n", mtd); mtd_funlock(fd, mtd); close(fd); exit(1); } e += mtdInfo.erasesize; } if (!quiet) fprintf(stderr, "\b\b\b[w]"); if ((result = write(fd, buf, r)) < (ssize_t)r) { if (result < 0) { fprintf(stderr, "Error writing image.\n"); } else { fprintf(stderr, "Insufficient space.\n"); } mtd_funlock(fd, mtd); close(fd); exit(1); } buflen = 0; #ifdef TRENDCHIP if( n_bytes != 0 ){ if( w >= n_bytes ) break; } #endif } if (!quiet) fprintf(stderr, "\b\b\b\b"); mtd_funlock(fd, mtd); close(fd); #if defined(TCSUPPORT_CT) flag = mtd_write_upgraderomfile(mtd); if(reboot_flag || flag) #else if(reboot_flag) #endif { #if defined(TCSUPPORT_START_TRAP) || defined(TCSUPPORT_SYSLOG_ENHANCE) system("killall -SIGUSR1 cfg_manager"); /* wait cfg_manager done */ while (!quit_signal() && count++ < 10) sleep(1); #endif #ifdef TCSUPPORT_SYSLOG_ENHANCE system("killall -9 syslogd"); #endif if ((fd=open("/proc/watchdog_reset", O_WRONLY)) == -1) { exit(1); } write(fd,"1\0",1); close(fd); } return 0; } #ifdef TCSUPPORT_MTD_ENCHANCEMENT long getFileSize(char *filename) { struct stat f_stat; if(stat(filename,&f_stat) == -1) { fprintf(stderr, "get file size error!!"); return -1; } return (long)f_stat.st_size; } int writeflash(int imagefd, const char *device,unsigned long tcoffset, unsigned long tclen,int quiet) { int fd; struct mtd_info_user mtdInfo; //char tcbuf[256] = {0};way 1 use this unsigned long judge_count = 0,read_count = 0,count = 0; unsigned long sector_start = 0,sector_num = 0,sector_size = 0,total_size = 0; struct erase_info_user mtdEraseInfo; char *sector = NULL; fd = mtd_open(device, O_RDWR); if(fd < 0) { fprintf(stderr, "Could not open mtd device: %s\n", device); exit(1); } mtd_flock(fd, device); //get mtd information if(ioctl(fd, MEMGETINFO, &mtdInfo)) { fprintf(stderr, "Could not get MTD device info from %s\n", device); goto writeflasherror; } //fprintf(stderr, "erasesize:0x%x,size:0x%x\n",mtdInfo.erasesize,mtdInfo.size); //let's do some sanity checks if(tcoffset >= mtdInfo.size) { fprintf(stderr, "writeflash: device \"%s\" is out of reach -- exit(1)\n", device); goto writeflasherror; } else if(tcoffset + tclen > mtdInfo.size) { tclen = mtdInfo.size - tcoffset; fprintf(stderr, "writeflash: extends beyond the end of device \"%s\" -- size truncated to %#x\n", device,tclen); } //malloc one block memory area sector = malloc(mtdInfo.erasesize); if(sector == NULL) { fprintf(stderr, "writeflash: malloc error!!not enough memory\n"); goto writeflasherror; } //real action(one block per cycle) while(tclen > 0) { if(quiet < 2) fprintf(stderr, "enter real action -----tclen:0x%x,tcoffset:0x%x\n",tclen,tcoffset); sector_start = tcoffset & ( ~ (mtdInfo.erasesize - 1) ); sector_size = mtdInfo.erasesize - (tcoffset - sector_start); if(sector_size > tclen) sector_size = tclen; if(quiet < 2) fprintf(stderr, "writeflash: write %d 'st sector,start from 0x%x,0x%x bytes\n",sector_num,sector_start,sector_size); //first ,read the whole sector from flash to memory cache lseek(fd,sector_start,SEEK_SET); count = read(fd,sector, mtdInfo.erasesize); if(count != mtdInfo.erasesize) { fprintf(stderr, "writeflash: fail to read the %d 'st sector\n",sector_num); goto writeflasherror; } #if 0 //way 1 //then,read data from file and store into memory cache read_count = 0; count = 0; lseek(imagefd,judge_count,SEEK_SET); while(read_count < sector_size) { //fprintf(stderr, "\n"); count = read(imagefd,tcbuf,sizeof(tcbuf)); if(count <= 0) break; if(read_count+count > sector_size) { lseek(imagefd,judge_count+read_count,SEEK_SET);//must use lseek to re-point the read point count = read(imagefd,tcbuf,sector_size - read_count); //fprintf(stderr, "\ttcbuf is %s",tcbuf); //fprintf(stderr, "\tsector_size - read_count is 0x %x",sector_size - read_count); //fprintf(stderr, "\trecount is 0x %x",count); } memcpy(sector + tcoffset - sector_start + read_count,tcbuf,count);//store the data to the according area read_count += count; } judge_count += write_count;//judge_count used for re-point #else //way 2 //then,read data from file and store into memory cache read_count = 0; lseek(imagefd,judge_count,SEEK_SET); read_count = read(imagefd,sector + tcoffset - sector_start,sector_size); //below check is necessarily if(read_count <= 0) { fprintf(stderr, "read:count <= 0\n"); break; } //fprintf(stderr, "\tcount is 0x%x\n",count); //judge_count += sector_size; judge_count += read_count; //fprintf(stderr, "\tjudge_count is 0x%x\n",judge_count); #endif //and then,erase the sector if (!quiet) fprintf(stderr, "\b\b\b[e]"); mtdEraseInfo.start = sector_start; mtdEraseInfo.length = mtdInfo.erasesize; if (ioctl (fd,MEMERASE,&mtdEraseInfo) < 0) { fprintf(stderr, "writeflash:Erasing device failed: %s\n", device); goto writeflasherror; } //at last,write back data from memory cashe to flash if (!quiet) fprintf(stderr, "\b\b\b[w]"); lseek(fd,sector_start,SEEK_SET); count = write(fd,sector, mtdInfo.erasesize); if(count != mtdInfo.erasesize) { fprintf(stderr, "writeflash: fail to write the %d 'st sector\n",sector_num); goto writeflasherror; } sector_num++; tclen -= sector_size; tcoffset += sector_size; //total_size += sector_size; total_size += read_count; } if (!quiet) fprintf(stderr, "\b\b\b\b"); if(quiet < 2) fprintf(stderr, "writeflash: total write 0x%x bytes\n",total_size); if(sector) free(sector); mtd_funlock(fd, device); close(fd); return 0; writeflasherror: if(sector) free(sector); mtd_funlock(fd, device); close(fd); exit(1); } int readflash(int imagefd, const char *device,unsigned long tcoffset,unsigned long tclen) { int fd, count; //COV, CID 149001 struct mtd_info_user mtdInfo; char tcbuf[256] = {0}; unsigned long read_conut = 0,write_count = 0; fd = mtd_open(device, O_RDWR | O_SYNC); if(fd < 0) { fprintf(stderr, "Could not open mtd device: %s\n", device); exit(1); } //get mtd information if(ioctl(fd, MEMGETINFO, &mtdInfo)) { fprintf(stderr, "Could not get MTD device info from %s\n", device); close(fd); exit(1); } if(tclen == 0 && tcoffset == 0) { tclen = mtdInfo.size; } //let's do some sanity checks if(tcoffset >= mtdInfo.size) { tclen = 0; fprintf(stderr, "readflash: device \"%s\" is out of reach -- do nothing\n", device); } else if(tcoffset + tclen > mtdInfo.size) { tclen = mtdInfo.size - tcoffset; fprintf(stderr, "readflash: extends beyond the end of device \"%s\" -- size truncated to %#x\n", device,tclen); } //seek the read point and read from flash first,and then write to the memeory file lseek(fd,tcoffset,SEEK_SET); lseek(imagefd,0,SEEK_SET); while(read_conut < tclen) { count = read(fd,tcbuf,sizeof(tcbuf)); if(count <= 0) break; read_conut += count; count = write(imagefd,tcbuf,count); if(count <= 0) break; write_count +=count; } //do some sanity checks if(read_conut != write_count) { fprintf(stderr, "readflash:error when readsize is %lu,writesize is %lu", read_conut,write_count); close(fd); exit(1); } close(fd); return 0; } int erasesector(const char *device,unsigned long tcoffset,int quiet) { int fd; struct mtd_info_user mtdInfo; unsigned long sector_start = 0; struct erase_info_user mtdEraseInfo; fd = mtd_open(device, O_RDWR); if(fd < 0) { fprintf(stderr, "Could not open mtd device: %s\n", device); exit(1); } //get mtd information if(ioctl(fd, MEMGETINFO, &mtdInfo)) { fprintf(stderr, "Could not get MTD device info from %s\n", device); goto erasesectorerror; } fprintf(stderr, "tcoffset:0x%x,mtdInfo.size:0x%x size-1:%0x\n",tcoffset,mtdInfo.size,mtdInfo.erasesize - 1); //let's do some sanity checks if(tcoffset >= mtdInfo.size) { fprintf(stderr, "erasesector: device \"%s\" is out of reach -- exit(1)\n", device); goto erasesectorerror; } else if(tcoffset & (mtdInfo.erasesize - 1)) { fprintf(stderr, "erasesector: offset is not at the sector boundry\n"); goto erasesectorerror; } if(quiet < 2) fprintf(stderr, "enter real action ----- tcoffset:0x%x\n",tcoffset); sector_start = tcoffset & ( ~(mtdInfo.erasesize - 1)); //erase the sector if (!quiet) fprintf(stderr, "\b\b\b[e]"); mtdEraseInfo.start = sector_start; mtdEraseInfo.length = mtdInfo.erasesize; if (ioctl (fd,MEMERASE,&mtdEraseInfo) < 0) { fprintf(stderr, "erasesector:Erasing device failed: %s\n", device); goto erasesectorerror; } close(fd); return 0; erasesectorerror: close(fd); exit(1); } #endif void executeWifiDownOp(int mode) { FILE *fp = NULL; char buf[65] = {0}; char APOn[4] = {0}; char BssidNum[4] = {0}; char WDSSwitch[4] = {0}; char tmp[32] = {0}; int i; char wifipatch[32]; char wificmd[32]; char wifiwdscmd[32]; if(mode) { strcpy(wifipatch,"/etc/Wireless/WLAN_APOn_AC"); strcpy(wificmd,"ifconfig rai%d down"); strcpy(wifiwdscmd,"ifconfig wdsi%d down"); } else { strcpy(wifipatch,"/etc/Wireless/WLAN_APOn"); strcpy(wificmd,"ifconfig ra%d down"); strcpy(wifiwdscmd,"ifconfig wds%d down"); } fp = fopen(wifipatch, "r"); if(!fp){ printf("\ncan't open %s",wifipatch); for (i=0; i<8; i++) { sprintf(tmp, wificmd,i); system(tmp); } #ifdef TCSUPPORT_WLAN_WDS for (i=0; i<4; i++) { sprintf(tmp, wifiwdscmd,i); system(tmp); } #endif } else{ while(fgets(buf, 64, fp) != NULL){ if(strstr(buf, "APOn=") != NULL) sscanf(buf, "APOn=%s", APOn); else if(strstr(buf, "Bssid_num=") != NULL) sscanf(buf, "Bssid_num=%s", BssidNum); #ifdef TCSUPPORT_WLAN_WDS else if(strstr(buf, "WdsEnable=") != NULL) sscanf(buf, "WdsEnable=%s", WDSSwitch); #endif memset(buf,0,sizeof(buf)); } fclose(fp); if (!strcmp(APOn,"1")){ #ifdef TCSUPPORT_WLAN_WDS if (!strcmp(WDSSwitch,"1")){ for (i=0; i<4; i++) { sprintf(tmp, wifiwdscmd,i); system(tmp); } } #endif for (i=0; i ...] [ ...] \n\n" "The device is in the format of mtdX (eg: mtd4) or its label.\n" "mtd recognises these commands:\n" " unlock unlock the device\n" " erase erase all data on device\n" #ifdef TRENDCHIP " write |- write n bytes from offset of to device\n" #else " write |- write (use - for stdin) to device\n" #endif #ifdef TCSUPPORT_MTD_ENCHANCEMENT " writeflash write to n bytes from offset of \n" " readflash read n bytes from offset of to \n" " erasesector erase one sector from offset of \n" #endif #if defined(TCSUPPORT_MT7570) && !defined(TC_SDK_7_3_235_200) " bob get | - ( used to get bob info form flash)\n" " bob save | - ( used to save bob info into flash)\n" #endif "Following options are available:\n" " -q quiet mode (once: no [w] on writing,\n" " twice: no status messages)\n" " -r reboot after successful command\n" " -f force write without trx checks\n" " -e erase before executing the command\n\n" "Example: To write linux.trx to mtd1 labeled as linux and reboot afterwards\n" " mtd -r write linux.trx linux\n\n"); exit(1); } int main(int argc, char **argv) { int ch, i, boot, imagefd = -1, force, quiet, unlocked; char *erase[MAX_ARGS], *device; const char *imagefile = NULL; sigset_t mask; enum { CMD_ERASE, CMD_WRITE, #ifdef TCSUPPORT_MTD_ENCHANCEMENT CMD_READ, CMD_ERASESECTOR, #endif #if defined(TCSUPPORT_MT7570) && !defined(TC_SDK_7_3_235_200) CMD_BOB_GET, CMD_BOB_SET, #endif CMD_UNLOCK } cmd; #ifdef TRENDCHIP int offset; #endif #ifdef TCSUPPORT_MTD_ENCHANCEMENT int operateflag = 0; unsigned long tcoffset = 0; unsigned long tclen = 0; long tcfilelen = -1; #endif erase[0] = NULL; boot = 0; force = 0; buflen = 0; quiet = 0; /* To block all signal */ if(sigfillset(&mask) != 0) { printf("init and set signal flag fail\n"); return -1; } if(sigprocmask(SIG_SETMASK, &mask, NULL) != 0) { printf("set signal mask fail\n"); return -1; } while ((ch = getopt(argc, argv, "Ffrqe:")) != -1) switch (ch) { case 'F': quiet = 1; /* FALLTHROUGH */ case 'f': force = 1; break; case 'r': boot = 1; reboot_flag = 1; break; case 'q': quiet++; break; case 'e': i = 0; while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS)) i++; erase[i++] = optarg; if (i < MAX_ARGS) erase[i] = NULL; //COV, CID 69053 break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc < 2) usage(); if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) { cmd = CMD_UNLOCK; device = argv[1]; } else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) { cmd = CMD_ERASE; device = argv[1]; //#ifdef TRENDCHIP #if defined (TRENDCHIP) || defined (TCSUPPORT_MTD_ENCHANCEMENT) } else if ((strcmp(argv[0], "write") == 0) #ifdef TCSUPPORT_MTD_ENCHANCEMENT ||(strcmp(argv[0], "writeflash") == 0) #endif ) { #ifdef TCSUPPORT_MTD_ENCHANCEMENT if(strcmp(argv[0], "writeflash") == 0) operateflag = 1;//use new mtd write function and don't do check #endif #else } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) { #endif cmd = CMD_WRITE; if (strcmp(argv[1], "-") == 0) { imagefile = ""; imagefd = 0; } else { imagefile = argv[1]; if ((imagefd = open(argv[1], O_RDONLY)) < 0) { fprintf(stderr, "Couldn't open image file: %s!\n", imagefile); exit(1); } } #ifdef TCSUPPORT_MTD_ENCHANCEMENT if(!operateflag) { #endif #ifdef TRENDCHIP if(argc == 3) device = argv[2]; else if(argc == 5){ n_bytes = atoi(argv[2]); offset = atoi(argv[3]); device = argv[4]; fprintf(stderr, "mtd:n_bytes=%d offset=%d\n", n_bytes, offset); /* ignore the offset bytes */ while(1){ if( offset <= BUFSIZE ){ read(imagefd, buf, offset); break; } else{ read(imagefd, buf, BUFSIZE); offset -= BUFSIZE; } } } else usage(); #else device = argv[2]; #endif /* check trx file before erasing or writing anything */ if (!force) if (!image_check(imagefd, device)) { if ((quiet < 2) || !force) fprintf(stderr, "TRX check failed!\n"); if (!force){ fclose(imagefd); exit(1); } } if (!mtd_check(device)) { fprintf(stderr, "Can't open device for writing!\n"); fclose(imagefd); exit(1); } #ifdef TCSUPPORT_MTD_ENCHANCEMENT } else { if(argc == 5) { tcfilelen = getFileSize(argv[1]); tclen = atoi(argv[2]); tcoffset = atoi(argv[3]); device = argv[4]; if (quiet < 2) fprintf(stderr, "mtd[writeflash]:device=%s tclen=%lu tcoffset=%lu tcfilelen =%d\n",device, tclen, tcoffset,tcfilelen); #if 0 if(tcfilelen < tclen) { fprintf(stderr, "operate size is over file max size!so truncate size to file max size\n"); tclen = tcfilelen; } #endif } else { usage();//in this function ,call exit(1),so here not call exit again } if (!mtd_check(device)) { fprintf(stderr, "Can't open device for writing!\n"); fclose(imagefd); exit(1); } } #endif } #ifdef TCSUPPORT_MTD_ENCHANCEMENT else if((strcmp(argv[0], "readflash") == 0)) { if(argc == 5 || argc == 3) { cmd = CMD_READ; imagefile = argv[1]; if ((imagefd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC)) < 0) { fprintf(stderr, "Couldn't open image file: %s!\n", imagefile); exit(1); } if(argc == 5) { tclen = atoi(argv[2]); tcoffset = atoi(argv[3]); device = argv[4]; } else { tclen = 0; tcoffset = 0; device = argv[2]; } if (quiet < 2) fprintf(stderr, "mtd[readflash]:device=%s tclen=%d tcoffset=%d\n",device, tclen, tcoffset); } else { usage();//in this function ,call exit(1),so here not call exit again } } else if((strcmp(argv[0], "erasesector") == 0)) { if(argc == 3) { cmd = CMD_ERASESECTOR; tcoffset = atoi(argv[1]); device = argv[2]; } else { usage();//in this function ,call exit(1),so here not call exit again } } #endif #if defined(TCSUPPORT_MT7570) && !defined(TC_SDK_7_3_235_200) else if((strcmp(argv[0], "bob") == 0)) { device = MTD_BOB_DEVICE; tcoffset = BOB_RA_OFFSET; tclen = BOB_RA_SIZE; if((strcmp(argv[1], "save") == 0)) { /* this function use to set bob to flash */ cmd = CMD_BOB_SET; if(argc == 3){ imagefile = argv[2]; } else if (argc == 2) { imagefile = MTD_BOB_DEFAULT_FILE; } else { usage();//in this function ,call exit(1),so here not call exit again } if ((imagefd = open(imagefile, O_RDONLY)) < 0) { fprintf(stderr, "Couldn't open image file: %s!\n", imagefile); //close(imagefd); exit(1); } if (!mtd_check(device)) { fprintf(stderr, "Can't open device for writing!\n"); close(imagefd); exit(1); } fprintf(stderr, "OPEN file %s fd = %d!\n",imagefile,imagefd); if(!bob_check(imagefd)) { fprintf(stderr, "BOB file is error\n"); close(imagefd); exit(1); } } else if((strcmp(argv[1], "get") == 0)) { /* this function use to get bob info to an designated file */ cmd = CMD_BOB_GET; if(argc == 3){ imagefile = argv[2]; } else if (argc == 2) { imagefile = MTD_BOB_DEFAULT_FILE; } else { usage();//in this function ,call exit(1),so here not call exit again } if ((imagefd = open(imagefile, O_RDWR | O_CREAT | O_TRUNC)) < 0) { fprintf(stderr, "Couldn't open image file: %s!\n", imagefile); exit(1); } } else { usage();//in this function ,call exit(1),so here not call exit again } } #endif else { usage(); } sync(); i = 0; unlocked = 0; while (erase[i] != NULL #ifdef TCSUPPORT_MTD_ENCHANCEMENT && !operateflag #endif ) { if (quiet < 2) fprintf(stderr, "Unlocking %s ...\n", erase[i]); mtd_unlock(erase[i]); if (quiet < 2) fprintf(stderr, "Erasing %s ...\n", erase[i]); mtd_erase(erase[i]); if (strcmp(erase[i], device) == 0) /* this means that is unlocked and erased */ unlocked = 1; i++; } if (!unlocked) { if (quiet < 2) fprintf(stderr, "Unlocking %s ...\n", device); mtd_unlock(device); } switch (cmd) { case CMD_UNLOCK: break; case CMD_ERASE: if (unlocked) { fprintf(stderr, "Already erased: %s\n", device); break; } if (quiet < 2) fprintf(stderr, "Erasing %s ...\n", device); mtd_erase(device); break; case CMD_WRITE: if (quiet < 2) fprintf(stderr, "Writing from %s to %s ... \n", imagefile, device); #ifdef TCSUPPORT_MTD_ENCHANCEMENT if(!operateflag){ if (reboot_flag) { system("killall -9 tcwdog"); system("killall -9 boa"); system("killall -9 cfg_manager"); system("killall -9 pppd"); system("killall -9 br2684ctl"); #ifdef TCSUPPORT_WLAN executeWifiDownOp(0); #endif #ifdef TCSUPPORT_WLAN_AC executeWifiDownOp(1); #endif } mtd_write(imagefd, device, quiet, (unlocked == 0)); } else writeflash(imagefd,device ,tcoffset, tclen,quiet); #else mtd_write(imagefd, device, quiet, (unlocked == 0)); #endif if (quiet < 2) fprintf(stderr, "\n"); break; #ifdef TCSUPPORT_MTD_ENCHANCEMENT case CMD_READ: if (quiet < 2) fprintf(stderr, "Reading from %s to %s ... \n",device ,imagefile); readflash(imagefd, device,tcoffset, tclen); break; case CMD_ERASESECTOR: if (quiet < 2) fprintf(stderr, "Erase one sector from 0x%0x of %s ... \n",tcoffset,device); erasesector(device,tcoffset,quiet); break; #endif #if defined(TCSUPPORT_MT7570) && !defined(TC_SDK_7_3_235_200) case CMD_BOB_GET: fprintf(stderr, "Doing bob get function , get bob info to %s \n",imagefile); readflash(imagefd, device,tcoffset, tclen); lseek(imagefd,0,SEEK_SET); if(!bob_check(imagefd)) { fprintf(stderr, "BOB file is error, use old mode \n"); readflash(imagefd, device,BOB_RA_OFFSET_OLD_MODE, tclen); lseek(imagefd,0,SEEK_SET); if(!bob_check(imagefd)){ fprintf(stderr, "OLD mode still error use current value \n"); readflash(imagefd, device,tcoffset, tclen); } } break; case CMD_BOB_SET: fprintf(stderr, "Doing bob set function set %s bob info to flash \n",imagefile); #ifdef TCSUPPORT_MTD_ENCHANCEMENT writeflash(imagefd,device ,tcoffset, tclen,quiet); fprintf(stderr, "writeflash(%d, %s,%d, %d,%d); \n",imagefd,device ,tcoffset, tclen,quiet); #else mtd_write(imagefd, device, quiet, (unlocked == 0)); fprintf(stderr, "mtd_write(%d, %s,%d, %d); \n",imagefd,device ,quiet,(unlocked == 0)); #endif fprintf(stderr, "Doing bob save function save bob info from %s \n",imagefile); break; #endif default: if (quiet < 2) fprintf(stderr, "unknown cmd type!\n"); break; } sync(); close(imagefd); if (boot) { if (quiet < 2) fprintf(stderr, "\nRebooting ... "); fflush(stdout); fflush(stderr); syscall(SYS_reboot,LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART,NULL); } return 0; }