初識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 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