📄 driver.c
字号:
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 + -