Linux Kernel --- device driver mode 架构之美

platform driver、device 对 device driver mode 封装的差强人意.
kernel 中几乎所有的platform driver 都不会在 /sys 下创建属性文件. 减少了与device 沟通的一种渠道, 内核黑客之所以这样架构是有深刻用意的,

设备驱动模型校验上层侵入的code是及其严格的, "免疫力"足够强大,看下面冰山一角.
在这里插入图片描述
看他们之间的交互通路
在这里插入图片描述
好,先看设备驱动模型暴露出来的第一个API, 先上一张图片,然后详细欣赏
在这里插入图片描述

/*
	看参数,一个原生的struct device, 
	无论你是一个虚拟总线上挂载的设备还是物理总线上挂载的设备, 
	结构体中都必须包含该核心的struct device 结构体. 	
	好,那么device driver mode 拿到了这个device 
	1: 做了哪些事情呢 ?
	2: 又能做什么呢 ? 
	3: 为什么要做这些 ? 作者用意何在 ?
*/
int device_add(struct device *dev)
{
		/*
			该设备的父设备. 通常是该设备相连接的 ControllerBUS, 
			比如 i2c_adapter对应i2c controller,
			ARM上 它挂载在 amba的apb总线上
			那么,拿到该设备的parent 是想:
			1 : 在该parent对应的sys目录下创建目录
			2 : 挂接到该parent维护的klist_children 链表上去
			3 : 父设备的运行时电源管理计数 + 1
			
			好,既然是这样,那么如果该parent 为 NULL,会怎么办 ?
			别急,哈哈,老鼠拉木箱,大的在后头...., 下面就有欣赏
		*/
		struct device *parent;
		/*
			嘿嘿🤭内核对象, 代表sys下的一个目录,真的很重要! 
			这个就不多说了,地球人都知道
			正是由于该对象的存在,sys下才建立起层次关系, device driver mode中的核心所在!
		*/
		struct kobject *kobj;
		
		/*
			它提供了两个回调函数 add_dev 、remove_dev
			提供这两个Callback 有什么作用呢? 没有硬性规定,看你的需求,
			device driver mode 实现的灵活性可见一斑.  下面有个实验来验证这个特性.
			
			再说一下这个class帮助你理解,class是班级的意思,好吧,按照作者的意思 该class下的
			相同功能的设备就应该是班级里的学生了.device_add()函数的最后 会有下面的行为 :
			遍历该 dev->class->p->interfaces 链表,具体该链表挂接的是什么、为什么要在最后来遍历
			它 执行上述的Callback函数,下面再分析,这里仅仅只是声明一个指针. 暂不作深入讨论.
		*/
		struct class_interface *class_intf;
		/*
			返回值,
			返回 0 表示该设备已经加入到 device driver mode中了.
			结果比过程要重要,除非你是去旅游,
			除非能有像弗莱明一样探索过程可以发现青霉素. 否则华而不实
		*/
		int error = -EINVAL;
		/*
			它的实现: 
			return dev->kobj.parent;
			
			在正常的注册过程中该值是没有任何意义,其价值在于注册失败后该怎么做.
			到时再分析吧,这里作者预先铺垫了注册失败后该怎么办.
		*/
		struct kobject *glue_dir = NULL;
		
		/*
			好了, 一个参数 、五个局部变量都定义好了,看下面code的执行逻辑了
			材米油盐都给你准备好了,看你怎么做饭了,
		*/

		/*
			增加设备的引用计数.
			如果传入的参数是 NULL, 那么该函数返回 NULL
			
			在该函数的最后 当该设备已经加入到 device driver mode 中了,还会将该设备的引用计数减1
			调用了这个函数:  put_device(dev);
			
			看整个注册过程是在 该设备的引用计数 > 0 的情况下完成的.
            难道设备的引用计数为 0 就不可以进行注册了吗 ? 好,下面详细说
            
            对称性: 
			这里的对称性我想到了一个: try_to_wake_up() 去唤醒一个 Task的时候
			是在 preempt_disable() 禁用内核抢占环境下执行的,完成后 preempt_enable()又开启抢占
			这种对称性在 kernel中真是太多了....
		*/
		dev = get_device(dev);
		if (!dev)
		    goto done;
	
		/*
			还是在校验传入的参数.
			
			要注册的device 是否设置了设备的私有数据.
			这个私有数据存在的意义之一: 提供该设备的子设备挂接的链表,
		    也就是说: 子设备挂载到了父设备维护的链表上的.
		    struct device_private {
		        struct klist klist_children;
		    }    
		*/
		if (!dev->p) {
		    /*
		        如果你不设置device_private,那么kernel帮你设置一个,
		        也就是说无论如何 注册的每一个设备都必须有自己的私有数据 device_private
		        好,😄,下面画一个图来呈现这个核心的数据结构. bus_type 中也有类似的架构设计
		    */ 
			error = device_private_init(dev); 
			if (error)
				goto done;
		}
		
		/*
	         设置device的名字.
	         注意了,在后面遍历klist链表的过程中,匹配driver的时候,有可能会使用到这里设置的名字
	         platform device driver 可以参见 platform_bus_type 提供的 platform_match()函数.
	         好,如果不提供init_name呢, 也好办,下面就会有设置.
		*/
	    if (dev->init_name) {
		    dev_set_name(dev, "%s", dev->init_name);
		    dev->init_name = NULL;
	    }
	    
		/*
			还是在设置名字,在注册device的时候设置好名字,可以帮组kernel减轻很多工作
			好,即使你注册device的时候没有名字,也行,但是设备所属的总线必须有名字
			不然,下面一个判断就会注册该device失败,
		*/
		if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
			dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
	
		/*
			一个婴儿刚出生加入到人类社会中来,得起个名吧. 即使像朱重八、朱初一之类得,
			感慨那些带有父母姓氏得孩子得名字,也许是女性地位在家庭中的提升的表现吧.
		*/
		if (!dev_name(dev)) {
			error = -EINVAL;
			goto name_error;
		}
		
		/*
			kernel也会给你一个温馨得提示,哈哈😄
			不过这个需要开启 CONFIG_DYNAMIC_DEBUG 配置才行.
			
			好,到这里终于是吧名字给搞定了. 
			看,为了一个name, kernel 竟然用了三个if来判断,TMD啰嗦 !!
			不过既然这样来架构,也说明device 名字得重要性.
		*/
		pr_debug("device: '%s': %s\n", dev_name(dev), __func__);

		/*
			看,上面的code只做了两件事:
			1 : 设置设备的名字
			2 : 设置设备的私有数据结构.

			好, 待把整个函数都分析完了,再从整体上看device driver mode 为什么要这么做.
			有没有更优秀的方法.
		*/
}

在这里插入图片描述

/*
	父设备引用计数 +1
	好了,如果要卸载这个设备,那么父设备的引用计数 就要 -1
	
	device_unregister() {
		👇
		device_del() {
			......
			......
			👇
			put_device(parent);
		}
	}
	生下来在户主户口簿上人数加 1, 死去 -1, 空空的来,如也的走,不带走一片云彩,
	哈哈 😄, 
	
	什么样的设备没有父设备 ? 什么样的设备不挂载到总线上 ? 
	下面就有说明.
*/
parent = get_device(dev->parent);

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值