probe是如何执行到的(以platform_bus为例)

Platform是如何工作的?(以一个i2c控制器驱动为例)

这里有两者情况:

  1. device加入了(device_add函数触发)
  2. driver加入(driver_register函数触发)

这里的基础是bus_type下有device list和driver list

struct bus_type
    ->subsys_private
    	->struct klist klist_devices;
		->struct klist klist_drivers;

开始分析,我们分析driver加入,从熟悉的platform_driver_register开始

static int __init i2c_adap_imx_init(void)
{
	return platform_driver_register(&i2c_imx_driver);
}
subsys_initcall(i2c_adap_imx_init);//如果使用了,那么i2c_adap_imx_init就会在内核启动过程中被do_one_initcall调用。
  • platform_driver_register

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

    int __platform_driver_register(struct platform_driver *drv,
    				struct module *owner)
    {
    	drv->driver.owner = owner;
    	drv->driver.bus = &platform_bus_type;//这里指定了driver的bus
    	if (drv->probe)
    		drv->driver.probe = platform_drv_probe;//这里将platform_drv_probe给了driver的probe,最后执行really_probe要用到。
    	if (drv->remove)
    		drv->driver.remove = platform_drv_remove;
    	if (drv->shutdown)
    		drv->driver.shutdown = platform_drv_shutdown;
    
    	return driver_register(&drv->driver);
    }
    
  • driver_register

    int driver_register(struct device_driver *drv)
    {
    	int ret;
    	struct device_driver *other;
    
    	BUG_ON(!drv->bus->p);
    
    	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);
    
    	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;
    }
    
  • bus_add_driver

    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);
    
    	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
    	if (!priv) {
    		error = -ENOMEM;
    		goto out_put_bus;
    	}
    	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;
    
    	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
    	if (drv->bus->p->drivers_autoprobe) {
    		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);
    	kfree(drv->p);
    	drv->p = NULL;
    out_put_bus:
    	bus_put(bus);
    	return error;
    }
    
  • driver_attach

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

    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,i->i_klist为bus的device list ;i->i_cur = NULL;
    			     (start ? &start->p->knode_bus : NULL));
    	while ((dev = next_device(&i)) && !error)//在这个循环中会便利bus上的dev,依次执行match,找到匹配的
    		error = fn(dev, data);
    	klist_iter_exit(&i);
    	return error;
    }
    
  • __driver_attach

    static int __driver_attach(struct device *dev, void *data)
    {
    	struct device_driver *drv = data;
    
    	/*
    	 * 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.
    	 */
    
    	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);//如果成功匹配到那么就准备执行其bus上的probe
    	device_unlock(dev);
    	if (dev->parent)
    		device_unlock(dev->parent);
    
    	return 0;
    }
    
  • driver_match_device

    static inline int driver_match_device(struct device_driver *drv,
    				      struct device *dev)
    {
    	return drv->bus->match ? drv->bus->match(dev, drv) : 1;//这里的drv要追溯到__platform_driver_register中的drv->driver.bus = &platform_bus_type;这里指定了driver的bus是platform_bus_type
    }
    
  • 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)
    {
    	struct platform_device *pdev = to_platform_device(dev);
    	struct platform_driver *pdrv = to_platform_driver(drv);
    
    	/* When driver_override is set, only bind to the matching driver */
    	if (pdev->driver_override)
    		return !strcmp(pdev->driver_override, drv->name);
    
    	/* Attempt an OF style match first */
    	if (of_driver_match_device(dev, drv))
    		return 1;
    
    	/* Then try ACPI style match */
    	if (acpi_driver_match_device(dev, drv))
    		return 1;
    
    	/* Then try to match against the id table */
    	if (pdrv->id_table)
    		return platform_match_id(pdrv->id_table, pdev) != NULL;
    
    	/* fall-back to driver name match */
    	return (strcmp(pdev->name, drv->name) == 0);
    }
    

接下来分析match的匹配:(这里需要拿到platform_device与platform_driver)

  • platform_device

    name: 字符串类型,表示设备的名称。用于在内核中唯一标识设备。
    id: 整数类型,表示设备的ID。用于在同类型设备中区分不同的设备实例。
    id_auto: 布尔类型,表示是否自动生成设备的ID。如果为真,则内核会自动分配设备的ID;如果为假,则使用id字段指定的ID。
    dev: 包含struct device结构体的成员,用于描述设备的常规属性,如父设备、设备地址等。
    num_resources: 无符号整数类型,表示设备资源的数量。可以是IO内存区域、中断等。
    resource: 指向struct resource结构体的指针,用于描述设备的资源信息,如IO内存、中断的起始地址和范围。
    id_entry: 指向struct platform_device_id结构体的指针,用于支持在设备驱动程序中根据设备ID进行匹配和绑定操作。
    driver_override: 字符串类型,用于强制匹配设备与指定驱动程序的名称。当设备的driver_override字段被设置时,设备只会与该名称匹配的驱动程序进行绑定。
    mfd_cell: 指向struct mfd_cell结构体的指针,用于支持多功能设备(Multifunction Device)的描述。
    archdata: 特定于架构的扩展字段,用于存储与架构相关的设备信息。
    
  • platform_driver

    static struct platform_driver i2c_imx_driver = {
    	.probe = i2c_imx_probe,
    	.remove = i2c_imx_remove,
    	.driver	= {
    		.name = DRIVER_NAME,
    		.owner = THIS_MODULE,
    		.of_match_table = i2c_imx_dt_ids,
    		.pm = IMX_I2C_PM,
    	},
    	.id_table	= imx_i2c_devtype,
    };
    
  1. 	/* When driver_override is set, only bind to the matching driver */
    	if (pdev->driver_override)
    		return !strcmp(pdev->driver_override, drv->name);//这里跟.name = DRIVER_NAME,有关,由于对于driver_override的来由(设备树部分)不太熟这里具体情况分析不了,知道的可以告诉我
    
  2. 	/* Attempt an OF style match first */
    	if (of_driver_match_device(dev, drv))
    		return 1;
    
    static inline int of_driver_match_device(struct device *dev,
    					 const struct device_driver *drv)
    {
    	return of_match_device(drv->of_match_table, dev) != NULL;//用到了.driver中的of_match_table,与设备树的compatible进行匹配
    }
    

    由于目前我对于内核(总线)如何解析和拿到设备树不太清楚,所以不能展开分析。

  3. 	/* Then try ACPI style match */
    	if (acpi_driver_match_device(dev, drv))//与电源管理相关的驱动和设备有关
    		return 1;
    
  4. 	/* Then try to match against the id table */
    	if (pdrv->id_table)
    		return platform_match_id(pdrv->id_table, pdev) != NULL;//使用.id_table
    
    static const struct platform_device_id *platform_match_id(
    			const struct platform_device_id *id,
    			struct platform_device *pdev)
    {
    	while (id->name[0]) {//遍历id_table与pdev->name去匹配(但是这里的pdev不太清楚是什么)
    		if (strcmp(pdev->name, id->name) == 0) {
    			pdev->id_entry = id;
    			return id;
    		}
    		id++;
    	}
    	return NULL;
    }
    
  5. 	/* fall-back to driver name match */
    	return (strcmp(pdev->name, drv->name) == 0);//再次使用.driver下的name与pdev->name匹配(第一次也是使用driver的name
    

ok,匹配过程说完了,那么匹配到了呢?回到我们的__driver_attach

  • __driver_attach

    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

    static int really_probe(struct device *dev, struct device_driver *drv)
    {
    	int ret = 0;
    	int local_trigger_count = atomic_read(&deferred_trigger_count);
    
    	atomic_inc(&probe_count);
    	pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
    		 drv->bus->name, __func__, drv->name, dev_name(dev));
    	WARN_ON(!list_empty(&dev->devres_head));
    
    	dev->driver = drv;
    
    	/* If using pinctrl, bind pins now before probing */
    	ret = pinctrl_bind_pins(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;
    	}
    
    	if (dev->bus->probe) {
    		ret = dev->bus->probe(dev);//不是执行总线的默认probe(而且有些总线还没有)
    		if (ret)
    			goto probe_failed;
    	} else if (drv->probe) {
    		ret = drv->probe(dev);//应该执行的是这个,前面应该把对应platform_driver的probe给了driver的probe
    		if (ret)
    			goto probe_failed;
    	}
    
    	if (dev->pm_domain && dev->pm_domain->sync)
    		dev->pm_domain->sync(dev);
    
    	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;
    .......
    .......
    done:
    	atomic_dec(&probe_count);
    	wake_up(&probe_waitqueue);
    	return ret;
    
    drv->driver.probe = platform_drv_probe;
    
  • platform_drv_probe

    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 != -EPROBE_DEFER) {
    		ret = drv->probe(dev);//这里最终执行platform_driver的probe
    		if (ret)
    			dev_pm_domain_detach(_dev, true);
    	}
    
    	if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
    		dev_warn(_dev, "probe deferral not supported\n");
    		ret = -ENXIO;
    	}
    
    	return ret;
    }
    

最终执行:

static struct platform_driver i2c_imx_driver = {
	.probe = i2c_imx_probe,
	.remove = i2c_imx_remove,
	.driver	= {
		.name = DRIVER_NAME,
		.owner = THIS_MODULE,
		.of_match_table = i2c_imx_dt_ids,
		.pm = IMX_I2C_PM,
	},
	.id_table	= imx_i2c_devtype,
};

中的i2c_imx_probe。


不足之处就是没有分析总线的dev信息是如何由设备树而来的。


补充一点:(其实really_probe中最终调用哪个probe是因总线而异的)

if (dev->bus->probe) {
    ret = dev->bus->probe(dev);//就行i2c_bus是走这条
    if (ret)
        goto probe_failed;
} else if (drv->probe) {
    ret = drv->probe(dev);//platform是走这条
    if (ret)
        goto probe_failed;
}

为什么说i2c_bus能走那条呢?

因为i2c_bus上有默认的probe,而不需要像platform一样将另一个probe传给driver的probe

static int i2c_device_probe(struct device *dev)
{
	struct i2c_client	*client = i2c_verify_client(dev);
	struct i2c_driver	*driver;
	int status;
	.......
    .......
	if (status != -EPROBE_DEFER) {
		status = driver->probe(client, i2c_match_id(driver->id_table,
					client));//执行真正的probe
		if (status)
			dev_pm_domain_detach(&client->dev, true);
	}

	return status;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值