从模型分析到Flash驱动模板

MTD(Memory Technology Device)即常说的Flash等使用存储芯片的存储设备,MTD子系统对应的是块设备驱动框架中的设备驱动层,可以说,MTD就是针对Flash设备设计的标准化硬件驱动框架。本文基于3.14内核,讨论MTD驱动框架。

MTD子系统框架

从模型分析到Flash驱动模板

设备节点层:MTD框架可以在/dev下创建字符设备节点(主设备号90)以及块设备节点(主设备号31), 用户通过访问此设备节点即可访问MTD字符设备或块设备。

MTD设备层: 基于MTD原始设备, Linux在这一层次定义出了MTD字符设备和块设备, 字符设备在mtdchar.c中实现, 块设备则是通过结构mtdblk_dev来描述,"/drivers/mtd/mtdchar.c"文件实现了MTD字符设备接口; "/drivers/mtd/mtdblock.c"文件实现了MTD块设备接口

MTD原始设备层: 由MTD原始设备的通用代码+特定的Flash数据组成。mtd_info、mtd_part、mtd_partition以及mtd_partitions等对象及其操作方法就属于这一层,对应的文件是"drivers/mtd/mtdcore.c"。类似于i2c驱动框架中的核心层。

硬件驱动层: 内核将常用的flash操作都已经在这个层次实现, 驱动开发只需要将相应的设备信息添加进去即可, 比如,NOR flash的芯片驱动位于"drivers/mtd/chips/", Nand flash位于"drivers/mtd/nand/"(eg s3c2410.c)

核心结构和方法简述

为了实现上述的框架, 内核中使用了如下类和API, 这些几乎是开发一个MTD驱动必须的

核心结构

mtd_info描述原始设备层的一个分区的结构, 描述一个设备或一个多分区设备中的一个分区

mtd_table管理原始设备层的mtd_info的数组

mtd_part表示一个分区, 其中的struct mtd_info mtd描述该分区的信息, 一个物理Flash设备可以有多于1个mtd_part,每个mtd_part都对应一个mtd_info。

mtd_partition描述一个分区表, 通过管理mtd_part以及每一个mtd_part中的mtd_info来描述所有的分区,一个物理Flash设备只有一个mtd_partition

mtd_partitions是一个list_head对象,用于管理mtd_partition们

map_info描述一个NOR Flash设备

nand_chip描述一个NAND Flash设备

核心方法

add_mtd_device()/del_mtd_device()注册/注销一个MTD设备

add_mtd_partitions()/del_mtd_partitions()注册注销一个或多个分区表,

do_map_probe()用来根据传入的参数匹配一个map_info对象的驱动,比如CFI接口或JEDEC接口的NOR Flash,并返回一个mtd_info以便注册分区信息。

nand_scan():NAND flash使用这个API来匹配驱动。

核心结构与方法详述 mtd_info

本身是没有list_head来供内核管理,对mtd_info对象的管理是通过mtd_part来实现的。mtd_info对象属于原始设备层,里面的很多函数接口内核已经实现了。mtd_info中的read()/write()等操作是MTD设备驱动要实现的主要函数,在NORFlash或NANDFlash中的驱动代码中几乎看不到mtd_info的成员函数,即这些函数对于Flash芯片是透明的,因为Linux在MTD的下层实现了针对NORFlash和NANDFlash的通用的mtd_info函数。

114 struct mtd_info { 115 u_char type; 116 uint32_t flags; 117 uint64_t size; // Total size of the MTD 118 123 uint32_t erasesize; 131 uint32_t writesize; 132 142 uint32_t writebufsize; 143 144 uint32_t oobsize; // Amount of OOB data per block (e.g. 16) 145 uint32_t oobavail; // Available OOB bytes per block 146 151 unsigned int erasesize_shift; 152 unsigned int writesize_shift; 153 /* Masks based on erasesize_shift and writesize_shift */ 154 unsigned int erasesize_mask; 155 unsigned int writesize_mask; 156 164 unsigned int bitflip_threshold; 165 166 // Kernel-only stuff starts here. 167 const char *name; 168 int index; 169 170 /* ECC layout structure pointer - read only! */ 171 struct nand_ecclayout *ecclayout; 172 173 /* the ecc step size. */ 174 unsigned int ecc_step_size; 175 176 /* max number of correctible bit errors per ecc step */ 177 unsigned int ecc_strength; 178 179 /* Data for variable erase regions. If numeraseregions is zero, 180 * it means that the whole device has erasesize as given above. 181 */ 182 int numeraseregions; 183 struct mtd_erase_region_info *eraseregions; 184 185 /* 186 * Do not call via these pointers, use corresponding mtd_*() 187 * wrappers instead. 188 */ 189 int (*_erase) (struct mtd_info *mtd, struct erase_info *instr); 190 int (*_point) (struct mtd_info *mtd, loff_t from, size_t len, 191 size_t *retlen, void **virt, resource_size_t *phys); 192 int (*_unpoint) (struct mtd_info *mtd, loff_t from, size_t len); 193 unsigned long (*_get_unmapped_area) (struct mtd_info *mtd, 194 unsigned long len, 195 unsigned long offset, 196 unsigned long flags); 197 int (*_read) (struct mtd_info *mtd, loff_t from, size_t len, 198 size_t *retlen, u_char *buf); 199 int (*_write) (struct mtd_info *mtd, loff_t to, size_t len, 200 size_t *retlen, const u_char *buf); 201 int (*_panic_write) (struct mtd_info *mtd, loff_t to, size_t len, 202 size_t *retlen, const u_char *buf); 203 int (*_read_oob) (struct mtd_info *mtd, loff_t from, 204 struct mtd_oob_ops *ops); 205 int (*_write_oob) (struct mtd_info *mtd, loff_t to, 206 struct mtd_oob_ops *ops); 207 int (*_get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, 208 size_t len); 209 int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, 210 size_t len, size_t *retlen, u_char *buf); 211 int (*_get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, 212 size_t len); 213 int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from, 214 size_t len, size_t *retlen, u_char *buf); 215 int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to, 216 size_t len, size_t *retlen, u_char *buf); 217 int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, 218 size_t len); 219 int (*_writev) (struct mtd_info *mtd, const struct kvec *vecs, 220 unsigned long count, loff_t to, size_t *retlen); 221 void (*_sync) (struct mtd_info *mtd); 222 int (*_lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len); 223 int (*_unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len); 224 int (*_is_locked) (struct mtd_info *mtd, loff_t ofs, uint64_t len); 225 int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs); 226 int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs); 227 int (*_suspend) (struct mtd_info *mtd); 228 void (*_resume) (struct mtd_info *mtd); 229 /* 230 * If the driver is something smart, like UBI, it may need to maintain 231 * its own reference counting. The below functions are only for driver. 232 */ 233 int (*_get_device) (struct mtd_info *mtd); 234 void (*_put_device) (struct mtd_info *mtd); 235 236 /* Backing device capabilities for this device 237 * - provides mmap capabilities 238 */ 239 struct backing_dev_info *backing_dev_info; 240 241 struct notifier_block reboot_notifier; /* default mode before reboot */ 242 243 /* ECC status information */ 244 struct mtd_ecc_stats ecc_stats; 245 /* Subpage shift (NAND) */ 246 int subpage_sft; 247 248 void *priv; 249 250 struct module *owner; 251 struct device dev; 252 int usecount; 253 };

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/8840177b6c5801da96185883ebeb051f.html