----------------------------------------------------------------------------------------------------------------------------
开发板 :NanoPC-T4开发板eMMC :16GBLPDDR3 :4GB显示屏 :15.6英寸HDMI接口显示屏u-boot :uboot 2023.04linux :5.2.8 ----------------------------------------------------------------------------------------------------------------------------
本篇博客是以linux 5.2.8版本源码进行讲解的,与linux 6.3源码略有细微差别,但是整体上大致是一样的。
一、rfkill子系统
1.1 rfkill概述
rfkill是Linux内核提供的一个框架,用于控制无线通信硬件(如 WiFi、蓝牙、NFC 等)的开关和状态。rfkill就是RF(射频) 设备的开关,有类似一键关闭所有射频外设的功能。
rfkill的出现方便管理各种RF芯片的开关, 目前已经很多厂商的设备使用的是rfkill的驱动来管理一些无线设备的电源了,都是和RF相关的芯片,比如WiFi,蓝牙, NFC, FM,,GPS等等。
由于这个rfkill的功能是管理无线设备的电源开关,所以这和硬件的关联是直接的,一般都会涉及到硬件的power或reset引脚。
rfkill子系统有"hard"和"soft" blocked的概念,blocked的意思就是发射器关闭;
- soft blocked ::表示软件层面对无线设备进行的阻止(比如说,通过运行rfkill激活命令)。在这种情况下,无线电器的硬件电源依旧是打开的,只是被软件控制给关掉了;
- hard blocked:表示硬件层面对无线设备进行的阻止,通常是由于硬件按键或者物理开关进行的关闭。在这种情况下,即使在操作系统层面执行启动命令,也无法使无线电器工作;
区别在于软/硬件控制的不同。soft blocked是软件层面的禁用,硬件还是打开的,可以通过命令解除禁用;而hard blocked是硬件层面的禁用,无论从软件还是命令层面都无法解除。
当无线设备处于hard blocked状态时,意味着无法通过软件命令或驱动程序打开该设备;相反,必须在硬件层面解除阻塞才能使设备重新工作。这通常需要找到控制设备硬件的开关或按键,并在上面进行操作。
1.2 rfkill子系统框架
rfkill子系统主要三个部分组成:
- rfkill core;为驱动程序提供了API,让驱动程序可向内核注册无线电发射器设备,以及打开和关闭内核的方法,,这样系统就知道怎么禁用设备硬件,rfkill core还向用户空间通知状态更改,并为用户空间提供查询当前状态的方法。 linux下提供了rfkill工具,用于开启和关闭无线设备功能;
- rfkill input模块: 输入层处理程序,不推荐使用的,已由用户空间策略代码代替;
- rfkill驱动程序:需要实现不同芯片的rkfill驱动程序;比如我们需要提供AP6356的rfkill驱动程序,实现AP6356设备的开启和关闭;
我们要做的一般是调试厂商已经做好的rfkill驱动,或者我们自己实现API的接口,这个并不难,其实最终就是操作GPIO引脚。
1.2.1 rfkill命令查看无线设备
在linux系统下可以通过rfkill工具查看无线设备的功能:
root@rk3399:/lib/modules# rfkill list
0: bt_default: Bluetooth
Soft blocked: yes
Hard blocked: no
1: phy0: Wireless LAN
Soft blocked: no
Hard blocked: no
root@rk3399:/lib/modules# rfkill
ID TYPE DEVICE SOFT HARD
0 bluetooth bt_default blocked unblocked
1 wlan phy0 unblocked unblocked
这里看到有两个无线设备,一个是蓝牙的,另一个WiFi的,蓝牙设备默认是禁用的。
1.2.2 开启关闭无线设备
我们可以通过执行如下命令开启蓝牙设备;
root@rk3399:/lib/modules# rfkill unblock 0
root@rk3399:/lib/modules# rfkill list
0: bt_default: Bluetooth
Soft blocked: no
Hard blocked: no
1: phy0: Wireless LAN
Soft blocked: no
Hard blocked: no
同样我们可以通过命令关闭WiFi设备,可以看到当关闭WiFi设备后,就无法通过ifconfig看到设备了;
root@rk3399:/lib/modules# rfkill block 1
root@rk3399:/lib/modules# rfkill list
0: bt_default: Bluetooth
Soft blocked: no
Hard blocked: no
1: phy0: Wireless LAN
Soft blocked: yes
Hard blocked: no
root@rk3399:/lib/modules# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.101 netmask 255.255.255.0 broadcast 192.168.0.255
ether 92:a7:05:0f:19:86 txqueuelen 1000 (Ethernet)
RX packets 719 bytes 677554 (677.5 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 438 bytes 36520 (36.5 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 24
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 195 bytes 15221 (15.2 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 195 bytes 15221 (15.2 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
此时我们通过ifconfig wlan0 up命令是无法启用WiFi的;
root@rk3399:/lib/modules# ifconfig wlan0 up
SIOCSIFFLAGS: Operation not possible due to RF-kill
1.3 目录结构
linux内核将rfkill子系统相关的代码位于内核net/rfkill目录下,rfkill驱动编程的API接口定义在include/linux/rfkill.h。
root@zhengyang:/work/sambashare/rk399/linux-5.2.8# ll net/rfkill
总用量 68
drwxr-xr-x 2 root root 4096 May 17 01:26 ./
drwxr-xr-x 70 root root 4096 May 17 01:26 ../
-rw-r--r-- 1 root root 31583 May 17 01:26 core.c
-rw-r--r-- 1 root root 8813 May 17 01:26 input.c
-rw-r--r-- 1 root root 814 May 17 01:26 Kconfig
-rw-r--r-- 1 root root 224 May 17 01:26 Makefile
-rw-r--r-- 1 root root 4078 May 17 01:26 rfkill-gpio.c
-rw-r--r-- 1 root root 590 May 17 01:26 rfkill.h
二、rfkill核心数据结构
学习rfkill驱动,首先要了解驱动框架涉及到的数据结构,知道每个数据结构以及成员的含义之后,再去看源码就容易了。
2.1 struct rfkill
内核使用struct rfkill数据结构来描述rfklill设备,包括rfkill设备的操作接口和状态描述等信息,定义在net/rfkill/core.c文件中:
struct rfkill{
spinlock_t lock;
enum rfkill_type type;
unsigned long state;
u32 idx;
bool registered;
bool persistent;
bool polling_paused;
bool suspended;
const struct rfkill_ops *ops;
void *data;
#ifdef CONFIG_RFKILL_LEDS
struct led_trigger led_trigger;
const char *ledtrigname;
#endif
struct device dev;
struct list_head node;
struct delayed_work poll_work;
struct work_struct uevent_work;
struct work_struct sync_work;
char name[];
};
其中:
- lock:自旋锁,用于保护rfkill结构体的访问。
- type:枚举类型,表示rfkill开关类型(例如 WiFi、蓝牙、NFC 等);
- state:无符号长整型,表示rfkill设备的状态,具体的取值与 type 相关;
- idx:无符号整型,表示rfkill设备在系统中的索引;
- registered:布尔类型,表示rfkill设备是否已经注册到系统中;
- persistent:布尔类型,表示rfkill设备是否具有持久化属性;
- polling_paused:布尔类型,表示rfkill设备是否处于轮询暂停状态;
- suspended:布尔类型,表示rfkill设备是否处于挂起状态;
- ops:指向一个 rfkill_ops 结构体的指针,表示rfkill设备的操作接口;
- data:指向一个 void 类型的指针,可以用来存储任何用户自定义的数据;
- led_trigger:一个 led_trigger 结构体,表示与rfkill设备相关联的灯;
- ledtrigname:表示与rfkill设备相关联的灯的名称;
- dev:一个 device 结构体,表示rfkill设备对应的device;
- node:一个list_head结构体,用于将rfkill设备添加到全局双向链表rfkill_list中;
- poll_work:一个delayed_work结构体,用于轮询rfkill设备状态的工作队列;
- uevent_work:一个 work_struct 结构体,用于处理rfkill设备状态变化的uevent事件;
- sync_work:一个work_struct结构体,用于同步rfkill设备的状态;
2.2 enum rfkill_type
enum rfkill_type用于表示rfkill开关类型,定义在include/uapi/linux/rfkill.h:
/**
* enum rfkill_type - type of rfkill switch.
*
* @RFKILL_TYPE_ALL: toggles all switches (requests only - not a switch type)
* @RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device.
* @RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device.
* @RFKILL_TYPE_UWB: switch is on a ultra wideband device.
* @RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
* @RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
* @RFKILL_TYPE_GPS: switch is on a GPS device.
* @RFKILL_TYPE_FM: switch is on a FM radio device.
* @RFKILL_TYPE_NFC: switch is on an NFC device.
* @NUM_RFKILL_TYPES: number of defined rfkilltypes
*/
enum rfkill_type {
RFKILL_TYPE_ALL = 0,
RFKILL_TYPE_WLAN,
RFKILL_TYPE_BLUETOOTH,
RFKILL_TYPE_UWB,
RFKILL_TYPE_WIMAX,
RFKILL_TYPE_WWAN,
RFKILL_TYPE_GPS,
RFKILL_TYPE_FM,
RFKILL_TYPE_NFC,
NUM_RFKILL_TYPES,
};
其中:
- RFKILL_TYPE_ALL:表示所有开关(仅请求,不是开关类型);
- RFKILL_TYPE_WLAN:表示802.11无线网络设备的开关;
- RFKILL_TYPE_BLUETOOTH:表示蓝牙设备上的开关;
- RFKILL_TYPE_UWB:表示超宽带设备上的开关;
- RFKILL_TYPE_WIMAX:表示 WiMAX 设备上的开关;
- RFKILL_TYPE_WWAN:表示无线广域网设备上的开关;
- RFKILL_TYPE_GPS:表示GPS设备上的开关;
- RFKILL_TYPE_FM:表示FM收音机设备上的开关;
- RFKILL_TYPE_NFC:表示NFC设备上的开关;
- NUM_RFKILL_TYPES:枚举类型成员数量,可以用于数组的声明等;
2.3 struct rfkill_ops
struct rfkill_ops用于表示对rfkill设备的操作,这些操作一般需要与底层硬件打交道。该结构体定义在include/linux/rfkill.h:
/**
* struct rfkill_ops - rfkill driver methods
*
* @poll: poll the rfkill block state(s) -- only assign this method
* when you need polling. When called, simply call one of the
* rfkill_set{,_hw,_sw}_state family of functions. If the hw
* is getting unblocked you need to take into account the return
* value of those functions to make sure the software block is
* properly used.
* @query: query the rfkill block state(s) and call exactly one of the
* rfkill_set{,_hw,_sw}_state family of functions. Assign this
* method if input events can cause hardware state changes to make
* the rfkill core query your driver before setting a requested
* block.
* @set_block: turn the transmitter on (blocked == false) or off
* (blocked == true) -- ignore and return 0 when hard blocked.
* This callback must be assigned.
*/
struct rfkill_ops {
void (*poll)(struct rfkill *rfkill, void *data);
void (*query)(struct rfkill *rfkill, void *data);
int (*set_block)(void *data, bool blocked);
};
其中:
- poll: 轮询 rfkill设备开关的状态,在需要进行轮询时才分配此方法。调用该方法时,只需调用 rfkill_set{,_hw,_sw}_state 函数之一。如果硬件正在被解除阻止,则必须考虑这些函数的返回值,以确保正确使用软件阻塞;
- query: 查询rfkill设备开关的状态,并调用 rfkill_set{,_hw,_sw}_state 函数之一。如果输入事件可能导致硬件状态更改,则应分配此方法,以使rfkill核心在设置请求块之前查询您的驱动程序;
- set_block: 打开(blocked == false)或关闭(blocked == true)发射器。当硬件被阻止时,请忽略并返回 0,这个回调必须被分配;
三、rfkill核心API
rfkill核心提供了一些常用的API,用于管理rfkill设备的状态、注册、反注册以及灯控制等操作,这些API声明在include/linux/rfkill.h。
3.1 分配/释放rfkill设备
3.1.1 rfkill_alloc
rfkill_alloc用于动态申请一个rfkill结构体,并进行初始化;
/**
* rfkill_alloc - Allocate rfkill structure
* @name: name of the struct -- the string is not copied internally
* @parent: device that has rf switch on it
* @type: type of the switch (RFKILL_TYPE_*)
* @ops: rfkill methods
* @ops_data: data passed to each method
*
* This function should be called by the transmitter driver to allocate an
* rfkill structure. Returns %NULL on failure.
*/
struct rfkill * __must_check rfkill_alloc(const char *name,
struct device *parent,
const enum rfkill_type type,
const struct rfkill_ops *ops,
void *ops_data);
rfkill_alloc函数实现位于net/rfkill/core.c文件中,该函数主要就是动态分配一个struct rfkill数据结构,并对ops、data、dev成员进行初始化;
struct rfkill * __must_check rfkill_alloc(const char *name, // rfkill设备名称
struct device *parent, // 一般传入平台设备的dev成员
const enum rfkill_type type, // rfkill设备开关类型
const struct rfkill_ops *ops, // rfkill设备操作集
void *ops_data) // rfkill驱动私有数据
{
struct rfkill *rfkill;
struct device *dev;
if (WARN_ON(!ops))
return NULL;
if (WARN_ON(!ops->set_block))
return NULL;
if (WARN_ON(!name))
return NULL;
if (WARN_ON(type == RFKILL_TYPE_ALL || type >= NUM_RFKILL_TYPES))
return NULL;
rfkill = kzalloc(sizeof(*rfkill) + strlen(name) + 1, GFP_KERNEL);
if (!rfkill)
return NULL;
spin_lock_init(&rfkill->lock);
INIT_LIST_HEAD(&rfkill->node);
rfkill->type = type;
strcpy(rfkill->name, name); // 初始化rfkill成员
rfkill->ops = ops;
rfkill->data = ops_data;
dev = &rfkill->dev;
dev->class = &rfkill_class; // 设置其类为rfkill_class,从而当注册rfkill->dev设备后,会在/sys/class/rfkill下创建以rfkill设备名命名的文件夹
dev->parent = parent; // 设置父设备为platform设备的device
device_initialize(dev); // 初始化
return rfkill;
}
需要注意的是:这里并什么申请设备编号以及注册字符设备的逻辑,因此并不会注册字符设备。
这里我们看一下类rfkill_class的定义:
static struct class rfkill_class = {
.name = "rfkill",
.dev_release = rfkill_release,
.dev_groups = rfkill_dev_groups,
.dev_uevent = rfkill_dev_uevent,
.pm = RFKILL_PM_OPS,
};
rfkill_class是在rfkill core模块入口函数中注册的;
class_register(&rfkill_class)
3.1.2 rfkill_destroy
其对应的释放rfkill结构体的函数是rfkill_destroy:
/**
* rfkill_destroy - Free rfkill structure
* @rfkill: rfkill structure to be destroyed
*
* Destroys the rfkill structure.
*/
void rfkill_destroy(struct rfkill *rfkill);
3.2 注册/卸载rfkill设备
rfkill控制器驱动编写,实际上就是去为RF芯片分配一个rfkill数据结构,然后去根据去编写rfkill设备的操作函数。最后将其注册到内核即可。
3.2.1 rfkill_register
rfkill设备注册是通过rfkill_register函数来完成的:
/**
* rfkill_register - Register a rfkill structure.
* @rfkill: rfkill structure to be registered
*
* This function should be called by the transmitter driver to register
* the rfkill structure. Before calling this function the driver needs
* to be ready to service method calls from rfkill.
*
* If rfkill_init_sw_state() is not called before registration,
* set_block() will be called to initialize the software blocked state
* to a default value.
*
* If the hardware blocked state is not set before registration,
* it is assumed to be unblocked.
*/
int __must_check rfkill_register(struct rfkill *rfkill);
rfkill_register函数实现位于net/rfkill/core.c文件中:
int __must_check rfkill_register(struct rfkill *rfkill)
{
static unsigned long rfkill_no; // 静态全局变量,从0开始自增
struct device *dev = &rfkill->dev;
int error;
BUG_ON(!rfkill);
mutex_lock(&rfkill_global_mutex); // 上锁
if (rfkill->registered) { // 如果已经注册,直接返回
error = -EALREADY;
goto unlock;
}
rfkill->idx = rfkill_no; // 编号
dev_set_name(dev, "rfkill%lu", rfkill_no); // 设置设备名称rfkill%d
rfkill_no++; // 自增
list_add_tail(&rfkill->node, &rfkill_list); // 将当前rfkill设备追加到全局双向链表rfkill_list
error = device_add(dev); // 将dev设备注册到内核设备驱动程序模型中
if (error)
goto remove;
error = rfkill_led_trigger_register(rfkill); // 注册LED触发器
if (error)
goto devdel;
rfkill->registered = true;
INIT_DELAYED_WORK(&rfkill->poll_work, rfkill_poll); // 设置poll_work工作函数为rfkill_poll
INIT_WORK(&rfkill->uevent_work, rfkill_uevent_work); // 设置uevent_work工作函数为rfkill_uevent_work
INIT_WORK(&rfkill->sync_work, rfkill_sync_work); // 设置sync_work工作函数为rfkill_sync_work
if (rfkill->ops->poll) // 如果rfkill具有轮询操作,则将轮询工作项加入workqueue中
queue_delayed_work(system_power_efficient_wq,
&rfkill->poll_work,
round_jiffies_relative(POLL_INTERVAL));
if (!rfkill->persistent || rfkill_epo_lock_active) {
schedule_work(&rfkill->sync_work); // 将工作sync_work添加到工作队列system_wq
} else {
#ifdef CONFIG_RFKILL_INPUT
bool soft_blocked = !!(rfkill->state & RFKILL_BLOCK_SW);
if (!atomic_read(&rfkill_input_disabled))
__rfkill_switch_all(rfkill->type, soft_blocked);
#endif
}
rfkill_global_led_trigger_event(); // 触发LED触发器时间
rfkill_send_events(rfkill, RFKILL_OP_ADD);
mutex_unlock(&rfkill_global_mutex); // 解锁
return 0;
devdel:
device_del(&rfkill->dev);
remove:
list_del_init(&rfkill->node);
unlock:
mutex_unlock(&rfkill_global_mutex);
return error;
}
这里调用了device_add将设备rfkill->dev注册到linux设备驱动模型中,会在/sys/class/rfkill类文件下创建rfkill%s链接文件,但是由于未设置设备号devt(默认就是0),不会在文件系统创建设备节点/dev/rfkill%d。
3.2.2 rfkill_unregister
其对应的卸载函数是rfkill_unregister:
/**
* rfkill_unregister - Unregister a rfkill structure.
* @rfkill: rfkill structure to be unregistered
*
* This function should be called by the network driver during device
* teardown to destroy rfkill structure. Until it returns, the driver
* needs to be able to service method calls.
*/
void rfkill_unregister(struct rfkill *rfkill);
rfkill_unregister函数实现位于net/rfkill/core.c文件中:
void rfkill_unregister(struct rfkill *rfkill)
{
BUG_ON(!rfkill);
if (rfkill->ops->poll)
cancel_delayed_work_sync(&rfkill->poll_work);
cancel_work_sync(&rfkill->uevent_work);
cancel_work_sync(&rfkill->sync_work);
rfkill->registered = false;
device_del(&rfkill->dev);
mutex_lock(&rfkill_global_mutex);
rfkill_send_events(rfkill, RFKILL_OP_DEL);
list_del_init(&rfkill->node);
rfkill_global_led_trigger_event();
mutex_unlock(&rfkill_global_mutex);
rfkill_led_trigger_unregister(rfkill);
}
3.3 暂停/恢复轮询操作
函数 rfkill_pause_polling(struct rfkill *rfkill) 的作用是暂停rfkill设备开关轮询操作,例如当发射器因其他原因关闭时。需要注意的是,这个函数不适用于挂起/恢复操作,因为在该情况下,核心会停止轮询操作(但也会正确处理在挂起之前暂停轮询的情况)。
/**
* rfkill_pause_polling(struct rfkill *rfkill)
*
* Pause polling -- say transmitter is off for other reasons.
* NOTE: not necessary for suspend/resume -- in that case the
* core stops polling anyway (but will also correctly handle
* the case of polling having been paused before suspend.)
*/
void rfkill_pause_polling(struct rfkill *rfkill);
与之相反的函数是rfkill_resume_polling,用于恢复rfkill设备开关轮询操作。需要注意的是,这个函数不适用于挂起/恢复操作,因为在该情况下,核心会停止轮询操作。
/**
* rfkill_resume_polling(struct rfkill *rfkill)
*
* Resume polling
* NOTE: not necessary for suspend/resume -- in that case the
* core stops polling anyway
*/
void rfkill_resume_polling(struct rfkill *rfkill);
3.4 设置设备状态
3.4.1 rfkill_set_hw_state
函数 rfkill_set_hw_state 用于设置内部rfkill硬件阻塞状态;当rfkill驱动程序在硬阻塞状态发生更改时接收到事件时,应使用此函数通知rfkill核心(以及通过核心通知用户空间)当前状态。如果在恢复后状态可能已更改,则还应使用此函数。
如果分配了 poll_state,则不必(但可以)调用此函数。
任何上下文中都可以调用此函数,甚至可以从rfkill回调中调用。该函数返回组合块状态(如果发射器应被阻止则为 true),因此驱动程序无需跟踪软件块状态(可能无法跟踪)。
/**
* rfkill_set_hw_state - Set the internal rfkill hardware block state
* @rfkill: pointer to the rfkill class to modify.
* @blocked: the current hardware block state to set
*
* rfkill drivers that get events when the hard-blocked state changes
* use this function to notify the rfkill core (and through that also
* userspace) of the current state. They should also use this after
* resume if the state could have changed.
*
* You need not (but may) call this function if poll_state is assigned.
*
* This function can be called in any context, even from within rfkill
* callbacks.
*
* The function returns the combined block state (true if transmitter
* should be blocked) so that drivers need not keep track of the soft
* block state -- which they might not be able to.
*/
bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked);
3.4.2 rfkill_set_sw_state
函数 rfkill_set_sw_state 用于设置内部rfkill软件阻塞状态。当 rfkill驱动程序在软阻塞状态发生更改时接收到事件时,应使用此函数通知rfkill核心(以及通过核心通知用户空间)当前状态。一些平台直接对输入进行操作,但允许再次更改,因此驱动程序也需要使用此函数。
如果状态是由用户更改的,则驱动程序在恢复后还应调用此函数。这只对“持久”设备有意义。
该函数返回组合块状态(如果发射器应被阻止则为 true)
/**
* rfkill_set_sw_state - Set the internal rfkill software block state
* @rfkill: pointer to the rfkill class to modify.
* @blocked: the current software block state to set
*
* rfkill drivers that get events when the soft-blocked state changes
* (yes, some platforms directly act on input but allow changing again)
* use this function to notify the rfkill core (and through that also
* userspace) of the current state.
*
* Drivers should also call this function after resume if the state has
* been changed by the user. This only makes sense for "persistent"
* devices (see rfkill_init_sw_state()).
*
* This function can be called in any context, even from within rfkill
* callbacks.
*
* The function returns the combined block state (true if transmitter
* should be blocked).
*/
bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked);
3.4.3 rfkill_set_states
函数 rfkill_set_states 用于设置内部rfkill阻塞状态。该函数可以在任何上下文中调用,甚至可以从rfkill回调中调用。
/**
* rfkill_set_states - Set the internal rfkill block states
* @rfkill: pointer to the rfkill class to modify.
* @sw: the current software block state to set
* @hw: the current hardware block state to set
*
* This function can be called in any context, even from within rfkill
* callbacks.
*/
void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw);
该函数的参数包括:
- rfkill: 指向要修改的 rfkill的指针;
- sw: 要设置的当前软件阻塞状态;
- hw: 要设置的当前硬件阻塞状态;
3.5 查询设备状态
函数 rfkill_blocked用于查询rfkill的阻塞状态;
/**
* rfkill_blocked - Query rfkill block state
*
* @rfkill: rfkill struct to query
*/
bool rfkill_blocked(struct rfkill *rfkill);
3.6 查询设备类型
函数 rfkill_find_type是一个辅助函数,用于通过名称查找rfkill设备的开关类型;
/**
* rfkill_blocked - Query rfkill block state
*
* @rfkill: rfkill struct to query
*/
bool rfkill_blocked(struct rfkill *rfkill);
/**
* rfkill_find_type - Helper for finding rfkill type by name
* @name: the name of the type
*
* Returns enum rfkill_type that corresponds to the name.
*/
enum rfkill_type rfkill_find_type(const char *name);
3.7 获取/设备灯
函数 rfkill_get_led_trigger_name用于获取与按钮 LED相关联的 LED触发器名称。如果 LED 触发器注册失败,则此函数可能返回 NULL 指针。可以将其用作 LED 的“默认触发器”。
const char *rfkill_get_led_trigger_name(struct rfkill *rfkill);
而函数 rfkill_set_led_trigger_name用于设置LED触发器名称,如果调用,必须在调用 rfkill_register之前进行调用才能生效。
/**
* rfkill_set_led_trigger_name - Set the LED trigger name
* @rfkill: rfkill struct
* @name: LED trigger name
*
* This function sets the LED trigger name of the radio LED
* trigger that rfkill creates. It is optional, but if called
* must be called before rfkill_register() to be effective.
*/
void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name);
3.8 rfkill驱动编写步骤
rfkill驱动编写比较简单,大体上分为以下几个步骤:
- 调用rfkill_alloc为rfkill设备申请一个struct rfkill数据结构,同时指定rfkill操作集,必须要实现set_block回调(通过控制GPIO实现RF设备的开启/关闭);
- 调用rfkill_set_states设置内部rfkill阻塞状态;
- 调用rfkill_register注册rfkill设备;
当rfkill驱动注册完成后,我们可以通过以下命令开启/关闭RF设备:
echo 0 >/sys/class/rfkill/rfkill0/state // 关闭 等价于rfkill block 0
echo 1 >/sys/class/rfkill/rfkill0/state // 开启 等价于rfkill unblock 0
四、rfkill WiFi设备驱动
我们以Rockchip提供的针对WiFi设备的rfkill驱动程序为例进行讲解,其代码位于net/rfkill/rfkill-wlan.c文件(需要注意是该文件在linux 5.2.8下并没有,我是从Rockchip github linux源码拷贝过来的);
/*
* Copyright (C) 2012 ROCKCHIP, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/* Rock-chips rfkill driver for wifi
*/
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/rfkill.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/delay.h>
#include <linux/rfkill-wlan.h>
#include <linux/rfkill-bt.h>
#include <linux/w