⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 driver.c

📁 rtl8139网卡在Windows2000/xp下的驱动程序源代码,无线网卡驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
		NdisMDeregisterIoPortRange(
			adapter->MiniportAdapterHandle,
			adapter->BaseIO,
			0x100,
			(PVOID)&adapter->ioaddr	);
	if(adapter)  //释放 DMA
		NdisMFreeMapRegisters(adapter->MiniportAdapterHandle);
	if(adapter->IRQVector > 0)  //释放 中断 资源
		NdisMDeregisterInterrupt(&adapter->IntObj);
	if(adapter->tx_bufs != NULL)  //释放发送缓冲区
			NdisMFreeSharedMemory(
				adapter->MiniportAdapterHandle,
				TX_BUF_SIZE * NUM_OF_DESC,
				FALSE,//not cached
				adapter->tx_bufs,
				adapter->tx_bufs_dma);
	if(adapter->rx_bufs != NULL)  //释放接收缓冲区
			NdisMFreeSharedMemory(
				adapter->MiniportAdapterHandle,
				RX_BUF_SIZE * NUM_OF_PACKETS,
				FALSE,//not cached
				adapter->rx_bufs,
				adapter->rx_bufs_dma);
	if(adapter->rx_ring != NULL)  //释放rx_ring
			NdisMFreeSharedMemory(
				adapter->MiniportAdapterHandle,
				RING_BUF_SIZE + RING_BUF_PAD,
				FALSE,//not cached
				adapter->rx_ring,
				adapter->rx_ring_dma);
	if(adapter->buf_pool != NULL)  //释放缓冲池
		NdisFreeBufferPool(adapter->buf_pool);
	if(adapter->pkt_pool != NULL)  //释放包描述符池
		NdisFreePacketPool(adapter->pkt_pool);
	NdisFreeMemory((PVOID)adapter,sizeof(ADAPTER),0); //释放存储区
}

//-------------------------------------------------------------------------
//#pragma LOCK_CODE IRQL:DISPATCH_LEVEL 拷贝要发送的包数据到缓冲区,返回包数据长度
ULONG CopyPktToBuf(	PNDIS_PACKET packet,PUCHAR buff	)
{
	PUCHAR			WritePtr = buff;
	UINT			BufferCount;
	PNDIS_BUFFER	srcBuff;
	UINT			PacketLength, BufferLength;
	UINT				i;
	PUCHAR			Address;

	NdisQueryPacket(   //返回给定packet的指定信息  
		packet,    //IN PNDIS_PACKET  Packet, 包描述符
		NULL,         // OUT PUINT  PhysicalBufferCount 返回由链接到给定包的缓冲描述符所映射的物理断点的最大数
		&BufferCount, //OUT PUINT  BufferCount 返回链接到给定包的缓冲描述符数量
		&srcBuff,  // OUT PNDIS_BUFFER  *FirstBuffer 返回链接到给定包的缓冲描述符首指针
		&PacketLength); //OUT PUINT  TotalPacketLength 返回包数据的全部字节长度
	ASSERT(PacketLength <= TX_BUF_SIZE); //每个发送包长 <= 1536
	for(i = 0; i < BufferCount; i ++)//包的缓冲描述符数量
	{
		NdisQueryBufferSafe(//获取 链接到 随后传送操作的包的缓冲描述符信息
			srcBuff, // IN PNDIS_BUFFER  Buffer  链接到给定包的缓冲描述符
			&Address, //OUT PVOID  *VirtualAddress  返回所描述范围的虚拟基地址
			&BufferLength, // OUT PUINT  Length  返回虚拟范围里的字节数
		    NormalPagePriority); //IN MM_PAGE_PRIORITY Priority 指定请求优先级
//从一调用者提供的位置将一指定数量的字节拷贝到另一地方 源和目的都是虚拟地址		
		NdisMoveMemory(WritePtr,     //OUT PVOID  Destination
			          Address,       //IN PVOID  Source
					  BufferLength); // IN ULONG  Length
		WritePtr += BufferLength;
//返回给定的当前缓存描述符指针的链中下一个缓存描述符 
		NdisGetNextBuffer(//如果当前是缓冲描述符链中的最后一个缓冲描述符,则返回NULL
			srcBuff, //IN PNDIS_BUFFER  CurrentBuffer当前的缓冲描述符
			&srcBuff); //OUT PNDIS_BUFFER  *NextBuffer 当前缓冲描述符的下一缓冲描述符
	}
	return PacketLength;
}

//-------------------------------------------------------------------------
//发送中断处理 IRQL:DISPATCH_LEVEL
VOID TxInt(	PADAPTER adapter)
{
	UINT	    i = 0;
    ULONG       Offset;
    ULONG       tmpTSD;
	while((i < 4)&&(adapter->FreeTxDesc < 4))//被释放的可用发送描述符数量
	{
		Offset = (i) << 2;
	    NdisRawReadPortUlong(adapter->ioaddr + TxStatus0 + Offset, &tmpTSD); 
		if(tmpTSD & TxStatOK)         //为1则表明包传送成功结束,传送不再发生
			adapter->XMIT_OK ++;      //表示正确传送的帧数
		if(tmpTSD & (TxUnderrun | TxAborted))  //为1则表明包传送FIFO耗尽或被丢弃了
			adapter->XMIT_ERR ++;              //表示没有传送的帧数
		if(tmpTSD & (TxStatOK | TxUnderrun | TxAborted))
		{
            adapter->FreeTxDesc ++;    //被释放的可用发送描述符数量
			NdisMSendResourcesAvailable(adapter->MiniportAdapterHandle);
    //告知NDIS:微端口驱动程序有足够的内部资源来接收另外一个发送请求
			i ++;
		}
	}
}

//-------------------------------------------------------------------------
//接收中断处理 IRQL:DISPATCH_LEVEL
VOID RxInt(	PADAPTER adapter)
{
	UCHAR			TmpCMD;
	UINT			NumOfPkt = 0;
	PNDIS_PACKET	RevPacket[NUM_OF_PACKETS];	//每次接收0x40个包
	while(TRUE)
	{
		NdisRawReadPortUchar(adapter->ioaddr + ChipCmd, &TmpCMD);
		if((TmpCMD & (UCHAR)RxBufEmpty))//接收缓冲区空,没有包存储在接收环状缓冲区中
		{ //接受到的数据包刚开始就是被连续放在这个环状缓冲区
			adapter->RCV_NO_BUFFER ++;//指定NIC由于缺少接收缓冲空间而不能接收的帧数
			break;
		}
		RevPacket[NumOfPkt] = RevOnePacket(adapter); //接收一个数据包
		if(RevPacket[NumOfPkt])	
			NumOfPkt ++;
		else 
			break;
	}

	if(NumOfPkt > 0)
	{
		NdisMIndicateReceivePacket(//告知NDIS:接收的包数组要传到适当的上层驱动程序
				adapter->MiniportAdapterHandle,
				RevPacket,  //IN PPNDIS_PACKET  ReceivePackets
				NumOfPkt);  //IN UINT  NumberOfPackets
		adapter->FreeRxPkt += NumOfPkt;  //被释放的可用接收包数量,NumOfPkt个包传到上层后要再加上
	}
}

//-------------------------------------------------------------------------
//#pragma LOCK_CODE  IRQL:DISPATCH_LEVEL  接收一个数据包
PNDIS_PACKET RevOnePacket(PADAPTER adapter)  
{
	PUCHAR		ReadPtr;
	USHORT		write_ptr;
	USHORT		max_byte;
	PPACKETHEADER	head;
	USHORT		pkt_size;
	PNDIS_PACKET	pkt_desc;
	ReadPtr = adapter->rx_ring + adapter->read_ptr;  
//要从环状缓冲区读数据的地址指针: 环状缓冲区虚拟基地址+从环状缓冲区数据拷贝的起始地址
	NdisRawReadPortUshort(adapter->ioaddr + RxBufAddr, &write_ptr);
// write_ptr : 当前的缓冲区地址指针,初值为0x0000,它反映了接收缓冲区中接收到的字节总数
	write_ptr = write_ptr % RING_BUF_SIZE;  //求余 得到环状缓冲区数据拷贝的末地址
	if(write_ptr > adapter->read_ptr)  //从环状缓冲区数据拷贝的起始地址初始值为0,表示从环状缓冲区虚拟基地址开始
		max_byte = write_ptr - adapter->read_ptr; //字节数 = 末地址 - 起始地址
	else
		max_byte = write_ptr + RING_BUF_SIZE - adapter->read_ptr;
	head = (PPACKETHEADER)ReadPtr;
	if(!PacketOK(head)) //接收的数据包有错误
	{
		RxErrHandle(adapter);   //重新置位环状缓冲区
		return NULL;
	}	
	if(adapter->FreeRxPkt <= 0) //被释放的可用接收包数量
		return NULL; //没有空
	pkt_size = *((PUSHORT)(ReadPtr + 2)) - 4;  //包的大小:减掉网卡加入的4个字节CRC
	if(head->PAM) //收到发给自己的包
	{
		adapter->RCV_OK ++;//指定NIC正确接收且向上层驱动程序指示的帧数
		adapter->rev_byte += pkt_size;  //接收的字节数
	}
	if(pkt_size + 8 > max_byte)
		return NULL;
	adapter->FreeRxPkt --;	//被释放的可用接收包数量 - 1
	pkt_desc = adapter->pkt_desc[adapter->cur_rx]; //包描述符
	NdisMoveMemory( //把长度为(PacketLength-4)个字节的数据从环状缓冲区里拷贝到接收缓冲区
		adapter->rx_bufs + (adapter->cur_rx * RX_BUF_SIZE),
		ReadPtr + 4,
		pkt_size);
	NdisAdjustBufferLength( //调整缓冲区描述符域的大小以匹配缓冲区中数据的实际长度
		adapter->buf_desc[adapter->cur_rx],
		pkt_size); //以字节为单位,指定缓冲描述符中设定的新的长度
	adapter->cur_rx = NextRxDesc(adapter->cur_rx);//当前接收的包的包的序号加1
//微端口因为将要用尽接收缓冲区,而决定必须强迫协议驱动程序拷贝指示的数据
	NDIS_SET_PACKET_STATUS(pkt_desc, NDIS_STATUS_RESOURCES);
	adapter->read_ptr = (adapter->read_ptr + pkt_size + 8 + 3) & (~3); //从环状缓冲区数据拷贝的起始地址前移 对齐 32
	adapter->read_ptr %= RING_BUF_SIZE;
	NdisRawWritePortUshort(adapter->ioaddr + RxBufPtr, adapter->read_ptr - 16);//当前读到的包地址
	return pkt_desc;
}

//-------------------------------------------------------------------------
//#pragma LOCK_CODE   IRQL:DISPATCH_LEVEL
BOOLEAN PacketOK(	PPACKETHEADER p	)  //判断接收的数据包是否好包
{
    BOOLEAN BadPacket = p->RUNT ||p->LONG ||p->CRC  ||p->FAE;
    if(BadPacket  //一个小于64Bytes的包 || 一个超过4KBytes的包 || CRC校验错误 || 帧对齐错误
		||(p->PacketLength > MAX_ETHERNET_FRAME_SIZE)   //数据包长度+网卡加入的4个字节CRC > 1518
		||(p->PacketLength < MIN_ETHERNET_FRAME_SIZE))  //64
	    return FALSE;
    else
		return TRUE;
}

//-------------------------------------------------------------------------
VOID RxErrHandle(PADAPTER adapter)  //重新置位环状缓冲区
{
	ULONG		TmpLong;
	NdisRawReadPortUlong(adapter->ioaddr + RxMissed, &TmpLong);//表示因Rx FIFO溢出而丢弃的包数量
	NdisRawWritePortUlong(adapter->ioaddr + RxMissed, 0);  //复位RxMissed寄存器
	adapter->ERR_COUNT += TmpLong;
	adapter->RCV_ERR ++;  //指定NIC接收到但由于发生错误而没指示给协议驱动程序的帧数
	NdisRawWritePortUshort(adapter->ioaddr + RxBufPtr, adapter->read_ptr - 16);// 当前读到的包地址
}

//-------------------------------------------------------------------------
VOID SetMII(PADAPTER	adapter	)
{
	USHORT	TmpShort;
	USHORT	media, ad, lp;

	NdisRawWritePortUshort(adapter->ioaddr + BasicModeCtrl, PHY_BMCR_RESET);
	do{  //复位PHY的状态和控制寄存器到默认状态
		NdisRawReadPortUshort(adapter->ioaddr + BasicModeCtrl, &TmpShort);
	}while(TmpShort & PHY_BMCR_RESET);
	DbgPrint("MII reset complete. \n");

	NdisRawReadPortUshort(adapter->ioaddr + BasicModeCtrl, &TmpShort);
	TmpShort |= PHY_BMCR_AUTONEGENBL | PHY_BMCR_AUTONEGRSTR;//使能Auto Negotiation | 重新开始Auto Negotiation
	NdisRawWritePortUshort(adapter->ioaddr + BasicModeCtrl, TmpShort);

	do{
		NdisRawReadPortUshort(adapter->ioaddr + BasicModeStatus, &TmpShort);
	}while(!(TmpShort & PHY_BMSR_AUTONEGCOMP)); //Auto Negotiation结束
	DbgPrint("MII AUTONEG complete. \n");

	NdisRawReadPortUshort(adapter->ioaddr + BasicModeStatus, &TmpShort);
	if(! (TmpShort & PHY_BMSR_LINKSTAT)) //PHY_BMSR_LINKSTAT:是否已建立有效联接
	{
		DbgPrint("link error.\n");
		return;
	}
	DbgPrint("link ok.\n");

	NdisRawReadPortUshort(adapter->ioaddr + BasicModeCtrl, &media);
	NdisRawReadPortUshort(adapter->ioaddr + NWayAdvert, &ad);
	NdisRawReadPortUshort(adapter->ioaddr + NWayLPAR, &lp);

		if (ad & PHY_ANAR_100BT4 && lp & PHY_ANAR_100BT4) 
		{ //local node支持100Base-T4 && link partner支持100Base-T4 
			media |= PHY_BMCR_SPEEDSEL;  //设置网络速度:1 = 100Mbps; 0 = 10Mbps
			media &= ~PHY_BMCR_DUPLEX;   // 设置双工模式:0 = normal operation  1 = full-duplex
		} else if (ad & PHY_ANAR_100BTXFULL &&lp & PHY_ANAR_100BTXFULL) 
		{//local node支持100Base-TX 全双工 && link partner支持100Base-TX 全双工
			media |= PHY_BMCR_SPEEDSEL;
			media |= PHY_BMCR_DUPLEX;
		} else if (ad & PHY_ANAR_100BTXHALF &&lp & PHY_ANAR_100BTXHALF) 
		{//local node支持100Base-TX  && link partner支持100Base-TX 
			media |= PHY_BMCR_SPEEDSEL;
			media &= ~PHY_BMCR_DUPLEX;
		} else if (ad & PHY_ANAR_10BTFULL &&lp & PHY_ANAR_10BTFULL) 
		{//local node支持10Base-TX 全双工 && link partner支持10Base-TX 全双工
			media &= ~PHY_BMCR_SPEEDSEL;
			media |= PHY_BMCR_DUPLEX;
		} else 
		{
			media &= ~PHY_BMCR_SPEEDSEL;
			media &= ~PHY_BMCR_DUPLEX;
		}
	NdisRawWritePortUshort(adapter->ioaddr + BasicModeCtrl, media);
}      

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -