RTL8139网卡驱动程序分析[转]
时间:2009-03-30
来源:互联网
原文链接: http://www.xfocus.net/articles/200707/931.html
创建时间:2007-07-27 更新时间:2007-07-28
文章属性:原创
文章提交:Addylee (Addylee2004_at_163.com)
本文以Linux内核中8139网卡驱动为例,对驱动程序的工作过程进行详细的分析,为初学者拨开迷雾,走出雾里看花的迷茫。本文虽然以Linux驱动为例,但是技术总是相通的,为了给Windows驱动初学者同样的启发,我有意的借用了许多Windows驱动中的名词,同时顺便略述了Windows驱动中的一些容易让初学者感到迷惑的概念。
根据sinister的建议,在接收部分加入了对NAPI和非NAPI方式的分析。 在此对sinister大虾表示感谢!
-----------------
后记:
多谢accessory兄的建议以及提供两个关于介绍RTL8139的链接,这里放在1楼,方便大家的参考。
(1) RTL8139
http://wiki.osdev.org/RTL8139
(2) Linux下Rtl8139too网卡设备驱动程序关键函数剖析
http://www.xxlinux.com/linux/e/DoPrint/?classid=13&id=11702
[ 本帖最后由 Godbach 于 2009-5-6 09:47 编辑 ]

RTL 8139网卡驱动分析.pdf (408.23 KB)
作者: Godbach 发布时间: 2009-03-30
作者: wuasiam 发布时间: 2009-03-30
收藏了,多谢!
这个驱动分析的应该是咱们常用的那种台式机的网卡。如果有条件了,可以手动的调试一下这个驱动程序,可以加深对网卡驱动的理解。
作者: Godbach 发布时间: 2009-03-30
这个驱动分析的应该是咱们常用的那种台式机的网卡。如果有条件了,可以手动的调试一下这个驱动程序,可以加深对网卡驱动的理解。
3ks,谢谢共享
作者: Minit 发布时间: 2009-03-30
作者: scutan 发布时间: 2009-03-30
顶一个。
找一个rtl 8139的网卡,插到PC上,估计就可以调试驱动程序了。有时间时尝试一下。
作者: Godbach 发布时间: 2009-03-30
我现在QEMU用的也是RTL8139~
作者: superfight 发布时间: 2009-03-30
= = 不用~ 开个虚拟机就行了~
我现在QEMU用的也是RTL8139~
你的意思把虚拟的网卡配置成使用RTL8139驱动的?
作者: Godbach 发布时间: 2009-03-30
你的意思把虚拟的网卡配置成使用RTL8139驱动的?
应该说是QEMU提供了虚拟的RTL8139网卡吧~ = 3=
作者: superfight 发布时间: 2009-03-30
应该说是QEMU提供了虚拟的RTL8139网卡吧~ = 3=
恩,就是这个意思。不过我这里已经装了vm-tools,好像没法修改虚拟网卡了。
作者: Godbach 发布时间: 2009-03-30
这篇8139驱动是我的入门文章
作者: duanius 发布时间: 2009-03-30
http://www.linuxforum.net/forum/ ... rt=1&PHPSESSID=
这篇8139驱动是我的入门文章
多谢共享。
作者: scutan: 发布时间: 2009-03-30
http://www.linuxforum.net/forum/ ... rt=1&PHPSESSID=
这篇8139驱动是我的入门文章
不错啊。结合着学习一下。
作者: scutan 发布时间: 2009-03-30
作者: Godbach 发布时间: 2009-03-30
作者: Godbach 发布时间: 2009-03-31
还讲了一些pci的基本知识
学习了
作者: peimichael 发布时间: 2009-03-31


作者: peimichael 发布时间: 2009-03-31
作者: cheran 发布时间: 2009-04-03
作者: jhjx704 发布时间: 2009-04-06
ldd3有一章实现了一个网卡驱动挺不错的,不用了解硬件的寄存器之类的东西。
还有'lo'接口的实现代码看看对于学习网卡驱动很有帮助
作者: jaminwm 发布时间: 2009-04-06

作者: hauto 发布时间: 2009-04-06
独孤求真,是独孤九剑的什么什么关系?

姓氏一样

作者: dreamice 发布时间: 2009-04-07
作者: Godbach 发布时间: 2009-04-07
作者: yscholly 发布时间: 2009-04-08
[ 本帖最后由 Godbach 于 2009-4-13 19:57 编辑 ]
作者: xdsnet 发布时间: 2009-04-13
而RTL8100B中PID初始化为0x8139,而RTL8139C中初始化为0x8129。我本机读取的config中PID为0x8139. 看来应该参考第一个文档。
作者: Godbach 发布时间: 2009-04-13
譬如,8139too.c中要读取网卡的Rev_ID,可以通过如下方式:
pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
其中 PCI_REVISION_ID即Rev_ID在配置空间中的偏移。
跟踪了一下这个函数的执行,调用的宏为:
int pci_bus_read_config_##size \
(struct pci_bus *bus, unsigned int devfn, int pos, type *value) \
{ \
int res; \
unsigned long flags; \
u32 data = 0; \
if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
spin_lock_irqsave(&pci_lock, flags); \
res = bus->ops->read(bus, devfn, pos, len, &data); \
*value = (type)data; \
spin_unlock_irqrestore(&pci_lock, flags); \
return res; \
}
其中size替换为byte即可。
这里可以看出,真正配置信息是从这行代码中读取的:
bus是struct pci_bus类型的。各位有谁知道ops成员什么时候被赋值的。里面应该定义的是配置空间的读写函数。
作者: Godbach 发布时间: 2009-04-14
- /*
- * direct.c - Low-level direct PCI config space access
- */
-
- #include <linux/pci.h>
- #include <linux/init.h>
- #include <linux/dmi.h>
- #include "pci.h"
-
- /*
- * Functions for accessing PCI configuration space with type 1 accesses
- */
-
- #define PCI_CONF1_ADDRESS(bus, devfn, reg) \
- (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
-
- int pci_conf1_read(unsigned int seg, unsigned int bus,
- unsigned int devfn, int reg, int len, u32 *value)
- {
- unsigned long flags;
-
- if ((bus > 255) || (devfn > 255) || (reg > 255)) {
- *value = -1;
- return -EINVAL;
- }
-
- spin_lock_irqsave(&pci_config_lock, flags);
-
- outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
-
- switch (len) {
- case 1:
- *value = inb(0xCFC + (reg & 3));
- break;
- case 2:
- *value = inw(0xCFC + (reg & 2));
- break;
- case 4:
- *value = inl(0xCFC);
- break;
- }
-
- spin_unlock_irqrestore(&pci_config_lock, flags);
-
- return 0;
- }
-
- int pci_conf1_write(unsigned int seg, unsigned int bus,
- unsigned int devfn, int reg, int len, u32 value)
- {
- unsigned long flags;
-
- if ((bus > 255) || (devfn > 255) || (reg > 255))
- return -EINVAL;
-
- spin_lock_irqsave(&pci_config_lock, flags);
-
- outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
-
- switch (len) {
- case 1:
- outb((u8)value, 0xCFC + (reg & 3));
- break;
- case 2:
- outw((u16)value, 0xCFC + (reg & 2));
- break;
- case 4:
- outl((u32)value, 0xCFC);
- break;
- }
-
- spin_unlock_irqrestore(&pci_config_lock, flags);
-
- return 0;
- }
-
- #undef PCI_CONF1_ADDRESS
-
- struct pci_raw_ops pci_direct_conf1 = {
- .read = pci_conf1_read,
- .write = pci_conf1_write,
- };
-
-
- /*
- * Functions for accessing PCI configuration space with type 2 accesses
- */
-
- #define PCI_CONF2_ADDRESS(dev, reg) (u16)(0xC000 | (dev << 8) | reg)
-
- static int pci_conf2_read(unsigned int seg, unsigned int bus,
- unsigned int devfn, int reg, int len, u32 *value)
- {
- unsigned long flags;
- int dev, fn;
-
- if ((bus > 255) || (devfn > 255) || (reg > 255)) {
- *value = -1;
- return -EINVAL;
- }
-
- dev = PCI_SLOT(devfn);
- fn = PCI_FUNC(devfn);
-
- if (dev & 0x10)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- spin_lock_irqsave(&pci_config_lock, flags);
-
- outb((u8)(0xF0 | (fn << 1)), 0xCF8);
- outb((u8)bus, 0xCFA);
-
- switch (len) {
- case 1:
- *value = inb(PCI_CONF2_ADDRESS(dev, reg));
- break;
- case 2:
- *value = inw(PCI_CONF2_ADDRESS(dev, reg));
- break;
- case 4:
- *value = inl(PCI_CONF2_ADDRESS(dev, reg));
- break;
- }
-
- outb(0, 0xCF8);
-
- spin_unlock_irqrestore(&pci_config_lock, flags);
-
- return 0;
- }
-
- static int pci_conf2_write(unsigned int seg, unsigned int bus,
- unsigned int devfn, int reg, int len, u32 value)
- {
- unsigned long flags;
- int dev, fn;
-
- if ((bus > 255) || (devfn > 255) || (reg > 255))
- return -EINVAL;
-
- dev = PCI_SLOT(devfn);
- fn = PCI_FUNC(devfn);
-
- if (dev & 0x10)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- spin_lock_irqsave(&pci_config_lock, flags);
-
- outb((u8)(0xF0 | (fn << 1)), 0xCF8);
- outb((u8)bus, 0xCFA);
-
- switch (len) {
- case 1:
- outb((u8)value, PCI_CONF2_ADDRESS(dev, reg));
- break;
- case 2:
- outw((u16)value, PCI_CONF2_ADDRESS(dev, reg));
- break;
- case 4:
- outl((u32)value, PCI_CONF2_ADDRESS(dev, reg));
- break;
- }
-
- outb(0, 0xCF8);
-
- spin_unlock_irqrestore(&pci_config_lock, flags);
-
- return 0;
- }
-
- #undef PCI_CONF2_ADDRESS
-
- static struct pci_raw_ops pci_direct_conf2 = {
- .read = pci_conf2_read,
- .write = pci_conf2_write,
- };
作者: Godbach 发布时间: 2009-04-14

作者: Godbach 发布时间: 2009-04-15
0000000 10ec 8139 0107 0290 0010 0200 4000 0000
0000020 c801 0000 b800 bfff 0000 0000 0000 0000
0000040 0000 0000 0000 0000 0000 0000 10ec 8139
0000060 0000 0000 0050 0000 0000 0000 010a 4020
0000100 0000 0000 0000 0000 0000 0000 0000 0000
0000120 0001 f7c2 0000 0000 0000 0000 0000 0000
0000140 0000 0000 0000 0000 0000 0000 0000 0000
*
0000400
不知道最前面的值代表什么,如果是字节书的话,MS也不连续啊
作者: fyx2008 发布时间: 2009-04-15
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28