您的位置:首页 > 其它

wince下DM9000A网卡驱动移植及学习总结---2

2013-07-13 23:52 309 查看

wince下DM9000A网卡驱动移植及学习总结---2

下面我将详细分析整个网卡驱动。

1.

Driver.cpp中有函数入口:DriverEntry,初始化一个Miniport Driver时该函数会被第一个调用,用来注册一个Miniport Driver,该函数原型如下:

NDIS_STATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)

参数说明:

DriverObject:指向一个由系统创建的驱动对象

PUNICODE_STRING:指向注册表中该驱动参数的路径----注册表路径

该函数中首先调用NdisMInitializeWrapper函数来通知NDIS Library要注册一个Miniport。(可以参考MSDN说明)然后会初始化NDIS40_MINIPORT_CHARACTERISTICS结构体,所有的Miniport的相关接口函数(形如MiniportXXXX的函数)都会赋值到NDIS40_MINIPORT_CHARACTERISTICS结构中,最后调用NdisMRegisterMiniport来注册Miniport。

2.

下面将进入初始化函数:MiniportInitialize,函数原型如下:

NDIS_STATUS MiniportInitialize(
OUT PNDIS_STATUS OpenErrorStatus,// 额外的状态信息,一般不会被使用
OUT PUINT SelectedMediaIndex, //被选中的媒介类型的索引号,以太网一般是										  //NdisMedium802_3
IN PNDIS_MEDIUM MediaArray, //媒介类型数组,包含了不同类型的网络媒介
IN UINT MediaArraySize,// 媒介类型数组大小
IN NDIS_HANDLE MiniportHandle, //适配器句柄,该参数要被保存,以后调用Ndisxxx函数
//时会被用到。
IN NDIS_HANDLE WrapperConfigHandle)// 一个封装配置句柄,会被
//NdisOpenConfiguration函数用到。


此函数主要完成初始化网卡的功能。首先,NIC_DRIVER_OBJECT类(Driver类)实例化如下:

NIC_DRIVER_OBJECT	*pnic;
if(!(pnic = new NIC_DRIVER_OBJECT(MiniportHandle,WrapperConfigHandle)))	//用到了上述传入的两个句柄
return	NDIS_STATUS_FAILURE;


实例化后调用其类成员函数:pnic->EDriverInitialize,下面我们看此函数(driver.cpp文件中)。

首先看到语句:

if(!m_pLower){ m_pLower = DeviceEntry(this,NULL);}

m_pLower是Driver.h中:

NIC_DEVICE_OBJECT  *m_pLower;

定义的,此时m_pLower等于NULL,所以会调用函数:DeviceEntry,此函数是设备类的入口,在Device.cpp中,打开发现只有一条语句:

return new C_DM9000(pDriverObject,pVoid);


所以此时相当于给Driver类的成员变量m_pLower(Device类)实例化。我们继续看函数EDriverInitialize,然后几条语句如下:

// Determinate media type
for(i=0; i<MediaArraySize; i++)
if(MediaArray[i] == NdisMedium802_3)	break;

if (i == MediaArraySize) {
THROW((ERR_STRING("Unsupported media"),DIS_STATUS_UNSUPPORTED_MEDIA));}

*SelectedMediaIndex = i;


是判断media type,上面说过以太网一般是NdisMedium802_3,从输入的MediaArray数组中得到SelectedMediaIndex(被选中的媒介类型的索引号)。

继续看函数EDriverInitialize,接下来:

// Read registry configurations

NdisOpenConfiguration(    &status,  &hconfig,     m_NdisWrapper);


调用函数NdisOpenConfiguration,查看MSDN发现,这个函数是用来返回注册表键值,保存在hconfig(注册表键值路径信息)中,后面会用到。

继续看函数EDriverInitialize,接下来:

m_pLower->DeviceSetDefaultSettings();

m_pLower->DeviceSetEepromFormat();

m_pLower->DeviceRetriveConfigurations(hconfig);

m_pLower->EDeviceValidateConfigurations();


调用m_pLower(Device类)的成员函数,主要完成Device类成员数组m_szConfigures[]、m_szEepromFormat[]m_szCurrentSettings[]的配置。

DeviceSetDefaultSettings不是虚函数,主要完成Device类成员数组:m_szConfigures[]m_szCurrentSettings[]的默认配置;

DeviceSetEepromFormat是虚函数,真正实现是在Dm9isa.cpp中,(其实不论在Device.cpp还是Dm9isa.cpp,由于DeviceDm9000是Dm9000的父类,所以效果都是一样,相当于是Device,后面不再区分),也是对Device成员数组:m_szEepromFormat[]的初始化设置;

DeviceRetriveConfigurations(hconfig),这个函数完成的功能是继续设置成员数组m_szConfigures[]的值:从前面返回的注册表路径hConfig中读取参数,注册表中没有设置的则使用全局变量g_szDm9ConfigParams的配置默认值。(后面玫瑰红颜色的是DeviceRetriveConfigurations(hconfig)函数详细分析:)

EDeviceValidateConfigurations虚函数,完成的功能:使上述的一些配置使能,即将有效的配置参数写到m_szCurrentSettings[]和m_szConfigures[]数组中。(后面淡蓝颜色的是EDeviceValidateConfigurations函数的详细分析)

继续看函数EDriverInitialize,接下来:

NdisCloseConfiguration(hconfig);//释放句柄

m_pLower->DeviceRegisterAdapter();


释放句柄和前面的NdisOpenConfiguration对应,DeviceRegisterAdapter里面调用了函数NdisMSetAttributesEx,它通知了NDIS库NIC初始化中一些有意义的信息(查MSDN,应该与具体驱动没有太多关系,是NDIS库自己需要处理的东西)。

继续看函数EDriverInitialize,接下来:

/* init tx buffers */

U32        m,uaddr;

if(!(uaddr = (U32) malloc(sizeof(DATA_BLOCK) * //data_block由header + 内容buffer的大小

(m=m_pLower->m_szConfigures[CID_TXBUFFER_NUMBER]*2))))   //m=32(0x20)*2=64

THROW((ERR_STRING("Insufficient memory")));

for(;m--;uaddr+=sizeof(DATA_BLOCK))

m_TQueue.Enqueue((PCQUEUE_GEN_HEADER)uaddr);


以上是用malloc函数分配tx
buffer 的大小:64*sizeof(DATA_BLOCK)大,注意:

m_szConfigures[CID_TXBUFFER_NUMBER]来自注册表,我们这里是0x20,Data_Block是有header和buffer组成。有关DATA_BLOCK的详细说明见后面灰色-25%颜色的说明。

分配完大小后,调成员函数m_TQueue (common.h中类:CQueue的实例)进行对tx的data_Block的header进行先后顺序的关系。

继续看函数EDriverInitialize,接下来:

m_pLower->EDeviceRegisterIoSpace();

m_pLower->EDeviceLoadEeprom();

m_pLower->EDeviceInitialize(m_pLower->m_nResetCounts=0);

m_pLower->EDeviceRegisterInterrupt();


EDeviceRegisterIoSpace是DM9000A寄存器IO空间的访问,注意:这个函数在Device的父类和子类都实现了,所以会调用子类的函数,进入发现子类函数先调了父类的这个函数再执行其他操作,所以我们还是需要看看父类这个函数的作用,父类其实将先前注册表读得的IOAddress的值转成IO口地址(调用函数MmMapIoSpace),这样与处理器就没有关系,实际上就是我们器件外部的地址总线,这里IOAddress的值为:0x10000000,转换后IO口的地址值为:0x2b0000,这个值就是后面2440访问DM9000的基地址,存于:m_szCurrentSettings[SID_PORT_BASE_ADDRESS]中;子类的函数完成读取DM9000的ID号等操作。这些就比较简单易于理解不再详细介绍。

EDeviceLoadEeprom()虽然在Device类中是个虚函数,但是子类没有实现,父类中有定义,所以调用的是父类中的函数。这个函数其实真正完成的功能是:

m_szEeprom[0]=0xc000;

m_szEeprom[1]=0x2826;

m_szEeprom[2]=0x3096;

EDeviceInitialize(m_pLower->m_nResetCounts=0),这个函数所带的参数是:复位的次数。子类中实现。这个函数实现的真正功能是配置DM9000A一些寄存器,注意完成这个函数后DM9000A并没有打开,中断等都没有使能s(有关DM9000A的初始化EDeviceInitialize,接收数据,发送数据等具体后面再介绍)。

EDeviceRegisterInterrupt()在父类中,主要是调用函数:NdisMRegisterInterrupt,查MSDN发现如下:This
function sets up a mapping between an NIC driver's MiniportISR and MiniportHandleInterrupt functions, already registered with NdisMRegisterMiniport, and the bus-relative vector and level on which its NIC interrupts.即:这个函数设置驱动中MiniportISR和MiniportHandleInterrupt的映射。在我们这里就是driver.cpp中函数DriverIsr和DriverInterruptHandler的映射关系(有关中断后面详细再分析)。

继续看函数EDriverInitialize,接下来:

m_pLower->DeviceOnSetupFilter(0);


DeviceOnSetupFilter(0),子类中实现。带入参数是:0,(这个函数第一次进入,所以完成的功能是将MAC地址写到DM9000A的相应寄存器中)所以执行如下语句:

if(!(m_szCurrentSettings[SID_GEN_CURRENT_PACKET_FILTER]=uFilter))

{

/* 1. set unicast */

// retrive node address

DeviceMacAddress(&sz[0]);

// set node address

for(n=0;n<ETH_ADDRESS_LENGTH;n++)

{

//RETAILMSG(1, (TEXT("DM9_PAR = %x \r\n"), sz
));

DeviceWritePort(DM9_PAR0+n,(U32)sz
);}

/* 2. clear multicast list and count */

m_nMulticasts = 0;

memset((void*)&m_szMulticastList,0,sizeof(m_szMulticastList));

/* 3. clear hash table */

// clear hash table

memset((void*)(&sz[0]),0,sizeof(sz));

for(n=0;n<sizeof(sz);n++)

DeviceWritePort(DM9_MAR0+n,(U32)sz
);

return uFilter;

}

首先调用DeviceMacAddress函数从m_szEepromFormat[EID_MAC_ADDRESS]中得到MAC地址(注意:要设置初始MAC地址可以在注册表中加入MAC地址参数,在上面读注册表是读入然后赋给m_szEepromFormat[EID_MAC_ADDRESS],在此时则可以读入到DM9000A内部),然后将ETH_ADDRESS_LENGTH(==6)个MAC地址写入DM9000A的物理地址寄存器(10h~15h),接下来,将m_szMulticastList[64][6]全部设置为:0,最后给DM9000A的Multicast
Address Register(16h~1dh)全部设置为0,最后返回uFilter(输入参数,此时为0)。

到此为止函数EDriverInitialize结束。

我们继续看函数MiniportInitialize,上面完成了设备的初始化操作,下面进行流控、中断等设置后就可以打开设备了。发现如下语句:

pnic->DriverStart();


这句就是在Driver.cpp中找到函数:DriverStart如下:

void NIC_DRIVER_OBJECT::DriverStart(void)

{

m_pLower->DeviceStart();

}


所以调用的是Device类的DeviceStart()函数,此函数子类实现。下面我们详细看看C_DM9000::DeviceStart函数。

首先执行的代码如下:

// set PHY supports flow control

DeviceWritePhy(0, 4, (DeviceReadPhy(0,4)|(1<<10)));


这两句是与DM9000A内部PHY相关的,完成的功能是将PHY寄存器4的bit
10 设置为高电平,即使能流控。DeviceReadPhy(0,4)是读PHY寄存器(地址为:4),这里第一个参数0好像没有作用,同样DeviceWrigePhy是写PHY寄存器4。而PHY寄存器4是Auto-negotiation
Advertisement Register (ANAR),bit 10是使能流控与否。这里PHY寄存器读过程需要注意:
1) 往DM9_EPADDR寄存器写入要读的PHY寄存器地址,注意这个寄存器的bit
7:bit6恒等于01,后面bit5:0才是PHY寄存器地址。
2) 往DM9_EPCNTL寄存器写入读PHY的命令。
3) 判断DM9_EPCNTL寄存器bit
0是否等于0,意思为:等待DM9000A自己内部完成读的操作(自己完成后会将要读的数据放置在DM9_EPLOW和DM9_EPHIGH寄存器上)。
4) 往DM9_EPCNTL寄存器写入0,清楚读操作命令。
5) 从DM9_EPLOW和DM9_EPHIGH寄存器读PHY要读取的寄存器的数据。
PHY寄存器写操作类似,不再赘述,详细加源代码。
继续看,代码如下:

val = DeviceReadPort(DM9_NCR);

if( val & MAKE_MASK(3))

{

/* full duplex mode */

val = DeviceReadPort(DM9_PAUSETH);

DeviceWritePort(DM9_PAUSETH,(U8)val);

// enable flow control<0>

// enable pause packet<5>

DeviceWritePort(DM9_FLOW,MAKE_MASK2(5,0));

}

else

{

/* non full duplex mode */

val = DeviceReadPort(DM9_BACKTH);

DeviceWritePort(DM9_BACKTH,(U8)val);

// enable back pressure<half dumplex mode)<4,3>

DeviceWritePort(DM9_FLOW,MAKE_MASK2(4,3));

}


这里是读DM9_NCR(网络控制寄存器)的值(这个reg的bit
3在DM9000A打开内部PHY后是只读的,表示全双工还是半双工),然后判断双工模式进行不同配置。我们这里是全双工模式,主要配置DM9_FLOW(0Ah)的bit
5和bit 0为1:
Bit 5:TXPEN:强制发送暂停包使能。按溢出门限最高值使能发送暂停包。

Bit 1:RXPCS:接收暂停包当前状态。

(这句之前的两句将DM9_PAUSETH值读出有赋回去,不知道有什么作用…)

继续看,代码如下:

// enable interrupt

DeviceEnableInterrupt();


使能收发数据包中断等,配置DM9_IMR寄存器的Bit0,1,2,3,7,意思如下:

7:PAR:1使能指针自动跳回。当SRAM的读、写指针超过SRAM的大小时,指针自动跳回起始位置。需要驱动程序设置该位,若设置则REG_F5(MDRAH)将自动位0CH。

3:ROOI:1使能接收溢出计数器溢出中断。

2:ROI:1使能接收溢出中断。

1:PTI:1使能数据包传输中断。

0:PRI:1使能数据包接收中断。

继续看,代码如下:

DeviceWritePort(DM9_RXCR,m_szCurrentSettings[SID_OP_MODE]);

DM9_RXCR接收控制寄存器05h(RX
Control Register )各bit意义如下:

7:保留。

6:WTDIS:看门狗定时器禁止。1禁止,0使能。

5:DIS_LONG:丢弃长数据包。1为丢弃数据包长度超过1522字节的数据包。

4:DIS_CRC:丢弃CRC校验错误的数据包。

3:ALL:忽略所有多点传送。

2:RUNT:忽略不完整的数据包。

1:PRMSC:混杂模式(Promiscuous
Mode)

0:RXEN:接收使能。

这里m_szCurrentSettings[SID_OP_MODE]的值是在初始化函数EDeviceValidateConfigurations中设置的,bit
0、1、4、5为:1,所以条语句完成的功能是室使能接受,即丢弃CRC校验错误的包即长度超过1522字节的包。

到此位置,C_DM9000::DeviceStart函数结束,MiniportInitialize函数也结束,所有的初始化介绍。总的来说,初始化就是设置先DM9000A的工作模式相关的一些变量值,然后用这些值配置DM9000A的寄存器来设置正确的工作模式,最后调用DeviceStart函数,使能流控中断以及打开接受使能等操作。

MiniportInitialize中涉及的相关函数即结构体的分析:

以下是前面提到的两个函数的分析:

void NIC_DEVICE_OBJECT::DeviceRetriveConfigurations(

NDIS_HANDLE           hConfig)

{

NDIS_STATUS      status;

PCONFIG_PARAMETER     pconfig;

PNDIS_CONFIGURATION_PARAMETER       param;

for(pconfig=DeviceConfigureParameters();

(pconfig->uId != (U32)-1);

pconfig++)

{

NdisReadConfiguration(//读注册表

&status,

¶m,//读出的参数

hConfig,//前面返回的注册表路径

&(pconfig->szName),

NdisParameterHexInteger);//读的类型

if(status == NDIS_STATUS_SUCCESS)//读成功

m_szConfigures[pconfig->uId] =

param->ParameterData.IntegerData;

else//读失败,证明注册表没有这个参数,使用默认的值

m_szConfigures[pconfig->uId] = pconfig->uDefValue;

}

}


上面加粗的是个函数,所以得先弄清楚这个函数干了什么,寻找发现这个函数的实现是在Device的子类中,其实这个函数就是从一个全局变量读取配置参数,如下:

PCONFIG_PARAMETER     C_DM9000::DeviceConfigureParameters(void)

{

return (PCONFIG_PARAMETER)&g_szDm9ConfigParams[0];

}

很简单,就是返回了一个全局变量的地址,这个全局变量也在Dm9isa.cpp中,如下:

CONFIG_PARAMETER       g_szDm9ConfigParams[] =

{

{ CID_CONNECTION_TYPE, -1, NDIS_STRING_CONST("ConnectionType") },

{ CID_SLOT_NUMBER, -1, NDIS_STRING_CONST("SlotNumber")},

{CID_BUFFER_PHYSICAL_ADDRESS,0,NDIS_STRING_CONST("BufferPhysicalAddress")},

{ CID_TXBUFFER_NUMBER, 0x20, NDIS_STRING_CONST("XmitBuffer")},

{ CID_RXBUFFER_NUMBER, 0x10, NDIS_STRING_CONST("RecvBuffer")},

{ CID_ADAPTER_NUMBER, 0, NDIS_STRING_CONST("AdapterNumber")},

{ CID_IO_BASE_ADDRESS, 0x300, NDIS_STRING_CONST("IoAddress")},

{ CID_IO_RANGE, 0x10, NDIS_STRING_CONST("IoRange")},

{ CID_IRQ_NUMBER, 3, NDIS_STRING_CONST("IrqNumber")},

{ -1,-1,NULL}

};


可见这个全局变量设置了一些初始值,CONFIG_PARAMETER的结构体如下:

typedef    struct      _CONFIG_PARAMETER

{

U32                      uId;

U32                      uDefValue;

NDIS_STRING             szName;

}     CONFIG_PARAMETER, *PCONFIG_PARAMETER;


所以全局变量设置的初始值的第一个参数表示ID(Device类的成员数组m_szConfigures[]的索引ID),第二个参数是默认值,第三个是名字,名字是用来读取注册表时用的。

EDeviceValidateConfigurations的分析,主要见语句的注释:

void C_DM9000::EDeviceValidateConfigurations(void)

{RETAILMSG(1,(TEXT("C_DM9000::EDeviceValidateConfigurations\r\n")));

NDIS_HANDLE           hndis = m_pUpper->GetNdisHandle();

// validate slot number

if(

(m_szConfigures[CID_IO_BASE_ADDRESS] == -1) ||

(m_szConfigures[CID_IRQ_NUMBER] == -1) )

THROW(());

m_szCurrentSettings[SID_GEN_TRANSMIT_BUFFER_SPACE] = //1514*32 = 48448

m_szConfigures[CID_TXBUFFER_NUMBER]//读注册表得到值为0x20=32

* ETH_MAX_FRAME_SIZE;//1514

m_szCurrentSettings[SID_GEN_RECEIVE_BUFFER_SPACE] = //48448

m_szConfigures[CID_RXBUFFER_NUMBER]//读注册表:0x20

* ETH_MAX_FRAME_SIZE;//1514

m_szConfigures[CID_CHECK_FOR_HANG_PERIOD] = 3;//hang 周期

m_szConfigures[CID_IRQ_GEN_TYPE] = NdisInterruptLatched;

m_szConfigures[CID_IRQ_SHARED] = TRUE;

m_szConfigures[CID_IRQ_LEVEL] = 0x0F;

m_szConfigures[CID_INTERFACE_TYPE] = NdisInterfaceIsa;

m_szConfigures[CID_BUS_MASTER] = FALSE;

// set receive mode

// <5> discard long packet

// <4> discard CRC error packet

// <0> rx enable

m_szCurrentSettings[SID_OP_MODE] = MAKE_MASK3(5,4,0);//工作模式,0011 0001=0x31

m_szCurrentSettings[SID_802_3_MAXIMUM_LIST_SIZE] = DM9_MULTICAST_LIST; //64

}


DATA_BLOCK的详细说明

在Driver.h中有定义:

typedef       struct      _DATA_BLOCK

{

CQUEUE_GEN_HEADER   Header;

unsigned char         Buffer[DRIVER_BUFFER_SIZE];

} DATA_BLOCK, *PDATA_BLOCK;

CQUEUE_GEN_HEADER结构体在common.h中有定义:

typedef       struct      _CQUEUE_GEN_HEADER

{

struct      _CQUEUE_GEN_HEADER *pNext;

U32        uFlags;

PVOID   pPacket;

U16        nReserved;

U16        nLength;

} CQUEUE_GEN_HEADER, *PCQUEUE_GEN_HEADER;


DM9000A的初始化函数C_DM9000::EDeviceInitialize()的详细分析:

这个函数在文件Dm9isa.cpp中;前几句代码代码如下:

// reset member varialbes

m_uLastAddressPort = (U32)-1;

DeviceWritePort(0x1f, 0x00);//General purpose Register ( 1FH )

NdisStallExecution(20);

// software reset the device

DeviceWritePort(DM9_NCR, 0x03);// Network Control Register (00H)

NdisStallExecution(20);

DeviceWritePort(DM9_NCR, 0x03); // Network Control Register (00H)

NdisStallExecution(20);


分析:DM9000A的General
purpose Register ( 1FH )寄存器,即GPIO引脚状态寄存器,这里设置power
up PHY,后面两句是软件复位DM9000A,两次复位以保证确实达到复位目的。

继续看,代码如下:

// read the io orgnization

// ISR<7:6> == x1, dword

// ISR<7:6> == 0x, word

// ISR<7:6> == 10, byte mode

val = DeviceReadPort(DM9_ISR);

if(val & MAKE_MASK(6))

{

m_nIoMode = DWORD_MODE;

m_nIoMaxPad = 3;

}

else if(!(val & MAKE_MASK(7)))

{

m_nIoMode = WORD_MODE;

m_nIoMaxPad = 1;

}

else

{

m_nIoMode = BYTE_MODE;

m_nIoMaxPad = 0;

}

以上是ISR(FEH):中断状态寄存器(Interrupt
Status Register)的读取来判断m_nIoMode,我认为其实这里是DM9000的程序,不应该是DM9000A的程序,因为DM9000A的datasheet中ISR寄存器bit
6 是reserved的,而查看DM9000的资料,它用bit
[7:6]来判断IO口模式,不过我们这里程序能用,是因为DM9000A的bit
7 == 0则是word类型,bit
7== 1则是byte类型,而这里正好是是word类型,个人认为如此。

继续看,代码如下:

DeviceWritePort(DM9_GPCR, (1<<0));

DeviceWritePort(DM9_GPR,  0x00);


这两句也是对应DM9000而不是DM9000A,第一句设置GPIO控制寄存器让GPIO0为输出,第二句让其输出0,而DM9000A的GPCR寄存器bit
0 本身就是只读,且为1,GPR寄存器bit
0 设置为0是powe up PHY,设置为1是power
down PHY;这里按照DM9000设置GPIO0,目的一样,设置为power
up PHY,即使能内部PHY。

继续看,代码如下:

DeviceWritePort(DM9_NSR, 0x00);


设置网络状态寄存器NSR(01h)Network Status Register,设置一些初始值:

7:SPEED:媒介速度,在内部PHY模式下,0为100Mbps,1为10Mbps。当LINKST=0时,此位不用。

6:LINKST:连接状态,在内部PHY模式下,0为连接失败,1为已连接。

5:WAKEST:唤醒事件状态。读取或写1将清零该位。不受软件复位影响。

4:保留。

3:TX2END:TX(发送)数据包2完成标志,读取或写1将清零该位。数据包指针2传输完成。

2:TX2END:TX(发送)数据包1完成标志,读取或写1将清零该位。数据包指针1传输完成。

1:RXOV:RX(接收)FIFO(先进先出缓存)溢出标志。

0:保留。

继续看,代码如下:

DeviceWritePort(DM9_IMR, (1<<7));


中断屏蔽寄存器(FEh)IMR(Interrupt Mask Register)(初始默认值为0)各bit如下:

7:PAR:1使能指针自动跳回。当SRAM的读、写指针超过SRAM的大小时,指针自动跳回起始位置。需要驱动程序设置该位,若设置则REG_F5(MDRAH)将自动位0CH。

6:保留。

5:LNKCHGI:1使能连接状态改变中断。

4:UDRUNI:1使能传输“Underrun”中断。

3:ROOI:1使能接收溢出计数器溢出中断。

2:ROI:1使能接收溢出中断。

1:PTI:1使能数据包传输终端。

0:PRI:1使能数据包接收中断。

继续看,代码如下:

m_nMaxTxPending = (DeviceReadPort(DM9_CHIPREV) >= 0x10)?2:1;

m_nTxPendings = 0;


CHIPREV(2ch)芯片修订版本,根据数据手册,DM9000A得到的值为0x18,所以m_nMaxTxPending
== 2。

到此位置,DM9000A的初始化配置EDeviceInitialize就完成了。

未完待续,上述中代码类型有些不对,修改太累,凑合看吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: