int platform_device_register(struct platform_device *pdev) { ?? ?device_initialize(&pdev->dev); ?? ?arch_setup_pdev_archdata(pdev); ?? ?return platform_device_add(pdev); }
int platform_device_add(struct platform_device *pdev) { ?? ?int i, ret;
?? ?if (!pdev) ?? ??? ?return -EINVAL;
?? ?if (!pdev->dev.parent) ?? ??? ?pdev->dev.parent = &platform_bus; ///sys/devices/platform
?? ?pdev->dev.bus = &platform_bus_type;
?? ?switch (pdev->id) { ?? ?default: ?? ??? ?dev_set_name(&pdev->dev, "%s.%d", pdev->name,? pdev->id); ?? ??? ?break; ?? ?case PLATFORM_DEVID_NONE: ?? ??? ?dev_set_name(&pdev->dev, "%s", pdev->name); ?? ??? ?break; ?? ?case PLATFORM_DEVID_AUTO: ?? ??? ?/* ?? ??? ? * Automatically allocated device ID. We mark it as such so ?? ??? ? * that we remember it must be freed, and we append a suffix ?? ??? ? * to avoid namespace collision with explicit IDs. ?? ??? ? */ ?? ??? ?ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); ?? ??? ?if (ret < 0) ?? ??? ??? ?goto err_out; ?? ??? ?pdev->id = ret; ?? ??? ?pdev->id_auto = true; ?? ??? ?dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id); ?? ??? ?break; ?? ?}
?? ?for (i = 0; i < pdev->num_resources; i++) { ?? ??? ?struct resource *p, *r = &pdev->resource[i];
?? ??? ?if (r->name == NULL) ?? ??? ??? ?r->name = dev_name(&pdev->dev);
?? ??? ?p = r->parent; ?? ??? ?if (!p) { ?? ??? ??? ?if (resource_type(r) == IORESOURCE_MEM) ?? ??? ??? ??? ?p = &iomem_resource; ?? ??? ??? ?else if (resource_type(r) == IORESOURCE_IO) ?? ??? ??? ??? ?p = &ioport_resource; ?? ??? ?}
?? ??? ?if (p && insert_resource(p, r)) { ?? ??? ??? ?dev_err(&pdev->dev, "failed to claim resource %d: %pR\n", i, r); ?? ??? ??? ?ret = -EBUSY; ?? ??? ??? ?goto failed; ?? ??? ?} ?? ?}
?? ?pr_debug("Registering platform device '%s'. Parent at %s\n", ?? ??? ? dev_name(&pdev->dev), dev_name(pdev->dev.parent));
?? ?ret = device_add(&pdev->dev); ?? ?if (ret == 0) ?? ??? ?return ret;
?failed: ?? ?if (pdev->id_auto) { ?? ??? ?ida_simple_remove(&platform_devid_ida, pdev->id); ?? ??? ?pdev->id = PLATFORM_DEVID_AUTO; ?? ?}
?? ?while (--i >= 0) { ?? ??? ?struct resource *r = &pdev->resource[i]; ?? ??? ?if (r->parent) ?? ??? ??? ?release_resource(r); ?? ?}
?err_out: ?? ?return ret; }
#define print_dev_t(buffer, dev)?? ??? ??? ??? ??? ?\ ?? ?sprintf((buffer), "%u:%u\n", MAJOR(dev), MINOR(dev))
static ssize_t dev_show(struct device *dev, struct device_attribute *attr, ?? ??? ??? ?char *buf) { ?? ?return print_dev_t(buf, dev->devt); } static DEVICE_ATTR_RO(dev);
int device_add(struct device *dev) { ?? ?struct device *parent; ?? ?struct kobject *kobj; ?? ?struct class_interface *class_intf; ?? ?int error = -EINVAL; ?? ?struct kobject *glue_dir = NULL;
?? ?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; ?? ?}
?? ?/* subsystems can specify simple device enumeration */ ?? ?if (!dev_name(dev) && dev->bus && dev->bus->dev_name) ?? ??? ?dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
?? ?if (!dev_name(dev)) { ?? ??? ?error = -EINVAL; ?? ??? ?goto name_error; ?? ?}
?? ?pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
?? ?parent = get_device(dev->parent); ?? ?kobj = get_device_parent(dev, parent); ?? ?if (IS_ERR(kobj)) { ?? ??? ?error = PTR_ERR(kobj); ?? ??? ?goto parent_error; ?? ?} ?? ?if (kobj) ?? ??? ?dev->kobj.parent = kobj;
?? ?/* use parent numa_node */ ?? ?if (parent && (dev_to_node(dev) == NUMA_NO_NODE)) ?? ??? ?set_dev_node(dev, dev_to_node(parent));
?? ?/* first, register with generic layer. */ ?? ?/* we require the name to be set before, and pass NULL */
?? ///sys/devices/platform/xxx ?? ?error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); ?? ?if (error) { ?? ??? ?glue_dir = get_glue_dir(dev); ?? ??? ?goto Error; ?? ?}
?? ?/* notify platform of device entry */ ?? ?if (platform_notify) ?? ??? ?platform_notify(dev);
///sys/devices/platform/xxx/uevent
?? ?error = device_create_file(dev, &dev_attr_uevent); ?? ?if (error) ?? ??? ?goto attrError;
?? ?error = device_add_class_symlinks(dev); ///sys/class/xxx/xxx ?? ?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);
?? ?if (MAJOR(dev->devt)) {? //如果device有设备号,/sys/devices/platform/xxx/dev ?? ??? ?error = device_create_file(dev, &dev_attr_dev); ?? ??? ?if (error) ?? ??? ??? ?goto DevAttrError;
?? ??? ?error = device_create_sys_dev_entry(dev); ?? ??? ?if (error) ?? ??? ??? ?goto SysEntryError;
?? ??? ?devtmpfs_create_node(dev); ?? ?}
?? ?/* Notify clients of device addition.? This call must come ?? ? * after dpm_sysfs_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);//牵线device与driver ?? ?if (parent) ?? ??? ?klist_add_tail(&dev->p->knode_parent, ?? ??? ??? ??????? &parent->p->klist_children);
?? ?if (dev->class) {? //如果device有class ?? ??? ?mutex_lock(&dev->class->p->mutex); ?? ??? ?/* tie the class to the device */ ?? ??? ?klist_add_tail(&dev->knode_class, ?? ??? ??? ??????? &dev->class->p->klist_devices);
?? ??? ?/* notify any interfaces that the device is here */ ?? ??? ?list_for_each_entry(class_intf, ?? ??? ??? ??? ???? &dev->class->p->interfaces, node) ?? ??? ??? ?if (class_intf->add_dev) ?? ??? ??? ??? ?class_intf->add_dev(dev, class_intf); ?? ??? ?mutex_unlock(&dev->class->p->mutex); ?? ?} done: ?? ?put_device(dev); ?? ?return error; ?SysEntryError: ?? ?if (MAJOR(dev->devt)) ?? ??? ?device_remove_file(dev, &dev_attr_dev); ?DevAttrError: ?? ?device_pm_remove(dev); ?? ?dpm_sysfs_remove(dev); ?DPMError: ?? ?bus_remove_device(dev); ?BusError: ?? ?device_remove_attrs(dev); ?AttrsError: ?? ?device_remove_class_symlinks(dev); ?SymlinkError: ?? ?device_remove_file(dev, &dev_attr_uevent); ?attrError: ?? ?kobject_uevent(&dev->kobj, KOBJ_REMOVE); ?? ?glue_dir = get_glue_dir(dev); ?? ?kobject_del(&dev->kobj); ?Error: ?? ?cleanup_glue_dir(dev, glue_dir); parent_error: ?? ?put_device(parent); name_error: ?? ?kfree(dev->p); ?? ?dev->p = NULL; ?? ?goto done; }
int bus_add_device(struct device *dev) { ?? ?struct bus_type *bus = bus_get(dev->bus); ?? ?int error = 0;
?? ?if (bus) { ?? ??? ?pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev)); ?? ??? ?error = device_add_groups(dev, bus->dev_groups); ?? ??? ?if (error) ?? ??? ??? ?goto out_put;
///sys/bus/platform/devices/xxx,并且目录是个链接 ?? ??? ?error = sysfs_create_link(&bus->p->devices_kset->kobj, ?? ??? ??? ??? ??? ??? ?&dev->kobj, dev_name(dev)); ?? ??? ?if (error) ?? ??? ??? ?goto out_groups; ?? ??? ?error = sysfs_create_link(&dev->kobj, ?? ??? ??? ??? ?&dev->bus->p->subsys.kobj, "subsystem"); ?? ??? ?if (error) ?? ??? ??? ?goto out_subsys; ?? ??? ?klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); ?? ?} ?? ?return 0;
out_subsys: ?? ?sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev)); out_groups: ?? ?device_remove_groups(dev, bus->dev_groups); out_put: ?? ?bus_put(dev->bus); ?? ?return error; }
static int device_add_class_symlinks(struct device *dev) { ?? ?struct device_node *of_node = dev_of_node(dev); ?? ?int error;
?? ?if (of_node) { ?? ??? ?error = sysfs_create_link(&dev->kobj, &of_node->kobj,"of_node"); ?? ??? ?if (error) ?? ??? ??? ?dev_warn(dev, "Error %d creating of_node link\n",error); ?? ??? ?/* An error here doesn't warrant bringing down the device */ ?? ?}
?? ?if (!dev->class) ?? ??? ?return 0;
?? ?error = sysfs_create_link(&dev->kobj, ?? ??? ??? ??? ?? &dev->class->p->subsys.kobj, ?? ??? ??? ??? ?? "subsystem"); ?? ?if (error) ?? ??? ?goto out_devnode;
?? ?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 ?? ?/* /sys/block has directories and does not need symlinks */ ?? ?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_devnode: ?? ?sysfs_remove_link(&dev->kobj, "of_node"); ?? ?return error; }
|