ARM-Linux驱动--MTD驱动分析(三)

来源:互联网 发布:数据库设计与实现 编辑:程序博客网 时间:2024/06/07 05:08
主机:Gentoo Linux 11.2 with linux kernel 3.0.6

硬件平台:FL2440(S3C2440)with linux kernel 2.6.35

原创作品,转载请标明出处http://blog.csdn.net/yming0221/article/details/7207908


*接上文ARM-Linux驱动--MTD驱动分析(二)

本文分析MTD设备的分区管理机制

分区管理实际上是将一个MTD设备分成几个分区,将其作为单独的MTD原始设备进行管理。

1、分区的结构体描述结构体mtd_part

[cpp] view plaincopyprint?
  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. };  

2、分区链表mtd_partitions

[cpp] view plaincopyprint?
  1. /* Our partition linked list */  
  2. //声明mtd_partitions链表  
  3. static LIST_HEAD(mtd_partitions);  

3、add_mtd_partitions函数

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

而add_one_partition函数实现如下:

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

4、del_mtd_partition函数

[cpp] view plaincopyprint?
  1. /* 
  2.  * This function unregisters and destroy all slave MTD objects which are 
  3.  * attached to the given master MTD object. 
  4.  */  
  5. //将一个主设备下的所有副设备删除  
  6. int del_mtd_partitions(struct mtd_info *master)  
  7. {  
  8.     struct mtd_part *slave, *next;  
  9.   
  10.     list_for_each_entry_safe(slave, next, &mtd_partitions, list)//遍历mtd_partitions链表,查找到指定的主设备  
  11.         if (slave->master == master) {  
  12.             list_del(&slave->list);//将主设备下的附属设备删除  
  13.             del_mtd_device(&slave->mtd);//调用del_mtd_device函数将每个设备从MTD原始设备表中删除  
  14.             kfree(slave);//释放内存  
  15.         }  
  16.   
  17.     return 0;  
  18. }  
  19. EXPORT_SYMBOL(del_mtd_partitions);  

5、其他的分区管理函数

[cpp] view plaincopyprint?
  1. /* 
  2.  * MTD methods which simply translate the effective address and pass through 
  3.  * to the _real_ device. 
  4.  */  
  5. //读取某个分区的指定数据  
  6. static int part_read(struct mtd_info *mtd, loff_t from, size_t len,  
  7.         size_t *retlen, u_char *buf)  
  8. {  
  9.     struct mtd_part *part = PART(mtd);  
  10.     struct mtd_ecc_stats stats;  
  11.     int res;  
  12.   
  13.     stats = part->master->ecc_stats;  
  14.   
  15.     if (from >= mtd->size)  
  16.         len = 0;  
  17.     else if (from + len > mtd->size)  
  18.         len = mtd->size - from;  
  19.     res = part->master->read(part->master, from + part->offset,  
  20.                    len, retlen, buf);  
  21.     if (unlikely(res)) {  
  22.         if (res == -EUCLEAN)  
  23.             mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;  
  24.         if (res == -EBADMSG)  
  25.             mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;  
  26.     }  
  27.     return res;  
  28. }  
  29.   
  30. static int part_point(struct mtd_info *mtd, loff_t from, size_t len,  
  31.         size_t *retlen, void **virt, resource_size_t *phys)  
  32. {  
  33.     struct mtd_part *part = PART(mtd);  
  34.     if (from >= mtd->size)  
  35.         len = 0;  
  36.     else if (from + len > mtd->size)  
  37.         len = mtd->size - from;  
  38.     return part->master->point (part->master, from + part->offset,  
  39.                     len, retlen, virt, phys);  
  40. }  
  41.   
  42. static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)  
  43. {  
  44.     struct mtd_part *part = PART(mtd);  
  45.   
  46.     part->master->unpoint(part->master, from + part->offset, len);  
  47. }  
  48. //获取空闲的内存驱动  
  49. static unsigned long part_get_unmapped_area(struct mtd_info *mtd,  
  50.                         unsigned long len,  
  51.                         unsigned long offset,  
  52.                         unsigned long flags)  
  53. {  
  54.     struct mtd_part *part = PART(mtd);  
  55.   
  56.     offset += part->offset;  
  57.     return part->master->get_unmapped_area(part->master, len, offset,  
  58.                            flags);  
  59. }  
  60.   
  61. static int part_read_oob(struct mtd_info *mtd, loff_t from,  
  62.         struct mtd_oob_ops *ops)  
  63. {  
  64.     struct mtd_part *part = PART(mtd);  
  65.     int res;  
  66.   
  67.     if (from >= mtd->size)  
  68.         return -EINVAL;  
  69.     if (ops->datbuf && from + ops->len > mtd->size)  
  70.         return -EINVAL;  
  71.     res = part->master->read_oob(part->master, from + part->offset, ops);  
  72.   
  73.     if (unlikely(res)) {  
  74.         if (res == -EUCLEAN)  
  75.             mtd->ecc_stats.corrected++;  
  76.         if (res == -EBADMSG)  
  77.             mtd->ecc_stats.failed++;  
  78.     }  
  79.     return res;  
  80. }  
  81.   
  82. static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,  
  83.         size_t len, size_t *retlen, u_char *buf)  
  84. {  
  85.     struct mtd_part *part = PART(mtd);  
  86.     return part->master->read_user_prot_reg(part->master, from,  
  87.                     len, retlen, buf);  
  88. }  
  89.   
  90. static int part_get_user_prot_info(struct mtd_info *mtd,  
  91.         struct otp_info *buf, size_t len)  
  92. {  
  93.     struct mtd_part *part = PART(mtd);  
  94.     return part->master->get_user_prot_info(part->master, buf, len);  
  95. }  
  96.   
  97. static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,  
  98.         size_t len, size_t *retlen, u_char *buf)  
  99. {  
  100.     struct mtd_part *part = PART(mtd);  
  101.     return part->master->read_fact_prot_reg(part->master, from,  
  102.                     len, retlen, buf);  
  103. }  
  104.   
  105. static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,  
  106.         size_t len)  
  107. {  
  108.     struct mtd_part *part = PART(mtd);  
  109.     return part->master->get_fact_prot_info(part->master, buf, len);  
  110. }  
  111. //分区写函数  
  112. static int part_write(struct mtd_info *mtd, loff_t to, size_t len,  
  113.         size_t *retlen, const u_char *buf)  
  114. {  
  115.     struct mtd_part *part = PART(mtd);  
  116.     if (!(mtd->flags & MTD_WRITEABLE))  
  117.         return -EROFS;  
  118.     if (to >= mtd->size)  
  119.         len = 0;  
  120.     else if (to + len > mtd->size)  
  121.         len = mtd->size - to;  
  122.     return part->master->write(part->master, to + part->offset,  
  123.                     len, retlen, buf);  
  124. }  
  125.   
  126. static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,  
  127.         size_t *retlen, const u_char *buf)  
  128. {  
  129.     struct mtd_part *part = PART(mtd);  
  130.     if (!(mtd->flags & MTD_WRITEABLE))  
  131.         return -EROFS;  
  132.     if (to >= mtd->size)  
  133.         len = 0;  
  134.     else if (to + len > mtd->size)  
  135.         len = mtd->size - to;  
  136.     return part->master->panic_write(part->master, to + part->offset,  
  137.                     len, retlen, buf);  
  138. }  
  139.   
  140. static int part_write_oob(struct mtd_info *mtd, loff_t to,  
  141.         struct mtd_oob_ops *ops)  
  142. {  
  143.     struct mtd_part *part = PART(mtd);  
  144.   
  145.     if (!(mtd->flags & MTD_WRITEABLE))  
  146.         return -EROFS;  
  147.   
  148.     if (to >= mtd->size)  
  149.         return -EINVAL;  
  150.     if (ops->datbuf && to + ops->len > mtd->size)  
  151.         return -EINVAL;  
  152.     return part->master->write_oob(part->master, to + part->offset, ops);  
  153. }  
  154.   
  155. static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,  
  156.         size_t len, size_t *retlen, u_char *buf)  
  157. {  
  158.     struct mtd_part *part = PART(mtd);  
  159.     return part->master->write_user_prot_reg(part->master, from,  
  160.                     len, retlen, buf);  
  161. }  
  162.   
  163. static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,  
  164.         size_t len)  
  165. {  
  166.     struct mtd_part *part = PART(mtd);  
  167.     return part->master->lock_user_prot_reg(part->master, from, len);  
  168. }  
  169.   
  170. static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,  
  171.         unsigned long count, loff_t to, size_t *retlen)  
  172. {  
  173.     struct mtd_part *part = PART(mtd);  
  174.     if (!(mtd->flags & MTD_WRITEABLE))  
  175.         return -EROFS;  
  176.     return part->master->writev(part->master, vecs, count,  
  177.                     to + part->offset, retlen);  
  178. }  
  179.   
  180. static int part_erase(struct mtd_info *mtd, struct erase_info *instr)  
  181. {  
  182.     struct mtd_part *part = PART(mtd);  
  183.     int ret;  
  184.     if (!(mtd->flags & MTD_WRITEABLE))  
  185.         return -EROFS;  
  186.     if (instr->addr >= mtd->size)  
  187.         return -EINVAL;  
  188.     instr->addr += part->offset;  
  189.     ret = part->master->erase(part->master, instr);  
  190.     if (ret) {  
  191.         if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)  
  192.             instr->fail_addr -= part->offset;  
  193.         instr->addr -= part->offset;  
  194.     }  
  195.     return ret;  
  196. }  
  197.   
  198. void mtd_erase_callback(struct erase_info *instr)  
  199. {  
  200.     if (instr->mtd->erase == part_erase) {  
  201.         struct mtd_part *part = PART(instr->mtd);  
  202.   
  203.         if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)  
  204.             instr->fail_addr -= part->offset;  
  205.         instr->addr -= part->offset;  
  206.     }  
  207.     if (instr->callback)  
  208.         instr->callback(instr);  
  209. }  
  210. EXPORT_SYMBOL_GPL(mtd_erase_callback);  
  211.   
  212. static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  
  213. {  
  214.     struct mtd_part *part = PART(mtd);  
  215.     if ((len + ofs) > mtd->size)  
  216.         return -EINVAL;  
  217.     return part->master->lock(part->master, ofs + part->offset, len);  
  218. }  
  219.   
  220. static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  
  221. {  
  222.     struct mtd_part *part = PART(mtd);  
  223.     if ((len + ofs) > mtd->size)  
  224.         return -EINVAL;  
  225.     return part->master->unlock(part->master, ofs + part->offset, len);  
  226. }  
  227. //分区同步函数  
  228. static void part_sync(struct mtd_info *mtd)  
  229. {  
  230.     struct mtd_part *part = PART(mtd);  
  231.     part->master->sync(part->master);  
  232. }  
  233. //支持电源管理的功能函数  
  234. static int part_suspend(struct mtd_info *mtd)  
  235. {  
  236.     struct mtd_part *part = PART(mtd);  
  237.     return part->master->suspend(part->master);  
  238. }  
  239.   
  240. static void part_resume(struct mtd_info *mtd)  
  241. {  
  242.     struct mtd_part *part = PART(mtd);  
  243.     part->master->resume(part->master);  
  244. }  
  245.   
  246. static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)  
  247. {  
  248.     struct mtd_part *part = PART(mtd);  
  249.     if (ofs >= mtd->size)  
  250.         return -EINVAL;  
  251.     ofs += part->offset;  
  252.     return part->master->block_isbad(part->master, ofs);  
  253. }  
  254. //标记设备地址坏块  
  255. static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)  
  256. {  
  257.     struct mtd_part *part = PART(mtd);  
  258.     int res;  
  259.   
  260.     if (!(mtd->flags & MTD_WRITEABLE))  
  261.         return -EROFS;  
  262.     if (ofs >= mtd->size)  
  263.         return -EINVAL;  
  264.     ofs += part->offset;  
  265.     res = part->master->block_markbad(part->master, ofs);  
  266.     if (!res)  
  267.         mtd->ecc_stats.badblocks++;  
  268.     return res;  
  269. }  

下篇分析具体的MTD设备,字符设备和块设备,待续........
原创粉丝点击