rfkill - RF 射频关闭开关支持¶
介绍¶
rfkill 子系统提供了一个通用接口,用于禁用系统中的任何无线电发射器。当发射器被阻止时,它不应辐射任何功率。
该子系统还提供响应按钮按下事件并禁用特定类型(或所有类型)的发射器的能力。这适用于需要关闭发射器的情况,例如在飞机上。
rfkill 子系统具有“硬”和“软”阻止的概念,它们在含义上几乎没有区别(阻止 == 关闭发射器),而是在于它们是否可以更改。
- 硬阻止
只读无线电阻止,无法被软件覆盖
- 软阻止
可写无线电阻止(不必是可读的),由系统软件设置。
rfkill 子系统有两个参数,rfkill.default_state 和 rfkill.master_switch_mode,它们在 admin-guide/kernel-parameters.rst 中有文档说明。
实现细节¶
rfkill 子系统由三个主要组件组成
rfkill 核心,
已弃用的 rfkill-input 模块(一个输入层处理程序,正在被用户空间策略代码取代)和
rfkill 驱动。
rfkill 核心为内核驱动程序提供 API,以便向内核注册其无线电发射器,提供打开和关闭它的方法,并让系统知道设备上可能实现的硬件禁用状态。
rfkill 核心代码还会通知用户空间状态变化,并提供用户空间查询当前状态的方法。请参阅下面的“用户空间支持”部分。
当设备被硬阻止(通过调用 rfkill_set_hw_state() 或来自 query_hw_block)时,将调用 set_block() 进行额外的软件阻止,但驱动程序可以忽略该方法调用,因为它们可以使用函数 rfkill_set_hw_state() 的返回值来同步软件状态,而不是跟踪对 set_block() 的调用。事实上,除非硬件实际上分别跟踪软阻止和硬阻止,否则驱动程序应该使用 rfkill_set_hw_state() 的返回值。
内核 API¶
无线电发射器的驱动程序通常实现一个 rfkill 驱动程序。
如果 rfkill 按钮只是一个按钮,平台驱动程序可能会实现输入设备。如果该按钮影响硬件,那么您需要实现一个 rfkill 驱动程序。如果平台提供打开/关闭发射器的方式,这也适用。
对于某些平台,硬件状态可能会在挂起/休眠期间发生变化,在这种情况下,需要在恢复时使用当前状态更新 rfkill 核心。
要创建 rfkill 驱动程序,驱动程序的 Kconfig 需要有
depends on RFKILL || !RFKILL
以确保当 rfkill 是模块化时,驱动程序不能被内置。 !RFKILL 允许在未配置 rfkill 时构建驱动程序,在这种情况下,仍然可以使用所有 rfkill API,但将由静态内联提供,这些内联编译后几乎什么也没有。
从控制可以被硬阻止的设备的 rfkill 驱动程序需要调用 rfkill_set_hw_state(),当状态发生改变时,除非它们也分配了 poll_hw_block() 回调(然后 rfkill 核心将轮询设备)。除非您无法以任何其他方式获取事件,否则不要这样做。
rfkill 提供每个开关的 LED 触发器,可用于根据开关状态驱动 LED(阻止时 LED_FULL,否则 LED_OFF)。
用户空间支持¶
推荐使用的用户空间接口是 /dev/rfkill,这是一个杂项字符设备,允许用户空间获取和设置 rfkill 设备和设备集的状态。它还会通知用户空间有关设备的添加和删除。该 API 是一个简单的读/写 API,在 linux/rfkill.h 中定义,带有一个 ioctl,允许关闭内核中已弃用的输入处理程序以进行过渡。
除了一个 ioctl 之外,与内核的通信是通过读取和写入“struct rfkill_event”的实例来完成的。在此结构中,软阻止和硬阻止被正确分离(与 sysfs 不同,请参见下文),用户空间能够获得系统中所有 rfkill 设备的一致快照。此外,可以将所有 rfkill 驱动程序(或指定类型的所有驱动程序)切换到一种状态,该状态还会更新热插拔设备的默认状态。
应用程序打开 /dev/rfkill 后,它可以读取所有设备的当前状态。可以通过轮询热插拔或状态更改事件的描述符,或者通过侦听 rfkill 核心框架发出的 uevent 来获取更改。
此外,每个 rfkill 设备都在 sysfs 中注册并发出 uevent。
rfkill 设备发出 uevent(操作为“change”),并设置以下环境变量
RFKILL_NAME
RFKILL_STATE
RFKILL_TYPE
这些变量的内容对应于上面解释的“name”、“state”和“type” sysfs 文件。
有关更多详细信息,请参阅 ABI file stable/sysfs-class-rfkill。