📄 e100bexadap.cpp
字号:
// E100bexAdap.cpp: implementation of the E100bexAdapter class.
//
//=============================================================================
//
// Compuware Corporation
// NuMega Lab
// 9 Townsend West
// Nashua, NH 03060 USA
//
// Copyright (c) 2000 Compuware Corporation. All Rights Reserved.
// Unpublished - rights reserved under the Copyright laws of the
// United States.
//
//=============================================================================
//
// Portions copied from Microsoft Windows 2000 DDK sample driver containing the
// following copyright
//
/****************************************************************************
** COPYRIGHT (C) 1994-1997 INTEL CORPORATION **
** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON **
** HTTP://WWW.INTEL.COM/ **
** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND **
** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER **
****************************************************************************/
#include <kndis.h>
#include "E100bexInc.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
E100bexAdapter::E100bexAdapter(void) :
KNdisMiniAdapter(),
m_CSRIoRange(),
m_CSRMemoryRange(),
m_Interrupt(),
m_Timer(),
m_NextFreeMapReg(0),
m_OldestUsedMapReg(0),
m_MaxPhysicalMappings(MAXIMUM_ETHERNET_PACKET_SIZE),
m_pCard(NULL),
m_pRxShMem(NULL),
m_pCbShMem(NULL),
m_pRxArea(NULL),
m_TxCBList(),
m_ActiveChainList(),
m_CompletedChainList(),
m_CoalesceBufferList(),
m_TxQueue(),
m_pTempHwDesc(NULL),
m_XmitCached(NULL),
m_XmitCachedSize(0)
{
}
E100bexAdapter::~E100bexAdapter(void)
{
delete m_pRxArea;
m_pRxArea = NULL;
// Delete the shared memory we allocated in initialize
DeleteSharedAdapterMemory();
// Delete our card object, also allocated in initialize
delete m_pCard;
}
////////////////////////////////////////////////////////////////////
// NDIS callback handlers
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// E100bexAdapter::Initialize
//
// MiniportInitialize is a required function that sets up a NIC (or
// virtual NIC) for network I/O operations, claims all hardware resources
// necessary to the NIC in the registry, and allocates resources the driver
// needs to carry out network I/O operations
//
// Parameters:
// Medium
// Reference to KNdisMedium object that we have to set the medium
// type our NIC supports
// Config
// Reference to KNdisConfig object that we use to query various
// configuration parameters
// IRQL:
// PASSIVE_LEVEL
// Return Mode:
// Synchronous
//
// TODO:
// 1) Select supported medium in Medium object
// 2) Read config parameters if any using Config object
// 3) Allocate h/w resources, pools, etc.
// 4) Register with NDIS using SetAttributes()
// 5) Register Shutdown Handler
// 6) Initialize and enable the NIC.
// NOTE: Be ready to process INTs even before the function exits
//
NDIS_STATUS E100bexAdapter::Initialize
(IN OUT KNdisMedium& Medium, IN KNdisConfig& Config)
{
NDIS_STATUS Status;
TRACE("E100bexAdapter::Initialize() Entered\n");
// Select our the Medium (pretending we are Ethernet):
if (! Medium.Select(NdisMedium802_3) )
KNDIS_RETURN_ERROR (NDIS_STATUS_UNSUPPORTED_MEDIA);
// Create our initialization structure for registry overrides
ADAPTER_INFO Ai;
// Read some other config stuff from the Registry, e.g.
if ((Status = ParseRegistryParameters(Config, Ai)) != NDIS_STATUS_SUCCESS)
KNDIS_RETURN_ERROR (Status);
// Initialize the number of Tcbs we will have in our queue
// this is to work around limitations of the hardware and the S-bit
m_NumTcb = m_RegNumTcb + 1;
// Reset the Stats counters and other data members if any:
m_Stats.Reset();
// Now let NDIS know about the BUS the NIC is on, and any flags that we need set
// for our adapter. Here's where the NDIS/Adapter-instance
// handshake takes place. This should happen *before* allocating the h/w resources:
SetAttributesEx(
NdisInterfacePci,
NDIS_ATTRIBUTE_DESERIALIZE | NDIS_ATTRIBUTE_BUS_MASTER);
// Get h/w resources assigned to our adapter.
KNdisPnpResourceRequest request(Config); // for NDIS 5
// Our adapter needs the Interrupt, Port and Memory resources.
// Get descriptors of those. We'll use the descriptors when
// allocating h/w access objects such as KNdisIoRange and
// KNdisInterrupt:
KNdisResource<CmResourceTypeInterrupt> Int(request);
KNdisResource<CmResourceTypePort> Port(request);
// Look for the last memory bar with a length of 0x1000, as others might
// be our flash address, a boot ROM address, or otherwise.
ULONG Ordinal = 0;
ULONG LastRightSizedOrdinal = 0;
BOOLEAN Valid;
do
{
KNdisResource<CmResourceTypeMemory> Memory(request, Ordinal);
Valid = Memory.IsValid();
if (Valid && Memory.Length() == 0x1000)
LastRightSizedOrdinal = Ordinal;
Ordinal++;
} while (Valid);
KNdisResource<CmResourceTypeMemory> Memory(request, LastRightSizedOrdinal);
// Make sure the resources are defined in the Registry:
if (!Int.IsValid())
KNDIS_RETURN_ERROR (NDIS_STATUS_NOT_ACCEPTED);
if (!Port.IsValid())
KNDIS_RETURN_ERROR (NDIS_STATUS_NOT_ACCEPTED);
if (!Memory.IsValid() || Memory.Length() != 0x1000)
KNDIS_RETURN_ERROR (NDIS_STATUS_NOT_ACCEPTED);
// Create the h/w access objects.
// Register our i/o ports:
m_CSRIoRange.Initialize(this, Port);
if (! NT_SUCCESS(m_CSRIoRange.Status()))
KNDIS_RETURN_ERROR (m_CSRIoRange.Status());
// Register our memory range:
m_CSRMemoryRange.Initialize(this, Memory);
if (! NT_SUCCESS(m_CSRMemoryRange.Status()))
KNDIS_RETURN_ERROR (m_CSRMemoryRange.Status());
// Create an instance of our PCI information class to
// query information from PCI configuration space
E100bexPciInformation PciInfo(this);
// Read the RevisionID
m_AiRevID = PciInfo.ReadRevisionId();
// Get the MemoryWriteInvalidateBit, then 'and' it with the value
// we obtained from the registry to set the control
Ai.MWIEnable = Ai.MWIEnable && PciInfo.GetMemoryWriteInvalidateBit();
// Enable bus mastering if not already enabled
if (FALSE == PciInfo.TestAndSetDmaMasterBit())
{
ASSERT(!"Bus master was not enabled\n");
}
// Read the subsystem vendor and subsystem device IDs
PciInfo.ReadSubsystemId(m_AiSubVendor, m_AiSubDevice);
// Create our "card" object. The real card class might want to use
// references to m_Ports and m_Interrupt as constructor's parameters.
m_pCard = new E100bexCard(*this, m_CSRMemoryRange, Ai);
if ( NULL == m_pCard )
KNDIS_RETURN_ERROR ( NDIS_STATUS_RESOURCES );
// Setup the shared adapter memory
if ((Status = SetupSharedAdapterMemory()) != NDIS_STATUS_SUCCESS)
KNDIS_RETURN_ERROR (Status);
// Disable interrupts on the H/W before registering the interrupt with NDIS
// Must SetupSharedAdapterMemory() before you can do this
m_pCard->DisableInterrupt();
// Register our interrupt: NOTE that we must register an interrupt object
// as long as we expose Disable/EnableInterrupt() handlers. NDIS would use
// them internally for KeSynchronizeExecition().
m_Interrupt.Initialize(
this,
Int,
NdisInterruptLatched);
if (! NT_SUCCESS(m_Interrupt.Status()))
KNDIS_RETURN_ERROR (m_Interrupt.Status());
// Setup and initialize the transmit structures
SetupTransmitQueues();
// set up our link indication variable
// it doesn't matter what this is right now because it will be
// set correctly if link fails
m_LinkIsActive = NdisMediaStateConnected;
// Set our power state to on.
m_Power = NdisDeviceStateD0;
// Initialize our timer object for use with our reset routine
m_Timer.Initialize(this, KNDIS_MEMBER_CALLBACK(AsyncResetTimerCallback));
// Set default filter and MAC options. In principle, we should also
// relay that to our card...
m_uMacOptions = NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
NDIS_MAC_OPTION_NO_LOOPBACK;
// Get network address (if any) from the Registry. If specified
// it will be used instead of burned permanent address:
if (Config.ReadNetworkAddress(m_AiNodeAddress) != NDIS_STATUS_SUCCESS)
m_AiNodeAddress.Invalidate();
// Check if there was a node address over-ride. If there isn't then
// use the adapter's permanent node address as the "current" node address.
// If a node address over-ride is present in the registry, then use
// that override address as the node address instead of the permanent
// address in the adapter's EEPROM
if ( ! m_AiNodeAddress.IsValid() )
{
// No node address override so use the permanent address
TRACE("E100bexAdapter::Initialize: No node address over-ride, using permanent address\n");
// Read our node address from the EEPROM.
ETHERNET_ADDRESS PermanentNodeAddress = m_pCard->ReadPermanentNodeAddress();
m_AiNodeAddress = PermanentNodeAddress;
}
TRACE("E100bexAdapter::Initialize: Node Address is %.2x %.2x %.2x %.2x %.2x %.2x\n",
m_AiNodeAddress.m_bytes[0],
m_AiNodeAddress.m_bytes[1],
m_AiNodeAddress.m_bytes[2],
m_AiNodeAddress.m_bytes[3],
m_AiNodeAddress.m_bytes[4],
m_AiNodeAddress.m_bytes[5]
);
// Validate the current node address (make sure its not a mulicast)
if ((UCHAR) m_AiNodeAddress.m_bytes[0] & 1)
{
TRACE("E100bexAdapter::Initialize: Node address invalid -- its a MC address\n");
KNDIS_RETURN_ERROR (NDIS_STATUS_FAILURE);
}
// Create a "receive frame" area. Must do this before EnableCard
if ( (Status = SetupReceiveQueues()) != NDIS_STATUS_SUCCESS )
KNDIS_RETURN_ERROR (Status);
// Initialize the hardware and enable the interrupt
if ( (Status = EnableCard()) != NDIS_STATUS_SUCCESS )
KNDIS_RETURN_ERROR (Status);
return NDIS_STATUS_SUCCESS;
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::EnableCard
//
// This routine will initializate the hardware and
// enable the card's interrupt.
//
// Parameters:
// IRQL:
// PASSIVE_LEVEL
// Return Mode:
// Synchronous
//
// NOTE:
// This method MUST NOT be called until the following have been done
// - The card object has been created
// - The m_AiNodeAddress has been initialized with the address that
// will be used by the card.
// - SetupReceiveQueues has been called
// - SetupTransmitQueues has been called
//
// This routine will be called from Initialize, and also from
// setOID_PNP_SET_POWER when transitioning from D3 to D0 power state.
//
NDIS_STATUS E100bexAdapter::EnableCard(void)
{
NDIS_STATUS Status;
// Test the adapter hardware
if (( Status = m_pCard->SelfTest() ) != NDIS_STATUS_SUCCESS)
KNDIS_RETURN_ERROR (Status);
if ( !m_pCard->DetectPhy() )
KNDIS_RETURN_ERROR (NDIS_STATUS_FAILURE);
m_pCard->SetMcTimeoutFlag();
// Start the card up. Interrupts are disabled...
if ( ! m_pCard->Init(m_AiNodeAddress) )
KNDIS_RETURN_ERROR (NDIS_STATUS_FAILURE);
// Clear all counters on the hardware and in the driver
m_pCard->ClearAllCounters();
StartReceiveUnit();
m_pCard->EnableInterrupt();
return NDIS_STATUS_SUCCESS;
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::StartReceiveUnit
//
// This routine will start the receive unit on the NIC.
//
// Parameters:
// IRQL:
// PASSIVE_LEVEL
// Return Mode:
// Synchronous
//
BOOLEAN E100bexAdapter::StartReceiveUnit()
{
TRACE("E100bexAdapter::StartReceiveUnit\n");
BOOLEAN Status = FALSE;
// If the receiver is ready, then don't try to restart.
if ( m_pCard->ReceiveUnitStarted() )
{
return Status;
}
TRACE2(("Re-starting the RU\n"))
KNdisPacket Pkt(m_pRxArea->GetPacket());
PHW_RFD pRfd = NULL;
if( Pkt.IsValid() )
{
pRfd = reinterpret_cast<PHW_RFD>(m_pRxArea->GetDescriptor(Pkt));
ASSERT( pRfd );
}
// Check to make sure that our RFD head is available. If its not, then
// we should process the rest of our receives
if (( !Pkt.IsValid() || pRfd->RfdCbHeader.CbStatus))
{
Status = ProcessRXInterrupt();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -