windows-nt/Source/XPSP1/NT/drivers/net/irda/mknet/sys/mkmini.c
2020-09-26 16:20:57 +08:00

621 lines
18 KiB
C

/*****************************************************************************
** **
** COPYRIGHT (C) 2000, 2001 MKNET CORPORATION **
** DEVELOPED FOR THE MK7100-BASED VFIR PCI CONTROLLER. **
** **
*****************************************************************************/
/*****************************************************************************
Module Name:
MKMINI.C
Routines:
MKMiniportReturnPackets
MKMiniportCheckForHang
MKMiniportHalt
MKMiniportShutdownHandler
MKMiniportInitialize
MKMiniportReset
(MK7EnableInterrupt & Disable in MK7COMM.C.)
DriverEntry
Comments:
Contains most NDIS API routines supplied to Windows by the miniport.
*****************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include "protot.h"
// Globals to help debug/test
PMK7_ADAPTER GAdapter;
//-----------------------------------------------------------------------------
// Procedure: [MKMiniportReturnPackets]
//
// Description: NDIS returns a previously indicated pkt by calling this routine.
//
// Arguments:
// IN NDIS_HANDLE MiniportAdapterContext
// - a context version of our Adapter pointer
// IN NDIS_PACKET Packet
// - the packet that is being freed
//
// Returns: (none)
//
//-----------------------------------------------------------------------------
VOID MKMiniportReturnPackets( NDIS_HANDLE MiniportAdapterContext,
PNDIS_PACKET Packet)
{
PMK7_ADAPTER Adapter;
PRPD rpd;
PRCB rcb;
//****************************************
// - SpinLock brackets the FreeList resource.
// - Recover the RPD from the returned pkt, then return
// the RPD to the FreeList.
//****************************************
Adapter = PMK7_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
NdisAcquireSpinLock(&Adapter->Lock);
ASSERT(Packet);
#if DBG
GDbgStat.rxPktsRtn++;
#endif
rpd = *(PRPD *)(Packet->MiniportReserved);
ASSERT(rpd);
ProcReturnedRpd(Adapter, rpd);
// 4.0.1 BOC
Adapter->UsedRpdCount--;
// 4.0.1 EOC
NdisReleaseSpinLock(&Adapter->Lock);
}
//-----------------------------------------------------------------------------
// Procedure: [MKMiniportCheckForHang]
//
// Description: This procedure does not do much for now.
//
// Arguments:
// MiniportAdapterContext (both) - pointer to the adapter object data area
//
// Returns:
// FALSE or TRUE
//-----------------------------------------------------------------------------
BOOLEAN MKMiniportCheckForHang(NDIS_HANDLE MiniportAdapterContext)
{
PMK7_ADAPTER Adapter;
Adapter = PMK7_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
NdisAcquireSpinLock(&Adapter->Lock);
// DbgPrint(" ==> Hang Check\n\r");
if (Adapter->IOMode == TX_MODE) {
Adapter->HangCheck++;
if (Adapter->HangCheck >= 3) {
NdisReleaseSpinLock(&Adapter->Lock);
return(TRUE);
}
}
NdisReleaseSpinLock(&Adapter->Lock);
return(FALSE);
}
//-----------------------------------------------------------------------------
// Procedure: [MKMiniportHalt]
//
// Description: Halts our hardware. We disable interrupts as well as the hw
// itself. We release other Windows resources such as allocated
// memory and timers.
//
// Arguments:
// MiniportAdapterContext - pointer to the adapter object data area.
//
// Returns: (none)
//-----------------------------------------------------------------------------
VOID MKMiniportHalt(NDIS_HANDLE MiniportAdapterContext)
{
PMK7_ADAPTER Adapter;
BOOLEAN Cancelled;
DBGFUNC(" MKMiniportHalt");
Adapter = PMK7_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
MK7DisableInterrupt(Adapter);
MK7DisableIr(Adapter);
Adapter->hardwareStatus = NdisHardwareStatusClosing;
// check to make sure there are no outstanding transmits
while(Adapter->FirstTxQueue) {
PNDIS_PACKET QueuePacket = Adapter->FirstTxQueue;
Adapter->NumPacketsQueued--;
DequeuePacket(Adapter->FirstTxQueue, Adapter->LastTxQueue);
NDIS_SET_PACKET_STATUS(QueuePacket, NDIS_STATUS_FAILURE);
NdisMSendComplete(
Adapter->MK7AdapterHandle,
QueuePacket,
NDIS_STATUS_FAILURE);
}
// deregister shutdown handler
NdisMDeregisterAdapterShutdownHandler(Adapter->MK7AdapterHandle);
// Free the interrupt object
NdisMDeregisterInterrupt(&Adapter->Interrupt);
NdisMCancelTimer(&Adapter->MinTurnaroundTxTimer, &Cancelled);
NdisFreeSpinLock(&Adapter->Lock);
// Free the entire adapter object, including the shared memory structures.
FreeAdapterObject(Adapter);
}
//-----------------------------------------------------------------------------
// Procedure: [MKMiniportShutdownHandler]
//
// Description: Removes an adapter instance that was previously initialized.
// To Shutdown simply Disable interrupts. Since the system is shutting
// down there is no need to release resources (memory, i/o space, etc.)
// that the adapter instance was using.
//
// Arguments:
// MiniportAdapterContext - pointer to the adapter object data area.
//
// Returns: (none)
//-----------------------------------------------------------------------------
VOID MKMiniportShutdownHandler(NDIS_HANDLE MiniportAdapterContext)
{
PMK7_ADAPTER Adapter;
Adapter = PMK7_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
MK7DisableInterrupt(Adapter);
}
//-----------------------------------------------------------------------------
// Procedure: [MKMiniportInitialize] (only single adapter support for now)
//
// Description: This routine is called once per supported adapter card in the
// system. This routine is responsible for initializing each adapter.
// This includes parsing all of the necessary parameters from the registry,
// allocating and initializing shared memory structures, configuring the
// MK7100 chip, registering the interrupt, etc.
//
// Arguments:
// OpenErrorStatus (mini) - Returns more info about any failure
// SelectedMediumIndex (mini) - Returns the index in MediumArray of the
// medium that the miniport is using
// MediumArraySize (mini) - An array of medium types that the driver
// supports
// MiniportAdapterHandle (mini) - pointer to the adapter object data area.
//
// WrapperConfigurationContext (both) - A value that we will pass to
// NdisOpenConfiguration.
//
//
// Returns:
// NDIS_STATUS_SUCCESS - If the adapter was initialized successfully.
// <not NDIS_STATUS_SUCCESS> - If for some reason the adapter didn't
// initialize
//-----------------------------------------------------------------------------
NDIS_STATUS
MKMiniportInitialize(PNDIS_STATUS OpenErrorStatus,
PUINT SelectedMediumIndex,
PNDIS_MEDIUM MediumArray,
UINT MediumArraySize,
NDIS_HANDLE MiniportAdapterHandle,
NDIS_HANDLE WrapperConfigurationContext)
{
ULONG i;
NDIS_STATUS Status;
PMK7_ADAPTER Adapter;
NDIS_HANDLE ConfigHandle;
NDIS_INTERFACE_TYPE IfType;
PVOID OverrideNetAddress;
MK7REG mk7reg;
DBGFUNC(" MKMiniportInitialize");
//****************************************
// We're an IrDA device. Exit w/ error if type not passed in.
//****************************************
for (i = 0; i < MediumArraySize; i++) {
if (MediumArray[i] == NdisMediumIrda)
break;
}
if (i == MediumArraySize) {
DBGSTR(("ERROR: IrDA Media type not found.\n"));
DBGLOG("=> MKMiniportInitialize (ERR): IrDA not found", 0);
return (NDIS_STATUS_UNSUPPORTED_MEDIA);
}
*SelectedMediumIndex = i;
//****************************************
// Allocate the Adapter Object, exit if error.
// (Cacheable, non-paged system memory)
//****************************************
Status = ALLOC_SYS_MEM(&Adapter, sizeof(MK7_ADAPTER));
if (Status != NDIS_STATUS_SUCCESS) {
DBGSTR(("ERROR: ADAPTER Allocate Memory failed (Status = 0x%x)\n", Status));
DBGLOG("<= MKMiniportInitialize: (ERR - 1)", 0);
return (Status);
}
NdisZeroMemory(Adapter, sizeof(MK7_ADAPTER));
Adapter->MK7AdapterHandle = MiniportAdapterHandle;
GAdapter = Adapter;
Adapter->hardwareStatus = NdisHardwareStatusInitializing;
//****************************************
// Process the Registry -- Get config settings, etc.
//****************************************
Status = ProcessRegistry(Adapter, WrapperConfigurationContext);
if (Status != NDIS_STATUS_SUCCESS) {
FreeAdapterObject(Adapter);
DBGSTR(("ERROR: ProcessRegistry() \n"));
DBGLOG("<= MKMiniportInitialize: (ERR - 2)", 0);
return (NDIS_STATUS_FAILURE);
}
//****************************************
// Let NDIS know kind of driver and features we support
//****************************************
IfType = NdisInterfacePci;
NdisMSetAttributesEx(
Adapter->MK7AdapterHandle,
(NDIS_HANDLE) Adapter,
0,
(ULONG) NDIS_ATTRIBUTE_DESERIALIZE | NDIS_ATTRIBUTE_BUS_MASTER,
IfType );
//****************************************
// Claim the physical Adapter for this Adapter object. We call on
// NdisMPciAssignResources to find our assigned resources.
//****************************************
if (ClaimAdapter(Adapter, WrapperConfigurationContext) != NDIS_STATUS_SUCCESS) {
FreeAdapterObject(Adapter);
DBGSTR(("ERROR: No adapter detected\n"));
DBGLOG("<= MKMiniportInitialize: (ERR - 3)", 0);
return (NDIS_STATUS_FAILURE);
}
//****************************************
// Set up the MK7 register I/O mapping w/ NDIS, interrupt mode, etc.
//****************************************
Status = SetupAdapterInfo(Adapter);
if (Status != NDIS_STATUS_SUCCESS) {
FreeAdapterObject(Adapter);
DBGSTR(("ERROR: I/O Space allocation failed (Status = 0x%X)\n",Status));
DBGLOG("<= MKMiniportInitialize: (ERR - 4)", 0);
return(NDIS_STATUS_FAILURE);
}
//****************************************
// Allocate & initialize memory/buffer needs.
//****************************************
Status = AllocAdapterMemory(Adapter);
if (Status != NDIS_STATUS_SUCCESS) {
FreeAdapterObject(Adapter);
MKLogError(Adapter, EVENT_10, NDIS_ERROR_CODE_OUT_OF_RESOURCES, 0);
DBGSTR(("ERROR: Shared Memory Allocation failed (Status = 0x%x)\n", Status));
DBGLOG("<= MKMiniportInitialize: (ERR - 5)", 0);
return (NDIS_STATUS_FAILURE);
}
// 4.1.0 Check hw version.
MK7Reg_Read(Adapter, R_CFG3, &mk7reg);
if ((mk7reg & 0x1000) != 0){
mk7reg &= 0xEFFF;
MK7Reg_Write(Adapter, R_CFG3, mk7reg);
mk7reg |= 0x1000;
MK7Reg_Write(Adapter, R_CFG3, mk7reg);
MK7Reg_Read(Adapter, R_CFG3, &mk7reg);
if ((mk7reg & 0x1000) != 0)
Adapter->HwVersion = HW_VER_1;
else
Adapter->HwVersion = HW_VER_2;
}
else{
Adapter->HwVersion = HW_VER_2;
}
//****************************************
// Disable interrupts while we finish with the initialization
// Must AllocAdapterMemory() before you can do this.
//****************************************
MK7DisableInterrupt(Adapter);
//****************************************
// Register our interrupt with the NDIS wrapper, hook our interrupt
// vector, & use shared interrupts for our PCI adapters
//****************************************
Status = NdisMRegisterInterrupt(&Adapter->Interrupt,
Adapter->MK7AdapterHandle,
Adapter->MKInterrupt,
Adapter->MKInterrupt,
TRUE, // call ISR each time NIC interrupts
TRUE, // shared irq
Adapter->InterruptMode); // NdisInterruptLatched, NdisInterruptLevelSensitive
if (Status != NDIS_STATUS_SUCCESS) {
FreeAdapterObject(Adapter);
MKLogError(Adapter,
EVENT_0,
NDIS_ERROR_CODE_INTERRUPT_CONNECT,
(ULONG) Adapter->MKInterrupt);
DBGLOG("<= MKMiniportInitialize: (ERR - 6)", 0);
return (NDIS_STATUS_FAILURE);
}
#if DBG
DbgTestInit(Adapter);
#endif
//****************************************
// allocate a spin lock
//****************************************
NdisAllocateSpinLock(&Adapter->Lock);
Adapter->HangCheck = 0;
Adapter->nowReceiving=FALSE; // 4.1.0
//****************************************
// Setup and initialize the transmit and receive structures then
// init the adapter
//****************************************
SetupTransmitQueues(Adapter, TRUE);
SetupReceiveQueues(Adapter);
if (!InitializeAdapter(Adapter)) {
FreeAdapterObject(Adapter);
NdisMDeregisterInterrupt(&Adapter->Interrupt);
DBGSTR(("ERROR: InitializeAdapter Failed.\n"));
DBGLOG("<= MKMiniportInitialize: (ERR - 7)", 0);
return (NDIS_STATUS_FAILURE);
}
//****************************************
// Register a shutdown handler
//****************************************
NdisMRegisterAdapterShutdownHandler(Adapter->MK7AdapterHandle,
(PVOID) Adapter,
(ADAPTER_SHUTDOWN_HANDLER) MKMiniportShutdownHandler);
StartAdapter(Adapter);
MK7EnableInterrupt(Adapter);
Adapter->hardwareStatus = NdisHardwareStatusReady;
DBGSTR(("MKMiniportInitialize: Completed Init Successfully\n"));
DBGLOG("<= MKMiniportInitialize", 0);
return (NDIS_STATUS_SUCCESS);
}
//-----------------------------------------------------------------------------
// RYM-5++
// Procedure: [MKMiniportReset]
//
// Description: Instructs the Miniport to issue a hardware reset to the
// network adapter. The driver also resets its software state. this
// function also resets the transmit queues.
//
// Arguments:
// AddressingReset - TRUE if the wrapper needs to call
// MiniportSetInformation to restore the addressing
// information to the current values
// MiniportAdapterContext - pointer to the adapter object data area.
//
// Returns:
// NDIS_STATUS_PENDING - This function sets a timer to complete, so
// pending is always returned
//
// (NOTE: The timer-based completion scheme has been disable by now starting
// the timer. We may now want to return Success instead of Pending.)
//-----------------------------------------------------------------------------
NDIS_STATUS
MKMiniportReset(PBOOLEAN AddressingReset,
NDIS_HANDLE MiniportAdapterContext)
{
PMK7_ADAPTER Adapter;
MK7REG mk7reg;
DBGFUNC("MKMiniportReset");
Adapter = PMK7_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
NdisAcquireSpinLock(&Adapter->Lock);
Adapter->hardwareStatus = NdisHardwareStatusReset;
*AddressingReset = TRUE;
// *** possible temporary code
// *** NDIS may actually handle this
Adapter->ResetInProgress = TRUE;
// Disable interrupts while we re-init the transmit structures
MK7DisableInterrupt(Adapter);
MK7DisableIr(Adapter);
// The NDIS 5 support for deserialized miniports requires that
// when reset is called, the driver de-queue and fail all uncompleted
// sends, and complete any uncompleted sends. Essentially we must have
// no pending send requests left when we leave this routine.
// we will fail all sends that we have left right now.
while(Adapter->FirstTxQueue) {
PNDIS_PACKET QueuePacket = Adapter->FirstTxQueue;
Adapter->NumPacketsQueued--;
DequeuePacket(Adapter->FirstTxQueue, Adapter->LastTxQueue);
// we must release the lock here before returning control to ndis
// (even temporarily like this)
NdisReleaseSpinLock(&Adapter->Lock);
NDIS_SET_PACKET_STATUS(QueuePacket, NDIS_STATUS_FAILURE);
NdisMSendComplete(
Adapter->MK7AdapterHandle,
QueuePacket,
NDIS_STATUS_FAILURE);
NdisAcquireSpinLock(&Adapter->Lock);
}
// clean up all the packets we have successfully TX'd
// ProcessTXInterrupt(Adapter);
// Clear out our software transmit structures
NdisZeroMemory((PVOID) Adapter->XmitCached, Adapter->XmitCachedSize);
// Re-initialize the transmit structures
ResetTransmitQueues(Adapter, FALSE);
ResetReceiveQueues(Adapter);
Adapter->tcbUsed = 0;
NdisMSetTimer(&Adapter->MK7AsyncResetTimer, 500);
// Adapter->hardwareStatus = NdisHardwareStatusReady;
// Adapter->ResetInProgress = FALSE;
// MK7EnableInterrupt(Adapter);
// MK7EnableIr(Adapter);
NdisReleaseSpinLock(&Adapter->Lock);
return(NDIS_STATUS_PENDING);
}
//-----------------------------------------------------------------------------
// Procedure: [DriverEntry]
//
// Description: This is the primary initialization routine for the MK7 driver.
// It is simply responsible for the intializing the wrapper and registering
// the adapter driver. The routine gets called once per driver, but
// MKMiniportInitialize(miniport) will get called multiple times if there are
// multiple adapters.
//
// Arguments:
// DriverObject - Pointer to driver object created by the system.
// RegistryPath - The registry path of this driver
//
// Returns:
// The status of the operation, normally this will be NDIS_STATUS_SUCCESS
//-----------------------------------------------------------------------------
NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
{
NDIS_STATUS Status;
NDIS_HANDLE NdisWrapperHandle;
NDIS_MINIPORT_CHARACTERISTICS MKMiniportChar;
DBGFUNC("MK7-DriverEntry");
DBGLOG("=> DriverEntry", 0);
//****************************************
// Now we must initialize the wrapper, and then register the Miniport
//****************************************
NdisMInitializeWrapper( &NdisWrapperHandle,
DriverObject,
RegistryPath,
NULL );
NdisZeroMemory(&MKMiniportChar, sizeof(MKMiniportChar));
// Initialize the Miniport characteristics for the call to
// NdisMRegisterMiniport.
MKMiniportChar.MajorNdisVersion = MK7_NDIS_MAJOR_VERSION;
MKMiniportChar.MinorNdisVersion = MK7_NDIS_MINOR_VERSION;
MKMiniportChar.CheckForHangHandler = MKMiniportCheckForHang;
MKMiniportChar.DisableInterruptHandler = MK7DisableInterrupt;
MKMiniportChar.EnableInterruptHandler = MK7EnableInterrupt;
MKMiniportChar.HaltHandler = MKMiniportHalt;
MKMiniportChar.HandleInterruptHandler = MKMiniportHandleInterrupt;
MKMiniportChar.InitializeHandler = MKMiniportInitialize;
MKMiniportChar.ISRHandler = MKMiniportIsr;
MKMiniportChar.QueryInformationHandler = MKMiniportQueryInformation;
MKMiniportChar.ReconfigureHandler = NULL;
MKMiniportChar.ResetHandler = MKMiniportReset;
MKMiniportChar.SetInformationHandler = MKMiniportSetInformation;
MKMiniportChar.SendHandler = NULL;
MKMiniportChar.SendPacketsHandler = MKMiniportMultiSend;
MKMiniportChar.ReturnPacketHandler = MKMiniportReturnPackets;
MKMiniportChar.TransferDataHandler = NULL;
// MKMiniportChar.AllocateCompleteHandler = D100AllocateComplete;
//****************************************
// Register this driver with the NDIS wrapper
// This will cause MKMiniportInitialize to be called before returning
// (is this really true? -- SoftIce shows this returning before
// MKMiniportInitialize() is called(?))
//****************************************
Status = NdisMRegisterMiniport( NdisWrapperHandle,
&MKMiniportChar,
sizeof(NDIS_MINIPORT_CHARACTERISTICS));
if (Status == NDIS_STATUS_SUCCESS) {
DBGLOG("<= DriverEntry", 0);
return (STATUS_SUCCESS);
}
DBGLOG("<= DriverEntry: Failed!", 0);
return (Status);
}