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

📄 driver.c

📁 rtl8139网卡在Windows2000/xp下的驱动程序源代码,无线网卡驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
						adapter->IRQVector,
						adapter->IRQLevel,
						TRUE,  //IN BOOLEAN  RequestIsr
						TRUE,  //IN BOOLEAN  SharedInterrupt
						adapter->IRQMode);
	if(NDIS_STATUS_SUCCESS != Status) 
		goto err;
//------------------------------------------------------------------------------
	ResetNIC(adapter);
	StartDevice(adapter);
	return Status;

err:
	KdPrint(("claim system resource failure. \n"));
	FreeRes(adapter);
	return Status;
}


///////////////////////////////////////////////////////////////////////////////
//如果MiniportCheckForHang函数返回TRUE,NDIS将调用MiniportReset函数
// 对NIC进行硬件复位 和 复位 驱动程序的软件状态
//如果AddressingReset设为TRUE,NDIS随后将调用MiniportSetInformation函数
NDIS_STATUS RReset(OUT PBOOLEAN  AddressingReset,IN NDIS_HANDLE  MiniportAdapterContext)
{
	PADAPTER		adapter = (PADAPTER)MiniportAdapterContext;
	NdisRawWritePortUshort(adapter->ioaddr + IntrMask, 0);//禁止所有中断
	NdisRawWritePortUchar(adapter->ioaddr + ChipCmd, 0);//接收、传输禁止
	ResetNIC(adapter);
	StartDevice(adapter);

	adapter->read_ptr = 0;  //从环状缓冲区数据拷贝的起始地址
	adapter->FreeRxPkt = NUM_OF_PACKETS;//被释放的可用接收包数量64
	adapter->cur_rx = 0;  //当前接收的包的包的序号
	adapter->dirty_rx = 0;
	adapter->FreeTxDesc = NUM_OF_DESC;//被释放的可用发送描述符数量4
	adapter->cur_tx = 0;  //当前发送的描述符的序号

	return NDIS_STATUS_SUCCESS;
}

//////////////////////////////////////////////////////////////////////////////
//按既定的顺序发送每一包数据 on a Busmaster DMA NIC
VOID RSendPkts(IN NDIS_HANDLE  MiniportAdapterContext,
			   IN PPNDIS_PACKET  PacketArray,//指向包数组中的首个元素,每一元素指定要发送数据包的包描述符的地址
               IN UINT  NumberofPackets )//包描述符的个数
{
	PADAPTER	adapter = (PADAPTER)MiniportAdapterContext;
	UINT		i;
	PUCHAR		vaddr;
	ULONG		paddr;
	static UINT		pkt_len;
	UCHAR	tmpCMD;
	ULONG offset;
	
	for(i = 0; i < NumberofPackets; i ++)
	{
		if(adapter->FreeTxDesc > 0)//被释放的可用发送描述符数量
		{
		     adapter->FreeTxDesc --;
		     vaddr = adapter->tx_bufs + (adapter->cur_tx * TX_BUF_SIZE);
//发送数据的虚拟地址 = 发送缓冲区虚拟基地址 + (当前发送的描述符的序号 * 每个发送包长1536 )
		     paddr =   //发送数据的物理地址
				  NdisGetPhysicalAddressLow(adapter->tx_bufs_dma) + (adapter->cur_tx * TX_BUF_SIZE);
			 pkt_len = CopyPktToBuf(PacketArray[i],vaddr);//拷贝要发送的包数据到缓冲区,返回包数据长度
		     adapter->xmit_byte += pkt_len;
		     NDIS_SET_PACKET_STATUS(PacketArray[i], NDIS_STATUS_SUCCESS);
	         NdisRawReadPortUchar(adapter->ioaddr + ChipCmd, &tmpCMD);
	         ASSERT(tmpCMD & CmdTxEnb); //发送使能
	         if(pkt_len < MIN_ETHERNET_FRAME_SIZE)	//包长度  64
		          pkt_len = MIN_ETHERNET_FRAME_SIZE;
			 offset = adapter->cur_tx << 2;//当前发送的描述符的序号
	         NdisRawWritePortUlong(
		          adapter->ioaddr + TxAddr0 + offset, //描述符 cur_tx(0~3)的发送起始地址
		          paddr);  //发送数据的物理地址
	         NdisRawWritePortUlong(
		          adapter->ioaddr + TxStatus0 + offset,//描述符 cur_tx(0~3)的发送状态
		          pkt_len | (2 << 16)); //Early Tx Threshold: 2 << 16 000010 2*32=64字节
 		     adapter->cur_tx = NextTxDesc(adapter->cur_tx);//当前发送的描述符的序号+1
		}
		else //驱动程序由于当前资源受限而不能进行在给定包数组中指定的所有发送
             NDIS_SET_PACKET_STATUS(PacketArray[i], NDIS_STATUS_RESOURCES);
	}
}

//////////////////////////////////////////////////////////////////////////////////////////
//如果微端口通过调用NdisMIndicateReceivePacket来向上层指示包,那么它必须注册一个MiniportReturnPacket函数
VOID RReturnPkt( IN NDIS_HANDLE MiniportAdapterContext,IN PNDIS_PACKET Packet)
{
	
}

/**************************************************************************
                              被调用函数
***************************************************************************/
//----------------------------------------------------------------------------
VOID ResetNIC(PADAPTER	adapter	)
{
	UCHAR	TmpCM;
	NdisRawWritePortUchar(adapter->ioaddr + ChipCmd, CmdReset|1); //复位设备 0x10 |1
	do{  //测试复位是否成功  复位操作期间TmpCM位维持为1,直到复位完成被自动清0
		NdisRawReadPortUchar(adapter->ioaddr + ChipCmd, &TmpCM);
	}while(TmpCM & CmdReset);
	NdisRawReadPortUchar(adapter->ioaddr + Config1, &TmpCM);
	ASSERT(TmpCM & Cfg1_PIO); //该宏tests an expression. If the expression is false, it breaks into the kernel debugger
	//The operational registers are mapped into PCI I/O space.
	ASSERT(TmpCM & Cfg1_MMIO);//The operational registers are mapped into PCI memory space
}

//-------------------EEPROM: AT93C46  1K位 64X16 地址位6位:A5~A0  数据位16位:D15~D0
USHORT readEEPROM(PUCHAR	ioaddr, //  port addr
		         USHORT	reg) //寄存器位置  例如 为 7
{
	int			i;
	UCHAR		TmpVal;
	USHORT		retval = 0;
	USHORT locate = (6 << 6) | reg;  // (6<<6)|7 = 0001 1000 0111
	int   addrlen = 9;  // Start Bit 1  +  READ Code 1 0  + 地址位:A5~A0  = 总共 9 位
	
	//操作类型  OP_READ 6
	NdisRawWritePortUchar(ioaddr, EE_PRO); // 0x80 进入编程状态
	NdisRawWritePortUchar(ioaddr, EE_ENB); // 0x88 片选 + 编程模式
	for(i = addrlen; i >= 0; i --)//串行写入
	{
		TmpVal = (locate & (1 << i)) ? EE_DI : 0;  //EE_DI 0x02
//当 locate 位(第9到0位)为1时 TmpVal值为0x02,为0时 TmpVal值为0
		NdisRawWritePortUchar(ioaddr, EE_ENB | TmpVal);    //low clk 
		NdisRawWritePortUchar(ioaddr, EE_ENB | TmpVal | EE_CLK); //raise clk
	}
	NdisRawWritePortUchar(ioaddr, EE_ENB); //low clk

	for(i = 0; i < 16; i ++)  //读结果
	{
		NdisRawWritePortUchar(ioaddr, EE_ENB | EE_CLK); //raise clk
		NdisRawReadPortUchar(ioaddr, &TmpVal);
		TmpVal &= EE_DO;  // &0x01
		retval = (retval << 1) | TmpVal;
		NdisRawWritePortUchar(ioaddr, EE_ENB); //low clk
	}
	NdisRawWritePortUchar(ioaddr, ~EE_CS);
	return retval;
}

//////////////////////////////////////////////////////////////////////////
NDIS_STATUS AllocRes(PADAPTER	adapter	)
{
	NDIS_STATUS	Status;
	UINT		i;
	NDIS_PHYSICAL_ADDRESS	PhysicalAddress;

	Status = NdisMAllocateMapRegisters( //为随后的总线DMA操作来在miniport驱动初始化期间预定系统资源
						adapter->MiniportAdapterHandle,
						0,//IN UINT  DmaChannel  must 0
						CM_RESOURCE_DMA_32, //IN NDIS_DMA_SIZE  DmaSize
						1,  //IN ULONG  BaseMapRegistersNeeded
						256 );//IN ULONG  MaximumBufferSize dma transtrate max = 2k
	if(NDIS_STATUS_SUCCESS != Status) 
		return Status;
//------------------------------------------------------------------发送
	NdisMAllocateSharedMemory(
			adapter->MiniportAdapterHandle,
			TX_BUF_SIZE * NUM_OF_DESC,  //1536 * 4
			FALSE,//not cached
			&adapter->tx_bufs, //发送缓冲区虚拟基地址
			&PhysicalAddress); //物理地址
	if(adapter->tx_bufs == NULL)
		return STATUS_INSUFFICIENT_RESOURCES;
	adapter->tx_bufs_dma = PhysicalAddress;

//------------------------------------------------------------接收
//分配和映射一个主机存储器范围,以便于主机系统和DMA NIC可同时访问存储器范围
	NdisMAllocateSharedMemory(//为数据结构分配共享内存
			adapter->MiniportAdapterHandle,
			RING_BUF_SIZE + RING_BUF_PAD,  //IN ULONG  Length  16K +1536
			FALSE,// IN BOOLEAN  Cached   FALSE not cached
			&adapter->rx_ring, //环状缓冲区虚拟基地址 OUT PVOID  *VirtualAddress
//返回为微端口驱动程序使用而分配的虚拟基地址,若不能分配,则返回NULL
			&PhysicalAddress); //物理地址 OUT PNDIS_PHYSICAL_ADDRESS  PhysicalAddress
	if(adapter->rx_ring == NULL)
		return STATUS_INSUFFICIENT_RESOURCES;
	adapter->rx_ring_dma = PhysicalAddress;

	
	NdisMAllocateSharedMemory(
			adapter->MiniportAdapterHandle,
			RX_BUF_SIZE * NUM_OF_PACKETS,  //1536 * 64
			FALSE,//not cached
			&adapter->rx_bufs, //接收缓冲区虚拟基地址
			&PhysicalAddress );//物理地址
	if(adapter->rx_bufs == NULL)
		return STATUS_INSUFFICIENT_RESOURCES;
	adapter->rx_bufs_dma = PhysicalAddress;

	NdisAllocatePacketPool(//为包描述符池分配和初始化一个存储块
		&Status,  //OUT PNDIS_STATUS  Status
		&adapter->pkt_pool, //OUT PNDIS_HANDLE  PoolHandle
		NUM_OF_PACKETS,	//IN UINT  NumberOfDescriptors,   池应该包含的包描述符的个数64
		16	); // IN UINT  ProtocolReservedLength  分配给每一包描述符ProtocolReserved数组的字节数
	if(Status != NDIS_STATUS_SUCCESS)
		return STATUS_INSUFFICIENT_RESOURCES;

	NdisAllocateBufferPool(//返回一个调用者通过调用NdisAllocateBuffer用来分配缓冲描述符的句柄
		&Status,
		&adapter->buf_pool,
		NUM_OF_PACKETS); //IN UINT  NumberOfDescriptors 缓冲描述符的个数 64
	if(Status != NDIS_STATUS_SUCCESS)
		return STATUS_INSUFFICIENT_RESOURCES;

//-------------------
	for(i = 0; i < NUM_OF_PACKETS; i ++)   // 64个包描述符 64个缓冲描述符 0 ~63 
	{   // 一个包描述符包含一个缓冲描述符 每个缓冲描述符的大小为RX_BUF_SIZE(1536)
		NdisAllocatePacket(//分配和初始化一个包描述符
			&Status,
			&adapter->pkt_desc[i], //OUT PNDIS_PACKET  *Packet 返回分配的包描述符指针
			adapter->pkt_pool);    //IN NDIS_HANDLE  PoolHandle
		if(Status != NDIS_STATUS_SUCCESS)
			return STATUS_INSUFFICIENT_RESOURCES;

		NdisAllocateBuffer( //创建了,在一已经分配的非分页内存块内映射特定虚拟(子)范围的,缓冲描述符
			&Status,
			&adapter->buf_desc[i],  //返回分配的缓冲描述符指针
			adapter->buf_pool,
			adapter->rx_bufs + (i * RX_BUF_SIZE), //IN PVOID  VirtualAddress 接收缓冲区虚拟基地址
//指向原先分配的系统空间内存(将要在缓冲描述符指针中映射)的虚拟基地址 
			RX_BUF_SIZE); //IN UINT  Length 要映射的字节数
	
		NdisChainBufferAtBack( //把一给定的缓冲描述符链接到,已连接到包描述符的缓冲描述符链的尾部
//如果给定的包还没有缓冲描述符存在,则把给定的要链接的缓冲描述符链到链的头部
			adapter->pkt_desc[i],   //IN OUT PNDIS_PACKET  Packet 
			adapter->buf_desc[i]);  //IN OUT PNDIS_BUFFER  Buffer
	}

	adapter->read_ptr = 0; //从环状缓冲区数据拷贝的起始地址
	adapter->FreeRxPkt = NUM_OF_PACKETS;   //被释放的可用接收包数量64
	adapter->cur_rx = 0;  //当前接收的包的包的序号
	adapter->dirty_rx = 0;
	adapter->FreeTxDesc = NUM_OF_DESC;   //被释放的可用发送描述符数量4
	adapter->cur_tx = 0;//当前发送的描述符的序号

	return NDIS_STATUS_SUCCESS;
}

//-------------------------------------------//#pragma PAGE_CODE IRQL:PASSIVE_LEVEL
VOID StartDevice(PADAPTER	adapter)
{
	SetMII(adapter);
	NdisRawWritePortUlong(adapter->ioaddr + RxConfig, rtl8139_rx_config);
	NdisRawWritePortUlong(adapter->ioaddr + TxConfig, RL_TXCFG_CONFIG);
	NdisRawWritePortUlong(adapter->ioaddr + RxBuf,  //接收缓冲开始地址
		NdisGetPhysicalAddressLow(adapter->rx_ring_dma));
	NdisRawWritePortUlong(adapter->ioaddr + RxMissed, 0);  //写入任何值都将复位RxMissed寄存器
    adapter->PacketFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST;
	//Directed包 含有的目的地址等于NIC的station地址
//Multicast address packets sent to addresses in the multicast address list
	NdisRawWritePortUlong(adapter->ioaddr + MAR0, 0x80004000);
	NdisRawWritePortUlong(adapter->ioaddr + MAR0 + 4, 0);
	((PULONG)adapter->mc_filter)[0] = 0x80004000; //multicast address list
	((PULONG)adapter->mc_filter)[1] = 0;
	NdisRawWritePortUchar(adapter->ioaddr + ChipCmd, CmdRxEnb | CmdTxEnb);//使能 接收和发送
	NdisRawWritePortUshort(adapter->ioaddr + IntrMask, R39_INTERRUPT_MASK);//使能大多数中断
}

//-------------------------------------------------------------------------
//#pragma PAGE_CODE 释放资源 IRQL:PASSIVE_LEVEL
VOID FreeRes(PADAPTER	adapter)
{
	if(adapter->ioaddr != 0)  //释放 I/O 端口资源

⌨️ 快捷键说明

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