您的位置:首页 > 其它

设备与驱动的匹配

2012-08-20 13:32 190 查看
看了许久,今天终于是了解了驱动及设备的注册及彼此的绑定过程,详细内容请见下文,如有不对地方请指正,多谢了!

一、

先看一下这个

int __init devices_init(void)
{
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
if (!devices_kset)
return -ENOMEM;
dev_kobj = kobject_create_and_add("dev", NULL);
if (!dev_kobj)
goto dev_kobj_err;
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
if (!sysfs_dev_block_kobj)
goto block_kobj_err;
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
if (!sysfs_dev_char_kobj)
goto char_kobj_err;

return 0;

char_kobj_err:
kobject_put(sysfs_dev_block_kobj);
block_kobj_err:
kobject_put(dev_kobj);
dev_kobj_err:
kset_unregister(devices_kset);
return -ENOMEM;
}

此功能不言而喻
再看

int device_register(struct device *dev)

{

device_initialize(dev);

return device_add(dev);

}

void device_initialize(struct device *dev)
{
dev->kobj.kset = devices_kset;
kobject_init(&dev->kobj, &device_ktype);
INIT_LIST_HEAD(&dev->dma_pools);
init_MUTEX(&dev->sem);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
device_init_wakeup(dev, 0);
device_pm_init(dev);
set_dev_node(dev, -1);
}

int device_add(struct device *dev)
{
struct device *parent = NULL;
struct class_interface *class_intf;
int error = -EINVAL;

dev = get_device(dev);
if (!dev)
goto done;

if (!dev->p) {
error = device_private_init(dev);
if (error)
goto done;
}
/*
* for statically allocated devices, which should all be converted
* some day, we need to initialize the name. We prevent reading back
* the name, and force the use of dev_name()
*/
if (dev->init_name) {
dev_set_name(dev, "%s", dev->init_name);
dev->init_name = NULL;
}

if (!dev_name(dev))
goto name_error;

pr_debug("device: '%s': %s\n", dev_name(dev), __func__);

parent = get_device(dev->parent);
setup_parent(dev, parent);

/* use parent numa_node */
if (parent)
set_dev_node(dev, dev_to_node(parent));

/* first, register with generic layer. */
/* we require the name to be set before, and pass NULL */
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
if (error)
goto Error;

/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);

error = device_create_file(dev, &uevent_attr);
if (error)
goto attrError;

if (MAJOR(dev->devt)) {
error = device_create_file(dev, &devt_attr);
if (error)
goto ueventattrError;

error = device_create_sys_dev_entry(dev);
if (error)
goto devtattrError;

devtmpfs_create_node(dev);
}

error = device_add_class_symlinks(dev);
if (error)
goto SymlinkError;
error = device_add_attrs(dev);
if (error)
goto AttrsError;
error = bus_add_device(dev);
if (error)
goto BusError;
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
device_pm_add(dev);

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

kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_probe_device(dev); //设备与驱动的探测绑定再次完成
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);

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

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

此函数的具体功能就不详细说了,主要看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);
}
}

这里如果设备的总线存在,且驱动为自动探测的话调用device_attach(dev);

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 { //这里如果设备没有驱动的话,到遍历总线上的驱动,最后调用__device_attach

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

__device_attach功能见下分分析

static int __device_attach(struct device_driver *drv, void *data)
{
struct device *dev = data;

if (!driver_match_device(drv, dev)) //这里首先进行match,这里的match调用的是bus里的match

return 0;

return driver_probe_device(drv, dev);
}

接下来再看driver_probe_device(drv, dev);

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(dev, drv);

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) {
//此处大家应该很重视吧,总线里的probe一般都为空,所以此处没用到,就此跳过
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) { //这里就是你写的驱动里的probe了,在这里才开始执行,呵呵,看到此处有何感慨!

ret = drv->probe(dev);
if (ret)
goto probe_failed;
}

driver_bound(dev); //这里完成设备的驱动节点绑定到驱动的设备链表上,至此完成了设备和驱动的绑定,同时也完成了设备驱动里的东东,注意在加载驱动的时候
bus_add_drver()实现的功能基本和这里的一样,下篇文章将分析

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

相信大家看到此处,定会万分惊喜终于找的了probe函数在何处执行,也知道了设备如何和驱动配对,绑定的,哦,不对,还没贴出绑定的函数了,如下

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

至此我什么也不想说了,下篇文章将讲述驱动配对设备
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: