rfkill - RF kill switch support (翻译)

本文介绍了rfkill子系统的基本概念及其实现细节。rfkill为内核驱动提供了API,允许注册无线设备,并通过用户空间接口控制设备的工作状态。此外,还详细解释了内核API的使用方法以及用户空间的支持。

1、介绍

          rfkill子系统在系统对于禁止无线设备工作提供了一个通用的接口,当无线设备被阻止工作时,它就不会在消耗功率。这个子系统在用户开关按钮上提供了一个方法去阻止某种无线设备的工作。这是用于某些环境下(比如飞机) ,无线设备就必须被关闭。子系统有硬件和软件模块的概念。在概念上这些意义很小,关于在于它能否被改变。

2、实现细节
       rfkill核心为内核驱动提供了API,这是为了在内核中注册这些无线设备。这种方法的打开或者关闭 是为了让系统知道硬件设备的工作状态。当设备是硬件模块(可以被rfkill_set_hw_state() 或者from query_hw_block调用),set_block()可以被其他的软件模块调用,驱动程序忽视这个方法的调用,他们可以用rfkill_set_hw_state()的返回值去同步软件的状态而不是一直在调用set_block(),实际上,驱动程序应该用rfkill_set_hw_state()的返回值,除非硬件实际上一直保持软件和硬件的独立。

3、内核API
      无线设备的驱动基本上实现了rfkill的驱动。如果rfkill开关只是一个按钮,平台驱动可能实现输入设备驱动。这个开关影响硬件的工作,所以你需要实现rfkill的驱动。平台需要提供一个方法去开(关)设备的方法。当一个状态改变的时候,除非他们分配了poll_hw_block()回调,rfkill_set_hw_state()就会被调用。

 4、userspace 支持
        被推荐使用的用户接口是/dev/rfkill,这是一个混合的字符设备,他允许用户空间使用和设置rfkill设备的状态。这也通知用户空间关于设备的增加和移除。在linux/rfkill.h中的API也就是一般简单的读/写API,对于打开或者关闭的过渡时期,ioctl需要传入关闭的状态。
      除了ioctl,和内核通信通过read()和write(),而不是struct rfkill_event。在这个结构体中,软件和硬件模块被分开。用户空间在系统中能得到rfkill驱动的状态。当然rfkill驱动的状态同事也得更新默认热插设备的状态。当一个应用打开/dev/rfkill,他可以读取到当前所有设备的状态。通过查询设备变化的消息和监听rfkill core发出的uevent,设备状态的变化可以被获得。另外,每个 rfkill的设备在sysfs和 emits uevents 中被注册。

   

int _rf_spectral_scan(RF_SCAN_RADIO_CFG *pParams, RF_SCAN_RESULT *pResult) { int rid = 0; char vapName2G[IFNAMELEN] = {0}; char vapName5G[IFNAMELEN] = {0}; char vapName[IFNAMELEN] = {0}; UNIX_SOCK_FD cmdFd; int ret = 0; UNIX_SOCK_FDSET_T setOfSock; long currentTime = 0; long starScanTime = 0; int i = 0, j = 0, m = 0; int max1 = -100; int max2 = -100; int max1_index = 0, max2_index = 0; RF_INTERF_ITEM *pTmpItem = NULL; int chanWidthIndex = 0; int chanwidth = 0; int centerChan = 0; int chanExistFlag = 0; RF_SCAN_ITEM *pScanItem = NULL; int rfScanTime = 0; if (NULL == pResult || NULL == pParams) { RFSCAN_DEBUG("input invaliad\n"); return -1; } /* kill wpa_supplicant, controller收到rfscan结果后,为了防止信道改变,会下发一次切信道的命令,那时会把wpa_supplicant拉起来 */ util_execFormatCmd("killall wpa_supplicant"); /* 启动airiq进程 */ util_execFormatCmd("airiq_service -c /usr/sbin/airiq_service.cfg &"); usleep(TIME_WAIT_AIRIQ_START); for (rid = 0; rid < MAX_RADIO_NUM_SUPP(); ++rid) { if(RF_NEED_SCAN == pParams[rid].isNeedScan) { RFSCAN_DEBUG("Radio: %d need scan.", rid); } else { RFSCAN_DEBUG("Radio: %d no need scan.", rid); continue; } if (RADIO_IS_2G(rid)) { if (WLAN_OK != wlan_lib_getUpVap(rid, vapName2G)) { RFSCAN_ERROR("no up vap for radio %d", rid); continue; } util_execFormatCmd("airiq_app -i %s -b -phy_mode 4x4 -v -print_events &", vapName2G); printf("airiq_app -i %s -b -phy_mode 4x4 -v -print_events &\n", vapName2G); usleep(500); } if (RADIO_IS_5G(rid)) { if (WLAN_OK != wlan_lib_getUpVap(rid, vapName5G)) { RFSCAN_ERROR("no up vap for radio %d", rid); continue; } util_execFormatCmd("airiq_app -i %s -a -phy_mode 4x4 -v -print_events &", vapName5G); printf("airiq_app -i %s -a -phy_mode 4x4 -v -print_events &\n", vapName5G); usleep(500); } } memset(&cmdFd, 0, sizeof(cmdFd)); if ((ret = unix_sock_initSrv(UNIX_SOCK_ID_AIR_IQ, &cmdFd, 5)) != 0) { RFSCAN_ERROR("init command socket failed, ret=%d", ret); return -1; } memset(&setOfSock, 0, sizeof(setOfSock)); starScanTime = util_getUptime(UTIL_UNIT_S); currentTime = starScanTime; /* 只扫2G:52s,双频或5G扫描:192s */ rfScanTime = RF_SCAN_MAX_TIME_2G; for (rid = 0; rid < MAX_RADIO_NUM_SUPP(); ++rid) { if(RF_NEED_SCAN == pParams[rid].isNeedScan && RADIO_IS_5G(rid) && WLAN_OK == wlan_lib_getUpVap(rid, vapName)) { rfScanTime = RF_SCAN_MAX_TIME; } } while (currentTime > 0 && (currentTime - starScanTime) < rfScanTime) { unix_sock_groupClear(&setOfSock); unix_sock_groupAddTo(cmdFd.fd, &setOfSock); if (unix_sock_groupWait(&setOfSock, rfScanTime) < 0) { currentTime = util_getUptime(UTIL_UNIT_S); continue; } if (unix_sock_isSet(cmdFd.fd, &setOfSock)) { /* handle spectral from driver */ if (0 != _rfScanRecvCmd(cmdFd.fd, pResult, pParams)) { RFSCAN_DEBUG("recv cmd from airiq failed\n"); } } currentTime = util_getUptime(UTIL_UNIT_S); } unix_sock_close(&cmdFd); util_execFormatCmd("killall airiq_app"); util_execFormatCmd("killall airiq_service"); /* 计算平均干扰值 */ for (i = 0; i < pResult->itemNum; i++) { for (j = 0; j < pResult->scanItem[i].interfTable.itemNum; j++) { pResult->scanItem[i].interfTable.interfItem[j].interf = _getAverageRssi(&pResult->scanItem[i].interfTable, j); } } /* 筛选每个信道中干扰值最大的两种干扰 */ for (i = 0; i < pResult->itemNum; i++) { if (pResult->scanItem[i].interfTable.itemNum > 2) { for (j = 0; j < pResult->scanItem[i].interfTable.itemNum; j++) { if (pResult->scanItem[i].interfTable.interfItem[j].interf > max1) { max2 = max1; max2_index = max1_index; max1 = pResult->scanItem[i].interfTable.interfItem[j].interf; max1_index = j; } else if (pResult->scanItem[i].interfTable.interfItem[j].interf > max2 && pResult->scanItem[i].interfTable.interfItem[j].interf <= max1) { max2 = pResult->scanItem[i].interfTable.interfItem[j].interf; max2_index = j; } } /* 保存索引为0的item,深拷贝避免被修改 */ pTmpItem = (RF_INTERF_ITEM *)malloc(sizeof(RF_INTERF_ITEM)); memset(pTmpItem, 0, sizeof(RF_INTERF_ITEM)); pTmpItem->interf = pResult->scanItem[i].interfTable.interfItem[0].interf; pTmpItem->interfType = pResult->scanItem[i].interfTable.interfItem[0].interfType; for (m = 0; m < RF_INTERF_POINT_MAX; m++) { pTmpItem->rssiCount[m] = pResult->scanItem[i].interfTable.interfItem[0].rssiCount[m]; } /* 将最大干扰的item赋值给item[0] */ memcpy(&pResult->scanItem[i].interfTable.interfItem[0], &pResult->scanItem[i].interfTable.interfItem[max1_index], sizeof(RF_INTERF_ITEM)); /* 将第二大干扰的item赋值给item[1] */ if (max2_index == 0) { /* 第二大干扰的item是原item[0],拷贝pTmpItem */ memcpy(&pResult->scanItem[i].interfTable.interfItem[1], pTmpItem, sizeof(RF_INTERF_ITEM)); } else { memcpy(&pResult->scanItem[i].interfTable.interfItem[1], &pResult->scanItem[i].interfTable.interfItem[max2_index], sizeof(RF_INTERF_ITEM)); } pResult->scanItem[i].interfTable.itemNum = 2; free(pTmpItem); } } /* 如果某个信道下没有干扰,需要上报信道利用率 */ for (rid = 0; rid < MAX_RADIO_NUM_SUPP(); ++rid) { if(RF_NEED_SCAN == pParams[rid].isNeedScan) { RFSCAN_DEBUG("Radio: %d need scan.", rid); } else { RFSCAN_DEBUG("Radio: %d no need scan.", rid); continue; } if (WLAN_OK != wlan_lib_getUpVap(rid, vapName)) { RFSCAN_ERROR("no up vap for radio %d", rid); continue; } /* 遍历需要扫描的信道 */ for (i = 0; i < pParams[rid].chanNum; i ++) { #ifdef CONFIG_SUPPORT_BW_320MHZ chanWidthIndex = RF_CHAN_WIDTH_320M; #elif defined(CONFIG_SUPPORT_BW_160MHZ) chanWidthIndex = RF_CHAN_WIDTH_160M; #else chanWidthIndex = RF_CHAN_WIDTH_80M; #endif /* 遍历带宽 */ for (; chanWidthIndex >= RF_CHAN_WIDTH_20M; chanWidthIndex--) { if (RADIO_IS_2G(rid) && chanWidthIndex >= RF_CHAN_WIDTH_80M) { /* 2G only support 20M and 40M */ continue; } /* get chanwidth for inform msg */ switch(chanWidthIndex) { case RF_CHAN_WIDTH_20M: chanwidth = 20; break; case RF_CHAN_WIDTH_40M: chanwidth = 40; break; case RF_CHAN_WIDTH_80M: chanwidth = 80; break; #ifdef CONFIG_SUPPORT_BW_160MHZ case RF_CHAN_WIDTH_160M: chanwidth = 160; break; #endif #ifdef CONFIG_SUPPORT_BW_320MHZ case RF_CHAN_WIDTH_320M: chanwidth = 320; break; #endif default: RFSCAN_DEBUG("invalid channel width: %d\n", chanwidth); } /* get centerChan */ centerChan = _getCenterChannel(rid, pParams[rid].chanList[i].chan, chanwidth); chanExistFlag = 0; for (j = 0; j < pResult->itemNum; j++) { if (centerChan == pResult->scanItem[j].chan && chanwidth == pResult->scanItem[j].chanWidth) { chanExistFlag = 1; break; } } /* no interference in centerChan */ if (chanExistFlag == 0 && centerChan >= pParams[rid].chanList[0].chan && centerChan <= pParams[rid].chanList[pParams[rid].chanNum - 1].chan) { /* add new item to result table */ pScanItem = & pResult->scanItem[pResult->itemNum]; pScanItem->radioID = rid; pScanItem->chan = centerChan; pScanItem->chanWidth = chanwidth; pScanItem->interfTable.itemNum = 1; pScanItem->interfTable.interfItem[0].interfType = RF_INTERF_TYPE_NONE; pScanItem->interfTable.interfItem[0].interf = RF_NOISE_LEVEL; pResult->itemNum ++; } } } } return 0; } 代码作用详细分析
最新发布
09-27
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

qq_807315755

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

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

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

打赏作者

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

抵扣说明:

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

余额充值