Linux MTD系统剖析【转】

转自:http://blog.csdn.net/lwj103862095/article/details/21545791

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。

如上图所示,MTD设备通常可分为四层,从上到下依次是:设备节点、MTD设备层、MTD原始设备层、硬件驱动层。

Flash硬件驱动层:Flash硬件驱动层负责对Flash硬件的读、写和擦除操作。MTD设备的Nand Flash芯片的驱动则drivers/mtd/nand/子目录下,Nor Flash芯片驱动位于drivers/mtd/chips/子目录下。

MTD原始设备层:用于描述MTD原始设备的数据结构是mtd_info,它定义了大量的关于MTD的数据和操作函数。其中mtdcore.c:  MTD原始设备接口相关实现,mtdpart.c :  MTD分区接口相关实现。

MTD设备层:基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)字符设备(设备号90)。其中mtdchar.c :  MTD字符设备接口相关实现,mtdblock.c : MTD块设备接口相关实现。

设备节点:通过mknod在/dev子目录下建立MTD块设备节点(主设备号为31)MTD字符设备节点(主设备号为90)。通过访问此设备节点即可访问MTD字符设备和块设备 

MTD数据结构:

1.Linux内核使用mtd_info结构体表示MTD原始设备,这其中定义了大量关于MTD的数据和操作函数(后面将会看到),所有的mtd_info结构体存放在mtd_table结构体数据里。在/drivers/mtd/mtdcore.c里:

 

[cpp] view plain copy

 
 print?

  1. struct mtd_info *mtd_table[MAX_MTD_DEVICES];  

2.Linux内核使用mtd_part结构体表示分区,其中mtd_info结构体成员用于描述该分区,大部分成员由其主分区mtd_part->master决定,各种函数也指向主分区的相应函数。

 

 

[cpp] view plain copy

 
 print?

  1. struct mtd_part {  
  2.     struct mtd_info mtd;        /* 分区信息, 大部分由master决定 */  
  3.     struct mtd_info *master;    /* 分区的主分区 */  
  4.     uint64_t offset;            /* 分区的偏移地址 */  
  5.     int index;                  /* 分区号 (Linux3.0后不存在该字段) */  
  6.     struct list_head list;      /* 将mtd_part链成一个链表mtd_partitons */  
  7.     int registered;  
  8. };  

mtd_info结构体主要成员,为了便于观察,将重要的数据放在前面,不大重要的编写在后面。

 

 

[cpp] view plain copy

 
 print?

  1. struct mtd_info {  
  2.     u_char type;         /* MTD类型,包括MTD_NORFLASH,MTD_NANDFLASH等(可参考mtd-abi.h) */  
  3.     uint32_t flags;      /* MTD属性标志,MTD_WRITEABLE,MTD_NO_ERASE等(可参考mtd-abi.h) */  
  4.     uint64_t size;       /* mtd设备的大小 */  
  5.     uint32_t erasesize;  /* MTD设备的擦除单元大小,对于NandFlash来说就是Block的大小 */  
  6.     uint32_t writesize;  /* 写大小, 对于norFlash是字节,对nandFlash为一页 */  
  7.     uint32_t oobsize;    /* OOB字节数 */  
  8.     uint32_t oobavail;   /* 可用的OOB字节数 */  
  9.     unsigned int erasesize_shift;   /* 默认为0,不重要 */  
  10.     unsigned int writesize_shift;   /* 默认为0,不重要 */  
  11.     unsigned int erasesize_mask;    /* 默认为1,不重要 */  
  12.     unsigned int writesize_mask;    /* 默认为1,不重要 */  
  13.     const char *name;               /* 名字,   不重要*/  
  14.     int index;                      /* 索引号,不重要 */  
  15.     int numeraseregions;            /* 通常为1 */  
  16.     struct mtd_erase_region_info *eraseregions; /* 可变擦除区域 */  
  17.       
  18.     void *priv;     /* 设备私有数据指针,对于NandFlash来说指nand_chip结构体 */  
  19.     struct module *owner;   /* 一般设置为THIS_MODULE */  
  20.       
  21.     /* 擦除函数 */  
  22.     int (*erase) (struct mtd_info *mtd, struct erase_info *instr);  
  23.   
  24.     /* 读写flash函数 */  
  25.     int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
  26.     int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);  
  27.   
  28.     /* 带oob读写Flash函数 */  
  29.     int (*read_oob) (struct mtd_info *mtd, loff_t from,  
  30.              struct mtd_oob_ops *ops);  
  31.     int (*write_oob) (struct mtd_info *mtd, loff_t to,  
  32.              struct mtd_oob_ops *ops);  
  33.   
  34.     int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  
  35.     int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
  36.     int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  
  37.     int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
  38.     int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
  39.     int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);  
  40.   
  41.     int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);  
  42.     int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);  
  43.     /* Sync */  
  44.     void (*sync) (struct mtd_info *mtd);  
  45.   
  46.     /* Chip-supported device locking */  
  47.     int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);  
  48.     int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);  
  49.   
  50.     /* 电源管理函数 */  
  51.     int (*suspend) (struct mtd_info *mtd);  
  52.     void (*resume) (struct mtd_info *mtd);  
  53.   
  54.     /* 坏块管理函数 */  
  55.     int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);  
  56.     int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);  
  57.   
  58.     void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);  
  59.     unsigned long (*get_unmapped_area) (struct mtd_info *mtd,  
  60.                         unsigned long len,  
  61.                         unsigned long offset,  
  62.                         unsigned long flags);  
  63.     struct backing_dev_info *backing_dev_info;  
  64.     struct notifier_block reboot_notifier;  /* default mode before reboot */  
  65.   
  66.     /* ECC status information */  
  67.     struct mtd_ecc_stats ecc_stats;  
  68.     int subpage_sft;  
  69.     struct device dev;  
  70.     int usecount;  
  71.     int (*get_device) (struct mtd_info *mtd);  
  72.     void (*put_device) (struct mtd_info *mtd);  
  73. };  

mtd_info结构体中的read()、write()、read_oob()、write_oob()、erase()是MTD设备驱动要实现的主要函数,幸运的是Linux大牛已经帮我们实现了一套适合大部分FLASH设备的mtd_info成员函数。

 

如果MTD设备只有一个分区,那么使用下面两个函数注册和注销MTD设备。

 

[cpp] view plain copy

 
 print?

  1. int add_mtd_device(struct mtd_info *mtd)  
  2. int del_mtd_device (struct mtd_info *mtd)  

如果MTD设备存在其他分区,那么使用下面两个函数注册和注销MTD设备。

[cpp] view plain copy

 
 print?

  1. int add_mtd_partitions(struct mtd_info *master,const struct mtd_partition *parts,int nbparts)  
  2. int del_mtd_partitions(struct mtd_info *master)  

其中mtd_partition结构体表示分区的信息

 

 

[cpp] view plain copy

 
 print?

  1. struct mtd_partition {  
  2.     char *name;             /* 分区名,如TQ2440_Board_uboot、TQ2440_Board_kernel、TQ2440_Board_yaffs2 */  
  3.     uint64_t size;          /* 分区大小 */  
  4.     uint64_t offset;        /* 分区偏移值 */  
  5.     uint32_t mask_flags;    /* 掩码标识,不重要 */  
  6.     struct nand_ecclayout *ecclayout;   /* OOB布局 */  
  7.     struct mtd_info **mtdp;     /* pointer to store the MTD object */  
  8. };  
  9. 其中nand_ecclayout结构体:  
  10. struct nand_ecclayout {  
  11.     __u32 eccbytes;     /* ECC字节数 */  
  12.     __u32 eccpos[64];   /* ECC校验码在OOB区域存放位置 */  
  13.     __u32 oobavail;       
  14.     /* 除了ECC校验码之外可用的OOB字节数 */  
  15.     struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];  
  16. };  

关于nand_ecclayout结构体实例,更多可参考drivers/mtd/nand/nand_base.c下的nand_oob_8、nand_oob_16、nand_oob_64实例。
MTD设备层:

 

mtd字符设备接口:

/drivers/mtd/mtdchar.c文件实现了MTD字符设备接口,通过它,可以直接访问Flash设备,与前面的字符驱动一样,通过file_operations结构体里面的open()、read()、write()、ioctl()可以读写Flash,通过一系列IOCTL 命令可以获取Flash 设备信息、擦除Flash、读写NAND 的OOB、获取OOB layout 及检查NAND 坏块等(MEMGETINFO、MEMERASE、MEMREADOOB、MEMWRITEOOB、MEMGETBADBLOCK IOCRL) 

mtd块设备接口:

/drivers/mtd/mtdblock.c文件实现了MTD块设备接口,主要原理是将Flash的erase block 中的数据在内存中建立映射,然后对其进行修改,最后擦除Flash 上的block,将内存中的映射块写入Flash 块。整个过程被称为read/modify/erase/rewrite 周期。 但是,这样做是不安全的,当下列操作序列发生时,read/modify/erase/poweroff,就会丢失这个block 块的数据。
MTD硬件驱动层:

Linux内核再MTD层下实现了通用的NAND驱动(/driver/mtd/nand/nand_base.c),因此芯片级的NAND驱动不再需要实现mtd_info结构体中的read()、write()、read_oob()、write_oob()等成员函数。

MTD使用nand_chip来表示一个NAND FLASH芯片, 该结构体包含了关于Nand Flash的地址信息,读写方法,ECC模式,硬件控制等一系列底层机制。

 

[cpp] view plain copy

 
 print?

  1. struct nand_chip {  
  2.     void  __iomem   *IO_ADDR_R;     /* 读8位I/O线地址 */  
  3.     void  __iomem   *IO_ADDR_W;     /* 写8位I/O线地址 */  
  4.   
  5.     /* 从芯片中读一个字节 */  
  6.     uint8_t (*read_byte)(struct mtd_info *mtd);       
  7.     /* 从芯片中读一个字 */  
  8.     u16     (*read_word)(struct mtd_info *mtd);       
  9.     /* 将缓冲区内容写入芯片 */  
  10.     void    (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);      
  11.     /* 读芯片读取内容至缓冲区/ */  
  12.     void    (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);  
  13.     /* 验证芯片和写入缓冲区中的数据 */  
  14.     int     (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);  
  15.     /* 选中芯片 */  
  16.     void    (*select_chip)(struct mtd_info *mtd, int chip);  
  17.     /* 检测是否有坏块 */  
  18.     int     (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);  
  19.     /* 标记坏块 */  
  20.     int     (*block_markbad)(struct mtd_info *mtd, loff_t ofs);  
  21.     /* 命令、地址、数据控制函数 */  
  22.     void    (*cmd_ctrl)(struct mtd_info *mtd, int dat,unsigned int ctrl);  
  23.     /* 设备是否就绪 */  
  24.     int     (*dev_ready)(struct mtd_info *mtd);  
  25.     /* 实现命令发送 */  
  26.     void    (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);  
  27.     int     (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);  
  28.     /* 擦除命令的处理 */  
  29.     void    (*erase_cmd)(struct mtd_info *mtd, int page);  
  30.     /* 扫描坏块 */  
  31.     int     (*scan_bbt)(struct mtd_info *mtd);  
  32.     int     (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);  
  33.     /* 写一页 */  
  34.     int     (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,  
  35.                       const uint8_t *buf, int page, int cached, int raw);  
  36.   
  37.     int     chip_delay;         /* 由板决定的延迟时间 */  
  38.     /* 与具体的NAND芯片相关的一些选项,如NAND_NO_AUTOINCR,NAND_BUSWIDTH_16等 */  
  39.     unsigned int    options;      
  40.   
  41.     /* 用位表示的NAND芯片的page大小,如某片NAND芯片 
  42.      * 的一个page有512个字节,那么page_shift就是9  
  43.      */  
  44.     int      page_shift;  
  45.     /* 用位表示的NAND芯片的每次可擦除的大小,如某片NAND芯片每次可 
  46.      * 擦除16K字节(通常就是一个block的大小),那么phys_erase_shift就是14 
  47.      */  
  48.     int      phys_erase_shift;  
  49.     /* 用位表示的bad block table的大小,通常一个bbt占用一个block, 
  50.      * 所以bbt_erase_shift通常与phys_erase_shift相等 
  51.      */  
  52.     int      bbt_erase_shift;  
  53.     /* 用位表示的NAND芯片的容量 */  
  54.     int      chip_shift;  
  55.     /* NADN FLASH芯片的数量 */  
  56.     int      numchips;  
  57.     /* NAND芯片的大小 */  
  58.     uint64_t chipsize;  
  59.     int      pagemask;  
  60.     int      pagebuf;  
  61.     int      subpagesize;  
  62.     uint8_t  cellinfo;  
  63.     int      badblockpos;  
  64.     nand_state_t    state;  
  65.     uint8_t     *oob_poi;  
  66.     struct nand_hw_control  *controller;  
  67.     struct nand_ecclayout   *ecclayout; /* ECC布局 */  
  68.       
  69.     struct nand_ecc_ctrl ecc;   /* ECC校验结构体,里面有大量的函数进行ECC校验 */  
  70.     struct nand_buffers *buffers;  
  71.     struct nand_hw_control hwcontrol;  
  72.     struct mtd_oob_ops ops;  
  73.     uint8_t     *bbt;  
  74.     struct nand_bbt_descr   *bbt_td;  
  75.     struct nand_bbt_descr   *bbt_md;  
  76.     struct nand_bbt_descr   *badblock_pattern;  
  77.     void        *priv;  
  78. };  

最后,我们来用图表的形式来总结一下,MTD设备层、MTD原始设备层、FLASH硬件驱动层之间的联系。

 

 

 

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。

如上图所示,MTD设备通常可分为四层,从上到下依次是:设备节点、MTD设备层、MTD原始设备层、硬件驱动层。

Flash硬件驱动层:Flash硬件驱动层负责对Flash硬件的读、写和擦除操作。MTD设备的Nand Flash芯片的驱动则drivers/mtd/nand/子目录下,Nor Flash芯片驱动位于drivers/mtd/chips/子目录下。

MTD原始设备层:用于描述MTD原始设备的数据结构是mtd_info,它定义了大量的关于MTD的数据和操作函数。其中mtdcore.c:  MTD原始设备接口相关实现,mtdpart.c :  MTD分区接口相关实现。

MTD设备层:基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)字符设备(设备号90)。其中mtdchar.c :  MTD字符设备接口相关实现,mtdblock.c : MTD块设备接口相关实现。

设备节点:通过mknod在/dev子目录下建立MTD块设备节点(主设备号为31)MTD字符设备节点(主设备号为90)。通过访问此设备节点即可访问MTD字符设备和块设备 

MTD数据结构:

1.Linux内核使用mtd_info结构体表示MTD原始设备,这其中定义了大量关于MTD的数据和操作函数(后面将会看到),所有的mtd_info结构体存放在mtd_table结构体数据里。在/drivers/mtd/mtdcore.c里:

 

[cpp] view plain copy

 
 print?

  1. struct mtd_info *mtd_table[MAX_MTD_DEVICES];  

2.Linux内核使用mtd_part结构体表示分区,其中mtd_info结构体成员用于描述该分区,大部分成员由其主分区mtd_part->master决定,各种函数也指向主分区的相应函数。

 

 

[cpp] view plain copy

 
 print?

  1. struct mtd_part {  
  2.     struct mtd_info mtd;        /* 分区信息, 大部分由master决定 */  
  3.     struct mtd_info *master;    /* 分区的主分区 */  
  4.     uint64_t offset;            /* 分区的偏移地址 */  
  5.     int index;                  /* 分区号 (Linux3.0后不存在该字段) */  
  6.     struct list_head list;      /* 将mtd_part链成一个链表mtd_partitons */  
  7.     int registered;  
  8. };  

mtd_info结构体主要成员,为了便于观察,将重要的数据放在前面,不大重要的编写在后面。

 

 

[cpp] view plain copy

 
 print?

  1. struct mtd_info {  
  2.     u_char type;         /* MTD类型,包括MTD_NORFLASH,MTD_NANDFLASH等(可参考mtd-abi.h) */  
  3.     uint32_t flags;      /* MTD属性标志,MTD_WRITEABLE,MTD_NO_ERASE等(可参考mtd-abi.h) */  
  4.     uint64_t size;       /* mtd设备的大小 */  
  5.     uint32_t erasesize;  /* MTD设备的擦除单元大小,对于NandFlash来说就是Block的大小 */  
  6.     uint32_t writesize;  /* 写大小, 对于norFlash是字节,对nandFlash为一页 */  
  7.     uint32_t oobsize;    /* OOB字节数 */  
  8.     uint32_t oobavail;   /* 可用的OOB字节数 */  
  9.     unsigned int erasesize_shift;   /* 默认为0,不重要 */  
  10.     unsigned int writesize_shift;   /* 默认为0,不重要 */  
  11.     unsigned int erasesize_mask;    /* 默认为1,不重要 */  
  12.     unsigned int writesize_mask;    /* 默认为1,不重要 */  
  13.     const char *name;               /* 名字,   不重要*/  
  14.     int index;                      /* 索引号,不重要 */  
  15.     int numeraseregions;            /* 通常为1 */  
  16.     struct mtd_erase_region_info *eraseregions; /* 可变擦除区域 */  
  17.       
  18.     void *priv;     /* 设备私有数据指针,对于NandFlash来说指nand_chip结构体 */  
  19.     struct module *owner;   /* 一般设置为THIS_MODULE */  
  20.       
  21.     /* 擦除函数 */  
  22.     int (*erase) (struct mtd_info *mtd, struct erase_info *instr);  
  23.   
  24.     /* 读写flash函数 */  
  25.     int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
  26.     int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);  
  27.   
  28.     /* 带oob读写Flash函数 */  
  29.     int (*read_oob) (struct mtd_info *mtd, loff_t from,  
  30.              struct mtd_oob_ops *ops);  
  31.     int (*write_oob) (struct mtd_info *mtd, loff_t to,  
  32.              struct mtd_oob_ops *ops);  
  33.   
  34.     int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  
  35.     int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
  36.     int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  
  37.     int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
  38.     int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
  39.     int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);  
  40.   
  41.     int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);  
  42.     int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);  
  43.     /* Sync */  
  44.     void (*sync) (struct mtd_info *mtd);  
  45.   
  46.     /* Chip-supported device locking */  
  47.     int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);  
  48.     int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);  
  49.   
  50.     /* 电源管理函数 */  
  51.     int (*suspend) (struct mtd_info *mtd);  
  52.     void (*resume) (struct mtd_info *mtd);  
  53.   
  54.     /* 坏块管理函数 */  
  55.     int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);  
  56.     int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);  
  57.   
  58.     void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);  
  59.     unsigned long (*get_unmapped_area) (struct mtd_info *mtd,  
  60.                         unsigned long len,  
  61.                         unsigned long offset,  
  62.                         unsigned long flags);  
  63.     struct backing_dev_info *backing_dev_info;  
  64.     struct notifier_block reboot_notifier;  /* default mode before reboot */  
  65.   
  66.     /* ECC status information */  
  67.     struct mtd_ecc_stats ecc_stats;  
  68.     int subpage_sft;  
  69.     struct device dev;  
  70.     int usecount;  
  71.     int (*get_device) (struct mtd_info *mtd);  
  72.     void (*put_device) (struct mtd_info *mtd);  
  73. };  

mtd_info结构体中的read()、write()、read_oob()、write_oob()、erase()是MTD设备驱动要实现的主要函数,幸运的是Linux大牛已经帮我们实现了一套适合大部分FLASH设备的mtd_info成员函数。

 

如果MTD设备只有一个分区,那么使用下面两个函数注册和注销MTD设备。

 

[cpp] view plain copy

 
 print?

  1. int add_mtd_device(struct mtd_info *mtd)  
  2. int del_mtd_device (struct mtd_info *mtd)  

如果MTD设备存在其他分区,那么使用下面两个函数注册和注销MTD设备。

[cpp] view plain copy

 
 print?

  1. int add_mtd_partitions(struct mtd_info *master,const struct mtd_partition *parts,int nbparts)  
  2. int del_mtd_partitions(struct mtd_info *master)  

其中mtd_partition结构体表示分区的信息

 

 

[cpp] view plain copy

 
 print?

  1. struct mtd_partition {  
  2.     char *name;             /* 分区名,如TQ2440_Board_uboot、TQ2440_Board_kernel、TQ2440_Board_yaffs2 */  
  3.     uint64_t size;          /* 分区大小 */  
  4.     uint64_t offset;        /* 分区偏移值 */  
  5.     uint32_t mask_flags;    /* 掩码标识,不重要 */  
  6.     struct nand_ecclayout *ecclayout;   /* OOB布局 */  
  7.     struct mtd_info **mtdp;     /* pointer to store the MTD object */  
  8. };  
  9. 其中nand_ecclayout结构体:  
  10. struct nand_ecclayout {  
  11.     __u32 eccbytes;     /* ECC字节数 */  
  12.     __u32 eccpos[64];   /* ECC校验码在OOB区域存放位置 */  
  13.     __u32 oobavail;       
  14.     /* 除了ECC校验码之外可用的OOB字节数 */  
  15.     struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];  
  16. };  

关于nand_ecclayout结构体实例,更多可参考drivers/mtd/nand/nand_base.c下的nand_oob_8、nand_oob_16、nand_oob_64实例。
MTD设备层:

 

mtd字符设备接口:

/drivers/mtd/mtdchar.c文件实现了MTD字符设备接口,通过它,可以直接访问Flash设备,与前面的字符驱动一样,通过file_operations结构体里面的open()、read()、write()、ioctl()可以读写Flash,通过一系列IOCTL 命令可以获取Flash 设备信息、擦除Flash、读写NAND 的OOB、获取OOB layout 及检查NAND 坏块等(MEMGETINFO、MEMERASE、MEMREADOOB、MEMWRITEOOB、MEMGETBADBLOCK IOCRL) 

mtd块设备接口:

/drivers/mtd/mtdblock.c文件实现了MTD块设备接口,主要原理是将Flash的erase block 中的数据在内存中建立映射,然后对其进行修改,最后擦除Flash 上的block,将内存中的映射块写入Flash 块。整个过程被称为read/modify/erase/rewrite 周期。 但是,这样做是不安全的,当下列操作序列发生时,read/modify/erase/poweroff,就会丢失这个block 块的数据。
MTD硬件驱动层:

Linux内核再MTD层下实现了通用的NAND驱动(/driver/mtd/nand/nand_base.c),因此芯片级的NAND驱动不再需要实现mtd_info结构体中的read()、write()、read_oob()、write_oob()等成员函数。

MTD使用nand_chip来表示一个NAND FLASH芯片, 该结构体包含了关于Nand Flash的地址信息,读写方法,ECC模式,硬件控制等一系列底层机制。

 

[cpp] view plain copy

 
 print?

  1. struct nand_chip {  
  2.     void  __iomem   *IO_ADDR_R;     /* 读8位I/O线地址 */  
  3.     void  __iomem   *IO_ADDR_W;     /* 写8位I/O线地址 */  
  4.   
  5.     /* 从芯片中读一个字节 */  
  6.     uint8_t (*read_byte)(struct mtd_info *mtd);       
  7.     /* 从芯片中读一个字 */  
  8.     u16     (*read_word)(struct mtd_info *mtd);       
  9.     /* 将缓冲区内容写入芯片 */  
  10.     void    (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);      
  11.     /* 读芯片读取内容至缓冲区/ */  
  12.     void    (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);  
  13.     /* 验证芯片和写入缓冲区中的数据 */  
  14.     int     (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);  
  15.     /* 选中芯片 */  
  16.     void    (*select_chip)(struct mtd_info *mtd, int chip);  
  17.     /* 检测是否有坏块 */  
  18.     int     (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);  
  19.     /* 标记坏块 */  
  20.     int     (*block_markbad)(struct mtd_info *mtd, loff_t ofs);  
  21.     /* 命令、地址、数据控制函数 */  
  22.     void    (*cmd_ctrl)(struct mtd_info *mtd, int dat,unsigned int ctrl);  
  23.     /* 设备是否就绪 */  
  24.     int     (*dev_ready)(struct mtd_info *mtd);  
  25.     /* 实现命令发送 */  
  26.     void    (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);  
  27.     int     (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);  
  28.     /* 擦除命令的处理 */  
  29.     void    (*erase_cmd)(struct mtd_info *mtd, int page);  
  30.     /* 扫描坏块 */  
  31.     int     (*scan_bbt)(struct mtd_info *mtd);  
  32.     int     (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);  
  33.     /* 写一页 */  
  34.     int     (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,  
  35.                       const uint8_t *buf, int page, int cached, int raw);  
  36.   
  37.     int     chip_delay;         /* 由板决定的延迟时间 */  
  38.     /* 与具体的NAND芯片相关的一些选项,如NAND_NO_AUTOINCR,NAND_BUSWIDTH_16等 */  
  39.     unsigned int    options;      
  40.   
  41.     /* 用位表示的NAND芯片的page大小,如某片NAND芯片 
  42.      * 的一个page有512个字节,那么page_shift就是9  
  43.      */  
  44.     int      page_shift;  
  45.     /* 用位表示的NAND芯片的每次可擦除的大小,如某片NAND芯片每次可 
  46.      * 擦除16K字节(通常就是一个block的大小),那么phys_erase_shift就是14 
  47.      */  
  48.     int      phys_erase_shift;  
  49.     /* 用位表示的bad block table的大小,通常一个bbt占用一个block, 
  50.      * 所以bbt_erase_shift通常与phys_erase_shift相等 
  51.      */  
  52.     int      bbt_erase_shift;  
  53.     /* 用位表示的NAND芯片的容量 */  
  54.     int      chip_shift;  
  55.     /* NADN FLASH芯片的数量 */  
  56.     int      numchips;  
  57.     /* NAND芯片的大小 */  
  58.     uint64_t chipsize;  
  59.     int      pagemask;  
  60.     int      pagebuf;  
  61.     int      subpagesize;  
  62.     uint8_t  cellinfo;  
  63.     int      badblockpos;  
  64.     nand_state_t    state;  
  65.     uint8_t     *oob_poi;  
  66.     struct nand_hw_control  *controller;  
  67.     struct nand_ecclayout   *ecclayout; /* ECC布局 */  
  68.       
  69.     struct nand_ecc_ctrl ecc;   /* ECC校验结构体,里面有大量的函数进行ECC校验 */  
  70.     struct nand_buffers *buffers;  
  71.     struct nand_hw_control hwcontrol;  
  72.     struct mtd_oob_ops ops;  
  73.     uint8_t     *bbt;  
  74.     struct nand_bbt_descr   *bbt_td;  
  75.     struct nand_bbt_descr   *bbt_md;  
  76.     struct nand_bbt_descr   *badblock_pattern;  
  77.     void        *priv;  
  78. };  

最后,我们来用图表的形式来总结一下,MTD设备层、MTD原始设备层、FLASH硬件驱动层之间的联系。

 

 

时间: 2024-09-30 03:58:55

Linux MTD系统剖析【转】的相关文章

Linux Framebuffer驱动剖析之二—驱动框架、接口实现和使用

本文继上一篇文章<Linux Framebuffer驱动剖析之一-软件需求>,深入分析LinuxFramebuffer子系统的驱动框架.接口实现和使用. 一.LinuxFramebuffer的软件需求 上一篇文章详细阐述了LinuxFramebuffer的软件需求(请先理解第一篇文章再来阅读本篇文章),总结如下: 1. 针对SOC的LCD控制寄存器进行编程,以支持不同的LCD屏,以使该SOC的应用场景最大化.这是硬件平台相关的需求.其对应Linux源码路径arch\arm\mach-s5pv2

危险病毒卤猪活动频繁 Linux等系统不受影响

上海计算机病毒防范服务中心日前发出预警:近期一种通过U盘.移动硬盘等移动存储设备传播的危险病毒"卤猪"(Win32.iuhzu.a)活动频繁,用户在使用移动存储设备过程中一旦感染该病毒,可能导致系统运行异常甚至崩溃等严重后果. 据介绍,该病毒主要攻击Windows 2000,Windows XP,Windows Server 2003等微软操作系统, Macintosh,Unix,Linux等系统不受影响. 来自上海市信息化服务热线等反病毒机构的专家介绍,"卤猪"病

linux的系统监控命令介绍

linux系统监控有以下命令: uptime:显示系统负载情况 mpstat:显示 CPU 性能 free:显示内存使用情况 vmstat:显示虚拟内存使用情况 iostat:显示系统 I/O 活动 netstat:显示网络的活动 df/du:显示磁盘使用情况 1. uptime fdipzone@ubuntu:~$ uptime 00:06:00 up 32 min, 2 users, load average: 0.00, 0.03, 0.07 00:06:00 表示当前时间 32min 表

Linux环境下的Java开发(一):找一个顺手的Linux桌面系统

说道Linux桌面系统,肯定有人会推荐Ubuntu Linux 7.04,也肯定有人会推荐 Fedora 7,但是经过我的使用,我觉得,最顺手的还是Red Flag Linux Desktop 5.0,不错,就是这个,我们国人自己开发的红旗. Ubuntu Linux 7.04 我下载后,在虚拟机中安装失败,在真实电脑中安装同样 是失败,因此不能参加比较.Fedora 7在虚拟机中安装失败,在真实机中安装成 功.Red Flag Linux Desktop 5.0在虚拟机和真实机中都可以安装,当

linux双系统直接删除linux修复

  window linux双系统直接删除linux修复 用win7和fedora双系统如果直接将fedora所在的分区格式化,由于grub写好的mbr不能找到相应的配置文件.所以不能启动win7. 这时需要修复mbr,具体办法如下: 插入win7系统安装盘,设置为光驱引导 选择完语言选项后,进入下一步,选择左下角的[系统修复]而不是继续安装. 自动搜索完已经安装的系统后,进入下一步. 这里不要点windows自动修复,而是进入[命令提示符模式] 先输入命令 bootrec/fixmbr 回车,

图片-在Windows 7下安装Linux双系统时出现黑屏

问题描述 在Windows 7下安装Linux双系统时出现黑屏 我用U盘在Windows 7下安装Linux双系统,进入Linux安装首页,然后点击安装,屏幕刷刷的出现了一些检测什么的,一切貌似很正常,之后就黑屏了,等了一会也没有一点反应,没办法只好重启了.这和我的显卡有关系吗?我的硬盘腾出了50G的内存,没有分配分区,应该够的吧?求各位大神指点一下小弟呀!谢谢大家! 解决方案 如何在windows下安装linux双系统,不用虚拟机在windows7下安装xp 双系统Windows与linux双

u盘-在Windows 7下安装Linux双系统时出现黑屏

问题描述 在Windows 7下安装Linux双系统时出现黑屏 我用U盘在Windows 7下安装Linux双系统,进入Linux安装首页,然后点击安装,屏幕刷刷的出现了一些检测什么的,一切貌似很正常,之后就黑屏了,等了一会也没有一点反应,没办法只好重启了.求各位大神指点一下小弟呀!谢谢大家! 解决方案 描述的不太详细,不好判断是哪方面出的问题.现在你的Windows启动有问题吗? 如果没问题 可以考虑虚拟机.或者重新安装. 安装过程中的等待是必要的. 解决方案二: 如何在windows下安装l

linux centos系统硬盘已经满了(提示超过90%使用),但是df查看磁盘空间只占用了40%

问题描述 linux centos系统硬盘已经满了(提示超过90%使用),但是df查看磁盘空间只占用了40% linux centos系统硬盘已经满了(提示超过90%使用),但是df查看磁盘空间只占用了40%为什么?该如何解决呢?谢谢 解决方案 1.centos有时在统计磁盘空间的时候存在误差,特别是在虚拟机上,建议你先重启一下系统,然后再用df命令看看磁盘空间. 解决方案二: 先用df查看一下磁盘空间分布状态.是不是有临时文件占用了 解决方案三: find path -type f -size

基于busybox的Linux小系统制作 (initrd)

我们有时候有需要在busybox基础上,制作linux,可是却不知道具体怎么做,这里将对基于busybox的linux小系统制作做出详细的步骤说明.准备环境:1.一个Redhat完整系统的虚拟机,本次实例使用的是Redhat Enterprise Linux 5.82.在主虚拟机上添加一块硬盘作为小系统的存储盘,这里添加的是IDE硬盘,3.准备linux内核源码以及busybox源码,这里使用linux-2.6.38.5和busybox-1.20.2版本4.复制当前系统上的内核配置(/usr/s