1
1
Files
zyxel-vmg8825_b50b-cfw/package/mtd-econet/src/mtd.c
T
2026-04-17 18:33:03 +02:00

1518 lines
35 KiB
C

/*
* mtd - simple memory technology device manipulation tool
*
* Copyright (c) 2006, 2007 Thorsten Glaser <tg@freewrt.org>
* Copyright (C) 2005 Waldemar Brodkorb <wbx@freewrt.org>,
* Felix Fietkau <nbd@openwrt.org>
*
* 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 <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <errno.h>
#include <error.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/reboot.h>
#include <sys/syscall.h>
#include <string.h>
#include <linux/reboot.h>
#include <linux/types.h>
#include <sys/file.h>
#include <signal.h>
#include <linux/version.h>
#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 <mtd/mtd-user.h>
#else
#include <linux/mtd/mtd.h>
#endif
#ifdef TCSUPPORT_INIC_HOST
#include <linux/mtd/fttdp_inic.h>
#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<atoi(BssidNum); i++) {
sprintf(tmp, wificmd,i);
system(tmp);
}
}
}
}
void
usage(void)
{
fprintf(stderr, "Usage: mtd [<options> ...] <command> [<arguments> ...] <device>\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 <imagefile>|- <n> <offset> write n bytes from offset of <imagefile> to device\n"
#else
" write <imagefile>|- write <imagefile> (use - for stdin) to device\n"
#endif
#ifdef TCSUPPORT_MTD_ENCHANCEMENT
" writeflash <imagefile> <n> <offset> <device> write <imagefile> to n bytes from offset of <device>\n"
" readflash <imagefile> <n> <offset> <device> read n bytes from offset of <device> to <imagefile>\n"
" erasesector <offset> <device> erase one sector from offset of <device>\n"
#endif
#if defined(TCSUPPORT_MT7570) && !defined(TC_SDK_7_3_235_200)
" bob get <imagefile> | - ( used to get bob info form flash)\n"
" bob save <imagefile> | - ( 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 <device> erase <device> 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 = "<stdin>";
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 <device> 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;
}