📄 nic_init.c
字号:
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Module Name:
NIC_INIT.c
Abstract:
Contains rotuines to do resource allocation and hardware
initialization & shutdown.
Environment:
Kernel mode
Revision History:
Eliyas Yakub Feb 13, 2003
--*/
#include "precomp.h"
#if defined(EVENT_TRACING)
#include "nic_init.tmh"
#endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, NICInitializeDeviceExtension)
#pragma alloc_text (PAGE, NICAllocateDeviceResources)
#pragma alloc_text (PAGE, NICMapHWResources)
#pragma alloc_text (PAGE, NICUnmapHWResources)
#pragma alloc_text (PAGE, NICGetDeviceInformation)
#pragma alloc_text (PAGE, NICReadAdapterInfo)
#pragma alloc_text (PAGE, NICAllocAdapterMemory)
#pragma alloc_text (PAGE, NICFreeAdapterMemory)
#pragma alloc_text (PAGE, NICInitRecv)
#pragma alloc_text (PAGE, NICSelfTest)
#pragma alloc_text (PAGE, NICInitializeAdapter)
#pragma alloc_text (PAGE, HwConfigure)
#pragma alloc_text (PAGE, HwClearAllCounters)
#pragma alloc_text (PAGE, HwSetupIAAddress)
#pragma alloc_text (PAGE, GetPCIBusInterfaceStandard)
#pragma alloc_text (PAGE, NICAllocRfd)
#pragma alloc_text (PAGE, NICFreeRfd)
#pragma alloc_text (PAGE, NICAllocRfdWorkItem)
#pragma alloc_text (PAGE, NICFreeRfdWorkItem)
#endif
NTSTATUS
NICInitializeDeviceExtension(
IN OUT PFDO_DATA FdoData
)
/*++
Routine Description:
Arguments:
FdoData Pointer to our FdoData
Return Value:
None
--*/
{
NTSTATUS status;
//
// Get the BUS_INTERFACE_STANDARD for our device so that we can
// read & write to PCI config space at IRQL <= DISPATCH_LEVEL.
//
status = GetPCIBusInterfaceStandard(FdoData->Self,
&FdoData->BusInterface);
if (!NT_SUCCESS (status)){
return status;
}
NICGetDeviceInfSettings(FdoData);
FdoData->ConservationIdleTime = -SECOND_TO_100NS * PCIDRV_DEF_IDLE_TIME;
FdoData->PerformanceIdleTime = -SECOND_TO_100NS * PCIDRV_DEF_IDLE_TIME;
//
// Initialize list heads, spinlocks, timers etc.
//
InitializeListHead(&FdoData->SendQueueHead);
InitializeListHead(&FdoData->RecvList);
InitializeListHead(&FdoData->RecvQueueHead);
InitializeListHead(&FdoData->PoMgmt.PatternList);
KeInitializeSpinLock(&FdoData->Lock);
KeInitializeSpinLock(&FdoData->SendLock);
KeInitializeSpinLock(&FdoData->RcvLock);
KeInitializeSpinLock(&FdoData->RecvQueueLock);
//
// To minimize init-time, queue a DPC to do link detection.
// This DPC will also be used to check of hardware hang.
//
KeInitializeDpc(&FdoData->WatchDogTimerDpc, // Dpc
NICWatchDogTimerDpc, // DeferredRoutine
FdoData // DeferredContext
);
KeInitializeTimer(&FdoData->WatchDogTimer );
//
// Event used to make sure the NICWatchDogTimerDpc has completed execution
// before freeing the resources and unloading the driver.
//
KeInitializeEvent(&FdoData->WatchDogTimerEvent, NotificationEvent, TRUE);
return status;
}
NTSTATUS
NICAllocateDeviceResources(
IN OUT PFDO_DATA FdoData,
IN PIRP Irp
)
/*++
Routine Description:
Allocates all the hw and software resources required for
the device, enables interrupt, and initializes the device.
Arguments:
FdoData Pointer to our FdoData
Irp Pointer to start-device irp.
Return Value:
None
--*/
{
NTSTATUS status;
LARGE_INTEGER DueTime;
do{
//
// First make sure this is our device before doing whole lot
// of other things.
//
status = NICGetDeviceInformation(FdoData);
if (!NT_SUCCESS (status)){
return status;
}
status = NICMapHWResources(FdoData, Irp);
if (!NT_SUCCESS (status)){
DebugPrint(ERROR, DBG_INIT,"NICMapHWResources failed: 0x%x\n",
status);
break;
}
//
// Read additional info from NIC such as MAC address
//
status = NICReadAdapterInfo(FdoData);
if (status != STATUS_SUCCESS)
{
break;
}
status = NICAllocAdapterMemory(FdoData);
if (status != STATUS_SUCCESS)
{
break;
}
NICInitSend(FdoData);
status = NICInitRecv(FdoData);
if (status != STATUS_SUCCESS)
{
break;
}
//
// Test our adapter hardware
//
status = NICSelfTest(FdoData);
if (status != STATUS_SUCCESS)
{
break;
}
status = NICInitializeAdapter(FdoData);
if (status != STATUS_SUCCESS)
{
break;
}
//
// Enable the interrupt
//
NICEnableInterrupt(FdoData);
//
// Set the link detection flag to indicate that NICWatchDogTimerDpc
// will be first doing link-detection.
//
MP_SET_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION);
FdoData->CheckForHang = FALSE;
FdoData->bLinkDetectionWait = FALSE;
FdoData->bLookForLink = FALSE;
//
// This event stays cleared until the NICWatchDogTimerDpc exits.
//
KeClearEvent(&FdoData->WatchDogTimerEvent);
//
// Watch dog timer is used to do the initial link detection during
// start and then used to make sure the device is not hung for
// any reason.
//
DueTime.QuadPart = NIC_LINK_DETECTION_DELAY;
KeSetTimer( &FdoData->WatchDogTimer, // Timer
DueTime, // DueTime
&FdoData->WatchDogTimerDpc // Dpc
);
}while(FALSE);
return status;
}
NTSTATUS
NICFreeDeviceResources(
IN OUT PFDO_DATA FdoData
)
/*++
Routine Description:
Free all the software resources. We shouldn't touch the hardware.
Arguments:
FdoData Pointer to our FdoData
Return Value:
None
--*/
{
NTSTATUS status;
KIRQL oldIrql;
DebugPrint(INFO, DBG_INIT, "-->NICFreeDeviceResources\n");
if(!KeCancelTimer(&FdoData->WatchDogTimer)){
//
// Wait for the timer to complete since it has already begun executing.
//
DebugPrint(INFO, DBG_INIT,
"Waiting for the watchdogtimer to exit..\n");
status = KeWaitForSingleObject( &FdoData->WatchDogTimerEvent,
Executive,
KernelMode,
FALSE,
NULL );
ASSERT(NT_SUCCESS(status));
}
//
// We need to raise the IRQL before acquiring the lock
// because the functions called inside the guarded
// region assume that they are called at Dpc level and release
// and reacquire the lock using DpcLevel spinlock functions.
//
KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
KeAcquireSpinLockAtDpcLevel(&FdoData->SendLock);
//
// Free the packets on SendWaitList
//
NICFreeQueuedSendPackets(FdoData);
//
// Free the packets being actively sent & stopped
//
NICFreeBusySendPackets(FdoData);
KeReleaseSpinLockFromDpcLevel(&FdoData->SendLock);
KeLowerIrql(oldIrql);
NICFreeAdapterMemory(FdoData);
//
// Disconnect from the interrupt and unmap any I/O ports
//
NICUnmapHWResources(FdoData);
DebugPrint(INFO, DBG_INIT, "<--NICFreeDeviceResources\n");
return STATUS_SUCCESS;
}
NTSTATUS
NICMapHWResources(
IN OUT PFDO_DATA FdoData,
IN PIRP Irp
)
/*++
Routine Description:
Gets the HW resources assigned by the bus driver from the start-irp
and maps it to system address space. Initializes the DMA adapter
and sets up the ISR.
Three base address registers are supported by the 8255x:
1) CSR Memory Mapped Base Address Register (BAR 0 at offset 10)
2) CSR I/O Mapped Base Address Register (BAR 1 at offset 14)
3) Flash Memory Mapped Base Address Register (BAR 2 at offset 18)
The 8255x requires one BAR for I/O mapping and one BAR for memory
mapping of these registers anywhere within the 32-bit memory address space.
The driver determines which BAR (I/O or Memory) is used to access the
Control/Status Registers.
Just for illustration, this driver maps both memory and I/O registers and
shows how to use READ_PORT_xxx or READ_REGISTER_xxx functions to perform
I/O in a platform independent basis. On some platforms, the I/O registers
can get mapped in to memory space and your driver should be able to handle
this transparently.
One BAR is also required to map the accesses to an optional Flash memory.
The 82557 implements this register regardless of the presence or absence
of a Flash chip on the adapter. The 82558 and 82559 only implement this
register if a bit is set in the EEPROM. The size of the space requested
by this register is 1Mbyte, and it is always mapped anywhere in the 32-bit
memory address space.
Note: Although the 82558 only supports up to 64 Kbytes of Flash memory
and the 82559 only supports 128 Kbytes of Flash memory, 1 Mbyte of
address space is still requested. Software should not access Flash
addresses above 64 Kbytes for the 82558 or 128 Kbytes for the 82559
because Flash accesses above the limits are aliased to lower addresses.
Arguments:
FdoData Pointer to our FdoData
Irp Pointer to start-device irp.
Return Value:
None
--*/
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceTrans;
PCM_PARTIAL_RESOURCE_LIST partialResourceListTranslated;
PIO_STACK_LOCATION stack;
ULONG i;
NTSTATUS status = STATUS_SUCCESS;
DEVICE_DESCRIPTION deviceDescription;
ULONG MaximumPhysicalMapping;
PDMA_ADAPTER DmaAdapterObject;
ULONG maxMapRegistersRequired, miniMapRegisters;
ULONG MapRegisters;
BOOLEAN bResPort = FALSE, bResInterrupt = FALSE, bResMemory = FALSE;
ULONG numberOfBARs = 0;
#if defined(DMA_VER2) // To avoid unreferenced local variables error
ULONG SGMapRegsisters;
ULONG ScatterGatherListSize;
#endif
stack = IoGetCurrentIrpStackLocation (Irp);
PAGED_CODE();
if (NULL == stack->Parameters.StartDevice.AllocatedResourcesTranslated) {
status = STATUS_DEVICE_CONFIGURATION_ERROR;
goto End;
}
//
// Parameters.StartDevice.AllocatedResourcesTranslated points
// to a CM_RESOURCE_LIST describing the hardware resources that
// the PnP Manager assigned to the device. This list contains
// the resources in translated form. Use the translated resources
// to connect the interrupt vector, map I/O space, and map memory.
//
partialResourceListTranslated = &stack->Parameters.StartDevice.\
AllocatedResourcesTranslated->List[0].PartialResourceList;
resourceTrans = &partialResourceListTranslated->PartialDescriptors[0];
for (i = 0;
i < partialResourceListTranslated->Count;
i++, resourceTrans++) {
switch (resourceTrans->Type) {
case CmResourceTypePort:
//
// We will increment the BAR count only for valid resources. We will
// not count the private device types added by the PCI bus driver.
//
numberOfBARs++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -