OpenWrt Forum Archive

Topic: Could not open mtd device: linux

The content of this topic has been archived between 13 Apr 2018 and 17 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

I'm using a forked version of Kamikaze for my Compex WP54AG. I tried to upgrade my firmware (both via ssh and webif) and I got this error.

Upgrading firmware, please wait ...

Could not open mtd device: linux
Can't open device for writing!

I am not asking for support, because I think the problem to be due to the instability of this "unofficial" firmware.
I just would like to understand what this error means and in which cases it usually occurs. It looks like it's not possible to overwrite the firmware partitions for some unknown and mysterious reasons smile

(Last edited by ggp81 on 26 Jun 2007, 18:57)

Call this a "me too" post.  I did however manage to get the SVN head of OpenWRT to run on the box (not the r7118 that Compex "supports").

I am having this same error when trying to go back to my original firmware:

Could not open mtd device: linux
Can't open device for writing!

Is the device name called something else in Kamikaze?

I get this error from the command line and from the Upgrade option via the web interface.

The "linux" in "mtd -r write something linux" refers to the mtd partition named "linux".

See /proc/mtd.

I can't think of any OpenWrt releases that don't specify a linux partition; it's likely that you're using something other than what's provided on

Yeah, I'm trying to go back to the original firmware on a Powerstation 2 unit.

Yesterday I installed the latest OpenWRT on the unit and everything is working OK, but want to go back to the original Powersatation .bin firmware and the update option gives me that error and won't flash the firmware to the unit.

Compex's fork of OpenWRT does use the following as a partition table:

0x00000000-0x00010000 : "MyLoader"
0x00010000-0x00020000 : "Partition Table"
0x00020000-0x00030000 : "lzma loader"
0x00030000-0x00100000 : "kernel"
0x00100000-0x00400000 : "rootfs"
0x002f0000-0x00400000 : "rootfs_data"

After the system is up and running, the mount table looks like:

Filesystem                Size      Used Available Use% Mounted on
none                      6.6M     16.0k      6.6M   0% /tmp
tmpfs                   512.0k         0    512.0k   0% /dev
/dev/mtdblock5            1.1M    196.0k    892.0k  18% /jffs
/jffs                     1.9M      1.9M         0 100% /

Given that layout, does anybody have any idea how one is supposed to reflash the box?  Would it be something like using mtd to put the .trx onto "rootfs", and erasing "rootfs_data" ?

Imagix wrote:

Compex's fork of OpenWRT does use the following as a partition table:

0x00000000-0x00010000 : "MyLoader"
0x00010000-0x00020000 : "Partition Table"
0x00020000-0x00030000 : "lzma loader"
0x00030000-0x00100000 : "kernel"
0x00100000-0x00400000 : "rootfs"
0x002f0000-0x00400000 : "rootfs_data"

Yes, that's the same for me.
This is the proc/mtd for an official OpenWrt

root@OpenWrt:~# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00040000 00010000 "cfe"
mtd1: 003b0000 00010000 "linux"
mtd2: 001e1c00 00010000 "rootfs"
mtd3: 00010000 00010000 "nvram"
mtd4: 00150000 00010000 "OpenWrt"

Maybe we just have to type: mtd -r write firmware.bin kernel

I am having the same issue getting the original firmware back on my powerstation 2... Any help would be appreciated.

Here is the diff file between Compex drivers/mtd/myloader.c and the official one for adm5120.

< static char *myloader_partitions_name[MYLO_MAX_PARTITIONS] =
< {"lzma loader", "kernel", "rootfs", "reserved0", "reserved1", "reserved2", "reserved3", "reserved4"};
<   sprintf(names, myloader_partitions_name[i]);
>   sprintf(names, "partition%d", i);

At Compex they suggest me to merge "lzma loader", "kernel" and "rootfs" partitions.

(Last edited by ggp81 on 5 Jul 2007, 13:31)

ggp81 wrote:

At Compex they suggest me to merge "lzma loader", "kernel" and "rootfs" partitions.

at now I have no idea about how to do that sad

Me neither... why cant anything be easy like it was in white russian?

Great News! its actually a lot simpler than I thought and remember... if you are looking to go back to the PS firmware, all you need to do is open up the case on the back of the powerstation, so you can see the internal LED's. then pull the power for a few seconds, plug it back in, and then hold the reset button until the "rdy" LED lights up in the top right corner... then go over to your computer, make sure you can ping the PS, then use a tftp program to send the file to the PS. 7 mins later and no more kamikaze!

I used a program called tftp2.exe to do this. very simple.

My aim now is changing the table of partitions to let mtd command (mtd -r write firmware.bin linux) work correctly. I studied some of the WP54 OpenWrt source code (which is same as the official one, except for some few lines of myloader.c). This is what I found.

Referring to trunk/target/linux/adm5120-2.6/files/drivers/mtd/myloader.c, these appear to be the lines dealing with partitions.

static char *myloader_partitions_name[MYLO_MAX_PARTITIONS] =
{"lzma loader", "kernel", "rootfs", "reserved0", "reserved1", "reserved2", "reserved3", "reserved4"};

int parse_myloader_partitions(struct mtd_info *master,
            struct mtd_partition **pparts,
            unsigned long origin)
    struct mylo_partition_table *tab;
    struct mylo_partition *part;
    struct mtd_partition *mtd_parts;
    struct mtd_partition *mtd_part;


    mtd_parts = kzalloc((num_parts*sizeof(*mtd_part) + num_parts*NAME_LEN_MAX),

    if (!mtd_parts) {
        ret = -ENOMEM;
        goto out_free_buf;

    mtd_part = mtd_parts;
    names = (char *)&mtd_parts[num_parts];

    strncpy(names, NAME_MYLOADER, NAME_LEN_MAX-1);
    mtd_part->name = names;
    mtd_part->offset = 0;
    mtd_part->size = blocklen;
    names += NAME_LEN_MAX;

    strncpy(names, NAME_PARTITION_TABLE, NAME_LEN_MAX-1);
    mtd_part->name = names;
    mtd_part->offset = blocklen;
    mtd_part->size = blocklen;
    names += NAME_LEN_MAX;

    for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
        part = &tab->partitions[i];

        if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)

        sprintf(names, myloader_partitions_name[i]);
        mtd_part->name = names;
        mtd_part->offset = le32_to_cpu(part->addr);
        mtd_part->size = le32_to_cpu(part->size);
        names += NAME_LEN_MAX;

mtd_part is a pointer to a mtd_partition class, which is defined in trunk/toolchain_build_mipsel/linux/include/linux/mtd/partitions.h

struct mtd_partition {
    char *name;            /* identifier string */
    u_int32_t size;            /* partition size */
    u_int32_t offset;        /* offset within the master MTD space */
    u_int32_t mask_flags;        /* master MTD flags to mask out for this partition */
    struct nand_ecclayout *ecclayout;    /* out of band layout for this partition (NAND only)*/
    struct mtd_info **mtdp;        /* pointer to store the MTD object */

To let mtd command (mtd -r write firmware.bin linux) work correctly, I think I would merge "lzma loader" and "kernel" partitions into a "linux" one.

static char *myloader_partitions_name[MYLO_MAX_PARTITIONS] =
{"linux", "rootfs", "reserved0", "reserved1", "reserved2", "reserved3", "reserved4", "reserved5"};

My only problem now is: how can I assign the right value of start point and size of the partitions?
I think the key is in those lines.

        mtd_part->offset = le32_to_cpu(part->addr);
        mtd_part->size = le32_to_cpu(part->size);

part is a pointer to a mylo_partition class, which is defined in trunk/target/linux/adm5120-2.6/files/include/asm-mips/mach-adm5120/myloader.h as following:

struct mylo_partition {
    uint16_t    flags;    /* partition flags */
    uint16_t    type;    /* type of the partition */
    uint32_t    addr;    /* relative address of the partition from the
                   flash start */
    uint32_t    size;    /* size of the partition in bytes */
    uint32_t    param;    /* if this is the active partition, the
                   MyLoader load code to this address */

And an array of this struct is included into a mylo_partition_table

struct mylo_partition_table {
    uint32_t    magic;    /* must be MYLO_MAGIC_PARTITIONS */
    uint32_t    res0;    /* unknown/unused */
    uint32_t    res1;    /* unknown/unused */
    uint32_t     res2;    /* unknown/unused */
    struct mylo_partition partitions[MYLO_MAX_PARTITIONS];

So my only question is how to correctly inizialize this structure with the right values of the partitions.
Since OpenWrt is an open source software, I hope someone to have the way, but above all the time to give me just a little hint to solve my problem.
Any help would be strongly appreciated.
Thank you in advance and sorry for the disturb.

(Last edited by ggp81 on 11 Jul 2007, 12:11)

According to trunk/target/linux/adm5120-2.6/files/drivers/mtd/maps/adm5120_mtd.c, partitions are created after bootloader and nvram sizes and offsets are checked.
This file works on standard OpenWrt table partition (cfe, linux, rootfs, nvram, rootfs-data). I just have to understand how can it be linked to the edited myloader.c, with the new table partition

struct mtd_partition * __init
init_mtd_partitions(struct mtd_info *mtd, size_t size)
    int cfe_size;

    if ((cfe_size = find_cfe_size(mtd,size)) < 0)
        return NULL;

    /* boot loader */
    adm5120_cfe_parts[0].offset = 0;
    adm5120_cfe_parts[0].size   = cfe_size;

    /* nvram */
    if (cfe_size != 384 * 1024) {
        adm5120_cfe_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
        adm5120_cfe_parts[3].size   = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
    } else {
        /* nvram (old 128kb config partition on netgear wgt634u) */
        adm5120_cfe_parts[3].offset = adm5120_cfe_parts[0].size;
        adm5120_cfe_parts[3].size   = ROUNDUP(NVRAM_SPACE, mtd->erasesize);

    /* linux (kernel and rootfs) */
    if (cfe_size != 384 * 1024) {
        adm5120_cfe_parts[1].offset = adm5120_cfe_parts[0].size;
        adm5120_cfe_parts[1].size   = adm5120_cfe_parts[3].offset -
    } else {
        /* do not count the elf loader, which is on one block */
        adm5120_cfe_parts[1].offset = adm5120_cfe_parts[0].size +
            adm5120_cfe_parts[3].size + mtd->erasesize;
        adm5120_cfe_parts[1].size   = size -
            adm5120_cfe_parts[0].size -
            (2*adm5120_cfe_parts[3].size) -

    /* find and size rootfs */
    if (find_root(mtd,size,&adm5120_cfe_parts[2])==0) {
        adm5120_cfe_parts[2].size = size - adm5120_cfe_parts[2].offset -

    return adm5120_cfe_parts;

ggp81 any update ?

im stuck on this same thing.


I'm another person looking to rewrite the flash from within OpenWRT w/ mtd.  Have you tried using the svn code yet?  They're doing a bunch of work on the adm5120 platform.  On the current code set, if I build the image according to Compex's system, it won't boot anymore... but the stock image built by OpenWRT will....

At now I don't need so much any more this function.
Imagix you are right! I think pre-7.07 to be totally compatible with WP54 (I didn't test it). Official 7.07 will be (according to Compex), so I am waiting for that stable release.

I have Linksys WRT 160NL and OpenWRT trunk from … squashfs.b

Partitions are

root@OpenWrt:/# df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/root                 1.3M      1.3M         0 100% /rom
tmpfs                    14.4M      3.0M     11.4M  21% /tmp
tmpfs                   512.0K         0    512.0K   0% /dev
/dev/mtdblock3            5.2M    292.0K      4.9M   5% /jffs
mini_fo:/jffs             1.3M      1.3M         0 100% /

root@OpenWrt:/# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00040000 00010000 "u-boot"
mtd1: 00140000 00010000 "kernel"
mtd2: 00660000 00010000 "rootfs"
mtd3: 00530000 00010000 "rootfs_data"
mtd4: 00010000 00010000 "nvram"
mtd5: 00010000 00010000 "art"
mtd6: 007a0000 00010000 "firmware"

Have upload to Linksys /tmp and renamed

mv openwrt-ar71xx-wrt160nl-squashfs.bin openwrt-ar71xx-wrt160nl-squashfs.trx

What is the right command for "mtd", "linux" is not there

root@OpenWrt:/tmp# mtd write openwrt-ar71xx-wrt160nl-squashfs.trx linux
Could not open mtd device: linux
Can't open device for writing!

Then I write

root@OpenWrt:/tmp#mtd -r write openwrt-ar71xx-wrt160nl-squashfs.trx kernel
Unlocking kernel ...
Writing from openwrt-ar71xx-wrt160nl-squashfs.trx to kernel ...  [e]Failed to erase block

What ist right command to successfully flash the Router?

So can you please tell the method to reflash the router.

When i tried "mtd -r write openwrt-atheros-ubnt2-squashfs.trx linux", i am getting the following errors

"Could not open mtd device: linux
Can't open device for writing!"

The cat /proc/mtd output is

dev:    size   erasesize  name
mtd0: 00030000 00010000 "RedBoot"
mtd1: 000d0000 00010000 "kernel"
mtd2: 002e0000 00010000 "rootfs"
mtd3: 00130000 00010000 "rootfs_data"
mtd4: 0000f000 0000f000 "FIS directory"
mtd5: 00001000 00001000 "RedBoot config"
mtd6: 00010000 00010000 "boardconfig"

If i do  mtd -r write Bullet2-v3.5.1.build4631.bin rootfs i am getting

Unlocking rootfs ...
Writing from Bullet2-v3.5.1.build4631.bin to rootfs ...  [e]Failed to erase block

Could any of you help me to fix this problem of reflashing the bullet as i am stuck in this.


sysupgrade openwrt-atheros-combined-squashfs.bin

Thank you Jow, your reply helped me to find the solution

I got the solution for my problem and i have explained it below

When we make the binaries using the command "make" (or make V=99),
openwrt-atheros-combined.squashfs.img will be created in /bin/atheros/ along with other binaries.

copy this to the /tmp folder in the router, and execute the command
"sysupgrade openwrt-atheros-combined.squashfs.img "

I have attached the logs which i got after executing  the command

root@OpenWrt:/tmp# /sbin/sysupgrade openwrt-atheros-combined.squashfs.img
Saving config files...
Switching to ramdisk...
mount: mounting mini_fo:/jffs on /mnt failed: Function not implemented
Performing system upgrade...
Unlocking kernel ...
Unlocking rootfs ...
Writing from <stdin> to kernel ...     
Writing from <stdin> to rootfs ...     
Appending jffs2 data from /tmp/sysupgrade.tgz to rootfs...
Updating FIS table...
Rebooting ...

Now once the router is up after the reboot, you will be able to connect to it using the ip you have configured or else with

You can also upgrade the firmware from the web browser;stok … m/upgrade/
Just browse and select the openwrt-atheros-combined.squashfs.img file.
It will upgrade and reboot. If you have changed the ip address then use the new ip after upgrade

Thank you for all your help

i don't how can i flash my original .bin...
what is make command?
what is /sbin/sysupgrade openwrt-atheros-combined.squashfs.img???  how do i get this???

You can flash the .bin file using tftp … ns/Bullets

make command is for compiling and generating the .bin file manually.
The .img file and .bin files will be generated once we execute the make command.

If you don't want to generate the files, you can get all the required files from the repository and flash it.

i can only access through ssh... no telnet, no tftp, no web (luci)
that's i want to remove Openwrt... it worked well for only 6h:)

Thanks for helping!!!

(Last edited by maxidvd on 19 Oct 2010, 20:21)

up, and...
how can i put the file into the router with scp?