2410平台上dm9000a网卡驱动分析
- 格式:doc
- 大小:137.00 KB
- 文档页数:20
WindowsCE6.0的DM9000A流接口驱动开发谢秋金;李晓菲;李康玉;尚秋峰【期刊名称】《单片机与嵌入式系统应用》【年(卷),期】2012(12)5【摘要】针对WindowsCE系统下专用网络驱动接口开发难度大的情况,本文介绍一种基于WindowsCE流接口驱动的工作机制及开发方法。
相比于WindowsCE对各种硬件设备所提供的专用接口,流接口驱动具有更大的灵活性,且能够实现应用层到底层硬件的控制。
以含有ARMll内核的S3C6410结合以太网通信芯片DM9000A为例,逐步分析流接口驱动程序的开发流程,并利用PC 机抓取以太网通信数据,验证了流接口驱动程序开发的正确性。
%According to the difficulty of dedicated network driver interface development in Windows CE System, this paper introduces the working mechanism and development method of stream interface driver based on Windows CE. Compared to dedicated interfaces of all kinds of hardware devices provided by Windows CE, stream interface driver has strong flexibility, and it can realize the control from application layer to hardware. The development process of stream interface driver is analyzed based onS3C6410 with ARMll core and Ethernet communication chip DM9000A. Ethernet communication data from PC show the correctness of the stream interface driver development.【总页数】4页(P78-81)【作者】谢秋金;李晓菲;李康玉;尚秋峰【作者单位】华北电力大学电子与通信工程系,保定071003;华北电力大学电子与通信工程系,保定071003;华北电力大学电子与通信工程系,保定071003;华北电力大学电子与通信工程系,保定071003【正文语种】中文【中图分类】TP316【相关文献】1.基于WinCE的车载智能显示终端CAN流接口驱动开发 [J], 穆云丽;王立德;宋娟2.WinCE5.0的USB Camera流接口驱动开发 [J], 李君懿;赵利;邹柏程3.基于MicroBlaze和DM9000A的以太网接口设计 [J], 刘鸣4.基于DM9000A的DSP6711以太网接口扩展 [J], 闫法钢; 李江涛; 周晓燕5.基于STM32的DM9000A网络接口裸机的应用研究 [J], 乔有田;王俊;邵万灵;张涛因版权原因,仅展示原文概要,查看原文内容请购买。
安装网卡驱动的方法安装网卡驱动的方法可以分为以下几个步骤:1. 获取正确的网卡驱动程序。
你可以在电脑网卡的生产商官方网站上下载对应的驱动程序,也可以使用电脑自带的驱动光盘。
2. 打开设备管理器。
在Windows系统中,可以按下Win + X键,选择“设备管理器”打开设备管理器。
3. 找到网卡设备。
在设备管理器中,展开“网络适配器”类别,找到你要安装驱动的网卡设备。
4. 右键点击网卡设备,选择“更新驱动程序”。
在弹出的菜单中,选择“自动搜索更新的驱动程序软件”。
5. 如果驱动程序已经在你的电脑上,系统会自动搜索并安装最新的驱动程序。
如果没有找到合适的驱动程序,你可以选择手动安装驱动程序。
6. 手动安装驱动程序。
当系统无法自动搜索到驱动程序时,你可以选择手动安装驱动程序。
在右键点击网卡设备后,选择“更新驱动程序”,然后选择“浏览我的计算机以查找驱动程序软件”。
7. 在弹出的对话框中,选择“让我从计算机上的可用驱动程序列表中选择”。
然后点击“浏览”按钮,找到你下载好的驱动程序所在的文件夹。
8. 选择正确的驱动程序。
在弹出的可选驱动程序列表中,选择你下载好的驱动程序,点击“下一步”进行安装。
9. 等待驱动程序安装完成。
系统会自动安装驱动程序,你只需要按照提示进行操作。
安装完成后,网卡设备应该被正确识别和驱动。
10. 重启电脑。
驱动程序的安装可能需要重启电脑,以确保驱动程序的正常运行。
安装完成后,你的网卡设备应该能够正常工作了。
如果仍然有问题,可以尝试重新安装驱动程序或者更新系统。
自己编写bootloaderbootloader从flash上把bootloader读取内存(包括有flash的读写、初始化内存SDRAM、同时也会初始化时钟,关闭看门口,启动则就是地址跳转,设置参数)最简单的bootloader1.关看门狗,设置时钟、设置SDRAM、设置NAND FLASH,2.把内核从NAND FLASH(开发板配置的nor flash比较小,没法写入内核)3.设置要传给内核的参数4.跳转执行U-boot制作从start.s文件开始分析。
下载下来的u-boot只有s3c2410,所以需要自己修改1.把board(单板)下面的2410拷贝成2440.2.拷贝配置文件,在include-configs把smdk2410_config.h拷贝成smdk2440_config.h3.如果此时make smdk2440_config,会提示没有规则的错误,需要修改其他文件4.搜索带smdk2410内容的文件grep“smdk2410”*-nR---可以看到boads.cfg中有相关内容,模仿2410来写。
5.修改过后,就可以make了。
编译通过后,进行调试,看什么地方出错。
1.在sourceinsight中添加新添加的内容。
2.分析错误,根据启动流程一步一步的进行。
3.start.s里面一些初始化代码修改,用之前裸机写的代码来替换部分初始化。
4.串口乱码,发现在get_HCLK里面没有定义config_s3c2440U-BOOT移植1.在http://www.denx.de/wiki/U-Boot/SourceCode中下载最新u-boot2.放入服务器/work/system目录下。
3.解压u-boot。
4.同时也在window下解压出来,建立sourceinsiged工程。
5.sourceinsiged中先把所有加入,然后把board中只保留summary的2410,Arch目录下只保留Arch/arm/cpu/arm920t(因为2440用的arm920t)6.在根目录下执行make smdk2410_config(配置)7.编译,执行make(全局编译)8.编译不能通过,有可能是编译器版本比较低的缘故。
1、先看芯片手册,弄懂dm9000基本工作原理和寄存器含义之后,再看代码2、看代码时用source insight,可以快速查看定义,代码的大致流程如下,其中标红的函数再仔细看看。
3、先把关于VxWorks驱动介绍的PPT做好,介绍大体框架,具体的程序不用着急着一步到位dm9000start()cpuForDM9000Init() →配置CPU,使用EINT7SYS_INT_CONNECT (pDrvCtrl, dm9000Int, (int)pDrvCtrl, &result); →注册中断处理函数dm9000IntintEnable (pDrvCtrl->ilevel); →使能该设备的中断/* Activate DM9000 */ →配置dm9000的0x05和0xff寄存器DM9000_OUT_CHAR( 0x05, DM9000_REG05 ); /* RX enable */DM9000_OUT_CHAR( 0xff, DM9000_REGFF );/* Enable TX/RX interrupt mask */dm9000Stop →→ dmfe_stop_dm9000( pDrvCtrl );→ cpuForDm9000disable();配置CPU,设置EINT7掩码→ SYS_INT_DISCONNECT (pDrvCtrl, dm9000Int, &result);注销中断函数dm9000Int→中断处理函数(详细分析。
)接收→netJobAdd ((FUNCPTR)dm9000HandleRcvInt, (int)pDrvCtrl, 0,0,0,0);→dm9000HandleRcvInt→dm9000Recv(详细分析。
vxworks网络数据结构MBlock)→dmfe_packet_receive发送→DM9000_OUT_CHAR( 0xfc, pDrvCtrl->queue_pkt_len & 0xff );→DM9000_OUT_CHAR( 0xfd, (pDrvCtrl->queue_pkt_len >> 8) & 0xff ); dm9000Send→intLock ()→dmfe_start_xmit( &skb, pDrvCtrl )→intUnLock ()dm9000PollStart →启动dm9000轮询模式dm9000PollRcv →轮询方式接收数据→ dmfe_packet_receive(详细分析。
DM9000⽹卡的基本⼯作原理MAC:主要负责数据帧的创建,数据差错,检查,传送控制等。
PHY:物理接⼝收发器,当收到MAC过来的数据时,它会加上校验码,然后按照物理层的规则进⾏数据编码,再发送到传输介质上,接收过程则相反。
MII:媒体独⽴接⼝,“媒体独⽴”表明MAC⼀定情况下,任何类型的PHY设备都可以正常⼯作。
DM9000⽹卡部分函数实现:/*//实验步骤//初始化dm900//数据包发送//数据包接收*/#include "dm9000.h"#include "arp.h"#define DM_ADD (*((volatile unsigned short *)0x18000000))#define DM_DAT (*((volatile unsigned short *)0x18000004))/*Register*/#define MEM_SYS_CFG (*(volatile unsigned *)0x7E00F120)#define SROM_BW (*(volatile unsigned *)0x70000000)#define SROM_BC1 (*(volatile unsigned *)0x70000008)#define GPNCON (*(volatile unsigned *)0x7F008830) /* 中断相关寄存器 */#define EINT0CON0 (*(volatile unsigned *)0x7F008900)#define EINT0MASK (*(volatile unsigned *)0x7F008920)#define EINT0PEND (*(volatile unsigned *)0x7F008924)#define VIC0INTENABLE (*(volatile unsigned *)0x71200010)#define EINT7_VECTADDR (*(volatile unsigned *)0x71200104)#define VIC0ADDRESS *((volatile unsigned int *)0x71200f00)#define VIC1ADDRESS *((volatile unsigned int *)0x71300f00)u8 *buffer = &arpbuf;u8 host_mac_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};u8 mac_addr[6] = {9,8,7,6,5,4};u8 ip_addr[4] = {192,168,1,113};u8 host_ip_addr[4] = {192,168,1,101};u16 packet_len;void cs_init(){// MEM_SYS_CFGSROM_BW &= (~(1<<4)); //设置位宽度SROM_BW |= (1<<4);SROM_BC1 = (0x0<<28)|(0x0<<24)|(0x7<<16)|(0x0<<12)|(0x0<<8)|(0x0<<4)|(0x0<<0); //设置时序参考uboot ok6410的⽹卡⽚选位于bank1 }void int_init() //中断初始化{GPNCON &= (~(0x3<<14));GPNCON |= (0x2<<14);// EINT0PEND &= (~(0x1<<7));// EINT0PEND |= (0x1<<7);}void dm9000_reg_write(u16 reg,u16 data){DM_ADD = reg;DM_DAT = data;}u8 dm9000_reg_read(u16 reg){DM_ADD = reg;return DM_DAT;}void dm9000_reset(){dm9000_reg_write(DM9000_GPCR, GPCR_GPIO0_OUT);dm9000_reg_write(DM9000_GPR, 0);dm9000_reg_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));dm9000_reg_write(DM9000_NCR, 0);dm9000_reg_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));dm9000_reg_write(DM9000_NCR, 0);}void dm9000_probe(void){u32 id_val;id_val = dm9000_reg_read(DM9000_VIDL);id_val |= dm9000_reg_read(DM9000_VIDH) << 8;id_val |= dm9000_reg_read(DM9000_PIDL) << 16;id_val |= dm9000_reg_read(DM9000_PIDH) << 24;if (id_val == DM9000_ID) {printf("dm9000 is found !\n");return ;} else {printf("dm9000 is not found !\n");return ;}}void dm9000_init(){u32 i;/*⽚选(独⽴芯⽚)*/cs_init();/*中断初始化*/int_init();/*设备复位操作*/dm9000_reset();/*捕获dm9000*/dm9000_probe();/*MAC初始化*//* Program operating register, only internal phy supported */dm9000_reg_write(DM9000_NCR, 0x0);/* TX Polling clear */dm9000_reg_write(DM9000_TCR, 0);/* Less 3Kb, 200us */dm9000_reg_write(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);/* Flow Control : High/Low Water */dm9000_reg_write(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));/* SH FIXME: This looks strange! Flow Control */dm9000_reg_write(DM9000_FCR, 0x0);/* Special Mode */dm9000_reg_write(DM9000_SMCR, 0);/* clear TX status */dm9000_reg_write(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);/* Clear interrupt status */dm9000_reg_write(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);/*填充MAC地址*/for (i = 0; i < 6; i++)dm9000_reg_write(DM9000_PAR+i, mac_addr[i]);/*激活DM9000*/dm9000_reg_write(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);/* Enable TX/RX interrupt mask */dm9000_reg_write(DM9000_IMR, IMR_PAR);}void dm9000_tx(u8 *data,u32 length){u32 i;/*禁⽌中断*/dm9000_reg_write(DM9000_IMR,0x80);/*写⼊发送数据的长度*/dm9000_reg_write(DM9000_TXPLL, length & 0xff);dm9000_reg_write(DM9000_TXPLH, (length >> 8) & 0xff);/*写⼊待发送的数据*/DM_ADD = DM9000_MWCMD; // MWCMD是DM9000内部SRAM的DMA指针,根据处理器模式,写后⾃动增加for(i=0;i<length;i+=2){DM_DAT = data[i] | (data[i+1]<<8); //低8 ⾼8}/*启动发送*/dm9000_reg_write(DM9000_TCR, TCR_TXREQ);/*等待发送结束*/while(1){u8 status;status = dm9000_reg_read(DM9000_TCR);if((status&0x01)==0x00)break;}/*清除发送状态*/dm9000_reg_write(DM9000_NSR,0x2c);/*恢复中断使能*/dm9000_reg_write(DM9000_IMR,0x81);// printf("dm9000_tx");}#define PTK_MAX_LEN 1522u32 dm9000_rx(u8 *data){u8 status,len;u16 tmp;u32 i;/*判断是否产⽣中断,且清除*/if(dm9000_reg_read(DM9000_ISR) & 0x01)dm9000_reg_write(DM9000_ISR,0x01);elsereturn0;/*空读*/dm9000_reg_read(DM9000_MRCMDX);/*读取状态*/status = dm9000_reg_read(DM9000_MRCMD);/*读取包长度*/len = DM_DAT;/*读取包数据*/if(len<PTK_MAX_LEN){for(i=0;i<len;i+=2){tmp = DM_DAT;data[i] = tmp & 0x0ff;data[i+1] = (tmp>>8)&0x0ff; }}return len;}。
基于RTEMS的网络驱动程序设计【摘要】网络互联已深入多个领域,而RTEMS实时操作系统对网络设备的支持却明显不足。
为添加RTEMS对网络的支持,充分利用RTEMS的性能。
首先对RTEMS网络设备驱动的运行机理进行了分析,介绍了网络设备驱动开发的框架。
然后在RTEMS平台中实现DM9000A网络接口卡驱动,结合网络驱动的实例重点分析了RTEMS系统下网路驱动程序的开发方法。
最后使得DM9000A 在RTEMS平台下能够正常编译,且通过实验来验证实现的可行性和有效性。
【关键词】RTEMS;实时系统;DM9000A网络接口卡;网络驱动1.引言RTEMS(Real-Time Executive for Multiprocessor Systems)是一个开放源代码的实时嵌入式操作系统,对各类主流的嵌入式平台都有良好的支持[1]。
为了添加RTEMS平台的网络应用功能,需要设计出合理的网络设备驱动程序。
为了满足RTEMS平台的驱动模型,必须对其组织组织框架有所理解。
由于RTEMS是开源的,这使得可以对其网络驱动模块部分进行分析和移植以满足不同的应用需求。
本文通过对RTEMS网络源码的分析,并结合DM9000A驱动的实例,探讨了如何为RTEMS添加网络驱动。
2.RTEMS的网络模块RTEMS网络栈基于BSD,并提供了绝大部分BSD的网络服务。
网络应用程序通过套接字(socket)接口来实现本地及网络设备间的通信。
应用程序通过网络模块与底层驱动进行交互,是无法直接访问网络设备的。
2.1 网络驱动运行机理不同于RTEMS平台的其他设备驱动,网络设备驱动不是交由IO管理器管理的,而是由BSD协议栈实现管理的。
如图1所示,由上之下,RTEMS网络栈分为网络协议接口层、网络设备接口层、设备驱动接口层,以及网络设备驱动层。
图1 RTEMS网络驱动框架网络设备驱动层提供访问物理设备的具体驱动程序。
设备驱动接口层,向上为上层提供访问设备的接口,向下提供统一的驱动程序调用接口,通过if_start 函数接口启动发送,通过设备的中断来触发具体的收、发操作。
基于DM9000A和LPC2214的嵌入式以太网接口设计排行榜收藏打印发给朋友举报来源:elenchina 发布者:刘伟明、杜林热度8票浏览180次【共0条评论】【我要评论】时间:2009年6月08日16:34引言互联网的迅速发展使得网络用户呈指数增长,在使用计算机进行网络互联的同时,各种家电设备、仪器仪表以及工业生产中的数据采集与控制设备也在逐步地走向网络化,以便共享网络中庞大的信息资源。
以太网技术以其灵活方便的连接方式、良好的开放性、高效、低廉等优点,已经广泛地应用于各种计算机网络,并且还在不断地发展。
目前基于以太网的新技术和联网设备不断出现,以太网已经成为事实上最常用的网络标准之一。
以太网控制芯片是以太网接口的核心器件,其性能是影响网络性能的关键的因素之一,如何正确使用网络控制器是设计以太网接口的关键。
本文介绍了一种以高性能的以太网控制芯片DM9000A和32位ARM处理器LPC2214为核心的嵌入式以太网接口的实现方法。
1、以太网控制器DM9000A介绍DM9000A是DA VICOM公司推出的一种高度集成、功能强大、少引脚、性价比高的单片快速以太网控制芯片,非常适用于嵌入式系统设计。
图1为DM9000A内部结构框图。
DM9000A具有一个通用的微处理器接口,内部集成了16kB SRAM(其中13kB用作接收缓冲区,3kB作为发送缓冲区),对内部存储器访问支持8位和16位数据接口以适用于不同的微处理器;内部集成了一个10/100M自适应PHY,可以连接到3类、4类、5类的10M无屏蔽双绞线和5类的100M无屏蔽双绞线。
图1 DM9000A内部结构框图DM9000A体积小,只有48个引脚,有利于缩小PCB面积;它完全支持IEEE802.3u规格,还支持IEEE802.3x全双工流控制。
DM9000A功耗非常低,单电源3.3V工作,内置 3.3V 变2.5V电源电路,I/O端口支持3.3V到5V的容差。
JZ2440学习笔记Chili2015.5前言本人入手JZ2440半个月,以前未接触过linux,但在校接触过许多不跑linux系统的CPU,具有LPC1114,LPC1343,STM32,blackfin等处理器的编程经验,对微处理器的原理以及运行方式具有一定的了解。
靠着这点小经验,以及新学习的知识,自己动手移植了最新的uboot,绝对原创,得益于韦老师的书籍以及开发板,能让我们这个小白可以踏进linux的世界,但本人毕竟在linux方面只是个类似小白的学生,许多不对之处,希望大家不吝指教!说明:阅读本文需要一点的ARM以及S3C2440的基础知识,建议先阅读《嵌入式Linux应用开发完全手册》,此书对对ARM以及JZ2440有很好的介绍和说明,在阅读中有不懂的也可以再去翻看此书,查漏补缺。
JZ2440移植最新u-boot-2015.04-rc4.tar1,配置uboot去官网下载最新uboot源代码u-boot-2015.04-rc4.tar,开发环境采用JZ2440光盘上的vmware 虚拟机ubuntu9.10。
本次采用smdk2410的默认配置来配置uboot,然后启动类似linux一样的menuconfig菜单进行配置,然后make,并烧写进JZ2440看效果,然后根据现象一步步修改。
我们移植uboot的基本原则是:因为我们刚上手,可能什么都不知道,更加不知需要更改什么,这个时候我们就先尽量什么都不改,直接烧写进去看现象,然后根据现象或者提示信息一步步更改,从而移植完成。
配置命令如下:book@book-desktop:~/uboot/u-boot-2015.04-rc4$ tar jxvf u-boot-2015.04-rc4.tar.bz2book@book-desktop:~/uboot/u-boot-2015.04-rc4$ cd u-boot-2015.04-rc4/book@book-desktop:~/uboot/u-boot-2015.04-rc4$ make smdk2410_defconfigbook@book-desktop:~/uboot/u-boot-2015.04-rc4$ make menuconfig3,在uboot根目录执行book@book-desktop:~/uboot/u-boot-2015.04-rc4$ make报错:cc1: error: bad value (armv4) for -march= switchcc1: error: bad value (armv4) for -mtune= switchmake[2]: *** [include/autoconf.mk] Error 1make[1]: *** [silentoldconfig] Error 1make: *** No rule to make target `include/config/auto.conf', needed by `include/config/uboot.release'. Stop.错误并不可怕,学会看错误提示,根据提示进行下一步工作。
2410平台上dm9000a网卡驱动分析 该驱动基于linux-2.6.24.4内核。
首先,需要在arch/arm/mach-s3c2410/mach-smdk2410.c文件中添加如下代码:
static struct resource s3c_dm9000_resource [] = { [0] = { .start = 0x10000000, .end = 0x10000040, .flags = IORESOURCE_MEM }, [1] = { .start = IRQ_EINT2, .end = IRQ_EINT2, .flags = IORESOURCE_IRQ, } };
注意上面的start、end等地址是指的网卡的物理地址。然后,还要在该文件中加入如下代码: struct platform_device s3c_device_dm9000 = { .name = "dm9000", .id = -1, .num_resources = ARRAY_SIZE(s3c_dm9000_resource), .resource = s3c_dm9000_resource, };
需要特别注意上面的name字段,当设备驱动程序寻找设别资源时,会根据该字段对设备进行匹配。另外,该文件中的smdk2410_devices[]数组中,还需要加入s3c_device_dm9000,不然系统启动时没有找到该资源就不会调用相应的probe函数。
下面分析驱动程序的probe函数。若驱动被编译进内核,则在系统启动的时候,该函数会被调用。该函数的源代码如下:
static int dm9k_drv_probe(struct platform_device *pdev) { struct net_device *ndev; unsigned long base; unsigned int *addr = NULL; int ret = -ENODEV; ndev = alloc_etherdev(sizeof(struct board_info)); if (!ndev) { printk("%s: could not allocate device.\n", CARDNAME); return -ENOMEM; }
ndev->dma = (unsigned char)-1; if (pdev->num_resources < 2 || pdev->num_resources > 3) { printk("DM9000: Wrong num of resources %d\n", pdev->num_resources); ret = -ENODEV; goto out; } base = pdev->resource[0].start; ndev->irq = pdev->resource[1].start; /* * Request the regions. */ if (!request_mem_region(base, 4, ndev->name)) { ret = -EBUSY; goto out; }
addr = ioremap(base, 4); if (!addr) { ret = -ENOMEM; goto release_mem; } ret = dm9k_probe(ndev, (unsigned long)addr); if (ret != 0) { iounmap(addr); release_mem: release_mem_region(base, 4); out: printk("%s: not found (%d).\n", CARDNAME, ret); kfree(ndev); } return ret; }
函数首先调用alloc_etherdev,该函数在include/linux/etherdevice.h中声明,其中有如下语句: #define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1) 而alloc_etherdev_mq函数又定义在net/ethernet/eth.c中,如下: struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count) { return alloc_netdev_mq(sizeof_priv, "eth%d", ether_setup, queue_count); }
可见,该函数只是用自己的参数来调用alloc_netdev_mq函数。alloc_netdev_mq函数定义在net/core/dev.c中,原型如下:
struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, void (*setup)(struct net_device *), unsigned int queue_count)
关于该函数的说明: /** * alloc_netdev_mq - allocate network device * @sizeof_priv: size of private data to allocate space for * @name: device name format string * @setup: callback to initialize device * @queue_count: the number of subqueues to allocate * * Allocates a struct net_device with private data area for driver use * and performs basic initialization. Also allocates subquue structs * for each queue on the device at the end of the netdevice. */
可见,alloc_etherdev为设备驱动分配了私有数据空间,并对设备驱动做了一些初始化工作。
接下来,设备驱动将要检查设备的resources的数量,如果数量小于2或者大于3,则初始化函数自动返回,初始化失败。我们的设备驱动中,resources的数量为2:一个表示设备的IO地址,另一个是设备的中断号。
代码
base = pdev->resource[0].start; ndev->irq = pdev->resource[1].start;
分别得到设备的端口地址和中断号。 接下来,驱动程序将向系统申请io内存,从地址base开始,大小为4个字节。如果申请成功,接下来需要做的就是将地址重新映射,从地址base开始,长度为4个字节。这样做的原因主要是驱动程序一般不直接访问物理地址,而访问虚拟地址。地址重新映射成功后,就调用dm9k_probe函数进行设备初始化。
dm9k_probe函数的全部代码如下 int __init dm9k_probe(struct net_device *dev, unsigned long addr) { struct board_info *db; /* Point a board information structure */ u32 id_val; u16 i, j; int retval; /* Search for DM9000 serial NIC */ PUTB(DM9KS_VID_L, addr); id_val = GETB(addr + 2); /* Change offset to 2 ^^^^^ */ PUTB(DM9KS_VID_H, addr); id_val |= GETB(addr + 2) << 8; PUTB(DM9KS_PID_L, addr); id_val |= GETB(addr + 2) << 16; PUTB(DM9KS_PID_H, addr); id_val |= GETB(addr + 2) << 24; if (id_val != DM9KS_ID && id_val != DM9010_ID) { /* Dm9k chip not found */ printk("dmfe_probe(): DM9000 not found. ID=%08X\n", id_val); return -ENODEV; }
printk(" I/O: %lx, VID: %x \n",addr, id_val); /* Allocated board information structure */ memset(dev->priv, 0, sizeof(struct board_info)); db = (board_info_t *)dev->priv; dmfe_dev = dev; db->io_addr = addr; db->io_data = addr + 2; /* Change offset to 2 ^^^^^ */ /* driver system function */
dev->base_addr = addr; dev->irq = IRQ_EINT2; dev->open = &dmfe_open; dev->hard_start_xmit = &dmfe_start_xmit; dev->watchdog_timeo = HZ; dev->tx_timeout = dmfe_timeout; dev->stop = &dmfe_stop; dev->get_stats = &dmfe_get_stats; dev->set_multicast_list = &dm9000_hash_table; dev->do_ioctl = &dmfe_do_ioctl; for(i=0,j=0x10; i<6; i++,j++) { db->srom[i] = ior(db, j);