Flash设备驱动
发布时间:2020-12-15 20:10:05 所属栏目:百科 来源:网络整理
导读:在linux系统中,提供了MTD(内存技术设备)系统来建立Flash针对linux的统一,抽象接口,MTD将文件系统与底层的Flash存取器进行了隔离,使得Flash驱动工程师无需关心Flash作为字符设备和块设备与Linux内核接口(由MTD层完成) 在引入MTD后,Linux系统中Flash设
在linux系统中,提供了MTD(内存技术设备)系统来建立Flash针对linux的统一,抽象接口,MTD将文件系统与底层的Flash存取器进行了隔离,使得Flash驱动工程师无需关心Flash作为字符设备和块设备与Linux内核接口(由MTD层完成) 在引入MTD后,Linux系统中Flash设备驱动及接口可分四层 (1)硬件驱动层,Flash硬件驱动层负责Flash硬件设备读,写,擦除 LInux MTD 设备的 NOR Flash 芯片驱动位于 drivers/mtd/chips 子目录下, NAND Flash的驱动程序则 位于 drivers/mtd/nand 子目录下。 (2)MTD原始设备层:MTD原始设备层有两部分组成,一部分是MTD原始设备的通用代码,另一部分是特定Flash数据,如分区等 (3)MTD设备层:基于MTD原始设备层,Linux系统可以定义出MTD的块设备(主设备号31)和字符设备(主设备号90)MTD字符设备定义在mtdchar.c中实现,通过注册一系列file_operations的函数(lseek,open,clos,read,write等),可实现设备读写控制,MTD 块设备则是定义在一个描述MTD 块设备的结构 mtdblk_dev ,并声明了一个名为 mtdblks 的指针数组,这个数组 中的每个mtdblk_dev 和 mtd_table 中的每一个mtd_info 一一对应。 (4)块设备节点:通过mknod在/dev子目录下建立MTD字符设备节点和MTD块设备节点 ? LInux MTD系统接口 在引入MTD后,底层Flash驱动直接与MTD原始设备层交互,利用其提供的接口注册设备和分区 用于描述MTD原始设备的数据结构是mtd_info,这其中定义了大量关于MTD的数据和操作函数,mtd_info是表示MTD原始设备结构体,每个分区也被认为是一个mtd_info,这些mtd_info指针被存放在mtd_table的数组里,这个结构体定义如下: struct mtd_info { ?u_char type;//内存技术类型 ?uint32_t flags;//标志位 ?uint64_t size; ?// MTD设备大小Total size of the MTD ? ?unsigned int erasesize_shift; ?unsigned int writesize_shift; ? ?unsigned int erasesize_mask; ?unsigned int writesize_mask; ?// Kernel-only stuff starts here. ?const char *name; ?int index; ? ?struct nand_ecclayout *ecclayout; ? ?int numeraseregions; ?struct mtd_erase_region_info *eraseregions; ? ?int (*erase) (struct mtd_info *mtd,struct erase_info *instr); ? ? ?int (*point) (struct mtd_info *mtd,loff_t from,size_t len,? ?size_t *retlen,void **virt,resource_size_t *phys); ? ?void (*unpoint) (struct mtd_info *mtd,size_t len); ? ?unsigned long (*get_unmapped_area) (struct mtd_info *mtd,? ? ? ? ?unsigned long len,? ? ? ? ?unsigned long offset,? ? ? ? ?unsigned long flags); ? ?struct backing_dev_info *backing_dev_info; ?int (*read) (struct mtd_info *mtd,size_t *retlen,u_char *buf); ?int (*write) (struct mtd_info *mtd,loff_t to,const u_char *buf); ? ?int (*panic_write) (struct mtd_info *mtd,const u_char *buf); ?int (*read_oob) (struct mtd_info *mtd,? ? struct mtd_oob_ops *ops); ?int (*write_oob) (struct mtd_info *mtd,? ? struct mtd_oob_ops *ops); ? ?int (*get_fact_prot_info) (struct mtd_info *mtd,struct otp_info *buf,size_t len); ?int (*read_fact_prot_reg) (struct mtd_info *mtd,u_char *buf); ?int (*get_user_prot_info) (struct mtd_info *mtd,size_t len); ?int (*read_user_prot_reg) (struct mtd_info *mtd,u_char *buf); ?int (*write_user_prot_reg) (struct mtd_info *mtd,u_char *buf); ?int (*lock_user_prot_reg) (struct mtd_info *mtd,size_t len); ? ?int (*writev) (struct mtd_info *mtd,const struct kvec *vecs,unsigned long count,size_t *retlen); ? ?void (*sync) (struct mtd_info *mtd); ? ?int (*lock) (struct mtd_info *mtd,loff_t ofs,uint64_t len); ?int (*unlock) (struct mtd_info *mtd,uint64_t len); ? ?int (*suspend) (struct mtd_info *mtd); ?void (*resume) (struct mtd_info *mtd); ? ?int (*block_isbad) (struct mtd_info *mtd,loff_t ofs); ?int (*block_markbad) (struct mtd_info *mtd,loff_t ofs); ?struct notifier_block reboot_notifier;? ? ?struct mtd_ecc_stats ecc_stats; ? ?int subpage_sft; ?void *priv; ?struct module *owner; ?struct device dev; ?int usecount; ? ?int (*get_device) (struct mtd_info *mtd); ?void (*put_device) (struct mtd_info *mtd); }; mtd_info的type字段给出了底层物理设备的类型,包括MTD_RAM,MTD_ROM,MTD_NORFLASH,MTD_NANSFLASH等 flags字段标志可以是MTD_WRITEABLE,MTD_BIT_WRITEABLE,MTD_NO_ERASE,MTD_POWERUP_LOCK等的组合 mtd_info中的read(),write(),read_oob(),write_oob(),erase()是MTD设备驱动要实现的主要函数,在Linux中MTD下层实现了针对NOR Flash和NAND Flash通用的mtd_info成员函数 某些内存技术带有额外数据(OOB),例如NAND Flash没512字节就会有16个字节的“额外数据” ? Flash驱动中使用如下两个函数注册和注销MTD设备 int add_mtd_device(struct mtd_info *mtd); int del_mtd_device(struct mtd_info *mtd); 下面代码中mtd_part结构体用于表示分区,其mtd_info成员结构体用于描述分区,它会被加入到mtd_table(定义为struct mtd_info *mtd_table[MAX_MTD_DEVICES])中,其大部分成员由其主分区mtd_part->master决定,各种函数也指向主分区相应的函数 struct mtd_part { ?struct mtd_info mtd;//分区信息(大部分由master决定) ?struct mtd_info *master;//该分区的主分区 ?uint64_t offset;//该分区的偏移地址 ?int index;// 主分区号 ?struct list_head list; ?int registered; }; mtd_partition(分区数组)会在MTD原始设备层调用add_mtd_partitions()时传递分区信息用,定义如下: struct mtd_partition { ?char *name; ? //标示字符串 ?uint64_t size; ? //分区大小 ?uint64_t offset; ?//主MTD内偏移地址 ?uint32_t mask_flags; ?//掩码标志 ?struct nand_ecclayout *ecclayout; //OOB布局out of band layout for this partition (NAND only) ?struct mtd_info **mtdp; ? }; Flash驱动中使用如下两个函数注册和注销分区 int add_mtd_partitions(struct mtd_info *master,struct mtd_partition *parts,int nbparts) int del_mtd_partitions(struct mtd_info *master); add_mtd_partitions()会对每一个新建立的分区建立一个mtd_part结构体,并将其加入mtd_partions(分区数组)中,并调用add_mtd_device()将此分区作为MTD设备键入mtd_table,成功时返回0,否则返回-ENOMEM del_mtd_partitions()的作用是对于mtd_partitions上的每一个分区,如果它的主分区是master(要被删除的分区号),则将它从mtd_partitions和mtd_table中删除,这是要调用del_mtd_device; add_mtd_partitions()中新建的mtd_part需要依赖于传进的mtd_partition(分区数组)参数对其进行初始化 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++) { ? slave = add_one_partition(master,parts + i,i,cur_offset); ? if (!slave) ? ?return -ENOMEM; ? cur_offset = slave->offset + slave->mtd.size; ?} ?return 0; } 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; ? ?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); ? ?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; ... } ? MTD用户空间编程 drives/mtd/mtdchar.c文件实现了MTD字符设备接口,通过它用户可以直接操作Flash设备,通过read(),write系统调用可以读写Flash,通过一系列IOCTL命令可以获得Flash设备信息,擦除Flash,读写NAND的OOB等 ? NOR Flash驱动 在Linux中,实现了针对CFI(公共Flash接口),JEDEC等接口的通用NOR驱动,这一层驱动直接面对mtd_info的成员函数,这使得NOR的芯片级驱动变得十分简单,只需定义具体内存映射情况结构体mao_info并使用指定调用do_mao_probe()探测mtd_info()就可以了 NOR Flash驱动的核心是定义map_info结构体,他指定NOR Flash的基址,位宽,大小等信息,然后调用do_map_probe()探测芯片就可以了,map_info原型如下: struct map_info { ?const char *name; ?unsigned long size; ?resource_size_t phys; #define NO_XIP (-1UL) ?void __iomem *virt; ?void *cached; ?int bankwidth; #ifdef CONFIG_MTD_COMPLEX_MAPPINGS ?map_word (*read)(struct map_info *,unsigned long); ?void (*copy_from)(struct map_info *,void *,unsigned long,ssize_t); ?void (*write)(struct map_info *,const map_word,unsigned long); ?void (*copy_to)(struct map_info *,const void *,ssize_t); ? #endif ? ?void (*inval_cache)(struct map_info *,ssize_t); ? ?void (*set_vpp)(struct map_info *,int); ?unsigned long pfow_base; ?unsigned long map_priv_1; ?unsigned long map_priv_2; ?void *fldrv_priv; ?struct mtd_chip_driver *fldrv; }; NOR Flash驱动在Linux中实现,主要工作如下: (1)定义map_info的实例,初始化其中的成员,根据目标板的情况name,size,bankwidth和phys赋值 (2)如果Flash需要分区,则定义mtd_partition数组,将实际电路板中Flash分区信息记录在其中 (3)以map_info和探测的接口类型(如“ch_probe”,"jedec_probe"等)为参数调用do_map_probe()探测Flash得到mtd_info do_map_probe()函数原型如下: struct mtd_info *do_map_probe(const char *name,struct map_info *map); 第一个为探测接口类型,常见的如下 do_map_probe("cfi_probe",&xxx_map_info); do_map_probe("jedec_probe",&xxx_map_info); do_map_probe("map_rom",&xxx_map_info); do_map_probe()会根据传入参数name(接口类型),通过get_mtd_chip_driver()得到具体的MTD驱动,如下所示: struct mtd_info *do_map_probe(const char *name,struct map_info *map) { ?struct mtd_chip_driver *drv; ?struct mtd_info *ret; ?drv = get_mtd_chip_driver(name); ?if (!drv && !request_module("%s",name)) ? drv = get_mtd_chip_driver(name);//通过接口类型找到驱动 ?if (!drv) ? return NULL; ?ret = drv->probe(map); ? ?module_put(drv->module); ?if (ret) ? return ret; ?return NULL; }? (4)在模块初始化时以mtd_info为参数调用add_mtd_device()或以mtd_info,partition数组为参数调用add_mtd_partitions()注册设备或分区 (5)在模块卸载时调用“反函数”来删除设备或分区 下面是一个NOR Flash的驱动 #define WINDOW_SIZE ... #define WINDOW_ADDR ... static struct map_info xxx_map = {//定义并初始化map_info .name = "xxx_Flash",.size = WINDOW_SIZE,//大小 .bankwidth = 1,//总线宽度 .phys = WINDOW_ADDR//物理地址 }; ? static struct mtd_partition xxx_partitions[] = {//定义数组用于分区 { .name = "Drive A",.offset = 0,//分区偏移地址 .size = 0x0e0000//分区大小 }, ... }; ? #define NUM_PARTITIONS ARRAY_SIZE(xxx_partitions) ? static struct mtd_info *mymtd; ? static int __init init_xxx_map(void) { int rc = 0; ? xxx_map.virt = ioremap_nocache(xxx_map.phys,xxx_map.size);//物理地址映射为虚拟地址 ... mymtd = do_map_probe("jedec_probe",&xxx_map);//探测NOR Flash得到mtd_info mymtd->owner = THIS_MODULE; add_mtd_partitions(mymtd,xxx_partitions,NUM_PARTTITIONS);//添加分区信息 ... ? } struct void __exit cleanup_xxx_map(void0 { if(mymtd){ del_mtd_partitions(mymtd);//删除分区 map_destroy(mymtd); } ... }? ? NAND Flash驱动 和NOR Flash非常类似,在Linux内核MTD的下层已经实现了通用的NAND驱动(在driver/mtd/nand/nand_bash.c中)即实现了mtd_info结构体的成员函数 MTD使用nand_chip数据结构表示一个NAND Flash芯片,这个结构体中包含了关于NAND Flash的地址信息,读写方法,ECC模式等,这个结构体原型如下: struct nand_chip { ?void ?__iomem *IO_ADDR_R; ?void ?__iomem *IO_ADDR_W; ?uint8_t ?(*read_byte)(struct mtd_info *mtd); ?u16 ?(*read_word)(struct mtd_info *mtd); ?void ?(*write_buf)(struct mtd_info *mtd,const uint8_t *buf,int len); ?void ?(*read_buf)(struct mtd_info *mtd,uint8_t *buf,int len); ?int ?(*verify_buf)(struct mtd_info *mtd,int len); ?void ?(*select_chip)(struct mtd_info *mtd,int chip); ?int ?(*block_bad)(struct mtd_info *mtd,int getchip); ?int ?(*block_markbad)(struct mtd_info *mtd,loff_t ofs); ?void ?(*cmd_ctrl)(struct mtd_info *mtd,int dat,? ? ? ? unsigned int ctrl); ?int ?(*dev_ready)(struct mtd_info *mtd); ?void ?(*cmdfunc)(struct mtd_info *mtd,unsigned command,int column,int page_addr); ?int ?(*waitfunc)(struct mtd_info *mtd,struct nand_chip *this); ?void ?(*erase_cmd)(struct mtd_info *mtd,int page); ?int ?(*scan_bbt)(struct mtd_info *mtd); ?int ?(*errstat)(struct mtd_info *mtd,struct nand_chip *this,int state,int status,int page); ?int ?(*write_page)(struct mtd_info *mtd,struct nand_chip *chip,? ? ? ? ? const uint8_t *buf,int page,int cached,int raw); ?int ?chip_delay; ?unsigned int options; ?int ?page_shift; ?int ?phys_erase_shift; ?int ?bbt_erase_shift; ?int ?chip_shift; ?int ?numchips; ?uint64_t chipsize; ?int ?pagemask; ?int ?pagebuf; ?int ?subpagesize; ?uint8_t ?cellinfo; ?int ?badblockpos; ?nand_state_t state; ?uint8_t ?*oob_poi; ?struct nand_hw_control ?*controller; ?struct nand_ecclayout *ecclayout; ?struct nand_ecc_ctrl ecc; ?struct nand_buffers *buffers; ?struct nand_hw_control hwcontrol; ?struct mtd_oob_ops ops; ?uint8_t ?*bbt; ?struct nand_bbt_descr *bbt_td; ?struct nand_bbt_descr *bbt_md; ?struct nand_bbt_descr *badblock_pattern; ?void ?*priv; }; 与NOR Flash一样,由于有了MTD层,完成一个NAND Flash驱动在Linux中的工作量也很少,主要工作如下: (1)如果Flash需要分区,则定义mtd_partition数组,将实际电路板中Flash分区信息记录以其中 (2)在模块加载是分配nand_chip的内存,根据目标板NAND控制器的情况初始化nand_chip中的cmd_ctrl(),dev_ready(),ready_byte(),write_buf()等成员(如果不赋值就使用nand_base.c中的默认函数),注意将mtd_info的priv指向nand_chip (3)以mtd_info为参数调用nand_scan()函数探测NAND Flash的存在得到mtd_info,nand_scan()函数原型如下: int nand_scan(struct mtd_info *mtd,int maxchips); (4)如果要分区则以mtd_info,mtd_partition为参数调用add_mtd_partitions()函数,添加分区 下面是一个NAND Flash设备驱动模块 #define CHIP_PHYSICAL_ADDRESS ?... #define NUM_PARTITIONS 2 static const struct mtd_partition partition_info[] = { ?{ ? .name = "NAND FS 0",? .offset = 0,? .size = 8 * 1024 * 1024},?{ ? .name = "NAND FS 1",? .offset = MTDPART_OFS_APPEND,//表示接着上面结束地址 ? .size = MTDPART_SIZ_FULL} }; static int __init au1xxx_nand_init(void) { ?struct nand_chip *this; ?u16 boot_swapboot = 0;? ?int retval; ?u32 mem_staddr; ?u32 nand_phys; ? //初始化结构体(分配内存) ?au1550_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),GFP_KERNEL); ?if (!au1550_mtd) { ? printk("Unable to allocate NAND MTD dev structure.n"); ? return -ENOMEM; ?} ? ?this = (struct nand_chip *)(&au1550_mtd[1]); ? //初始化成员函数 ?memset(au1550_mtd,sizeof(struct mtd_info)); ?memset(this,sizeof(struct nand_chip)); ? ?au1550_mtd->priv = this; ?au1550_mtd->owner = THIS_MODULE; ? ?au_writel(0,MEM_STNDCTL); #ifdef CONFIG_MIPS_PB1550 ? ?au_writel(au_readl(GPIO2_DIR) & ~(1 << 6),GPIO2_DIR); ?boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr->status >> 6) & 0x1); ?switch (boot_swapboot) { ?case 0: ?case 2: ?case 8: ?case 0xC: ?case 0xD: ?? ? nand_width = 0; ? break; ?case 1: ?case 9: ?case 3: ?case 0xE: ?case 0xF: ?? ? nand_width = 1; ? break; ?default: ? printk("Pb1550 NAND: bad boot:swapn"); ? retval = -EINVAL; ? goto outmem; ?} #endif ? #ifdef NAND_STCFG ?if (NAND_CS == 0) { ? au_writel(NAND_STCFG,?MEM_STCFG0); ? au_writel(NAND_STTIME,MEM_STTIME0); ? au_writel(NAND_STADDR,MEM_STADDR0); ?} ?if (NAND_CS == 1) { ? au_writel(NAND_STCFG,?MEM_STCFG1); ? au_writel(NAND_STTIME,MEM_STTIME1); ? au_writel(NAND_STADDR,MEM_STADDR1); ?} ?if (NAND_CS == 2) { ? au_writel(NAND_STCFG,?MEM_STCFG2); ? au_writel(NAND_STTIME,MEM_STTIME2); ? au_writel(NAND_STADDR,MEM_STADDR2); ?} ?if (NAND_CS == 3) { ? au_writel(NAND_STCFG,?MEM_STCFG3); ? au_writel(NAND_STTIME,MEM_STTIME3); ? au_writel(NAND_STADDR,MEM_STADDR3); ?} #endif ? ?mem_staddr = 0x00000000; ?if (((au_readl(MEM_STCFG0) & 0x7) == 0x5) && (NAND_CS == 0)) ? mem_staddr = au_readl(MEM_STADDR0); ?else if (((au_readl(MEM_STCFG1) & 0x7) == 0x5) && (NAND_CS == 1)) ? mem_staddr = au_readl(MEM_STADDR1); ?else if (((au_readl(MEM_STCFG2) & 0x7) == 0x5) && (NAND_CS == 2)) ? mem_staddr = au_readl(MEM_STADDR2); ?else if (((au_readl(MEM_STCFG3) & 0x7) == 0x5) && (NAND_CS == 3)) ? mem_staddr = au_readl(MEM_STADDR3); ?if (mem_staddr == 0x00000000) { ? printk("Au1xxx NAND: ERROR WITH NAND CHIP-SELECTn"); ? kfree(au1550_mtd); ? return 1; ?} ?nand_phys = (mem_staddr << 4) & 0xFFFC0000; ?p_nand = (void __iomem *)ioremap(nand_phys,0x1000); ? ?if (NAND_CS == 0) ? nand_width = au_readl(MEM_STCFG0) & (1 << 22); ?if (NAND_CS == 1) ? nand_width = au_readl(MEM_STCFG1) & (1 << 22); ?if (NAND_CS == 2) ? nand_width = au_readl(MEM_STCFG2) & (1 << 22); ?if (NAND_CS == 3) ? nand_width = au_readl(MEM_STCFG3) & (1 << 22); ? ?this->dev_ready = au1550_device_ready; ?this->select_chip = au1550_select_chip; ?this->cmdfunc = au1550_command; ? ?this->chip_delay = 30; ?this->ecc.mode = NAND_ECC_SOFT; ?this->options = NAND_NO_AUTOINCR; ?if (!nand_width) ? this->options |= NAND_BUSWIDTH_16; ?this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte; ?au1550_write_byte = (!nand_width) ? au_write_byte16 : au_write_byte; ?this->read_word = au_read_word; ?this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf; ?this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf; ?this->verify_buf = (!nand_width) ? au_verify_buf16 : au_verify_buf; ? ?if (nand_scan(au1550_mtd,1)) {//探测NAND Flash ? retval = -ENXIO; ? goto outio; ?} ? //注册分区 ?add_mtd_partitions(au1550_mtd,partition_info,ARRAY_SIZE(partition_info)); ?return 0; ?outio: ?iounmap((void *)p_nand); ?outmem: ?kfree(au1550_mtd); ?return retval; } 最后强调的是,在NAND芯片驱动中,如果nand_chip中没有赋值,将使用默认值(nand_base.c中的默认值),下面是nand_chip中的nand_ecc_ctrl结构体类型成员ecc赋值,定义OOB的分布模式 static struct nand_ecclayout nand_oob_8 = { ?.eccbytes = 3,?.eccpos = {0,1,2},?.oobfree = { ? {.offset = 3,? ?.length = 2},? {.offset = 6,? ?.length = 2}} }; static struct nand_ecclayout nand_oob_16 = { ?.eccbytes = 6,2,3,6,7},?.oobfree = { ? {.offset = 8,? ?. length = 8}} }; static struct nand_ecclayout nand_oob_64 = { ?.eccbytes = 24,?.eccpos = { ? ? ?40,41,42,43,44,45,46,47,? ? ?48,49,50,51,52,53,54,55,? ? ?56,57,58,59,60,61,62,63},?.oobfree = { ? {.offset = 2,? ?.length = 38}} }; static struct nand_ecclayout nand_oob_128 = { ?.eccbytes = 48,?.eccpos = { ? ? ?80,81,82,83,84,85,86,87,? ? ?88,89,90,91,92,93,94,95,? ? ?96,97,98,99,100,101,102,103,? ? ?104,105,106,107,108,109,110,111,? ? ?112,113,114,115,116,117,118,119,? ? ?120,121,122,123,124,125,126,127},? ?.length = 78}} }; NOR Flash驱动实例 针对S3C2410等平台而言。外接NOR Flash的情况下,由于NOR Flash直接映射到CPU的内存空间,为了使用NOR Flash驱动,我们只需要在BSP的板文件中添加相应的信息, 例如NOR Flash所在的物理地址和到校,分区信息,总线宽度等,这些信息以platform资源和数据的形式呈现,如下: static struct resource nor_resource = { .start = OMAP_CS0_PHYS,.end = OMAP_CS0_PHYS + SZ_32M - 1,.flags = IORESOURCE_MEM,//表示地址 }; static struct mtd_partition nor_partitions[] = {//分区结构体 { ? ? ?.name = "bootloader",? ? ?.offset = 0,? ? ?.size = SZ_128K,? ? ?.mask_flags = MTD_WRITEABLE,},{ ? ? ?.name = "params",? ? ?.offset = MTDPART_OFS_APPEND,? ? ?.mask_flags = 0,{ ? ? ?.name = "kernel",? ? ?.size = SZ_2M,? ? ?.mask_flags = 0 },{ ? ? ?.name = "rootfs",? ? ?.size = MTDPART_SIZ_FULL,}; static struct flash_platform_data nor_data = { .map_name = "cfi_probe",.width = 2,.parts = nor_partitions,.nr_parts = ARRAY_SIZE(nor_partitions),}; static struct platform_device nor_device = { .name = "omapflash",//应该和驱动里的(physmap.c)一致 .id = 0,.dev = { .platform_data = &nor_data,.num_resources = 1,//资源数 .resource = &nor_resource,//资源结构体 }; 下面来总结一下: 由于引入了MTD系统以及MTD下层的通用NOR和NAND驱动,Linux中NOR和NAND Flash芯片级驱动的设计难度大大降低,对于NOR驱动工作仅仅只需在BSP中添加相关的platform信息。 在串口驱动中,讲解了tty_driver到uart_driver的角色转换,在Flash驱动中,讲解了mtd_info向map_info/nand_chip的转移,可以说,Linux驱动这种分层设计思想是贯穿个中Linux驱动框架的。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |