/** * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem. * * A kset defines a group of kobjects. They can be individually * different "types" but overall these kobjects all want to be grouped * together and operated on in the same manner. ksets are used to * define the attribute callbacks and other common events that happen to * a kobject. * * @list: the list of all kobjects for this kset * @list_lock: a lock for iterating over the kobjects * @kobj: the embedded kobject for this kset (recursion, isn't it fun...) * @uevent_ops: the set of uevent operations for this kset. These are * called whenever a kobject has something happen to it so that the kset * can add new environment variables, or filter out the uevents if so * desired. */ structkset { structlist_headlist; spinlock_t list_lock; structkobjectkobj; conststructkset_uevent_ops *uevent_ops; } __randomize_layout;
/** * struct bus_type - The bus type of the device * * @name: The name of the bus. * @dev_name: Used for subsystems to enumerate devices like ("foo%u", dev->id). * @dev_root: Default device to use as the parent. * @bus_groups: Default attributes of the bus. * @dev_groups: Default attributes of the devices on the bus. * @drv_groups: Default attributes of the device drivers on the bus. * @match: Called, perhaps multiple times, whenever a new device or driver * is added for this bus. It should return a positive value if the * given device can be handled by the given driver and zero * otherwise. It may also return error code if determining that * the driver supports the device is not possible. In case of * -EPROBE_DEFER it will queue the device for deferred probing. * @uevent: Called when a device is added, removed, or a few other things * that generate uevents to add the environment variables. * @probe: Called when a new device or driver add to this bus, and callback * the specific driver's probe to initial the matched device. * @sync_state: Called to sync device state to software state after all the * state tracking consumers linked to this device (present at * the time of late_initcall) have successfully bound to a * driver. If the device has no consumers, this function will * be called at late_initcall_sync level. If the device has * consumers that are never bound to a driver, this function * will never get called until they do. * @remove: Called when a device removed from this bus. * @shutdown: Called at shut-down time to quiesce the device. * * @online: Called to put the device back online (after offlining it). * @offline: Called to put the device offline for hot-removal. May fail. * * @suspend: Called when a device on this bus wants to go to sleep mode. * @resume: Called to bring a device on this bus out of sleep mode. * @num_vf: Called to find out how many virtual functions a device on this * bus supports. * @dma_configure: Called to setup DMA configuration on a device on * this bus. * @pm: Power management operations of this bus, callback the specific * device driver's pm-ops. * @iommu_ops: IOMMU specific operations for this bus, used to attach IOMMU * driver implementations to a bus and allow the driver to do * bus-specific setup * @p: The private data of the driver core, only the driver core can * touch this. * @lock_key: Lock class key for use by the lock validator * @need_parent_lock: When probing or removing a device on this bus, the * device core should lock the device's parent. * * A bus is a channel between the processor and one or more devices. For the * purposes of the device model, all devices are connected via a bus, even if * it is an internal, virtual, "platform" bus. Buses can plug into each other. * A USB controller is usually a PCI device, for example. The device model * represents the actual connections between buses and the devices they control. * A bus is represented by the bus_type structure. It contains the name, the * default attributes, the bus' methods, PM operations, and the driver core's * private data. */ structbus_type { constchar *name; //总线类型的名称 constchar *dev_name;//总线设备名称 structdevice *dev_root;//总线设备的根设备 conststructattribute_group **bus_groups;//总线类型的属性组 conststructattribute_group **dev_groups;//设备的属性组 conststructattribute_group **drv_groups;//驱动程序的属性组
int (*match)(struct device *dev, struct device_driver *drv);//设备和驱动程序之间的匹配函数 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);//设备的事件处理函数 int (*probe)(struct device *dev);//设备的探测函数 void (*sync_state)(struct device *dev);//设备状态同步函数 int (*remove)(struct device *dev);//设备的移除函数 void (*shutdown)(struct device *dev);
int (*online)(struct device *dev);//设备上线函数 int (*offline)(struct device *dev);//设备离线函数
int (*suspend)(struct device *dev, pm_message_t state);//设备的挂起函数 int (*resume)(struct device *dev);//设备的恢复函数
int (*num_vf)(struct device *dev);//设备的虚拟功能数目函数
int (*dma_configure)(struct device *dev);//设备的 DMA 配置函数
/** * struct device - The basic device structure * @parent: The device's "parent" device, the device to which it is attached. * In most cases, a parent device is some sort of bus or host * controller. If parent is NULL, the device, is a top-level device, * which is not usually what you want. * @p: Holds the private data of the driver core portions of the device. * See the comment of the struct device_private for detail. * @kobj: A top-level, abstract class from which other classes are derived. * @init_name: Initial name of the device. * @type: The type of device. * This identifies the device type and carries type-specific * information. * @mutex: Mutex to synchronize calls to its driver. * @lockdep_mutex: An optional debug lock that a subsystem can use as a * peer lock to gain localized lockdep coverage of the device_lock. * @bus: Type of bus device is on. * @driver: Which driver has allocated this * @platform_data: Platform data specific to the device. * Example: For devices on custom boards, as typical of embedded * and SOC based hardware, Linux often uses platform_data to point * to board-specific structures describing devices and how they * are wired. That can include what ports are available, chip * variants, which GPIO pins act in what additional roles, and so * on. This shrinks the "Board Support Packages" (BSPs) and * minimizes board-specific #ifdefs in drivers. * @driver_data: Private pointer for driver specific info. * @links: Links to suppliers and consumers of this device. * @power: For device power management. * See Documentation/driver-api/pm/devices.rst for details. * @pm_domain: Provide callbacks that are executed during system suspend, * hibernation, system resume and during runtime PM transitions * along with subsystem-level and driver-level callbacks. * @em_pd: device's energy model performance domain * @pins: For device pin management. * See Documentation/driver-api/pinctl.rst for details. * @msi_list: Hosts MSI descriptors * @msi_domain: The generic MSI domain this device is using. * @numa_node: NUMA node this device is close to. * @dma_ops: DMA mapping operations for this device. * @dma_mask: Dma mask (if dma'ble device). * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all * hardware supports 64-bit addresses for consistent allocations * such descriptors. * @bus_dma_limit: Limit of an upstream bridge or bus which imposes a smaller * DMA limit than the device itself supports. * @dma_range_map: map for DMA memory ranges relative to that of RAM * @dma_parms: A low level driver may set these to teach IOMMU code about * segment limitations. * @dma_pools: Dma pools (if dma'ble device). * @dma_mem: Internal for coherent mem override. * @cma_area: Contiguous memory area for dma allocations * @archdata: For arch-specific additions. * @of_node: Associated device tree node. * @fwnode: Associated device node supplied by platform firmware. * @devt: For creating the sysfs "dev". * @id: device instance * @devres_lock: Spinlock to protect the resource of the device. * @devres_head: The resources list of the device. * @knode_class: The node used to add the device to the class list. * @class: The class of the device. * @groups: Optional attribute groups. * @release: Callback to free the device after all references have * gone away. This should be set by the allocator of the * device (i.e. the bus driver that discovered the device). * @iommu_group: IOMMU group the device belongs to. * @iommu: Per device generic IOMMU runtime data * @removable: Whether the device can be removed from the system. This * should be set by the subsystem / bus driver that discovered * the device. * * @offline_disabled: If set, the device is permanently online. * @offline: Set after successful invocation of bus type's .offline(). * @of_node_reused: Set if the device-tree node is shared with an ancestor * device. * @state_synced: The hardware state of this device has been synced to match * the software state of this device by calling the driver/bus * sync_state() callback. * @dma_coherent: this particular device is dma coherent, even if the * architecture supports non-coherent devices. * @dma_ops_bypass: If set to %true then the dma_ops are bypassed for the * streaming DMA operations (->map_* / ->unmap_* / ->sync_*), * and optionall (if the coherent mask is large enough) also * for dma allocations. This flag is managed by the dma ops * instance from ->dma_supported. * * At the lowest level, every device in a Linux system is represented by an * instance of struct device. The device structure contains the information * that the device model core needs to model the system. Most subsystems, * however, track additional information about the devices they host. As a * result, it is rare for devices to be represented by bare device structures; * instead, that structure, like kobject structures, is usually embedded within * a higher-level representation of the device. */ structdevice {
constchar *init_name; /* initial name of the device *///设备初始化的名字 conststructdevice_type *type;
structbus_type *bus;/* type of bus device is on *///设备所属的总线 structdevice_driver *driver;/* which driver has allocated this device */ void *platform_data; /* Platform specific data, device core doesn't touch it */ void *driver_data; /* Driver data, set and get with dev_set_drvdata/dev_get_drvdata */ #ifdef CONFIG_PROVE_LOCKING structmutexlockdep_mutex; #endif structmutexmutex;/* mutex to synchronize calls to * its driver. */
#ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */ #endif dev_t devt; /* dev_t, creates the sysfs "dev" */ u32 id; /* device instance */
/** * struct device_driver - The basic device driver structure * @name: Name of the device driver. * @bus: The bus which the device of this driver belongs to. * @owner: The module owner. * @mod_name: Used for built-in modules. * @suppress_bind_attrs: Disables bind/unbind via sysfs. * @probe_type: Type of the probe (synchronous or asynchronous) to use. * @of_match_table: The open firmware table. * @acpi_match_table: The ACPI match table. * @probe: Called to query the existence of a specific device, * whether this driver can work with it, and bind the driver * to a specific device. * @sync_state: Called to sync device state to software state after all the * state tracking consumers linked to this device (present at * the time of late_initcall) have successfully bound to a * driver. If the device has no consumers, this function will * be called at late_initcall_sync level. If the device has * consumers that are never bound to a driver, this function * will never get called until they do. * @remove: Called when the device is removed from the system to * unbind a device from this driver. * @shutdown: Called at shut-down time to quiesce the device. * @suspend: Called to put the device to sleep mode. Usually to a * low power state. * @resume: Called to bring a device from sleep mode. * @groups: Default attributes that get created by the driver core * automatically. * @dev_groups: Additional attributes attached to device instance once the * it is bound to the driver. * @pm: Power management operations of the device which matched * this driver. * @coredump: Called when sysfs entry is written to. The device driver * is expected to call the dev_coredump API resulting in a * uevent. * @p: Driver core's private data, no one other than the driver * core can touch this. * * The device driver-model tracks all of the drivers known to the system. * The main reason for this tracking is to enable the driver core to match * up drivers with new devices. Once drivers are known objects within the * system, however, a number of other things become possible. Device drivers * can export information and configuration variables that are independent * of any specific device. */ structdevice_driver { constchar *name;// 设备驱动程序的名称 structbus_type *bus;// 设备驱动程序所属的总线类型
structmodule *owner;// 拥有该驱动程序的模块。 constchar *mod_name; /* used for built-in modules */// 用于内置模块的名称
/** * struct class - device classes * @name: Name of the class. * @owner: The module owner. * @class_groups: Default attributes of this class. * @dev_groups: Default attributes of the devices that belong to the class. * @dev_kobj: The kobject that represents this class and links it into the hierarchy. * @dev_uevent: Called when a device is added, removed from this class, or a * few other things that generate uevents to add the environment * variables. * @devnode: Callback to provide the devtmpfs. * @class_release: Called to release this class. * @dev_release: Called to release the device. * @shutdown_pre: Called at shut-down time before driver shutdown. * @ns_type: Callbacks so sysfs can detemine namespaces. * @namespace: Namespace of the device belongs to this class. * @get_ownership: Allows class to specify uid/gid of the sysfs directories * for the devices belonging to the class. Usually tied to * device's namespace. * @pm: The default device power management operations of this class. * @p: The private data of the driver core, no one other than the * driver core can touch this. * * A class is a higher-level view of a device that abstracts out low-level * implementation details. Drivers may see a SCSI disk or an ATA disk, but, * at the class level, they are all simply disks. Classes allow user space * to work with devices based on what they do, rather than how they are * connected or how they work. */ structclass { constchar *name; //设备类的名称 structmodule *owner;//拥有该类的模块 // 类属性组,用于描述设备类的属性,在类注册到内核时,会自动在/sys/class/xxx_class 下创建对应的属性文件 conststructattribute_group **class_groups; // 设备属性组,用于描述设备的属性,在类注册到内核时,会自动在该类下的设备目录创建对应的属性文件 conststructattribute_group **dev_groups; // 设备的内核对象 structkobject *dev_kobj;
/** * kobject_create_and_add() - Create a struct kobject dynamically and * register it with sysfs. * @name: the name for the kobject * @parent: the parent kobject of this kobject, if any. * * This function creates a kobject structure dynamically and registers it * with sysfs. When you are finished with this structure, call * kobject_put() and the structure will be dynamically freed when * it is no longer being used. * * If the kobject was not able to be created, NULL will be returned. */ struct kobject *kobject_create_and_add(constchar *name, struct kobject *parent) { structkobject *kobj; int retval;
/** * kobject_add() - The main kobject add function. * @kobj: the kobject to add * @parent: pointer to the parent of the kobject. * @fmt: format to name the kobject with. * * The kobject name is set and added to the kobject hierarchy in this * function. * * If @parent is set, then the parent of the @kobj will be set to it. * If @parent is NULL, then the parent of the @kobj will be set to the * kobject associated with the kset assigned to this kobject. If no kset * is assigned to the kobject, then the kobject will be located in the * root of the sysfs tree. * * Note, no "add" uevent will be created with this call, the caller should set * up all of the necessary sysfs files for the object and then call * kobject_uevent() with the UEVENT_ADD parameter to ensure that * userspace is properly notified of this kobject's creation. * * Return: If this function returns an error, kobject_put() must be * called to properly clean up the memory associated with the * object. Under no instance should the kobject that is passed * to this function be directly freed with a call to kfree(), * that can leak memory. * * If this function returns success, kobject_put() must also be called * in order to properly clean up the memory associated with the object. * * In short, once this function is called, kobject_put() MUST be called * when the use of the object is finished in order to properly free * everything. */ intkobject_add(struct kobject *kobj, struct kobject *parent, constchar *fmt, ...) { va_list args; int retval;
if (!kobj) return -EINVAL;
if (!kobj->state_initialized) { pr_err("kobject '%s' (%p): tried to add an uninitialized object, something is seriously wrong.\n", kobject_name(kobj), kobj); dump_stack(); return -EINVAL; } va_start(args, fmt); retval = kobject_add_varg(kobj, parent, fmt, args); va_end(args);
retval = kobject_set_name_vargs(kobj, fmt, vargs); if (retval) { pr_err("kobject: can not set name properly!\n"); return retval; } kobj->parent = parent; return kobject_add_internal(kobj); }
staticintkobject_add_internal(struct kobject *kobj) { int error = 0; structkobject *parent;
if (!kobj) return -ENOENT;
if (!kobj->name || !kobj->name[0]) { WARN(1, "kobject: (%p): attempted to be registered with empty name!\n", kobj); return -EINVAL; }
parent = kobject_get(kobj->parent);
/* join kset if set, use it as parent if we do not already have one */ if (kobj->kset) { if (!parent) parent = kobject_get(&kobj->kset->kobj); kobj_kset_join(kobj); kobj->parent = parent; }
/* be noisy on error issues */ if (error == -EEXIST) pr_err("%s failed for %s with -EEXIST, don't try to register things with the same name in the same directory.\n", __func__, kobject_name(kobj)); else pr_err("%s failed for %s (error: %d parent: %s)\n", __func__, kobject_name(kobj), error, parent ? kobject_name(parent) : "'none'"); } else kobj->state_in_sysfs = 1;
error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj)); if (error) return error;
error = populate_dir(kobj); if (error) { sysfs_remove_dir(kobj); return error; }
if (ktype) { error = sysfs_create_groups(kobj, ktype->default_groups); if (error) { sysfs_remove_dir(kobj); return error; } }
/* * @kobj->sd may be deleted by an ancestor going away. Hold an * extra reference so that it stays until @kobj is gone. */ sysfs_get(kobj->sd);
/* * If @kobj has ns_ops, its children need to be filtered based on * their namespace tags. Enable namespace support on @kobj->sd. */ ops = kobj_child_ns_ops(kobj); if (ops) { BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE); BUG_ON(ops->type >= KOBJ_NS_TYPES); BUG_ON(!kobj_ns_type_registered(ops->type));
/** * sysfs_create_dir_ns - create a directory for an object with a namespace tag * @kobj: object we're creating directory for * @ns: the namespace tag to use */ intsysfs_create_dir_ns(struct kobject *kobj, constvoid *ns) { structkernfs_node *parent, *kn; kuid_t uid; kgid_t gid;
if (WARN_ON(!kobj)) return -EINVAL;
if (kobj->parent) parent = kobj->parent->sd; else parent = sysfs_root_kn;
if (t && !t->release) pr_debug("kobject: '%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n", kobject_name(kobj), kobj);
/* remove from sysfs if the caller did not do it */ if (kobj->state_in_sysfs) { pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n", kobject_name(kobj), kobj); __kobject_del(kobj); } else { /* avoid dropping the parent reference unnecessarily */ parent = NULL; }
constchar *init_name; /* initial name of the device */ conststructdevice_type *type;
structbus_type *bus;/* type of bus device is on */ structdevice_driver *driver;/* which driver has allocated this device */ void *platform_data; /* Platform specific data, device core doesn't touch it */ void *driver_data; /* Driver data, set and get with dev_set_drvdata/dev_get_drvdata */ #ifdef CONFIG_PROVE_LOCKING structmutexlockdep_mutex; #endif structmutexmutex;/* mutex to synchronize calls to * its driver. */
#ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */ #endif dev_t devt; /* dev_t, creates the sysfs "dev" */ u32 id; /* device instance */
/** * bus_register - register a driver-core subsystem * @bus: bus to register * * Once we have that, we register the bus with the kobject * infrastructure, then register the children subsystems it has: * the devices and drivers that belong to the subsystem. */ intbus_register(struct bus_type *bus) { int retval; structsubsys_private *priv; structlock_class_key *key = &bus->lock_key; // 分配并初始化一个 subsys_private 结构体,用于保存子系统的相关信息 priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); if (!priv) return -ENOMEM;
// drivers/base/base.h /** * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure. * * @subsys - the struct kset that defines this subsystem * @devices_kset - the subsystem's 'devices' directory * @interfaces - list of subsystem interfaces associated * @mutex - protect the devices, and interfaces lists. * * @drivers_kset - the list of drivers associated * @klist_devices - the klist to iterate over the @devices_kset * @klist_drivers - the klist to iterate over the @drivers_kset * @bus_notifier - the bus notifier list for anything that cares about things * on this bus. * @bus - pointer back to the struct bus_type that this structure is associated * with. * * @glue_dirs - "glue" directory to put in-between the parent device to * avoid namespace conflicts * @class - pointer back to the struct class that this structure is associated * with. * * This structure is the one that is the actual kobject allowing struct * bus_type/class to be statically allocated safely. Nothing outside of the * driver core should ever touch these fields. */ structsubsys_private { structksetsubsys; structkset *devices_kset; structlist_headinterfaces; structmutexmutex;
// drivers/base/core.c intdevice_add(struct device *dev) { structdevice *parent; structkobject *kobj; structclass_interface *class_intf; int error = -EINVAL; structkobject *glue_dir =NULL; // 获取设备的引用 dev = get_device(dev); if (!dev) goto done;
if (!dev->p) { // 如果设备的私有数据(private data)未初始化,则进行初始化 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; }
/* use parent numa_node */ if (parent && (dev_to_node(dev) == NUMA_NO_NODE)) set_dev_node(dev, dev_to_node(parent));// 使用父设备的 NUMA 节点
/* first, register with generic layer. */ /* we require the name to be set before, and pass NULL */ // 首先,向通用层注册设备 // 需要在此之前设置设备的名称,并将 parent 设置为 NULL error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); if (error) { glue_dir = get_glue_dir(dev); goto Error; }
/* notify platform of device entry */ // 通知平台设备的添加 error = device_platform_notify(dev, KOBJ_ADD); if (error) goto platform_error; // 创建设备的 uevent 属性文件 error = device_create_file(dev, &dev_attr_uevent); if (error) goto attrError; // 添加设备类的符号链接 error = device_add_class_symlinks(dev); 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);
// 如果设备的 devt 存在主设备号 if (MAJOR(dev->devt)) { // 创建设备的 dev 属性文件 error = device_create_file(dev, &dev_attr_dev); if (error) goto DevAttrError; // 创建设备的 sys 设备节点 error = device_create_sys_dev_entry(dev); if (error) goto SysEntryError; // 在 devtmpfs 上创建设备节点 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);
/* * Check if any of the other devices (consumers) have been waiting for * this device (supplier) to be added so that they can create a device * link to it. * * This needs to happen after device_pm_add() because device_link_add() * requires the supplier be registered before it's called. * * But this also needs to happen before bus_probe_device() to make sure * waiting consumers can link to it before the driver is bound to the * device and the driver sync_state callback is called for this device. */ // 检查其他设备(消费者)是否一直在等待该设备(供应者)的添加,以便可以创建设备链接。 if (dev->fwnode && !dev->fwnode->dev) { dev->fwnode->dev = dev; fw_devlink_link_device(dev); } // 对总线中的设备进行探测 bus_probe_device(dev); if (parent)// 如果存在父设备,则将当前设备添加到父设备的子设备列表中 klist_add_tail(&dev->p->knode_parent, &parent->p->klist_children); // 如果设备有类别 if (dev->class) { mutex_lock(&dev->class->p->mutex); /* tie the class to the device */ klist_add_tail(&dev->p->knode_class, &dev->class->p->klist_devices);// 将设备添加到类别的设备列表中
/** * bus_add_device - add device to bus * @dev: device being added * * - Add device's bus attributes. * - Create links to device's bus. * - Add the device to its bus's list of devices. */ intbus_add_device(struct device *dev) { structbus_type *bus = bus_get(dev->bus);// 获取设备所属的总线类型(bus_type)的指针 int error = 0;
/** * platform_device_add - add a platform device to device hierarchy * @pdev: platform device we're adding * * This is part 2 of platform_device_register(), though may be called * separately _iff_ pdev was allocated by platform_device_alloc(). */ intplatform_device_add(struct platform_device *pdev) { u32 i; int ret;
if (!pdev)// 检查输入的平台设备指针是否为空 return -EINVAL;
if (!pdev->dev.parent)// 如果平台设备的父设备为空,将父设备设置为 platform_bus pdev->dev.parent = &platform_bus;
switch (pdev->id) {// 根据平台设备的 id 进行不同的处理 default: dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);// 根据设备名和 id 设置设备的名字 break; case PLATFORM_DEVID_NONE: // 如果 id 为 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. */ /* * 自动分配的设备 ID。将其标记为自动分配的,以便我们记住它需要释放, * 并且为了避免与显式 ID 的命名空间冲突,我们附加一个后缀。 */ ret = ida_alloc(&platform_devid_ida, 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++) { structresource *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; elseif (resource_type(r) == IORESOURCE_IO) p = &ioport_resource; }
if (p) { // 如果父资源存在,并且将资源插入到父资源中失败,则返回错误 ret = insert_resource(p, r); if (ret) { dev_err(&pdev->dev, "failed to claim resource %d: %pR\n", i, r); 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) {// 如果设备 ID 是自动分配的,需要移除已分配的 ID ida_free(&platform_devid_ida, pdev->id); pdev->id = PLATFORM_DEVID_AUTO; }
while (i--) {// 在失败的情况下,释放已插入的资源 structresource *r = &pdev->resource[i]; if (r->parent) release_resource(r); }
// drivers/base/driver.c /** * driver_register - register driver with bus * @drv: driver to register * * We pass off most of the work to the bus_add_driver() call, * since most of the things we have to do deal with the bus * structures. */ intdriver_register(struct device_driver *drv) { int ret; structdevice_driver *other; // 检查总线是否已初始化 if (!drv->bus->p) { pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n", drv->name, drv->bus->name); return -EINVAL; } // 检查驱动程序的方法是否需要更新 if ((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || (drv->bus->shutdown && drv->shutdown)) pr_warn("Driver '%s' needs updating - please use " "bus_type methods\n", drv->name); // 检查驱动程序是否已被注册 other = driver_find(drv->name, drv->bus); if (other) { pr_err("Error: Driver '%s' is already registered, " "aborting...\n", drv->name); return -EBUSY; }
ret = bus_add_driver(drv);// 将驱动程序添加到总线 if (ret) return ret; ret = driver_add_groups(drv, drv->groups);// 添加驱动程序的组属性 if (ret) { bus_remove_driver(drv);// 移除已添加的驱动程序 return ret; } kobject_uevent(&drv->p->kobj, KOBJ_ADD);// 发送内核对象事件,通知驱动程序添加成功
//drivers/base/dd.c /** * driver_attach - try to bind driver to devices. * @drv: driver. * * Walk the list of devices that the bus has on it and try to * match the driver with each one. If driver_probe_device() * returns 0 and the @dev->driver is set, we've found a * compatible pair. */ intdriver_attach(struct device_driver *drv) { //bus_for_each_dev() 函数主要是提供了一个遍历指定总线上的设备对象列表, // 并对每个设备对象进行特定操作的快捷方式,可以用于驱动程序中需要管理和操作大量设备实例的场景 return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); } EXPORT_SYMBOL_GPL(driver_attach);
/* * Lock device and try to bind to it. We drop the error * here and always return 0, because we need to keep trying * to bind to devices and some drivers will return an error * simply if it didn't support the device. * * driver_probe_device() will spit a warning if there * is an error. */
ret = driver_match_device(drv, dev);// 尝试将驱动程序绑定到设备上 if (ret == 0) { /* no match */ return0; } elseif (ret == -EPROBE_DEFER) { dev_dbg(dev, "Device match requests probe deferral\n"); driver_deferred_probe_add(dev);// 请求推迟探测设备 /* * Driver could not match with device, but may match with * another device on the bus. */ return0; } elseif (ret < 0) {// 总线无法匹配设备,返回错误码 dev_dbg(dev, "Bus failed to match device: %d\n", ret); /* * Driver could not match with device, but may match with * another device on the bus. */ return0; } /* ret > 0 means positive match */
if (driver_allows_async_probing(drv)) { /* * Instead of probing the device synchronously we will * probe it asynchronously to allow for more parallelism. * * We only take the device lock here in order to guarantee * that the dev->driver and async_driver fields are protected */ dev_dbg(dev, "probing driver %s asynchronously\n", drv->name); device_lock(dev);// 锁定设备以保护 dev->driver 和 async_driver 字段 if (!dev->driver) { get_device(dev); dev->p->async_driver = drv;// 设置设备的异步驱动程序 async = true; } device_unlock(dev); if (async) async_schedule_dev(__driver_attach_async_helper, dev);// 异步调度驱动程序的附加处理函数 return0; }
// drivers/base/dd.c /** * device_driver_attach - attach a specific driver to a specific device * @drv: Driver to attach * @dev: Device to attach it to * * Manually attach driver to a device. Will acquire both @dev lock and * @dev->parent lock if needed. */ intdevice_driver_attach(struct device_driver *drv, struct device *dev) { int ret = 0;
__device_driver_lock(dev, dev->parent);
/* * If device has been removed or someone has already successfully * bound a driver before us just skip the driver probe call. */ if (!dev->p->dead && !dev->driver) ret = driver_probe_device(drv, dev);
__device_driver_unlock(dev, dev->parent);
return ret; }
/** * driver_probe_device - attempt to bind device & driver together * @drv: driver to bind a device to * @dev: device to try to bind to the driver * * This function returns -ENODEV if the device is not registered, * 1 if the device is bound successfully and 0 otherwise. * * This function must be called with @dev lock held. When called for a * USB interface, @dev->parent lock must be held as well. * * If the device has a parent, runtime-resume the parent before driver probing. */ intdriver_probe_device(struct device_driver *drv, struct device *dev) { int ret = 0;
if (!device_is_registered(dev))// 检查设备是否已注册,如果未注册则返回错误码 -ENODEV 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_get_suppliers(dev); if (dev->parent)// 如果设备有父设备,获取父设备的同步运行时引用计数 pm_runtime_get_sync(dev->parent);
pm_runtime_barrier(dev);// 等待设备的运行时状态达到稳定 if (initcall_debug)// 根据初始化调试标志选择调用真实的探测函数 ret = really_probe_debug(dev, drv); else ret = really_probe(dev, drv); pm_request_idle(dev);// 请求设备进入空闲状态(省电模式)
if (dev->parent)// 如果设备有父设备,释放父设备的运行时引用计数 pm_runtime_put(dev->parent);
// drivers/base/dd.c staticintreally_probe(struct device *dev, struct device_driver *drv) { int ret = -EPROBE_DEFER;// 初始化返回值为延迟探测 int local_trigger_count = atomic_read(&deferred_trigger_count);// 获取当前延迟探测计数 bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) && !drv->suppress_bind_attrs;
if (defer_all_probes) { /* * Value of defer_all_probes can be set only by * device_block_probing() which, in turn, will call * wait_for_device_probe() right after that to avoid any races. */ dev_dbg(dev, "Driver %s force probe deferral\n", drv->name); driver_deferred_probe_add(dev); return ret; }
ret = device_links_check_suppliers(dev);// 检查设备的供应者链路 if (ret == -EPROBE_DEFER) driver_deferred_probe_add_trigger(dev, local_trigger_count);// 将设备添加到延迟探测触发列表 if (ret) return ret;
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)); if (!list_empty(&dev->devres_head)) { dev_crit(dev, "Resources present before probing\n"); ret = -EBUSY; goto done; }
re_probe: dev->driver = drv;
/* If using pinctrl, bind pins now before probing */ ret = pinctrl_bind_pins(dev);/* 如果使用了 pinctrl,绑定引脚 */ if (ret) goto pinctrl_bind_failed;
if (dev->bus->dma_configure) {// 配置 DMA ret = dev->bus->dma_configure(dev); if (ret) goto probe_failed; }
ret = driver_sysfs_add(dev);// 添加驱动的 sysfs if (ret) { pr_err("%s: driver_sysfs_add(%s) failed\n", __func__, dev_name(dev)); goto probe_failed; }
if (dev->pm_domain && dev->pm_domain->activate) {// 如果设备有电源管理域并且存在激活函数,激活电源管理域 ret = dev->pm_domain->activate(dev); if (ret) goto probe_failed; }
if (dev->bus->probe) {// 如果总线有探测函数,调用总线的探测函数 ret = dev->bus->probe(dev); if (ret) goto probe_failed; } elseif (drv->probe) {// 否则调用驱动的探测函数 ret = drv->probe(dev); if (ret) goto probe_failed; }
ret = device_add_groups(dev, drv->dev_groups); if (ret) { dev_err(dev, "device_add_groups() failed\n"); goto dev_groups_failed; }
if (dev_has_sync_state(dev)) { ret = device_create_file(dev, &dev_attr_state_synced); if (ret) { dev_err(dev, "state_synced sysfs add failed\n"); goto dev_sysfs_state_synced_failed; } }
if (test_remove) {// 如果启用了驱动移除测试 test_remove = false;
// drivers/base/bus.c /** * bus_probe_device - probe drivers for a new device * @dev: device to probe * * - Automatically probe for a driver if the bus allows it. */ voidbus_probe_device(struct device *dev) { structbus_type *bus = dev->bus; structsubsys_interface *sif;
if (!bus) return;
if (bus->p->drivers_autoprobe) device_initial_probe(dev);
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 staticint __device_attach(struct device *dev, bool allow_async) { int ret = 0; bool async = false;
device_lock(dev); if (dev->p->dead) { goto out_unlock; } elseif (dev->driver) { if (device_is_bound(dev)) {// 如果设备已经绑定了驱动程序,则返回 1 ret = 1; goto out_unlock; } ret = device_bind_driver(dev);// 尝试将设备与驱动程序进行绑定 if (ret == 0) ret = 1; else { dev->driver = NULL;// 绑定失败,将设备的驱动程序指针置为 NULL ret = 0; } } else { struct device_attach_data data = {// 如果设备没有驱动程序,需要遍历总线上的驱动程序进行匹配 .dev = dev, .check_async = allow_async, .want_async = false, };
if (dev->parent)// 如果设备有父设备,调用 pm_runtime_get_sync() 增加父设备的引用计数 pm_runtime_get_sync(dev->parent); // 遍历总线上的驱动程序,调用 __device_attach_driver() 进行匹配 ret = bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); if (!ret && allow_async && data.have_async) { /* * If we could not find appropriate driver * synchronously and we are allowed to do * async probes and there are drivers that * want to probe asynchronously, we'll * try them. */ /* * 如果无法同步找到适合的驱动程序,并且允许异步探测以及有驱动程序要求异步探测, * 则尝试进行异步探测。 */ dev_dbg(dev, "scheduling asynchronous probe\n"); get_device(dev);// 增加设备的引用计数,以确保在异步探测期间设备不会被释放 async = true; } else { pm_request_idle(dev);// 如果无法异步探测或者没有驱动程序要求异步探测,则调用 pm_request_idle() 进入空闲状态 }
if (dev->parent)// 如果设备有父设备,调用 pm_runtime_put() 减少父设备的引用计数 pm_runtime_put(dev->parent); } out_unlock: device_unlock(dev); if (async) async_schedule_dev(__device_attach_async_helper, dev);// 调度异步任务 __device_attach_async_helper() 进行异步探测 return ret; }
// drivers/base/dd.c /** * device_bind_driver - bind a driver to one device. * @dev: device. * * Allow manual attachment of a driver to a device. * Caller must have already set @dev->driver. * * Note that this does not modify the bus reference count. * Please verify that is accounted for before calling this. * (It is ok to call with no other effort from a driver's probe() method.) * * This function must be called with the device lock held. */ intdevice_bind_driver(struct device *dev) { int ret;
ret = driver_sysfs_add(dev); if (!ret) driver_bound(dev); elseif (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DRIVER_NOT_BOUND, dev); return ret; } EXPORT_SYMBOL_GPL(device_bind_driver);
/* * Make sure the device is no longer in one of the deferred lists and * kick off retrying all pending devices */ /* * 确保设备不再位于延迟探测列表中,并启动重试所有待处理设备 */ driver_deferred_probe_del(dev); driver_deferred_probe_trigger(); // 如果设备有总线,调用总线通知链进行通知 if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev); // 发送内核对象事件通知 kobject_uevent(&dev->kobj, KOBJ_BIND); }