linux中platform总线解析(三)(platform驱动的注册)


直接看代码。

其中注册过程中用到的一些重要的结构体:

platform_driver结构:

struct platform_driver {
	int (*probe)(struct platform_device *);
	int (*remove)(struct platform_device *);
	void (*shutdown)(struct platform_device *);
	int (*suspend)(struct platform_device *, pm_message_t state);
	int (*resume)(struct platform_device *);
	struct device_driver driver;
	const struct platform_device_id *id_table;
};

device_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 */

	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;

};


platform驱动的注册函数时pkatform_register,看一下这个函数具体做了什么:

int platform_driver_register(struct platform_driver *drv)
{
//设置驱动的挂载的总线类型
	drv->driver.bus = &platform_bus_type;
//如果总线对应函数存在,就覆盖掉驱动中的函数
	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);
}

可以看到这里的具体注册工作是由函数driver_register来进行的。

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

	BUG_ON(!drv->bus->p);
//如果驱动和总线都不存在probe,remove,shutdown函数就报警告信息
	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;
	}
//把驱动加入到bus中
	ret = bus_add_driver(drv);
	if (ret)
		return ret;
//sysfs相关	
	ret = driver_add_groups(drv, drv->groups);
	if (ret) {
		bus_remove_driver(drv);
		return ret;
	}
//sysfs相关
	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;
//分配驱动私有数据类型(设备,驱动等链表信息)
	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;
//把驱动加入到bus上的klist_drivers链表中
//这就真正意义上的把驱动加入到系统中了
	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;
	}
//这个函数到这里就完成了注册工作
//下面大多就是跟sysfs相关的操作,跟本篇相关性不大,先不分析
	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_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);
	}
	error = driver_add_groups(drv, bus->drv_groups);
	if (error)
	
	if (!drv->suppress_bind_attrs) {
		error = add_bind_files(drv);
			}
	}
	return 0;
out_unregister:
	kobject_put(&priv->kobj);
	kfree(drv->p);
	drv->p = NULL;
out_put_bus:
	bus_put(bus);
	return error;
}

关于sysfs操作先放到一边不取关注。

这里把驱动加入到bus的链表中后,就是真正意义上的把驱动加入到了系统中。

接下来就为把驱动绑定到设备上。

//为驱动绑定设备
int driver_attach(struct device_driver *drv)
{
//遍历bus上的设备链表,为驱动查找设备
	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;
//把总线的设备链表放入到i中
	klist_iter_init_node(&bus->p->klist_devices, &i,
			     (start ? &start->p->knode_bus : NULL));
//遍历链表,为每个设备调用fn函数进行匹配
//这里的fn就是函数__driver_attach
	while ((dev = next_device(&i)) && !error)
		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;

//把设备和驱动进行匹配
	if (!driver_match_device(drv, dev))
		return 0;

	if (dev->parent)	/* Needed for USB */
		device_lock(dev->parent);
	device_lock(dev);
//如果设备没有绑定驱动,就调用driver_probe_device函数
	if (!dev->driver)
		driver_probe_device(drv, dev);
	device_unlock(dev);
	if (dev->parent)
		device_unlock(dev->parent);

	return 0;
}

这里首先调用platfrom_match来对设备和驱动进行匹配,如果匹配完成后,就调用函数driver_probe_device进行绑定。


//调用总线上的match函数进行匹配操作,这里是platform_match函数
static inline int driver_match_device(struct device_driver *drv,
				      struct device *dev)
{
	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

//这里的匹配函数就和device注册时一样啦。总共有四种情况
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);

	/* 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;

//device和driver中的id_table一致就匹配
	if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;

//名字一致,就是匹配
	return (strcmp(pdev->name, drv->name) == 0);
}
匹配一致后,调用函数driver_probe_device进行绑定。这里就和device一致了。具体的分析看platform_device的注册。

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);

	if (dev->parent)
		pm_runtime_get_sync(dev->parent);
//调用really_probe进行真正的绑定
	pm_runtime_barrier(dev);
	ret = really_probe(dev, drv);
	pm_request_idle(dev);

	if (dev->parent)
		pm_runtime_put(dev->parent);
	return ret;
}

到这里驱动的注册就完成了


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值