1. 程式人生 > >初識Linux 驅動移植 之 dm9621網絡卡驅動移植

初識Linux 驅動移植 之 dm9621網絡卡驅動移植

概述

將kernel移植到開發板並能正常載入和啟動核心後,發現網絡卡並沒有工作,因此將網絡卡作為第一個移植的實踐。這篇文章用於記錄移植dm9621網絡卡過程中遇到的問題以及如何定位問題並嘗試解決。

配置核心

在找到dm9621網絡卡驅動的原始碼後,需要將其新增到核心,並編譯到核心去不採用動態載入模組,需要做哪些修改呢?這需要通過核心配置選單來配置,將dm9620.c(dm9621 網絡卡驅動原始碼)拷貝到 driver/net/usb 目錄下,通過配置該目錄下Kconfig 和 Makefile 來決定。

//Kconfig 新增(新增dm9620 編譯選項):
+config USB_NET_DM9620
+   tristate "Davicom DM9620/21 based USB 2.0 10/100 ethernet devices"
+    depends on USB_USBNET
+    select CRC32
+   help
+       This option adds support for Davicom DM9620 based USB 2.0
+      10/100 Ethernet adapters.
+
+     This driver creates an interface named "ethX",where X depends on
+      what other networking devices you have in use.
+
+      To compile this driver as a module.choose M here.

//Makefile 新增(CONFIG_USB_NET_DM9620 為 y時編譯進核心,為 M 時編譯成模組):
+ obj-$(CONFIG_USB_NET_DM9620)    += dm9620.o  

新增好之後就可以通過 make menuconfig來配置了,由於dm9621是usb型別網絡卡,因此需要依賴於usb 網路框架:

Device Drivers  --->   
     [*] Network device support  ---> 
               USB Network Adapters  ---> 
                   <*> Multi-purpose USB Networking Framework
                     <*>   Davicom DM9620/21 based USB 2.0 10/100 ethernet devices

dm9621 網絡卡驅動編譯配置選項

dm9621 網絡卡驅動編譯配置選項

問題探索

讀 dm9621 MAC 地址失敗

在kernel的啟動資訊中可以看到dm9620 相關的啟動資訊中有這樣一條資訊:

(unregistered net_device): Error reading MAC address

這資訊來源在 呼叫usbnet_probe()函式(usbnet.c)中呼叫bind函式時讀取MAC地址失敗,目標網絡卡裝置未註冊。通過新增除錯來排查dm9620驅動註冊是否成功,下面是dm9620驅動註冊過程中函式呼叫關係:

usb_register()    // module_init(usb_register)
    usb_register_driver()    // 註冊一個 USB interface 驅動
        driver_register()    // 匯流排型驅動註冊(dm9620 是usb型別)
            bus_add_driver()    // 將驅動新增到匯流排(將dm9620驅動新增到usb匯流排)
                driver_attach()    // 將驅動繫結到裝置
                    bus_for_each_dev()    // 裝置迭代器,查詢所有的裝置,並呼叫回撥函式
                        __driver_attach()    // 繫結查詢到的裝置
                          driver_match_device()    // 實現驅動和裝置的匹配工作
                          driver_probe_device()    // 如果匹配成功會呼叫該函式,將裝置和驅動進行繫結

通過新增除錯資訊,在執行呼叫driver_match_device函式後會由於匹配dm9620驅動和裝置失敗返回,而不呼叫driver_probe_device函式進行裝置和驅動的繫結。分析到這就猜測是不是裝置的問題,通過使用lsusb命令,發現並沒有dm9621 的usb網絡卡裝置,因此推測應該是網絡卡裝置沒有被發現導致註冊失敗。而這個網絡卡裝置是通過usb3503A hub連線到開發板的,在使用lsusb命令時同樣沒有發現3053 usb裝置,因此呢這個usb裝置也沒有被發現。通過檢視usb3503A 的初始化操作,發現原始碼使用的GPIO引腳並非板子上usb3503 連結的引腳,因此需要修改usb3503A 的reset 和 connect 引腳:

// 位於板子配置初始化檔案中 arch/arm/mach-exynos/mach-smdk4x12.c
// usb_hub_gpio_init() 對usb3503 引腳進行初始化
- #define GPIO_HUB_RESET EXYNOS4_GPL2(2)
- #define GPIO_HUB_CONNECT EXYNOS4_GPK3(2)
+ #define GPIO_HUB_RESET EXYNOS4212_GPM2(4)
+ #define GPIO_HUB_CONNECT EXYNOS4212_GPM3(3)

通過修改上面的修改,重新編譯載入核心後,再次使用lsusb命令,可以檢視到已經發現了usb3503 和 dm9621 裝置: 在這裡插入圖片描述

網絡卡反覆斷開重連

通過之前的修改,雖然已經發現了網絡卡裝置,但是發現網絡卡裝置會發生2~3次的被發現和斷開,下面是kernel中dm9620驅動相關的啟動資訊: 在這裡插入圖片描述 這是怎麼回事呢?這種現象很像是多次插拔了usb網絡卡,通過開發板的原理圖發現,dm9621 的RSTB引腳是連結到4412晶片的GPC0_1 引腳,猜測可能該引腳被多次的配置,因為將這個引腳拉低會初始化dm9621 ,因此會造成這種類似的現象。通過搜尋,發現GPC0_1 在原碼中被當成其他引腳功能使用,因此將這些使用了該引腳程式碼註釋掉(在s3c-fb.c 和setup-fb-s5p.c中引用,原因是暫時還沒找到這些原碼應該使用哪個才是正確的引腳)。同時在板級初始化函式中新增對dm9621的初始化:

static void __init smdk4x12_machine_init(void)
{
……
+ #ifdef CONFIG_USB_NET_DM9620
+	dm9620_reset();
+ #endif
}
+ #ifdef CONFIG_USB_NET_DM9620
+ static void __init dm9620_reset(void)
+ {
+	int err = 0;

+	err = gpio_request_one(EXYNOS4_GPC0(1), GPIOF_OUT_INIT_HIGH, "DM9620_RESET");
+	if (err)
+		pr_err("failed to request GPC0_1 for DM9620 reset control\n");

+	s3c_gpio_setpull(EXYNOS4_GPC0(1), S3C_GPIO_PULL_UP);
+	gpio_set_value(EXYNOS4_GPC0(1), 0);
	
+	mdelay(1000); //dg change 5 ms to 1000ms for test dm9620 

+	gpio_set_value(EXYNOS4_GPC0(1), 1);
+	gpio_free(EXYNOS4_GPC0(1));
+}
+ #endif