RK3399教程:android hal 加载wifi

android hal 加载wifi ko模块流程

Android启动的时候会去加载wifi模块,这时候这部分代码在frameworks\opt\net\wifi\libwifi_hal\,这部分的代码主要的功能为,大概内容为通过读取uevnt的获取到系统下的wifi模块的vip和pid,从而从代码的列表中查找到是那个一个wifi模块,然后又从列表中获取wifi模块的驱动代码在那里,从而调用insmod xxxx.ko加载wifi模块。

frameworks\opt\net\wifi\libwifi_hal\rk_wifi_ctrl.cpp
static wifi_device supported_wifi_devices[] = {
	{"RTL8188EU",	"0bda:8179"},
	{"RTL8188EU",	"0bda:0179"},
	{"RTL8723BU",	"0bda:b720"},
	{"RTL8723BS",	"024c:b723"},
	{"RTL8822BS",	"024c:b822"},
	{"RTL8723CS",	"024c:b703"},
	{"RTL8723DS",	"024c:d723"},
	{"RTL8188FU",	"0bda:f179"},
	{"RTL8822BU",	"0bda:b82c"},
	{"RTL8189ES",	"024c:8179"},
	{"RTL8189FS",	"024c:f179"},
	{"RTL8192DU",	"0bda:8194"},
	{"RTL8812AU",	"0bda:8812"},
	{"SSV6051",	"3030:3030"},
	{"ESP8089",	"6666:1111"},
	{"AP6354",	"02d0:4354"},
	{"AP6330",	"02d0:4330"},
	{"AP6356S",	"02d0:4356"},
	{"AP6335",	"02d0:4335"},
	{"AP6255",      "02d0:a9bf"},
	{"RTL8822BE",	"10ec:b822"},
	{"MVL88W8977",	"02df:9145"},
};


frameworks\opt\net\wifi\libwifi_hal\wifi_hal_common.cpp

//wifi模块的驱动ko,文件的路径地址"/vendor/lib/modules/"
#define WIFI_MODULE_PATH		"/vendor/lib/modules/"
wifi_ko_file_name module_list[] =
{
	{"RTL8723BU", RTL8723BU_DRIVER_MODULE_NAME, RTL8723BU_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"RTL8188EU", RTL8188EU_DRIVER_MODULE_NAME, RTL8188EU_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"RTL8192DU", RTL8192DU_DRIVER_MODULE_NAME, RTL8192DU_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"RTL8822BU", RTL8822BU_DRIVER_MODULE_NAME, RTL8822BU_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"RTL8822BS", RTL8822BS_DRIVER_MODULE_NAME, RTL8822BS_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"RTL8188FU", RTL8188FU_DRIVER_MODULE_NAME, RTL8188FU_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"RTL8189ES", RTL8189ES_DRIVER_MODULE_NAME, RTL8189ES_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"RTL8723BS", RTL8723BS_DRIVER_MODULE_NAME, RTL8723BS_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"RTL8723CS", RTL8723CS_DRIVER_MODULE_NAME, RTL8723CS_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"RTL8723DS", RTL8723DS_DRIVER_MODULE_NAME, RTL8723DS_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"RTL8812AU", RTL8812AU_DRIVER_MODULE_NAME, RTL8812AU_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"RTL8189FS", RTL8189FS_DRIVER_MODULE_NAME, RTL8189FS_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"RTL8822BE", RTL8822BE_DRIVER_MODULE_NAME, RTL8822BE_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"SSV6051",     SSV6051_DRIVER_MODULE_NAME,   SSV6051_DRIVER_MODULE_PATH, SSV6051_DRIVER_MODULE_ARG},
	{"ESP8089",     ESP8089_DRIVER_MODULE_NAME,   ESP8089_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"AP6335",          BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"AP6330",          BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"AP6354",          BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"AP6356S",         BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"AP6255",          BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"APXXX",           BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"MVL88W8977",      MVL_DRIVER_MODULE_NAME,       MVL_DRIVER_MODULE_PATH, MVL88W8977_DRIVER_MODULE_ARG},
        {"RK912",         RK912_DRIVER_MODULE_NAME,     RK912_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
	{"UNKNOW",       DRIVER_MODULE_NAME_UNKNOW,    DRIVER_MODULE_PATH_UNKNOW, UNKKOWN_DRIVER_MODULE_ARG}

};

hardware\interfaces\wifi\1.2\default\service.cpp
//加载 WifiModeController然后会调用到WifiModeController::WifiModeController()
android::sp<android::hardware::wifi::V1_2::IWifi> service =
        new android::hardware::wifi::V1_2::implementation::Wifi(
            std::make_shared<WifiLegacyHal>(),
            std::make_shared<WifiModeController>(), 
            std::make_shared<WifiFeatureFlags>());


hardware\interfaces\wifi\1.2\default\wifi_mode_controller.cpp
WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
    bool WifiModeController::initialize() {
    if (!driver_tool_->LoadDriver()) {       //调用到下面的 LoadDriver
        LOG(ERROR) << "Failed to load WiFi driver";
        return false;
    }
    return true;
}


加载wifi驱动代码调用路径
frameworks\opt\net\wifi\libwifi_hal\driver_tool.cpp
    bool DriverTool::LoadDriver()
           return ::wifi_load_driver()
                    wifi_load_driver()  //frameworks\opt\net\wifi\libwifi_hal\wifi_hal_common.cpp
                   check_wifi_chip_type_string  //frameworks\opt\net\wifi\libwifi_hal\wifi_hal_common.cpp
                   if (!strcmp(wifi_type , module_list[i].wifi_name)) {
						wifi_ko_path = module_list[i].wifi_module_path;   //从module_list中获取到wifi驱动,xxxx.ko的路径,在这里是"/vendor/lib/modules/xxxx.ko"   
						wifi_ko_arg = module_list[i].wifi_module_arg;
                   }
				   save_wifi_chip_type(wifi_type);     //保存我们加载wifi的一些信息,这些信息用来给wpa_supplicant加载对于的wifi启动参数。
                   insmod(wifi_ko_path, wifi_ko_arg); //加载ko模块,和我们手动命令insmod xxxx.ko效果一样的

                 

//此功能为了从supported_wifi_devices这个列表里面获取当前SDIO上面挂载的是那个模块
int check_wifi_chip_type_string(char *type)
{
	if (identify_sucess == -1) {
		if (get_wifi_device_id(SDIO_DIR, PREFIX_SDIO) == 0)
			PLOG(DEBUG) << "SDIO WIFI identify sucess";
		else if (get_wifi_device_id(USB_DIR, PREFIX_USB) == 0)
			PLOG(DEBUG) << "USB WIFI identify sucess";
		else if (get_wifi_device_id(PCIE_DIR, PREFIX_PCIE) == 0)
			PLOG(DEBUG) << "PCIE WIFI identify sucess";
		else {
			PLOG(DEBUG) << "maybe there is no usb wifi or sdio or pcie wifi,set default wifi module Brocom APXXX";
			strcpy(recoginze_wifi_chip, "APXXX");
			identify_sucess = 1 ;
		}
	}

	strcpy(type, recoginze_wifi_chip);    //复制supported_wifi_devices里面的wifi_name的值
	PLOG(ERROR) << "check_wifi_chip_type_string : " << type;
	return 0;
} 
                        

wifi启动驱动加载fw流程

现在的wifi模块启动的时候都要加载一个fw固件,这个固件是做什么用的呢?可能是厂商用来做一下差异配置把,或者是加载射频参数进行使用,大家可以理解为加载一个bin文件到wifi模组中,每次wiif模组上电的时候都需要加载一次,加载的操作在wifi驱动的加载的时候,不同的厂商加载的bin文件不一样,下面我们可以通过系统启动的时候打印的log可以看到如下打印,下面的例子是博通的wifi模组的打印,Realtek不一样。

博通wifi加载过程

               Final fw_path=/vendor/etc/firmware/fw_bcm43438a1.bin
[   64.276445] Final nv_path=/vendor/etc/firmware/nvram_ap6212a.txt
[   64.276669] Final clm_path=/vendor/etc/firmware/clm.blob
[   64.276896] Final conf_path=/vendor/etc/firmware/config.txt
[   64.279224] dhd_os_open_image: /vendor/etc/firmware/fw_bcm43438a1.bin (414665 bytes) open success
[   64.365150] dhd_os_open_image: /vendor/etc/firmware/nvram_ap6212a.txt (1003 bytes) open success
[   64.365249] NVRAM version: AP6212A_NVRAM_V1.0.1_20160606

grep "Final fw_path=" -nr
通过查找Final fw_path=查找出在那里打印出的log,从而找到。
kernel/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c:8341:        printf("Final fw_path=%s\n", bus->fw_path);
所以可以知道在驱动里面会加载fw固件,但是这个固件的地址是在那里传进来的需要进一步追踪bus->fw_path这个值。

经过追踪发现在rockchip这个平台,固件的路径在内核里面写死了,代码在kernel\drivers\net\wireless\rockchip_wlan\rkwifi\rk_wifi_config.c里面定义了一个函数int rkwifi_set_firmware(char *fw, char *nvram),这个函数在博通的wifi驱动里面被调用,从而获取wifi固件的烧录地址,kernel\drivers\net\wireless\rockchip_wlan\rkwifi\bcmdhd\dhd_linux.c的bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo)中被调用。

对于博通的wifi和蓝牙二和一芯片来说一般需要加载3个固件分别对应给wifi和蓝牙使用的:
对于wifi部分有fw_bcm43438a1.bin和nvram_ap6212a.txt
对于蓝牙部分的固件有
bcm43438a1.hcd

对于Realtek的wifi,wifi部分不需要加载固件,但是蓝牙需要加载固件,固件的地址在kernel\drivers\bluetooth\rtk_btusb.c里面定义

static patch_info fw_patch_table[] = {
/* { vid, pid, lmp_sub_default, lmp_sub, everion, mp_fw_name, fw_name, config_name, fw_cache, fw_len, mac_offset } */
{ 0x0BDA, 0x1724, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723A */
{ 0x0BDA, 0x8723, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AE */
{ 0x0BDA, 0xA723, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AE for LI */
{ 0x0BDA, 0x0723, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AE */
{ 0x13D3, 0x3394, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AE for Azurewave*/

蓝牙加载驱动的时候内核层会调用request_firmware(&cfg, config_name, &udev->dev);来下载固件。
request_firmware使用方法可以参考:https://blog.csdn.net/magod/article/details/6049558。
当内核调用request_firmware这个函数的时候,在应用层就会在这个目录/sys/class/firmware生成一个节点,这个节点由三个属性分为为:

loading
这个属性应当被加载固件的用户空间进程设置为 1. 当加载进程完成, 它应当设为 0. 写一个值 -1 到 loading 会中止固件加载进程.

data
data 是一个二进制的接收固件数据自身的属性. 在设置 loading 后, 用户空间进程应当写固件到这个属性.

device
这个属性是一个符号连接到 /sys/devices 下面的被关联入口项.

所有由此推测,需要下载蓝牙固件的时候,应用层一定会往data这个属性写入固件的数据。

android hal 加载wpa_supplicant流程

我们前面的《android hal 加载wifi ko模块流程》中已经说明了,系统启动后会获取到 wifi 芯片 vid pid 加载相应的wifi ko驱动,然后在加载ko驱动的同时保存wifi芯片的一些信息,比如我们加载的wifi模块是博通Broadcom的就保存好博通Broadcom wifi的名字等信息,如果是加载的模块是瑞昱(Realtek)的就保存瑞昱(Realtek)wifi名字的信息。之后系统会启动之后系统会读取init.connectivity.rc 这个脚本,这个脚本会启动wpa_supplicant这个服务,这个应用服务会常驻在后台,启动wpa_supplicant的时候需要指定wifi模块的参数,参数保存在“/vendor/etc/wifi/wpa_config.txt”,源码目录放在/device/rockchip/common/wpa_config.txt。

librkwifi-ctrl.so从那里来?

在\frameworks\opt\net\wifi\libwifi_hal\Android.bp

cc_library_shared {               //编译成可执行文件,cc_library_shared编译成动态库
    name: "librkwifi-ctrl",     //生成librkwifi-ctrl.so库
    vendor: true,                 //编译出来放在/vendor目录下(默认是放在/system目录下)
    cflags: wifi_hal_cflags,
    local_include_dirs: ["include"],       //用户值定的头文件查找路径
    shared_libs: ["libbase"],              //编译依赖的动态库   
    header_libs: ["libcutils_headers"],
    srcs: ["rk_wifi_ctrl.cpp"],               //源文件,格式["a.cpp", "b.cpp"]
}

猜你喜欢

转载自blog.csdn.net/qq_27809619/article/details/120281399
今日推荐