文件/drivers/base/core.c
static struct kobject *get_device_parent(struct device *dev,
struct device *parent){
if (dev->class) {
static DEFINE_MUTEX(gdp_mutex);
struct kobject *kobj = NULL;
struct kobject *parent_kobj;
struct kobject *k;
#ifdef CONFIG_BLOCK
/* block disks show up in /sys/block */
if (sysfs_deprecated && dev->class == &block_class) {
if (parent && parent->class == &block_class)
return &parent->kobj;
return &block_class.p->subsys.kobj;
}
#endif
/*
* 如果没有parent, 就放在"/sys/devices/virtual"下.
* Class-devices会把一个非class-device作为parent, 放在
* 一个"glue"目录下避免命名空间冲突.
*/
if (parent == NULL)
parent_kobj = virtual_device_parent(dev);
else if (parent->class && !dev->class->ns_type)
return &parent->kobj;
else
parent_kobj = &parent->kobj;
mutex_lock(&gdp_mutex);
/* 在parent下找到我们的class目录,并引用它*/
spin_lock(&dev->class->p->glue_dirs.list_lock);
list_for_each_entry(k, &dev->class->p->glue_dirs.list, entry)
if (k->parent == parent_kobj) {
kobj = kobject_get(k);
break;
}
spin_unlock(&dev->class->p->glue_dirs.list_lock);
if (kobj) {
mutex_unlock(&gdp_mutex);
return kobj;
}
/* 或在父设备下创建一个新的class目录 */
k = class_dir_create_and_add(dev->class, parent_kobj);
/* 不要为这个简单的“glue”目录发出uevent*/
mutex_unlock(&gdp_mutex);
return k;
}
/* 子系统可以为他们的设备指定一个默认的root目录 */
if (!parent && dev->bus && dev->bus->dev_root)
return &dev->bus->dev_root->kobj;
if (parent)
return &parent->kobj;
return NULL;
}
文件/drivers/base/core.c
static int device_add_class_symlinks(struct device *dev)
{
int error;
if (!dev->class)
return 0;
error = sysfs_create_link(&dev->kobj, &dev->class->p->subsys.kobj, "subsystem");
if (error)
goto out;
if (dev->parent && device_is_not_partition(dev)) {
error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
if (error)
goto out_subsys;
}
#ifdef CONFIG_BLOCK
if (sysfs_deprecated && dev->class == &block_class)
return 0;
#endif
/* link in the class directory pointing to the device */
error = sysfs_create_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev));
if (error)
goto out_device;
return 0;
out_device:
sysfs_remove_link(&dev->kobj, "device");
out_subsys:
sysfs_remove_link(&dev->kobj, "subsystem");
out:
return error;
}
文件/drivers/base/bus.c
/**
* bus_probe_device - 为一个新设备探测驱动
* @dev: 要探测的设备
*
* - 当总线允许的时候,自动探测驱动
*/
void bus_probe_device(struct device *dev)
{
struct bus_type *bus = dev->bus;
struct subsys_interface *sif;
int ret;
if (!bus)
return;
if (bus->p->drivers_autoprobe) {
ret = device_attach(dev);
WARN_ON(ret < 0);
}
mutex_lock(&bus->p->mutex);
list_for_each_entry(sif, &bus->p->interfaces, node)
if (sif->add_dev)
sif->add_dev(dev, sif);
mutex_unlock(&bus->p->mutex);
}
文件/drivers/base/dd.c
/**
* device_attach - 尝试把一个设备粘附上一个驱动
* @dev: device.
*
* 步进遍历该总线拥有的驱动list,并为每一对调用driver_probe_device()。
* 如果找到了一个兼容对,就break并return.
*
* 如果一个设备绑定到了一个驱动上就返回1;
* 没有没有匹配的驱动找到,就返回0;
* 如果设备未注册返回-ENODEV
*
* 当其实为一个USB接口调用,必须要有一个@dev->parent的lock。
*/
int device_attach(struct device *dev)
{
int ret = 0;
device_lock(dev);
if (dev->driver) {
if (klist_node_attached(&dev->p->knode_driver)) {
ret = 1;
goto out_unlock;
}
ret = device_bind_driver(dev);
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
ret = 0;
}
} else {
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
pm_request_idle(dev);
}
out_unlock:
device_unlock(dev);
return ret;
}
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);
}
文件/drivers/base/dd.c
/**
* driver_probe_device - 尝试把设备和驱动绑定在一起
* @drv: 要绑定到设备的驱动
* @dev: 尝试绑定到驱动上的设备
*
* 如果设备未注册,该方法返回-ENODEV,
* 如果设备绑定成功返回1,否则返回0
*
* 该方法必须在@dev被锁的情况下调用。 如果是为USB接口调用,
* @dev->parent也必须被锁。
*/
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_barrier(dev);
ret = really_probe(dev, drv);
pm_request_idle(dev);
return ret;
}
文件/drivers/base/platform.c
/**
* platform_match - 绑定platform设备到platform驱动
* @dev: device.
* @drv: driver.
*
* Platform 设备ID被认定为这样编码:
* "<name><instance>", <name>是一个设备类型的短描述符,
* 如"pci"或"floppy",而<instance>是该设备的枚举实例,如'0'
* 或'42'. 驱动ID是简单的"<name>"。 所以提取platform_device
* 结构的<name>并拿他和驱动的名称比较。返回它们是否匹配。
*/
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;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
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;
/* 如果使用pinctrl, 在探测前绑定pins */
ret = pinctrl_bind_pins(dev);
if (ret)
goto probe_failed;
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;
dev_set_drvdata(dev, NULL);
if (ret == -EPROBE_DEFER) {
/* Driver requested deferred probing */
dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
driver_deferred_probe_add(dev);
} else 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);
} else {
pr_debug("%s: probe of %s rejects match %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;
}