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

本文详细解析了Linux内核中设备(device)、驱动(driver)和总线(bus)的注册过程,包括device_add()函数中设备注册的具体步骤,driver_register()函数中驱动注册的流程等。

接上一篇文章,继续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,在此基础上就可以轻松的去分析各个模块的驱动程序了^_^!

This is, on the surface, a book about writing device drivers for the Linux system. That is a worthy goal, of course; the flow of new hardware products is not likely to slow down anytime soon, and somebody is going to have to make all those new gadgets work with Linux. But this book is also about how the Linux kernel works and how to adapt its workings to your needs or interests. Linux is an open system; with this book, we hope, it is more open and accessible to a larger community of developers. This is the third edition of Linux Device Drivers. The kernel has changed greatly since this book was first published, and we have tried to evolve the text to match. This edition covers the 2.6.10 kernel as completely as we are able. We have, this time around, elected to omit the discussion of backward compatibility with previous kernel versions. The changes from 2.4 are simply too large, and the 2.4 interface remains well documented in the (freely available) second edition. This edition contains quite a bit of new material relevant to the 2.6 kernel. The discussion of locking and concurrency has been expanded and moved into its own chapter. The Linux device model, which is new in 2.6, is covered in detail. There are new chapters on the USB bus and the serial driver subsystem; the chapter on PCI has also been enhanced. While the organization of the rest of the book resembles that of the earlier editions, every chapter has been thoroughly updated. We hope you enjoy reading this book as much as we have enjoyed writing it.
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值