int device_add(struct device *dev) { struct device *parent = NULL; struct class_interface *class_intf; int error = -EINVAL; /*引用计数加1*/ dev = get_device(dev); if (!dev) goto done;
/* Temporarily support init_name if it is set. * It will override bus_id for now */ if (dev->init_name) dev_set_name(dev, "%s", dev->init_name);
if (!strlen(dev->bus_id)) goto done;
pr_debug("device: '%s': %s\n", dev->bus_id, __func__); /*父设备的引用计数加1,并设置kobject的parent*/ 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. */ /*将内嵌的kobject加入到层次结构中,并且建立sysfs entry.*/ error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id); if (error) goto Error;
/* notify platform of device entry */ if (platform_notify) platform_notify(dev);
/* notify clients of device entry (new way) */ if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_ADD_DEVICE, dev); /*建立属性为uevent_attr的属性文件*/ error = device_create_file(dev, &uevent_attr); if (error) goto attrError; /*如果device中指定了设备号,则建立属性为devt_attr的属性文件*/ 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; }
error = device_add_class_symlinks(dev); if (error) goto SymlinkError; error = device_add_attrs(dev); if (error) goto AttrsError; /* bus_add_device()会在对应总线代表目录的device目录下创建一个到device的链接*/ error = bus_add_device(dev); if (error) goto BusError; error = dpm_sysfs_add(dev); if (error) goto DPMError; device_pm_add(dev);
/*设置环境变量,产生一个add事件; kobject_uevent_env()会调用call_usermodehelper(argv[0], argv, env->envp, UMH_WAIT_EXEC); 引起热拔插事件用户空间脚本执行。*/ kobject_uevent(&dev->kobj, KOBJ_ADD); /* bus_attach_device()是匹配设备与驱动,跟下去可以知道:如果dev->driver已经存在,最终会调用device_bind_driver()进行绑定,否则遍历dev->bus上drivers列表,调用dev->bus.match(dev,drv)来看是否有一个驱动与该dev匹配。如果匹配则绑定。*/ bus_attach_device(dev); if (parent) klist_add_tail(&dev->knode_parent, &parent->klist_children); //如果设备属于某个类,则建立类的sysfs符号链接
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: if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); 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); goto done; }
|