查看: 2623|回复: 1

[Linux技术] ARM-Linux驱动--MTD驱动分析(三)

[复制链接]
  • TA的每日心情

    2014-4-10 13:56
  • 签到天数: 5 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2014-1-23 09:03:07 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 forlinx2013 于 2014-1-24 09:19 编辑

    欢迎大家来到飞凌爱板网专区,对嵌入式技术感兴趣的朋友不妨多多关注一下,我们提供了公司所有开发板的所有资料,也会更新大量技术文章,欢迎大家一块学习提高!!!

    主机:Gentoo Linux 11.2 with linux kernel 3.0.6
    硬件平台:FL2440S3C2440with linux kernel 2.6.35

    本文分析MTD设备的分区管理机制
    分区管理实际上是将一个MTD设备分成几个分区,将其作为单独的MTD原始设备进行管理。
    1、分区的结构体描述结构体mtd_part
    1 /* Our partition node structure */  
    2 //分区结构信息   
    3 struct mtd_part {  
    4     struct mtd_info mtd;//mtd_info数据结构,会被加入mtd_table中   
    5     struct mtd_info *master;//该分区的主分区   
    6     uint64_t offset;//该分区的偏移地址   
    7     struct list_head list;  
    8 };  
    /* Our partition node structure */
    //分区结构信息
    struct mtd_part {
        struct mtd_info mtd;//mtd_info数据结构,会被加入mtd_table
        struct mtd_info *master;//该分区的主分区
        uint64_t offset;//该分区的偏移地址
        struct list_head list;
    };

    2、分区链表mtd_partitions
    9 /* Our partition linked list */  
    10 //声明mtd_partitions链表   
    11 static LIST_HEAD(mtd_partitions);  
    /* Our partition linked list */
    //声明mtd_partitions链表
    static LIST_HEAD(mtd_partitions);

    3、add_mtd_partitions函数
    12 /*
    13  * This function, given a master MTD object and a partition table, creates
    14  * and registers slave MTD objects which are bound to the master according to
    15  * the partition definitions.
    16  *
    17  * We don't register the master, or expect the caller to have done so,
    18  * for reasons of data integrity.
    19  */  
    20 //根据一个MTD主设备和分区表,创建新的主设备下的副设备并记录到分区表中   
    21 //这里我们不将注射被注册到分区表中,只注册副设备到到分区表中   
    22 int add_mtd_partitions(struct mtd_info *master,  
    23                const struct mtd_partition *parts,  
    24                int nbparts)  
    25 {  
    26     struct mtd_part *slave;  
    27     uint64_t cur_offset = 0;  
    28     int i;  
    29   
    30     printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);  
    31   
    32     for (i = 0; i < nbparts; i++) {//对每一个分区调用add_one_partition函数更新分区表   
    33         slave = add_one_partition(master, parts + i, i, cur_offset);  
    34         if (!slave)  
    35             return -ENOMEM;  
    36         cur_offset = slave->offset + slave->mtd.size;  
    37     }  
    38   
    39     return 0;  
    40 }  
    41 EXPORT_SYMBOL(add_mtd_partitions);  
    /*
    * This function, given a master MTD object and a partition table, creates
    * and registers slave MTD objects which are bound to the master according to
    * the partition definitions.
    *
    * We don't register the master, or expect the caller to have done so,
    * for reasons of data integrity.
    */
    //根据一个MTD主设备和分区表,创建新的主设备下的副设备并记录到分区表中
    //这里我们不将注射被注册到分区表中,只注册副设备到到分区表中
    int add_mtd_partitions(struct mtd_info *master,
                   const struct mtd_partition *parts,
                   int nbparts)
    {
        struct mtd_part *slave;
        uint64_t cur_offset = 0;
        int i;

        printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);

        for (i = 0; i < nbparts; i++) {//对每一个分区调用add_one_partition函数更新分区表
            slave = add_one_partition(master, parts + i, i, cur_offset);
            if (!slave)
                return -ENOMEM;
            cur_offset = slave->offset + slave->mtd.size;
        }

        return 0;
    }
    EXPORT_SYMBOL(add_mtd_partitions);

    而add_one_partition函数实现如下:
    42 //创建一个分区   
    43 static struct mtd_part *add_one_partition(struct mtd_info *master,  
    44         const struct mtd_partition *part, int partno,  
    45         uint64_t cur_offset)  
    46 {  
    47     struct mtd_part *slave;  
    48   
    49     /* allocate the partition structure */  
    50     slave = kzalloc(sizeof(*slave), GFP_KERNEL);//分配内存   
    51     if (!slave) {  
    52         printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n",  
    53             master->name);  
    54         del_mtd_partitions(master);  
    55         return NULL;  
    56     }  
    57     list_add(&slave->list, &mtd_partitions);//将原始设备表添加到分区表中   
    58   
    59     /* set up the MTD object for this partition */  
    60     //大部分根据master相应的信息设置MTD分区slave的信息   
    61     slave->mtd.type = master->type;  
    62     slave->mtd.flags = master->flags & ~part->mask_flags;  
    63     slave->mtd.size = part->size;  
    64     slave->mtd.writesize = master->writesize;  
    65     slave->mtd.oobsize = master->oobsize;  
    66     slave->mtd.oobavail = master->oobavail;  
    67     slave->mtd.subpage_sft = master->subpage_sft;  
    68   
    69     slave->mtd.name = part->name;  
    70     slave->mtd.owner = master->owner;  
    71     slave->mtd.backing_dev_info = master->backing_dev_info;  
    72   
    73     /* NOTE:  we don't arrange MTDs as a tree; it'd be error-prone
    74      * to have the same data be in two different partitions.
    75      */  
    76     slave->mtd.dev.parent = master->dev.parent;  
    77   
    78     slave->mtd.read = part_read;  
    79     slave->mtd.write = part_write;  
    80   
    81     if (master->panic_write)  
    82         slave->mtd.panic_write = part_panic_write;  
    83   
    84     if (master->point && master->unpoint) {  
    85         slave->mtd.point = part_point;  
    86         slave->mtd.unpoint = part_unpoint;  
    87     }  
    88   
    89     if (master->get_unmapped_area)  
    90         slave->mtd.get_unmapped_area = part_get_unmapped_area;  
    91     if (master->read_oob)  
    92         slave->mtd.read_oob = part_read_oob;  
    93     if (master->write_oob)  
    94         slave->mtd.write_oob = part_write_oob;  
    95     if (master->read_user_prot_reg)  
    96         slave->mtd.read_user_prot_reg = part_read_user_prot_reg;  
    97     if (master->read_fact_prot_reg)  
    98         slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;  
    99     if (master->write_user_prot_reg)  
    100         slave->mtd.write_user_prot_reg = part_write_user_prot_reg;  
    101     if (master->lock_user_prot_reg)  
    102         slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;  
    103     if (master->get_user_prot_info)  
    104         slave->mtd.get_user_prot_info = part_get_user_prot_info;  
    105     if (master->get_fact_prot_info)  
    106         slave->mtd.get_fact_prot_info = part_get_fact_prot_info;  
    107     if (master->sync)  
    108         slave->mtd.sync = part_sync;  
    109     if (!partno && !master->dev.class && master->suspend && master->resume) {  
    110             slave->mtd.suspend = part_suspend;  
    111             slave->mtd.resume = part_resume;  
    112     }  
    113     if (master->writev)  
    114         slave->mtd.writev = part_writev;  
    115     if (master->lock)  
    116         slave->mtd.lock = part_lock;  
    117     if (master->unlock)  
    118         slave->mtd.unlock = part_unlock;  
    119     if (master->block_isbad)  
    120         slave->mtd.block_isbad = part_block_isbad;  
    121     if (master->block_markbad)  
    122         slave->mtd.block_markbad = part_block_markbad;  
    123     slave->mtd.erase = part_erase;  
    124     slave->master = master;  
    125     slave->offset = part->offset;  
    126   
    127     if (slave->offset == MTDPART_OFS_APPEND)  
    128         slave->offset = cur_offset;  
    129     if (slave->offset == MTDPART_OFS_NXTBLK) {  
    130         slave->offset = cur_offset;  
    131         if (mtd_mod_by_eb(cur_offset, master) != 0) {  
    132             /* Round up to next erasesize */  
    133             slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;  
    134             printk(KERN_NOTICE "Moving partition %d: "  
    135                    "0x%012llx -> 0x%012llx\n", partno,  
    136                    (unsigned long long)cur_offset, (unsigned long long)slave->offset);  
    137         }  
    138     }  
    139     if (slave->mtd.size == MTDPART_SIZ_FULL)  
    140         slave->mtd.size = master->size - slave->offset;  
    141   
    142     printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset,  
    143         (unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name);  
    144   
    145     /* let's do some sanity checks */  
    146     if (slave->offset >= master->size) {  
    147         /* let's register it anyway to preserve ordering */  
    148         slave->offset = 0;  
    149         slave->mtd.size = 0;  
    150         printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n",  
    151             part->name);  
    152         goto out_register;  
    153     }  
    154     if (slave->offset + slave->mtd.size > master->size) {  
    155         slave->mtd.size = master->size - slave->offset;  
    156         printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n",  
    157             part->name, master->name, (unsigned long long)slave->mtd.size);  
    158     }  
    159     if (master->numeraseregions > 1) {  
    160         /* Deal with variable erase size stuff */  
    161         int i, max = master->numeraseregions;  
    162         u64 end = slave->offset + slave->mtd.size;  
    163         struct mtd_erase_region_info *regions = master->eraseregions;  
    164   
    165         /* Find the first erase regions which is part of this
    166          * partition. */  
    167         for (i = 0; i < max && regions.offset <= slave->offset; i++)  
    168             ;  
    169         /* The loop searched for the region _behind_ the first one */  
    170         if (i > 0)  
    171             i--;  
    172   
    173         /* Pick biggest erasesize */  
    174         for (; i < max && regions.offset < end; i++) {  
    175             if (slave->mtd.erasesize < regions.erasesize) {  
    176                 slave->mtd.erasesize = regions.erasesize;  
    177             }  
    178         }  
    179         BUG_ON(slave->mtd.erasesize == 0);  
    180     } else {  
    181         /* Single erase size */  
    182         slave->mtd.erasesize = master->erasesize;  
    183     }  
    184   
    185     if ((slave->mtd.flags & MTD_WRITEABLE) &&  
    186         mtd_mod_by_eb(slave->offset, &slave->mtd)) {  
    187         /* Doesn't start on a boundary of major erase size */  
    188         /* FIXME: Let it be writable if it is on a boundary of
    189          * _minor_ erase size though */  
    190         slave->mtd.flags &= ~MTD_WRITEABLE;  
    191         printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",  
    192             part->name);  
    193     }  
    194     if ((slave->mtd.flags & MTD_WRITEABLE) &&  
    195         mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {  
    196         slave->mtd.flags &= ~MTD_WRITEABLE;  
    197         printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",  
    198             part->name);  
    199     }  
    200   
    201     slave->mtd.ecclayout = master->ecclayout;  
    202     if (master->block_isbad) {  
    203         uint64_t offs = 0;  
    204   
    205         while (offs < slave->mtd.size) {  
    206             if (master->block_isbad(master,  
    207                         offs + slave->offset))  
    208                 slave->mtd.ecc_stats.badblocks++;  
    209             offs += slave->mtd.erasesize;  
    210         }  
    211     }  
    212   
    213 out_register:  
    214     /* register our partition */  
    215     //最后调用add_mtd_device根据该设备的mtd_info信息添加设备链表,将其作为一个独立的MTD原始设备   
    216     add_mtd_device(&slave->mtd);  
    217   
    218     return slave;  
    219 }  
    //创建一个分区
    static struct mtd_part *add_one_partition(struct mtd_info *master,
            const struct mtd_partition *part, int partno,
            uint64_t cur_offset)
    {
        struct mtd_part *slave;

        /* allocate the partition structure */
        slave = kzalloc(sizeof(*slave), GFP_KERNEL);//分配内存
        if (!slave) {
            printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n",
                master->name);
            del_mtd_partitions(master);
            return NULL;
        }
        list_add(&slave->list, &mtd_partitions);//将原始设备表添加到分区表中

        /* set up the MTD object for this partition */
        //大部分根据master相应的信息设置MTD分区slave的信息
        slave->mtd.type = master->type;
        slave->mtd.flags = master->flags & ~part->mask_flags;
        slave->mtd.size = part->size;
        slave->mtd.writesize = master->writesize;
        slave->mtd.oobsize = master->oobsize;
        slave->mtd.oobavail = master->oobavail;
        slave->mtd.subpage_sft = master->subpage_sft;

        slave->mtd.name = part->name;
        slave->mtd.owner = master->owner;
        slave->mtd.backing_dev_info = master->backing_dev_info;

        /* NOTE:  we don't arrange MTDs as a tree; it'd be error-prone
         * to have the same data be in two different partitions.
         */
        slave->mtd.dev.parent = master->dev.parent;

        slave->mtd.read = part_read;
        slave->mtd.write = part_write;

        if (master->panic_write)
            slave->mtd.panic_write = part_panic_write;

        if (master->point && master->unpoint) {
            slave->mtd.point = part_point;
            slave->mtd.unpoint = part_unpoint;
        }

        if (master->get_unmapped_area)
            slave->mtd.get_unmapped_area = part_get_unmapped_area;
        if (master->read_oob)
            slave->mtd.read_oob = part_read_oob;
        if (master->write_oob)
            slave->mtd.write_oob = part_write_oob;
        if (master->read_user_prot_reg)
            slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
        if (master->read_fact_prot_reg)
            slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
        if (master->write_user_prot_reg)
            slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
        if (master->lock_user_prot_reg)
            slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
        if (master->get_user_prot_info)
            slave->mtd.get_user_prot_info = part_get_user_prot_info;
        if (master->get_fact_prot_info)
            slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
        if (master->sync)
            slave->mtd.sync = part_sync;
        if (!partno && !master->dev.class && master->suspend && master->resume) {
                slave->mtd.suspend = part_suspend;
                slave->mtd.resume = part_resume;
        }
        if (master->writev)
            slave->mtd.writev = part_writev;
        if (master->lock)
            slave->mtd.lock = part_lock;
        if (master->unlock)
            slave->mtd.unlock = part_unlock;
        if (master->block_isbad)
            slave->mtd.block_isbad = part_block_isbad;
        if (master->block_markbad)
            slave->mtd.block_markbad = part_block_markbad;
        slave->mtd.erase = part_erase;
        slave->master = master;
        slave->offset = part->offset;

        if (slave->offset == MTDPART_OFS_APPEND)
            slave->offset = cur_offset;
        if (slave->offset == MTDPART_OFS_NXTBLK) {
            slave->offset = cur_offset;
            if (mtd_mod_by_eb(cur_offset, master) != 0) {
                /* Round up to next erasesize */
                slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
                printk(KERN_NOTICE "Moving partition %d: "
                       "0x%012llx -> 0x%012llx\n", partno,
                       (unsigned long long)cur_offset, (unsigned long long)slave->offset);
            }
        }
        if (slave->mtd.size == MTDPART_SIZ_FULL)
            slave->mtd.size = master->size - slave->offset;

        printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset,
            (unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name);

        /* let's do some sanity checks */
        if (slave->offset >= master->size) {
            /* let's register it anyway to preserve ordering */
            slave->offset = 0;
            slave->mtd.size = 0;
            printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n",
                part->name);
            goto out_register;
        }
        if (slave->offset + slave->mtd.size > master->size) {
            slave->mtd.size = master->size - slave->offset;
            printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n",
                part->name, master->name, (unsigned long long)slave->mtd.size);
        }
        if (master->numeraseregions > 1) {
            /* Deal with variable erase size stuff */
            int i, max = master->numeraseregions;
            u64 end = slave->offset + slave->mtd.size;
            struct mtd_erase_region_info *regions = master->eraseregions;

            /* Find the first erase regions which is part of this
             * partition. */
            for (i = 0; i < max && regions.offset <= slave->offset; i++)
                ;
            /* The loop searched for the region _behind_ the first one */
            if (i > 0)
                i--;

            /* Pick biggest erasesize */
            for (; i < max && regions.offset < end; i++) {
                if (slave->mtd.erasesize < regions.erasesize) {
                    slave->mtd.erasesize = regions.erasesize;
                }
            }
            BUG_ON(slave->mtd.erasesize == 0);
        } else {
            /* Single erase size */
            slave->mtd.erasesize = master->erasesize;
        }

        if ((slave->mtd.flags & MTD_WRITEABLE) &&
            mtd_mod_by_eb(slave->offset, &slave->mtd)) {
            /* Doesn't start on a boundary of major erase size */
            /* FIXME: Let it be writable if it is on a boundary of
             * _minor_ erase size though */
            slave->mtd.flags &= ~MTD_WRITEABLE;
            printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
                part->name);
        }
        if ((slave->mtd.flags & MTD_WRITEABLE) &&
            mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
            slave->mtd.flags &= ~MTD_WRITEABLE;
            printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
                part->name);
        }

        slave->mtd.ecclayout = master->ecclayout;
        if (master->block_isbad) {
            uint64_t offs = 0;

            while (offs < slave->mtd.size) {
                if (master->block_isbad(master,
                            offs + slave->offset))
                    slave->mtd.ecc_stats.badblocks++;
                offs += slave->mtd.erasesize;
            }
        }

    out_register:
        /* register our partition */
        //最后调用add_mtd_device根据该设备的mtd_info信息添加设备链表,将其作为一个独立的MTD原始设备
        add_mtd_device(&slave->mtd);

        return slave;
    }


    4、del_mtd_partition函数
    220 /*
    221  * This function unregisters and destroy all slave MTD objects which are
    222  * attached to the given master MTD object.
    223  */  
    224 //将一个主设备下的所有副设备删除   
    225 int del_mtd_partitions(struct mtd_info *master)  
    226 {  
    227     struct mtd_part *slave, *next;  
    228   
    229     list_for_each_entry_safe(slave, next, &mtd_partitions, list)//遍历mtd_partitions链表,查找到指定的主设备   
    230         if (slave->master == master) {  
    231             list_del(&slave->list);//将主设备下的附属设备删除   
    232             del_mtd_device(&slave->mtd);//调用del_mtd_device函数将每个设备从MTD原始设备表中删除   
    233             kfree(slave);//释放内存   
    234         }  
    235   
    236     return 0;  
    237 }  
    238 EXPORT_SYMBOL(del_mtd_partitions);  
    /*
    * This function unregisters and destroy all slave MTD objects which are
    * attached to the given master MTD object.
    */
    //将一个主设备下的所有副设备删除
    int del_mtd_partitions(struct mtd_info *master)
    {
        struct mtd_part *slave, *next;

        list_for_each_entry_safe(slave, next, &mtd_partitions, list)//遍历mtd_partitions链表,查找到指定的主设备
            if (slave->master == master) {
                list_del(&slave->list);//将主设备下的附属设备删除
                del_mtd_device(&slave->mtd);//调用del_mtd_device函数将每个设备从MTD原始设备表中删除
                kfree(slave);//释放内存
            }

        return 0;
    }
    EXPORT_SYMBOL(del_mtd_partitions);


    回复

    使用道具 举报

  • TA的每日心情

    2014-4-10 13:56
  • 签到天数: 5 天

    连续签到: 1 天

    [LV.2]偶尔看看I

     楼主| 发表于 2014-1-23 09:05:07 | 显示全部楼层
    本帖最后由 forlinx2013 于 2014-1-24 09:19 编辑

    欢迎大家来到飞凌爱板网专区,对嵌入式技术感兴趣的朋友不妨多多关注一下,我们提供了公司所有开发板的所有资料,也会更新大量技术文章,欢迎大家一块学习提高!!!

    5、其他的分区管理函数
    [cpp]view plaincopyprint?
    239 /*
    240  * MTD methods which simply translate the effective address and pass through
    241  * to the _real_ device.
    242  */  
    243 //读取某个分区的指定数据   
    244 static int part_read(struct mtd_info *mtd, loff_t from, size_t len,  
    245         size_t *retlen, u_char *buf)  
    246 {  
    247     struct mtd_part *part = PART(mtd);  
    248     struct mtd_ecc_stats stats;  
    249     int res;  
    250   
    251     stats = part->master->ecc_stats;  
    252   
    253     if (from >= mtd->size)  
    254         len = 0;  
    255     else if (from + len > mtd->size)  
    256         len = mtd->size - from;  
    257     res = part->master->read(part->master, from + part->offset,  
    258                    len, retlen, buf);  
    259     if (unlikely(res)) {  
    260         if (res == -EUCLEAN)  
    261             mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;  
    262         if (res == -EBADMSG)  
    263             mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;  
    264     }  
    265     return res;  
    266 }  
    267   
    268 static int part_point(struct mtd_info *mtd, loff_t from, size_t len,  
    269         size_t *retlen, void **virt, resource_size_t *phys)  
    270 {  
    271     struct mtd_part *part = PART(mtd);  
    272     if (from >= mtd->size)  
    273         len = 0;  
    274     else if (from + len > mtd->size)  
    275         len = mtd->size - from;  
    276     return part->master->point (part->master, from + part->offset,  
    277                     len, retlen, virt, phys);  
    278 }  
    279   
    280 static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)  
    281 {  
    282     struct mtd_part *part = PART(mtd);  
    283   
    284     part->master->unpoint(part->master, from + part->offset, len);  
    285 }  
    286 //获取空闲的内存驱动   
    287 static unsigned long part_get_unmapped_area(struct mtd_info *mtd,  
    288                         unsigned long len,  
    289                         unsigned long offset,  
    290                         unsigned long flags)  
    291 {  
    292     struct mtd_part *part = PART(mtd);  
    293   
    294     offset += part->offset;  
    295     return part->master->get_unmapped_area(part->master, len, offset,  
    296                            flags);  
    297 }  
    298   
    299 static int part_read_oob(struct mtd_info *mtd, loff_t from,  
    300         struct mtd_oob_ops *ops)  
    301 {  
    302     struct mtd_part *part = PART(mtd);  
    303     int res;  
    304   
    305     if (from >= mtd->size)  
    306         return -EINVAL;  
    307     if (ops->datbuf && from + ops->len > mtd->size)  
    308         return -EINVAL;  
    309     res = part->master->read_oob(part->master, from + part->offset, ops);  
    310   
    311     if (unlikely(res)) {  
    312         if (res == -EUCLEAN)  
    313             mtd->ecc_stats.corrected++;  
    314         if (res == -EBADMSG)  
    315             mtd->ecc_stats.failed++;  
    316     }  
    317     return res;  
    318 }  
    319   
    320 static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,  
    321         size_t len, size_t *retlen, u_char *buf)  
    322 {  
    323     struct mtd_part *part = PART(mtd);  
    324     return part->master->read_user_prot_reg(part->master, from,  
    325                     len, retlen, buf);  
    326 }  
    327   
    328 static int part_get_user_prot_info(struct mtd_info *mtd,  
    329         struct otp_info *buf, size_t len)  
    330 {  
    331     struct mtd_part *part = PART(mtd);  
    332     return part->master->get_user_prot_info(part->master, buf, len);  
    333 }  
    334   
    335 static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,  
    336         size_t len, size_t *retlen, u_char *buf)  
    337 {  
    338     struct mtd_part *part = PART(mtd);  
    339     return part->master->read_fact_prot_reg(part->master, from,  
    340                     len, retlen, buf);  
    341 }  
    342   
    343 static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,  
    344         size_t len)  
    345 {  
    346     struct mtd_part *part = PART(mtd);  
    347     return part->master->get_fact_prot_info(part->master, buf, len);  
    348 }  
    349 //分区写函数   
    350 static int part_write(struct mtd_info *mtd, loff_t to, size_t len,  
    351         size_t *retlen, const u_char *buf)  
    352 {  
    353     struct mtd_part *part = PART(mtd);  
    354     if (!(mtd->flags & MTD_WRITEABLE))  
    355         return -EROFS;  
    356     if (to >= mtd->size)  
    357         len = 0;  
    358     else if (to + len > mtd->size)  
    359         len = mtd->size - to;  
    360     return part->master->write(part->master, to + part->offset,  
    361                     len, retlen, buf);  
    362 }  
    363   
    364 static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,  
    365         size_t *retlen, const u_char *buf)  
    366 {  
    367     struct mtd_part *part = PART(mtd);  
    368     if (!(mtd->flags & MTD_WRITEABLE))  
    369         return -EROFS;  
    370     if (to >= mtd->size)  
    371         len = 0;  
    372     else if (to + len > mtd->size)  
    373         len = mtd->size - to;  
    374     return part->master->panic_write(part->master, to + part->offset,  
    375                     len, retlen, buf);  
    376 }  
    377   
    378 static int part_write_oob(struct mtd_info *mtd, loff_t to,  
    379         struct mtd_oob_ops *ops)  
    380 {  
    381     struct mtd_part *part = PART(mtd);  
    382   
    383     if (!(mtd->flags & MTD_WRITEABLE))  
    384         return -EROFS;  
    385   
    386     if (to >= mtd->size)  
    387         return -EINVAL;  
    388     if (ops->datbuf && to + ops->len > mtd->size)  
    389         return -EINVAL;  
    390     return part->master->write_oob(part->master, to + part->offset, ops);  
    391 }  
    392   
    393 static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,  
    394         size_t len, size_t *retlen, u_char *buf)  
    395 {  
    396     struct mtd_part *part = PART(mtd);  
    397     return part->master->write_user_prot_reg(part->master, from,  
    398                     len, retlen, buf);  
    399 }  
    400   
    401 static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,  
    402         size_t len)  
    403 {  
    404     struct mtd_part *part = PART(mtd);  
    405     return part->master->lock_user_prot_reg(part->master, from, len);  
    406 }  
    407   
    408 static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,  
    409         unsigned long count, loff_t to, size_t *retlen)  
    410 {  
    411     struct mtd_part *part = PART(mtd);  
    412     if (!(mtd->flags & MTD_WRITEABLE))  
    413         return -EROFS;  
    414     return part->master->writev(part->master, vecs, count,  
    415                     to + part->offset, retlen);  
    416 }  
    417   
    418 static int part_erase(struct mtd_info *mtd, struct erase_info *instr)  
    419 {  
    420     struct mtd_part *part = PART(mtd);  
    421     int ret;  
    422     if (!(mtd->flags & MTD_WRITEABLE))  
    423         return -EROFS;  
    424     if (instr->addr >= mtd->size)  
    425         return -EINVAL;  
    426     instr->addr += part->offset;  
    427     ret = part->master->erase(part->master, instr);  
    428     if (ret) {  
    429         if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)  
    430             instr->fail_addr -= part->offset;  
    431         instr->addr -= part->offset;  
    432     }  
    433     return ret;  
    434 }  
    435   
    436 void mtd_erase_callback(struct erase_info *instr)  
    437 {  
    438     if (instr->mtd->erase == part_erase) {  
    439         struct mtd_part *part = PART(instr->mtd);  
    440   
    441         if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)  
    442             instr->fail_addr -= part->offset;  
    443         instr->addr -= part->offset;  
    444     }  
    445     if (instr->callback)  
    446         instr->callback(instr);  
    447 }  
    448 EXPORT_SYMBOL_GPL(mtd_erase_callback);  
    449   
    450 static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  
    451 {  
    452     struct mtd_part *part = PART(mtd);  
    453     if ((len + ofs) > mtd->size)  
    454         return -EINVAL;  
    455     return part->master->lock(part->master, ofs + part->offset, len);  
    456 }  
    457   
    458 static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  
    459 {  
    460     struct mtd_part *part = PART(mtd);  
    461     if ((len + ofs) > mtd->size)  
    462         return -EINVAL;  
    463     return part->master->unlock(part->master, ofs + part->offset, len);  
    464 }  
    465 //分区同步函数   
    466 static void part_sync(struct mtd_info *mtd)  
    467 {  
    468     struct mtd_part *part = PART(mtd);  
    469     part->master->sync(part->master);  
    470 }  
    471 //支持电源管理的功能函数   
    472 static int part_suspend(struct mtd_info *mtd)  
    473 {  
    474     struct mtd_part *part = PART(mtd);  
    475     return part->master->suspend(part->master);  
    476 }  
    477   
    478 static void part_resume(struct mtd_info *mtd)  
    479 {  
    480     struct mtd_part *part = PART(mtd);  
    481     part->master->resume(part->master);  
    482 }  
    483   
    484 static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)  
    485 {  
    486     struct mtd_part *part = PART(mtd);  
    487     if (ofs >= mtd->size)  
    488         return -EINVAL;  
    489     ofs += part->offset;  
    490     return part->master->block_isbad(part->master, ofs);  
    491 }  
    492 //标记设备地址坏块   
    493 static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)  
    494 {  
    495     struct mtd_part *part = PART(mtd);  
    496     int res;  
    497   
    498     if (!(mtd->flags & MTD_WRITEABLE))  
    499         return -EROFS;  
    500     if (ofs >= mtd->size)  
    501         return -EINVAL;  
    502     ofs += part->offset;  
    503     res = part->master->block_markbad(part->master, ofs);  
    504     if (!res)  
    505         mtd->ecc_stats.badblocks++;  
    506     return res;  
    507 }  
    /*
    * MTD methods which simply translate the effective address and pass through
    * to the _real_ device.
    */
    //读取某个分区的指定数据
    static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
            size_t *retlen, u_char *buf)
    {
        struct mtd_part *part = PART(mtd);
        struct mtd_ecc_stats stats;
        int res;
        stats = part->master->ecc_stats;
        if (from >= mtd->size)
            len = 0;
        else if (from + len > mtd->size)
            len = mtd->size - from;
        res = part->master->read(part->master, from + part->offset,
                       len, retlen, buf);
        if (unlikely(res)) {
            if (res == -EUCLEAN)
                mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
            if (res == -EBADMSG)
                mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
        }
        return res;
    }
    static int part_point(struct mtd_info *mtd, loff_t from, size_t len,
            size_t *retlen, void **virt, resource_size_t *phys)
    {
        struct mtd_part *part = PART(mtd);
        if (from >= mtd->size)
            len = 0;
        else if (from + len > mtd->size)
            len = mtd->size - from;
        return part->master->point (part->master, from + part->offset,
                        len, retlen, virt, phys);
    }
    static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
    {
        struct mtd_part *part = PART(mtd);
        part->master->unpoint(part->master, from + part->offset, len);
    }
    //获取空闲的内存驱动
    static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
                            unsigned long len,
                            unsigned long offset,
                            unsigned long flags)
    {
        struct mtd_part *part = PART(mtd);
        offset += part->offset;
        return part->master->get_unmapped_area(part->master, len, offset,
                               flags);
    }
    static int part_read_oob(struct mtd_info *mtd, loff_t from,
            struct mtd_oob_ops *ops)
    {
        struct mtd_part *part = PART(mtd);
        int res;
        if (from >= mtd->size)
            return -EINVAL;
        if (ops->datbuf && from + ops->len > mtd->size)
            return -EINVAL;
        res = part->master->read_oob(part->master, from + part->offset, ops);
        if (unlikely(res)) {
            if (res == -EUCLEAN)
                mtd->ecc_stats.corrected++;
            if (res == -EBADMSG)
                mtd->ecc_stats.failed++;
        }
        return res;
    }
    static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
            size_t len, size_t *retlen, u_char *buf)
    {
        struct mtd_part *part = PART(mtd);
        return part->master->read_user_prot_reg(part->master, from,
                        len, retlen, buf);
    }
    static int part_get_user_prot_info(struct mtd_info *mtd,
            struct otp_info *buf, size_t len)
    {
        struct mtd_part *part = PART(mtd);
        return part->master->get_user_prot_info(part->master, buf, len);
    }
    static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
            size_t len, size_t *retlen, u_char *buf)
    {
        struct mtd_part *part = PART(mtd);
        return part->master->read_fact_prot_reg(part->master, from,
                        len, retlen, buf);
    }
    static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
            size_t len)
    {
        struct mtd_part *part = PART(mtd);
        return part->master->get_fact_prot_info(part->master, buf, len);
    }
    //分区写函数
    static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
            size_t *retlen, const u_char *buf)
    {
        struct mtd_part *part = PART(mtd);
        if (!(mtd->flags & MTD_WRITEABLE))
            return -EROFS;
        if (to >= mtd->size)
            len = 0;
        else if (to + len > mtd->size)
            len = mtd->size - to;
        return part->master->write(part->master, to + part->offset,
                        len, retlen, buf);
    }
    static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
            size_t *retlen, const u_char *buf)
    {
        struct mtd_part *part = PART(mtd);
        if (!(mtd->flags & MTD_WRITEABLE))
            return -EROFS;
        if (to >= mtd->size)
            len = 0;
        else if (to + len > mtd->size)
            len = mtd->size - to;
        return part->master->panic_write(part->master, to + part->offset,
                        len, retlen, buf);
    }
    static int part_write_oob(struct mtd_info *mtd, loff_t to,
            struct mtd_oob_ops *ops)
    {
        struct mtd_part *part = PART(mtd);
        if (!(mtd->flags & MTD_WRITEABLE))
            return -EROFS;
        if (to >= mtd->size)
            return -EINVAL;
        if (ops->datbuf && to + ops->len > mtd->size)
            return -EINVAL;
        return part->master->write_oob(part->master, to + part->offset, ops);
    }
    static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
            size_t len, size_t *retlen, u_char *buf)
    {
        struct mtd_part *part = PART(mtd);
        return part->master->write_user_prot_reg(part->master, from,
                        len, retlen, buf);
    }
    static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
            size_t len)
    {
        struct mtd_part *part = PART(mtd);
        return part->master->lock_user_prot_reg(part->master, from, len);
    }
    static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,
            unsigned long count, loff_t to, size_t *retlen)
    {
        struct mtd_part *part = PART(mtd);
        if (!(mtd->flags & MTD_WRITEABLE))
            return -EROFS;
        return part->master->writev(part->master, vecs, count,
                        to + part->offset, retlen);
    }
    static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
    {
        struct mtd_part *part = PART(mtd);
        int ret;
        if (!(mtd->flags & MTD_WRITEABLE))
            return -EROFS;
        if (instr->addr >= mtd->size)
            return -EINVAL;
        instr->addr += part->offset;
        ret = part->master->erase(part->master, instr);
        if (ret) {
            if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
                instr->fail_addr -= part->offset;
            instr->addr -= part->offset;
        }
        return ret;
    }
    void mtd_erase_callback(struct erase_info *instr)
    {
        if (instr->mtd->erase == part_erase) {
            struct mtd_part *part = PART(instr->mtd);
            if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
                instr->fail_addr -= part->offset;
            instr->addr -= part->offset;
        }
        if (instr->callback)
            instr->callback(instr);
    }
    EXPORT_SYMBOL_GPL(mtd_erase_callback);
    static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
    {
        struct mtd_part *part = PART(mtd);
        if ((len + ofs) > mtd->size)
            return -EINVAL;
        return part->master->lock(part->master, ofs + part->offset, len);
    }
    static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
    {
        struct mtd_part *part = PART(mtd);
        if ((len + ofs) > mtd->size)
            return -EINVAL;
        return part->master->unlock(part->master, ofs + part->offset, len);
    }
    //分区同步函数
    static void part_sync(struct mtd_info *mtd)
    {
        struct mtd_part *part = PART(mtd);
        part->master->sync(part->master);
    }
    //支持电源管理的功能函数
    static int part_suspend(struct mtd_info *mtd)
    {
        struct mtd_part *part = PART(mtd);
        return part->master->suspend(part->master);
    }
    static void part_resume(struct mtd_info *mtd)
    {
        struct mtd_part *part = PART(mtd);
        part->master->resume(part->master);
    }
    static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
    {
        struct mtd_part *part = PART(mtd);
        if (ofs >= mtd->size)
            return -EINVAL;
        ofs += part->offset;
        return part->master->block_isbad(part->master, ofs);
    }
    //标记设备地址坏块
    static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
    {
        struct mtd_part *part = PART(mtd);
        int res;
        if (!(mtd->flags & MTD_WRITEABLE))
            return -EROFS;
        if (ofs >= mtd->size)
            return -EINVAL;
        ofs += part->offset;
        res = part->master->block_markbad(part->master, ofs);
        if (!res)
            mtd->ecc_stats.badblocks++;
        return res;
    }
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-11-24 21:16 , Processed in 0.123923 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.