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

本文深入剖析了Wince环境下DM9000A网卡驱动的移植过程,详细介绍了驱动初始化流程,包括MiniportInitialize函数的执行逻辑,以及配置参数读取和设置细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 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_pLowerDriver.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,由于DeviceDm9000Dm9000的父类,所以效果都是一样,相当于是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,它通知了NDISNIC初始化中一些有意义的信息(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是有headerbuffer组成。有关DATA_BLOCK的详细说明见后面灰色-25%颜色的说明。

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

继续看函数EDriverInitialize接下来

         

              m_pLower->EDeviceRegisterIoSpace();

              m_pLower->EDeviceLoadEeprom();

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

              m_pLower->EDeviceRegisterInterrupt();


 

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

      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.即:这个函数设置驱动中MiniportISRMiniportHandleInterrupt的映射。在我们这里就是driver.cpp中函数DriverIsrDriverInterruptHandler的映射关系(有关中断后面详细再分析)

继续看函数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[n]));

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

                     

              /* 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[n]);

 

              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,最后给DM9000AMulticast 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寄存器4bit 10 设置为高电平,即使能流控。DeviceReadPhy(0,4)是读PHY寄存器(地址为:4),这里第一个参数0好像没有作用,同样DeviceWrigePhy是写PHY寄存器4。而PHY寄存器4Auto-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_EPLOWDM9_EPHIGH寄存器上)

4)             DM9_EPCNTL寄存器写入0,清楚读操作命令。

5)             DM9_EPLOWDM9_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(网络控制寄存器)的值(这个regbit 3DM9000A打开内部PHY后是只读的,表示全双工还是半双工),然后判断双工模式进行不同配置。我们这里是全双工模式,主要配置DM9_FLOW(0Ah)bit 5bit 01

Bit 5TXPEN:强制发送暂停包使能。按溢出门限最高值使能发送暂停包。

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

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

      继续看,代码如下:

 

// enable interrupt

DeviceEnableInterrupt();


       使能收发数据包中断等,配置DM9_IMR寄存器的Bit01237,意思如下:

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

3ROOI1使能接收溢出计数器溢出中断。

2ROI1使能接收溢出中断。

1PTI1使能数据包传输中断。

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

      继续看,代码如下:

 

DeviceWritePort(DM9_RXCR,m_szCurrentSettings[SID_OP_MODE]);

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

7:保留。

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

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

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

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

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

1PRMSC:混杂模式(Promiscuous Mode

0RXEN:接收使能。

这里m_szCurrentSettings[SID_OP_MODE]的值是在初始化函数EDeviceValidateConfigurations中设置的,bit 0145为: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);


 分析:DM9000AGeneral 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;

       }

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

继续看,代码如下:

             

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

 DeviceWritePort(DM9_GPR,  0x00);


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

      继续看,代码如下:

 

DeviceWritePort(DM9_NSR, 0x00);


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

7SPEED:媒介速度,在内部PHY模式下,0100Mbps110Mbps。当LINKST=0时,此位不用。

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

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

4:保留。

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

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

1RXOVRX(接收)FIFO(先进先出缓存)溢出标志。

0:保留。

      继续看,代码如下:

                    

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


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

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

6:保留。

5LNKCHGI1使能连接状态改变中断。

4UDRUNI1使能传输“Underrun”中断。

3ROOI1使能接收溢出计数器溢出中断。

2ROI1使能接收溢出中断。

1PTI1使能数据包传输终端。

0PRI1使能数据包接收中断。

继续看,代码如下:

 

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

      m_nTxPendings = 0;


 

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

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

 

未完待续,上述中代码类型有些不对,修改太累,凑合看吧

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值