免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: Godbach
打印 上一主题 下一主题

RTL8139网卡驱动程序分析[转] [复制链接]

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
31 [报告]
发表于 2009-04-15 17:29 |只看该作者
网上找到了一篇介绍PCI配置空间的访问方法,可以对照着理解第28的前一部分代码.

链接:http://blog.ednchina.com/tiloog/136959/message.aspx

访问配置空间可以采用两种方式:一是通过BIOS调用进行访问;二是在Intel CPU平台上可以通过I/O口进行访问。I/O访问方式比较简单。在开发PCI数据采集卡时,我采用了PLX公司提供的PLXMON软件对设备卡进行了调试,该软件可以访问设备卡的配置空间。另外,我又采用C语言编写了一段程序直接对配置空间进行了访问,效果不错,核心程序代码如下(需要注意的一点是,我当时在windows98平台上测试的,所以直接通过_inpd等函数访问IO端口,windows98之后IO端口对于应用程序进行了屏蔽~~只能在内核才能对IO端口进行访问):

#include <stdio.h>

#include <conio.h>

void main()

{

__u32 data,address;



address=0x80000000 + 9 * 8 * 0x100;  //插槽号为9

_outpd(0x0cf8, address);

data=_inpd(0x0cfc);

printf(“%x”, data);

address=0x80000004 + 9 * 8 * 0x100;  //访问第二个寄存器

_outpd(0x0cf8, address);

data=_inpd(0x0cfc);

printf(“%x”, data);

}

    0XCF8~0XCFB称为配置地址空间,0XCFC~0XCFF称为配置数据空间,这是两个双字空间,配置地址空间的格式如下:


最高位是配置访问使能位,要访问配置空间,使能位必须为1。位30到24为保留位,只读且为0,总线号用在一个系统中从256条总线中选择一条,对应系统引导时PCI期间列表中的BUS NO项,在PC机中,每个PCI插槽的设备号是固定的,而且互不相同。功能号用来选择多功能设备中的某一个功能,最多由8种功能供选择,单功能设备此项为0。寄存器号为配置空间寄存器的索引号。最低两位必须为0。

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
32 [报告]
发表于 2009-04-15 17:36 |只看该作者
在Linux下如果需要读取PCI设备的配置空间:
需要先通过如下的宏:
#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
        (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))

构造出配置空间的地址,然后将该地址写入地址0xCF8:
outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);

然后就可以从0xCFC地址中读取出对应配置空间寄存器的值,:
        switch (len) {
        case 1:
                *value = inb(0xCFC + (reg & 3));
                break;
        case 2:
                *value = inw(0xCFC + (reg & 2));
                break;
        case 4:
                *value = inl(0xCFC);
                break;
        }

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
33 [报告]
发表于 2009-04-16 17:11 |只看该作者
RTL8139中进行probe的函数如下:
static int __devinit rtl8139_init_one (struct pci_dev *pdev,
                                       const struct pci_device_id *ent)
{
       ......

        i = rtl8139_init_board (pdev, &dev);
        if (i < 0)
                return i;

        assert (dev != NULL);
        tp = netdev_priv(dev);

        ioaddr = tp->mmio_addr;
        assert (ioaddr != NULL);

        addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
        for (i = 0; i < 3; i++)
                ((u16 *) (dev->dev_addr)) =    le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len));
        memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
       //...
}


上面贴出的部分代码,rtl8139_init_board完成对网卡的一些初始化。然后表示网卡的结构体dev->base_addr指向了网卡的寄存器空间的起始地址。该地址开始的前6个字节是网卡的MAC地址。但不知道为什么随后还要通过 read_eeprom来读取网卡的MAC地址,并赋值给dev->dev_addr和dev->perm_addr。

[ 本帖最后由 Godbach 于 2009-4-16 17:13 编辑 ]

论坛徽章:
0
34 [报告]
发表于 2009-04-21 02:16 |只看该作者
另外一个关于 RTL8139驱动的讲解:
http://linuxgazette.net/156/jangir.html

我现在正按照上面的例子写一个自己的 RTL8139 驱动。但是中断一打开系统就死掉了。
上面的文章不足的地方是针对 2.4内核的。我现在在2.6下面测试,还是有些地方要改的。

LZ还在弄这个驱动么?有兴趣的话可以交流下。

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
35 [报告]
发表于 2009-04-21 09:51 |只看该作者
原帖由 accessory 于 2009-4-21 02:16 发表
另外一个关于 RTL8139驱动的讲解:
http://linuxgazette.net/156/jangir.html

我现在正按照上面的例子写一个自己的 RTL8139 驱动。但是中断一打开系统就死掉了。
上面的文章不足的地方是针对 2.4内核的。我 ...


我现在也是个人感兴趣,有时间的话自己分析分析。2.6下本身也是有代码的。大致对照着该文,在2.6下看就可以了。
不知道你为什么要再去写一个驱动?

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
36 [报告]
发表于 2009-04-21 16:01 |只看该作者
LZ还在弄这个驱动么?有兴趣的话可以交流下。


我在33楼的问题,不知道accessory兄能否解释一下?

论坛徽章:
0
37 [报告]
发表于 2009-04-21 23:14 |只看该作者
原帖由 Godbach 于 2009-4-16 17:11 发表
RTL8139中进行probe的函数如下:

上面贴出的部分代码,rtl8139_init_board完成对网卡的一些初始化。然后表示网卡的结构体dev->base_addr指向了网卡的寄存器空间的起始地址。该地址开始的前6个字节是网卡的 ...



注意:对于网卡来说,有2个地址。一个是IO读写的地址(这个所有得外设都有),还有一个是网卡特有的 MAC地址。
dev 是一个net_device结构。它的->base_addr保存的是IO读写地址。而它的dev_addr保存的是MAC地址。2个是不一样的。
具体可以参考LINUX DEVICE DRIVER 3RD EDITION, CHAPTER 17. PAGE 507

其实现在的 8139TOO.C 支持debug输出。在加载的时候,可以用这句:
modprobe 8139too debug=3
同时改 /etc/syslogd.conf,把里面的默认DEBUG输出的值改成“debug”,而不是“info". 就可以在 /var/log/messages里看到 8139TOO的输出了。
下面是在我的QEMU虚拟机里的输出:
eth0: RealTek RTL8139 at 0xf89c000, 52:54:00:12:34:56, IRQ 10.

上面的输出是由8130TOO.C里的这句打出来的:
1028 printk (KERN_INFO "%s: %s at 0x%lx, "
1029                "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
1030                "IRQ %d\n",
1031                dev->name,
1032                board_info[ent->driver_data].name,
1033                dev->base_addr,
1034                dev->dev_addr[0], dev->dev_addr[1],
1035                dev->dev_addr[2], dev->dev_addr[3],
1036                dev->dev_addr[4], dev->dev_addr[5],
1037                dev->irq);

PS:如果只想看上面的输出的话,MODPROBE时不带参数,不改SYSLOGD.CONF都可以。
目前我的测试环境:QEMU 0.10.2, GUEST OS:CentOS 5.3
另外,现在的在QEMU上的centos默认的是用8139CP.C来作为驱动的,大概因为QEMU模拟的8139比较新。如果想试8130too.c的话,需要先卸载8139cp

[ 本帖最后由 accessory 于 2009-4-21 23:26 编辑 ]

论坛徽章:
0
38 [报告]
发表于 2009-04-21 23:18 |只看该作者
原帖由 Godbach 于 2009-4-21 09:51 发表


我现在也是个人感兴趣,有时间的话自己分析分析。2.6下本身也是有代码的。大致对照着该文,在2.6下看就可以了。
不知道你为什么要再去写一个驱动?


我要把它的驱动改一改。其实直接在现在的源码上改也可以。呵呵

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
39 [报告]
发表于 2009-04-22 09:54 |只看该作者
一个是IO读写的地址(这个所有得外设都有),还有一个是网卡特有的 MAC地址。

但是从IO读写地址已经可以得到MAC地址了?

论坛徽章:
0
40 [报告]
发表于 2009-04-22 23:23 |只看该作者
原帖由 Godbach 于 2009-4-22 09:54 发表

但是从IO读写地址已经可以得到MAC地址了?


是的。不过没必要每次用到MAC地址时都去读硬件,那样效率太低。所以一般是读一次,保存在内存里。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP