1. Linux 设备框架 1.1 软件架构 首先必须明确一点,驱动是 Linux 中最为复杂,也是代码量最为庞大的部分。并不是因为其架构多么匪夷所思,而是作为一个通用操作系统,Linux 必须要支持 30 多种体系下面的无数硬件设备,这种复杂度已经达到了 O(n*m) 的级别。
设想一下,如果由你为一个设备编写跨平台驱动,肯定想通过尽可能少的代码改动,完成各个平台的适配,这绝非易事。如果使用普通的 #ifdef menuconfig 等方式来完成配置,也存在很多 boilerplate,因此,一个良好的框架就显得非常关键了。
下面来简化一下我们遇到的问题:让 N 个不同的设备在 M 中不同的 CPU 架构上运行起来。
这个问题咋一看复杂度高得吓人,O(N*M),是一种典型的强耦合,不符合软件工程 高内聚,低耦合  的基本原则。为了改进这种网状架构 ,可以引入一个中间层 (计算机世界所有问题都可以通过引入一个间接的中间层解决),让 N 个设备与中间层耦合,中间层与 M 种 CPU 架构耦合,这样就将复杂度降低了一个数量级。
2. 设备驱动模型 上面提到,可以通过分层的思想,降低设备框架的复杂度,具体是如何操作的呢?首先来看几个关键的概念
2.1 设备,总线,驱动 
设备:某种物理设备,比如网卡,硬盘,USB设备等各式各样的外设。 
总线:设备之间传递数据的通道,可以多个设备共用一条总线,也可以单个设备独享总线,一般总线的一端总是 CPU。 
驱动:与特定设备相关的程序,用来告诉 CPU 如何控制设备工作。 
 
其中,设备和驱动是紧密相连的,设备依赖驱动来发挥功能,但是,正如上面对软件架构所分析的那样,如果设备和驱动之间直接进行匹配,后果就是强耦合,高复杂度。庆幸的一点是,还有总线!
总线充当了设备与驱动之间的中间层,分别集中对设备,驱动进行管理,就完成了解耦。
2.2 总线 2.2.1 数据结构 总线对应下面的结构体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 struct  bus_type  { 	const  char 		*name; 	const  char 		*dev_name; 	struct  device 		*dev_root ; 	const  struct  attribute_group  **bus_groups ; 	const  struct  attribute_group  **dev_groups ; 	const  struct  attribute_group  **drv_groups ; 	int  (*match)(struct device *dev, struct device_driver *drv); 	int  (*uevent)(struct device *dev, struct kobj_uevent_env *env); 	int  (*probe)(struct device *dev); 	void  (*sync_state)(struct device *dev); 	int  (*remove)(struct device *dev); 	void  (*shutdown)(struct device *dev); 	int  (*online)(struct device *dev); 	int  (*offline)(struct device *dev); 	int  (*suspend)(struct device *dev, pm_message_t  state); 	int  (*resume)(struct device *dev); 	int  (*num_vf)(struct device *dev); 	int  (*dma_configure)(struct device *dev); 	const  struct  dev_pm_ops  *pm ; 	const  struct  iommu_ops  *iommu_ops ; 	struct  subsys_private  *p ; 	struct  lock_class_key  lock_key ; 	bool  need_parent_lock; };
 
各个字段的含义:
name:总线的名称,每注册一种新的总线,就会在 /sys/bus 下面创建一个名为 name 的新目录 
bus_groups、dev_groups、drv_groups:分别表示 总线、设备、驱动的属性 
match:向总线注册一个新的设备或新的驱动,调用该函数进行匹配, 
probe:总线完成设备与驱动的匹配之后,调用该函数,最终调用驱动提供的 probe 函数 
remote:删除总线时,调用该函数 
p:私有结构,其中的 klist_devices 和 klist_drivers 分别保存了该总线上所有的设备和驱动 
 
实际上,可以将总线也看成一个设备,不过这种设备比较特殊,它存在的目的是为了管理别的普通设备
2.2.2 总线注册/注销 既然是设备,也就对应 register/unregister 函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 int  bus_register (struct bus_type *bus)  { 	int  retval; 	struct  subsys_private  *priv ; 	struct  lock_class_key  *key  =  &bus->lock_key;      	priv = kzalloc(sizeof (struct subsys_private), GFP_KERNEL); 	if  (!priv) 		return  -ENOMEM; 	priv->bus = bus; 	bus->p = priv;      	BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);      	retval = kobject_set_name(&priv->subsys.kobj, "%s" , bus->name); 	if  (retval) 		goto  out; 	priv->subsys.kobj.kset = bus_kset; 	priv->subsys.kobj.ktype = &bus_ktype; 	priv->drivers_autoprobe = 1 ;      	retval = kset_register(&priv->subsys); 	if  (retval) 		goto  out;      	retval = bus_create_file(bus, &bus_attr_uevent); 	if  (retval) 		goto  bus_uevent_fail;      	priv->devices_kset = kset_create_and_add("devices" , NULL , 						 &priv->subsys.kobj); 	if  (!priv->devices_kset) { 		retval = -ENOMEM; 		goto  bus_devices_fail; 	}      	priv->drivers_kset = kset_create_and_add("drivers" , NULL , 						 &priv->subsys.kobj); 	if  (!priv->drivers_kset) { 		retval = -ENOMEM; 		goto  bus_drivers_fail; 	}      	INIT_LIST_HEAD(&priv->interfaces); 	__mutex_init(&priv->mutex, "subsys mutex" , key); 	klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); 	klist_init(&priv->klist_drivers, NULL , NULL );      	retval = add_probe_files(bus); 	if  (retval) 		goto  bus_probe_files_fail; 	retval = bus_add_groups(bus, bus->bus_groups); 	if  (retval) 		goto  bus_groups_fail; 	return  0 ;      	return  retval; } EXPORT_SYMBOL_GPL(bus_register);void  bus_unregister (struct bus_type *bus)  { 	pr_debug("bus: '%s': unregistering\n" , bus->name); 	if  (bus->dev_root) 		device_unregister(bus->dev_root); 	bus_remove_groups(bus, bus->bus_groups); 	remove_probe_files(bus); 	kset_unregister(bus->p->drivers_kset); 	kset_unregister(bus->p->devices_kset); 	bus_remove_file(bus, &bus_attr_uevent); 	kset_unregister(&bus->p->subsys); } EXPORT_SYMBOL_GPL(bus_unregister);
 
如果对于 kobject/kset 感到疑惑,可以详细阅读另一篇 文章 ,这里只需要认识到,kobject/kset 是一种设备树状管理的方式,对应 sysfs 中的目录和文件,可以将其类比为多叉树的结点 
可以看到,register 操作大部分都是在 创建 sysfs 下所需的文件(夹),通过 /sys/bus/BUS_NAME/devices 和 /sys/bus/BUS_NAME/drivers 两个目录向用户暴露设备以及驱动列表,通过其余的一些文件暴露 bus 本身的一些属性。
unregister 操作这里不再赘述
2.3 设备 2.3.1 数据结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 struct  device  { 	struct  kobject  kobj ; 	struct  device 		*parent ; 	struct  device_private 	*p ; 	const  char 		*init_name;  	const  struct  device_type  *type ; 	struct  bus_type 	*bus ; 		 	struct  device_driver  *driver ; 	 	void 		*platform_data;	 	void 		*driver_data;	 	struct  mutex 		mutex ; 	 	struct  dev_links_info 	links ; 	struct  dev_pm_info 	power ; 	struct  dev_pm_domain 	*pm_domain ; 	u64		*dma_mask;	 	u64		coherent_dma_mask; 	u64		bus_dma_limit;	 	const  struct  bus_dma_region  *dma_range_map ; 	struct  device_dma_parameters  *dma_parms ; 	struct  list_head 	dma_pools ; 	 	 	struct  dev_archdata 	archdata ; 	struct  device_node 	*of_node ;   	struct  fwnode_handle 	*fwnode ;   	dev_t 			devt;	 	u32			id;	 	spinlock_t 		devres_lock; 	struct  list_head 	devres_head ; 	struct  class 		*class ; 	const  struct  attribute_group  **groups ; 	 	void 	(*release)(struct device *dev); 	struct  iommu_group 	*iommu_group ; 	struct  dev_iommu 	*iommu ; 	bool 			offline_disabled:1 ; 	bool 			offline:1 ; 	bool 			of_node_reused:1 ; 	bool 			state_synced:1 ; };
 
关键字段的含义:
kobj:内嵌的 kobject,用于设备树状结构管理 
parent:该设备的父对象 
init_name:设备名称 
bus:归属于哪一个总线 
release:设备注销时,执行该回调函数 
 
2.3.2 设备注册/注销 设备需要注册之后才能使用,对应  device_register
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 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 128 129 130 131 132 133 134 135 136 137 138 139 140 int  device_register (struct device *dev)  { 	device_initialize(dev); 	return  device_add(dev); } EXPORT_SYMBOL_GPL(device_register);int  device_add (struct device *dev)  { 	struct  device  *parent ; 	struct  kobject  *kobj ; 	struct  class_interface  *class_intf ; 	int  error = -EINVAL; 	struct  kobject  *glue_dir  =  NULL ; 	dev = get_device(dev); 	if  (!dev) 		goto  done; 	if  (!dev->p) { 		error = device_private_init(dev); 		if  (error) 			goto  done; 	}      	if  (dev->init_name) { 		dev_set_name(dev, "%s" , dev->init_name); 		dev->init_name = NULL ; 	} 	 	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; 	} 	pr_debug("device: '%s': %s\n" , dev_name(dev), __func__);      	parent = get_device(dev->parent); 	kobj = get_device_parent(dev, parent); 	if  (IS_ERR(kobj)) { 		error = PTR_ERR(kobj); 		goto  parent_error; 	} 	if  (kobj) 		dev->kobj.parent = kobj; 	 	if  (parent && (dev_to_node(dev) == NUMA_NO_NODE)) 		set_dev_node(dev, dev_to_node(parent)); 	 	error = kobject_add(&dev->kobj, dev->kobj.parent, NULL ); 	if  (error) { 		glue_dir = get_glue_dir(dev); 		goto  Error; 	} 	 	error = device_platform_notify(dev, KOBJ_ADD); 	if  (error) 		goto  platform_error;      	error = device_create_file(dev, &dev_attr_uevent); 	if  (error) 		goto  attrError; 	error = device_add_class_symlinks(dev); 	if  (error) 		goto  SymlinkError; 	error = device_add_attrs(dev); 	if  (error) 		goto  AttrsError;      	error = bus_add_device(dev); 	if  (error) 		goto  BusError; 	error = dpm_sysfs_add(dev); 	if  (error) 		goto  DPMError; 	device_pm_add(dev); 	if  (MAJOR(dev->devt)) { 		error = device_create_file(dev, &dev_attr_dev); 		if  (error) 			goto  DevAttrError; 		error = device_create_sys_dev_entry(dev); 		if  (error) 			goto  SysEntryError; 		devtmpfs_create_node(dev); 	} 	if  (dev->bus) 		blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 					     BUS_NOTIFY_ADD_DEVICE, dev);      	kobject_uevent(&dev->kobj, KOBJ_ADD); 	if  (dev->fwnode && !dev->fwnode->dev) { 		dev->fwnode->dev = dev; 		fw_devlink_link_device(dev); 	}      	bus_probe_device(dev); 	if  (parent) 		klist_add_tail(&dev->p->knode_parent, 			       &parent->p->klist_children); 	if  (dev->class) { 		mutex_lock(&dev->class->p->mutex); 		 		klist_add_tail(&dev->p->knode_class, 			       &dev->class->p->klist_devices); 		 		list_for_each_entry(class_intf, 				    &dev->class->p->interfaces, node) 			if  (class_intf->add_dev) 				class_intf->add_dev(dev, class_intf); 		mutex_unlock(&dev->class->p->mutex); 	} done: 	put_device(dev); 	return  error;      	goto  done; } EXPORT_SYMBOL_GPL(device_add);
 
关键的一些操作已经添加了注释,这里还需要强调一下 bus_probe_device。
当设备和驱动匹配成功之后,会执行一些初始化操作,这一步必不可少,因为很多脏活累活都是在 probe 回调函数中完成的。
该 probe 函数就在 device_driver 结构中,而完成匹配+执行 probe 函数的任务,就交给了 bus_probe_device,其关键函数调用链如下所示:
1 2 3 4 5 6 7 8 bus_probe_device     --> device_initial_probe         --> __device_attach             --> __device_attach_driver                 --> driver_match_device                 --> driver_probe_device                     --> really_probe                         --> driver->probe/bus->probe
 
如果弄清楚了 device_register 的操作,那么 device_unregister 对你来说应该不是难事,只需要反向执行注册时执行的操作即可,详细操作可以参考 device_del 函数。
1 2 3 4 5 6 7 void  device_unregister (struct device *dev)  { 	pr_debug("device: '%s': %s\n" , dev_name(dev), __func__); 	device_del(dev); 	put_device(dev); } EXPORT_SYMBOL_GPL(device_unregister);
 
2.4 驱动 2.4.1 数据结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 struct  device_driver  { 	const  char 		*name; 	struct  bus_type 		*bus ; 	struct  module 		*owner ; 	const  char 		*mod_name;	 	bool  suppress_bind_attrs;	 	enum  probe_type  probe_type ; 	const  struct  of_device_id 	*of_match_table ; 	const  struct  acpi_device_id 	*acpi_match_table ; 	int  (*probe) (struct device *dev); 	void  (*sync_state)(struct device *dev); 	int  (*remove) (struct device *dev); 	void  (*shutdown) (struct device *dev); 	int  (*suspend) (struct device *dev, pm_message_t  state); 	int  (*resume) (struct device *dev); 	const  struct  attribute_group  **groups ; 	const  struct  attribute_group  **dev_groups ; 	const  struct  dev_pm_ops  *pm ; 	void  (*coredump) (struct device *dev); 	struct  driver_private  *p ; };
 
关键字段含义:
name:驱动名称,bus 通常会将该名称与设备名匹配 
bus:归属于哪个总线 
owner:该驱动的拥有者,一般为 THIS_MODULE 
probe:当驱动和设备匹配之后,会执行该函数,对设备初始化 
remove:设备从系统中移出或者系统关闭的时候,执行该函数 
 
2.4.2 驱动注册/注销 驱动 注册/注销 对应 driver_register 和 driver_unregister。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 int  driver_register (struct device_driver *drv)  { 	int  ret; 	struct  device_driver  *other ; 	if  (!drv->bus->p) { 		pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n" , 			   drv->name, drv->bus->name); 		return  -EINVAL; 	}      	if  ((drv->bus->probe && drv->probe) || 	    (drv->bus->remove && drv->remove) || 	    (drv->bus->shutdown && drv->shutdown)) 		pr_warn("Driver '%s' needs updating - please use "  			"bus_type methods\n" , drv->name);      	other = driver_find(drv->name, drv->bus); 	if  (other) { 		pr_err("Error: Driver '%s' is already registered, "  			"aborting...\n" , drv->name); 		return  -EBUSY; 	}      	ret = bus_add_driver(drv); 	if  (ret) 		return  ret; 	ret = driver_add_groups(drv, drv->groups); 	if  (ret) { 		bus_remove_driver(drv); 		return  ret; 	}      	kobject_uevent(&drv->p->kobj, KOBJ_ADD); 	return  ret; } EXPORT_SYMBOL_GPL(driver_register);
 
与 device 类似,添加一个驱动时,也需要查找有没有匹配的设备,如果有,就执行 probe 函数,这一步是在 bus_probe_device 中完成的,其函数调用链如下:
1 2 3 4 5 6 7 8 bus_add_driver     --> driver_attach         --> __device_attach             --> __device_attach_driver                 --> driver_match_device                 --> driver_probe_device                     --> really_probe                         --> driver->probe/bus->probe
 
同理,驱动的注销对应 driver_unregister,详细操作位于 bus_remove_driver,也基本是注册驱动时的逆向操作
1 2 3 4 5 6 7 8 9 10 void  driver_unregister (struct device_driver *drv)  { 	if  (!drv || !drv->p) { 		WARN(1 , "Unexpected driver unregister!\n" ); 		return ; 	} 	driver_remove_groups(drv, drv->groups); 	bus_remove_driver(drv); } EXPORT_SYMBOL_GPL(driver_unregister);