2020-09-30 17:12:29 +02:00

739 lines
15 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
ltinit.c
Abstract:
This module contains the main processing routines.
Author:
Stephen Hou (stephh@microsoft.com)
Nikhil Kamkolkar (nikhilk@microsoft.com)
Revision History:
19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
Notes: Tab stop: 4
--*/
#define _GLOBALS_
#include "ltmain.h"
#include "ltreg.h"
#include "ltreq.h"
#include "ltfirm.h"
#include "lttimer.h"
#include "ltreset.h"
// Define file id for errorlogging
#define FILENUM LTINIT
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This is the entry routine for the localtalk driver.
Arguments:
DriverObject: The IO driver object for this driver object.
RegistryPath: The path to the registry config for this driver.
Return Value:
STATUS_SUCCESS: If load was successful
Error : Otherwise
--*/
{
NDIS_STATUS Status;
NDIS_MAC_CHARACTERISTICS LtChar;
static const NDIS_STRING MacName = NDIS_STRING_CONST("LT200");
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
("Debugging breakpoint, Hit G <cr> to continue\n"));
DBGBREAK(DBG_LEVEL_INFO);
// Initialize the NDIS Wrapper.
NdisInitializeWrapper(
&LtNdisWrapperHandle,
DriverObject,
RegistryPath,
NULL);
// Setup the MAC Characteristics
LtChar.MajorNdisVersion = NDIS_MAJOR_VERSION;
LtChar.MinorNdisVersion = NDIS_MINOR_VERSION;
LtChar.OpenAdapterHandler = LtInitOpenAdapter;
LtChar.CloseAdapterHandler = LtInitCloseAdapter;
LtChar.SendHandler = LtSend;
LtChar.RequestHandler = LtRequest;
LtChar.TransferDataHandler = LtRecvTransferData;
LtChar.ResetHandler = LtReset;
LtChar.QueryGlobalStatisticsHandler = LtReqQueryGlobalStatistics;
LtChar.UnloadMacHandler = LtInitUnload;
LtChar.AddAdapterHandler = LtInitAddAdapter;
LtChar.RemoveAdapterHandler = LtInitRemoveAdapter;
LtChar.Name = MacName;
NdisRegisterMac(
&Status,
&LtMacHandle,
LtNdisWrapperHandle,
NULL, // Context for AddAdapter/Unload
&LtChar,
sizeof(LtChar));
if (Status != NDIS_STATUS_SUCCESS)
{
// Can only get here if something went wrong registering the MAC or
// all of the adapters
NdisTerminateWrapper(LtNdisWrapperHandle, DriverObject);
}
return Status;
}
NDIS_STATUS
LtInitAddAdapter(
IN NDIS_HANDLE MacMacContext,
IN NDIS_HANDLE ConfigurationHandle,
IN PNDIS_STRING AdapterName
)
/*++
Routine Description:
This is called by NDIS when we do a register adapter.
Arguments:
MacMacContext : Context passed to Add/Unload. NULL in our case.
ConfigurationHandle : Handle to configuration info.
AdapterName : Name to use to register the adapter.
Return Value:
NDIS_STATUS_SUCCESS : If successful, error otherwise
--*/
{
NDIS_HANDLE ConfigHandle;
UCHAR SuggestedNodeId;
UINT BusNumber, IoBaseAddress;
NDIS_INTERFACE_TYPE BusType;
BOOLEAN configHandleOpen = FALSE;
NDIS_STATUS Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
if (ConfigurationHandle == NULL)
{
return(Status);
}
do
{
NdisOpenConfiguration(
&Status,
&ConfigHandle,
ConfigurationHandle);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
configHandleOpen = TRUE;
// The following functions return the parameter as specified in the
// Configuration database or the default. If the database has an
// incorrect value, then the default is returned and an Error Event
// is logged.
BusNumber = LtRegGetBusNumber(ConfigHandle);
Status = LtRegGetBusType(ConfigHandle, &BusType);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
// Get the io base address
Status = LtRegGetIoBaseAddr(
&IoBaseAddress,
ConfigurationHandle,
ConfigHandle,
BusType);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
// Get default id or pram node id to try.
SuggestedNodeId = LtRegGetNodeId(ConfigHandle);
} while (FALSE);
// We have to register the adapter to log an error if that happened.
Status = LtInitRegisterAdapter(
LtMacHandle,
ConfigurationHandle,
AdapterName,
BusType,
SuggestedNodeId,
IoBaseAddress,
LT_MAX_ADAPTERS,
Status);
if (configHandleOpen)
{
NdisCloseConfiguration(ConfigHandle);
}
return Status;
}
VOID
LtInitRemoveAdapter(
IN NDIS_HANDLE MacAdapterContext
)
/*++
Routine Description:
Called to remove an adapter. This is only called after all bindings
are closed.
Arguments:
MacAdapterContext : Context value passed to NdisRegister. Adapter
Return Value:
None.
--*/
{
BOOLEAN Cancelled, TimerQueued, Closing;
PLT_ADAPTER Adapter = (PLT_ADAPTER)MacAdapterContext;
NdisAcquireSpinLock(&Adapter->Lock);
Closing = ((Adapter->Flags & ADAPTER_CLOSING) != 0);
Adapter->Flags |= ADAPTER_CLOSING;
TimerQueued = ((Adapter->Flags & ADAPTER_TIMER_QUEUED) != 0);
Adapter->Flags &= ~ADAPTER_TIMER_QUEUED;
NdisReleaseSpinLock(&Adapter->Lock);
if (Closing)
{
ASSERTMSG("LtInitRemoveAdapter: Removing twice!\n", 0);
return;
}
// Acording to Adam, this routine will NEVER be called with
// outstanding opens.
ASSERTMSG("LtRemoveAdapter: OpenCount is not zero!\n",
(Adapter->OpenCount == 0));
// There are no opens left so remove ourselves.
if (TimerQueued)
{
NdisCancelTimer(&Adapter->PollingTimer, &Cancelled);
if (Cancelled)
{
// Remove the timer reference
LtDeReferenceAdapter(Adapter);
}
}
ASSERTMSG("LtRemoveAdapter: RefCount not correct!\n", (Adapter->RefCount == 1));
// Remove the creation reference
LtDeReferenceAdapter(Adapter);
return;
}
NDIS_STATUS
LtInitOpenAdapter(
OUT PNDIS_STATUS OperErrorStatus,
OUT NDIS_HANDLE *MacBindingHandle,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE NdisBindingContext,
IN NDIS_HANDLE MacAdapterContext,
IN UINT OpenOptions,
IN PSTRING AddressingInformation
)
/*++
Routine Description:
Called by ndis when a protocol attempts to bind to us.
Arguments:
As described in the NDIS 3.0 Spec.
Return Value:
NDIS_STATUS_SUCCESSFUL : If ok, error otherwise
--*/
{
UINT i;
PLT_OPEN NewOpen;
PLT_ADAPTER Adapter = (PLT_ADAPTER)MacAdapterContext;
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
// if the adapter is being closed, then do not allow the open
LtReferenceAdapter(Adapter, &StatusToReturn);
if (StatusToReturn != NDIS_STATUS_SUCCESS)
{
ASSERTMSG("LtInitOpenAdapter: Adapter is closing down!\n", 0);
return(StatusToReturn);
}
do
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
("LtInitOpenAdapter Entered:\n"));
// Search thru the supplied MediumArray for NdisMediumLocalTalk
for (i = 0; i < MediumArraySize; i++)
{
if (MediumArray[i] == NdisMediumLocalTalk)
{
break;
}
}
if (i == MediumArraySize)
{
StatusToReturn = NDIS_STATUS_UNSUPPORTED_MEDIA;
break;
}
*SelectedMediumIndex = i;
// Allocate some space for the open binding.
NdisAllocateMemory(
(PVOID)&NewOpen,
(UINT)sizeof(LT_OPEN),
(UINT)0,
LtNdisPhyAddr);
if (NewOpen == NULL)
{
StatusToReturn = NDIS_STATUS_RESOURCES;
// NdisWriteErrorLogEntry();
TMPLOGERR();
break;
}
NdisZeroMemory(
NewOpen,
sizeof(LT_OPEN));
*MacBindingHandle = (NDIS_HANDLE)NewOpen;
NewOpen->NdisBindingContext = NdisBindingContext;
NewOpen->Flags |= BINDING_OPEN;
NewOpen->LtAdapter = Adapter;
// Set the creation reference
NewOpen->RefCount = 1;
InitializeListHead(&NewOpen->Linkage);
// Insert into adapter list and increment adapter open count.
NdisAcquireSpinLock(&Adapter->Lock);
InsertTailList(&Adapter->OpenBindings, &NewOpen->Linkage);
Adapter->OpenCount++;
NdisReleaseSpinLock(&Adapter->Lock);
} while (FALSE);
if (StatusToReturn != NDIS_STATUS_SUCCESS)
{
LtDeReferenceAdapter(Adapter);
}
return StatusToReturn;
}
NDIS_STATUS
LtInitCloseAdapter(
IN NDIS_HANDLE MacBindingHandle
)
/*++
Routine Description:
Called by NDIS to close a binding.
Arguments:
MacBindingHandle : Context passed back in OpenAdapter.
Return Value:
NDIS_STATUS_SUCCESS : If successful, error otherwise.
NDIS_STATUS_PENDING : If pending.
--*/
{
PLT_ADAPTER Adapter;
PLT_OPEN Open;
NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
BOOLEAN Closing = FALSE;
Open = (PLT_OPEN)MacBindingHandle;
Adapter = Open->LtAdapter;
NdisAcquireSpinLock(&Adapter->Lock);
// Do not do any thing if already closing.
if (Open->Flags & BINDING_CLOSING)
{
StatusToReturn = NDIS_STATUS_CLOSING;
}
else
{
// This flag prevents further requests on this binding.
Open->Flags |= BINDING_CLOSING;
Closing = TRUE;
}
NdisReleaseSpinLock(&Adapter->Lock);
if (Closing)
{
// Remove the creation reference
LtDeReferenceBinding(Open);
}
return StatusToReturn;
}
VOID
LtInitUnload(
IN NDIS_HANDLE MacMacContext
)
/*++
Routine Description:
Called when the driver is to be unloaded.
Arguments:
MacMacContext : Context passed to RegisterMac.
Return Value:
None.
--*/
{
NDIS_STATUS Status;
UNREFERENCED_PARAMETER(MacMacContext);
ASSERT(MacMacContext == (NDIS_HANDLE)NULL);
NdisDeregisterMac(
&Status,
LtMacHandle);
NdisTerminateWrapper(
LtNdisWrapperHandle,
NULL);
return;
}
NDIS_STATUS
LtInitRegisterAdapter(
IN NDIS_HANDLE LtMacHandle,
IN NDIS_HANDLE WrapperConfigurationContext,
IN PNDIS_STRING AdapterName,
IN NDIS_INTERFACE_TYPE BusType,
IN UCHAR SuggestedNodeId,
IN UINT IoBaseAddress,
IN UINT MaxAdapters,
IN NDIS_STATUS ConfigError
)
/*++
Routine Description:
This routine (and its interface) are not portable. They are
defined by the OS, the architecture, and the particular Lt
implementation.
This routine is responsible for the allocation of the datastructures
for the driver as well as any hardware specific details necessary
to talk with the device.
Arguments:
LtMacHandle : The handle given back to the mac from ndis when
the mac registered itself.
WrapperConfigurationContext
: configuration context passed in by NDIS in the AddAdapter
call.
AdapterName : The string containing the name to give to the device adapter.
BusType : The type of bus in use. (MCA, ISA, EISA ...)
IoBaseAddress : The base IO address of the card.
MaxAdapters : The maximum number of opens at any one time.
ConfigError : Error with the Config parameters if any.
Return Value:
NDIS_STATUS_SUCCESS : If successful, error otherwise.
--*/
{
// Pointer for the adapter root.
PLT_ADAPTER Adapter;
NDIS_STATUS Status, RefStatus;
NDIS_ERROR_CODE LogErrorCode;
// Holds information needed when registering the adapter.
NDIS_ADAPTER_INFORMATION AdapterInformation;
// Allocate the Adapter block.
NdisAllocateMemory(
(PVOID)&Adapter,
sizeof(LT_ADAPTER),
0,
LtNdisPhyAddr);
if (Adapter == NULL)
{
return(NDIS_STATUS_RESOURCES);
}
NdisZeroMemory(
Adapter,
sizeof(LT_ADAPTER));
Adapter->NdisMacHandle = LtMacHandle;
// Set up the AdapterInformation structure.
NdisZeroMemory (&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION));
AdapterInformation.DmaChannel = 0;
AdapterInformation.Master = FALSE ;
AdapterInformation.Dma32BitAddresses = FALSE ;
AdapterInformation.AdapterType = BusType ;
AdapterInformation.PhysicalMapRegistersNeeded = 0;
AdapterInformation.MaximumPhysicalMapping = 0;
AdapterInformation.NumberOfPortDescriptors = 1 ;
AdapterInformation.PortDescriptors[0].InitialPort = IoBaseAddress;
AdapterInformation.PortDescriptors[0].NumberOfPorts = 4;
AdapterInformation.PortDescriptors[0].PortOffset = (PVOID *)(&(Adapter->MappedIoBaseAddr));
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("LtInitRegisterAdapter: IoBaseAddr %lx\n", IoBaseAddress));
// Register the adapter with NDIS.
if ((Status = NdisRegisterAdapter(
&Adapter->NdisAdapterHandle,
Adapter->NdisMacHandle,
Adapter,
WrapperConfigurationContext,
AdapterName,
&AdapterInformation)) != NDIS_STATUS_SUCCESS)
{
// Could not register the adapter, so we cannot log any errors
// either.
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_FATAL,
("LtInitRegisterAdapter: Failed %lx\n", Status));
// Free up the memory allocated.
NdisFreeMemory(
Adapter,
sizeof(LT_ADAPTER),
0);
return(Status);
}
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("LtInitRegisterAdapter: MappedIoBaseAddr %lx\n", Adapter->MappedIoBaseAddr));
do
{
// Ok. We are all set.
Adapter->BusType = BusType;
InitializeListHead(&Adapter->Request);
InitializeListHead(&Adapter->OpenBindings);
InitializeListHead(&Adapter->LoopBack);
InitializeListHead(&Adapter->Transmit);
InitializeListHead(&Adapter->Receive);
NdisAllocateSpinLock(&Adapter->Lock);
Adapter->OpenCount = 0;
// Set refcount to 1 - creation
Adapter->RefCount = 1;
NdisInitializeTimer(
&Adapter->PollingTimer,
LtTimerPoll,
(PVOID)Adapter);
// If there were no configuration errors, then go ahead with the
// initialize.
if (ConfigError == NDIS_STATUS_SUCCESS)
{
// Start the card up. This writes an error
// log entry if it fails.
if (LtFirmInitialize(Adapter, SuggestedNodeId))
{
// Ok, the firmware code has been downloaded to the card.
// Start the poll timer. We should do this before we call
// GetAddress. Add a reference for the timer.
NdisAcquireSpinLock(&Adapter->Lock);
LtReferenceAdapterNonInterlock(Adapter, &RefStatus);
ASSERTMSG("LtInitRegisterAdapter: RefAdater Failed!\n",
(RefStatus == NDIS_STATUS_SUCCESS));
Adapter->Flags |= ADAPTER_TIMER_QUEUED;
NdisSetTimer(&Adapter->PollingTimer, LT_POLLING_TIME);
NdisReleaseSpinLock(&Adapter->Lock);
break;
}
LogErrorCode = NDIS_ERROR_CODE_HARDWARE_FAILURE;
}
else
{
LogErrorCode = NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER;
}
// We either could not initialize the hardware or get the node
// address. OR there was a config error. Log it and deregister
// the adapter.
LOGERROR(Adapter->NdisAdapterHandle, LogErrorCode);
// Deregister the adapter. This calls LtInitRemoveAdapter which
// will do all necessary cleanup.
NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
Status = NDIS_STATUS_FAILURE;
break;
} while (FALSE);
return(Status);
}
BOOLEAN
LtInitGetAddressSetPoll(
IN PLT_ADAPTER Adapter,
IN UCHAR SuggestedNodeId
)
/*++
Routine Description:
This gets the node id from the card (starts it off actually) and
sets the card to be in polling mode.
Arguments:
Adapter : Pointer to the adapter structure
SuggestedNodeId : Pram node id or 0
Return Value:
TRUE : if success, FALSE otherwise
--*/
{
ULONG Seed, Random;
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
("LtGetAddress: Getting a node address for lt adapter...\n"));
if (SuggestedNodeId == 0)
{
Seed = (ULONG)Adapter;
Random = RtlRandom(&Seed);
SuggestedNodeId =
(UCHAR)((Random % LT_MAX_CLIENT_NODE_ID) + LT_MIN_SERVER_NODE_ID);
}
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
("LtGetAddress: Suggested Node Id = %lx\n", SuggestedNodeId));
// Command Length LSB
NdisRawWritePortUchar(XFER_PORT, 2);
// Command Length MSB
NdisRawWritePortUchar(XFER_PORT, 0);
NdisRawWritePortUchar(XFER_PORT, (UCHAR)LT_CMD_LAP_INIT);
NdisRawWritePortUchar(XFER_PORT, SuggestedNodeId);
// Use 0xFF for the interrupt if this card is to be polled.
// We *ONLY* support polling.
NdisRawWritePortUchar(XFER_PORT, LT_ADAPTER_POLLED_MODE);
return TRUE;
}