您的位置:首页 > 运维架构 > Linux

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

2017-11-17 17:21 561 查看


直接看代码。


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

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


到这里驱动的注册就完成了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: