本文主要记录给Baytrail 平台 Android6.0系统移植EWM-W163M201E WiFi的过程和中间遇到的问题。Android版本是6.0,Kernel版本是3.14.64,CPU是 Bay Trail平台Vallyview-D/M系列,WiFi是研华的EWM-W163M201E模块。
- 驱动下载
WiFi驱动一般都是wifi 厂商提供的,一般情况下厂商会提供wifi驱动,wifi firmware和wifi potting guide等资料给软件工程师 。本次使用的EWM-W163M201E wifi模块的Main Chipset是 QCA6174A 它需要的驱动是ath10k。厂商说这个驱动是包含在Linux源码中的,但是通过查看源码发现我们的3.14.64 kernel里面的ath10k驱动由于版本较低的缘故还没有添加QCA6174A 的支持。那么就遇到一个比较尴尬的事情,没有任何驱动也没有任何资料可以使用参考。没办法我就查找各种资料幸好功夫不负有心人我找到了compat-wireless驱动源码,发现里面有我们需要的驱动。我们就从下面路径下载了comat-wireless驱动compat-wireless-2017-09-25.tar.xz,然后单独编译移植到我们的系统。
compat-wireless驱动下载地址:http://mirror2.openwrt.org/sources/
- 驱动编译
- 修改顶层Makefile
下载到驱动源码后首先需要通过修改顶层Makefile中的KMODDIR,KLIB,KMODPATH_ARG,KLIB_BUILD等变量来设置kernel路径和驱动安装路径(这里和后面说的安装路径都是指编译后的驱动存放路径,编译Android的时候会把这个安装路径下的驱动和lib库等文件打包到相关Image中),以确保驱动可以正常编译和安装到你的Android系统中。如下是我的修改可做参考--- a/compat-wireless-2017-09-25/Makefile 2017-09-29 04:51:19.000000000 +0800 +++ b/compat-wireless-2017-09-25/Makefile 2019-01-15 17:29:54.336700189 +0800 @@ -8,14 +8,18 @@ MAKEFLAGS += --no-print-directory SHELL := /bin/bash BACKPORT_DIR := $(shell pwd) -KMODDIR ?= updates +KMODDIR = kernel ifneq ($(origin KLIB), undefined) KMODPATH_ARG := "INSTALL_MOD_PATH=$(KLIB)" else -KLIB := /lib/modules/$(shell uname -r)/ +KLIB := "/home/work/Android_BSP/byt_mr_2016ww32/device/advantech/upos-kernel/x86_64/" -KMODPATH_ARG := +KMODPATH_ARG := "INSTALL_MOD_PATH=$(KLIB)" endif -KLIB_BUILD ?= $(KLIB)/build/ +KLIB_BUILD = "/home/work/Android_BSP/byt_mr_2016ww32/device/advantech/upos-kernel/linux" KERNEL_CONFIG := $(KLIB_BUILD)/.config KERNEL_MAKEFILE := $(KLIB_BUILD)/Makefile CONFIG_MD5 := $(shell md5sum $(KERNEL_CONFIG) 2>/dev/null | sed 's/\s.*//')
- 配置编译选项
通过make menuconfig来配置我们需要的编译选项。我需要编译cfg80211,mac80211,ath10,ath10_core,ath10_pci等驱动。如下是我的操作可供参考 - 编译和安装
上面配置好后就可以分别执行make和make install命令编译和安装驱动了。我设置的驱动放置路径为x86_64,那么如下是我编译安装后看到的驱动
- Android相关修改
Android相关修改主要包括添加wifi firmware,hardware层修改,framwork层修改,wpa_supplicant服务添加等。下面我们逐一来介绍。
- wifi firmware
wifi驱动加载的时候一般都需要添加firmware的,而firmware一般也是由厂商提供的。奇葩的是PM也没有问厂商要到firmware。那怎么办呢?那我就各种的找,真是柳暗花明又一村我发现安装Ubuntu系统后该模块是可以使用的。所以我就查看Ubuntu系统的dmesg,终于找到了ubuntu系统中使用的QCA6174A相关firmware,然后把他拷贝了出来。有了firmware只需要将它拷贝到系统指定的路径即可,加载驱动的时候就会自动在相关路径寻找并加载。下面是我的添加可供参考
需要注意的是给系统的system/etc/modprobe.d/路径下还拷贝了ath10k.conf文件,该文件只有一条命令,但是是必须添加的因为发现如果不添加驱动加载的时候会报错--- a/device/advantech/upos/upos.mk +++ b/device/advantech/upos/upos.mk @@ -68,6 +68,18 @@ PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/third_party/busybox-x86_64:system/bin/busybox-x86_64 \ $(LOCAL_PATH)/third_party/busybox-x86_64:system/bin/busybox +PRODUCT_COPY_FILES += \ + $(LOCAL_PATH)/third_party/ath10k/QCA6174/hw3.0/board.bin:system/vendor/firmware/ath10k/QCA6174/hw3.0/board.bin \ + $(LOCAL_PATH)/third_party/ath10k/QCA6174/hw3.0/board-2.bin:system/vendor/firmware/ath10k/QCA6174/hw3.0/board-2.bin \ + $(LOCAL_PATH)/third_party/ath10k/QCA6174/hw3.0/firmware-4.bin:system/vendor/firmware/ath10k/QCA6174/hw3.0/firmware-4.bin \ + $(LOCAL_PATH)/third_party/ath10k/QCA6174/hw3.0/notice_ath10k_firmware-4.txt:system/vendor/firmware/ath10k/QCA6174/hw3.0/notice_ath10k_firmware-4.txt \ + $(LOCAL_PATH)/third_party/ath10k/QCA6174/hw2.1/board.bin:system/vendor/firmware/ath10k/QCA6174/hw2.1/board.bin \ + $(LOCAL_PATH)/third_party/ath10k/QCA6174/hw2.1/board-2.bin:system/vendor/firmware/ath10k/QCA6174/hw2.1/board-2.bin \ + $(LOCAL_PATH)/third_party/ath10k/QCA6174/hw2.1/firmware-5.bin:system/vendor/firmware/ath10k/QCA6174/hw2.1/firmware-5.bin \ + $(LOCAL_PATH)/third_party/ath10k/QCA6174/hw2.1/notice_ath10k_firmware-5.txt:system/vendor/firmware/ath10k/QCA6174/hw2.1/notice_ath10k_firmware-5.txt \ + $(LOCAL_PATH)/third_party/ath10k/ath10k.conf:system/etc/modprobe.d/ath10k.conf + + PRODUCT_PACKAGES += \ AndroidTerm \ libjackpal-androidterm4 \
options ath10k_core skip_otp=y
- hardware层修改
WiFi相关代码在hardware层的分为两部分。一部分是/libhardware_legacy/wifi.c。这部分代码是wifi驱动加载卸载,firmware存放路径和加载,wifi socket通信等相关处理的关键。另一部分是/hardware/qcom/wlan/qcwcn/wpa_supplicant_8_lib。它里面的driver_cmd_nl80211.c是驱动和wpa_supplicant通信的关键。kernel和wpa_supplicant之间的交互一般都有固定的驱动接口如WEXT、NL80211。QCA6174A的驱动接口是NL80211,而/hardware/qcom/wlan/qcwcn/wpa_supplicant_8_lib正是QCA6174A需要的NL80211代码。需要在BoardConfig.mk中配置一下才可以编译和使用指定的wpa_supplicant_8_lib。如下是我的配置--- a/device/advantech/upos/BoardConfig.mk +++ b/device/advantech/upos/BoardConfig.mk @@ -207,6 +207,19 @@ BOARD_HAVE_BLUETOOTH_LINUX := false BOARD_KERNEL_CMDLINE += acpi_backlight=video +############################################################## +# Source: device/intel/mixins/groups/wlan/autodetect/BoardConfig.mk +############################################################## +ADDITIONAL_DEFAULT_PROPERTIES += wifi.interface=wlan0 +#WPA_SUPPLICANT_VERSION := VER_2_1_DEVEL +WPA_SUPPLICANT_VERSION := VER_0_8_X +BOARD_WPA_SUPPLICANT_DRIVER := NL80211 +#WIFI_DRIVER_MODULE_PATH ?= auto +#BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_rtl +BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_qcwcn +BOARD_WLAN_DEVICE := qcwcn +DEVICE_PACKAGE_OVERLAYS += device/intel/common/wlan/overlay-wifi-display + DEVICE_PACKAGE_OVERLAYS += device/intel/common/audio/overlay DEVICE_PACKAGE_OVERLAYS += device/intel/common/audio/overlay-no-ultrasound
- framwork层修改
系统网络选项配置和优先级的配置实在/frameworks/base/core/res/res/values/config.xml文件中的,不过我们通常的做法是不直接修改frameworks中的该文件,而是在平台代码中添加相关文件然后编译系统的时候以overlay的方式来修改它,那么下面是我们的修改--- a/device/intel/common/wlan/overlay-wifi-display/frameworks/base/core/res/res/values/config.xml +++ b/device/intel/common/wlan/overlay-wifi-display/frameworks/base/core/res/res/values/config.xml @@ -14,4 +14,50 @@ --> <bool name="config_enableWifiDisplay">true</bool> + <!-- This string array should be overridden by the device to present a list of network + attributes. This is used by the connectivity manager to decide which networks can coexist + based on the hardware --> + <!-- An Array of "[Connection name],[ConnectivityManager.TYPE_xxxx], + [associated radio-type],[priority],[restoral-timer(ms)],[dependencyMet] --> + <!-- the 5th element "resore-time" indicates the number of milliseconds to delay + before automatically restore the default connection. Set -1 if the connection + does not require auto-restore. --> + <!-- the 6th element indicates boot-time dependency-met value. --> + <string-array translatable="false" name="networkAttributes"> + <item>"wifi,1,1,1,-1,true"</item> + <item>"mobile,0,0,0,-1,true"</item> + <item>"mobile_mms,2,0,2,60000,true"</item> + <item>"mobile_supl,3,0,2,60000,true"</item> + <item>"mobile_hipri,5,0,3,60000,true"</item> + <item>"ethernet,9,9,1,-1,true"</item> + <item>"mobile_fota,10,0,2,60000,true"</item> + <item>"mobile_ims,11,0,2,60000,true"</item> + <item>"mobile_cbs,12,0,2,60000,true"</item> + <item>"wifi_p2p,13,1,0,-1,true"</item> + </string-array> + <!-- This string array should be overridden by the device to present a list of radio + attributes. This is used by the connectivity manager to decide which networks can coexist + based on the hardware --> + <!-- An Array of "[ConnectivityManager connectionType], + [# simultaneous connection types]" --> + <string-array translatable="false" name="radioAttributes"> + <item>"1,1"</item> + <item>"0,1"</item> + <item>"9,1"</item> + </string-array> + + <!-- Set of NetworkInfo.getType() that reflect data usage. --> + <integer-array translatable="false" name="config_data_usage_network_types"> + <item>0</item> <!-- TYPE_MOBILE --> + <item>2</item> <!-- TYPE_MOBILE_MMS --> + <item>3</item> <!-- TYPE_MOBILE_SUPL --> + <item>4</item> <!-- TYPE_MOBILE_DUN --> + <item>5</item> <!-- TYPE_MOBILE_HIPRI --> + <item>9</item> <!-- TYPE_ETHERNET --> + <item>10</item> <!-- TYPE_MOBILE_FOTA --> + <item>11</item> <!-- TYPE_MOBILE_IMS --> + <item>12</item> <!-- TYPE_MOBILE_CBS --> + </integer-array> + + </resources>
- wpa_supplicant服务添加
wpa_suppulicant服务是wifi模块在HAL层和framework层通信的关键,它是一个后台运行的服务。源码在/external/wpa_supplicant_8/wpa_supplicant/目录下,我们需要在device目录的平台代码的makefile中添加编译选项,如下是我们添加的
上面出来添加wpa_supplicant的编译外还将需要的wpa_cupplicant.conf配置文件也拷贝到了系统指定目录,另外frameworks/native/data/etc/android.hardware.wifi.xml和frameworks/native/data/etc/android.hardware.wifi.direct.xml分别代表的是设备是否支持wifi功能和wifi直连功能,如果不添加android.hardware.wifi.xml的话在Setting中就无法看到WIFI选项。--- a/device/advantech/upos/device.mk +++ b/device/advantech/upos/device.mk @@ -303,6 +303,19 @@ PRODUCT_COPY_FILES += \ PRODUCT_PACKAGES += \ audio.a2dp.default +############################################################## +# Source: device/intel/mixins/groups/wlan/autodetect/product.mk +############################################################## +PRODUCT_COPY_FILES += \ + device/intel/common/wlan/wpa_supplicant-common.conf:system/etc/wifi/wpa_supplicant.conf \ + device/intel/common/wlan/wpa_supplicant_overlay.conf:system/etc/wifi/wpa_supplicant_overlay.conf \ + frameworks/native/data/etc/android.hardware.wifi.xml:system/etc/permissions/android.hardware.wifi.xml + #frameworks/native/data/etc/android.hardware.wifi.direct.xml:system/etc/permissions/android.hardware.wifi.direct.xml + +PRODUCT_PACKAGES += \ + wpa_supplicant + + # Tinyalsa PRODUCT_PACKAGES_DEBUG += \ tinymix \
编译了wpa_supplicant后,就需要添加一个后台服务来运行它,并且需要添加获取IP的服务。如下是我的添加:--- a/device/advantech/upos/init.rc +++ b/device/advantech/upos/init.rc @@ -14,6 +14,12 @@ on post-fs-data on post-fs-data setprop persist.sys.root_access 3 +on post-fs-data + mkdir /data/misc/wifi 0770 wifi wifi + mkdir /data/misc/wifi/sockets 0770 wifi wifi + mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi + mkdir /data/misc/dhcp 0770 dhcp dhcp + on boot setprop service.adb.tcp.port 5555 @@ -214,6 +220,42 @@ on post-fs-data import /init.debug-charging.rc + +service wpa_supplicant /system/bin/wpa_supplicant -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \ + -O/data/misc/wifi/sockets -e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0 + class main + socket wpa_wlan0 dgram 660 wifi wifi + disabled + + +#setprop wifi.supplicant wpa_supplicant + + +service dhcpcd_wlan0 /system/bin/dhcpcd -aABDKL + class main + disabled + oneshot + +service iprenew_wlan0 /system/bin/dhcpcd -n + class main + disabled + oneshot + +on property:init.svc.wpa_supplicant=stopped + stop dhcpcd + on fs mkdir /dev/pstore 0755 root system mount pstore pstore /dev/pstore
- 其他修改
我们在移植的时候发现系统状态栏的网络状态显示不正常,老是存在一个感叹号,但是网络却是可以使用的。经过追踪代码发现是Android网络的验证机制导致的。Android系统可以通过Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED全局变量来控制网络连接以后是否需要进行网络可用性检查。如果该值被设置为1或者没有设置该值则系统会通过访问Settings.Global.CAPTIVE_PORTAL_SERVER全局变量指定的网址来判断网络是否可用。如果全局变量Settings.Global.CAPTIVE_PORTAL_SERVER没有被设置系统则会使用默认的DEFAULT_SERVER="connectivitycheck.gstatic.com"网址测试。那么问题就出在这里,国内由于某种原因这个网址有时可用连接上有时连接不上,所以当连接不上的时候无论是Ethernet网络、WiFi网络还是3G/4G网络,它的状态栏图标都会有感叹号。想了解这部分可以参考/frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java代码。那么问题找到了该怎么解决呢?一般有下面两种方法可以解决:
- 方法一
通过设置Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED为0将网络检查取消掉,但是这样会存在一个问题。当我们连接的Ethernet网络或者网络需要网络认证才可以使用的话,我们就无法进入到这个网络认证界面了,也就是说无法认证连接网络了。 - 方法二:
设置Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED为1,并将Settings.Global.CAPTIVE_PORTAL_SERVER设置为一个国内可用的网络地址即可。这里需要注意的是Settings.Global.CAPTIVE_PORTAL_SERVER不是随便设置个网址就可以的,它必须是一个可以返回204状态码的网址。
那么我们就是使用第二种方法解决了这个问题的。做法如下:
--- a/device/advantech/upos/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml
+++ b/device/advantech/upos/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml
@@ -22,6 +22,12 @@
<bool name="def_wake_gesture_enabled">false</bool>
<!-- Keep screen on at all times by default -->
<bool name="def_stay_on_while_plugged_in">true</bool>
+
+ <add-resource type="integer" name="def_captive_portal_detection_enable" />
+ <integer name="def_captive_portal_detection_enable">1</integer>
+
+ <add-resource type="string" name="def_captive_portal_server" />
+ <string name="def_captive_portal_server">204.gentool.top</string>
</resources>
--- a/frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2576,6 +2576,12 @@ class DatabaseHelper extends SQLiteOpenHelper {
loadBooleanSetting(stmt, Settings.Global.ASSISTED_GPS_ENABLED,
R.bool.assisted_gps_enabled);
+ loadIntegerSetting(stmt, Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED,
+ R.integer.def_captive_portal_detection_enable);
+
+ loadStringSetting(stmt, Settings.Global.CAPTIVE_PORTAL_SERVER,
+ R.string.def_captive_portal_server);
+
loadBooleanSetting(stmt, Settings.Global.AUTO_TIME,
R.bool.def_auto_time); // Sync time to NITZ