关于直接编写应用程序读写/dev/mtd0 或者 /dev/mtdblock0的问题。

时间:2022-03-20 11:17:34
关于直接编写应用程序读写/dev/mtd0 或者 /dev/mtdblock0的问题。

开发板的Linux环境:
# uname -a
Linux 192.168.102.213 2.6.12-4.2-brcmstb #73 Tue Apr 14 16:06:50 CST 2009 7403a0 unknown

我的开发板的Nor flash分区情况是
# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 01800000 00020000 "rootfs"
mtd1: 00200000 00020000 "vmlinux"
mtd2: 00400000 00020000 "config"
mtd3: 00080000 00020000 "splash"
mtd4: 00080000 00020000 "cfe"
mtd5: 00000080 00020000 "mactype"
mtd6: 00040000 00020000 "nvram"
mtd7: 00040000 00020000 "feature"

# ls /dev/mtd* -al
crwxr-xr-x    1 nobody   nobody    90,   0 Mar  2  2009 /dev/mtd0
crwxr-xr-x    1 nobody   nobody    90,   2 Mar  2  2009 /dev/mtd1
crwxr-xr-x    1 nobody   nobody    90,   4 Mar  2  2009 /dev/mtd2
crwxr-xr-x    1 nobody   nobody    90,   6 Mar  2  2009 /dev/mtd3
crwxr-xr-x    1 nobody   nobody    90,   8 Mar  2  2009 /dev/mtd4
crwxr-xr-x    1 nobody   nobody    90,  10 Mar  2  2009 /dev/mtd5
crwxr-xr-x    1 nobody   nobody    90,  12 Mar  2  2009 /dev/mtd6
-rw-r--r--    1 root     root           19 Apr 15  2009 /dev/mtd9
brwxr-xr-x    1 nobody   nobody    31,   0 Mar  2  2009 /dev/mtdblock0
brwxr-xr-x    1 nobody   nobody    31,   1 Mar  2  2009 /dev/mtdblock1
brwxr-xr-x    1 nobody   nobody    31,   2 Mar  2  2009 /dev/mtdblock2
brwxr-xr-x    1 nobody   nobody    31,   3 Mar  2  2009 /dev/mtdblock3
brwxr-xr-x    1 nobody   nobody    31,   4 Mar  2  2009 /dev/mtdblock4
brwxr-xr-x    1 nobody   nobody    31,   5 Mar  2  2009 /dev/mtdblock5
brwxr-xr-x    1 nobody   nobody    31,   6 Mar  2  2009 /dev/mtdblock6
crwxr-xr-x    1 nobody   nobody    90,   1 Mar  2  2009 /dev/mtdr0
crwxr-xr-x    1 nobody   nobody    90,   3 Mar  2  2009 /dev/mtdr1
crwxr-xr-x    1 nobody   nobody    90,   5 Mar  2  2009 /dev/mtdr2
crwxr-xr-x    1 nobody   nobody    90,   7 Mar  2  2009 /dev/mtdr3
crwxr-xr-x    1 nobody   nobody    90,   9 Mar  2  2009 /dev/mtdr4
crwxr-xr-x    1 nobody   nobody    90,  11 Mar  2  2009 /dev/mtdr5
crwxr-xr-x    1 nobody   nobody    90,  13 Mar  2  2009 /dev/mtdr6

通过NFS启动系统后,执行应用程序能读出 /dev/mtd6里面的数据,但是我要写入数据,该如何做?是不是在wriere()前要调用
ioctl()来擦除某个块,然后才能写? 请大家帮助,谢谢!
贴上我的一些关键代码:

FILE *fd = open("/dev/mtd6", O_RDWR)
read_len = read(fd, buff, sizeof(buff)-1);

int ret = ioctl(fd, MEMGETBADBLOCK, &offset); /* 擦某个块 */
write_len = write(buff, 1024/*sizeof(buff)-1*/, fd); /* 写入1K 数据 */



10 个解决方案

#1


我现在用读,或者读写打开/dev/mtd0 或者/dev/mtdblock0,可是调用这个函数出错:

int get_mtdinfo(int fd)
{
struct mtd_info_user mtdInfo;
struct erase_info_user mtdEraseInfo;
int num;

memset(&mtdInfo, 0, sizeof(struct mtd_info_user));
num = ioctl(fd, MEMGETINFO, &mtdInfo);

if(num < 0) 
{
fprintf(stderr, "Error: could not get MTD device info from MTD device, [error=%d]\n", errno);
return -1;
}
printf("mtdInfo: type=%d, flags=%d, size=%d, erasesize=%d\n", \
mtdInfo.type, mtdInfo.flags, mtdInfo.size, mtdInfo.erasesize);
return 0;
}


错误码:errno=25.

#make menuconfig
查看内核配置如下:
Linux Kernel v2.6.11-1.1369_FC4 Configuration

<M> Memory Technology Device (MTD) support
[ ]   Debugging
<M>   MTD concatenating support
[*]   MTD partitioning support
 <M>     RedBoot partition table parsing
(-1)      Location of RedBoot partition table
 [ ]         Include unallocated flash regions 
[ ]         Force read-only for RedBoot system images
[*]     Command line partition table parsing 
   ---   User Modules And Translation Layers  
<M>   Direct char device access to MTD devices 
<M>   Caching block device access to MTD devices
 <M>     Readonly block device access to MTD devices
<M>   FTL (Flash Translation Layer) support 
<M>   NFTL (NAND Flash Translation Layer) support
[*]     Write support for NFTL
<M>   INFTL (Inverse NAND Flash Translation Layer) support

#2


我已确定,mtd6: 00040000 00020000 "nvram" ,mtd6这个flash分区的开始地址和分区大小都是擦除块(128KB)的倍数关系。符合驱动要求的写条件。

#3


在内核的MTD驱动中的分区表:

#elif(CTV_DEFAULT_SIZE_MB == 32)

{ name: "vmlinux",  offset: 0x01D00000, size: 2048 * 1024},//3456*1024 },
{ name: "config",   offset: 0x01800000, size: 4096 * 1024},
{ name: "splash",   offset: 0x01C80000, size: 512 * 1024}, 
{ name: "cfe",   offset: 0x01C00000, size: 512*1024 },
// { name: "macadr", offset: 0x01FFF800, size: 144 },
{ name: "mactype",  offset: 0x01FFF780, size: 128 },
{ name: "nvram",  offset: 0x01F40000, size: 256 * 1024 },
{ name: "feature",  offset: 0x01F00000, size: 256 * 1024 },
#endif

#4


请高手相助,多谢,可以另外开贴给分!Thanks.

#5


早上的帖子不是已经回你了嘛,给了一个简短的 dd 源码,稍微改一下就行了。你想要的那些东西貌似 dd 都能完成:
# dd if=/dev/mtd4 of=/dev/mtd5 bs=1024

#6


麻烦你再贴一下,那贴子,我不小心删除了。

#7


前面那部分就是处理 mtd_erase(), mtd_eraseall() 的,但是现在找不到了...

#8


请楼上,查一下网页的历史记录。谢了。

#9


已解决:
是编译选项里,指向了FC4的linux的头文件(是错误的),正确的做法指向broadcom的内核的头文件。

CC := mipsel-uclibc-gcc #gcc
DIR := /opt/stblinux-2.6.12/include  #/usr/include, 不应当指向linux FC4的目录里的头文件。

CFLAGS := -o2 -I$(DIR)
参见
http://linux.chinaunix.net/bbs/viewthread.php?tid=1097651&pid=6983619&page=1&extra=page%3D1#pid6983619

#10


/*
 * flash_erase.c -- erase parts of a MTD device
*/

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <mtd/mtd-user.h>

int region_erase(int Fd, int start, int count, int unlock, int regcount)
{
int i, j;
region_info_t * reginfo;

reginfo = calloc(regcount, sizeof(region_info_t));

for(i = 0; i < regcount; i++)
{
reginfo[i].regionindex = i;
if(ioctl(Fd,MEMGETREGIONINFO,&(reginfo[i])) != 0)
return 8;
else
printf("Region %d is at %d of %d sector and with sector "
"size %x\n", i, reginfo[i].offset, reginfo[i].numblocks,
reginfo[i].erasesize);
}

// We have all the information about the chip we need.

for(i = 0; i < regcount; i++)
{ //Loop through the regions
region_info_t * r = &(reginfo[i]);

if((start >= reginfo[i].offset) &&
(start < (r->offset + r->numblocks*r->erasesize)))
break;
}

if(i >= regcount)
{
printf("Starting offset %x not within chip.\n", start);
return 8;
}

//We are now positioned within region i of the chip, so start erasing
//count sectors from there.

for(j = 0; (j < count)&&(i < regcount); j++)
{
erase_info_t erase;
region_info_t * r = &(reginfo[i]);

erase.start = start;
erase.length = r->erasesize;

if(unlock != 0)
{ //Unlock the sector first.
if(ioctl(Fd, MEMUNLOCK, &erase) != 0)
{
perror("\nMTD Unlock failure");
close(Fd);
return 8;
}
}
printf("\rPerforming Flash Erase of length %u at offset 0x%x",
erase.length, erase.start);
fflush(stdout);
if(ioctl(Fd, MEMERASE, &erase) != 0)
{
perror("\nMTD Erase failure");
close(Fd);
return 8;
}


start += erase.length;
if(start >= (r->offset + r->numblocks*r->erasesize))
{ //We finished region i so move to region i+1
printf("\nMoving to region %d\n", i+1);
i++;
}
}

printf(" done\n");

return 0;
}

int non_region_erase(int Fd, int start, int count, int unlock)
{
mtd_info_t meminfo;

if (ioctl(Fd,MEMGETINFO,&meminfo) == 0)
{
erase_info_t erase;

erase.start = start;

erase.length = meminfo.erasesize;

for (; count > 0; count--) {
printf("\rPerforming Flash Erase of length %u at offset 0x%x",
erase.length, erase.start);
fflush(stdout);

if(unlock != 0)
{
//Unlock the sector first.
printf("\rPerforming Flash unlock at offset 0x%x",erase.start);
if(ioctl(Fd, MEMUNLOCK, &erase) != 0)
{
perror("\nMTD Unlock failure");
close(Fd);
return 8;
}
}

if (ioctl(Fd,MEMERASE,&erase) != 0)
{
perror("\nMTD Erase failure");
close(Fd);
return 8;
}
erase.start += meminfo.erasesize;
}
printf(" done\n");
}
return 0;
}

int main(int argc,char *argv[])
{
int regcount;
int Fd;
int start;
int count;
int unlock;
int res = 0;

if (1 >= argc)
{
fprintf(stderr,"You must specify a device\n");
return 16;
}

if (argc > 2)
start = strtol(argv[2], NULL, 0);
else
start = 0;

if (argc > 3)
count = strtol(argv[3], NULL, 0);
else
count = 1;

if(argc > 4)
unlock = strtol(argv[4], NULL, 0);
else
unlock = 0;


// Open and size the device
if ((Fd = open(argv[1],O_RDWR)) < 0)
{
fprintf(stderr,"File open error\n");
return 8;
}

printf("Erase Total %d Units\n", count);

if (ioctl(Fd,MEMGETREGIONCOUNT,&regcount) == 0)
{
if(regcount == 0)
{
res = non_region_erase(Fd, start, count, unlock);
}
else
{
res = region_erase(Fd, start, count, unlock, regcount);
}
}

return res;
}

#1


我现在用读,或者读写打开/dev/mtd0 或者/dev/mtdblock0,可是调用这个函数出错:

int get_mtdinfo(int fd)
{
struct mtd_info_user mtdInfo;
struct erase_info_user mtdEraseInfo;
int num;

memset(&mtdInfo, 0, sizeof(struct mtd_info_user));
num = ioctl(fd, MEMGETINFO, &mtdInfo);

if(num < 0) 
{
fprintf(stderr, "Error: could not get MTD device info from MTD device, [error=%d]\n", errno);
return -1;
}
printf("mtdInfo: type=%d, flags=%d, size=%d, erasesize=%d\n", \
mtdInfo.type, mtdInfo.flags, mtdInfo.size, mtdInfo.erasesize);
return 0;
}


错误码:errno=25.

#make menuconfig
查看内核配置如下:
Linux Kernel v2.6.11-1.1369_FC4 Configuration

<M> Memory Technology Device (MTD) support
[ ]   Debugging
<M>   MTD concatenating support
[*]   MTD partitioning support
 <M>     RedBoot partition table parsing
(-1)      Location of RedBoot partition table
 [ ]         Include unallocated flash regions 
[ ]         Force read-only for RedBoot system images
[*]     Command line partition table parsing 
   ---   User Modules And Translation Layers  
<M>   Direct char device access to MTD devices 
<M>   Caching block device access to MTD devices
 <M>     Readonly block device access to MTD devices
<M>   FTL (Flash Translation Layer) support 
<M>   NFTL (NAND Flash Translation Layer) support
[*]     Write support for NFTL
<M>   INFTL (Inverse NAND Flash Translation Layer) support

#2


我已确定,mtd6: 00040000 00020000 "nvram" ,mtd6这个flash分区的开始地址和分区大小都是擦除块(128KB)的倍数关系。符合驱动要求的写条件。

#3


在内核的MTD驱动中的分区表:

#elif(CTV_DEFAULT_SIZE_MB == 32)

{ name: "vmlinux",  offset: 0x01D00000, size: 2048 * 1024},//3456*1024 },
{ name: "config",   offset: 0x01800000, size: 4096 * 1024},
{ name: "splash",   offset: 0x01C80000, size: 512 * 1024}, 
{ name: "cfe",   offset: 0x01C00000, size: 512*1024 },
// { name: "macadr", offset: 0x01FFF800, size: 144 },
{ name: "mactype",  offset: 0x01FFF780, size: 128 },
{ name: "nvram",  offset: 0x01F40000, size: 256 * 1024 },
{ name: "feature",  offset: 0x01F00000, size: 256 * 1024 },
#endif

#4


请高手相助,多谢,可以另外开贴给分!Thanks.

#5


早上的帖子不是已经回你了嘛,给了一个简短的 dd 源码,稍微改一下就行了。你想要的那些东西貌似 dd 都能完成:
# dd if=/dev/mtd4 of=/dev/mtd5 bs=1024

#6


麻烦你再贴一下,那贴子,我不小心删除了。

#7


前面那部分就是处理 mtd_erase(), mtd_eraseall() 的,但是现在找不到了...

#8


请楼上,查一下网页的历史记录。谢了。

#9


已解决:
是编译选项里,指向了FC4的linux的头文件(是错误的),正确的做法指向broadcom的内核的头文件。

CC := mipsel-uclibc-gcc #gcc
DIR := /opt/stblinux-2.6.12/include  #/usr/include, 不应当指向linux FC4的目录里的头文件。

CFLAGS := -o2 -I$(DIR)
参见
http://linux.chinaunix.net/bbs/viewthread.php?tid=1097651&pid=6983619&page=1&extra=page%3D1#pid6983619

#10


/*
 * flash_erase.c -- erase parts of a MTD device
*/

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <mtd/mtd-user.h>

int region_erase(int Fd, int start, int count, int unlock, int regcount)
{
int i, j;
region_info_t * reginfo;

reginfo = calloc(regcount, sizeof(region_info_t));

for(i = 0; i < regcount; i++)
{
reginfo[i].regionindex = i;
if(ioctl(Fd,MEMGETREGIONINFO,&(reginfo[i])) != 0)
return 8;
else
printf("Region %d is at %d of %d sector and with sector "
"size %x\n", i, reginfo[i].offset, reginfo[i].numblocks,
reginfo[i].erasesize);
}

// We have all the information about the chip we need.

for(i = 0; i < regcount; i++)
{ //Loop through the regions
region_info_t * r = &(reginfo[i]);

if((start >= reginfo[i].offset) &&
(start < (r->offset + r->numblocks*r->erasesize)))
break;
}

if(i >= regcount)
{
printf("Starting offset %x not within chip.\n", start);
return 8;
}

//We are now positioned within region i of the chip, so start erasing
//count sectors from there.

for(j = 0; (j < count)&&(i < regcount); j++)
{
erase_info_t erase;
region_info_t * r = &(reginfo[i]);

erase.start = start;
erase.length = r->erasesize;

if(unlock != 0)
{ //Unlock the sector first.
if(ioctl(Fd, MEMUNLOCK, &erase) != 0)
{
perror("\nMTD Unlock failure");
close(Fd);
return 8;
}
}
printf("\rPerforming Flash Erase of length %u at offset 0x%x",
erase.length, erase.start);
fflush(stdout);
if(ioctl(Fd, MEMERASE, &erase) != 0)
{
perror("\nMTD Erase failure");
close(Fd);
return 8;
}


start += erase.length;
if(start >= (r->offset + r->numblocks*r->erasesize))
{ //We finished region i so move to region i+1
printf("\nMoving to region %d\n", i+1);
i++;
}
}

printf(" done\n");

return 0;
}

int non_region_erase(int Fd, int start, int count, int unlock)
{
mtd_info_t meminfo;

if (ioctl(Fd,MEMGETINFO,&meminfo) == 0)
{
erase_info_t erase;

erase.start = start;

erase.length = meminfo.erasesize;

for (; count > 0; count--) {
printf("\rPerforming Flash Erase of length %u at offset 0x%x",
erase.length, erase.start);
fflush(stdout);

if(unlock != 0)
{
//Unlock the sector first.
printf("\rPerforming Flash unlock at offset 0x%x",erase.start);
if(ioctl(Fd, MEMUNLOCK, &erase) != 0)
{
perror("\nMTD Unlock failure");
close(Fd);
return 8;
}
}

if (ioctl(Fd,MEMERASE,&erase) != 0)
{
perror("\nMTD Erase failure");
close(Fd);
return 8;
}
erase.start += meminfo.erasesize;
}
printf(" done\n");
}
return 0;
}

int main(int argc,char *argv[])
{
int regcount;
int Fd;
int start;
int count;
int unlock;
int res = 0;

if (1 >= argc)
{
fprintf(stderr,"You must specify a device\n");
return 16;
}

if (argc > 2)
start = strtol(argv[2], NULL, 0);
else
start = 0;

if (argc > 3)
count = strtol(argv[3], NULL, 0);
else
count = 1;

if(argc > 4)
unlock = strtol(argv[4], NULL, 0);
else
unlock = 0;


// Open and size the device
if ((Fd = open(argv[1],O_RDWR)) < 0)
{
fprintf(stderr,"File open error\n");
return 8;
}

printf("Erase Total %d Units\n", count);

if (ioctl(Fd,MEMGETREGIONCOUNT,&regcount) == 0)
{
if(regcount == 0)
{
res = non_region_erase(Fd, start, count, unlock);
}
else
{
res = region_erase(Fd, start, count, unlock, regcount);
}
}

return res;
}