`
cloudtech
  • 浏览: 4605629 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

LINUX设备驱动之设备模型五--device&driver&bus(三)

 
阅读更多

接上一篇文章,继续device_add()中的代码:

error = bus_add_device(dev);

if (error)

goto BusError;

在对应总线目录下的device目录下创建几个到device的链接文件。

error = dpm_sysfs_add(dev);

if (error)

goto DPMError;

device_pm_add(dev);

添加power文件。

/* Notify clients of device addition.This call must come

* after dpm_sysf_add() and before kobject_uevent().

*/

if (dev->bus)

blocking_notifier_call_chain(&dev->bus->p->bus_notifier,

BUS_NOTIFY_ADD_DEVICE, dev);

调用bus的回调函数。

kobject_uevent(&dev->kobj, KOBJ_ADD);

产生一个add事件。

bus_probe_device(dev);

这个函数将匹配已经注册到总线的驱动程序,如下:

void bus_probe_device(struct device *dev)

{

struct bus_type *bus = dev->bus;

int ret;

if (bus && bus->p->drivers_autoprobe) {

ret = device_attach(dev);

WARN_ON(ret < 0);

}

}

只有bus->p->drivers_autoprobe设置为1是才会去匹配,device_attach()如下:

int device_attach(struct device *dev)

{

int ret = 0;

down(&dev->sem);

if (dev->driver) {

ret = device_bind_driver(dev);

if (ret == 0)

ret = 1;

else {

dev->driver = NULL;

ret = 0;

}

} else {

pm_runtime_get_noresume(dev);

ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);

pm_runtime_put_sync(dev);

}

up(&dev->sem);

return ret;

}

如果已指定了dev->driver,则直接在相应的driver目录下建立链接文件,将驱动和设备绑定。

int device_bind_driver(struct device *dev)

{

int ret;

ret = driver_sysfs_add(dev);

if (!ret)

driver_bound(dev);

return ret;

}

driver_bound()函数如下:

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

}

通知总线绑定驱动,将设备添加到驱动的设备链表。

否则调用bus_for_each_drv()匹配总线上的驱动:

int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,

void *data, int (*fn)(struct device_driver *, void *))

{

struct klist_iter i;

struct device_driver *drv;

int error = 0;

if (!bus)

return -EINVAL;

klist_iter_init_node(&bus->p->klist_drivers, &i,

start ? &start->p->knode_bus : NULL);

while ((drv = next_driver(&i)) && !error)

error = fn(drv, data);

klist_iter_exit(&i);

return error;

}

历遍总线上的驱动,每次都调用回调函数fn()(这里是__device_attach),如果fn()返回1则匹配成功,__device_attach()如下:

static int __device_attach(struct device_driver *drv, void *data)

{

struct device *dev = data;

if (!driver_match_device(drv, dev))

return 0;

return driver_probe_device(drv, dev);

}

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->bus的match方法进行匹配,如果成功就会继续调用driver_probe_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);

pm_runtime_get_noresume(dev);

pm_runtime_barrier(dev);

ret = really_probe(dev, drv);

pm_runtime_put_sync(dev);

return ret;

}

进行一下验证和同步后调用really_probe()最终详细的匹配:

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;

}

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;

}

先假定dev的驱动为drv,然后如果总线闪的probe存在,则调用它,否则调用drv的probe()函数,返回0则匹配成功,调用driver_bound()进行设备和驱动的绑定。driver_bound()函数在上面已经分析。

接着device_add()函数中的代码:

if (dev->class) {

mutex_lock(&dev->class->p->class_mutex);

/* tie the class to the device */

klist_add_tail(&dev->knode_class,

&dev->class->p->class_devices);

/* notify any interfaces that the device is here */

list_for_each_entry(class_intf,

&dev->class->p->class_interfaces, node)

if (class_intf->add_dev)

class_intf->add_dev(dev, class_intf);

mutex_unlock(&dev->class->p->class_mutex);

}

Dev所属class的一些操作。

done:

put_device(dev);

return error;

DPMError:

bus_remove_device(dev);

BusError:

device_remove_attrs(dev);

AttrsError:

device_remove_class_symlinks(dev);

SymlinkError:

if (MAJOR(dev->devt))

device_remove_sys_dev_entry(dev);

devtattrError:

if (MAJOR(dev->devt))

device_remove_file(dev, &devt_attr);

ueventattrError:

device_remove_file(dev, &uevent_attr);

attrError:

kobject_uevent(&dev->kobj, KOBJ_REMOVE);

kobject_del(&dev->kobj);

Error:

cleanup_device_parent(dev);

if (parent)

put_device(parent);

name_error:

kfree(dev->p);

dev->p = NULL;

goto done;

最后是一下除错撤销处理。

}

至此,已经详细的分析了创建和注册设备的函数。

内核撤销设备注册的函数为device_unregister(),这里不再分析。

内核提供注册驱动的函数为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);

验证driver的包含了需要的方法,并打印信息。

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;

}

如果驱动已注册则返回-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;

}

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;

if (drv->bus->p->drivers_autoprobe) {

error = driver_attach(drv);

if (error)

goto out_unregister;

}

klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);

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

}

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

}

}

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;

}

简单的分析一下:为drv分配内存并初始化,创建文件系统中相应的目录、属性文件和链接,调用driver_attach()匹配总线上的设备,将驱动注册到bus上,产生一个kobject_uevent() ADD事件。详细的过程请参考内核源码。

同样内核提供driver_unregister()函数撤销驱动注册,这里不再分析。

至此,已经清楚了设备驱动模型的device、driver和bus,在此基础上就可以轻松的去分析各个模块的驱动程序了^_^!

分享到:
评论

相关推荐

    linux设备模型之bus,device,driver

    linux设备模型之bus,device,driver

    linux驱动 bus-device-driver模型 bus.7z

    linux驱动 bus-device-driver模型

    linux设备驱动模型--设备篇

    介绍linux设备驱动模型概念中的设备篇

    linux设备驱动模型

    linux设备驱动模型 1、kobject原理与实例分析 2、kset原理与实例分析 3、bus(总线)原理与实例分析 4、device(设备)原理与实例分析 5、driver(驱动)原理与实例分析

    Linux驱动程序开发-设备驱动模型

    Linux驱动程序开发-设备驱动模型 Linux2.6设备驱动模型的基本元素是Class、Bus、Device、Driver,下面我们分别介绍各个部分。

    linux设备模型.pdf

    接着, 第8, 9, 10, 11章描述了设备模型中最重要的4个概念: Bus, Class, Device, Driver. 第12章介绍了platform系统, 它是基于Bus, Class, Device, Driver抽象出来的一个更上层的东西, 理解了前面的内容之后, 再来看...

    Linux 设备模型

    因此,由于这个共性,内核在设备模型的基础上(device和device_driver),对这些设备进行了更进一步的封装,抽象出paltform bus、platform device和platform driver,以便驱动开发人员可以方便的开发这类设备的驱动...

    驱动模型代码

    linux3.16 bus device driver 驱动模型

    unix分析关于UNIX的一些浅析

    下图即为Linux 2.6中引入的设备驱动模型的结构图(只是个总体框架,并不是指这的platform总线,设备和驱动)。 总线上包括设备和驱动的集合,总线上所有设备组成双向循环链表,包含在platform_device...

    linux 2.6.36+ok6410 SPI子系统接口讨论

    linux下的设备模型包括几个主要的概念sysfs (dev是用户空间接口,根据sysfs下的class目录由mdev负责建立)bus总线,linux下的设备都是建立在总线上的,platform总线是一个虚拟的总线,所有的的片上设备基本上都接在...

    总线,设备,驱动关联

    Linux设备模型中三个很重要的概念就是总线,设备,驱动.即bus,device,driver,们只需要知道,drivers 和 devices 的存在,让struct bus_type与两个链表联系了起来,一个是 devices 的链表,一个是drivers 的链表,也就是说,...

Global site tag (gtag.js) - Google Analytics