学习《Linux设备模型浅析之设备篇》笔记(三)
文件/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;
}
總結
以上是生活随笔為你收集整理的学习《Linux设备模型浅析之设备篇》笔记(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学习《Linux设备模型浅析之设备篇》笔
- 下一篇: 学习《Linux设备模型浅析之设备篇》笔