platform設備和驅動的註冊(2)

上篇文章中分析了platform_device_register()函數,本文接着分析platform_driver_register()函數。

static struct platform_driver driver = {
	.driver = {
		.name	= "spi-pnx8xxx",
		.owner	= THIS_MODULE,
		.bus	= &platform_bus_type,
	},
	.remove = __exit_p(pnx_remove),
};

platform_driver_register(&driver);

int platform_driver_register(struct platform_driver *drv)
{
	/*指向platform總線*/
	drv->driver.bus = &platform_bus_type;
	/*設置driver函數,注意當找到匹配的設備是就會調用platform_drv_probe,進而調用drv->probe*/
	if (drv->probe)
		drv->driver.probe = platform_drv_probe;
	if (drv->remove)
		drv->driver.remove = platform_drv_remove;
	if (drv->shutdown)
		drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}
int driver_register(struct device_driver *drv)
{
	int ret;
	struct device_driver *other;

	BUG_ON(!drv->bus->p);
	/*如果總線設置了的probe()remove()shutdown()
	 *而驅動也設置了這函數,就提示只用總線的函數,
	 *從上文中的probe函數的執行優先順序也可以看出
	 */
	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);
	/*
	 *驅動註冊時會調用kobject_add_internal函數(見下面的bus_add_driver函數)
	 *kobject_add_internal()函數會將本驅動的kobj->entry添加到
	 *bus->p->drivers_kset->list中,即/sys/bus/platform/drivers中
	 *現在就在bus->p->drivers_kset->list中查找和spi-pnx8xxx同名的驅動
	 *如果找到說明之前已經註冊過該驅動,就會打印出錯信息。
	 */
	other = driver_find(drv->name, drv->bus);
	if (other) {
		put_driver(other);
		printk(KERN_ERR "Error: Driver '%s' is already registered, "
			"aborting...\n", drv->name);
		return -EBUSY;
	}
	/*將驅動添加到總線上,並查找匹配的設備,最後執行probe函數*/
	ret = bus_add_driver(drv);
	if (ret)
		return ret;
	/*drv->groups爲NULL*/
	ret = driver_add_groups(drv, drv->groups);
	if (ret)
		bus_remove_driver(drv);
	return ret;
}
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;
	/*將父容器設置爲bus->p->drivers_kset,即/sys/bus/platform/drivers目錄*/
	priv->kobj.kset = bus->p->drivers_kset;
	/*在/sys/bus/platform/drivers中創建spi-pnx8xxx目錄
	 *並將kobj->parent設置爲/sys/bus/platform/drivers
	 *將kobj->entry添加到bus->p->drivers_kset->list中,
	 *即/sys/bus/platform/drivers對象集合(kset)中
	 */
	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
				     "%s", drv->name);
	if (error)
		goto out_unregister;
	/*查找匹配的設備,最後執行probe函數*/
	if (drv->bus->p->drivers_autoprobe) {
		error = driver_attach(drv);
		if (error)
			goto out_unregister;
	}
	/*將priv->knode_bus添加到bus->p->klist_drivers鏈表中,從而實現把驅動添加到總線上
	 *以後總線就可以在klist_drivers中查找該驅動
	 */
	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
	module_add_driver(drv->owner, drv);
	
	/*創建uevent文件*/
	error = driver_create_file(drv, &driver_attr_uevent);
	if (error) {
		printk(KERN_ERR "%s: uevent attr (%s) failed\n",
			__func__, drv->name);
	}
	
	/*bus->drv_attrs爲NULL*/
	error = driver_add_attrs(bus, drv);
	if (error) {
		/* How the hell do we get out of this pickle? Give up */
		printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
			__func__, drv->name);
	}

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

	kobject_uevent(&priv->kobj, KOBJ_ADD);
	return 0;

out_unregister:
	kfree(drv->p);
	drv->p = NULL;
	kobject_put(&priv->kobj);
out_put_bus:
	bus_put(bus);
	return error;
}
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)
		return -EINVAL;
	/*遍歷klist_devices,對每個設備調用__driver_attach,判斷是否匹配*/
	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;

	/*
	 * 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 */
		down(&dev->parent->sem);
	down(&dev->sem);
	/*綁定*/
	if (!dev->driver)
		driver_probe_device(drv, dev);
	up(&dev->sem);
	if (dev->parent)
		up(&dev->parent->sem);

	return 0;
}

static inline int driver_match_device(struct device_driver *drv,
				      struct device *dev)
{
	/*調用總線中的match函數,判斷是否匹配*/
	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
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_noresume(dev);
	pm_runtime_barrier(dev);
	/*綁定*/
	ret = really_probe(dev, drv);
	pm_runtime_put_sync(dev);

	return ret;
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
	int ret = 0;

	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 (driver_sysfs_add(dev)) {
		printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
			__func__, dev_name(dev));
		goto probe_failed;
	}
	/*執行總線中的probe函數或者驅動中的probe函數,總線優先*/
	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;
	}
	/*綁定*/
	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;

probe_failed:
	devres_release_all(dev);
	driver_sysfs_remove(dev);
	dev->driver = NULL;

	if (ret != -ENODEV && ret != -ENXIO) {
		/* driver matched but the probe failed */
		printk(KERN_WARNING
		       "%s: probe of %s failed with error %d\n",
		       drv->name, dev_name(dev), ret);
	}
	/*
	 * Ignore errors returned by ->probe so that the next driver can try
	 * its luck.
	 */
	ret = 0;
done:
	atomic_dec(&probe_count);
	wake_up(&probe_waitqueue);
	return ret;
}
static void driver_bound(struct device *dev)
{
	if (klist_node_attached(&dev->p->knode_driver)) {
		printk(KERN_WARNING "%s: device %s already bound\n",
			__func__, kobject_name(&dev->kobj));
		return;
	}

	pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
		 __func__, dev->driver->name);

	if (dev->bus)
		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
					     BUS_NOTIFY_BOUND_DRIVER, dev);
	/*將找到的設備添加到驅動的設備列表中*/
	klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
}
static int driver_sysfs_add(struct device *dev)
{
	int ret;
	/*創建軟連接
	 */sys/bus/platform/drivers/spi-pnx8xxx/spi-pnx8xxx ->
	 */sys/devices/platform/spi-pnx8xxx
	 */
	ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
			  kobject_name(&dev->kobj));
	if (ret == 0) {
		/*創建軟連接
	 	 */sys/devices/platform/spi-pnx8xxx/driver ->
	 	 */sys/bus/platform/drivers/spi-pnx8xxx
	 	 */
		ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
					"driver");
		if (ret)
			sysfs_remove_link(&dev->driver->p->kobj,
					kobject_name(&dev->kobj));
	}
	return ret;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章