MTD设备驱动

MTD(memory technology device):内存技术设备
是linux用于描述ROM,NAND,NOR等内存设备的子系统的抽象
MTD设备可以按块读写也可以按字节读写,也就是说MTD设备既可以是块设备也可以是字符设备

一.MTD设备基础
1.关键结构体对象
在MTD中用mtd_info来描述一个内存设备

struct mtd_info {
	u_char type;			//mtd设备类型
	uint32_t flags;			//标志
	uint64_t size;			//mtd设备总容量
	uint32_t erasesize;		//擦除数据大小
	uint32_t writesize;		//可写入数据最小字节数
	uint32_t writebufsize;		//写缓冲区大小
	uint32_t oobsize;			//oob区字节数
	uint32_t oobavail;			//可用oob区字节数
	unsigned int erasesize_shift;	//擦除数据偏移值
	unsigned int writesize_shift;	//写入数据偏移值
	unsigned int erasesize_mask;	//擦除数据大小掩码
	unsigned int writesize_mask;	//写入数据大小掩码
	const char *name;			//mtd设备名
	int index;			//索引值
	struct nand_ecclayout *ecclayout;	//nand ecc布局
	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, loff_t from, 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, loff_t from, size_t len, size_t *retlen, u_char *buf);	//读
	int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);	//写
	int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
	int (*read_oob) (struct mtd_info *mtd, loff_t from,struct mtd_oob_ops *ops);	//读oob区
	int (*write_oob) (struct mtd_info *mtd, loff_t to,struct mtd_oob_ops *ops);		//写oob区
	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, loff_t from, size_t len, size_t *retlen, u_char *buf);
	int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
	int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
	int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
	int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
	int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, 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, loff_t ofs, uint64_t len);
	int (*is_locked) (struct mtd_info *mtd, loff_t ofs, 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中用mtd_part来描述一个flash分区关系

struct mtd_part {
	struct mtd_info mtd;		//分区信息
	struct mtd_info *master;	//主分区
	uint64_t offset;			//分区偏移值
	struct list_head list;		//链表
};

在MTD中用mtd_partition来描述一个flash分区名字大小等信息

struct mtd_partition {
	char *name;			//分区名
	uint64_t size;			//分区大小
	uint64_t offset;			//分区的偏移值
	uint32_t mask_flags;		//标志掩码
	struct nand_ecclayout *ecclayout;	//ecc布局
};

2.主设备号

#define MTD_CHAR_MAJOR 90		//MTD字符设备主设备号
#define MTD_BLOCK_MAJOR 31		//MTD块设备主设备号

3.设备类

static struct class mtd_class = {
	.name = "mtd",			//类名
	.owner = THIS_MODULE,	//模块所有者
	.suspend = mtd_cls_suspend,
	.resume = mtd_cls_resume,
};

设备类的注册在init_mtd函数中注册

module_init(init_mtd); //模块入口

static int __init init_mtd(void)
{
	int ret;
	ret = class_register(&mtd_class);	//注册MTD设备类
	if (ret)
		goto err_reg;
	ret = mtd_bdi_init(&mtd_bdi_unmappable, "mtd-unmap");
	if (ret)
		goto err_bdi1;
	ret = mtd_bdi_init(&mtd_bdi_ro_mappable, "mtd-romap");
	if (ret)
		goto err_bdi2;
	ret = mtd_bdi_init(&mtd_bdi_rw_mappable, "mtd-rwmap");
	if (ret)
		goto err_bdi3;
#ifdef CONFIG_PROC_FS
	if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))	//创建proc文件系统接口"/proc/mtd"
		proc_mtd->read_proc = mtd_read_proc;
#endif /* CONFIG_PROC_FS */
	return 0;
err_bdi3:
	bdi_destroy(&mtd_bdi_ro_mappable);
err_bdi2:
	bdi_destroy(&mtd_bdi_unmappable);
err_bdi1:
	class_unregister(&mtd_class);
err_reg:
	pr_err("Error registering mtd class or bdi: %d\n", ret);
	return ret;
}

4.全局链表

mtd_partitions	//mtd设备分区链表
	add_mtd_partitions函数中添加
	
blktrans_majors	//mtd_blktrans_ops结构体对象链表
	添加链表:register_mtd_blktrans函数中
	遍历链表:blktrans_notify_add函数中
			块设备:mtdblock_tr->add_mtd(mtdblock_add_mtd) >>> add_mtd_blktrans_dev
	
mtd_notifiers	//mtd_notifiers通知者链表
	添加链表:register_mtd_blktrans >>> register_mtd_user函数中
	遍历链表:add_mtd_device函数中遍历
			块设备:blktrans_notifier->add(blktrans_notify_add)

5.整体流程:

5.1 字符设备部分

module_init(init_mtd)			//注册mtd设备类
module_init(init_mtdchar);		//mtd字符设备模块入口
    __register_chrdev	//注册字符设备
    调用register_mtd_user
        添加mtdchar_notifier到全局mtd_notifiers链表
接着调用add_mtd_partitions函数
    for循环建立分区{
        继承mtd_info--master属性(nand/nor...)
        添加分区到全局mtd_partitions链表
            接着调用add_mtd_device函数
                -------------------------------------------mtd_notifiers
                遍历全局mtd_notifiers链表
                    调用m
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值