nand flash 重要结构体

oob相关:
nand_chip->oob_poi 用来oob数据的buff,buff大小为mtd_info->oobsize

ecc相关:
ecc数据存放在以下两个地方,也就是以下两个地方可以找到。
1)存放在nand_chip->oob_poi数组中
存放在nand_chip->oob_poi数组中nand_chip->ecc.layout指定的地方,访问方式如下:
for (i = 0; i < chip->ecc.total; i++)
ecc_code[i] = chip->oob_poi[eccpos[i]];

2)存放在nand_chip->buffers中

ecc数据长度在nand_chip->ecc->total中指定。

bbt相关:
建立BBT的过程,
管理BBT的数据区不能超过1个Block

1、一个新的nand flash在每个block的第1和第2个页面或最后一个页面的oob区域中存放了这个block的坏块标志,
那到底是存放在第1和第2个页面的oob区域还是存放在最后一个页面的oob区域中是由下面两个宏来标示的。
/* Search good / bad pattern on the first and the second page */
#define NAND_BBT_SCAN2NDPAGE 0x00008000
/* Search good / bad pattern on the last page of the eraseblock */
#define NAND_BBT_SCANLASTPAGE 0x00010000

2、当一个产品第一次开机时,kernel会遍历上面据说的每个block 的oob区域,生成bbt,保存在nand_chip->bbt 所指向的内存中,并将bbt写入到flash的某两个block中,(两个block是因为有一个是备份),写到哪两个block呢.可以写到这个flash可用的前两个block中,也可以写到这个flash的最后两个可用的block中.具体看td->options中有没有NAND_BBT_LASTBLOCK标示.如果有则表示是在最后一个可用的块中.下面代码是找存放bbt的那个block.

        if (td->options & NAND_BBT_LASTBLOCK) {//如果定义了NAND_BBT_LASTBLOCK,就从后向前找
            startblock = numblocks * (chip + 1) - 1;
            dir = -1;
        } else {//没有定义NAND_BBT_LASTBLOCK,就从前向后找.
            startblock = chip * numblocks;
            dir = 1;
        }

子页只有SLC nand flash才可能会有。MLC的nand flash没有子页。



struct mtd_info {
    u_char type;
    uint32_t flags;
    uint64_t size;   // Total size of the MTD

    /* "Major" erase size for the device. Na茂ve users may take this
     * to be the only erase size available, or may use the more detailed
     * information below if they desire
     */
    uint32_t erasesize;
    /* Minimal writable flash unit size. In case of NOR flash it is 1 (even
     * though individual bits can be cleared), in case of NAND flash it is
     * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
     * it is of ECC block size, etc. It is illegal to have writesize = 0.
     * Any driver registering a struct mtd_info must ensure a writesize of
     * 1 or larger.
     */
    uint32_t writesize;

    /*
     * Size of the write buffer used by the MTD. MTD devices having a write
     * buffer can write multiple writesize chunks at a time. E.g. while
     * writing 4 * writesize bytes to a device with 2 * writesize bytes
     * buffer the MTD driver can (but doesn't have to) do 2 writesize
     * operations, but not 4. Currently, all NANDs have writebufsize
     * equivalent to writesize (NAND page size). Some NOR flashes do have
     * writebufsize greater than writesize.
     */
    uint32_t writebufsize;

    uint32_t oobsize;   // Amount of OOB data per block (e.g. 16)
    uint32_t oobavail;  // Available OOB bytes per block

    /*
     * If erasesize is a power of 2 then the shift is stored in
     * erasesize_shift otherwise erasesize_shift is zero. Ditto writesize.
     */
    unsigned int erasesize_shift;
    unsigned int writesize_shift;
    /* Masks based on erasesize_shift and writesize_shift */
    unsigned int erasesize_mask;
    unsigned int writesize_mask;

    /*
     * read ops return -EUCLEAN if max number of bitflips corrected on any
     * one region comprising an ecc step equals or exceeds this value.
     * Settable by driver, else defaults to ecc_strength.  User can override
     * in sysfs.  N.B. The meaning of the -EUCLEAN return code has changed;
     * see Documentation/ABI/testing/sysfs-class-mtd for more detail.
     */
    unsigned int bitflip_threshold;

    // Kernel-only stuff starts here.
    const char *name;
    int index;

    /* ECC layout structure pointer - read only! */
    struct nand_ecclayout *ecclayout;

    /* the ecc step size. */
    unsigned int ecc_step_size;

    /* max number of correctible bit errors per ecc step */
    unsigned int ecc_strength;

    /* Data for variable erase regions. If numeraseregions is zero,
     * it means that the whole device has erasesize as given above.
     */
    int numeraseregions;
    struct mtd_erase_region_info *eraseregions;

    /*
     * Do not call via these pointers, use corresponding mtd_*()
     * wrappers instead.
     */
    int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
    int (*_point) (struct mtd_info *mtd, loff_t from, size_t len,
               size_t *retlen, void **virt, resource_size_t *phys);
    int (*_unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
    unsigned long (*_get_unmapped_area) (struct mtd_info *mtd,
                         unsigned long len,
                         unsigned long offset,
                         unsigned long flags);

    //读取数据,长度随意。
    //如果不满1页,函数内部会找到数据所在的那一页,并读出完整的1页数据,并将长度的数据copy到buf中
    //如果len长度大于1页,则会连续读多个页。
    //在这个函数里都会去读取oob数据,然后进行ecc校验。
    int (*_read) (struct mtd_info *mtd, loff_t from, size_t len,
              size_t *retlen, u_char *buf);
    int (*_write) (struct mtd_info *mtd, loff_t to, size_t len,
               size_t *retlen, const u_char *buf);
    int (*_panic_write) (struct mtd_info *mtd, loff_t to, size_t len,
                 size_t *retlen, const u_char *buf);

    //可以只读Data区的数据(这时候与mtd_info->_read函数功能相同),
    //也可以只读oob区的数据,还可以两者都读出来。
    int (*_read_oob) (struct mtd_info *mtd, loff_t from,
              struct mtd_oob_ops *ops);
    int (*_write_oob) (struct mtd_info *mtd, loff_t to,
               struct mtd_oob_ops *ops);
    int (*_get_fact_prot_info) (struct mtd_info *mtd, size_t len,
                    size_t *retlen, struct otp_info *buf);
    int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from,
                    size_t len, size_t *retlen, u_char *buf);
    int (*_get_user_prot_info) (struct mtd_info *mtd, size_t len,
                    size_t *retlen, struct otp_info *buf);
    int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from,
                    size_t len, size_t *retlen, u_char *buf);
    int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to,
                     size_t len, size_t *retlen, u_char *buf);
    int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
                    size_t len);
    int (*_writev) (struct mtd_info *mtd, const struct kvec *vecs,
            unsigned long count, loff_t to, size_t *retlen);
    void (*_sync) (struct mtd_info *mtd);
    int (*_lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
    int (*_unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
    int (*_is_locked) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
    int (*_block_isreserved) (struct mtd_info *mtd, loff_t ofs);
    int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
    int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
    int (*_suspend) (struct mtd_info *mtd);
    void (*_resume) (struct mtd_info *mtd);
    void (*_reboot) (struct mtd_info *mtd);
    /*
     * If the driver is something smart, like UBI, it may need to maintain
     * its own reference counting. The below functions are only for driver.
     */
    int (*_get_device) (struct mtd_info *mtd);
    void (*_put_device) (struct mtd_info *mtd);

    /* Backing device capabilities for this device
     * - provides mmap capabilities
     */
    struct backing_dev_info *backing_dev_info;

    struct notifier_block reboot_notifier;  /* default mode before reboot */

    //ecc_stats这个名字其实不太准确,看名字它是用来表示ecc状态的,但实际上它有两个用途,
    //一个是用来表示ecc状态(corrected,与failed),
    //另一个是用来表示坏块的情况(badblocks与bbtblocks).mtd_ecc_stats结构体如下:
    //struct mtd_ecc_stats {
    //  __u32 corrected;--表示此flash 在ecc校验时,发现bit反转,但已经被修正的bit数量.
    //  __u32 failed;--表示此flash 在ecc校验时,发现bit反转,但无法被修正的bit数量.
    //  __u32 badblocks;--表示此flash 坏块的数量.
    //  __u32 bbtblocks;--表示此flash 保留块的数量.(保留块应该是用别的用途吧)
    //};
    /* ECC status information */
    struct mtd_ecc_stats ecc_stats;


    //subpage_sft表示这个nand flash 有多少个子页的shift形式表示,
    //如果有2个子页,subpage_sft=1,4个子页则subpage_sft=2。
    //subpage_sft是在nand_scan_tail函数中赋值的。如下:
    //if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
    //  switch (ecc->steps) {
    //  case 2:
    //      mtd->subpage_sft = 1;
    //      break;
    //  case 4:
    //  case 8:
    //  case 16:
    //      mtd->subpage_sft = 2;
    //      break;
    //  }
    //}
    /* Subpage shift (NAND) */
    int subpage_sft;

    void *priv;

    struct module *owner;
    struct device dev;
    int usecount;
};


struct nand_chip {
    void __iomem *IO_ADDR_R;
    void __iomem *IO_ADDR_W;

    //以下这此都是最小粒度的与flash 控制寄存器打交道的函数。
    uint8_t (*read_byte)(struct mtd_info *mtd);
    u16 (*read_word)(struct mtd_info *mtd);
    void (*write_byte)(struct mtd_info *mtd, uint8_t byte);
    void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
    void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
    void (*select_chip)(struct mtd_info *mtd, int chip);
    int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
    int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
    void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
    int (*init_size)(struct mtd_info *mtd, struct nand_chip *this,
            u8 *id_data);
    int (*dev_ready)(struct mtd_info *mtd);
    void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,
            int page_addr);
    int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
    int (*erase)(struct mtd_info *mtd, int page);
    int (*scan_bbt)(struct mtd_info *mtd);

    //这个函数很奇怪,整个kernel代码中都没有为这个函数指针赋值。
    int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
            int status, int page);

    //这个write_page函数一般指向nand_write_page函数,而此函数又会调用
    //nand_ecc_ctrl.write_page_raw函数,而nand_ecc_ctrl.
    //write_page_raw函数又会调到nand_chip->write_buf函数。如下:
    //if (unlikely(raw))
    //  status = chip->ecc.write_page_raw(mtd, chip, buf,oob_required);
    //else if (subpage)
    //  status = chip->ecc.write_subpage(mtd, chip, offset, data_len,buf, oob_required);
    //else
    //  status = chip->ecc.write_page(mtd, chip, buf, oob_required);
    int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
            uint32_t offset, int data_len, const uint8_t *buf,
            int oob_required, int page, int cached, int raw);
    int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,
            int feature_addr, uint8_t *subfeature_para);
    int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
            int feature_addr, uint8_t *subfeature_para);

    //当读取数据核验失败时(,也就是读数据时发生了不可修正的bit反转时)
    //并且重试次数小于read_retries次数时,可重新读取,但在重新读取之前需要调用此函数。
    //如果想要某个nand flash 不支持重试,则让setup_read_retry函数指针等于NULL即可。
    int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);

    int chip_delay;
    unsigned int options;
    unsigned int bbt_options;

    //这个也很简单
    int page_shift;
    int phys_erase_shift;
    int bbt_erase_shift;
    int chip_shift;

    //表示这个nand flash有多少个chip
    int numchips;

    //表示一个chip有多少个字节.mtd->size=nand_chip->chipsize*nand_chip->numchips
    uint64_t chipsize;

    //页掩码,比如一个页大小是2K,则pagemask=0x3ff
    int pagemask;

    //nand_chip->buffers中存放的buff数据是哪一页的buff。
    int pagebuf;

    //在读取一个page或subpage时,执行的几个step读取中被修正的bit最多的一次修正了多少个bit。
    unsigned int pagebuf_bitflips;

    //一个子页的大小,如512 Byte
    int subpagesize;

    //此变量表明一个cell存放几个bit,在nand flash中数据都是存放在cell中的,
    //对于SLC型flash一般一个cell存放一个bit,而对于MLC则有可能存放2个或4个bit。
    uint8_t bits_per_cell;


    uint16_t ecc_strength_ds;
    uint16_t ecc_step_ds;
    int onfi_timing_mode_default;

    //在每个block的第1和第2个页面或最后一个页面的oob区域中存放了这个block的坏块标志,
    //但具体这个坏块标志是在oob区中的哪个偏移量开始的,是由badblockpos指定的。
    //见nand_create_badblock_pattern函数中以下这句:
    //bd->offs = this->badblockpos;
    int badblockpos;

    int badblockbits;

    int onfi_version;
    int jedec_version;
    union {
        struct nand_onfi_params onfi_params;
        struct nand_jedec_params jedec_params;
    };

    //当读取数据核验失败时(,也就是读数据时发生了不可修正的bit反转时)重试的次数。
    int read_retries;

    //指明nand flash当前的操作状态,如正在读(FL_READING)正在写(FL_WRITING),
    //正在擦除(FL_ERASING)等,一般最好通过nand_get_device函数来设置flash状态。
    flstate_t state;

    //oob_poi 用来oob数据的buff,buff大小为mtd_info.oobsize
    uint8_t *oob_poi;
    struct nand_hw_control *controller;

    // nand flash ecc相关数据与操作。
    struct nand_ecc_ctrl ecc;

    //nand flash 一个页面的data 区的buff,struct nand_buffers 
    //中带有此buff的读出来的ecc与计算出来的ecc,见下文介绍
    struct nand_buffers *buffers;
    struct nand_hw_control hwcontrol;

    //bbt用来指向内存中坏块表的
    uint8_t *bbt;

    //linux 会将flash 坏块表bbt存放在flash的某个block中,这样开机时不用每次遍历一
    //遍所有的block的oob区去建立bbt了。而只需要读入这一个block数据,进行解析就可以得到bbt。
    //为了保险起见,坏块表bbt在flash上还存放了两份,这样就算一份坏了,还要以使用另一份。
    //bbt_td就是用来指向正常情况下读取使用的bbt所在的block的,而bbt_md是用来指向备份的那个block
    struct nand_bbt_descr *bbt_td;
    struct nand_bbt_descr *bbt_md;

    //当第一次使用一个flash时,flash上还没有哪个block是存放bbt信息的,
    //这时需要遍历所有的block的oob区去建立bbt,如何遍历呢,就是根据badblock_pattern这个
    //模式去查找oob区中指定的位置是否存在与badblock_pattern->pattern相匹配的字节,
    //匹配的字节长度为badblock_pattern->len,(在nand_bbt.c文件中
    //nand_create_badblock_pattern函数为默认实现,pattern为FF FF,len为两个字节)
    struct nand_bbt_descr *badblock_pattern;

    void *priv;
};


struct nand_ecc_ctrl {
    //ecc计算模式,有几模式,如硬件ecc,软件ecc
    nand_ecc_modes_t mode;

    //nand flash一页数据中,有多少个ecc核验段,因为一个page可能有2K,但一次ecc校验只能管理256或 
    //512Byte,steps=page size/nand_ecc_ctrl->size
    int steps;
    //一次ecc对应data区的多少byte
    int size;
    //一次ecc对应oob区的多少byte
    int bytes;

    //nand中一页data数据对应多少个ecc数据。total=bytes*steps
    int total;

    //在一次ecc中最大可以修正的bit数量,一般是1,当一个bit出错时,可以修正。
    int strength;
    int prepad;

    //ecc数据在oob区的具体存放位置。见网上另一篇文章,链接如下: 
    //http://blog.csdn.net/lanmanck/article/details/5813361
    struct nand_ecclayout   *layout;
    void *priv;

    //用来控制ecc相关的寄存器操作,如
    //NAND_ECC_WRITE是用来将ecc写入ecc寄存器,主要用在数据写入时使用。
    //NAND_ECC_READ是用来reset ecc寄存器,方便接下来读数据时,硬件从新开始计算ecc,
    //并填充寄存器,如下面的使用例子。
    //for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
    //  chip->ecc.hwctl(mtd, NAND_ECC_READ);
    //  chip->read_buf(mtd, p, eccsize);
    //  chip->ecc.calculate(mtd, p, &ecc_calc[i]);
    //}
    void (*hwctl)(struct mtd_info *mtd, int mode);

    //计算ecc值,dat是要计算的数据,ecc_code是存放计算后的结果,
    //当读取一个页数据时要调用nand_ecc_ctrl->steps次此函数才能计算完一页的ecc出来。
    //另外对于带硬件ecc功能的nand flash 控制器而言这个函数就是读ecc 的寄存器,见hwctl函数上的例子。
    //而且对应硬件ecc来说,必须每读一个step后立刻去读ecc寄存器。
    //对于软件ecc,则可以先把一页数据都读出来后,再针对每一个step长度的数据一一计算ecc。
    int (*calculate)(struct mtd_info *mtd, const uint8_t *dat,
            uint8_t *ecc_code);

    //根据计算出来的ecc与读出来的ecc修正dat中的数据反转位,返回值表示修正了多少个bit。
    int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc,
            uint8_t *calc_ecc);

    //读取一页最原始的数据,不进行任何核验和处理,见下面的nand_read_page_raw函数,
    //此函数在nand_base.c文件实现,当nand flash驱动没有实现read_page_raw函数时,
    //将会默认设置为这个函数。
    //static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
    //            uint8_t *buf, int oob_required, int page)
    //{
    //  chip->read_buf(mtd, buf, mtd->writesize);
    //  if (oob_required)
    //      chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
    //  return 0;
    //}
    int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
            uint8_t *buf, int oob_required, int page);
    int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
            const uint8_t *buf, int oob_required);

    //读取一页最原始的数据,带核验与修正bit功能。返回值表示在读此页的过程中某个step读取过程中修正的bit最多的一次修正了几个bit。
    int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
            uint8_t *buf, int oob_required, int page);
    int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
            const uint8_t *buf, int oob_required);

    //读一个子页,有些nand flash支持子页的功能,一个页可以分为几个子页,一般比如一个512Byte的页可以分为2个256Byte的子页。此函数除了读的是而不是页外,其它功能与nand_ecc_ctrl->read_page功能是相同的,也带有核验与修正bit功能。
    int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
            uint32_t offs, uint32_t len, uint8_t *buf, int page);
    int (*write_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
            uint32_t offset, uint32_t data_len,
            const uint8_t *data_buf, int oob_required);

    //一般情况下,与nand_ecc_ctrl->read_oob函数功能相同,
    //这一点可以从nand_base.c文件中nand_scan_tail函数中以下代码看出
    //  if (!ecc->read_oob_raw)
    //  ecc->read_oob_raw = ecc->read_oob;
    //if (!ecc->write_oob_raw)
    //  ecc->write_oob_raw = ecc->write_oob;
    //即然是一般情况下与nand_ecc_ctrl->read_oob函数功能相同,那什么时候不同呢,
    //我想应该是在当nand_ecc_ctrl->read_oob在读取oob数据时提供核验功能或修正功能时,
    //这个功能只负责读取不做其它的事情。
    int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
            int page);
    int (*read_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
            int page);

    //只读取oob区的数据,不读data区数据。
    int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page);
    int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip,
            int page);
};

struct nand_buffers表示nand flash 一个页面的data 区的buff,带有此buff的读出来的ecc与计算出来的ecc,ecccalc表示计算出来的ecc,ecccode表示从oob区读出来的ecc

struct nand_buffers {
    uint8_t *ecccalc;
    uint8_t *ecccode;
    uint8_t *databuf;
};



感觉nand_bbt_descr是一个神奇的结构体,它有两个用途,先说一下它用在哪个地方吧,它在3个地方出现了,而且是在同一个结构体中出现3个nand_bbt_descr指针,那就是nand_chip。见下:
struct nand_chip {
    ....
    struct nand_bbt_descr *bbt_td;
    struct nand_bbt_descr *bbt_md;
    struct nand_bbt_descr *badblock_pattern;
    ....
}
bbt_td与bbt_md用来搜索与存放bbt在哪个blocak
badblock_pattern用来搜索oob区域中的坏块标志

struct nand_bbt_descr {
    int options;
    int pages[NAND_MAX_CHIPS];
    int offs;
    int veroffs;
    uint8_t version[NAND_MAX_CHIPS];
    int len;
    int maxblocks;
    int reserved_block_code;
    uint8_t *pattern;
};
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的带cache的nand flash驱动的示例代码: ```c #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #define CACHE_SIZE 4096 struct nand_cache { u8 data[CACHE_SIZE]; int page; bool dirty; }; struct my_nand { struct nand_chip chip; struct nand_cache cache; }; static int my_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t page, uint8_t *buf, int len) { struct my_nand *my_chip = container_of(chip, struct my_nand, chip); if (my_chip->cache.page == page) { memcpy(buf, my_chip->cache.data, len); } else { int ret = nand_read_page(mtd, chip, page, buf, len); if (ret == 0) { my_chip->cache.page = page; memcpy(my_chip->cache.data, buf, len); } return ret; } } static int my_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t page, uint8_t *buf, int len) { struct my_nand *my_chip = container_of(chip, struct my_nand, chip); int ret = nand_write_page(mtd, chip, page, buf, len); if (ret == 0) { my_chip->cache.page = page; memcpy(my_chip->cache.data, buf, len); my_chip->cache.dirty = true; } return ret; } static int my_nand_erase(struct mtd_info *mtd, struct erase_info *instr) { struct my_nand *my_chip = container_of(mtd_to_nand(mtd), struct my_nand, chip); int ret = nand_erase(mtd, instr); if (ret == 0) { my_chip->cache.page = -1; my_chip->cache.dirty = false; } return ret; } static struct my_nand my_nand_chip = { .chip = { .read_page = my_nand_read_page, .write_page = my_nand_write_page, .erase = my_nand_erase, // ...other nand_chip functions }, .cache = { .page = -1, .dirty = false, }, }; static int my_nand_probe(struct platform_device *pdev) { int ret; // Initialize the nand_chip structure my_nand_chip.chip.dev.parent = &pdev->dev; my_nand_chip.chip.IO_ADDR_R = /* NAND read address */; my_nand_chip.chip.IO_ADDR_W = /* NAND write address */; // ...other nand_chip initialization // Register the NAND flash with the MTD subsystem ret = nand_scan(&my_nand_chip.chip, /* number of chip enables */, NULL); if (ret != 0) { return ret; } // Register the MTD device ret = mtd_device_register(&my_nand_chip.chip, /* partition info */, /* number of partitions */, NULL); if (ret != 0) { nand_release(&my_nand_chip.chip); return ret; } return 0; } static int my_nand_remove(struct platform_device *pdev) { mtd_device_unregister(&my_nand_chip.chip); nand_release(&my_nand_chip.chip); return 0; } static struct platform_driver my_nand_driver = { .probe = my_nand_probe, .remove = my_nand_remove, .driver = { .name = "my_nand", // ...other driver information }, }; module_platform_driver(my_nand_driver); ``` 上面的代码中,`my_nand_read_page`和`my_nand_write_page`函数会先检查缓存中是否有该页的数据,如果有就直接从缓存中读取或将数据写入缓存。如果缓存中没有该页的数据,则调用原始的`nand_read_page`或`nand_write_page`函数读取或写入NAND flash,并更新缓存。`my_nand_erase`函数会在NAND flash擦除时清除缓存。在`my_nand_chip`结构体中,我们通过`cache`成员变量来保存缓存的数据和状态。在`my_nand_probe`函数中,我们先初始化`my_nand_chip`结构体的`chip`成员,然后调用`nand_scan`函数注册NAND flash,并调用`mtd_device_register`函数注册MTD设备。在`my_nand_remove`函数中,我们需要注销MTD设备和NAND flash。最后,我们使用`module_platform_driver`宏来注册驱动程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值