everything is a package. so is mtd now
authorwbx <wbx@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Thu, 21 Jul 2005 00:27:08 +0000 (00:27 +0000)
committerwbx <wbx@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Thu, 21 Jul 2005 00:27:08 +0000 (00:27 +0000)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@1513 3c298f89-4303-0410-b956-a3cf2f4a3e73

package/Config.in
package/Makefile
package/mtd/Config.in [new file with mode: 0644]
package/mtd/Makefile [new file with mode: 0644]
package/mtd/ipkg/mtd.control [new file with mode: 0644]
package/mtd/mtd.c [new file with mode: 0644]

index bd80720..93e55e7 100644 (file)
@@ -8,6 +8,7 @@ source "package/bridge/Config.in"
 source "package/dnsmasq/Config.in"
 source "package/ipkg/Config.in"
 source "package/iptables/Config.in"
+source "package/mtd/Config.in"
 
 comment "Applications"
 source "package/haserl/Config.in"
index 45998e9..8a54481 100644 (file)
@@ -75,6 +75,7 @@ package-$(BR2_PACKAGE_MICROPERL) += microperl
 package-$(BR2_PACKAGE_MINI_HTTPD) += mini_httpd
 package-$(BR2_PACKAGE_MINI_SENDMAIL) += mini_sendmail
 package-$(BR2_PACKAGE_MONIT) += monit
+package-$(BR2_PACKAGE_MTD) += mtd
 package-$(BR2_PACKAGE_MYSQL) += mysql
 package-$(BR2_PACKAGE_NCURSES) += ncurses
 package-$(BR2_PACKAGE_NDISC) += ndisc
diff --git a/package/mtd/Config.in b/package/mtd/Config.in
new file mode 100644 (file)
index 0000000..df0b9bf
--- /dev/null
@@ -0,0 +1,6 @@
+config BR2_PACKAGE_MTD
+       tristate "mtd - update utility for trx firmware images"
+       default y
+       help
+        update utility for trx firmware images.
+
diff --git a/package/mtd/Makefile b/package/mtd/Makefile
new file mode 100644 (file)
index 0000000..4975469
--- /dev/null
@@ -0,0 +1,26 @@
+# $Id$
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME := mtd
+PKG_RELEASE := 1
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(TOPDIR)/package/rules.mk
+
+$(eval $(call PKG_template,MTD,$(PKG_NAME),$(PKG_RELEASE),$(ARCH)))
+
+$(PKG_BUILD_DIR)/.prepared:
+       mkdir -p $@
+       touch $@
+
+$(PKG_BUILD_DIR)/.built:
+       $(TARGET_CC) $(TARGET_CFLAGS) -o $(PKG_BUILD_DIR)/mtd mtd.c
+       touch $@
+
+$(IPKG_MTD): 
+       install -d -m0755 $(IDIR_MTD)/sbin
+       install -m0755 $(PKG_BUILD_DIR)/mtd $(IDIR_MTD)/sbin
+       $(RSTRIP) $(_IPK_DIR)/sbin/*
+       $(IPKG_BUILD) $(IDIR_MTD) $(PACKAGE_DIR)
diff --git a/package/mtd/ipkg/mtd.control b/package/mtd/ipkg/mtd.control
new file mode 100644 (file)
index 0000000..102bd70
--- /dev/null
@@ -0,0 +1,6 @@
+Package: mtd
+Priority: optional
+Section: sys
+Maintainer: Felix Fietkau <nbd@vd-s.ath.cx>
+Source: buildroot internal
+Description: Tool for modifying the flash chip
diff --git a/package/mtd/mtd.c b/package/mtd/mtd.c
new file mode 100644 (file)
index 0000000..74949fd
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * mtd - simple memory technology device manipulation tool
+ *
+ * Copyright (C) 2005 Waldemar Brodkorb <wbx@dass-it.de>,
+ *                   Felix Fietkau <nbd@vd-s.ath.cx>
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ * code is based on linux-mtd example code
+ */
+
+#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 <string.h>
+
+#include <linux/mtd/mtd.h>
+
+#define TRX_MAGIC       0x30524448      /* "HDR0" */
+#define BUFSIZE (10 * 1024)
+#define MAX_ARGS 8
+
+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 */
+};
+
+int
+trx_check(const char *trxfile, const char *mtd)
+{
+       struct mtd_info_user mtdInfo;
+       int trxfd, fd;
+       size_t count;
+       struct trx_header trx;
+       struct stat trxstat;
+
+       trxfd = open(trxfile,O_RDONLY); 
+       if(trxfd < 0) {
+               fprintf(stderr, "Could not open trx image: %s\n", trxfile);
+               exit(1);
+       }
+
+       if (fstat(trxfd,&trxstat) < 0) {
+               fprintf(stderr, "Could not get trx image file status: %s\n", trxfile);
+               close(trxfd);
+               exit(1);
+       }
+
+       count = read(trxfd, &trx, sizeof(struct trx_header));
+       if (count < sizeof(struct trx_header)) {
+               fprintf(stderr, "Could not trx header, file too small (%ld bytes)\n", count);
+               close(trxfd);
+               exit(1);
+       }
+
+       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");
+               close(trxfd);
+               exit(1);
+       }
+       
+       lseek(trxfd, 0, SEEK_SET);
+
+       /* check if image fits to mtd device */
+
+       fd = mtd_open(mtd, O_RDWR);
+       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);
+       }
+               
+       if(mtdInfo.size < trxstat.st_size) {
+               fprintf(stderr, "Image too big for partition: %s\n", mtd);
+               close(trxfd);
+               close(fd);
+               exit(1);
+       }       
+       
+       printf("Writing %s to %s ...\n", trxfile, mtd);
+
+       close(fd);
+
+       return(trxfd);
+}
+
+int
+mtd_unlock(const char *mtd)
+{
+       int fd;
+       struct mtd_info_user mtdInfo;
+       struct erase_info_user mtdLockInfo;
+
+       fd = mtd_open(mtd, O_RDWR);
+       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);
+       }
+
+       printf("Unlocking %s ...\n", mtd);
+       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)) {
+                               snprintf(dev, sizeof(dev), "/dev/mtd/%d", i);
+                               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);
+       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);
+       }
+
+       printf("Erasing %s ...\n", mtd);
+       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;
+
+}
+
+int
+mtd_write(int trxfd, const char *mtd)
+{
+       int fd,i;
+       size_t result,size,written;
+       struct mtd_info_user mtdInfo;
+       struct erase_info_user mtdEraseInfo;
+       unsigned char src[BUFSIZE],dest[BUFSIZE];
+       struct stat trxstat;
+
+       if (fstat(trxfd,&trxstat) < 0) {
+               fprintf(stderr, "Could not get trx image file status\n");
+               close(trxfd);
+               exit(1);
+       }
+
+       fd = mtd_open(mtd, O_RDWR);
+       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.start = 0;
+       mtdEraseInfo.length = trxstat.st_size & ~(mtdInfo.erasesize -1);
+       if(trxstat.st_size % mtdInfo.erasesize) mtdEraseInfo.length += mtdInfo.erasesize;
+
+       /* erase the chunk */
+       if (ioctl (fd,MEMERASE,&mtdEraseInfo) < 0) {
+               fprintf(stderr, "Erasing mtd failed: %s\n", mtd);
+               exit(1);
+       }
+       
+       size = trxstat.st_size;
+       i = BUFSIZE;
+       written = 0;
+
+       while (size) {
+               if (size < BUFSIZE) i = size;
+               read(trxfd,src,i);
+               result = write(fd,src,i);
+               if (i != result) {
+                       if (result < 0) {
+                               fprintf(stderr,"Error while writing image");
+                               exit(1);
+                       }
+                       fprintf(stderr,"Error writing image");
+                       exit(1);
+               }
+               written += i;
+               size -= i;
+       }
+       
+       return 0;
+}
+
+void usage(void)
+{
+       printf("Usage: mtd [<options> ...] <command> [<arguments> ...] <device>\n\n"
+       "The device is in the format of mtdX (eg: mtd4) or its label.\n"
+       "mtd recognizes these commands:\n"
+       "       unlock                  unlock the device\n"
+       "       erase                   erase all data on device\n"
+       "       write <imagefile>       write imagefile to device\n"
+       "Following options are available:\n"
+       "       -r                      reboot after successful command\n"
+       "       -e <device>             erase <device> before executing the command\n\n"
+       "Example: To write linux.trx to mtd4 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, unlock, trxfd;
+       char *erase[MAX_ARGS], *device;
+       enum {
+               CMD_ERASE,
+               CMD_WRITE,
+               CMD_UNLOCK
+       } cmd;
+       
+       erase[0] = NULL;
+       boot = 0;
+
+       while ((ch = getopt(argc, argv, "re:")) != -1)
+               switch (ch) {
+                       case 'r':
+                               boot = 1;
+                               break;
+                       case 'e':
+                               i = 0;
+                               while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS))
+                                       i++;
+                                       
+                               erase[i++] = optarg;
+                               erase[i] = NULL;
+                               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];
+       } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) {
+               cmd = CMD_WRITE;
+               device = argv[2];
+               /* check trx file before erasing or writing anything */
+               trxfd = trx_check(argv[1], device);
+       } else {
+               usage();
+       }
+
+       sync();
+
+       i = 0;
+       while (erase[i] != NULL) {
+               mtd_unlock(erase[i]);
+               mtd_erase(erase[i]);
+               i++;
+       }
+       
+       mtd_unlock(device);
+
+       switch (cmd) {
+               case CMD_UNLOCK:
+                       break;
+               case CMD_ERASE:
+                       mtd_erase(device);
+                       break;
+               case CMD_WRITE:
+                       mtd_write(trxfd, device);
+                       break;
+       }
+
+       if (boot)
+               kill(1, 15); // send SIGTERM to init for reboot
+
+       return 0;
+}