首页 > 编程语言 >设备驱动程序 【ChatGPT】

设备驱动程序 【ChatGPT】

时间:2023-12-10 13:22:41浏览次数:55  
标签:struct 总线 driver device ChatGPT 设备 驱动程序

设备驱动程序

请参阅结构体device_driver的kerneldoc。

分配

设备驱动程序是静态分配的结构。尽管系统中可能有多个驱动程序支持的设备,但struct device_driver代表了整个驱动程序(而不是特定的设备实例)。

初始化

驱动程序必须至少初始化名称和总线字段。当它到达时,它还应该初始化devclass字段,以便在内部获得适当的链接。它还应该尽可能初始化尽可能多的回调,尽管每个都是可选的。

声明

如上所述,struct device_driver对象是静态分配的。以下是eepro100驱动程序的声明示例。此声明仅是假设的;它依赖于驱动程序完全转换为新模型:

static struct device_driver eepro100_driver = {
       .name          = "eepro100",
       .bus           = &pci_bus_type,

       .probe         = eepro100_probe,
       .remove                = eepro100_remove,
       .suspend               = eepro100_suspend,
       .resume                = eepro100_resume,
};

大多数驱动程序将无法完全转换为新模型,因为它们所属的总线具有特定于总线的结构和特定于总线的字段,无法泛化。

其中最常见的例子是设备ID结构。驱动程序通常定义其支持的设备ID数组。这些结构的格式和比较设备ID的语义完全是特定于总线的。将它们定义为特定于总线的实体将牺牲类型安全性,因此我们保留特定于总线的结构。

特定于总线的驱动程序应在总线特定驱动程序的定义中包含一个通用的struct device_driver。如下所示:

struct pci_driver {
       const struct pci_device_id *id_table;
       struct device_driver     driver;
};

包含特定于总线字段的定义将如下所示(再次使用eepro100驱动程序):

static struct pci_driver eepro100_driver = {
       .id_table       = eepro100_pci_tbl,
       .driver               = {
              .name           = "eepro100",
              .bus            = &pci_bus_type,
              .probe          = eepro100_probe,
              .remove         = eepro100_remove,
              .suspend        = eepro100_suspend,
              .resume         = eepro100_resume,
       },
};

有些人可能会觉得嵌套结构初始化的语法很奇怪甚至有点丑陋。到目前为止,这是我们找到的做我们想做的事情的最佳方式...

注册

int driver_register(struct device_driver *drv);

驱动程序在启动时注册结构。对于没有特定于总线字段的驱动程序(即没有特定于总线的驱动程序结构),它们将使用driver_register并传递指向其struct device_driver对象的指针。

然而,大多数驱动程序将具有特定于总线的结构,并且将需要使用诸如pci_driver_register之类的内容向总线注册。

驱动程序注册其驱动程序结构尽可能早是很重要的。与核心的注册初始化struct device_driver对象中的几个字段,包括引用计数和锁。这些字段被假定始终有效,并且可能被设备模型核心或总线驱动程序使用。

过渡总线驱动程序

通过定义包装函数,可以更轻松地过渡到新模型。驱动程序可以完全忽略通用结构,并让总线包装器填充字段。对于回调,总线可以定义通用回调,将调用转发到驱动程序的特定于总线的回调。

此解决方案仅供临时使用。为了在驱动程序中获取类信息,驱动程序必须进行修改。由于将驱动程序转换为新模型应该减少一些基础设施复杂性和代码大小,建议在添加类信息时将其转换。

访问

一旦对象已注册,它可以访问对象的公共字段,如锁和设备列表:

int driver_for_each_dev(struct device_driver *drv, void *data,
                        int (*callback)(struct device *dev, void *data));

devices字段是所有已绑定到驱动程序的设备的列表。LDM核心提供了一个辅助函数,用于操作驱动程序控制的所有设备。此辅助函数在每次访问节点时锁定驱动程序,并对每个访问的设备进行适当的引用计数。

sysfs

当驱动程序注册时,在其总线目录中创建了一个sysfs目录。在此目录中,驱动程序可以导出一个接口到用户空间,以全局控制驱动程序的操作;例如,在驱动程序中切换调试输出。

此目录的一个未来特性将是一个“设备”目录。此目录将包含指向其支持的设备目录的符号链接。

回调

int     (*probe)        (struct device *dev);

probe()条目在任务上下文中调用,总线的rwsem被锁定,并且驱动程序部分绑定到设备。驱动程序通常在probe()和其他例程中使用container_of()将“dev”转换为特定于总线的类型。该类型通常提供设备资源数据,例如pci_dev.resource[]或platform_device.resources,除了dev->platform_data之外,这些数据用于初始化驱动程序。

此回调包含了特定于驱动程序的逻辑,以将驱动程序绑定到给定设备。这包括验证设备是否存在,驱动程序是否能处理设备的版本,是否可以分配和初始化驱动程序数据结构,以及是否可以初始化任何硬件。驱动程序通常使用dev_set_drvdata()将其状态的指针存储。当驱动程序成功将自身绑定到该设备时,probe()将返回零,并且驱动程序模型代码将完成其绑定到该设备的部分。

驱动程序的probe()可以返回负的errno值,以指示驱动程序未绑定到此设备,在这种情况下,它应该释放分配给该设备的所有资源。

可选地,probe()可以返回-EPROBE_DEFER,如果驱动程序依赖尚未可用的资源(例如,由尚未初始化的驱动程序提供)。驱动程序核心将把设备放到延迟探测列表中,并稍后尝试再次调用它。如果驱动程序必须推迟,它应尽早返回-EPROBE_DEFER,以减少在需要在稍后的时间撤消和重新执行的设置工作上花费的时间。

警告
如果在创建子设备后返回-EPROBE_DEFER,即使在清理路径中再次删除这些子设备,也不得返回-EPROBE_DEFER,否则可能导致对同一驱动程序的.probe()调用的无限循环。

void    (*sync_state)   (struct device *dev);

sync_state仅对设备调用一次。当设备的所有使用设备成功探测时,它被调用。通过查看连接该设备与其使用设备的设备链接,可以获得该设备的使用设备的列表。

在late_initcall_sync()期间首次尝试调用sync_state(),以便为固件和驱动程序提供时间将设备链接到彼此。在首次尝试调用sync_state()期间,如果在那时点上的设备的所有使用设备已经成功探测,那么sync_state()将立即被调用。如果在首次尝试期间没有设备的使用设备,那也被视为“设备的所有使用设备已经探测成功”,并且sync_state()将立即被调用。

如果在首次尝试调用sync_state()期间,仍有尚未成功探测的使用设备,那么sync_state()调用将被推迟,并且仅在将来当一个或多个使用设备成功探测时才会重新尝试。如果在重新尝试期间,驱动程序核心发现设备的一个或多个使用设备尚未成功探测,那么sync_state()调用将再次被推迟。

sync_state()的典型用例是使内核干净地接管设备的管理权,例如,如果设备由引导加载程序保持在特定的硬件配置和状态,设备的驱动程序可能需要保持设备在引导配置中,直到设备的所有使用设备都已探测。一旦设备的所有使用设备都已探测,设备的驱动程序可以将设备的硬件状态同步到与所有使用设备请求的聚合软件状态匹配。因此,名称为sync_state()。

虽然sync_state()的明显资源示例包括诸如调节器之类的资源,但sync_state()也可以用于复杂资源,如IOMMU。例如,具有多个使用设备(其地址由IOMMU重新映射的设备)的IOMMU可能需要保持其映射固定在(或者增加到)引导配置,直到其所有使用设备已探测。

虽然sync_state()的典型用例是使内核干净地接管设备的管理权,但sync_state()的使用并不限于此。只要在所有设备的使用设备探测后执行操作有意义,就可以使用它:

int     (*remove)       (struct device *dev);

调用remove以从设备中解绑驱动程序。如果设备从系统中物理移除,如果驱动程序模块正在卸载,在重新启动序列期间或其他情况下,可能会调用此函数。

由驱动程序确定设备是否存在。它应该释放专门为设备分配的任何资源;即设备的driver_data字段中的任何内容。

如果设备仍然存在,它应该使设备静止,并将其置于支持的低功耗状态。

int     (*suspend)      (struct device *dev, pm_message_t state);

调用suspend以将设备置于低功耗状态。

int     (*resume)       (struct device *dev);

Resume用于从低功耗状态唤醒设备。

属性

struct driver_attribute {
        struct attribute        attr;
        ssize_t (*show)(struct device_driver *driver, char *buf);
        ssize_t (*store)(struct device_driver *, const char *buf, size_t count);
};

设备驱动程序可以通过其sysfs目录导出属性。驱动程序可以使用DRIVER_ATTR_RW和DRIVER_ATTR_RO宏声明属性,该宏的工作方式与DEVICE_ATTR_RW和DEVICE_ATTR_RO宏完全相同。

例如:

DRIVER_ATTR_RW(debug);

这相当于声明:

struct driver_attribute driver_attr_debug;

然后可以使用以下内容将属性添加到驱动程序目录中并从中删除:

int driver_create_file(struct device_driver *, const struct driver_attribute *);
void driver_remove_file(struct device_driver *, const struct driver_attribute *);

标签:struct,总线,driver,device,ChatGPT,设备,驱动程序
From: https://www.cnblogs.com/pengdonglin137/p/17892543.html

相关文章

  • 总线类型 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/driver-api/driver-model/bus.html总线类型定义请参阅结构体bus_type的内核文档。intbus_register(structbus_type*bus);声明内核中的每个总线类型(如PCI、USB等)应该声明一个此类型的静态对象。它们必须初始化name字段,并可以选......
  • 设备驱动设计模式 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/driver-api/driver-model/design-patterns.html设备驱动设计模式这份文档描述了设备驱动中常见的设计模式。子系统维护者可能会要求驱动开发者遵循这些设计模式。状态容器container_of()1.状态容器虽然内核中包含一些设备驱动,假......
  • 设备基本结构 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/driver-api/driver-model/device.html设备基本结构请参阅内核文档以了解structdevice的结构。编程接口发现设备的总线驱动程序使用以下方法将设备注册到核心:intdevice_register(structdevice*dev);总线应该初始化以下字段:p......
  • Devres - 管理设备资源 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/driver-api/driver-model/devres.htmlDevres-管理设备资源[email protected]首稿日期:2007年1月10日1.简介在尝试将libata转换为使用iomap时,出现了devres。每个iomapped地址应该在驱动程序分离时保留和取消映射。例如,一个普......
  • 驱动绑定 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/driver-api/driver-model/binding.html驱动绑定驱动绑定是将设备与能够控制它的设备驱动程序关联起来的过程。通常由总线驱动程序处理这一过程,因为总线特定的结构用于表示设备和驱动程序。使用通用设备和设备驱动程序结构后,大部分绑定可......
  • 硬件自旋锁框架 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/hwspinlock.html硬件自旋锁框架简介硬件自旋锁模块为异构处理器和不在单一共享操作系统下运行的处理器之间的同步和互斥提供硬件辅助。例如,OMAP4具有双核Cortex-A9、双核Cortex-M3和一个C64x+DSP,每个处理器运行不同的操作系......
  • 驱动模型 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/driver-api/driver-model/index.htmlDriverModel(驱动程序模型)DriverBinding(驱动绑定)BusTypes(总线类型)DeviceDriverDesignPatterns(设备驱动程序设计模式)TheBasicDeviceStructure(基本设备结构)Devres-ManagedDeviceResou......
  • percpu 读写信号量 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/percpu-rw-semaphore.html"Percpurwsemaphores"是一种新的读写信号量设计,针对读取操作进行了优化。传统的读写信号量存在一个问题,即当多个核心获取读取锁时,包含信号量的缓存行在各个核心的L1缓存之间反复传输,导致性能下降......
  • 保持内核代码的可抢占安全 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/preempt-locking.html在可抢占内核下的适当锁定:保持内核代码的可抢占安全作者[email protected]介绍可抢占内核会引发新的锁定问题。这些问题与SMP下的问题相同:并发性和可重入性。幸运的是,Linux可抢占内核模型利......
  • 序列计数器和顺序锁 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/seqlock.html#序列计数器和顺序锁介绍序列计数器是一种具有无锁读取器(只读重试循环)和无写入者饥饿的读者-写者一致性机制。它们用于很少写入数据的情况(例如系统时间),其中读者希望获得一致的信息集,并且愿意在信息发生变化时重试......