历史上的今天
今天是:2024年11月10日(星期日)
2021年11月10日 | mini2440 dm9000 网卡驱动详解 (一)
2021-11-10 来源:eefocus
虽然Linux驱动程序应该是和具体的硬件平台分离的,但是为了更好的理解DM9000的驱动程序,这里还是结合一下Mini2440开发板,这样也可以更好的体会如何实现驱动和平台分离。
本文分成以下几个部分:
一、Mini2440开发板上DM9000的电气连接和Mach-mini2440.c文件的关系。
二、两个重要的结构体介绍:sk_buff和net_device
三、具体代码分析
一、Mini2440开发板上DM9000的电气连接和Mach-mini2440.c文件的关系
Mini2440开发板上DM9000与S3C2440的连接关系如下:

这个DM9000平台设备作为众多平台设备中的一个在扳子初始化的时候就被添加到了总线上。代码清单如下:
其中片选信号AEN使用了nGCS4,所以网卡的内存区域在BANK4,也就是从地址0x20000000开始。DM9000的TXD[2:0]作为strap pin在电路图中是空接的,所以IO base是300H。中断使用了EINT7。这些内容在Mach文件中有如下体现:
#define S3C2410_CS4 (0x20000000)
#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 + 0x300)
static struct resource mini2440_dm9k_resource[] __initdata = {
[0] = {
.start = MACH_MINI2440_DM9K_BASE,
.end = MACH_MINI2440_DM9K_BASE + 3,
.flags = IORESOURCE_MEM
},
[1] = {
.start = MACH_MINI2440_DM9K_BASE + 4,
.end = MACH_MINI2440_DM9K_BASE + 7,
.flags = IORESOURCE_MEM
},
[2] = {
.start = IRQ_EINT7,
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
}
};
另外在Mach文件中还定义了DM9000平台设备,设备名称为“dm9000”,设备资源就是上面定义的IO和中断资源。代码清单如下:
static struct dm9000_plat_data mini2440_dm9k_pdata __initdata = {
.flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
};
static struct platform_device mini2440_device_eth __initdata = {
.name = "dm9000",
.id = -1,
.num_resources = ARRAY_SIZE(mini2440_dm9k_resource),
.resource = mini2440_dm9k_resource,
.dev = {
.platform_data = &mini2440_dm9k_pdata,
},
};
MACHINE_START(MINI2440, "MINI2440")
/* Maintainer: Michel Pollet .phys_io = S3C2410_PA_UART, .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = mini2440_map_io, .init_machine = mini2440_init, /*初始化函数*/ .init_irq = s3c24xx_init_irq, .timer = &s3c24xx_timer, MACHINE_END static void __init mini2440_init(void) { ... ... platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices)); ... ... } static struct platform_device *mini2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_wdt, /* &s3c_device_adc,*/ /* ADC doesn't like living with touchscreen ! */ &s3c_device_i2c0, &s3c_device_rtc, &s3c_device_usbgadget, &mini2440_device_eth, /*dm9000是众多平台设备中的一个*/ &mini2440_led1, &mini2440_led2, &mini2440_led3, &mini2440_led4, &mini2440_button_device, &s3c_device_nand, &s3c_device_sdi, &s3c_device_iis, &mini2440_audio, /* &s3c_device_timer[0],*/ /* buzzer pwm, no API for it */ /* remaining devices are optional */ }; 二、两个重要的结构体简单介绍:sk_buff和net_device *sk_buff 如果把网络传输看成是运送货物的话,那么sk_buff就是这个“货物”了,所有经手这个货物的人都要干点什么事儿,要么加个包装,要么印个戳儿等等。收货的时候就要拆掉这些包装,得到我们需要的货物(payload data)。没有货物你还运输什么呢?由此可见sk_buff的重要性了。关于sk_buff的详细介绍和几个操作它的函数,参考:“linux内核sk_buff的结构分析” http://www.linuxidc.com/Linux/2011-07/39163.htm,写得非常明白了。赞一个~ *net_device 又是一个庞大的结构体。好吧,我承认我从来就没有看全过这个结构体。它在内核中就是指代了一个网络设备。驱动程序需要在探测的时候分配并初始化这个结构体,然后使用register_netdev来注册它,这样就可以把操作硬件的函数与内核挂接在一起。 三、具体代码的分析 在顺序分析之前先看三个结构体变量和一个自定义的结构体。 * dm9000_driver变量。是platform_driver结构体变量,其中包含了重要的:驱动的名字(用来match)和几个重要操作函数。 static struct platform_driver dm9000_driver = { .driver = { .name = "dm9000", .owner = THIS_MODULE, }, .probe = dm9000_probe, .remove = __devexit_p(dm9000_drv_remove), .suspend = dm9000_drv_suspend, .resume = dm9000_drv_resume, }; * dm9000_netdev_ops变量。是net_device_ops结构体变量, 其中定义了操作net_device的重要函数,我们在驱动程序中根据需要的操作要填充这些函数。代码清单如下: static const struct net_device_ops dm9000_netdev_ops = { .ndo_open = dm9000_open, .ndo_stop = dm9000_stop, .ndo_start_xmit = dm9000_start_xmit, .ndo_tx_timeout = dm9000_timeout, .ndo_set_multicast_list = dm9000_hash_table, .ndo_do_ioctl = dm9000_ioctl, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = dm9000_poll_controller, #endif }; * dm9000_ethtool_ops变量。是ethtool_ops结构体变量,为了支持ethtool,其中的函数主要是用于查询和设置网卡参数(当然也有的驱动程序可能不支持ethtool)。代码清单如下: static const struct ethtool_ops dm9000_ethtool_ops = { .get_drvinfo = dm9000_get_drvinfo, .get_settings = dm9000_get_settings, .set_settings = dm9000_set_settings, .get_msglevel = dm9000_get_msglevel, .set_msglevel = dm9000_set_msglevel, .nway_reset = dm9000_nway_reset, .get_link = dm9000_get_link, .get_eeprom_len = dm9000_get_eeprom_len, .get_eeprom = dm9000_get_eeprom, .set_eeprom = dm9000_set_eeprom, }; *board_info结构体。用来保存芯片相关的一些私有信息。具体在代码中分析。下面是这个结构体的清单。 /* Structure/enum declaration ------------------------------- */ typedef struct board_info { void __iomem *io_addr; /* Register I/O base address */ void __iomem *io_data; /* Data I/O address */ u16 irq; /* IRQ */ u16 tx_pkt_cnt; u16 queue_pkt_len; u16 queue_start_addr; u16 dbug_cnt; u8 io_mode; /* 0:word, 2:byte */ u8 phy_addr; u8 imr_all;
史海拾趣
|
整理下裁员/倒闭行业类别~有个快消招聘,找工作的来~ 奢侈品行业的情况有谁知道? 最近裁员倒闭的一片片,实在看的太多了,整理下下,有补充的可以跟贴,一并列举上。 也给要找的在找的将要找工作的人一点点参考。 申明: 本来的确打算一直做,因为都是大家提供的消息,但是似乎现在有些不同的“凡响”,我无意争什么,所以, ...… 查看全部问答> |
|
准备上个项目,人手不够,打算找人合作。 杭州有产品经验,有业余时间,熟悉工业级ARM,51,tcp/ip,RTOS等之一的技术便可。 有兴趣的回个贴。 技术专长,业余时间,要求等。 sssbang@163.com … 查看全部问答> |
|
//向服务器提交数据 void CRDAExamDlg::OnBtnpush() { ISSCERDA*pCERDA = NULL; BSTR bStr = NULL; BSTR bConnectStr = NULL; ...… 查看全部问答> |
|
广东北电做vxwork应用,小公司做嵌入式linux应用,该选择哪个? 广东北电做vxwork应用,小公司做嵌入式linux应用,该选择哪个? 其中小公司离家很近,北电离家远一点(隔壁城市) 本人有嵌入式linux两年经验了 两者待遇差不多… 查看全部问答> |
|
目标板是基本最小系统+JTAG部分,所以很多部分都要自己动手来完成了! 数控电源人机界面 1、数码管+键盘; 2、LCD+键盘; 3、PC小工具; 预留PWM,ADC,COMP功能的外围脚 [ ...… 查看全部问答> |




