阅读Linux设备驱动模型源码之 device结构体成员详解

时间:2021-12-19 20:54:56

【前言】

        我们学习 Linux 设备驱动,很多人在一开始往往急于想找到快速入门的方法,希望能有一个提纲挈领的使用说明来帮助我们快速理解 Linux 设备驱动的设计思路和框架,从而摆脱掉 Linux 内核这头庞然怪兽。我自己最初也是这样。然而事与愿违,如果学习 Linux 设备驱动能有这样的捷径让大多数人快速掌握,那么具备开发 Linux 设备驱动的能力也就变得不再值钱了。所以,学习 Linux 设备驱动的正道还是丢掉世俗的浮躁、静下心来好好阅读内核源码。正如 Linus Torvalds 的神谕那样,“Read the fucking source code”。我想,这也是做好其它事情的不二法门。

        在这种想法的指引下,在前一阵子对 platform 驱动模型、i2c 驱动模型、ASoC 驱动模型、kobject+kset+ktype 有了大体认识之后,我再次开始阅读内核中的设备驱动框架代码。说实话,代码中的注释有的时候比我们在书上或网上看到的讲解更加清晰直观。我把 device 结构体的官方注释翻译成了中文写在下面。


【device结构体成员详解】

/**
* device 结构体 - 设备驱动模型中的基础结构体之一
* @parent:设备所依附的“父设备”。
* 大多数情况下,这样的父设备是某种总线或主控制器。
* 如果该成员变量的值为 NULL 表示当前设备是一个最“顶端”设备,
* 通常这样的设备都不是你想得到的那个。
* @p:该成员变量是一个指向设备结构体中驱动内核部分的私有数据的指针。
* 更详细的信息可以阅读 device_private 结构体的注释。
* @kobj:kobj是最“顶层”的抽象类,所有其它的类都继承自它。
* @init_name:设备结构体所对应的设备的名称。
* @type:设备结构体所对应的设备的类型。
* 该成员变量用于标识设备类型,并存储着该类型设备特有的信息。
* @mutex:用于同步驱动中的函数调用的互斥锁。
* @bus:设备所挂接的总线的类型。
* @driver:该成员变量指向开辟当前设备结构体空间的设备驱动。
* @platform_data: 该成员变量用于保存和设备硬件相关的平台数据。
* 示例:对于自定义电路板上的设备来说,典型的情况譬如嵌入式设备
* 以及一些基于 SOC 的硬件,Linux 系统通常会使用 platform_data 指针指向
* 与电路板硬件相关的结构体,这些结构体中的成员描述了它们对应的设备硬件资源
* 以及电路板的电路连接情况。这些被描述的内容可以包括芯片的哪些端口可用,与
* 上一代芯片相比有什么改动,哪个 GPIO 引脚有额外的功能等等。
* 这个成员变量的实现使得 BSP 的工作量减小了许多,
* 同时也减少了我们为兼容不同的电路板而写的 #ifdefs 语句的数量。
* @driver_data: 指向驱动特定信息的私有指针。
* @power:用于设备的电源管理。
* 更详细的信息可以阅读 Documentation/power/devices.txt 文档。
* @pm_domain:为设备提供当系统被挂起、
* 休眠、唤醒和电源状态切换时的回调函数,
* 以及子系统级别和驱动级别的回调函数。
* @pins:用于设备引脚管理。
*更详细的信息可以阅读 Documentation/pinctrl.txt 文档。
* @msi_list:主机 MSI 描述符。
* @msi_domain: 设备结构体所使用的 MSI 域。
* @numa_node:与设备结构体最邻近的 NUMA 节点。
* @dma_mask:DMA掩码(前提是当前设备可进行 DMA 操作)。
* @coherent_dma_mask: 作用和 dma_mask 类似,用于一致性 DMA 地址映射。因为并不是所有
* 硬件都支持在 64 位地址下开辟连续的内存空间。
* @dma_pfn_offset: DMA区域范围在内存中的地址偏移量。
* @dma_parms:一个低权限级别的驱动会通过这个成员变量告知 IOMMU 代码关于
* 段操作限制相关的规则。
* @dma_pools:指向 DMA池 的指针(前提是当前设备可进行 DMA 操作)。
* @dma_mem:一致性 DMA 的可读写区域。
* @cma_area:DMA区域中的连续内存空间。
* @archdata:芯片架构相关的内容。
* @of_node:设备所在设备树的节点。
* @fwnode:平台固件对应的设备树节点。
* @devt:用于在 sysfs 中创建设备文件。
* @id:设备实例(ID 编号)。
* @devres_lock: 用于保护设备上的资源访问的自旋锁。
* @devres_head: 设备上的资源列表。
* @knode_class: 用于将当前设备加入到类列表的节点。
* @class:设备所属的类。
* @groups:设备的属性集合(可选)。
* @release:当设备的引用计数减少为 0 时,使用该成员变量所指向的析构函数
* 释放当前设备结构体。这个成员变量的值应该由当前设备的创建者进行
* 设置(比如成功找到设备的总线驱动)。
* @iommu_group: 设备所属的 IOMMU 集合。
*
* @offline_disabled: 如果这个成员变量的值被置 1,则设备将处于永远在线状态。
* @offline:如果总线类型所辖的 offline() 函数被成功调用,则该成员变量的值将被置 1。
*
* 在最底层级别,Linux系统中的每个设备都被一个 device 结构体的
* 实例所表示。device 结构体中包含了设备模型内核在描述系统结构时
* 所需要的信息。大多数子系统在此基础上还会查找它们下属设备的额外信息。
* 这导致我们很难用少数 device 结构体来表示设备的所有信息,所以通常
* 还会配合 kobject 结构体来描述设备的更高层信息。
*/
struct device {
struct device*parent;

struct device_private*p;

struct kobject kobj;
const char*init_name; /* 设备的初始化名称 */
const struct device_type *type;

struct mutexmutex;/* mutex to synchronize calls to
* its driver.
*/

struct bus_type*bus;/* type of bus device is on */
struct device_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/get_drvdata */
struct dev_pm_infopower;
struct dev_pm_domain*pm_domain;

#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
struct irq_domain*msi_domain;
#endif
#ifdef CONFIG_PINCTRL
struct dev_pin_info*pins;
#endif
#ifdef CONFIG_GENERIC_MSI_IRQ
struct list_headmsi_list;
#endif

#ifdef CONFIG_NUMA
intnuma_node;/* NUMA node this device is close to */
#endif
u64*dma_mask;/* dma mask (if dma'able device) */
u64coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
unsigned longdma_pfn_offset;

struct device_dma_parameters *dma_parms;

struct list_headdma_pools;/* dma pools (if dma'ble) */

struct dma_coherent_mem*dma_mem; /* internal for coherent mem
override */
#ifdef CONFIG_DMA_CMA
struct cma *cma_area;/* contiguous memory area for dma
allocations */
#endif
/* arch specific additions */
struct dev_archdataarchdata;

struct device_node*of_node; /* associated device tree node */
struct fwnode_handle*fwnode; /* firmware device node */

dev_tdevt;/* dev_t, creates the sysfs "dev" */
u32id;/* device instance */

spinlock_tdevres_lock;
struct list_headdevres_head;

struct klist_nodeknode_class;
struct class*class;
const struct attribute_group **groups;/* optional groups */

void(*release)(struct device *dev);
struct iommu_group*iommu_group;

booloffline_disabled:1;
booloffline:1;
};