
网卡设备驱动[47页].docx
47页……………………………………………………………最新资料推荐…………………………………………………网卡设备驱动1. 8139too网卡设备简介一个PCI设备,总共有三个地址空间:内存,端口和配置内存和端口其实是同一个内容的不同访问路径而已PCI设备的配置空间是标准化的,每个PCI设备的配置空间的前64个字节的含义都是一样的但各个设备的内存和端口空间是完全不一样的在硬件概念上,设备的I/O内存和I/O端口空间没有区别,其实都是设备拥用的一些读写寄存器 8139too网卡拥有256字节的读写寄存器空间它的整个布局如下: /* Symbolic offsets to registers. */ enum RTL8139_registers { MAC0 = 0, /* Ethernet hardware address. */ MAR0 = 8, /* Multicast filter. */ TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ RxBuf = 0x30, ChipCmd = 0x37, RxBufPtr = 0x38, RxBufAddr = 0x3A, IntrMask = 0x3C, IntrStatus = 0x3E, TxConfig = 0x40, RxConfig = 0x44, Timer = 0x48, /* A general-purpose counter. */ RxMissed = 0x4C, /* 24 bits valid, write clears. */ Cfg9346 = 0x50, Config0 = 0x51, Config1 = 0x52, FlashReg = 0x54, MediaStatus = 0x58, Config3 = 0x59, Config4 = 0x5A, /* absent on RTL-8139A */ HltClk = 0x5B, MultiIntr = 0x5C, TxSummary = 0x60, BasicModeCtrl = 0x62, BasicModeStatus = 0x64, NWayAdvert = 0x66, NWayLPAR = 0x68, NWayExpansion = 0x6A, /* Undocumented registers, but required for proper operation. */ FIFOTMS = 0x70, /* FIFO Control and test. */ CSCR = 0x74, /* Chip Status and Configuration Register. */ PARA78 = 0x78, PARA7c = 0x7c, /* Magic transceiver parameter register. */ Config5 = 0xD8, /* absent on RTL-8139A */ }; 每个寄存器都有它特殊的含义和用途。
举个例子(我们假设使用I/O内存的方式,ioaddr为设备内存映射在CPU内存地址空间的起始地址,下述代码能读取板卡的版本号): #define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \ (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22) #define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1) /* identify chip attached to board */ version = ioread32( ioaddr + TxConfig ) & HW_REVID_MASK; 在我的电脑上,version读出来的值的0x74400000,经过比对,板卡名称为:RTL-8100B/8139D 下面是整个系例版本号的表格: enum chip_flags { HasHltClk = (1 << 0), HasLWake = (1 << 1), }; /* directly indexed by chip_t, above */ const static struct { const char *name; u32 version; /* from RTL8139C/RTL8139D docs */ u32 flags; } rtl_chip_info[] = { { "RTL-8139", HW_REVID(1, 0, 0, 0, 0, 0, 0),HasHltClk,}, { "RTL-8139 rev K", HW_REVID(1, 1, 0, 0, 0, 0, 0),HasHltClk,}, { "RTL-8139A", HW_REVID(1, 1, 1, 0, 0, 0, 0),HasHltClk,}, { "RTL-8139A rev G",HW_REVID(1, 1, 1, 0, 0, 1, 0),HasHltClk,}, { "RTL-8139B", HW_REVID(1, 1, 1, 1, 0, 0, 0),HasLWake, }, { "RTL-8130", HW_REVID(1, 1, 1, 1, 1, 0, 0),HasLWake, }, { "RTL-8139C", HW_REVID(1, 1, 1, 0, 1, 0, 0),HasLWake, }, { "RTL-8100", HW_REVID(1, 1, 1, 1, 0, 1, 0),HasLWake, }, { "RTL-8100B/8139D",HW_REVID(1, 1, 1, 0, 1, 0, 1),HasLWake, }, { "RTL-8101", HW_REVID(1, 1, 1, 0, 1, 1, 1),HasLWake, }, }; 在这个表格中,RTL_8139B以下(包括RTL_8139B)的板卡都属于较新的版本。
新老版本之间有不同的唤醒方式先看新版本的: #define LWAKE 0x10 #define Cfg1_PM_Enable 0x01 u8 new_tmp8, tmp8; enum Config4Bits { LWPTN = (1 << 2), /* not on 8139, 8139A */ }; enum Cfg9346Bits { Cfg9346_Lock = 0x00, Cfg9346_Unlock = 0xC0, }; new_tmp8 = tmp8 = ioread8( ioaddr + Config1 ); if( (rtl_chip_info[tp->chipset].flags & HasLWake) && (tmp8 & LWAKE)) new_tmp8 &= ~LWAKE; new_tmp8 |= Cfg1_PM_Enable; if (new_tmp8 != tmp8) { iowrite8( Cfg9346_Unlock, ioaddr + Cfg9346 ); iowrite8( tmp8, ioaddr + Config1 ); iowrite8( Cfg9346_Lock, ioaddr + Cfg9346 ); } if (rtl_chip_info[tp->chipset].flags & HasLWake) { tmp8 = ioread8( ioaddr + Config4 ); if (tmp8 & LWPTN) { iowrite8( Cfg9346_Unlock, ioaddr + Cfg9346 ); iowrite8( tmp8 & ~LWPTN, ioaddr + Config4 ); iowrite8( Cfg9346_Lock, ioaddr + Cfg9346 ); } } 基本的一个流程是:如果板卡版本本身支持了HasLWake,而Config1中读出的值带有LWAKE,把Config1的值写回,并把Config4 中的LWPTN去除。
而我的网卡中从Config1, Config4读取的值分别为0x8d, 0x88,所以,无需做任何操作 下面是旧版本的唤醒方式: enum Config1Bits { Cfg1_PM_Enable = 0x01, Cfg1_VPD_Enable = 0x02, Cfg1_PIO = 0x04, Cfg1_MMIO = 0x08, LWAKE = 0x10, /* not on 8139, 8139A */ Cfg1_Driver_Load = 0x20, Cfg1_LED0 = 0x40, Cfg1_LED1 = 0x80, SLEEP = (1 << 1), /* only on 8139, 8139A */ 。
