summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/elnkmc/reset.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/ndis/elnkmc/reset.c2331
1 files changed, 2331 insertions, 0 deletions
diff --git a/private/ntos/ndis/elnkmc/reset.c b/private/ntos/ndis/elnkmc/reset.c
new file mode 100644
index 000000000..7a4925fba
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/reset.c
@@ -0,0 +1,2331 @@
+/*++
+
+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
+
+