📄 nic_init.c
字号:
DebugPrint(LOUD, DBG_INIT,
"I/O mapped CSR: (%x) Length: (%d)\n",
resourceTrans->u.Port.Start.LowPart,
resourceTrans->u.Port.Length);
//
// Since we know the resources are listed in the same order the as
// BARs in the config space, this should be the second one.
//
if(numberOfBARs != 2) {
DebugPrint(ERROR, DBG_INIT, "I/O mapped CSR is not in the right order\n");
status = STATUS_DEVICE_CONFIGURATION_ERROR;
goto End;
}
//
// The port is in memory space on this machine.
// We shuld use READ_PORT_Xxx, and WRITE_PORT_Xxx routines
// to read or write to the port.
//
FdoData->IoBaseAddress = ULongToPtr(resourceTrans->u.Port.Start.LowPart);
FdoData->IoRange = resourceTrans->u.Port.Length;
//
// Since all our accesses are USHORT wide, we will create an accessor
// table just for these two functions.
//
FdoData->ReadPort = NICReadPortUShort;
FdoData->WritePort = NICWritePortUShort;
bResPort = TRUE;
FdoData->MappedPorts = FALSE;
break;
case CmResourceTypeMemory:
numberOfBARs++;
if(numberOfBARs == 1) {
DebugPrint(LOUD, DBG_INIT, "Memory mapped CSR:(%x:%x) Length:(%d)\n",
resourceTrans->u.Memory.Start.LowPart,
resourceTrans->u.Memory.Start.HighPart,
resourceTrans->u.Memory.Length);
//
// Our CSR memory space should be 0x1000 in size.
//
ASSERT(resourceTrans->u.Memory.Length == 0x1000);
FdoData->MemPhysAddress = resourceTrans->u.Memory.Start;
FdoData->CSRAddress = MmMapIoSpace(
resourceTrans->u.Memory.Start,
NIC_MAP_IOSPACE_LENGTH,
MmNonCached);
if(FdoData->CSRAddress == NULL) {
DebugPrint(ERROR, DBG_INIT, "MmMapIoSpace failed\n");
status = STATUS_INSUFFICIENT_RESOURCES;
goto End;
}
DebugPrint(LOUD, DBG_INIT, "CSRAddress=%p\n", FdoData->CSRAddress);
bResMemory = TRUE;
} else if(numberOfBARs == 2){
DebugPrint(LOUD, DBG_INIT,
"I/O mapped CSR in Memory Space: (%x) Length: (%d)\n",
resourceTrans->u.Memory.Start.LowPart,
resourceTrans->u.Memory.Length);
//
// The port is in memory space on this machine.
// We should call MmMapIoSpace to map the physical to virtual
// address, and also use the READ/WRITE_REGISTER_xxx function
// to read or write to the port.
//
FdoData->IoBaseAddress = MmMapIoSpace(
resourceTrans->u.Memory.Start,
resourceTrans->u.Memory.Length,
MmNonCached);
if(FdoData->IoBaseAddress == NULL) {
DebugPrint(ERROR, DBG_INIT, "MmMapIoSpace failed\n");
status = STATUS_INSUFFICIENT_RESOURCES;
goto End;
}
FdoData->ReadPort = NICReadRegisterUShort;
FdoData->WritePort = NICWriteRegisterUShort;
FdoData->MappedPorts = TRUE;
bResPort = TRUE;
} else if(numberOfBARs == 3){
DebugPrint(LOUD, DBG_INIT, "Flash memory:(%x:%x) Length:(%d)\n",
resourceTrans->u.Memory.Start.LowPart,
resourceTrans->u.Memory.Start.HighPart,
resourceTrans->u.Memory.Length);
//
// Our flash memory should be 1MB in size. Since we don't
// access the memory, let us not bother mapping it.
//
} else {
DebugPrint(ERROR, DBG_INIT,
"Memory Resources are not in the right order\n");
status = STATUS_DEVICE_CONFIGURATION_ERROR;
goto End;
}
break;
case CmResourceTypeInterrupt:
ASSERT(!bResInterrupt);
bResInterrupt = TRUE;
//
// Save all the interrupt specific information in the device
// extension because we will need it to disconnect and connect the
// interrupt later on during power suspend and resume.
//
FdoData->InterruptLevel = (UCHAR)resourceTrans->u.Interrupt.Level;
FdoData->InterruptVector = resourceTrans->u.Interrupt.Vector;
FdoData->InterruptAffinity = resourceTrans->u.Interrupt.Affinity;
if (resourceTrans->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
FdoData->InterruptMode = Latched;
} else {
FdoData->InterruptMode = LevelSensitive;
}
//
// Because this is a PCI device, we KNOW it must be
// a LevelSensitive Interrupt.
//
ASSERT(FdoData->InterruptMode == LevelSensitive);
DebugPrint(LOUD, DBG_INIT,
"Interrupt level: 0x%0x, Vector: 0x%0x, Affinity: 0x%x\n",
FdoData->InterruptLevel,
FdoData->InterruptVector,
(UINT)FdoData->InterruptAffinity); // casting is done to keep WPP happy
break;
default:
//
// This could be device-private type added by the PCI bus driver. We
// shouldn't filter this or change the information contained in it.
//
DebugPrint(LOUD, DBG_INIT, "Unhandled resource type (0x%x)\n",
resourceTrans->Type);
break;
}
}
//
// Make sure we got all the 3 resources to work with.
//
if (!(bResPort && bResInterrupt && bResMemory)) {
status = STATUS_DEVICE_CONFIGURATION_ERROR;
goto End;
}
//
// Disable interrupts here which is as soon as possible
//
NICDisableInterrupt(FdoData);
IoInitializeDpcRequest(FdoData->Self, (PKDEFERRED_ROUTINE)NICDpcForIsr);
//
// Register the interrupt
//
status = IoConnectInterrupt(&FdoData->Interrupt,
NICInterruptHandler,
FdoData, // ISR Context
NULL,
FdoData->InterruptVector,
FdoData->InterruptLevel,
FdoData->InterruptLevel,
FdoData->InterruptMode,
TRUE, // shared interrupt
FdoData->InterruptAffinity,
FALSE);
if (status != STATUS_SUCCESS)
{
DebugPrint(ERROR, DBG_INIT, "IoConnectInterrupt failed %x\n", status);
goto End;
}
MP_SET_FLAG(FdoData, fMP_ADAPTER_INTERRUPT_IN_USE);
//
// Zero out the entire structure first.
//
RtlZeroMemory(&deviceDescription, sizeof(DEVICE_DESCRIPTION));
//
// DMA_VER2 is defined when the driver is built to work on XP and
// above. The difference between DMA_VER2 and VER0 is that VER2
// support BuildScatterGatherList & CalculateScatterGatherList functions.
// BuildScatterGatherList performs the same operation as
// GetScatterGatherList, except that it uses the buffer supplied
// in the ScatterGatherBuffer parameter to hold the scatter/gather
// list that it creates. In contrast, GetScatterGatherList
// dynamically allocates a buffer to hold the scatter/gather list.
// If insufficient memory is available to allocate the buffer,
// GetScatterGatherList can fail with a STATUS_INSUFFICIENT_RESOURCES
// error. Drivers that must avoid this scenario can pre-allocate a
// buffer to hold the scatter/gather list, and use BuildScatterGatherList
// instead. A driver can use the CalculateScatterGatherList routine
// to determine the size of buffer to allocate to hold the
// scatter/gather list.
//
#if defined(DMA_VER2)
deviceDescription.Version = DEVICE_DESCRIPTION_VERSION2;
#else
deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
#endif
deviceDescription.Master = TRUE;
deviceDescription.ScatterGather = TRUE;
deviceDescription.Dma32BitAddresses = TRUE;
deviceDescription.Dma64BitAddresses = FALSE;
deviceDescription.InterfaceType = PCIBus;
//
// Bare minimum number of map registers required to do
// a single NIC_MAX_PACKET_SIZE transfer.
//
miniMapRegisters = ((NIC_MAX_PACKET_SIZE * 2 - 2) / PAGE_SIZE) + 2;
//
// Maximum map registers required to do simultaneous transfer
// of all TCBs assuming each packet spanning NIC_MAX_PHYS_BUF_COUNT
// (Each request has chained MDLs).
//
maxMapRegistersRequired = FdoData->NumTcb * NIC_MAX_PHYS_BUF_COUNT;
//
// The maximum length of buffer for maxMapRegistersRequired number of
// map registers would be.
//
MaximumPhysicalMapping = (maxMapRegistersRequired-1) << PAGE_SHIFT;
deviceDescription.MaximumLength = MaximumPhysicalMapping;
DmaAdapterObject = IoGetDmaAdapter(FdoData->UnderlyingPDO,
&deviceDescription,
&MapRegisters);
if (DmaAdapterObject == NULL)
{
DebugPrint(ERROR, DBG_INIT, "IoGetDmaAdapter failed\n");
status = STATUS_INSUFFICIENT_RESOURCES;
goto End;
}
if(MapRegisters < miniMapRegisters) {
DebugPrint(ERROR, DBG_INIT, "Not enough map registers: Allocated %d, Required %d\n",
MapRegisters, miniMapRegisters);
status = STATUS_INSUFFICIENT_RESOURCES;
goto End;
}
FdoData->AllocatedMapRegisters = MapRegisters;
//
// Adjust our TCB count based on the MapRegisters we got.
//
FdoData->NumTcb = MapRegisters/miniMapRegisters;
//
// Reset it NIC_MAX_TCBS if it exceeds that.
//
FdoData->NumTcb = min(FdoData->NumTcb, NIC_MAX_TCBS);
DebugPrint(TRACE, DBG_INIT, "MapRegisters Allocated %d\n", MapRegisters);
DebugPrint(TRACE, DBG_INIT, "Adjusted TCB count is %d\n", FdoData->NumTcb);
FdoData->DmaAdapterObject = DmaAdapterObject;
MP_SET_FLAG(FdoData, fMP_ADAPTER_SCATTER_GATHER);
#if defined(DMA_VER2)
status = DmaAdapterObject->DmaOperations->CalculateScatterGatherList(
DmaAdapterObject,
NULL,
0,
MapRegisters * PAGE_SIZE,
&ScatterGatherListSize,
&SGMapRegsisters);
ASSERT(NT_SUCCESS(status));
ASSERT(SGMapRegsisters == MapRegisters);
if (!NT_SUCCESS(status))
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto End;
}
FdoData->ScatterGatherListSize = ScatterGatherListSize;
#endif
//
// For convenience, let us save the frequently used DMA operational
// functions in our device context.
//
FdoData->AllocateCommonBuffer =
*DmaAdapterObject->DmaOperations->AllocateCommonBuffer;
FdoData->FreeCommonBuffer =
*DmaAdapterObject->DmaOperations->FreeCommonBuffer;
End:
//
// If we have jumped here due to any kind of mapping or resource allocation
// failure, we should clean up. Since we know that if we fail Start-Device,
// the system is going to send Remove-Device request, we will defer the
// job of cleaning to NICUnmapHWResources which is called in the Remove path.
//
return status;
}
NTSTATUS
NICUnmapHWResources(
IN OUT PFDO_DATA FdoData
)
/*++
Routine Description:
Disconnect the interrupt and unmap all the memory and I/O resources.
Arguments:
FdoData Pointer to our FdoData
Return Value:
None
--*/
{
PDMA_ADAPTER DmaAdapterObject = FdoData->DmaAdapterObject;
//
// Free hardware resources
//
if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_INTERRUPT_IN_USE))
{
IoDisconnectInterrupt(FdoData->Interrupt);
FdoData->Interrupt = NULL;
MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_INTERRUPT_IN_USE);
}
if (FdoData->CSRAddress)
{
MmUnmapIoSpace(FdoData->CSRAddress, NIC_MAP_IOSPACE_LENGTH);
FdoData->CSRAddress = NULL;
}
if(FdoData->MappedPorts){
MmUnmapIoSpace(FdoData->IoBaseAddress, FdoData->IoRange);
FdoData->IoBaseAddress = NULL;
}
if(DmaAdapterObject && MP_TEST_FLAG(FdoData, fMP_ADAPTER_SCATTER_GATHER)){
DmaAdapterObject->DmaOperations->PutDmaAdapter(DmaAdapterObject);
FdoData->DmaAdapterObject = NULL;
FdoData->AllocateCommonBuffer = NULL;
FdoData->FreeCommonBuffer = NULL;
MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_SCATTER_GATHER);
}
return STATUS_SUCCESS;
}
NTSTATUS
NICGetDeviceInformation(
IN PFDO_DATA FdoData
)
/*++
Routine Description:
This function reads the PCI config space and make sure that it's our
device and stores the device IDs and power information in the device
extension. Should be done in the StartDevice.
Arguments:
FdoData Pointer to our FdoData
Return Value:
None
--*/
{
NTSTATUS status = STATUS_SUCCESS;
UCHAR buffer[NIC_PCI_E100_HDR_LENGTH ];
PPCI_COMMON_CONFIG pPciConfig = (PPCI_COMMON_CONFIG) buffer;
USHORT usPciCommand;
ULONG bytesRead =0;
DebugPrint(TRACE, DBG_INIT, "---> NICGetDeviceInformation\n");
bytesRead = FdoData->BusInterface.GetBusData(
FdoData->BusInterface.Context,
PCI_WHICHSPACE_CONFIG, //READ
buffer,
FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID),
NIC_PCI_E100_HDR_LENGTH);
if (bytesRead != NIC_PCI_E100_HDR_LENGTH) {
DebugPrint(ERROR, DBG_INIT,
"GetBusData (NIC_PCI_E100_HDR_LENGTH) failed =%d\n",
bytesRead);
return STATUS_INVALID_DEVICE_REQUEST;
}
//
// Is this our device?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -