RTL8821CE 無線網卡/藍牙驅動的編譯 Linux Kernel 5.0.0-20


  RTL8821CE 在Linux Kernel 5.0 上並沒有相關驅動,藍牙設備雖可以識別但無法使用,而WiFi設備都不能識別出來。

  在搜索引擎中搜索一番,找到了一個可行的回答,但是這個回答是2017年給出的,有些過時了。但是基本思路還是不變的,只要稍作修改就可成功編譯驅動程序。

  從 chili555 的回答中給出的下載鏈接下載驅動源代碼壓縮包(所在項目還在繼續開發,本文使用的是2019年8月初下載的源代碼)。

  按照 chili555 給出的步驟操作,在執行make命令前,要修改一下Makefile.mkrtl8821ce.mk兩個文件內的路徑配置,只要把文件內的所有$(srctree)/刪去就行了。

  示例(行首的-表示修改前的代碼,+表示修改后的代碼。):

-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

  編譯時出現了以下錯誤,錯誤原因是函數簽名不符。

  注意:這里的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

//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

/*
/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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM