📄 driver.c
字号:
#include "driver.h"
//////////////////////////////////////////////////////////////////////////////////
//DriverEntry由系统调用来装载驱动程序。DriverEntry产生一个微端口驱动程序
//和NDIS库的连接,并且向NDIS注册微端口的版本和入口指针
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath )
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
NDIS_HANDLE NdisWrapperHandle;
NDIS_MINIPORT_CHARACTERISTICS R8139Char;
//----------------------------------------------------------------------------
RtlInitUnicodeString(&ntDeviceName, L"\\Device\\miniport-rtl");
RtlInitUnicodeString(&win32SymbolicLinkName, L"\\DosDevices\\miniport-rtl");
Status = IoCreateDevice ( DriverObject,
0,
&ntDeviceName, //内核设备名 向内核标识设备
FILE_DEVICE_UNKNOWN,
0,
FALSE, //不排斥,非独占的,一次可有多个线程同时访问该设备
&g_deviceObject);
if(Status == NDIS_STATUS_SUCCESS)
{ //创建一个符号链接来使得内核设备名对WIN32可用
Status = IoCreateSymbolicLink( &win32SymbolicLinkName, //win32符号链接名
&ntDeviceName ); //内核设备名
if(Status != NDIS_STATUS_SUCCESS)
IoDeleteDevice(g_deviceObject);
}
//------------------------------------------------------------------------------
//为miniport驱动程序初始化NDIS库数据结构, 产生 微端口驱动程序与NDIS库的一个连接
//将驱动程序对象的地址DriverObject和指向驱动程序具体信息的有关注册表路径RegistryPath作为参数
//返回代表这个微端口NIC驱动程序结构的句柄NdisWrapperHandle, 若失败,则为NULL
NdisMInitializeWrapper(&NdisWrapperHandle, //OUT PNDIS_HANDLE NdisWrapperHandle,
DriverObject, //IN PVOID SystemSpecific1
RegistryPath, //IN PVOID SystemSpecific2
NULL); //IN PVOID SystemSpecific3
if (NdisWrapperHandle == NULL)
return NDIS_STATUS_FAILURE;
NdisZeroMemory(&R8139Char, sizeof(NDIS_MINIPORT_CHARACTERISTICS));
R8139Char.MajorNdisVersion = 5;
R8139Char.MinorNdisVersion = 0;
R8139Char.CheckForHangHandler= RCheck; //MiniportCheckForHang
R8139Char.HaltHandler = RHalt; //MiniportHalt
R8139Char.HandleInterruptHandler= RIsrDpc; //MiniportHandleInterrupt
R8139Char.InitializeHandler = RInit; //MiniportInitialize
R8139Char.ISRHandler = RIsr; //MiniportISR
R8139Char.QueryInformationHandler = RQuery; //MiniportQueryInformation
R8139Char.ResetHandler = RReset; //MiniportReset
R8139Char.SetInformationHandler = RSet; //MiniportSetInformation
R8139Char.ReturnPacketHandler = RReturnPkt; //MiniportReturnPacket
R8139Char.SendPacketsHandler = RSendPkts; //MiniportSendPackets
//将自己(微端口驱动程序的MiniportXxx入口点)注册到NDIS(NdisWrapperHandle)
Status = NdisMRegisterMiniport(NdisWrapperHandle, //IN NDIS_HANDLE NdisWrapperHandle
&R8139Char, //IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
sizeof(NDIS_MINIPORT_CHARACTERISTICS)); //IN UINT CharacteristicsLength
if(Status != NDIS_STATUS_SUCCESS)
NdisTerminateWrapper(NdisWrapperHandle, NULL); //释放微端口驱动程序调用NdisMInitializeWrapper时分配的系统资源
DriverObject->MajorFunction[IRP_MJ_CREATE] = ROpen;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = RClose;
DriverObject->MajorFunction[IRP_MJ_READ] = RRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = RWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RIoControl;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = RCleanup;
DriverObject->DriverUnload = RUnload;
return Status;
}
//////////////////////////////////////////////////////////////////////
//NDIS每两秒调用一次MiniportCheckForHang函数来检查NIC的运行状态
//如果它检测到NIC工作不正常,那么MiniportCheckForHang返回TRUE;否则,它返回FALSE
//如果返回TRUE,NDIS将调用MiniportReset函数
BOOLEAN RCheck( IN NDIS_HANDLE MiniportAdapterContext)
{
return FALSE;
}
//////////////////////////////////////////////////////////////////////
//终止一个微端口驱动程序, 释放由微端口MiniportInitialize所声明的系统资源
VOID RHalt( IN NDIS_HANDLE MiniportAdapterContext )
{
PADAPTER adapter = (PADAPTER)MiniportAdapterContext;
NdisRawWritePortUshort(adapter->ioaddr + IntrMask, 0); //禁止所有中断
NdisRawWritePortUchar(adapter->ioaddr + ChipCmd, 0); //接收、传输禁止
FreeRes((PADAPTER)MiniportAdapterContext);
}
//////////////////////////////////////////////////////////////////////////////
//#pragma LOCK_CODE
VOID RIsr(OUT PBOOLEAN InterruptRecognized,
OUT PBOOLEAN QueueMiniportHandleInterrupt,
IN NDIS_HANDLE MiniportAdapterContext )
{
PADAPTER adapter = (PADAPTER)MiniportAdapterContext;
USHORT currentISR;
NdisRawReadPortUshort(adapter->ioaddr + IntrStatus, ¤tISR);
if(currentISR & R39_INTERRUPT_MASK)
{
NdisRawWritePortUshort(adapter->ioaddr + IntrMask, 0); //禁止所有中断
adapter->curISR = currentISR & R39_INTERRUPT_MASK;
*InterruptRecognized = TRUE;//若检测到来自NIC的中断则设该变量为TRUE
*QueueMiniportHandleInterrupt = TRUE;
//如果应该调用MiniportHandleInterrupt函数来处理中断则设QueueMiniportHandleInterrupt为TRUE
}else
{
*InterruptRecognized = FALSE;
*QueueMiniportHandleInterrupt = FALSE;
}
}
//////////////////////////////////////////////////////////////////////
//#pragma LOCK_CODE 处理中断
VOID RIsrDpc( IN NDIS_HANDLE MiniportAdapterContext )
{
PADAPTER adapter = (PADAPTER)MiniportAdapterContext;
USHORT write_ptr;
if((adapter->curISR & TxOK)||(adapter->curISR & TxErr)) //如果包传送成功结束或由于过量冲突而丢弃
TxInt(adapter);
if(adapter->curISR & RxOK) // 表明包接收成功结束
RxInt(adapter);
if( adapter->curISR & (RxErr|RxOverflow|RxFIFOOver))
{ // 接收包有CRC错误或帧对齐错误 | 接收环状缓冲区资源耗尽 | 接收FIFO溢出
NdisRawReadPortUshort(adapter->ioaddr + RxBufAddr, &write_ptr);
//当前的缓冲区地址指针,初值为0x0000,它反映了接收缓冲区中接收到的字节总数
adapter->read_ptr = write_ptr % RING_BUF_SIZE;//求余 得到环状缓冲区数据拷贝的末地址
NdisRawWritePortUshort(adapter->ioaddr + RxBufPtr, adapter->read_ptr - 16);
NdisRawWritePortUshort(adapter->ioaddr + IntrStatus, RxOK); //写入ISR没效果
}
NdisRawWritePortUshort(adapter->ioaddr + IntrMask, R39_INTERRUPT_MASK); //使能大多数中断
}
////////////////////////////////////////////////////////////////////////////
//当在微端口DriverEntry函数中调用NdisMRegisterMiniport函数返回时,
//NDIS立即为每个微端口管理的NIC,调用微端口的MiniportInitialize函数
NDIS_STATUS RInit(
OUT PNDIS_STATUS OpenErrorStatus,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE MiniportAdapterHandle,
IN NDIS_HANDLE WrapperConfigurationContext)
{
UINT i;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PADAPTER adapter;
ULONG ulReadSize ;
ULONG ulVenDevID;
PNDIS_RESOURCE_LIST resList;
CM_PARTIAL_RESOURCE_DESCRIPTOR resDesc;
USHORT TmpCommand;
KdPrint(("go into RInit \n"));
for (i = 0; i < MediumArraySize; i++) // 媒体类型定义
{ // MediumArray 操作系统支持的媒体类型
if (MediumArray[i] == NdisMedium802_3)
break; //跳出本层循环
}
if (i == MediumArraySize) // 表示没发现MediumArray[i] == NdisMedium802_3
{
KdPrint(("802.3 Media type not found.\n"));
return NDIS_STATUS_UNSUPPORTED_MEDIA;
}
*SelectedMediumIndex = i; // return the selected medium type
//------------------------------------------------------------------------------
//分配驻留(不分页)的系统空间内存,允许调用者提供一个可用来跟踪驱动程序内存分配的标记
Status = NdisAllocateMemoryWithTag(
&adapter, //OUT PVOID *VirtualAddress 存储该函数返回所分配的内存虚拟基地址
sizeof(ADAPTER), //IN UINT Length
'9318'); //IN ULONG Tag 'dehw' 可达到4字节,反顺序
if(Status != NDIS_STATUS_SUCCESS)
goto err;
NdisZeroMemory(adapter, sizeof(ADAPTER));
g_adapter = adapter;
adapter->MiniportAdapterHandle = MiniportAdapterHandle;
//------------------------------------------------------------------------------
//告知NDIS库在初始化过程中的有关调用者的NIC的重要属性
NdisMSetAttributes( MiniportAdapterHandle,//IN NDIS_HANDLE MiniportAdapterHandle,
adapter, //IN NDIS_HANDLE MiniportAdapterContext,
TRUE, //IN BOOLEAN BusMaster,
NdisInterfacePci); //IN NDIS_INTERFACE_TYPE AdapterType
//------------------------------------------------------------------------------
//从PCI设备的配置空间获得PCI总线的配置信息
ulReadSize = NdisReadPciSlotInformation(
MiniportAdapterHandle, //IN NDIS_HANDLE NdisAdapterHandle,
0, //IN ULONG SlotNumber,保留值,NDIS忽略该参数
0, //IN ULONG Offset指定PCI配置空间内的字节偏移量,从该处开始来传输配置信息
&ulVenDevID, //IN PVOID Buffer
4); //IN ULONG Length
if(ulVenDevID != 0x813910ec)
{
DbgPrint("no find our nic card. \n");
Status = NDIS_STATUS_FAILURE;
goto err;
}
// I/O空间访问使能 MEMORY空间访问使能 总线Master使能
NdisReadPciSlotInformation(
adapter->MiniportAdapterHandle,
0,//IN ULONG SlotNumber,保留值,NDIS忽略该参数
PCI_COMMAND, //0x04 指定PCI配置空间内的字节偏移量,从该处开始来传输配置信息
&TmpCommand,
2);//IN ULONG Length
TmpCommand |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
NdisWritePciSlotInformation(
adapter->MiniportAdapterHandle,
0,
PCI_COMMAND,
&TmpCommand,
2);
//------------------------------------------------------------------------------
//返回注册表中的PCI NIC的特定硬件资源,例如 IRQ ,I/O端口,存储器范围
//在 windows xp及以后版本,该函数由NdisMQueryAdapterResources代替
Status = NdisMPciAssignResources(MiniportAdapterHandle, //IN NDIS_HANDLE MiniportHandle
0, // IN ULONG SlotNumber 保留值,NDIS忽略该参数
&resList); //OUT PNDIS_RESOURCE_LIST *AssignedResources
if(Status != NDIS_STATUS_SUCCESS)
goto err;
for(i = 0; i < resList->Count; i ++)
{
resDesc = resList->PartialDescriptors[i];
switch(resDesc.Type)
{
case CmResourceTypePort: //I/O端口资源
adapter->BaseIO = (ULONG)resDesc.u.Port.Start.LowPart; //端口总线特定的开始地址
ASSERT(0x100 == resDesc.u.Port.Length);
break;
case CmResourceTypeInterrupt: //中断资源
adapter->IRQLevel = resDesc.u.Interrupt.Level;
adapter->IRQVector = resDesc.u.Interrupt.Vector;
adapter->IRQAffinity = resDesc.u.Interrupt.Affinity;
adapter->IRQMode = resDesc.Flags & (CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE | CM_RESOURCE_INTERRUPT_LATCHED);
break;
// case CmResourceTypeMemory: //内存资源 8139不使用内存资源
// break;
default:
break;
}
}
//------------------------------------------------------------------------------
//sets up driver access to device I/O ports with the NdisRawReadPortXxx and NdisRawWritePortXxx
//functions and claims the range of I/O port addresses in the registry for that driver's NIC
//在adapter->ioaddr中返回映射的虚拟基地址,
//用于在NdisRawReadPortXxx 和 NdisRawWritePortXxx 函数中读写NIC的寄存器
Status = NdisMRegisterIoPortRange(
(PVOID*)&adapter->ioaddr,//OUT PVOID *PortOffset 返回映射的虚拟基地址
adapter->MiniportAdapterHandle,
adapter->BaseIO, //IN UINT InitialPort
0x100);//IN UINT NumberOfPorts
if(NDIS_STATUS_SUCCESS != Status)
goto err;
((USHORT*)adapter->NetworkAddress)[0] = readEEPROM((PUCHAR)(adapter->ioaddr+Cmd93C46), 7);
((USHORT*)adapter->NetworkAddress)[1] = readEEPROM((PUCHAR)(adapter->ioaddr+Cmd93C46), 8);
((USHORT*)adapter->NetworkAddress)[2] = readEEPROM((PUCHAR)(adapter->ioaddr+Cmd93C46), 9);
//------------------------------------------------------------------------------
Status = AllocRes(adapter);
if(NDIS_STATUS_SUCCESS != Status)
goto err;
//------------------------------------------------------------------------------
Status = NdisMRegisterInterrupt(
&adapter->IntObj, //OUT PNDIS_MINIPORT_INTERRUPT Interrupt
adapter->MiniportAdapterHandle,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -