Linux 总线bus、设备device、驱动device_driver三者之间的关系

1.总线bus

通常所说的总线都是cpu与设备之间通信的协议,就像两个地方,一个地方住着cpu,一个地方住着设备,总线就相当于CPU通过什么方式到达设备。(就像你要通过一个墓道,就要按照墓主人设计的方式过去,要不就会被暗器杀掉,永远也到达不了)。
但是,Linux里面的总线,我的理解就是连接设备和驱动,不是常规意义上的总线,最简单就是platform总线,它不是一个协议,它就是为了那些没有广义上协议(usb、spi、iic)的设备服务的。
 

bus的结构体如下所示:

struct bus_type {
	const char		*name;            //总线的名字
	const char		*dev_name;
	struct device		*dev_root;
	struct device_attribute	*dev_attrs;	/* use dev_groups instead */
	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);								//如果设备和驱动匹配成功,则会调用此函数,这个函数由
																	//struct device_driver里面的probe函数实现,bus里面
																	//probe最后会调用device_driver里面的probe函数。
																	//这个函数用来初始化设备。这个函数Linux内核里面已经实现
	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);

	const struct dev_pm_ops *pm;

	const struct iommu_ops *iommu_ops;

	struct subsys_private *p;
	struct lock_class_key lock_key;
};

下面以platform总线为例,讲解总线的注册。

int __init platform_bus_init(void)
{
	int error;

	early_platform_cleanup();

	error = device_register(&platform_bus);
	if (error)
		return error;
	error =  bus_register(&platform_bus_type); //这里调用总线的注册函数。
	if (error)
		device_unregister(&platform_bus);
	of_platform_register_reconfig_notifier();
	return error;
}

主要看platform_bus_type结构体

struct bus_type platform_bus_type = {
	.name		= "platform",      //总线的名字
	.dev_groups	= platform_dev_groups,
	.match		= platform_match,  //总线的匹配函数
	.uevent		= platform_uevent,	
	.pm		= &platform_dev_pm_ops,
};

platform_match函数原型如下:

static int platform_match(struct device *dev, struct device_driver *drv)
{
	------------只看具体的实现-------------
	return (strcmp(pdev->name, drv->name) == 0);
}

从上面可以看出,platform总线是通过设备和驱动的名字来实现匹配的。
内核实现的probe函数如下:

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
	int ret = 0;

	if (!device_is_registered(dev))
		return -ENODEV;

	pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
		 drv->bus->name, __func__, dev_name(dev), drv->name);

	pm_runtime_get_suppliers(dev);
	if (dev->parent)
		pm_runtime_get_sync(dev->parent);

	pm_runtime_barrier(dev);
	ret = really_probe(dev, drv); //调用驱动中的probe函数.
	pm_request_idle(dev);

	if (dev->parent)
		pm_runtime_put(dev->parent);

	pm_runtime_put_suppliers(dev);
	return ret;
}

really_probe函数中调用驱动中的probe函数的源码:

	if (dev->bus->probe) {  //platform总线的bus中的probe为空
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) { //drv->probe的条件满足,所以调用drv中probe
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}

2.设备device

设备device的结构体如下所示:

struct device {
	struct device		*parent;//父设备

	struct device_private	*p;//设备的私有数据

	struct kobject kobj;		//表示该设备并把它链接到设备模型中的kobject中
	const char		*init_name; /* initial name of the device */
	const struct device_type *type; //设备的类型

	struct mutex		mutex;	/* mutex to synchronize calls to
					 * its driver.
					 */

	struct bus_type	*bus;		/* type of bus device is on设备链接到那个总线上*/
	struct device_driver *driver;	/* 管理该设备的驱动which driver has allocated this
					   device */
	void		*platform_data;	/* 平台的特有数据Platform specific data, device
					   core doesn't touch it */
	void		*driver_data;	/* 驱动的特有数据Driver data, set and get with
					   dev_set/get_drvdata */
	struct dev_links_info	links;
	struct dev_pm_info	power;
	struct dev_pm_domain	*pm_domain;

#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
	struct irq_domain	*msi_domain;
#endif
#ifdef CONFIG_PINCTRL
	struct dev_pin_info	*pins;
#endif
#ifdef CONFIG_GENERIC_MSI_IRQ
	struct list_head	Smsi_list;
#endif

#ifdef CONFIG_NUMA
	int		numa_node;	/* NUMA node this device is close to */
#endif
	u64		*dma_mask;	/* dma mask (if dma'able device) */
	u64		coherent_dma_mask;/* Like dma_mask, but for
					     alloc_coherent mappings as
					     not all hardware supports
					     64 bit addresses for consistent
					     allocations such descriptors. */
	unsigned long	dma_pfn_offset;

	struct device_dma_parameters *dma_parms;

	struct list_head	dma_pools;	/* dma pools (if dma'ble) */

	struct dma_coherent_mem	*dma_mem; /* internal for coherent mem
					     override */
#ifdef CONFIG_DMA_CMA
	struct cma *cma_area;		/* contiguous memory area for dma
					   allocations */
#endif
	/* arch specific additions */
	struct dev_archdata	archdata;

	struct device_node	*of_node; /* associated device tree node */
	struct fwnode_handle	*fwnode; /* firmware device node */

	dev_t			devt;	/* dev_t, creates the sysfs "dev" */
	u32			id;	/* device instance */

	spinlock_t		devres_lock;
	struct list_head	devres_head;

	struct klist_node	knode_class;
	struct class		*class; //指向所属的类
	const struct attribute_group **groups;	/* optional groups */

	void	(*release)(struct device *dev);
	struct iommu_group	*iommu_group;
	struct iommu_fwspec	*iommu_fwspec;

	bool			offline_disabled:1;
	bool			offline:1;
};

它一般作为一个基类,就像kobject一样,比如在struct platform_device中就包含了这个结构体。它包含了设备的基本信息,设备所属的bus、管理设备的驱动、设备的私有数据等内容。
设备device的API如下所示:

int device_register(struct device *dev)
{
	device_initialize(dev);			//初始化struct device	
	return device_add(dev);			//在内核中添加一个设备并在内核中建立目录层次结构,
}
int device_add(struct device *dev)
{

	dev = get_device(dev);	//struct device中的struct kobject引用计数+1

	if (!dev->p) {
		error = device_private_init(dev); //dev->p->device = 
	}


	if (dev->init_name) {
		dev_set_name(dev, "%s", dev->init_name);  //将名字赋值给struct device里面的kobject  
		dev->init_name = NULL;
	}

	/* subsystems can specify simple device enumeration */
	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;
	}
	parent = get_device(dev->parent);//返回父节点,且父节点的引用计数+1
	kobj = get_device_parent(dev, parent);
	if (kobj)
		dev->kobj.parent = kobj; //重新设计父节点

	/* use parent numa_node */
	if (parent && (dev_to_node(dev) == NUMA_NO_NODE))
		set_dev_node(dev, dev_to_node(parent));

	/* first, register with generic layer. */
	/* we require the name to be set before, and pass NULL */
	error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); //建立文件夹
	if (error) {
		glue_dir = get_glue_dir(dev);
		goto Error;
	}

	/* notify platform of device entry */
	if (platform_notify)
		platform_notify(dev);

	error = device_create_file(dev, &dev_attr_uevent); //在dev所创建的文件夹下创建属性文件
	if (error)
		goto attrError;
	//建立subsystem链接文件到所属class     //sys文件夹下的目标文件夹建立软链接
	error = device_add_class_symlinks(dev);
	if (error)
		goto SymlinkError;
	//添加dev的属性描述文件
	error = device_add_attrs(dev);
	if (error)
		goto AttrsError;
	//添加链接文件到所属bus
	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);
	}

	/* Notify clients of device addition.  This call must come
	 * after dpm_sysfs_add() and before kobject_uevent().
	 */
	if (dev->bus)
		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
					     BUS_NOTIFY_ADD_DEVICE, dev);

	kobject_uevent(&dev->kobj, KOBJ_ADD);
	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);
		/* tie the class to the device */
		klist_add_tail(&dev->knode_class,
			       &dev->class->p->klist_devices);

		/* notify any interfaces that the device is here */
		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);
	}

}
void bus_probe_device(struct device *dev)
{
	struct bus_type *bus = dev->bus;
	struct subsys_interface *sif;

	if (!bus)
		return;

	if (bus->p->drivers_autoprobe)//设置了自动匹配初始化那么就开始匹配
		device_initial_probe(dev);

	mutex_lock(&bus->p->mutex);
	list_for_each_entry(sif, &bus->p->interfaces, node)
		if (sif->add_dev)
			sif->add_dev(dev, sif);
	mutex_unlock(&bus->p->mutex);
}
void device_initial_probe(struct device *dev)
{
	__device_attach(dev, true);
}
``

```c
static int __device_attach(struct device *dev, bool allow_async)
{
	int ret = 0;

	device_lock(dev);
	if (dev->driver) {  //默认制定了driver就直接绑定
		if (device_is_bound(dev)) {
			ret = 1;
			goto out_unlock;
		}
		ret = device_bind_driver(dev);
		if (ret == 0)
			ret = 1;
		else {
			dev->driver = NULL;
			ret = 0;
		}
	} else {//如果没有就进行遍历
		struct device_attach_data data = {
			.dev = dev,
			.check_async = allow_async,
			.want_async = false,
		};

		if (dev->parent)
			pm_runtime_get_sync(dev->parent);

		ret = bus_for_each_drv(dev->bus, NULL, &data,
					__device_attach_driver);
		if (!ret && allow_async && data.have_async) {
			/*
			 * If we could not find appropriate driver
			 * synchronously and we are allowed to do
			 * async probes and there are drivers that
			 * want to probe asynchronously, we'll
			 * try them.
			 */
			dev_dbg(dev, "scheduling asynchronous probe\n");
			get_device(dev);
			async_schedule(__device_attach_async_helper, dev);
		} else {
			pm_request_idle(dev);
		}

		if (dev->parent)
			pm_runtime_put(dev->parent);
	}
out_unlock:
	device_unlock(dev);
	return ret;
}
static int __device_attach_driver(struct device_driver *drv, void *_data)
{
	struct device_attach_data *data = _data;
	struct device *dev = data->dev;
	bool async_allowed;
	int ret;

	/*
	 * Check if device has already been claimed. This may
	 * happen with driver loading, device discovery/registration,
	 * and deferred probe processing happens all at once with
	 * multiple threads.
	 */
	if (dev->driver)
		return -EBUSY;

	ret = driver_match_device(drv, dev); //内核写的设备和驱动的匹配函数
	if (ret == 0) {
		/* no match */
		return 0;
	} else if (ret == -EPROBE_DEFER) {
		dev_dbg(dev, "Device match requests probe deferral\n");
		driver_deferred_probe_add(dev);
	} else if (ret < 0) {
		dev_dbg(dev, "Bus failed to match device: %d", ret);
		return ret;
	} /* ret > 0 means positive match */

	async_allowed = driver_allows_async_probing(drv);

	if (async_allowed)
		data->have_async = true;

	if (data->check_async && async_allowed != data->want_async)
		return 0;

	return driver_probe_device(drv, dev);//内核写的探测函数,如果匹配成功就会执行此函数
}

匹配函数原型如下:

static inline int driver_match_device(struct device_driver *drv,
				      struct device *dev)
{
	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

从里面可以看出,还是调用的bus注册时候的match函数。

探测函数原型如下

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
	int ret = 0;

	if (!device_is_registered(dev))
		return -ENODEV;

	pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
		 drv->bus->name, __func__, dev_name(dev), drv->name);

	pm_runtime_get_suppliers(dev);
	if (dev->parent)
		pm_runtime_get_sync(dev->parent);

	pm_runtime_barrier(dev);
	ret = really_probe(dev, drv); //真正的探测函数
	pm_request_idle(dev);

	if (dev->parent)
		pm_runtime_put(dev->parent);

	pm_runtime_put_suppliers(dev);
	return ret;
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
if (dev->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}
}

在里面首先会调用bus注册时候的probe函数,如果没有则调用驱动中的函数。

3.设备驱动driver

driver结构体如下所示:

struct device_driver {
	const char		*name;
	struct bus_type		*bus;

	struct module		*owner;
	const char		*mod_name;	/* used for built-in modules */

	bool suppress_bind_attrs;	/* disables bind/unbind via sysfs */
	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);
	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 dev_pm_ops *pm;

	struct driver_private *p;
};

设备驱动的API:

driver_register
	bus_add_driver
		driver_attach
			bus_for_each_dev
				__driver_attach
					driver_match_device
					driver_probe_device

可以看到最后调用的还是内核所开放的接口,当然,上面文件夹、属性文件、链接文件都没有写出来。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux 内核中,struct device_driver 结构体用于表示设备驱动程序。它定义在 include/linux/device.h 头文件中,其定义如下: ```c struct device_driver { const char *name; /* 驱动程序的名称 */ struct bus_type *bus; /* 设备所在的总线类型 */ struct module *owner; /* 指向驱动程序的模块 */ const char *mod_name; /* 驱动程序的模块名称 */ bool suppress_bind_attrs; /* 是否抑制属性绑定 */ const struct of_device_id *of_match_table; /* of_match_table 数组 */ const struct acpi_device_id *acpi_match_table; /* ACPI 设备 ID 数组 */ const struct dmi_system_id *dmi_match_table; /* DMI 系统 ID 数组 */ const struct attribute_group **groups; /* 属性组数组 */ int (*probe) (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 dev_pm_ops *pm; /* 设备的电源管理操作 */ struct driver_private *p; /* 驱动程序的私有数据 */ }; ``` 其中,常用的成员变量如下: - `name`:驱动程序的名称。 - `bus`:指向设备所在的总线类型的指针。 - `probe`:设备探测函数,当设备被发现时会调用该函数。 - `remove`:设备移除函数,当设备被移除时会调用该函数。 - `suspend`:设备挂起函数,当设备被挂起时会调用该函数。 - `resume`:设备恢复函数,当设备从挂起状态恢复时会调用该函数。 此外,还有一些用于设备属性和电源管理的成员变量,以及一些用于匹配设备的成员变量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值