I2C驱动框架专向分析(二)

1.1 问题简要分析

在学习I2c驱动的过程中,一直没有理解probe函数中的client是如何传入的,在这里记录并分享追踪源码的过程。

static int i2c_wds_probe(struct i2c_client *client, const struct i2c_device_id *id)

 要明白这个问题,需要分析i2c_driver以及i2c_client的注册过程,接下来本文将详细分析i2c总线流程。

1.2 i2c_driver注册过程

static int __init i2c_wds_driver_init(void)
{
	return i2c_add_driver(&i2c_wds_driver);
}

调用i2c_add_driver函数注册一个i2c设备驱动,我们可以追踪这个函数,看一下i2c_driver是如何注册到总线中。

/* use a define to avoid include chaining to get THIS_MODULE */
#define i2c_add_driver(driver) \
	i2c_register_driver(THIS_MODULE, driver)
struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
};

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
	int res;

	/* Can't register until after driver model init */
	if (unlikely(WARN_ON(!i2c_bus_type.p)))
		return -EAGAIN;

	/* add the driver to the list of i2c drivers in the driver core */
	driver->driver.owner = owner;
	driver->driver.bus = &i2c_bus_type;

	/* When registration returns, the driver core
	 * will have called probe() for all matching-but-unbound devices.
	 */
	res = driver_register(&driver->driver);
	if (res)
		return res;

	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

	INIT_LIST_HEAD(&driver->clients);
	/* Walk the adapters that are already present */
	i2c_for_each_dev(driver, __process_new_driver);

	return 0;
}

    driver->driver.bus = &i2c_bus_type; 此函数会将i2c_driver与i2c总线关联,关联的作用是可以在新设备注册到i2c总线时,i2c设备可以遍历并匹配总线上的驱动,后面我们还会分析这个问题,并且该总线结构体存在probe函数(请大家记住这点,后面分析会用到)。,进入到driver_register函数中。

int driver_register(struct device_driver *drv)
{
	int ret;
	struct device_driver *other;
.....

.....
.....

	ret = bus_add_driver(drv);
....
	return ret;
}

bus_add_driver(struct device_driver *drv)此函数会将i2c驱动注册到总线中,由于函数体太长,下面仅介绍重要代码段,进入到该函数找到 driver_attach(struct device_driver *drv)

int driver_attach(struct device_driver *drv)
{
	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}

int bus_for_each_dev(struct bus_type *bus, struct device *start,
		     void *data, int (*fn)(struct device *, void *))
{
	struct klist_iter i;
	struct device *dev;
	int error = 0;

	if (!bus || !bus->p)
		return -EINVAL;

	klist_iter_init_node(&bus->p->klist_devices, &i,
			     (start ? &start->p->knode_bus : NULL));
	while ((dev = next_device(&i)) && !error)
		error = fn(dev, data);
	klist_iter_exit(&i);
	return error;
}

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

.....

	if (!driver_match_device(drv, dev))
		return 0;

	if (dev->parent)	/* Needed for USB */
		device_lock(dev->parent);
	device_lock(dev);
	if (!dev->driver)
		driver_probe_device(drv, dev);
	device_unlock(dev);
	if (dev->parent)
		device_unlock(dev->parent);

	return 0;
}

bus_for_each_dev函数中遍历bus总线上的设备,并在__driver_attach函数中进行匹配,driver_match_device(drv, dev)匹配成功之后调用driver_probe_device(drv, dev)函数,进入到该函数中。

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_barrier(dev);
	ret = really_probe(dev, drv);
	pm_request_idle(dev);

	return ret;
}

匹配成功之后调用really_probe(dev, drv)函数,并传入匹配成功的i2c设备中的device和i2c驱动中的device_driver。进入到该函数,找到下面函数段:

.......
.......
.......

	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;
	}
.......
.......
.......

根据代码可以知道如果总线上存在probe函数,优先调用总线中的probe函数。因此我们进入到总线中的probe函数中

static int i2c_device_probe(struct device *dev)
{
	struct i2c_client	*client = i2c_verify_client(dev);
	struct i2c_driver	*driver;
	int status;

	if (!client)
		return 0;

	if (!client->irq && dev->of_node) {
		int irq = of_irq_get(dev->of_node, 0);

		if (irq == -EPROBE_DEFER)
			return irq;
		if (irq < 0)
			irq = 0;

		client->irq = irq;
	}

	driver = to_i2c_driver(dev->driver);
	if (!driver->probe || !driver->id_table)
		return -ENODEV;

	if (!device_can_wakeup(&client->dev))
		device_init_wakeup(&client->dev,
					client->flags & I2C_CLIENT_WAKE);
	dev_dbg(dev, "probe\n");

	status = of_clk_set_defaults(dev->of_node, false);
	if (status < 0)
		return status;

	status = dev_pm_domain_attach(&client->dev, true);
	if (status != -EPROBE_DEFER) {
		status = driver->probe(client, i2c_match_id(driver->id_table,
					client));
		if (status)
			dev_pm_domain_detach(&client->dev, true);
	}

	return status;
}

在代码中,首先根据传入的dev找到client结构体,再根据dev中绑定的驱动找到i2c_driver驱动结构体。然后通过driver->probe(client, i2c_match_id(driver->id_table, client))调用我们编写的i2c_driver中的probe函数,并将client传入。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值