RTL8821CE 在Linux Kernel 5.0 上並無相關驅動,藍牙設備雖能夠識別但沒法使用,而WiFi設備都不能識別出來。html
在搜索引擎中搜索一番,找到了一個可行的回答,可是這個回答是2017年給出的,有些過期了。可是基本思路仍是不變的,只要稍做修改就可成功編譯驅動程序。linux
從 chili555 的回答中給出的下載連接下載驅動源代碼壓縮包(所在項目還在繼續開發,本文使用的是2019年8月初下載的源代碼)。git
按照 chili555給出的步驟操做,在執行make
命令前,要修改一下Makefile.mk
和rtl8821ce.mk
兩個文件內的路徑配置,只要把文件內的全部$(srctree)/
刪去就好了。github
示例(行首的-
表示修改前的代碼,+
表示修改後的代碼。):shell
-EXTRA_CFLAGS += -I$(srctree)/$(src)/platform +EXTRA_CFLAGS += -I$(src)/platform _PLATFORM_FILES := platform/platform_ops.o -EXTRA_CFLAGS += -I$(srctree)/$(src)/hal/btc +EXTRA_CFLAGS += -I$(src)/hal/btc
編譯時出現瞭如下錯誤,錯誤緣由是函數簽名不符。ubuntu
注意:這裏的os_intfs.c
文件是我修改過的,出錯的1470行對應於原始文件中的1467行。安全
CC [M] /home/name/nv/rtl8821ce/os_dep/linux/os_intfs.o /home/name/nv/rtl8821ce/os_dep/linux/os_intfs.c:1470:22: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types] .ndo_select_queue = rtw_select_queue, ^~~~~~~~~~~~~~~~ /home/name/nv/rtl8821ce/os_dep/linux/os_intfs.c:1470:22: note: (near initialization for ‘rtw_netdev_ops.ndo_select_queue’) cc1: some warnings being treated as errors
在源代碼中找到出錯代碼所在的結構體名稱net_device_ops
。less
//rtl8821ce/os_dep/linux/os_intfs.c:1459 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)) static const struct net_device_ops rtw_netdev_ops = { //... .ndo_start_xmit = rtw_xmit_entry, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) .ndo_select_queue = rtw_select_queue, //error: initialization from incompatible pointer type #endif .ndo_set_mac_address = rtw_net_set_mac_address, //... }; #endif
在搜索引擎搜索一番後找到了net_device_ops
的聲明,在頭文件netdevice.h
中。函數
發現兩函數的函數簽名不一致,os_intfs.c
中的函數實現少了第四個形參select_queue_fallback_t fallback
。ui
/* /usr/src/linux-headers-5.0.0-20/include/linux/netdevice.h:1247 */ struct net_device_ops { //...... u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev, select_queue_fallback_t fallback); //...... } /* rtl8821ce/os_dep/linux/os_intfs.c:1325 */ static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) , struct net_device *sb_dev #endif ) { _adapter *padapter = rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; skb->priority = rtw_classify8021d(skb); if (pmlmepriv->acm_mask != 0) skb->priority = qos_acm(pmlmepriv->acm_mask, skb->priority); return rtw_1d_to_queue[skb->priority]; }
如今考慮如何修補這個函數實現。幸虧在函數體中並無用到第四個形參,於是直接把缺乏的形參添上就能夠了(可能會引入一些BUG)。
下面是rtl8821ce/os_dep/linux/os_intfs.c
的修改內容變化(由diff -u
生成)。
@@ -1323,9 +1323,8 @@ unsigned int rtw_classify8021d(struct sk_buff *skb) static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) ,struct net_device *sb_dev -#endif + ,select_queue_fallback_t fallback ) { _adapter *padapter = rtw_netdev_priv(dev);
以後,再進行編譯,獲得下面的輸出,表示編譯經過了。以後就能夠安裝和加載模塊了。注意只有關閉了安全啓動,才能加載未簽名的內核模塊。能夠參考個人這篇隨筆Linux內核模塊在安全啓動模式下的簽名和安裝,自簽名模塊並加載。
LD [M] /home/name/nv/rtl8821ce/8821ce.o Building modules, stage 2. MODPOST 1 modules CC /home/name/nv/rtl8821ce/8821ce.mod.o LD [M] /home/name/nv/rtl8821ce/8821ce.ko
相關連接:
https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/endlessm/linux/tree/master/drivers/net/wireless/rtl8821ce
https://github.com/endlessm/linux/tree/master/drivers/net/wireless/rtl8821ce
https://askubuntu.com/questions/990378/wi-fi-not-working-on-lenovo-thinkpad-e570-realtek-rtl8821ce/990571#990571