设备驱动模型:device, bus, driver之间的联系

对于驱动工程师而言,在移植porting对应设备的driver时,要在devicetree中增加对应的设备节点,其中有一个compatible属性,这个属性的字符串要和driver里面的of_device_id.compatible字符串要一致才能匹配调用驱动probe函数。 那device和driver是如何匹配?device,driver匹配后三者之间的数据结构联系是什么样的?

这是三者之间的联系图,后面我们从platform bus注册,platform_device创建注册和platform_driver注册。在其注册过程中产生如下的关系

                                                                  图一

1.platform bus注册时主要做了什么

struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_groups	= platform_dev_groups,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.dma_configure	= platform_dma_configure,
	.pm		= &platform_dev_pm_ops,
};


int __init platform_bus_init(void)
{
	int error;

	early_platform_cleanup();

	error = device_register(&platform_bus);
	if (error) {
		put_device(&platform_bus);
		return error;
	}
	error =  bus_register(&platform_bus_type);
	if (error)
		device_unregister(&platform_bus);
	of_platform_register_reconfig_notifier();
	return error;
}

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);   //先分配struct subsys_private空间
	if (!priv)
		return -ENOMEM;

	priv->bus = bus;    //指向bus
	bus->p = priv;       //把bus的p指针指向struct subsys_private

	BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

	retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);   //把bus的name赋值给subsys.kobj,用于后面再/sys/bus/下面创建platform文件夹
	if (retval)
		goto out;

	priv->subsys.kobj.kset = bus_kset;  //给subsys.kob指定bus_kset, 由于没由给subsys.kobj指定parent,所以后面subsys.kobj->parent会指向bus_kset.kobj
	priv->subsys.kobj.ktype = &bus_ktype; //主要是这种类型的release的回调函数,和sysfs_ops
	priv->drivers_autoprobe = 1;  //允许增加device或driver时自动匹配probe

	retval = kset_register(&priv->subsys);  //在前面的bus_kset.kobj下面创建文件夹,这里就是上面的bus_kset,也就是对应/sys/bus文件夹
	if (retval)
		goto out;

	retval = bus_create_file(bus, &bus_attr_uevent); //在/sys/bus/platform下创建uevent属性文件
	if (retval)
		goto bus_uevent_fail;

	priv->devices_kset = kset_create_and_add("devices", NULL,
						 &priv->subsys.kobj);   //在/sys/bus/platform下创建devices文件夹用于存放platform_device
	if (!priv->devices_kset) {
		retval = -ENOMEM;
		goto bus_devices_fail;
	}

	priv->drivers_kset = kset_create_and_add("drivers", NULL,
						 &priv->subsys.kobj);   //在/sys/bus/platform下创建drivers文件夹用于存放platform_driver
	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);  //初始化bus的存放devices的链表,用于存放device
	klist_init(&priv->klist_drivers, NULL, NULL); //初始化bus的存放drivers的链表,用于存放driver

	retval = add_probe_files(bus);  //在/sys/bus/platform下创建drivers_autoprobe和drivers_probe两个属性文件
	if (retval)
		goto bus_probe_files_fail;

	retval = bus_add_groups(bus, bus->bus_groups);  //这一块没看懂,但是理论上就是在对应的platform/devices/xxx/创建modalias和driver_override
	if (retval)
		goto bus_groups_fail;

	pr_debug("bus: '%s': registered\n", bus->name);
	return 0;
}

注册platform bus,最主要的事情,应该有一下几点:
1). 初始化bus的存放klist_devices的链表,用于链接platform_device.dev.p->knode_bus
2.) 初始化bus的存放klist_drivers的链表,用于链接platform_driver.device_driver.p->knode_bus
3.) 注册platform_match回调函数,用于platform_device, platform_driver的匹配函数

2.platform_device创建注册

由于流程比较长,这里先上图

                                                          图二

 platform_device初始化

static struct platform_device *of_platform_device_create_pdata(
					struct device_node *np,
					const char *bus_id,
					void *platform_data,
					struct device *parent)
{
	struct platform_device *dev;

	if (!of_device_is_available(np) ||
	    of_node_test_and_set_flag(np, OF_POPULATED))
		return NULL;
/*
 * of_device_alloc主要给platform_device分配空间,调用了device_initialize,
 * 并初始化了一些resource包含irq, reg,并将resource赋值给platform_device->resource
 */
	dev = of_device_alloc(np, bus_id, parent);
	if (!dev)
		goto err_clear_flag;

	dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
	if (!dev->dev.dma_mask)
		dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
/*
 * 注意这里,这里将platform_device->dev.bus赋值为platform_bus_type, 后面
 * platform_device, platform_driver就是根据这里的bus调用对应的platform_match函数
 */
	dev->dev.bus = &platform_bus_type; 
	dev->dev.platform_data = platform_data;
	of_msi_configure(&dev->dev, dev->dev.of_node);

	if (of_device_add(dev) != 0) {
		platform_device_put(dev);
		goto err_clear_flag;
	}

	return dev;

err_clear_flag:
	of_node_clear_flag(np, OF_POPULATED);
	return NULL;
}

根据上面图二的调用流程,我们解下来简单分析一下device_add函数

//下面函数有精简
int device_add(struct device *dev)
{
	struct device *parent;
	struct kobject *kobj;
	struct class_interface *class_intf;
	int error = -EINVAL, fw_ret;
	struct kobject *glue_dir = NULL;

	dev = get_device(dev);
	if (!dev)
		goto done;

	if (!dev->p) {
/*
 * 初始化device.p,后续会用到p->knode_driver, p->knode_bus,分别用来关联driver, bus
 */
		error = device_private_init(dev);
		if (error)
			goto done;
	}


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

	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;
/*
 * 将dev->p->knode_bus加入到bus的&bus->p->klist_devices链表里面去,这就将device和bus关
 * 联起来了
 */
	error = bus_add_device(dev);
	if (error)
		goto BusError;



/*
 * 下面是从bus的klist_drivers链表里面每个节点的driver进行匹配,匹配上后调用driver的probe
 */
	bus_probe_device(dev);
	if (parent)
		klist_add_tail(&dev->p->knode_parent,
			       &parent->p->klist_children);


done:
	put_device(dev);
	return error;

}

接着我们跳到driver_match_device函数

static inline int driver_match_device(struct device_driver *drv,
				      struct device *dev)
{
/*
 * 能走到这里的前提是platform_driver已经注册到了platform bus上去了,那么这里先看流程。
 * platform_driver注册的时候platform_driver.drv->bus已经赋值为platform_bus_type,所以
 * 调用bus->match函数就会调用到platform_bus_type.match, 也就是platform_match。
 */
	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

上面就match完成了,解下来要调用platform_driver的probe函数。下面看看调用probe前做了哪些事。

//下面这个函数略有精简
static int really_probe(struct device *dev, struct device_driver *drv)
{
	int ret = -EPROBE_DEFER;
	int local_trigger_count = atomic_read(&deferred_trigger_count);
	bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) &&
			   !drv->suppress_bind_attrs;

re_probe:
    //这里将device->driver指向匹配的device_driver, 如果probe失败下面会赋值为NULL
	dev->driver = drv;

	/* If using pinctrl, bind pins now before probing */
/*
 * 会从pinctrl_list里面获取device对应的pinctrl, 如果存在"init"名称的pinctrl, 那么就选择
 * 设置“init”的pinctrl模式。如不存在"init"的pinctrl, 就选择设置为"default"名字的pinctrl
 */
	ret = pinctrl_bind_pins(dev);
	if (ret)
		goto pinctrl_bind_failed;
//dma配置相关的
	ret = dma_configure(dev);
	if (ret)
		goto probe_failed;

	if (driver_sysfs_add(dev)) {
		printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
			__func__, dev_name(dev));
		goto probe_failed;
	}

	if (dev->pm_domain && dev->pm_domain->activate) {
		ret = dev->pm_domain->activate(dev);
		if (ret)
			goto probe_failed;
	}
// 对于platform_bus_type这里的probe是没有赋值的,所以不会走这个分支
	if (dev->bus->probe) {
		BOOTPROF_TIME_LOG_START(ts);
		ret = dev->bus->probe(dev);
		BOOTPROF_TIME_LOG_END(ts);
		bootprof_probe(ts, dev, drv, (unsigned long)dev->bus->probe);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {
		BOOTPROF_TIME_LOG_START(ts);
/* 具体platform_driver的probe是有赋值的,这里device_driver->probe会回调到platform_driver的 
 * Probe。后面分析platform_driver注册的时候,再来看看。
 */
		ret = drv->probe(dev);
		BOOTPROF_TIME_LOG_END(ts);
		bootprof_probe(ts, dev, drv, (unsigned long)drv->probe);
		if (ret)
			goto probe_failed;
	}

	

	pinctrl_init_done(dev);

/* 
 * 将&dev->p->knode_driver放到driver的dev->driver->p->klist_devices链表中,这样device和 
 * driver就建立了联系
 */
	driver_bound(dev);
	ret = 1;
	pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
		 drv->bus->name, __func__, dev_name(dev), drv->name);
	goto done;


	ret = 0;
done:
	atomic_dec(&probe_count);
	wake_up(&probe_waitqueue);
	return ret;
}

上面platform_device整个注册流程就走完了。

3.platform_driver的注册流程

                                                                    图三

下面看看platform_driver的注册流程

#define platform_driver_register(drv) \
	__platform_driver_register(drv, THIS_MODULE)

int __platform_driver_register(struct platform_driver *drv,
				struct module *owner)
{
	drv->driver.owner = owner;
//这里直接将platform_driver->driver.bus直接赋值为platform_bus_type
	drv->driver.bus = &platform_bus_type;
//将platform_driver->driver.probe 直接赋值为platform_drv_probe
	drv->driver.probe = platform_drv_probe;
	drv->driver.remove = platform_drv_remove;
	drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}

static int platform_drv_probe(struct device *_dev)
{
	struct platform_driver *drv = to_platform_driver(_dev->driver);
	struct platform_device *dev = to_platform_device(_dev);
	int ret;

	ret = of_clk_set_defaults(_dev->of_node, false);
	if (ret < 0)
		return ret;

	ret = dev_pm_domain_attach(_dev, true);
	if (ret)
		goto out;
//如果platform_driver->probe有赋值的,那么直接调用platform_driver->probe, 这里就是上面讲relly_probe时说的,会回调到platform_driver->probe
	if (drv->probe) {
		ret = drv->probe(dev);
		if (ret)
			dev_pm_domain_detach(_dev, true);
	}

out:
	if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
		dev_warn(_dev, "probe deferral not supported\n");
		ret = -ENXIO;
	}

	return ret;
}
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))
		printk(KERN_WARNING "Driver '%s' needs updating - please use "
			"bus_type methods\n", drv->name);
//到对应的bus上找又没有名字叫drv->name,如存在则说明已经这个driver在该类型的bus上已经注册上了
	other = driver_find(drv->name, drv->bus);
	if (other) {
		printk(KERN_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;
}

根据图三函数调用流程__platform_driver_register->driver_register, 来看一下driver_register

int bus_add_driver(struct device_driver *drv)
{
	struct bus_type *bus;
	struct driver_private *priv;
	int error = 0;

	bus = bus_get(drv->bus);
	if (!bus)
		return -EINVAL;

	pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
//这里初始化driver_private,driver->p 
	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		error = -ENOMEM;
		goto out_put_bus;
	}
//初始化klist_devices,后面用来存放对应的device->p->knode_driver节点
	klist_init(&priv->klist_devices, NULL, NULL);
	priv->driver = drv;
	drv->p = priv;
	priv->kobj.kset = bus->p->drivers_kset;
	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
				     "%s", drv->name);
	if (error)
		goto out_unregister;
//这里讲drvier和bus建立链接,把driver->p->knode_bus加入到了bus的bus->p->klist_drivers链表中
	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
	if (drv->bus->p->drivers_autoprobe) {
		if (driver_allows_async_probing(drv)) {
			pr_debug("bus: '%s': probing driver %s asynchronously\n",
				drv->bus->name, drv->name);
			async_schedule(driver_attach_async, drv);
		} else {
			error = driver_attach(drv);
			if (error)
				goto out_unregister;
		}
	}
	module_add_driver(drv->owner, drv);

	error = driver_create_file(drv, &driver_attr_uevent);
	if (error) {
		printk(KERN_ERR "%s: uevent attr (%s) failed\n",
			__func__, drv->name);
	}
	error = driver_add_groups(drv, bus->drv_groups);
	if (error) {
		/* How the hell do we get out of this pickle? Give up */
		printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
			__func__, drv->name);
	}

	if (!drv->suppress_bind_attrs) {
		error = add_bind_files(drv);
		if (error) {
			/* Ditto */
			printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
				__func__, drv->name);
		}
	}

	return 0;

out_unregister:
	kobject_put(&priv->kobj);
	/* drv->p is freed in driver_release()  */
	drv->p = NULL;
out_put_bus:
	bus_put(bus);
	return error;
}

下面看一下__driver_attach, driver_attach->__driver_attach

static int __driver_attach(struct device *dev, void *data)
{
	struct device_driver *drv = data;
	int ret;

	/*
	 * Lock device and try to bind to it. We drop the error
	 * here and always return 0, because we need to keep trying
	 * to bind to devices and some drivers will return an error
	 * simply if it didn't support the device.
	 *
	 * driver_probe_device() will spit a warning if there
	 * is an error.
	 */
//这里还是调用drv->bus->match(dev, drv),也就是调用到platform_bus_type->match函数
	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 */

	if (dev->parent && dev->bus->need_parent_lock)
		device_lock(dev->parent);
	device_lock(dev);
	if (!dev->p->dead && !dev->driver)
//这函数里面会调用really_probe,这个就和前面注册device是一样,就不往下分析了
		driver_probe_device(drv, dev);
	device_unlock(dev);
	if (dev->parent && dev->bus->need_parent_lock)
		device_unlock(dev->parent);

	return 0;
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值