概述

将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
Logo

更多推荐