本文共 3373 字,大约阅读时间需要 11 分钟。
int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)用于将一个acpi_dev和dev在sys中建立symlink,主要用于hotplug的设备,例如cpu。其源码分析如下:int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev){ struct acpi_device_physical_node *physical_node, *pn; char physical_node_name[PHYSICAL_NODE_NAME_SIZE]; struct list_head *physnode_list; unsigned int node_id; int retval = -EINVAL; #如果这个dev已经有对应的acpi_dev则退出 if (has_acpi_companion(dev)) { if (acpi_dev) { dev_warn(dev, "ACPI companion already set\n"); return -EINVAL; } else { acpi_dev = ACPI_COMPANION(dev); } } #如果acpi_dev为null,则退出 if (!acpi_dev) return -EINVAL; #分别增加acpi_dev 和dev的引用计数 get_device(&acpi_dev->dev); get_device(dev); physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL); if (!physical_node) { retval = -ENOMEM; goto err; } mutex_lock(&acpi_dev->physical_node_lock); /* * Keep the list sorted by node_id so that the IDs of removed nodes can * be recycled easily. */ physnode_list = &acpi_dev->physical_node_list; node_id = 0; list_for_each_entry(pn, &acpi_dev->physical_node_list, node) { /* Sanity check. */ #检查acpi_dev是否已经指向形参dev,如果已经指向的话且dev对应的acpi_dev也匹配的话,则退出 if (pn->dev == dev) { mutex_unlock(&acpi_dev->physical_node_lock); dev_warn(dev, "Already associated with ACPI node\n"); kfree(physical_node); #dev和acpi_dev 不匹配则退出 if (ACPI_COMPANION(dev) != acpi_dev) goto err; put_device(dev); put_device(&acpi_dev->dev); return 0; } if (pn->node_id == node_id) { physnode_list = &pn->node; node_id++; } } physical_node->node_id = node_id; physical_node->dev = dev; list_add(&physical_node->node, physnode_list); acpi_dev->physical_node_count++; #说明dev已经和acpi_dev 绑定了 if (!has_acpi_companion(dev)) ACPI_COMPANION_SET(dev, acpi_dev); #将node_id 添加到physical_node_name 这个buf表示的name中 acpi_physnode_link_name(physical_node_name, node_id); #建立acpi_dev 和dev的symlink retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, physical_node_name); if (retval) dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n", physical_node_name, retval); #建立dev和acpi_dev的symlink retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, "firmware_node"); if (retval) dev_err(dev, "Failed to create link firmware_node (%d)\n", retval); mutex_unlock(&acpi_dev->physical_node_lock); if (acpi_dev->wakeup.flags.valid) device_set_wakeup_capable(dev, true); return 0; err: ACPI_COMPANION_SET(dev, NULL); put_device(dev); put_device(&acpi_dev->dev); return retval;}与acpi_bind_one 对应的是acpi_unbind_one 来取消dev和apci_dev的symlink其源码分析如下:int acpi_unbind_one(struct device *dev){ struct acpi_device *acpi_dev = ACPI_COMPANION(dev); struct acpi_device_physical_node *entry; if (!acpi_dev) return 0; mutex_lock(&acpi_dev->physical_node_lock); list_for_each_entry(entry, &acpi_dev->physical_node_list, node) if (entry->dev == dev) { char physnode_name[PHYSICAL_NODE_NAME_SIZE]; list_del(&entry->node); acpi_dev->physical_node_count--; acpi_physnode_link_name(physnode_name, entry->node_id); sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name); sysfs_remove_link(&dev->kobj, "firmware_node"); ACPI_COMPANION_SET(dev, NULL); /* Drop references taken by acpi_bind_one(). */ put_device(dev); put_device(&acpi_dev->dev); kfree(entry); break; } mutex_unlock(&acpi_dev->physical_node_lock); return 0;}可见主要是调用sysfs_remove_link 来去掉dev和acpi_dev之间的symlink
转载地址:http://vdnmi.baihongyu.com/