1回答

0收藏

[原创] ARM-Linux驱动--MTD驱动分析(三)

飞凌嵌入式 飞凌嵌入式 3035 人阅读 | 1 人回复 | 2014-01-23

本帖最后由 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);


分享到:
回复

使用道具 举报

回答|共 1 个

倒序浏览

沙发

forlinx2011

发表于 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;
}
您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

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