通过二十、Linux驱动之移植DM9000C网卡驱动(上)对厂家提供的网卡驱动程序dm9dev9000c.c的分析,下面将该网卡驱动移植到JZ2440开发板上(内核版本为linux-2.6.22.6)。

1. 硬件分析

本人使用的开发板是JZ2440CPUS3C2440A,与DM9000C芯片连接如下:

    SD0~15:16位地址、数据线,由CMD引脚决定访问类型。
    CMD:命令线,当CMD为高表示传输的是数据,CMD为低表示传输的是地址
    INT:
中断引脚,接在2440GPF7脚上
    IOR#:
读引脚,接在2440nOE脚上
    IOW#:
写引脚,接在2440nWE脚上
    CS#:
片选,接在2440bank4的片选上面。

1.1 位宽选择

DM9000C支持两种位宽模式,8位宽和16位宽。选择不同的模式引脚接法不同。如下:


    通过选择DM9000的21号引脚是接上拉电阻还是浮空输入(低电平)来选择位宽模式,对于JZ2440开发板上的DM9000C的21号引脚浮空,选择的是16位宽模式。

1.2 BANK与片选信号

首先看到有16根数据线(地址线复用),这些数据线同样还连接到了开发板上的其他芯片(如SDRAM、NOR FLASH、NAND FLASH),当想要去读写DM9000C或者操作其他芯片时都在这些I/O引脚上发出信号,我们如何让他们之间不会互相干扰,正确控制自己想要控制的芯片呢?
    S3C2440A有一个存储控制器,如下图:

    接在地址线或数据线上的芯片可能有很多,不同的芯片都会有CE片选引脚,可以手动控制该引脚来选择操作的芯片。              
    S3C2440A帮我们省去了这一操作,S3C2440A通过将可寻址地址(物理地址)划分为8个内存块(每个内存块128MB,8*128MB=(2^27)B,所以S3C2440A地址线共有27根(LADDR0~26)),每个内存块都有一个片选信号(nGCS0~nGCS7),具体每一部分物理地址范围如上图。以第5个内存块物理地址0x2000 0000-0x2800 0000为例,当CPU读写该范围内的物理地址时,CPU会自动将nGCS4引脚拉低,挂在该片选信号线上的芯片就会被选中,本节所讲的DM9000就是挂在该内存块上,所以当CPU发出0x2000 0000-0x2800 0000的物理地址数据时,DM9000就会被选中。从这里也可以看出此时的DM9000C芯片基地址为0x2000 0000。

1.3 地址数据线共用

对于DM9000C芯片来说,读写地址与数据使用的是同一组16个I/O引脚,DM9000C芯片如何区分CPU读写的是地址还是数据呢?
    可以看到原理图中DM9000C的第32引脚CMD命令信号线连到CPU的地址线LADDR2上,也就是说当CPU发出物理地址(0x2000 0000-0x2800 0000)|0x4时,此时CPU再发出的数据线信号对于DM9000C来说实际是地址信号。例如:
    1. 当在地址0X2000 0000上读写数据时,表示读写的数据是DM9000C的地址
    2. 当访问的地址0X2000 0004上读写数据时,表示读写的数据是DM9000C的数据

1.4 中断信号

    DM9000C芯片的34号引脚INT中断信号引脚连接到2440GPF7,也就是接到CPU的外部中断线7上。当DM9000C收到外部的数据后,会暂存到内部地址中,然后产生一个上升沿中断,等待2440读取数据;当DM9000C2440的数据转发出去后,也会产生一个上升沿中断给2440

1.5 总结

1. DM9000C芯片物理基地址应设为0x20000000
    2. 中断号为EINT7
    3. 16
位总线宽度

2. 修改代码

2.1 修改代码为标准驱动格式

1. 添加宏定义“#define MODULE 1”如下:

2. 修改入口出口函数名,并增加模块装载卸载函数,如下:


2.2 修改硬件相关代码

2.2.1 修改iobase

iobase是一个全局static变量,也就是网卡的基地址(这里是虚拟地址),例如,在dmfe_probe1()函数中有如下代码:

/*#define DM9KS_VID_L        0x28#define DM9KS_VID_H     0x29#define DM9KS_PID_L     0x2A#define DM9KS_PID_H     0x2B
*/int __init dmfe_probe1(struct net_device *dev)
{... .../*获取ID*/outb(DM9KS_VID_L, iobase);        //地址总线输出iobase,数据总线输出0x28id_val = inb(iobase + 4);         //地址总线输出iobase+4,读入数据总线数据outb(DM9KS_VID_H, iobase);        //地址总线输出iobase,数据总线输出0x29id_val |= inb(iobase + 4) << 8;   //地址总线输出iobase+4,读入数据总线数据outb(DM9KS_PID_L, iobase);        //地址总线输出iobase,数据总线输出0x2Aid_val |= inb(iobase + 4) << 16;  //地址总线输出iobase+4,读入数据总线数据outb(DM9KS_PID_H, iobase);        //地址总线输出iobase,数据总线输出0x2Bid_val |= inb(iobase + 4) << 24;  //地址总线输出iobase+4,读入数据总线数据... ...
}

由硬件分析可知,我们的iobase的物理地址应设为0x20000000
      1. 当CPU地址总线输出iobase0x20000000(物理地址)时,DM9000Ccmd引脚为低电平,此时CPU数据总线输出的0x28对于DM9000来说表示读0x28地址
      2. 当CPU地址总线输出iobase+40x20000004(物理地址)时,DM9000Ccmd引脚为高电平,此时CPU数据总线输入输出对应读写DM9000C
    依次读地址也就是寄存器0x28、0x29、0x2A、0x2B,得到厂家ID和设备ID。所以需要我们根据硬件给它重新赋值(将实际物理地址转换为虚拟地址),在入口函数dm9dev9000c_init中添加代码如下:

iobase = (int)ioremap(0x20000000, 4096);    //重映射物理基地址0x2000 0000

在出口函数dm9dev9000c_exit中添加代码如下:

iounmap(iobase);

2.2.2 去掉版本判断

去掉下面dmfe_probe1()函数中这行芯片版本判断代码:   

2.2.3 修改中断

   dm9dev9000c_init函数中,添加修改中断号代码,将irq改为IRQ_EINT7,如下:

irq    = IRQ_EINT7;     //设置中断号为外部中断7

在上一节二十、Linux驱动之移植DM9000C网卡驱动(上)中分析dmfe_open()函数时提到,申请中断函数时默认的中断触发方式设置不对,应该改为“IRQF_TRIGGER_RISING”,上升沿触发,dmfe_open()函数中修改代码如下:

2.2.4 位宽(这里只做分析,不需要修改代码)

dmfe_start_xmit()函数中有如下代码:

/*#define DM9KS_DWORD_MODE   1#define DM9KS_BYTE_MODE    2#define DM9KS_WORD_MODE    0
*/static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev)
{... ...switch(db->io_mode)    //选择位宽模式{case DM9KS_BYTE_MODE:    //8-bit位宽模式for (i = 0; i < skb->len; i++)outb((data_ptr[i] & 0xff), db->io_data);break;case DM9KS_WORD_MODE:    //16-bit位宽模式tmplen = (skb->len + 1) / 2;for (i = 0; i < tmplen; i++)outw(((u16 *)data_ptr)[i], db->io_data);break;case DM9KS_DWORD_MODE:   //32-bit位宽模式tmplen = (skb->len + 3) / 4;          for (i = 0; i< tmplen; i++)outl(((u32 *)data_ptr)[i], db->io_data);break;}... ...
}

在硬件分析1.1中,我们分析了硬件上如何选择DM9000C位宽模式,如何让CPU知道我们选择了哪种位宽模式呢?在dmfe_init_dm9000()函数中有如下代码:

    这里通过读取DM9KS_ISR(宏定义为0xfe)中断状态寄存器第7位来读取位宽模式,我们可以从DM9000CEP芯片手册中看到:

2.2.4 设置2440相关寄存器

1. 设置BWSCON总线宽度控制寄存器
    因为DM9000C网卡接在2440BANK4上,所以要设置2440BANK4的硬件位宽、时序等。S3C2440A芯片手册有如下:

可得如下几点信息:
      1. 设置ST4=0,不使用UB/LB(表示高字节与低字节数据是否分开传输)。
      2. 设置WS4=0,其中WAIT引脚为PE4,而我们DM9000C没有引脚接入PE4,所以禁止。
      3. 设置DW4=0x01,我们的DM9000C的数据线为16位。
      4. BWSCON寄存器物理基地址为0x48000000。

2. 设置BANKCON4控制寄存器
    还需要设置BANKCON4控制寄存器。S3C2440A芯片手册有如下:
S3C2440A芯片手册有如下:

可得如下几点信息:
      1. 设置Tacs=0,因为CSCMD可以同时结束(bank4地址(也就是CMD)稳定多久后,CS片选才启动)。
      2. 设置Tcos=T1=0(CS片选后,多久才能使能读写)。
      3. 设置Tacc=T2>=10ns=1,表示2个时钟 (读写使能后,多久才能访问数据)  。
      4. 设置Tcoh=T4>=3ns=1,表示1个时钟 ,因为当DM9000C的写信号取消后,数据线上的数据还需要至少3ns才消失(nOE读写取消后,片选需要维持多长时间)。
      5. 设置Tcah=0,因为 CSCMD可以同时结束 (CS片选取消后,地址(也就是CMD)需要维持多长时间)。
      6. 设置PMC为0,正常模式。
      7. BANKCON4控制寄存器物理基地址为0x48000014
    对于该部分硬件相关的代码在dm9dev9000c_init()函数中添加如下红框部分:


    dm9dev9000c_init()函数完整修改代码如下:

int __init dm9dev9000c_init(void)
{volatile unsigned long *bwscon; // 0x48000000volatile unsigned long *bankcon4; // 0x48000014unsigned long val;iobase = (int)ioremap(0x20000000, 1024);  //重映射基地址irq    = IRQ_EINT7;   //修改中断号为IRQ_EINT7/* 设置S3C2440的memory controller */bwscon   = ioremap(0x48000000, 4);bankcon4 = ioremap(0x48000014, 4);/* DW4[17:16]: 1,16bit位宽* WS4[18]   : 0,WAIT disable* ST4[19]   : 0,不使用UB/LB*/val = *bwscon;val &= ~(0xf<<16);val |= (1<<16);*bwscon = val;//Tacc[10:8] : 设为1//Tcoh[7:6]  : 设为1//*bankcon4 = (1<<8)|(1<<6);  /* 对于DM9000C可以设Tacc为1, 对于DM9000E,Tacc要设大一点,比如最大值7  */*bankcon4 = (7<<8)|(1<<6);  /* MINI2440使用DM9000E,Tacc要设大一点 */iounmap(bwscon);iounmap(bankcon4);   switch(mode) {case DM9KS_10MHD:case DM9KS_100MHD:case DM9KS_10MFD:case DM9KS_100MFD:media_mode = mode;break;default:media_mode = DM9KS_AUTO;}dmfe_dev = dmfe_probe();if(IS_ERR(dmfe_dev))return PTR_ERR(dmfe_dev);return 0;
}

2.2.5 添加头文件

添加相关头文件,代码如下:

#include <asm/delay.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/arch-s3c2410/regs-mem.h>

这样代码就修改完成了,就下来进行编译测试。

3. 测试

内核:linux-2.6.22.6
编译器:arm-linux-gcc-3.4.5
环境:ubuntu9.10

1. 将dm9dev9000c.c拷贝到内核的linux-2.6.22.6/drivers/net目录里。
    2. 修改该目录里的Makefile,执行命令如下(我的内核放在/work/system/下):
      vi /work/system/linux-2.6.22.6/drivers/net/Makefile    (修改如下图)
   
    3. 重新编译内核,下载启动,就可以正常使用网卡了。
      make uImage
   
如下挂载网络文件系统启动,说明移植成功了。
   

二十一、Linux驱动之移植DM9000C网卡驱动(下)相关推荐

  1. 【移植驱动到Linux3.4.2内核之一】移植DM9000C网卡驱动

    学习交流加 个人qq: 1126137994 个人微信: liu1126137994 学习交流资源分享qq群: 962535112 之前已经把uboot,内核,文件系统,都移植好了,今天开始我们把第二 ...

  2. 基于嵌入式Linux的千兆以太网卡驱动程序设计及测试

    基于嵌入式Linux的千兆以太网卡驱动程序设计及测试 一. 引言 千兆以太网是一种具有高带宽和高响应的新网络技术,相关协议遵循IEEE 802.3规范标准.采用和10M以太网相似的帧格式.网络协议和布 ...

  3. 0 【Ubuntu/Linux】Ubuntu18.04有线连接图标不见(Linux系统安装2.5G有线网卡驱动,亲测避坑)

    前言 本人电脑安装的是windows10+Ubuntu18.04双系统,不是Linux虚拟机!!!!(虚拟机的网络问题需要看别的文章了) 本人的电脑是微星B560M MOTAR主板,该主板的网卡是2. ...

  4. 【uboot】imx6ull uboot移植LAN8720A网卡驱动

    文章目录 相关文章 1. 前言 2. IMX6ULL Ethernet LAN8720A硬件连接 3. 支持LAN8720A修改步骤 4. 验证测试 问题1:如何确定LAN8720A网卡PHYAD地址 ...

  5. ar8171 linux网卡驱动下载,ar8171 8175网卡驱动

    ar8171 8175网卡驱动下载.ar8171 8175网卡驱动是一款网卡驱动,适用于win7/8/10系统,ar8171 8175网卡驱动能够快速的进行所需的硬盘驱动,轻松的调用其内的各项功能! ...

  6. html安装网卡驱动,网卡驱动,详细教您网卡驱动怎么安装

    随着电脑的普及,现在很多人都喜欢使用电脑上网,而上网就需要网卡驱动,可见网卡驱动是电脑中非常重要的一个驱动,那么网络驱动怎么安装呢?下面,小编就来跟大家介绍安装网卡驱动的操作步骤. 安装网卡驱动的详细 ...

  7. linux 2440网卡驱动,Linux-2.6.30平台下移植DM9000网卡驱动到TQ2440

    平台:虚拟机Ubuntu 12.04  内核:linux-2.6.30 开发板:TQ2440 包括编译内核.制作文件系统,到目前可以在虚拟机上可以通过交叉网线可以和开发板互通,用了弄了差不多快两天时间 ...

  8. 以太网卡驱动程序移植linux,基于S3C2440的DM9000网卡驱动的移植

    摘  要: 主要研究了基于Linux内核的网卡驱动的移植.Linux网络设备驱动程序的体系结构可以分为4层,首先分析了各层的具体功能实现,并在此基础上充分利用S3C2440开发板完成DM9000网卡驱 ...

  9. 嵌入式Linux移植USB网卡驱动

    开发板:友善之臂smart210 操作系统:Ubuntu 12,04 交叉编译器:arm-none-linux-gnueabi gcc version 4.3.2 WIFI 模组:TP-LINK TL ...

最新文章

  1. POST与GET两种请求方式的区别:
  2. 烟台大学计算机学院老师,王鹏-烟台大学计算机与控制工程学院
  3. gulp html 压缩,gulp-gzip压缩
  4. python默认参数举例_Python之在函数中使用列表作为默认参数
  5. 【 CodeForces - 864B】Polycarp and Letters(水题,字符串,有坑)
  6. 医学图像分析相关的会议
  7. python信息传送管道_python – 获取返回管道输入的命令
  8. oracle展bom逻辑,oracle 求BOM树型展开的总用量
  9. 黑马程序员--java基础知识注意点收录
  10. 基于Linux平台的libpcap源码分析和优化
  11. centos安装VirtualBox增强包VBoxGuestAdditions
  12. JSONObject.fromObject - JSON与对象的转换
  13. 5分钟了解什么是自然语言处理技术
  14. Github注册教程
  15. BCH硬分叉已经成功完成,现在是入手的好时机吗?
  16. 家庭影院投影仪哪款值得买?2022年双11家庭影院4K投影仪首选当贝X3 Pro
  17. 从根节点到叶节点的路径数字之和
  18. [Swift]LeetCode1031. 两个非重叠子数组的最大和 | Maximum Sum of Two Non-Overlapping Subarrays...
  19. Alphasense B4系列PPB 级空气质量传感器应用
  20. FAST上网设置服务器未响应,fast路由器不能上网的解决方法

热门文章

  1. elementui 项目记录
  2. Openwrt/koolshare基于接口控制用户上网时间的方法
  3. Python all()函数
  4. Cisco路由器做限速
  5. halcon给图像添加不同颜色的透明遮罩(叠加透明ROI)
  6. 东软集团:与哈尔滨签署战略合作协议 围绕智慧城市健康城市合作
  7. RecyclerView的超强辅助Graywater——综合实操篇
  8. 简易的视频随机截屏程序
  9. openpyxl指定已有工作表的方法
  10. oracle 01221,ora-01221问题抛出引起的系列问题,还请赐教