mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2331 lines
50 KiB
2331 lines
50 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
reset.c
|
|
|
|
Abstract:
|
|
|
|
This is the file containing the reset code for the 3Com Etherlink/MC
|
|
and Etherlink 16 Ethernet adapter. This driver conforms to the
|
|
NDIS 3.0 interface.
|
|
|
|
Author:
|
|
|
|
Johnson R. Apacible (JohnsonA) 10-June-1991
|
|
|
|
Environment:
|
|
|
|
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include <ndis.h>
|
|
|
|
//
|
|
// So we can trace things...
|
|
//
|
|
|
|
#include <efilter.h>
|
|
#include <elnkhw.h>
|
|
#include <elnksw.h>
|
|
|
|
|
|
#define STATIC
|
|
|
|
STATIC
|
|
VOID
|
|
ElnkAbortPendingQueue(
|
|
IN PELNK_ADAPTER Adapter,
|
|
IN BOOLEAN AbortOpens
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
ElnkSetConfigurationBlock(
|
|
IN PELNK_ADAPTER Adapter
|
|
);
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
SetConfigurationBlockAndInit(
|
|
IN PELNK_ADAPTER Adapter
|
|
);
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
SetupSharedMemory(
|
|
IN PELNK_ADAPTER Adapter
|
|
);
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
ElnkPowerUpInit(
|
|
IN PELNK_ADAPTER Adapter
|
|
);
|
|
|
|
extern
|
|
VOID
|
|
ChangeAddressDispatch(
|
|
IN PELNK_ADAPTER Adapter,
|
|
IN UINT AddressCount,
|
|
IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
|
|
IN PELNK_OPEN Open,
|
|
IN BOOLEAN Set
|
|
);
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
ElnkInitialInit(
|
|
IN PELNK_ADAPTER Adapter,
|
|
IN UINT ElnkInterruptVector
|
|
);
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
DoResetIndications(
|
|
IN PELNK_ADAPTER Adapter,
|
|
IN NDIS_STATUS Status
|
|
);
|
|
|
|
VOID
|
|
ResetAdapterVariables(
|
|
IN PELNK_ADAPTER Adapter
|
|
);
|
|
|
|
VOID
|
|
Elnk16GenerateIdPattern(
|
|
IN PELNK_ADAPTER Adapter
|
|
);
|
|
|
|
//
|
|
// Common Elnkmc and Elnk16 routines
|
|
//
|
|
|
|
BOOLEAN
|
|
ElnkSyncStartReceive(
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to synchronize with the ISR the starting of a
|
|
receive unit.
|
|
|
|
Arguments:
|
|
|
|
see NDIS 3.0 spec.
|
|
|
|
Notes:
|
|
|
|
returns TRUE on success, else FALSE.
|
|
|
|
--*/
|
|
{
|
|
PELNK_ADAPTER Adapter = (PELNK_ADAPTER)Context;
|
|
|
|
IF_LOG('w');
|
|
|
|
WRITE_ADAPTER_REGISTER(
|
|
Adapter,
|
|
OFFSET_SCB_RD,
|
|
(USHORT)(Adapter->RfdOffset)
|
|
);
|
|
|
|
WRITE_ADAPTER_REGISTER(
|
|
Adapter,
|
|
OFFSET_SCBCMD,
|
|
RUC_START
|
|
);
|
|
|
|
ELNK_CA;
|
|
|
|
Adapter->RuRestarted = TRUE;
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
ElnkSyncAbort(
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to synchronize with the ISR the starting of a
|
|
abort of a command block.
|
|
|
|
Arguments:
|
|
|
|
see NDIS 3.0 spec.
|
|
|
|
Notes:
|
|
|
|
returns TRUE on success, else FALSE.
|
|
|
|
--*/
|
|
{
|
|
PELNK_ADAPTER Adapter = (PELNK_ADAPTER)Context;
|
|
|
|
WRITE_ADAPTER_REGISTER(
|
|
Adapter,
|
|
OFFSET_SCBCMD,
|
|
CUC_ABORT | RUC_ABORT
|
|
);
|
|
|
|
ELNK_CA;
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
ElnkSyncReset(
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to synchronize with the ISR the starting of a
|
|
reset command block.
|
|
|
|
Arguments:
|
|
|
|
see NDIS 3.0 spec.
|
|
|
|
Notes:
|
|
|
|
returns TRUE on success, else FALSE.
|
|
|
|
--*/
|
|
{
|
|
PELNK_ADAPTER Adapter = (PELNK_ADAPTER)Context;
|
|
|
|
WRITE_ADAPTER_REGISTER(
|
|
Adapter,
|
|
OFFSET_SCBCMD,
|
|
SCB_COMMAND_RESET
|
|
);
|
|
|
|
ELNK_CA;
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
STATIC
|
|
NDIS_STATUS
|
|
ElnkReset(
|
|
IN NDIS_HANDLE MacBindingHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The ElnkReset request instructs the MAC to issue a hardware reset
|
|
to the network adapter. The MAC also resets its software state. See
|
|
the description of NdisReset for a detailed description of this request.
|
|
|
|
Arguments:
|
|
|
|
MacBindingHandle - The context value returned by the MAC when the
|
|
adapter was opened. In reality, it is a pointer to ELNK_OPEN.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Holds the status that should be returned to the caller.
|
|
//
|
|
NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
|
|
|
|
PELNK_ADAPTER Adapter =
|
|
PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
|
|
|
//
|
|
// Hold the locks while we update the reference counts on the
|
|
// adapter and the open.
|
|
//
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
Adapter->References++;
|
|
|
|
if (!Adapter->ResetInProgress)
|
|
{
|
|
PELNK_OPEN Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
|
|
|
|
if (!Open->BindingShuttingDown)
|
|
{
|
|
Open->References++;
|
|
|
|
SetupForReset(
|
|
Adapter,
|
|
PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)
|
|
);
|
|
|
|
Open->References--;
|
|
}
|
|
else
|
|
{
|
|
StatusToReturn = NDIS_STATUS_CLOSING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Adapter->References--;
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
return(NDIS_STATUS_RESET_IN_PROGRESS);
|
|
}
|
|
|
|
ELNK_DO_DEFERRED(Adapter);
|
|
|
|
return(StatusToReturn);
|
|
}
|
|
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
ElnkSetConfigurationBlock(
|
|
IN PELNK_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine simply fills the configuration block
|
|
with the information necessary for initialization.
|
|
|
|
NOTE: This routine assumes that it is called with the lock
|
|
acquired OR that only a single thread of execution is accessing
|
|
the particular adapter.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter which holds the initialization block
|
|
to initialize.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UINT PacketFilters;
|
|
UINT i;
|
|
|
|
PCONFIG_CB Configuration;
|
|
|
|
Configuration = &Adapter->MulticastBlock->Parm.Config;
|
|
|
|
NdisZeroMappedMemory(
|
|
(PUCHAR)Configuration,
|
|
sizeof(CONFIG_CB)
|
|
);
|
|
|
|
//
|
|
// Setup default configuration values
|
|
//
|
|
|
|
Adapter->OldParameterField = DEFAULT_PARM5;
|
|
|
|
//
|
|
// Set up the address filtering.
|
|
//
|
|
// First get hold of the combined packet filter.
|
|
//
|
|
if (Adapter->FilterDB != NULL) {
|
|
PacketFilters = ETH_QUERY_FILTER_CLASSES(Adapter->FilterDB);
|
|
} else {
|
|
PacketFilters = 0;
|
|
}
|
|
|
|
//
|
|
// this code was removed as it isn't necessary and causes the cards to
|
|
// not be able to send packets unless the packet filter is changed.
|
|
//
|
|
#if 0
|
|
|
|
if (PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) {
|
|
|
|
//
|
|
// If one binding is promiscuous there is no point in
|
|
// setting up any other filtering. Every packet is
|
|
// going to be accepted by the hardware.
|
|
//
|
|
|
|
Adapter->OldParameterField |= CONFIG_PROMISCUOUS;
|
|
|
|
} else if (PacketFilters & NDIS_PACKET_TYPE_ALL_MULTICAST) {
|
|
|
|
//
|
|
// Simulate All Multicast
|
|
//
|
|
|
|
Adapter->OldParameterField |= CONFIG_PROMISCUOUS;
|
|
|
|
} else if (PacketFilters & NDIS_PACKET_TYPE_BROADCAST) {
|
|
|
|
//
|
|
// Enable broadcast packets.
|
|
//
|
|
|
|
Adapter->OldParameterField &= ~CONFIG_BROADCAST;
|
|
|
|
}
|
|
|
|
if (!Adapter->IsExternal) {
|
|
|
|
Adapter->OldParameterField |= CONFIG_INTERNAL;
|
|
|
|
}
|
|
|
|
//
|
|
// see if we need to change adapter default configuration
|
|
//
|
|
|
|
NdisWriteRegisterUshort(&Configuration->Parameter1, DEFAULT_PARM1);
|
|
NdisWriteRegisterUshort(&Configuration->Parameter2, DEFAULT_PARM2);
|
|
NdisWriteRegisterUshort(&Configuration->Parameter3, DEFAULT_PARM3);
|
|
NdisWriteRegisterUshort(&Configuration->Parameter4, DEFAULT_PARM4);
|
|
NdisWriteRegisterUshort(&Configuration->Parameter6, DEFAULT_PARM6);
|
|
|
|
NdisWriteRegisterUshort(
|
|
&Configuration->Parameter5,
|
|
Adapter->OldParameterField
|
|
);
|
|
|
|
NdisWriteRegisterUshort(&Adapter->MulticastBlock->Status, CB_STATUS_FREE);
|
|
NdisWriteRegisterUshort(&Adapter->MulticastBlock->Command, CB_CONFIG);
|
|
NdisWriteRegisterUshort(&Adapter->MulticastBlock->NextCbOffset, ELNK_NULL);
|
|
|
|
ElnkSubmitCommandBlockAndWait(Adapter);
|
|
#endif
|
|
//
|
|
// Do Individual Address Setup
|
|
//
|
|
|
|
NdisWriteRegisterUshort(&Adapter->MulticastBlock->Status, CB_STATUS_FREE);
|
|
NdisWriteRegisterUshort(&Adapter->MulticastBlock->Command, CB_SETUP);
|
|
NdisWriteRegisterUshort(&Adapter->MulticastBlock->NextCbOffset, ELNK_NULL);
|
|
|
|
for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++) {
|
|
NdisWriteRegisterUchar(
|
|
&Adapter->MulticastBlock->Parm.Setup.StationAddress[i],
|
|
Adapter->CurrentAddress[i]
|
|
);
|
|
}
|
|
|
|
ElnkSubmitCommandBlockAndWait(Adapter);
|
|
|
|
//
|
|
// Now Query the Multicast Addresses
|
|
//
|
|
|
|
if (PacketFilters & NDIS_PACKET_TYPE_MULTICAST) {
|
|
|
|
UINT NumberOfMulticastAddresses;
|
|
NDIS_STATUS Status;
|
|
|
|
EthQueryGlobalFilterAddresses(
|
|
&Status,
|
|
Adapter->FilterDB,
|
|
ETH_LENGTH_OF_ADDRESS * ELNK_MAXIMUM_MULTICAST,
|
|
&NumberOfMulticastAddresses,
|
|
Adapter->PrivateMulticastBuffer
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
ChangeAddressDispatch(
|
|
Adapter,
|
|
NumberOfMulticastAddresses,
|
|
Adapter->PrivateMulticastBuffer,
|
|
ELNK_BOGUS_OPEN,
|
|
TRUE
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
ElnkStartAdapterReset(
|
|
IN PELNK_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the first phase of resetting the adapter hardware.
|
|
|
|
It makes the following assumptions:
|
|
|
|
1) That the hardware has been stopped.
|
|
|
|
2) That it can not be preempted.
|
|
|
|
3) That no other adapter activity can occur.
|
|
|
|
When this routine is finished all of the adapter information
|
|
will be as if the driver was just initialized.
|
|
|
|
Spinlock assumed held.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter whose hardware is to be reset.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Go through the various transmit lists and abort every packet.
|
|
//
|
|
|
|
{
|
|
|
|
UINT i;
|
|
PNDIS_PACKET Packet;
|
|
PELNK_RESERVED Reserved;
|
|
PELNK_OPEN Open;
|
|
PNDIS_PACKET Next;
|
|
|
|
for (
|
|
i = 0;
|
|
i < 3;
|
|
i++
|
|
) {
|
|
|
|
switch (i) {
|
|
|
|
case 0:
|
|
Next = Adapter->FirstLoopBack;
|
|
break;
|
|
case 1:
|
|
Next = Adapter->FirstFinishTransmit;
|
|
break;
|
|
|
|
case 2:
|
|
Next = Adapter->FirstStagePacket;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
while (Next) {
|
|
|
|
Packet = Next;
|
|
Reserved = PELNK_RESERVED_FROM_PACKET(Packet);
|
|
Next = Reserved->Next;
|
|
Open =
|
|
PELNK_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
|
|
|
|
//
|
|
// The completion of the packet is one less reason
|
|
// to keep the open around.
|
|
//
|
|
|
|
ASSERT(Open->References);
|
|
|
|
Open->References--;
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
NdisCompleteSend(
|
|
Open->NdisBindingContext,
|
|
Packet,
|
|
NDIS_STATUS_REQUEST_ABORTED
|
|
);
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SetConfigurationBlockAndInit(Adapter);
|
|
|
|
}
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
SetConfigurationBlockAndInit(
|
|
IN PELNK_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
It is this routines responsibility to make sure that the
|
|
Configuration block is filled and the adapter is initialized
|
|
*but not* started.
|
|
|
|
NOTE: This routine assumes that it is called with the lock
|
|
acquired OR that only a single thread of execution is working
|
|
with this particular adapter.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter whose hardware is to be initialized.
|
|
|
|
Return Value:
|
|
|
|
TRUE is reset successful, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
|
|
BOOLEAN StatusOfReset = FALSE;
|
|
|
|
//
|
|
// We have 2 ways of doing reset, one for initial power up
|
|
// and the other when we have already setup the scb
|
|
//
|
|
|
|
ResetAdapterVariables(Adapter);
|
|
|
|
StatusOfReset = ElnkPowerUpInit(Adapter);
|
|
|
|
if (StatusOfReset) {
|
|
|
|
//
|
|
// Setup the shared memory structures
|
|
//
|
|
|
|
SetupSharedMemory(Adapter);
|
|
|
|
//
|
|
// Fill in the adapter's initialization block.
|
|
//
|
|
|
|
ElnkSetConfigurationBlock(Adapter);
|
|
|
|
ELNK_ENABLE_INTERRUPT;
|
|
|
|
DoResetIndications(Adapter, NDIS_STATUS_SUCCESS);
|
|
|
|
if (!Adapter->FirstReset) {
|
|
|
|
NdisSetTimer(
|
|
&Adapter->DeadmanTimer,
|
|
5000
|
|
);
|
|
|
|
} else {
|
|
|
|
Adapter->FirstReset = FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
DoResetIndications(Adapter, NDIS_STATUS_FAILURE);
|
|
|
|
}
|
|
|
|
return(StatusOfReset);
|
|
}
|
|
|
|
|
|
VOID
|
|
ElnkStartChip(
|
|
IN PELNK_ADAPTER Adapter,
|
|
IN PELNK_RECEIVE_INFO ReceiveInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to start an already initialized Elnk.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter for the Elnk to start.
|
|
|
|
ReceiveInfo - Pointer to the first receive entry to be
|
|
used by the adapter.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// If the memory is not mapped, then we can do nothing
|
|
//
|
|
|
|
if (!Adapter->MemoryIsMapped) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Start the receive unit
|
|
//
|
|
|
|
Adapter->RfdOffset = ReceiveInfo->RfdOffset;
|
|
|
|
ELNK_WAIT;
|
|
|
|
NdisSynchronizeWithInterrupt(
|
|
&(Adapter->Interrupt),
|
|
(PVOID)ElnkSyncStartReceive,
|
|
(PVOID)(Adapter)
|
|
);
|
|
|
|
ELNK_WAIT;
|
|
}
|
|
|
|
VOID
|
|
ElnkStopChip(
|
|
IN PELNK_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to stop the Elnk.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The Elnk adapter to stop.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR CurrentCsr;
|
|
|
|
//
|
|
// If the adapter has previously been reset, we need to stop both the
|
|
// CU and the RU
|
|
//
|
|
|
|
if (!Adapter->FirstReset) {
|
|
|
|
NdisSynchronizeWithInterrupt(
|
|
&(Adapter->Interrupt),
|
|
(PVOID)ElnkSyncAbort,
|
|
(PVOID)(Adapter)
|
|
);
|
|
|
|
}
|
|
|
|
ELNK_READ_UCHAR(
|
|
Adapter,
|
|
ELNK_CSR,
|
|
&CurrentCsr
|
|
);
|
|
|
|
ELNK_WRITE_UCHAR(
|
|
Adapter,
|
|
ELNK_CSR,
|
|
CurrentCsr & ~CSR_INTEN
|
|
);
|
|
}
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
ElnkPowerUpInit(
|
|
IN PELNK_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the card and reads and sets relevant
|
|
information from and to the 82586.
|
|
|
|
NOTE: This routine assumes that it is called with the lock
|
|
acquired OR that only a single thread of execution is working
|
|
with this particular adapter.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter whose hardware is to be initialized.
|
|
|
|
Return Value:
|
|
|
|
TRUE is reset successful, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
NDIS_PHYSICAL_ADDRESS PhysicalAddress;
|
|
|
|
//
|
|
// Get station address
|
|
//
|
|
|
|
ElnkGetStationAddress(
|
|
Adapter
|
|
);
|
|
|
|
//
|
|
// Check for validity of the address
|
|
//
|
|
if (((Adapter->NetworkAddress[0] == 0xFF) &&
|
|
(Adapter->NetworkAddress[1] == 0xFF) &&
|
|
(Adapter->NetworkAddress[2] == 0xFF) &&
|
|
(Adapter->NetworkAddress[3] == 0xFF) &&
|
|
(Adapter->NetworkAddress[4] == 0xFF) &&
|
|
(Adapter->NetworkAddress[5] == 0xFF)) ||
|
|
((Adapter->NetworkAddress[0] == 0x00) &&
|
|
(Adapter->NetworkAddress[1] == 0x00) &&
|
|
(Adapter->NetworkAddress[2] == 0x00) &&
|
|
(Adapter->NetworkAddress[3] == 0x00) &&
|
|
(Adapter->NetworkAddress[4] == 0x00) &&
|
|
(Adapter->NetworkAddress[5] == 0x00)))
|
|
{
|
|
ElnkLogError(
|
|
Adapter,
|
|
startChip,
|
|
NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER,
|
|
0);
|
|
|
|
return(FALSE);
|
|
}
|
|
//
|
|
// Do Memory Mapping
|
|
//
|
|
|
|
if (!Adapter->MemoryIsMapped) {
|
|
|
|
NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
|
|
NdisSetPhysicalAddressLow(PhysicalAddress, Adapter->SharedRamPhys);
|
|
|
|
NdisMapIoSpace(
|
|
&Status,
|
|
(PVOID *)(&Adapter->SharedRam),
|
|
Adapter->NdisAdapterHandle,
|
|
PhysicalAddress,
|
|
Adapter->SharedRamSize * 1024
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
ElnkLogError(
|
|
Adapter,
|
|
startChip,
|
|
NDIS_ERROR_CODE_RESOURCE_CONFLICT,
|
|
0
|
|
);
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
Adapter->MemoryIsMapped = TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// everything must be in a single 64K segment
|
|
//
|
|
|
|
Adapter->Scp = (PSCP) ELNK_GET_HOST_ADDRESS(Adapter, OFFSET_SCP);
|
|
|
|
Adapter->Iscp = (PISCP) ELNK_GET_HOST_ADDRESS(Adapter, OFFSET_ISCP);
|
|
|
|
Adapter->Scb = (PSCB) ELNK_GET_HOST_ADDRESS(Adapter, OFFSET_SCB);
|
|
|
|
Adapter->MulticastBlock = (PNON_TRANSMIT_CB)
|
|
ELNK_GET_HOST_ADDRESS(Adapter, OFFSET_MULTICAST);
|
|
|
|
Adapter->TransmitQueue = (PTRANSMIT_CB) Adapter->SharedRam;
|
|
|
|
Adapter->ReceiveQueue = (PRECEIVE_FRAME_DESCRIPTOR) (
|
|
(PUCHAR)(Adapter->TransmitQueue) +
|
|
Adapter->NumberOfTransmitBuffers *
|
|
(sizeof(TRANSMIT_CB) +
|
|
ELNK_OFFSET_TO_NEXT_BUFFER));
|
|
|
|
if ELNKDEBUG {
|
|
DPrint2("Shared Ram = %lx\n",Adapter->SharedRam);
|
|
DPrint2("Scp = %lx\n",Adapter->Scp);
|
|
DPrint2("IScp = %lx\n",Adapter->Iscp);
|
|
DPrint2("Scb = %lx\n",Adapter->Scb);
|
|
DPrint2("MulticastBlock = %lx\n",Adapter->MulticastBlock);
|
|
DPrint2("****** Adapter = %lx\n",Adapter);
|
|
}
|
|
|
|
#if ELNKMC
|
|
//
|
|
// Reset Chip
|
|
//
|
|
|
|
ELNK_WRITE_UCHAR(
|
|
Adapter,
|
|
ELNK_CSR,
|
|
CSR_RESET |
|
|
CSR_BANK_SELECT_MASK
|
|
);
|
|
|
|
NdisStallExecution(1000);
|
|
|
|
ELNK_WRITE_UCHAR(
|
|
Adapter,
|
|
ELNK_CSR,
|
|
CSR_BANK_SELECT_MASK |
|
|
CSR_INTEN
|
|
);
|
|
|
|
//
|
|
// Do a Channel Attention to wake up card. When card wakes up, it will
|
|
// be very hungry and will try to get its food from the reset vector at
|
|
// location offset + 3FF6 for the address of the ISCP
|
|
//
|
|
|
|
//
|
|
// Setup the Reset vector First
|
|
//
|
|
|
|
NdisWriteRegisterUshort(&Adapter->Scp->SysBus, 0);
|
|
NdisWriteRegisterUshort(&Adapter->Scp->IscpBase, 0);
|
|
NdisWriteRegisterUshort(
|
|
&Adapter->Scp->IscpOffset,
|
|
OFFSET_ISCP
|
|
);
|
|
|
|
|
|
//
|
|
// Setup the ISCP
|
|
//
|
|
|
|
NdisWriteRegisterUlong(&Adapter->Iscp->ScbBaseAddress, 0);
|
|
|
|
NdisWriteRegisterUshort(
|
|
&Adapter->Iscp->ScbOffset,
|
|
OFFSET_SCB
|
|
);
|
|
|
|
NdisWriteRegisterUshort(&Adapter->Iscp->Busy, 0x01);
|
|
|
|
|
|
//
|
|
// Put the Scb in a known state
|
|
//
|
|
|
|
NdisWriteRegisterUshort(&Adapter->Scb->Status, CB_STATUS_FREE);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->Command, 0);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->CommandListOffset, ELNK_NULL);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->RFAOffset, ELNK_NULL);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->CrcErrors, 0);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->AlignmentErrors, 0);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->ResourceErrors, 0);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->OverrunErrors, 0);
|
|
|
|
//
|
|
// Do Channel Attention
|
|
//
|
|
|
|
ELNK_CA;
|
|
#else
|
|
|
|
//
|
|
// Setup the Reset vector First
|
|
//
|
|
|
|
NdisWriteRegisterUshort(&Adapter->Scp->SysBus, 0);
|
|
NdisWriteRegisterUshort(&Adapter->Scp->IscpBase, 0);
|
|
NdisWriteRegisterUshort(
|
|
&Adapter->Scp->IscpOffset,
|
|
OFFSET_ISCP
|
|
);
|
|
|
|
|
|
//
|
|
// Setup the ISCP
|
|
//
|
|
|
|
NdisWriteRegisterUlong(&Adapter->Iscp->ScbBaseAddress, 0);
|
|
|
|
NdisWriteRegisterUshort(
|
|
&Adapter->Iscp->ScbOffset,
|
|
OFFSET_SCB
|
|
);
|
|
|
|
NdisWriteRegisterUshort(&Adapter->Iscp->Busy, 0x01);
|
|
|
|
|
|
//
|
|
// Put the Scb in a known state
|
|
//
|
|
|
|
NdisWriteRegisterUshort(&Adapter->Scb->Status, CB_STATUS_FREE);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->Command, 0);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->CommandListOffset, ELNK_NULL);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->RFAOffset, ELNK_NULL);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->CrcErrors, 0);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->AlignmentErrors, 0);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->ResourceErrors, 0);
|
|
NdisWriteRegisterUshort(&Adapter->Scb->OverrunErrors, 0);
|
|
|
|
//
|
|
// Reset Chip
|
|
//
|
|
|
|
ELNK_WRITE_UCHAR(
|
|
Adapter,
|
|
ELNK_CSR,
|
|
CSR_RESET
|
|
);
|
|
|
|
NdisStallExecution(1000);
|
|
|
|
ELNK_WRITE_UCHAR(
|
|
Adapter,
|
|
ELNK_CSR,
|
|
CSR_INTEN
|
|
);
|
|
|
|
//
|
|
// Do a Channel Attention to wake up card. When card wakes up, it will
|
|
// be very hungry and will try to get its food from the reset vector at
|
|
// location offset + 3FF6 for the address of the ISCP
|
|
//
|
|
|
|
ELNK_WRITE_UCHAR(
|
|
Adapter,
|
|
ELNK_CSR,
|
|
CSR_DEFAULT
|
|
);
|
|
//
|
|
// Do Channel Attention
|
|
//
|
|
|
|
ELNK_CA;
|
|
#endif
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
DoResetIndications(
|
|
IN PELNK_ADAPTER Adapter,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by SetConfigurationBlockAndInit to perform any
|
|
indications which need to be done after a reset. Note that
|
|
this routine will be called after either a successful reset
|
|
or a failed reset.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter whose hardware has been initialized.
|
|
|
|
Status - The status of the reset to send to the protocol(s).
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// This will point (possibly null) to the open that
|
|
// initiated the reset.
|
|
//
|
|
PELNK_OPEN ResettingOpen;
|
|
|
|
//
|
|
// We save off the open that caused this reset incase
|
|
// we get *another* reset while we're indicating the
|
|
// last reset is done.
|
|
//
|
|
|
|
ResettingOpen = Adapter->ResettingOpen;
|
|
|
|
//
|
|
// We need to signal every open binding that the
|
|
// reset is complete. We increment the reference
|
|
// count on the open binding while we're doing indications
|
|
// so that the open can't be deleted out from under
|
|
// us while we're indicating (recall that we can't own
|
|
// the lock during the indication).
|
|
//
|
|
|
|
{
|
|
|
|
PELNK_OPEN Open;
|
|
PLIST_ENTRY CurrentLink;
|
|
|
|
CurrentLink = Adapter->OpenBindings.Flink;
|
|
|
|
while (CurrentLink != &Adapter->OpenBindings) {
|
|
|
|
Open = CONTAINING_RECORD(
|
|
CurrentLink,
|
|
ELNK_OPEN,
|
|
OpenList
|
|
);
|
|
|
|
Open->References++;
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Reset failed. Notify of death
|
|
//
|
|
|
|
|
|
NdisIndicateStatus(
|
|
Open->NdisBindingContext,
|
|
NDIS_STATUS_CLOSED,
|
|
NULL,
|
|
0
|
|
);
|
|
}
|
|
|
|
NdisIndicateStatus(
|
|
Open->NdisBindingContext,
|
|
NDIS_STATUS_RESET_END,
|
|
&Status,
|
|
sizeof(Status)
|
|
);
|
|
|
|
NdisIndicateStatusComplete(Open->NdisBindingContext);
|
|
|
|
Open->References--;
|
|
|
|
CurrentLink = CurrentLink->Flink;
|
|
|
|
}
|
|
|
|
//
|
|
// Look to see which open initiated the reset.
|
|
//
|
|
// If the reset was initiated for some obscure hardware
|
|
// reason that can't be associated with a particular
|
|
// open (e.g. memory error on receiving a packet) then
|
|
// we won't have an initiating request so we can't
|
|
// indicate. (The ResettingOpen pointer will be
|
|
// NULL in this case.)
|
|
//
|
|
|
|
if (ResettingOpen) {
|
|
|
|
NdisCompleteReset(
|
|
ResettingOpen->NdisBindingContext,
|
|
Status
|
|
);
|
|
|
|
ResettingOpen->References--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Adapter->ResetInProgress = FALSE;
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Process any Opens that may have been queued in the meantime
|
|
//
|
|
ElnkStartChip(Adapter, &Adapter->ReceiveInfo[Adapter->ReceiveHead]);
|
|
ElnkProcessRequestQueue(Adapter);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Abort everything
|
|
//
|
|
ElnkAbortPendingQueue(Adapter, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
ElnkAbortPendingQueue(
|
|
IN PELNK_ADAPTER Adapter,
|
|
IN BOOLEAN AbortOpens
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine aborts all stuff in the pending queue.
|
|
|
|
NOTE: This routine must be called with the lock acquired.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter whose hardware is to be initialized.
|
|
|
|
AbortOpens - Should Open requests be aborted.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
PNDIS_REQUEST CurrentRequest;
|
|
PNDIS_REQUEST * CurrentNextLocation;
|
|
PELNK_OPEN TmpOpen;
|
|
|
|
PELNK_REQUEST_RESERVED Reserved;
|
|
|
|
//
|
|
// If there is a close at the top of the queue, then
|
|
// it may be in two states:
|
|
//
|
|
// 1- Has interrupted, and the InterruptDpc got the
|
|
// interrupt out of Adapter->IsrValue before we zeroed it.
|
|
//
|
|
// 2- Has interrupted, but we zeroed Adapter->IsrValue
|
|
// before it read it, OR has not yet interrupted.
|
|
//
|
|
// In case 1, the interrupt will be processed and the
|
|
// close will complete without our intervention. In
|
|
// case 2, the open will not complete. In that case
|
|
// the CAM will have been updated for that open, so
|
|
// all that remains is for us to dereference the open
|
|
// as would have been done in the interrupt handler.
|
|
//
|
|
// Closes that are not at the top of the queue we
|
|
// leave in place; when we restart the queue after
|
|
// the reset, they will get processed.
|
|
//
|
|
|
|
CurrentRequest = Adapter->FirstRequest;
|
|
|
|
if (CurrentRequest) {
|
|
|
|
Reserved = PELNK_RESERVED_FROM_REQUEST(CurrentRequest);
|
|
|
|
//
|
|
// If the first request is a close, take it off the
|
|
// queue, and "complete" it.
|
|
//
|
|
|
|
if (CurrentRequest->RequestType == NdisRequestClose) {
|
|
Adapter->FirstRequest = Reserved->Next;
|
|
--(Reserved->OpenBlock)->References;
|
|
CurrentRequest = Adapter->FirstRequest;
|
|
}
|
|
|
|
CurrentNextLocation = &(Adapter->FirstRequest);
|
|
|
|
while (CurrentRequest) {
|
|
|
|
Reserved = PELNK_RESERVED_FROM_REQUEST(CurrentRequest);
|
|
|
|
if (CurrentRequest->RequestType == NdisRequestClose) {
|
|
|
|
CurrentNextLocation = &(Reserved->Next);
|
|
|
|
} else if (CurrentRequest->RequestType == NdisRequestOpen) {
|
|
|
|
if (AbortOpens) {
|
|
|
|
//
|
|
// Complete the open
|
|
//
|
|
|
|
TmpOpen = Reserved->OpenBlock;
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
NdisCompleteOpenAdapter(
|
|
TmpOpen->NdisBindingContext,
|
|
NDIS_STATUS_FAILURE,
|
|
0);
|
|
|
|
ELNK_FREE_PHYS(TmpOpen);
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
//
|
|
// Remove it from the list
|
|
//
|
|
|
|
*CurrentNextLocation = Reserved->Next;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Skip the open
|
|
//
|
|
|
|
CurrentNextLocation = &(Reserved->Next);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Not a close, remove it from the list and
|
|
// fail it.
|
|
//
|
|
|
|
*CurrentNextLocation = Reserved->Next;
|
|
TmpOpen = Reserved->OpenBlock;
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
NdisCompleteRequest(
|
|
TmpOpen->NdisBindingContext,
|
|
CurrentRequest,
|
|
NDIS_STATUS_REQUEST_ABORTED
|
|
);
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
TmpOpen->References--;
|
|
|
|
}
|
|
|
|
CurrentRequest = *CurrentNextLocation;
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
SetupForReset(
|
|
IN PELNK_ADAPTER Adapter,
|
|
IN PELNK_OPEN Open
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to fill in the who and why a reset is
|
|
being set up as well as setting the appropriate fields in the
|
|
adapter.
|
|
|
|
NOTE: This routine must be called with the lock acquired.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter whose hardware is to be initialized.
|
|
|
|
Open - A (possibly NULL) pointer to an Elnk open structure.
|
|
The reason it could be null is if the adapter is initiating the
|
|
reset on its own.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Cancelled;
|
|
|
|
//
|
|
// Stop our deadman timer
|
|
//
|
|
|
|
NdisCancelTimer(&Adapter->DeadmanTimer, &Cancelled);
|
|
|
|
//
|
|
// Shut down the chip. We won't be doing any more work until
|
|
// the reset is complete.
|
|
//
|
|
|
|
ElnkStopChip(Adapter);
|
|
|
|
//
|
|
// We need to signal every open binding that the
|
|
// reset has started. We increment the reference
|
|
// count on the open binding while we're doing indications
|
|
// so that the open can't be deleted out from under
|
|
// us while we're indicating (recall that we can't own
|
|
// the lock during the indication).
|
|
//
|
|
|
|
Adapter->CurrentCsr = CSR_DEFAULT;
|
|
|
|
{
|
|
|
|
PELNK_OPEN Open;
|
|
PLIST_ENTRY CurrentLink;
|
|
|
|
CurrentLink = Adapter->OpenBindings.Flink;
|
|
|
|
while (CurrentLink != &Adapter->OpenBindings) {
|
|
|
|
Open = CONTAINING_RECORD(
|
|
CurrentLink,
|
|
ELNK_OPEN,
|
|
OpenList
|
|
);
|
|
|
|
Open->References++;
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
NdisIndicateStatus(
|
|
Open->NdisBindingContext,
|
|
NDIS_STATUS_RESET_START,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
NdisIndicateStatusComplete(Open->NdisBindingContext);
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
Open->References--;
|
|
|
|
CurrentLink = CurrentLink->Flink;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Adapter->ResetInProgress = TRUE;
|
|
|
|
//
|
|
// Shut down all of the transmit queues so that the
|
|
// transmit portion of the chip will eventually calm down.
|
|
//
|
|
|
|
Adapter->StageOpen = FALSE;
|
|
|
|
ElnkAbortPendingQueue(Adapter, FALSE);
|
|
|
|
Adapter->ResettingOpen = Open;
|
|
|
|
//
|
|
// If there is a valid open we should up the reference count
|
|
// so that the open can't be deleted before we indicate that
|
|
// their request is finished.
|
|
//
|
|
|
|
if (Open) {
|
|
|
|
Open->References++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
ElnkGetStationAddress(
|
|
IN PELNK_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the network address from the hardware.
|
|
|
|
Arguments:
|
|
|
|
Adapter - Where to store the network address.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
#if !ELNKMC
|
|
//
|
|
// Select card address
|
|
//
|
|
|
|
ELNK_WRITE_UCHAR(
|
|
Adapter,
|
|
ELNK_CSR,
|
|
0x01
|
|
);
|
|
#endif
|
|
|
|
ELNK_READ_UCHAR(
|
|
Adapter,
|
|
ELNK_STATION_ID,
|
|
&Adapter->NetworkAddress[0]
|
|
);
|
|
|
|
ELNK_READ_UCHAR(
|
|
Adapter,
|
|
ELNK_STATION_ID + 1,
|
|
&Adapter->NetworkAddress[1]
|
|
);
|
|
|
|
ELNK_READ_UCHAR(
|
|
Adapter,
|
|
ELNK_STATION_ID + 2 ,
|
|
&Adapter->NetworkAddress[2]
|
|
);
|
|
ELNK_READ_UCHAR(
|
|
Adapter,
|
|
ELNK_STATION_ID + 3,
|
|
&Adapter->NetworkAddress[3]
|
|
);
|
|
ELNK_READ_UCHAR(
|
|
Adapter,
|
|
ELNK_STATION_ID + 4,
|
|
&Adapter->NetworkAddress[4]
|
|
);
|
|
ELNK_READ_UCHAR(
|
|
Adapter,
|
|
ELNK_STATION_ID + 5,
|
|
&Adapter->NetworkAddress[5]
|
|
);
|
|
|
|
if ELNKDEBUG {
|
|
UINT i;
|
|
for (i=0;i<6;i++) {
|
|
DPrint2("%x-",(UCHAR)Adapter->NetworkAddress[i]);
|
|
}
|
|
DPrint1("\n");
|
|
}
|
|
|
|
//
|
|
// if no new address is specified, use the BIA
|
|
//
|
|
|
|
if (!Adapter->AddressChanged) {
|
|
|
|
ETH_COPY_NETWORK_ADDRESS(
|
|
Adapter->CurrentAddress,
|
|
Adapter->NetworkAddress
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
#pragma NDIS_INIT_FUNCTION(ElnkInitialInit)
|
|
|
|
|
|
BOOLEAN
|
|
ElnkInitialInit(
|
|
IN PELNK_ADAPTER Adapter,
|
|
IN UINT ElnkInterruptVector
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets up the initial init of the driver.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter for the hardware.
|
|
|
|
ElnkInterruptVector - Interrupt number used by the card.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// stop the chip
|
|
//
|
|
|
|
ElnkStopChip(Adapter);
|
|
|
|
NdisInitializeInterrupt(
|
|
&Status,
|
|
&Adapter->Interrupt,
|
|
Adapter->NdisAdapterHandle,
|
|
ElnkIsr,
|
|
Adapter,
|
|
ElnkStandardInterruptDpc,
|
|
ElnkInterruptVector,
|
|
ElnkInterruptVector,
|
|
FALSE,
|
|
#if ELNKMC
|
|
(NdisInterruptLevelSensitive)
|
|
#else
|
|
(NdisInterruptLatched)
|
|
#endif
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
if (!SetConfigurationBlockAndInit(Adapter)) {
|
|
|
|
if ELNKDEBUG DPrint1("Error configurating block and initializing...\n");
|
|
ElnkLogError(
|
|
Adapter,
|
|
initialInit,
|
|
NDIS_ERROR_CODE_HARDWARE_FAILURE,
|
|
0
|
|
);
|
|
NdisRemoveInterrupt(&Adapter->Interrupt);
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
if ELNKDEBUG DPrint1("Elnk: Unsuccessful connect to interrupt\n");
|
|
ElnkLogError(
|
|
Adapter,
|
|
initialInit,
|
|
NDIS_ERROR_CODE_INTERRUPT_CONNECT,
|
|
(ULONG) ElnkInterruptVector
|
|
);
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
SetupSharedMemory(
|
|
IN PELNK_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes and organizes the
|
|
|
|
- Command List
|
|
|
|
- Receive Frame Area
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter to allocate memory for.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Pointer to a Receive Entry. Used while initializing
|
|
// the Receive Queue.
|
|
//
|
|
PRECEIVE_FRAME_DESCRIPTOR CurrentReceiveEntry;
|
|
|
|
//
|
|
// Pointer to a Command Block. Used while initializing
|
|
// the Command Queue.
|
|
//
|
|
PTRANSMIT_CB CurrentCommandBlock;
|
|
|
|
//
|
|
// for loop variables
|
|
//
|
|
UINT i;
|
|
|
|
if ELNKDEBUG DPrint1("Allocating Command Blocks\n");
|
|
|
|
//
|
|
// Put the Command Blocks into a known state.
|
|
//
|
|
|
|
for(
|
|
i = 0, CurrentCommandBlock = Adapter->TransmitQueue;
|
|
i < Adapter->NumberOfTransmitBuffers;
|
|
i++
|
|
) {
|
|
|
|
NdisZeroMappedMemory(
|
|
(PUCHAR)CurrentCommandBlock,
|
|
sizeof(TRANSMIT_CB)
|
|
);
|
|
|
|
Adapter->TransmitInfo[i].NextCommand = ELNK_EMPTY;
|
|
Adapter->TransmitInfo[i].OwningPacket = NULL;
|
|
Adapter->TransmitInfo[i].OwningOpenBinding = NULL;
|
|
|
|
Adapter->TransmitInfo[i].CommandBlock = CurrentCommandBlock;
|
|
Adapter->TransmitInfo[i].CbOffset = ELNK_GET_CARD_ADDRESS(
|
|
Adapter,
|
|
CurrentCommandBlock
|
|
);
|
|
|
|
Adapter->TransmitInfo[i].Buffer = CurrentCommandBlock + 1;
|
|
|
|
Adapter->TransmitInfo[i].BufferOffset = ELNK_GET_CARD_ADDRESS(
|
|
Adapter,
|
|
Adapter->TransmitInfo[i].Buffer
|
|
);
|
|
|
|
ASSERT(Adapter->TransmitInfo[i].BufferOffset ==
|
|
(Adapter->TransmitInfo[i].CbOffset + sizeof(TRANSMIT_CB))
|
|
);
|
|
|
|
NdisWriteRegisterUshort(
|
|
&CurrentCommandBlock->TbdOffset,
|
|
ELNK_GET_CARD_ADDRESS(Adapter, &CurrentCommandBlock->Tbd)
|
|
);
|
|
|
|
|
|
//
|
|
// ELNK_NULL is non-zero
|
|
//
|
|
|
|
NdisWriteRegisterUshort(
|
|
&CurrentCommandBlock->NextCbOffset,
|
|
ELNK_NULL
|
|
);
|
|
|
|
NdisWriteRegisterUshort(
|
|
&CurrentCommandBlock->Tbd.NextTbdOffset,
|
|
ELNK_NULL
|
|
);
|
|
|
|
NdisWriteRegisterUlong(
|
|
&CurrentCommandBlock->Tbd.BufferOffset,
|
|
Adapter->TransmitInfo[i].BufferOffset
|
|
);
|
|
|
|
if ELNKDEBUG DPrint4("cb address = %x offset = %x buff = %x\n",
|
|
CurrentCommandBlock,
|
|
Adapter->TransmitInfo[i].CbOffset,
|
|
Adapter->TransmitInfo[i].BufferOffset
|
|
);
|
|
|
|
|
|
CurrentCommandBlock = (PTRANSMIT_CB)((PUCHAR)Adapter->TransmitInfo[i].Buffer +
|
|
ELNK_OFFSET_TO_NEXT_BUFFER);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// The multicast transmitinfo is the nth + 1 where n is the number
|
|
// of transmit buffers.
|
|
//
|
|
|
|
//
|
|
// Fill in the multicast Block
|
|
//
|
|
|
|
NdisZeroMappedMemory(
|
|
(PUCHAR)Adapter->MulticastBlock,
|
|
sizeof(NON_TRANSMIT_CB)
|
|
);
|
|
|
|
Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].NextCommand =
|
|
ELNK_EMPTY;
|
|
Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].OwningPacket = NULL;
|
|
Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].OwningOpenBinding = NULL;
|
|
|
|
Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].CommandBlock =
|
|
(PTRANSMIT_CB) Adapter->MulticastBlock;
|
|
|
|
Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].CbOffset = OFFSET_MULTICAST;
|
|
|
|
Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].Buffer = NULL;
|
|
|
|
Adapter->TransmitInfo[Adapter->NumberOfTransmitBuffers].BufferOffset = ELNK_NULL;
|
|
|
|
NdisWriteRegisterUshort(
|
|
&Adapter->MulticastBlock->NextCbOffset,
|
|
ELNK_NULL
|
|
);
|
|
|
|
if ELNKDEBUG DPrint1("Allocating receive buffers\n");
|
|
|
|
//
|
|
// Allocate the receive buffers and attach them to the Receive
|
|
// Queue entries.
|
|
//
|
|
|
|
for(
|
|
i = 0, CurrentReceiveEntry = (PRECEIVE_FRAME_DESCRIPTOR) Adapter->ReceiveQueue;
|
|
i < Adapter->NumberOfReceiveBuffers;
|
|
i++
|
|
) {
|
|
|
|
NdisZeroMemory(
|
|
&Adapter->ReceiveInfo[i],
|
|
sizeof(ELNK_RECEIVE_INFO)
|
|
);
|
|
|
|
NdisZeroMappedMemory(
|
|
(PUCHAR)CurrentReceiveEntry,
|
|
sizeof(RECEIVE_FRAME_DESCRIPTOR)
|
|
);
|
|
|
|
|
|
if ELNKDEBUG DPrint2("Rfd = %x",CurrentReceiveEntry);
|
|
|
|
Adapter->ReceiveInfo[i].Rfd = CurrentReceiveEntry;
|
|
Adapter->ReceiveInfo[i].RfdOffset = ELNK_GET_CARD_ADDRESS(
|
|
Adapter,
|
|
CurrentReceiveEntry
|
|
);
|
|
|
|
if ELNKDEBUG DPrint2(" Offset = %x",Adapter->ReceiveInfo[i].RfdOffset);
|
|
|
|
NdisWriteRegisterUshort(
|
|
&Adapter->ReceiveInfo[i].Rfd->RbdOffset,
|
|
ELNK_GET_CARD_ADDRESS(Adapter,&CurrentReceiveEntry->Rbd)
|
|
);
|
|
|
|
Adapter->ReceiveInfo[i].NextRfdIndex =
|
|
(i+1) % Adapter->NumberOfReceiveBuffers;
|
|
Adapter->ReceiveInfo[i].Buffer = CurrentReceiveEntry + 1;
|
|
|
|
Adapter->ReceiveInfo[i].BufferOffset = ELNK_GET_CARD_ADDRESS(
|
|
Adapter,
|
|
Adapter->ReceiveInfo[i].Buffer
|
|
);
|
|
|
|
if ELNKDEBUG DPrint2(" Buffer Offset = %x\n",Adapter->ReceiveInfo[i].BufferOffset);
|
|
|
|
CurrentReceiveEntry = (PRECEIVE_FRAME_DESCRIPTOR)
|
|
((PUCHAR) Adapter->ReceiveInfo[i].Buffer +
|
|
ELNK_OFFSET_TO_NEXT_BUFFER);
|
|
|
|
}
|
|
|
|
if ELNKDEBUG DPrint1("initializing links\n");
|
|
|
|
for(
|
|
i = 0;
|
|
i < Adapter->NumberOfReceiveBuffers;
|
|
i++
|
|
) {
|
|
|
|
UINT Next = Adapter->ReceiveInfo[i].NextRfdIndex;
|
|
|
|
//
|
|
// Fill the Receive Buffer Descriptor
|
|
//
|
|
|
|
CurrentReceiveEntry = Adapter->ReceiveInfo[i].Rfd;
|
|
|
|
NdisWriteRegisterUlong(
|
|
&CurrentReceiveEntry->Rbd.BufferOffset,
|
|
Adapter->ReceiveInfo[i].BufferOffset
|
|
);
|
|
|
|
NdisWriteRegisterUshort(
|
|
&CurrentReceiveEntry->Rbd.Size,
|
|
(USHORT) (MAXIMUM_ETHERNET_PACKET_SIZE | RBD_END_OF_LIST)
|
|
);
|
|
|
|
NdisWriteRegisterUshort(
|
|
&CurrentReceiveEntry->Rbd.Status,
|
|
(USHORT) 0
|
|
);
|
|
|
|
#if 0
|
|
|
|
NdisWriteRegisterUshort(
|
|
&CurrentReceiveEntry->Rbd.NextRbdOffset,
|
|
Adapter->ReceiveInfo[Next].Rfd->RbdOffset
|
|
);
|
|
|
|
#endif
|
|
|
|
NdisWriteRegisterUshort(
|
|
&CurrentReceiveEntry->Rbd.NextRbdOffset,
|
|
ELNK_NULL
|
|
);
|
|
|
|
//
|
|
// Fill the Receive Frame Descriptor
|
|
//
|
|
|
|
NdisWriteRegisterUshort(
|
|
&CurrentReceiveEntry->NextRfdOffset,
|
|
Adapter->ReceiveInfo[Next].RfdOffset
|
|
);
|
|
}
|
|
|
|
//
|
|
// initialize the last descriptor
|
|
//
|
|
|
|
NdisWriteRegisterUshort(
|
|
&CurrentReceiveEntry->Command,
|
|
RFD_COMMAND_END_OF_LIST | RFD_COMMAND_SUSPEND
|
|
);
|
|
|
|
#if 0
|
|
NdisWriteRegisterUshort(
|
|
&CurrentReceiveEntry->Rbd.Size,
|
|
(USHORT) MAXIMUM_ETHERNET_PACKET_SIZE | RBD_END_OF_LIST
|
|
);
|
|
#endif
|
|
|
|
//
|
|
// reset pointers
|
|
//
|
|
|
|
Adapter->ReceiveHead = 0;
|
|
Adapter->ReceiveTail = Adapter->NumberOfReceiveBuffers - 1;
|
|
}
|
|
|
|
|
|
#if !ELNKMC
|
|
|
|
BOOLEAN AlreadyGeneratedPattern = FALSE;
|
|
|
|
#pragma NDIS_INIT_FUNCTION(Elnk16ConfigureAdapter)
|
|
|
|
BOOLEAN
|
|
Elnk16ConfigureAdapter(
|
|
IN PELNK_ADAPTER Adapter,
|
|
IN BOOLEAN IsExternal,
|
|
IN BOOLEAN ZwsEnabled
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to setup the card registers for the correct
|
|
configuration
|
|
|
|
Arguments:
|
|
|
|
Adapter - adapter to configure.
|
|
IsExternal - are we using External transceiver?
|
|
ZwsEnabled - should zero wait state be enabled?
|
|
|
|
Return Value:
|
|
|
|
Returns true if configuration was done.
|
|
|
|
--*/
|
|
{
|
|
if (!AlreadyGeneratedPattern) {
|
|
|
|
//
|
|
// Initialize State
|
|
//
|
|
|
|
NdisWritePortUchar(
|
|
Adapter->NdisAdapterHandle,
|
|
ELNK16_ID_PORT,
|
|
0x00
|
|
);
|
|
|
|
Elnk16GenerateIdPattern(Adapter);
|
|
|
|
//
|
|
// Go to run state
|
|
//
|
|
|
|
NdisWritePortUchar(
|
|
Adapter->NdisAdapterHandle,
|
|
ELNK16_ID_PORT,
|
|
0x00
|
|
);
|
|
|
|
AlreadyGeneratedPattern = TRUE;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
//
|
|
// Go to reset state
|
|
//
|
|
|
|
Elnk16GenerateIdPattern(Adapter);
|
|
|
|
//
|
|
// Go to IoLoad state
|
|
//
|
|
|
|
Elnk16GenerateIdPattern(Adapter);
|
|
|
|
//
|
|
// Set I/O base address
|
|
//
|
|
|
|
{
|
|
USHORT IdPort;
|
|
IdPort = (USHORT) (Adapter->IoBase - 0x200);
|
|
if (IdPort > 0) {
|
|
|
|
IdPort = IdPort >> 4 ;
|
|
}
|
|
NdisWritePortUchar(
|
|
Adapter->NdisAdapterHandle,
|
|
ELNK16_ID_PORT,
|
|
(UCHAR)IdPort
|
|
);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Now in the configuration state
|
|
//
|
|
|
|
//
|
|
// Check if we have a card present...
|
|
//
|
|
|
|
{
|
|
UCHAR Port1;
|
|
UCHAR Port2;
|
|
UCHAR Port3;
|
|
UCHAR Port4;
|
|
UCHAR Port5;
|
|
UCHAR Port6;
|
|
|
|
//
|
|
// Select 3Com signature. We should get *3COM* in ascii
|
|
//
|
|
|
|
ELNK_WRITE_UCHAR(Adapter, ELNK_CSR, 0x00);
|
|
|
|
ELNK_READ_UCHAR(Adapter, ELNK16_3COM, &Port1);
|
|
ELNK_READ_UCHAR(Adapter, ELNK16_3COM + 1, &Port2);
|
|
ELNK_READ_UCHAR(Adapter, ELNK16_3COM + 2, &Port3);
|
|
ELNK_READ_UCHAR(Adapter, ELNK16_3COM + 3, &Port4);
|
|
ELNK_READ_UCHAR(Adapter, ELNK16_3COM + 4, &Port5);
|
|
ELNK_READ_UCHAR(Adapter, ELNK16_3COM + 5, &Port6);
|
|
|
|
if (!((Port1 == '*') &&
|
|
(Port2 == '3') &&
|
|
(Port3 == 'C') &&
|
|
(Port4 == 'O') &&
|
|
(Port5 == 'M') &&
|
|
(Port6 == '*'))) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#if NDIS_NT
|
|
|
|
switch (Adapter->SharedRamSize) {
|
|
case 16:
|
|
Adapter->CardOffset = 0xC000;
|
|
Adapter->NumberOfTransmitBuffers = ELNK16_16K_TRANSMITS;
|
|
Adapter->NumberOfReceiveBuffers = ELNK16_16K_RECEIVES;
|
|
break;
|
|
case 32:
|
|
Adapter->CardOffset = 0x8000;
|
|
Adapter->NumberOfTransmitBuffers = ELNK16_32K_TRANSMITS;
|
|
Adapter->NumberOfReceiveBuffers = ELNK16_32K_RECEIVES;
|
|
break;
|
|
case 48:
|
|
Adapter->CardOffset = 0x4000;
|
|
Adapter->NumberOfTransmitBuffers = ELNK16_48K_TRANSMITS;
|
|
Adapter->NumberOfReceiveBuffers = ELNK16_48K_RECEIVES;
|
|
break;
|
|
case 64:
|
|
Adapter->CardOffset = 0;
|
|
Adapter->NumberOfTransmitBuffers = ELNK16_64K_TRANSMITS;
|
|
Adapter->NumberOfReceiveBuffers = ELNK16_64K_RECEIVES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Save transceiver type
|
|
//
|
|
|
|
Adapter->IsExternal = IsExternal;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
//
|
|
// Set Transceiver type
|
|
//
|
|
|
|
{
|
|
UCHAR PortValue;
|
|
if (IsExternal) {
|
|
PortValue = 0x00;
|
|
} else {
|
|
PortValue = 0x80;
|
|
}
|
|
|
|
ELNK_WRITE_UCHAR(Adapter, ELNK16_ROM_CONFIG, PortValue);
|
|
|
|
}
|
|
|
|
//
|
|
// Set window base address
|
|
//
|
|
|
|
{
|
|
UCHAR PortValue;
|
|
switch (Adapter->SharedRamPhys) {
|
|
case 0xC0000:
|
|
PortValue = 0;
|
|
break;
|
|
case 0xC8000:
|
|
PortValue = 0x08;
|
|
break;
|
|
case 0xD0000:
|
|
PortValue = 0x10;
|
|
break;
|
|
case 0xD8000:
|
|
PortValue = 0x18;
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Set ZWS value
|
|
//
|
|
|
|
if (ZwsEnabled) {
|
|
PortValue |= 0x80;
|
|
}
|
|
|
|
ELNK_WRITE_UCHAR(Adapter, ELNK16_RAM_CONFIG, PortValue);
|
|
|
|
}
|
|
|
|
//
|
|
// Set interrupt number
|
|
//
|
|
|
|
ELNK_WRITE_UCHAR(Adapter, ELNK16_ICR, (UCHAR)Adapter->InterruptVector);
|
|
|
|
//
|
|
// Go to the run state
|
|
//
|
|
|
|
Elnk16GenerateIdPattern(Adapter);
|
|
|
|
#endif
|
|
|
|
#endif NDIS_NT
|
|
|
|
#if NDIS_WIN
|
|
{
|
|
UCHAR Temp;
|
|
// Transceiver type
|
|
ELNK_READ_UCHAR(Adapter, ELNK16_ROM_CONFIG, &Temp);
|
|
Adapter->IsExternal = (Temp & ROMCR_BNC) ? 0 : 1;
|
|
DPrint2("Temp = %x ",Temp);
|
|
DPrint2("Adapter->IsExternal = %x\n",Adapter->IsExternal);
|
|
|
|
// Interrupt number
|
|
ELNK_READ_UCHAR(Adapter, ELNK16_ICR, &Temp);
|
|
Adapter->InterruptVector = (UINT)(Temp & 0x0F);
|
|
DPrint2("Temp = %x ",Temp);
|
|
DPrint2("Adapter->InterruptVector = %x\n",Adapter->InterruptVector);
|
|
|
|
// MM Base & Size
|
|
ELNK_READ_UCHAR(Adapter, ELNK16_RAM_CONFIG, &Temp);
|
|
if (Temp & 0x20) {
|
|
Adapter->SharedRamSize = 64;
|
|
switch (Temp & 0x0F) {
|
|
case 0x00:
|
|
Adapter->SharedRamPhys = 0xF00000;
|
|
break;
|
|
case 0x01:
|
|
Adapter->SharedRamPhys = 0xF20000;
|
|
break;
|
|
case 0x02:
|
|
Adapter->SharedRamPhys = 0xF40000;
|
|
break;
|
|
case 0x03:
|
|
Adapter->SharedRamPhys = 0xF60000;
|
|
break;
|
|
default:
|
|
Adapter->SharedRamPhys = 0xF80000;
|
|
break;
|
|
}
|
|
} else {
|
|
|
|
switch (Temp & 0x03) {
|
|
case 0x00:
|
|
Adapter->SharedRamSize = 16;
|
|
break;
|
|
case 0x01:
|
|
Adapter->SharedRamSize = 32;
|
|
break;
|
|
case 0x02:
|
|
Adapter->SharedRamSize = 48;
|
|
break;
|
|
default:
|
|
Adapter->SharedRamSize = 64;
|
|
break;
|
|
}
|
|
|
|
switch (Temp & 0x18) {
|
|
case 0x00:
|
|
Adapter->SharedRamPhys = 0x0C0000;
|
|
break;
|
|
case 0x08:
|
|
Adapter->SharedRamPhys = 0x0C8000;
|
|
break;
|
|
case 0x10:
|
|
Adapter->SharedRamPhys = 0x0D0000;
|
|
break;
|
|
default:
|
|
Adapter->SharedRamPhys = 0x0D8000;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
switch (Adapter->SharedRamSize) {
|
|
case 16:
|
|
Adapter->CardOffset = 0xC000;
|
|
Adapter->NumberOfTransmitBuffers = ELNK16_16K_TRANSMITS;
|
|
Adapter->NumberOfReceiveBuffers = ELNK16_16K_RECEIVES;
|
|
break;
|
|
case 32:
|
|
Adapter->CardOffset = 0x8000;
|
|
Adapter->NumberOfTransmitBuffers = ELNK16_32K_TRANSMITS;
|
|
Adapter->NumberOfReceiveBuffers = ELNK16_32K_RECEIVES;
|
|
break;
|
|
case 48:
|
|
Adapter->CardOffset = 0x4000;
|
|
Adapter->NumberOfTransmitBuffers = ELNK16_48K_TRANSMITS;
|
|
Adapter->NumberOfReceiveBuffers = ELNK16_48K_RECEIVES;
|
|
break;
|
|
case 64:
|
|
Adapter->CardOffset = 0;
|
|
Adapter->NumberOfTransmitBuffers = ELNK16_64K_TRANSMITS;
|
|
Adapter->NumberOfReceiveBuffers = ELNK16_64K_RECEIVES;
|
|
break;
|
|
}
|
|
|
|
DPrint2("Temp = %x ",Temp);
|
|
DPrint2("Adapter->SharedRamSize = %x\n",Adapter->SharedRamSize);
|
|
DPrint2("Adapter->SharedRamPhys = %x\n",Adapter->SharedRamPhys);
|
|
DPrint2("Adapter->CardOffset = %x\n",Adapter->CardOffset);
|
|
DPrint2("Adapter->NumberOfTransmitBuffers = %x\n",Adapter->NumberOfTransmitBuffers);
|
|
DPrint2("Adapter->NumberOfReceiveBuffers = %x\n",Adapter->NumberOfReceiveBuffers);
|
|
|
|
// ZWS not needed
|
|
}
|
|
#endif // NDIS_WIN
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
VOID
|
|
Elnk16GenerateIdPattern(
|
|
IN PELNK_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will write the ID pattern to port 0x100h.
|
|
|
|
Arguments:
|
|
|
|
Adapter - Context of the adapter
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UCHAR Value;
|
|
UINT i;
|
|
|
|
Value = 0xff;
|
|
Adapter;
|
|
|
|
for (i = 0 ; i < 255 ; i++) {
|
|
|
|
NdisWritePortUchar(
|
|
Adapter->NdisAdapterHandle,
|
|
ELNK16_ID_PORT,
|
|
Value
|
|
);
|
|
|
|
if (Value & 0x80) {
|
|
|
|
Value = (UCHAR) (Value << 1);
|
|
Value ^= 0xe7;
|
|
|
|
} else {
|
|
|
|
Value = (UCHAR) (Value << 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#endif // !ELNKMC
|
|
|
|
|