Rockchip RK3399 - rfkill子系统

本文详细介绍了Linux内核中的rfkill子系统,用于控制无线通信硬件的开关状态,如WiFi、蓝牙等。rfkill包括硬件和软件封锁的概念,提供rfkill命令查看和控制无线设备。rfkill子系统由核心、输入模块和驱动程序组成,驱动程序需要实现rfkill_ops接口。此外,文章还探讨了Rockchip RK3399平台上的rfkill WiFi和蓝牙设备驱动,包括电路原理、设备节点配置、中断处理和状态控制等。
摘要由CSDN通过智能技术生成

----------------------------------------------------------------------------------------------------------------------------

开发板   :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设备开关的状态,并响应用户的请求或硬件事件。

三、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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Graceful_scenery

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值