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

发布者:AdventureSeeker最新更新时间:2016-04-26 来源: eefocus关键字:ARM-Linux驱动  MTD  驱动分析 手机看文章 扫描二维码
随时随地手机看文章
主机:Gentoo Linux 11.2 with linux kernel 3.0.6

硬件平台:FL2440(S3C2440)with 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. };  

2、分区链表mtd_partitions

 

  1. /* Our partition linked list */  
  2. //声明mtd_partitions链表  
  3. static LIST_HEAD(mtd_partitions);  

3、add_mtd_partitions函数
  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函数实现如下:
  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函数
  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、其他的分区管理函数
  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设备,字符设备和块设备,待续........
关键字:ARM-Linux驱动  MTD  驱动分析 引用地址:ARM-Linux驱动--MTD驱动分析(三)

上一篇:ARM-Linux驱动移植--Linux下烧写工具DNW和USB驱动安装
下一篇:ARM-Linux驱动--MTD驱动分析(二)

推荐阅读最新更新时间:2024-03-16 14:51

S3C2440 (4.3寸)LCD驱动程序之层次分析(十六)
在上一节LCD层次分析时,得出写个LCD驱动入口函数,需要以下4步: 1)分配一个fb_info结构体:framebuffer_alloc(); 2)设置fb_info; 3)设置硬件相关的操作; 4)使能LCD,并注册fb_info:register_framebuffer(); 本节需要用到的函数: 函数dma_alloc_writecombine():(分配显存) void * dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp);//分配DMA缓存区给现存 //返回值为:申请到
[单片机]
S3C2440 (4.3寸)LCD<font color='red'>驱动</font>程序之层次<font color='red'>分析</font>(十六)
Mini2440 DM9000 驱动分析(二)
在真正的开始分析dm9000 driver的probe之前,首先来看看dm9000 驱动中几个十分重要的结构 1、dm9000_driver static struct platform_driver dm9000_driver = { .driver = { .name = dm9000 , .owner = THIS_MODULE, .pm = &dm9000_drv_pm_ops, }, .probe = dm9000_probe, .remove = __devexit_p(dm9000_drv_remove), }; dm9000_driver是platform_driver结构体变量,其中
[单片机]
基于S3c2440的I2C驱动与测试程序追踪交叉分析
VMware虚拟机+Fedora10, 硬件平台TQ2440, 内核2.6.30.4 对应的驱动程序豁然开朗, 然后自己添加了一些dev_dbg后, 对于不理解的地方也有了一定的参考提示, 记录下来与大家分享。 测试程序如下: /*i2c_test.c * hongtao_liu */ #include #include #include #include #include #include #include #include #define I2C_RETRIES 0x0701 #define I2C_ TI MEOUT 0x0702 #define I2C_RDWR 0x0707 /*********定义struct i
[单片机]
1W大功率LED驱动电源电路分析
  大功率发光二极管比日光灯具有更高的发光效率和使用寿命。人们应根据实际使用方式另外加装散热器。目前,国产3W发白光的LED零售价为15元,但由于3W大功率LED质量还不够可靠,暂不宜使用。5W大功率LED只有进口货,每只售价高达60元,仅适用于特殊要求的灯光工程之中,最适合人们家里作照明用的就是国产1W发光二极管。   鉴于大功率发光二极管工作电压仅为3V,通过全桥整流将220V交流电变成直流电,在全桥上的电压降约为1.8V,只驱动一只发光二极管工作的电能利用效率仅为60%。必须把3只以上发光二极管串联起来工作,才能使总的电能利用效率超过80%。   根据3基色合成白光原理,将红、绿、蓝3只1W大功率发光二极管串联起来工作
[电源管理]
1W大功率LED<font color='red'>驱动</font>电源电路<font color='red'>分析</font>
驱动关键技术分析驱动系统结构及原理
电机驱动低速高扭、扭矩波动小,因此悬置布置时不用追求高的解耦率,重点考虑限位、抗扭作用; 从外特性上对比来看,电机驱动相比内燃机驱动,扭矩响应速度快、峰值扭矩作用区间宽,在特殊路况下容易出现动态冲击事件,产品的耐久、强度需要特殊考虑; 传统车工作转速区间比较集中,而新能源车相对较宽,需要在很宽的转速范围内考虑共振等NVH问题。
[嵌入式]
电<font color='red'>驱动</font>关键技术<font color='red'>分析</font> 电<font color='red'>驱动</font>系统结构及原理
电动汽车驱动方式优缺点技术分析
电动汽车相对传统汽车具有能量转换效率高、噪声小、零排放等优点,同时由于电动机的带载性和宽调速特性,可去掉离合器和变速箱等机械装置,使结构简化,维护、保养方便。在当今能源、环境双重问题的推动下,世界主要汽车生产国都以前所未有的力度发展电动汽车产业,科研人员对电动汽车的研发也获得了绝佳机遇。因此,电动汽车正在开创汽车产业的新格局,它将成为汽车工业发展的主要方向。 驱动电机作为电动汽车的核心部件,其好坏对电动汽车的动力性、经济性、安全性都有重要影响。但汽车驱动电机有别于其它工业电机,电机驱动系统不仅受汽车结构尺寸的影响,同时还要满足复杂工况下的运行条件。因此,除了要求驱动电机效率高、质量小、功率密度大、尺寸小、可靠性好及成本低的特点
[嵌入式]
电动汽车<font color='red'>驱动</font>方式优缺点技术<font color='red'>分析</font>
MapPtrToProcess 用法 WINCE驱动分析3
以使用下面的应用程序代码测试这个driver,使用evc编译。 #include windows.h #include Windev.h #include stdio.h #include "objbase.h" #include "initguid.h" #include "foo.h" //char data1 ; int  WinMain(void) {     HANDLE hnd;     COPY_STRUCT cs ;     int i;     //static char data1 ;   auto char data1 ;     auto char
[嵌入式]
Teledyne LeCroy 发布电机驱动分析
在8通道、12bit高精度示波器上的针对三相电机驱动的功率分析能力 Chestnut Ridge, NY, February 4, 2015 -力科(Teledyne LeCroy)发布了MDA800系列电机驱动分析仪(MDA),该设备将三相功率分析仪的静态(稳态)计算能力,独特的动态三相电源和电机的机械分析功能与高带宽(1 GHz)的控制系统结合为一台仪器。 电机驱动器分析仪(MDA)搭载于HDO8000示波器平台上。该平台标配8个输入通道(16个数字通道可选),拥有12位垂直分辨率,2.5 GS/ s的实时采样率,高达1 GHz的带宽和高达250 Mpts的单通道采集存储。拥有一整套完整的串行触
[测试测量]
Teledyne LeCroy 发布电机<font color='red'>驱动</font><font color='red'>分析</font>仪
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved