summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/wd/wd.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/ndis/wd/wd.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/ndis/wd/wd.c')
-rw-r--r--private/ntos/ndis/wd/wd.c4599
1 files changed, 4599 insertions, 0 deletions
diff --git a/private/ntos/ndis/wd/wd.c b/private/ntos/ndis/wd/wd.c
new file mode 100644
index 000000000..289770e76
--- /dev/null
+++ b/private/ntos/ndis/wd/wd.c
@@ -0,0 +1,4599 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ wd.c
+
+Abstract:
+
+ This is the main file for the Western Digital
+ Ethernet controller. This driver conforms to the NDIS 3.1 interface.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 15-Jan-1992
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+#include <efilter.h>
+#include <wdhrd.h>
+#include <wdlmireg.h>
+#include <wdlmi.h>
+#include <wdsft.h>
+#include "keywords.h"
+
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+static UCHAR WdBroadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+#if DBG
+
+
+#define LOGSIZE 512
+
+extern UCHAR WdDebugLog[LOGSIZE] = {0};
+extern UINT WdDebugLogPlace = 0;
+
+
+extern
+VOID
+LOG (UCHAR A) {
+ WdDebugLog[WdDebugLogPlace++] = A;
+ WdDebugLog[(WdDebugLogPlace + 4) % LOGSIZE] = '\0';
+ if (WdDebugLogPlace >= LOGSIZE) WdDebugLogPlace = 0;
+}
+
+
+ULONG WdDebugFlag= WD_DEBUG_LOG; // WD_DEBUG_LOG | WD_DEBUG_LOUD | WD_DEBUG_VERY_LOUD;
+
+#define IF_LOG(A) A
+
+#else
+
+#define IF_LOG(A)
+
+#endif
+
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+
+
+//
+// The global MAC block.
+//
+
+extern MAC_BLOCK WdMacBlock={0};
+
+
+
+//
+// If you add to this, make sure to add the
+// a case in WdFillInGlobalData() and in
+// WdQueryGlobalStatistics() if global
+// information only or
+// WdQueryProtocolStatistics() if it is
+// protocol queriable information.
+//
+UINT WdGlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS
+ };
+
+//
+// If you add to this, make sure to add the
+// a case in WdQueryGlobalStatistics() and in
+// WdQueryProtocolInformation()
+//
+UINT WdProtocolSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE
+ };
+
+
+
+
+
+
+
+UINT
+WdCopyOver(
+ OUT PUCHAR Buf, // destination
+ IN PNDIS_PACKET Packet, // source packet
+ IN UINT Offset, // offset in packet
+ IN UINT Length // number of bytes to copy
+ );
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ This is the transfer address of the driver. It initializes
+ WdMacBlock and calls NdisInitializeWrapper() and
+ NdisRegisterMac().
+
+Arguments:
+
+Return Value:
+
+ Indicates the success or failure of the initialization.
+
+--*/
+
+{
+ PMAC_BLOCK NewMacP = &WdMacBlock;
+ NDIS_STATUS Status;
+ NDIS_HANDLE NdisWrapperHandle;
+
+#ifdef NDIS_NT
+ NDIS_STRING MacName = NDIS_STRING_CONST("Smc8000n");
+#endif
+
+#ifdef NDIS_WIN
+ NDIS_STRING MacName = NDIS_STRING_CONST("SMC8000W");
+#endif
+
+#if NDIS_WIN
+ UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + 8 * sizeof (USHORT)];
+#endif
+
+#if NDIS_WIN
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=0;
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=9;
+
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 0)=CNFG_ID_8003E;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 1)=CNFG_ID_8003S;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 2)=CNFG_ID_8003W;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 3)=CNFG_ID_BISTRO03E;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 4)=CNFG_ID_8013E;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 5)=CNFG_ID_8013W;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 6)=CNFG_ID_BISTRO13E;
+ *((PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray) + 7)=CNFG_ID_BISTRO13W;
+
+
+ (PVOID) DriverObject = (PVOID) pIds;
+#endif
+
+ //
+ // Ensure that the MAC_RESERVED structure will fit in the
+ // MacReserved section of a packet.
+ //
+
+ ASSERT(sizeof(MAC_RESERVED) <= sizeof(((PNDIS_PACKET)NULL)->MacReserved));
+
+
+ //
+ // Pass the wrapper a pointer to the device object.
+ //
+
+ NdisInitializeWrapper(&NdisWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ //
+ // Set up the driver object.
+ //
+
+ NewMacP->DriverObject = DriverObject;
+
+ NdisAllocateSpinLock(&NewMacP->SpinLock);
+
+ NewMacP->NdisWrapperHandle = NdisWrapperHandle;
+ NewMacP->Unloading = FALSE;
+ NewMacP->NumAdapters = 0;
+ NewMacP->AdapterQueue = (PWD_ADAPTER)NULL;
+
+
+ //
+ // Prepare to call NdisRegisterMac.
+ //
+
+ NewMacP->MacCharacteristics.MajorNdisVersion = WD_NDIS_MAJOR_VERSION;
+ NewMacP->MacCharacteristics.MinorNdisVersion = WD_NDIS_MINOR_VERSION;
+ NewMacP->MacCharacteristics.Reserved = 0;
+ NewMacP->MacCharacteristics.OpenAdapterHandler = WdOpenAdapter;
+ NewMacP->MacCharacteristics.CloseAdapterHandler = WdCloseAdapter;
+ NewMacP->MacCharacteristics.SendHandler = WdSend;
+ NewMacP->MacCharacteristics.TransferDataHandler = WdTransferData;
+ NewMacP->MacCharacteristics.ResetHandler = WdReset;
+ NewMacP->MacCharacteristics.RequestHandler = WdRequest;
+ NewMacP->MacCharacteristics.QueryGlobalStatisticsHandler =
+ WdQueryGlobalStatistics;
+ NewMacP->MacCharacteristics.UnloadMacHandler = WdUnload;
+ NewMacP->MacCharacteristics.AddAdapterHandler = WdAddAdapter;
+ NewMacP->MacCharacteristics.RemoveAdapterHandler = WdRemoveAdapter;
+
+ NewMacP->MacCharacteristics.Name = MacName;
+
+ NdisRegisterMac(&Status,
+ &NewMacP->NdisMacHandle,
+ NdisWrapperHandle,
+ (NDIS_HANDLE)&WdMacBlock,
+ &NewMacP->MacCharacteristics,
+ sizeof(NewMacP->MacCharacteristics));
+
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // NdisRegisterMac failed.
+ //
+
+ NdisFreeSpinLock(&NewMacP->SpinLock);
+ NdisTerminateWrapper(NdisWrapperHandle, NULL);
+ IF_LOUD( DbgPrint( "NdisRegisterMac failed with code 0x%x\n", Status );)
+ return Status;
+ }
+
+
+ IF_LOUD( DbgPrint( "NdisRegisterMac succeeded\n" );)
+
+ IF_LOUD( DbgPrint("Adapter Initialization Complete\n");)
+
+ return Status;
+
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(WdAddAdapter)
+
+NDIS_STATUS
+WdAddAdapter(
+ IN NDIS_HANDLE MacMacContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ )
+/*++
+Routine Description:
+
+ This is the Wd MacAddAdapter routine. The system calls this routine
+ to add support for a particular WD adapter. This routine extracts
+ configuration information from the configuration data base and registers
+ the adapter with NDIS.
+
+Arguments:
+
+ see NDIS 3.0 spec...
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - Adapter was successfully added.
+ NDIS_STATUS_FAILURE - Adapter was not added, also MAC deregistered.
+
+--*/
+{
+
+ LM_STATUS LmStatus;
+ NDIS_HANDLE ConfigHandle;
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ NDIS_STRING IOAddressStr = IOBASE;
+ NDIS_STRING MaxMulticastListStr = MAXMULTICASTLIST;
+ NDIS_STRING NetworkAddressStr = NETADDRESS;
+ NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
+ NDIS_STRING MediaTypeStr = NDIS_STRING_CONST("MediaType");
+ NDIS_STRING MaxPacketSizeStr = NDIS_STRING_CONST("MaximumPacketSize");
+ NDIS_STRING InterruptStr = INTERRUPT;
+ NDIS_STRING MemoryBaseAddrStr = MEMMAPPEDBASEADDRESS;
+
+ ULONG ConfigErrorValue = 0;
+ BOOLEAN ConfigError = FALSE;
+
+ USHORT WdIoBaseAddr = DEFAULT_IOBASEADDR;
+ UCHAR WdBusType = 0; // AT bus, 1 == MCA;
+ UCHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS] = {0x00};
+ PVOID NetAddress;
+ ULONG Length;
+ UINT MaxMulticastList = DEFAULT_MULTICASTLISTMAX;
+
+ PMAC_BLOCK NewMacP = &WdMacBlock;
+ NDIS_STATUS Status;
+ PWD_ADAPTER Adapter;
+ NDIS_ADAPTER_INFORMATION AdapterInformation; // needed to register adapter
+
+
+ UNREFERENCED_PARAMETER(MacMacContext);
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Read MaxMulticastList
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MaxMulticastListStr,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ MaxMulticastList = ReturnedValue->ParameterData.IntegerData;
+
+ }
+
+ //
+ // Read Bus Type
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &BusTypeStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ if (ReturnedValue->ParameterData.IntegerData == NdisInterfaceMca) {
+
+ WdBusType = 1;
+
+ } else {
+
+ WdBusType = 0;
+
+ }
+
+ }
+
+
+ //
+ // Read Io Base Address (if Appropriate)
+ //
+
+ if (WdBusType != 1) {
+
+ //
+ // Read I/O Address
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &IOAddressStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ WdIoBaseAddr = (USHORT)(ReturnedValue->ParameterData.IntegerData);
+
+ }
+
+ }
+
+ //
+ // Read net address
+ //
+
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ if ((Length == ETH_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
+
+ ETH_COPY_NETWORK_ADDRESS(
+ CurrentAddress,
+ NetAddress
+ );
+
+ }
+
+RegisterAdapter:
+
+ //
+ // Allocate memory for the adapter block now.
+ //
+
+ Status = NdisAllocateMemory( (PVOID *)&Adapter, sizeof(WD_ADAPTER), 0, HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ ConfigError = TRUE;
+ ConfigErrorValue = NDIS_ERROR_CODE_OUT_OF_RESOURCES;
+
+ goto RegisterAdapter;
+
+ }
+
+
+ NdisZeroMemory(Adapter,sizeof(WD_ADAPTER));
+
+ if (!ConfigError && (WdBusType == 1)) {
+
+ if (LM_Get_Mca_Io_Base_Address(
+ &(Adapter->LMAdapter),
+ ConfigurationHandle,
+ &WdIoBaseAddr
+ )) {
+
+ WdIoBaseAddr = 0;
+ ConfigError = TRUE;
+ ConfigErrorValue = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
+
+ }
+
+ }
+
+ //
+ // The adapter is initialized, register it with NDIS.
+ // This must occur before interrupts are enabled since the
+ // InitializeInterrupt routine requires the NdisAdapterHandle
+ //
+
+ //
+ // Set up the AdapterInformation structure; zero it
+ // first in case it is extended later.
+ //
+
+ NdisZeroMemory (&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION));
+ AdapterInformation.AdapterType = (WdBusType == 1)?
+ NdisInterfaceMca:
+ NdisInterfaceIsa;
+ AdapterInformation.NumberOfPortDescriptors = 1;
+ AdapterInformation.PortDescriptors[0].InitialPort = (ULONG)WdIoBaseAddr;
+ AdapterInformation.PortDescriptors[0].NumberOfPorts = 0x20;
+
+
+ Status = NdisRegisterAdapter(&Adapter->LMAdapter.NdisAdapterHandle,
+ WdMacBlock.NdisMacHandle,
+ (NDIS_HANDLE)Adapter,
+ ConfigurationHandle,
+ AdapterName,
+ &AdapterInformation
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // NdisRegisterAdapter failed.
+ //
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+
+ if (ConfigError) {
+
+ //
+ // Log Error and exit.
+ //
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ ConfigErrorValue,
+ 1
+ );
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ NdisDeregisterAdapter(Adapter->LMAdapter.NdisAdapterHandle);
+
+ NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ Adapter->LMAdapter.io_base = WdIoBaseAddr;
+ Adapter->LMAdapter.bus_type = WdBusType;
+
+ LmStatus = LM_Get_Config(&(Adapter->LMAdapter));
+
+ if (LmStatus == ADAPTER_NOT_FOUND) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 0
+ );
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ NdisDeregisterAdapter(Adapter->LMAdapter.NdisAdapterHandle);
+ NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ if (LmStatus == ADAPTER_NO_CONFIG) {
+
+ //
+ // Read any information from the registry which might help
+ //
+
+
+ //
+ // Read Interrupt
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &InterruptStr,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ Adapter->LMAdapter.irq_value = (USHORT)(ReturnedValue->ParameterData.IntegerData);
+
+ }
+
+
+
+ //
+ // Read MemoryBaseAddress
+ //
+
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MemoryBaseAddrStr,
+ NdisParameterHexInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+#if NDIS_NT
+ Adapter->LMAdapter.ram_base = (ULONG)(ReturnedValue->ParameterData.IntegerData);
+#else
+ Adapter->LMAdapter.ram_base = (ULONG)((ReturnedValue->ParameterData.IntegerData) << 4);
+#endif
+
+ }
+
+
+ }
+
+ NdisCloseConfiguration(ConfigHandle);
+
+
+ if (WdRegisterAdapter(Adapter,
+ DEFAULT_NUMBUFFERS,
+ MaxMulticastList,
+ CurrentAddress
+ )
+ != NDIS_STATUS_SUCCESS) {
+
+
+
+ //
+ // WdRegisterAdapter failed.
+ //
+
+ NdisDeregisterAdapter(Adapter->LMAdapter.NdisAdapterHandle);
+ NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
+ return NDIS_STATUS_FAILURE;
+ }
+
+
+
+ IF_LOUD( DbgPrint( "WdRegisterAdapter succeeded\n" );)
+
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(WdRegisterAdapter)
+
+NDIS_STATUS
+WdRegisterAdapter(
+ IN PWD_ADAPTER Adapter,
+ IN UINT NumBuffers,
+ IN UINT MulticastListMax,
+ IN UCHAR NodeAddress[ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+
+Routine Description:
+
+ Called when a new adapter should be registered. It allocates space for
+ the adapter and open blocks, initializes the adapters block, and
+ calls NdisRegisterAdapter().
+
+Arguments:
+
+ Adapter - A pointer to the adapter structure.
+ NumBuffers - Number of transmit buffers.
+ MulticastListMax - Number of multicast list addresses allowed.
+ NodeAddress - Ethernet address for this adapter. if all 0x00 then the
+ permanent address on the card is used.
+
+Return Value:
+
+ Indicates the success or failure of the registration.
+
+--*/
+
+{
+ UINT i;
+ CHAR KernelInterrupt;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+ NDIS_STATUS status; //general purpose return from NDIS calls
+
+
+ Adapter->MulticastListMax = MulticastListMax;
+
+ //
+ // check that NumBuffers <= MAX_XMIT_BUFS
+ //
+
+ if (NumBuffers > MAX_XMIT_BUFS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ status = NDIS_STATUS_RESOURCES;
+
+ goto fail1;
+
+ }
+
+
+ Adapter->OpenQueue = (PWD_OPEN)NULL;
+
+ //
+ // Allocate the Spin lock.
+ //
+ NdisAllocateSpinLock(&Adapter->Lock);
+
+
+ //
+ // Initialize Transmit information
+ //
+
+ Adapter->DeferredDpc = (PVOID) WdInterruptDpc;
+
+ //
+ // Initialize References.
+ //
+
+ NdisInitializeTimer(&(Adapter->DeferredTimer),
+ Adapter->DeferredDpc,
+ Adapter);
+
+ //
+ // Link us on to the chain of adapters for this MAC.
+ //
+
+ Adapter->MacBlock = &WdMacBlock;
+ NdisAcquireSpinLock(&WdMacBlock.SpinLock);
+ Adapter->NextAdapter = WdMacBlock.AdapterQueue;
+ WdMacBlock.AdapterQueue = Adapter;
+ NdisReleaseSpinLock(&WdMacBlock.SpinLock);
+
+ //
+ // Set up the interrupt handlers.
+ //
+
+ KernelInterrupt = (CCHAR)(Adapter->LMAdapter.irq_value);
+
+ NdisInitializeInterrupt(&status, // status of call
+ &(Adapter->LMAdapter.NdisInterrupt), // interrupt info str
+ Adapter->LMAdapter.NdisAdapterHandle,
+ (PNDIS_INTERRUPT_SERVICE) WdInterruptHandler,
+ Adapter, // context for ISR, DPC
+ (PNDIS_DEFERRED_PROCESSING) WdInterruptDpc,
+ KernelInterrupt, // int #
+ KernelInterrupt, // IRQL
+ FALSE, // NOT shared
+ (Adapter->LMAdapter.bus_type == 0) ?
+ NdisInterruptLatched : // ATBus
+ NdisInterruptLevelSensitive // MCA
+ );
+
+
+ if (status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 0
+ );
+
+ goto fail3;
+ }
+
+ IF_LOUD( DbgPrint("Interrupt Connected\n");)
+
+ //
+ // Map the memory mapped portion of the card.
+ //
+ //
+
+ NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
+ NdisSetPhysicalAddressLow(PhysicalAddress, (ULONG)(Adapter->LMAdapter.ram_base));
+
+ NdisMapIoSpace(&status,
+ &Adapter->LMAdapter.ram_access,
+ Adapter->LMAdapter.NdisAdapterHandle,
+ PhysicalAddress,
+ Adapter->LMAdapter.ram_size * 1024);
+
+ if (status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ goto failmap;
+
+ }
+
+
+ //
+ // Now Initialize the card.
+ //
+
+ //
+ // Set Relevant variables first...
+ //
+ // base_io and ram_size are set from LM_Get_Config.
+ //
+ //
+ //
+ // ram_access, node_address, max_packet_size, buffer_page_size,
+ // num_of_tx_buffs and receive_mask need to be set.
+ //
+
+ for (i = 0; i < 6 ; i ++) {
+
+ Adapter->LMAdapter.node_address[i] = NodeAddress[i];
+
+ }
+
+ Adapter->LMAdapter.max_packet_size = WD_MAX_PACKET_SIZE;
+ Adapter->LMAdapter.buffer_page_size= WD_BUFFER_PAGE_SIZE;
+ Adapter->LMAdapter.num_of_tx_buffs = (USHORT)NumBuffers;
+
+ Adapter->LMAdapter.ptr_rx_CRC_errors = &(Adapter->CrcErrors);
+ Adapter->LMAdapter.ptr_rx_too_big = &(Adapter->TooBig);
+ Adapter->LMAdapter.ptr_rx_lost_pkts = &(Adapter->MissedPackets);
+ Adapter->LMAdapter.ptr_rx_align_errors = &(Adapter->FrameAlignmentErrors);
+ Adapter->LMAdapter.ptr_rx_overruns = &(Adapter->Overruns);
+
+ Adapter->LMAdapter.ptr_tx_deferred = &(Adapter->FramesXmitDeferred);
+ Adapter->LMAdapter.ptr_tx_max_collisions = &(Adapter->FramesXmitBad);
+ Adapter->LMAdapter.ptr_tx_one_collision = &(Adapter->FramesXmitOneCollision);
+ Adapter->LMAdapter.ptr_tx_mult_collisions = &(Adapter->FramesXmitManyCollisions);
+ Adapter->LMAdapter.ptr_tx_ow_collision = &(Adapter->FramesXmitOverWrite);
+ Adapter->LMAdapter.ptr_tx_CD_heartbeat = &(Adapter->FramesXmitHeartbeat);
+ Adapter->LMAdapter.ptr_tx_underruns = &(Adapter->FramesXmitUnderruns);
+ Adapter->LMAdapter.FilterDB = NULL;
+
+ if (LM_Initialize_Adapter(&(Adapter->LMAdapter)) != SUCCESS){
+
+ //
+ // The Card could not be written to.
+ //
+
+ Adapter->HardwareFailure = TRUE;
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ goto fail6;
+ }
+
+
+ //
+ // Initialize Filter Database
+ //
+
+ if (!EthCreateFilter(MulticastListMax,
+ WdChangeMulticastAddresses,
+ WdChangeFilterClasses,
+ WdCloseAction,
+ Adapter->LMAdapter.node_address,
+ &Adapter->Lock,
+ &Adapter->LMAdapter.FilterDB
+ )) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ status = NDIS_STATUS_FAILURE;
+
+ goto fail6;
+
+ }
+
+ //
+ // Initialize the wake up timer to catch interrupts that
+ // don't complete. It fires continuously
+ // every 5 seconds, and we check if there are any
+ // uncompleted operations from the previous two-second
+ // period.
+ //
+
+ Adapter->WakeUpDpc = (PVOID)WdWakeUpDpc;
+
+ NdisInitializeTimer(&Adapter->WakeUpTimer,
+ (PVOID)(Adapter->WakeUpDpc),
+ Adapter );
+
+ NdisSetTimer(
+ &Adapter->WakeUpTimer,
+ 5000
+ );
+
+ //
+ // Initialization completed successfully.
+ //
+
+ IF_LOUD( { DbgPrint(" WdLan: [OK]\n");})
+
+ return NDIS_STATUS_SUCCESS;
+
+
+ //
+ // Code to unwind what has already been set up when a part of
+ // initialization fails, which is jumped into at various
+ // points based on where the failure occured. Jumping to
+ // a higher-numbered failure point will execute the code
+ // for that block and all lower-numbered ones.
+ //
+
+fail6:
+
+ NdisUnmapIoSpace(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ Adapter->LMAdapter.ram_access,
+ Adapter->LMAdapter.ram_size * 1024);
+
+failmap:
+
+ NdisRemoveInterrupt(&(Adapter->LMAdapter.NdisInterrupt));
+
+ NdisAcquireSpinLock(&WdMacBlock.SpinLock);
+
+ //
+ // Take us out of the AdapterQueue.
+ //
+
+ if (WdMacBlock.AdapterQueue == Adapter) {
+
+ WdMacBlock.AdapterQueue = Adapter->NextAdapter;
+
+ } else {
+
+ PWD_ADAPTER TmpAdapter = WdMacBlock.AdapterQueue;
+
+ while (TmpAdapter->NextAdapter != Adapter) {
+
+ TmpAdapter = TmpAdapter->NextAdapter;
+
+ }
+
+ TmpAdapter->NextAdapter = TmpAdapter->NextAdapter->NextAdapter;
+ }
+
+ NdisReleaseSpinLock(&WdMacBlock.SpinLock);
+
+fail3:
+ NdisFreeSpinLock(&Adapter->Lock);
+
+fail1:
+
+ return status;
+}
+
+
+#pragma NDIS_PAGABLE_FUNCTION(WdOpenAdapter)
+
+
+NDIS_STATUS
+WdOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ 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 OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function. It initializes the open block and links it in
+ the appropriate lists.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PWD_ADAPTER Adapter = ((PWD_ADAPTER)MacAdapterContext);
+ PWD_OPEN NewOpen;
+ NDIS_STATUS Status;
+
+ //
+ // Don't use extended error or OpenOptions for Wd
+ //
+
+ UNREFERENCED_PARAMETER(OpenOptions);
+
+ *OpenErrorStatus=NDIS_STATUS_SUCCESS;
+
+ IF_LOUD( DbgPrint("In Open Adapter\n");)
+
+ //
+ // Scan the media list for our media type (802.3)
+ //
+
+ *SelectedMediumIndex = (UINT)(-1);
+
+ while (MediumArraySize > 0) {
+
+ if (MediumArray[--MediumArraySize] == NdisMedium802_3 ) {
+
+ *SelectedMediumIndex = MediumArraySize;
+
+ break;
+ }
+ }
+
+
+ if (*SelectedMediumIndex == -1) {
+
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ }
+
+ //
+ // Link this open to the appropriate lists.
+ //
+
+ if (Adapter->HardwareFailure) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ //
+ // Allocate memory for the open.
+ //
+
+
+ Status = NdisAllocateMemory((PVOID *)&NewOpen, sizeof(WD_OPEN), 0, HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Adapter->References++;
+
+ //
+ // Link this open to the appropriate lists.
+ //
+
+ if (Adapter->OpenQueue == NULL) {
+
+ //
+ // The first open on this adapter.
+ //
+
+ if (LM_Open_Adapter(&(Adapter->LMAdapter)) != SUCCESS) {
+
+ IF_LOUD( DbgPrint("OpenFailed!\n");)
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ IF_LOUD( DbgPrint("OpenSuccess!\n");)
+
+ }
+
+ NewOpen->NextOpen = Adapter->OpenQueue;
+ Adapter->OpenQueue = NewOpen;
+
+ if (!EthNoteFilterOpenAdapter(
+ Adapter->LMAdapter.FilterDB,
+ NewOpen,
+ NdisBindingContext,
+ &NewOpen->NdisFilterHandle
+ )) {
+
+ Adapter->References--;
+
+ Adapter->OpenQueue = NewOpen->NextOpen;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ return NDIS_STATUS_FAILURE;
+
+
+ }
+
+ //
+ // Set up the open block.
+ //
+
+ NewOpen->Adapter = Adapter;
+ NewOpen->MacBlock = Adapter->MacBlock;
+ NewOpen->NdisBindingContext = NdisBindingContext;
+ NewOpen->AddressingInformation = AddressingInformation;
+ NewOpen->Closing = FALSE;
+ NewOpen->LookAhead = WD_MAX_LOOKAHEAD;
+ NewOpen->ProtOptionFlags = 0;
+
+ Adapter->MaxLookAhead = WD_MAX_LOOKAHEAD;
+
+ NewOpen->ReferenceCount = 1;
+
+ *MacBindingHandle = (NDIS_HANDLE)NewOpen;
+
+ WD_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("Out Open Adapter\n");)
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+VOID
+WdAdjustMaxLookAhead(
+ IN PWD_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine finds the open with the maximum lookahead value and
+ stores that in the adapter block.
+
+ NOTE: THIS ROUTINE MUST BE CALLED WITH THE SPINLOCK HELD.
+
+Arguments:
+
+ Adapter - A pointer to the adapter block.
+
+Returns:
+
+ None.
+
+--*/
+{
+ ULONG CurrentMax = 0;
+ PWD_OPEN CurrentOpen;
+
+ CurrentOpen = Adapter->OpenQueue;
+
+ while (CurrentOpen != NULL) {
+
+ if (CurrentOpen->LookAhead > CurrentMax) {
+
+ CurrentMax = CurrentOpen->LookAhead;
+
+ }
+
+ CurrentOpen = CurrentOpen->NextOpen;
+ }
+
+ if (CurrentMax == 0) {
+
+ CurrentMax = WD_MAX_LOOKAHEAD;
+
+ }
+
+ Adapter->MaxLookAhead = CurrentMax;
+
+}
+
+NDIS_STATUS
+WdCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function. Unlinks the open block and frees it.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PWD_OPEN Open = ((PWD_OPEN)MacBindingHandle);
+ PWD_ADAPTER Adapter = Open->Adapter;
+ PWD_OPEN TmpOpen;
+ NDIS_STATUS StatusToReturn;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (Open->Closing) {
+
+ //
+ // The open is already being closed.
+ //
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return NDIS_STATUS_CLOSING;
+ }
+
+ Adapter->References++;
+
+ Open->ReferenceCount++;
+
+ //
+ // Remove this open from the list for this adapter.
+ //
+
+ if (Open == Adapter->OpenQueue) {
+
+ Adapter->OpenQueue = Open->NextOpen;
+
+ } else {
+
+ TmpOpen = Adapter->OpenQueue;
+
+ while (TmpOpen->NextOpen != Open) {
+
+ TmpOpen = TmpOpen->NextOpen;
+
+ }
+
+ TmpOpen->NextOpen = Open->NextOpen;
+ }
+
+
+
+ //
+ // Remove from Filter package to block all receives.
+ //
+
+ StatusToReturn = EthDeleteFilterOpenAdapter(
+ Adapter->LMAdapter.FilterDB,
+ Open->NdisFilterHandle,
+ NULL
+ );
+
+ //
+ // If the status is successful that merely implies that
+ // we were able to delete the reference to the open binding
+ // from the filtering code. If we have a successful status
+ // at this point we still need to check whether the reference
+ // count to determine whether we can close.
+ //
+ //
+ // The delete filter routine can return a "special" status
+ // that indicates that there is a current NdisIndicateReceive
+ // on this binding. See below.
+ //
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Check whether the reference count is two. If
+ // it is then we can get rid of the memory for
+ // this open.
+ //
+ // A count of two indicates one for this routine
+ // and one for the filter which we *know* we can
+ // get rid of.
+ //
+
+ if (Open->ReferenceCount != 2) {
+
+ //
+ // We are not the only reference to the open. Remove
+ // it from the open list and delete the memory.
+ //
+
+
+ Open->Closing = TRUE;
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the original open.
+ //
+
+ Open->ReferenceCount -= 2;
+
+ //
+ // Change the status to indicate that we will
+ // be closing this later.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ } else {
+
+ Open->ReferenceCount -= 2;
+
+ }
+
+ } else if (StatusToReturn == NDIS_STATUS_PENDING) {
+
+ Open->Closing = TRUE;
+
+ //
+ // Account for this routines reference to the open
+ // as well as reference because of the original open.
+ //
+
+ Open->ReferenceCount -= 2;
+
+ } else if (StatusToReturn == NDIS_STATUS_CLOSING_INDICATING) {
+
+ //
+ // When we have this status it indicates that the filtering
+ // code was currently doing an NdisIndicateReceive. It
+ // would not be wise to delete the memory for the open at
+ // this point. The filtering code will call our close action
+ // routine upon return from NdisIndicateReceive and that
+ // action routine will decrement the reference count for
+ // the open.
+ //
+
+ Open->Closing = TRUE;
+
+ //
+ // This status is private to the filtering routine. Just
+ // tell the caller the the close is pending.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ //
+ // Account for this routines reference to the open.
+ //
+
+ Open->ReferenceCount--;
+
+ } else {
+
+ //
+ // Account for this routines reference to the open.
+ //
+
+ Open->ReferenceCount--;
+
+ }
+
+ //
+ // See if this is the last reference to this open.
+ //
+
+ if (Open->ReferenceCount == 0) {
+
+ //
+ // Check if the MaxLookAhead needs adjustment.
+ //
+
+ if (Open->LookAhead == Adapter->MaxLookAhead) {
+
+ WdAdjustMaxLookAhead(Adapter);
+
+ }
+
+
+ if (Adapter->OpenQueue == NULL) {
+
+ //
+ // We can disable the card.
+ //
+
+ if (NdisSynchronizeWithInterrupt(
+ &(Adapter->LMAdapter.NdisInterrupt),
+ (PVOID)WdSyncCloseAdapter,
+ (PVOID)(&(Adapter->LMAdapter))
+ ) == FALSE) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ IF_LOUD( DbgPrint("CloseAdapter FAILED!\n");)
+
+ } else {
+
+
+ IF_LOUD( DbgPrint("CloseAdapter Success!\n");)
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Will get removed when count drops to zero.
+ //
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ }
+
+
+ WD_DO_DEFERRED(Adapter);
+
+ return(StatusToReturn);
+
+}
+
+NDIS_STATUS
+WdRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allows a protocol to query and set information
+ about the MAC.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to PWD_OPEN.
+
+ NdisRequest - A structure which contains the request type (Set or
+ Query), an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ PWD_OPEN Open = (PWD_OPEN)(MacBindingHandle);
+ PWD_ADAPTER Adapter = (Open->Adapter);
+
+
+ IF_LOUD( DbgPrint("In Request\n");)
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Ensure that the open does not close while in this function.
+ //
+
+ Open->ReferenceCount++;
+
+ Adapter->References++;
+
+ //
+ // Process request
+ //
+
+ if (Open->Closing) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ } else if (NdisRequest->RequestType == NdisRequestQueryInformation) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = WdQueryInformation(Adapter, Open, NdisRequest);
+
+ } else if (NdisRequest->RequestType == NdisRequestSetInformation) {
+
+ if (Adapter->HardwareFailure) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = WdSetInformation(Adapter,Open,NdisRequest);
+
+ }
+
+ } else {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ StatusToReturn = NDIS_STATUS_NOT_RECOGNIZED;
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(Open);
+
+ WD_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("Out Request\n");)
+
+ return(StatusToReturn);
+
+}
+
+NDIS_STATUS
+WdQueryProtocolInformation(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN NDIS_OID Oid,
+ IN BOOLEAN GlobalMode,
+ IN PVOID InfoBuffer,
+ IN UINT BytesLeft,
+ OUT PUINT BytesNeeded,
+ OUT PUINT BytesWritten
+)
+
+/*++
+
+Routine Description:
+
+ The WdQueryProtocolInformation process a Query request for
+ NDIS_OIDs that are specific to a binding about the MAC. Note that
+ some of the OIDs that are specific to bindings are also queryable
+ on a global basis. Rather than recreate this code to handle the
+ global queries, I use a flag to indicate if this is a query for the
+ global data or the binding specific data.
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+ Open - a pointer to the open instance.
+
+ Oid - the NDIS_OID to process.
+
+ GlobalMode - Some of the binding specific information is also used
+ when querying global statistics. This is a flag to specify whether
+ to return the global value, or the binding specific value.
+
+ PlaceInInfoBuffer - a pointer into the NdisRequest->InformationBuffer
+ into which store the result of the query.
+
+ BytesLeft - the number of bytes left in the InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information buffer
+ then this will contain the number of bytes needed to complete the
+ request.
+
+ BytesWritten - a pointer to the number of bytes written into the
+ InformationBuffer.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+ ULONG GenericULong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Common variables for pointing to result of query
+ //
+
+ PVOID MoveSource = (PVOID)(&GenericULong);
+ ULONG MoveBytes = sizeof(ULONG);
+
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // Copy result in common variable to result buffer.
+ //
+
+ //
+ // Make sure that ulong is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(ULONG) == 4);
+
+
+ IF_LOUD( DbgPrint("In QueryProtocol\n");)
+
+ //
+ // Make sure no changes occur while processing.
+ //
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ //
+ // Switch on request type
+ //
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_NO_LOOPBACK
+ );
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ if (!GlobalMode) {
+
+ MoveSource = (PVOID)(WdProtocolSupportedOids);
+ MoveBytes = sizeof(WdProtocolSupportedOids);
+
+ } else {
+
+ MoveSource = (PVOID)(WdGlobalSupportedOids);
+ MoveBytes = sizeof(WdGlobalSupportedOids);
+
+ }
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ if (Adapter->HardwareFailure) {
+
+ HardwareStatus = NdisHardwareStatusNotReady;
+
+ } else {
+
+ HardwareStatus = NdisHardwareStatusReady;
+
+ }
+
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericULong = WD_MAX_LOOKAHEAD;
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericULong = (ULONG)(WD_MAX_PACKET_SIZE - WD_HEADER_SIZE);
+
+ break;
+
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericULong = (ULONG)(WD_MAX_PACKET_SIZE);
+
+ break;
+
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericULong = (ULONG)(100000);
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericULong = (ULONG)(Adapter->LMAdapter.num_of_tx_buffs
+ * Adapter->LMAdapter.xmit_buf_size);
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericULong = (ULONG)((Adapter->LMAdapter.ram_size * 1024) -
+ (Adapter->LMAdapter.num_of_tx_buffs
+ * Adapter->LMAdapter.xmit_buf_size));
+
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(Adapter->LMAdapter.buffer_page_size);
+
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericULong = (ULONG)(Adapter->LMAdapter.buffer_page_size);
+
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericULong,
+ Adapter->LMAdapter.permanent_node_address,
+ 3
+ );
+ GenericULong &= 0xFFFFFF00;
+ MoveSource = (PVOID)(&GenericULong);
+ MoveBytes = sizeof(GenericULong);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"SMC Adapter.";
+ MoveBytes = 13;
+
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = ((USHORT)WD_NDIS_MAJOR_VERSION << 8) |
+ WD_NDIS_MINOR_VERSION;
+
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(GenericUShort);
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (GlobalMode) {
+
+ UINT Filter;
+
+ Filter = ETH_QUERY_FILTER_CLASSES(Adapter->LMAdapter.FilterDB);
+
+ GenericULong = (ULONG)(Filter);
+
+ } else {
+
+ UINT Filter = 0;
+
+ Filter = ETH_QUERY_PACKET_FILTER(Adapter->LMAdapter.FilterDB,
+ Open->NdisFilterHandle);
+
+ GenericULong = (ULONG)(Filter);
+
+ }
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ if ( GlobalMode ) {
+
+ GenericULong = (ULONG)(Adapter->MaxLookAhead);
+
+ } else {
+
+ GenericULong = Open->LookAhead;
+
+ }
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ WD_MOVE_MEM((PCHAR)GenericArray,
+ Adapter->LMAdapter.permanent_node_address,
+ ETH_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->LMAdapter.permanent_node_address);
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ WD_MOVE_MEM((PCHAR)GenericArray,
+ Adapter->LMAdapter.node_address,
+ ETH_LENGTH_OF_ADDRESS);
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = sizeof(Adapter->LMAdapter.node_address);
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ {
+ UINT NumAddresses;
+
+
+ if (GlobalMode) {
+
+ NumAddresses = ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(Adapter->LMAdapter.FilterDB);
+
+ if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) {
+
+ *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ break;
+
+ }
+
+ EthQueryGlobalFilterAddresses(
+ &StatusToReturn,
+ Adapter->LMAdapter.FilterDB,
+ BytesLeft,
+ &NumAddresses,
+ InfoBuffer
+ );
+
+ *BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ } else {
+
+ NumAddresses = EthNumberOfOpenFilterAddresses(
+ Adapter->LMAdapter.FilterDB,
+ Open->NdisFilterHandle
+ );
+
+ if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > BytesLeft) {
+
+ *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ break;
+
+ }
+
+ EthQueryOpenFilterAddresses(
+ &StatusToReturn,
+ Adapter->LMAdapter.FilterDB,
+ Open->NdisFilterHandle,
+ BytesLeft,
+ &NumAddresses,
+ InfoBuffer
+ );
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ *BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
+
+ }
+
+ }
+
+
+
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericULong = (ULONG) (Adapter->MulticastListMax);
+
+ break;
+
+
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if ((StatusToReturn == NDIS_STATUS_SUCCESS) &&
+ (Oid != OID_802_3_MULTICAST_LIST)) {
+
+ if (MoveBytes > BytesLeft) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes - BytesLeft;
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ } else {
+
+ //
+ // Store result.
+ //
+
+ WD_MOVE_MEM(InfoBuffer, MoveSource, MoveBytes);
+
+ (*BytesWritten) += MoveBytes;
+
+ }
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Out QueryProtocol\n");)
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+WdQueryInformation(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ The WdQueryInformation is used by WdRequest to query information
+ about the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to a particular open instance.
+
+ NdisRequest - A structure which contains the request type (Query),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ UINT BytesWritten = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ IF_LOUD( DbgPrint("In QueryInfor\n");)
+
+ StatusToReturn = WdQueryProtocolInformation(
+ Adapter,
+ Open,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ FALSE,
+ InfoBuffer,
+ BytesLeft,
+ &BytesNeeded,
+ &BytesWritten
+ );
+
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
+
+ IF_LOUD( DbgPrint("Out QueryInfor\n");)
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+WdSetInformation(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ The WdSetInformation is used by WdRequest to set information
+ about the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter.
+
+ Open - A pointer to an open instance.
+
+ NdisRequest - A structure which contains the request type (Set),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // General Algorithm:
+ //
+ // Verify length
+ // Switch(Request)
+ // Process Request
+ //
+
+ UINT BytesRead = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
+
+ //
+ // Variables for a particular request
+ //
+
+ NDIS_OID Oid;
+ UINT OidLength;
+
+ //
+ // Variables for holding the new values to be used.
+ //
+
+ ULONG LookAhead;
+ ULONG Filter;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+
+ IF_LOUD( DbgPrint("In SetInfo\n");)
+
+
+
+ //
+ // Get Oid and Length of request
+ //
+
+ Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
+
+ OidLength = BytesLeft;
+
+ switch (Oid) {
+
+
+ case OID_802_3_MULTICAST_LIST:
+
+ //
+ // Verify length
+ //
+
+ if ((OidLength % ETH_LENGTH_OF_ADDRESS) != 0){
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ StatusToReturn = WdSetMulticastAddresses(
+ Adapter,
+ Open,
+ NdisRequest,
+ (UINT)(OidLength / ETH_LENGTH_OF_ADDRESS),
+ (PVOID)InfoBuffer
+ );
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4 ) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+ WD_MOVE_MEM(&Filter, InfoBuffer, 4);
+
+ //
+ // Verify bits
+ //
+
+ if (Filter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP
+ )) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ StatusToReturn = WdSetPacketFilter(Adapter,
+ Open,
+ NdisRequest,
+ Filter
+ );
+
+
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ WD_MOVE_MEM(&LookAhead, InfoBuffer, 4);
+
+ if (LookAhead <= (WD_MAX_LOOKAHEAD)) {
+
+ if (LookAhead > Adapter->MaxLookAhead) {
+
+ Adapter->MaxLookAhead = LookAhead;
+
+ Open->LookAhead = LookAhead;
+
+ } else {
+
+ if ((Open->LookAhead == Adapter->MaxLookAhead) &&
+ (LookAhead < Open->LookAhead)) {
+
+ Open->LookAhead = LookAhead;
+
+ WdAdjustMaxLookAhead(Adapter);
+
+ } else {
+
+ Open->LookAhead = LookAhead;
+
+ }
+
+ }
+
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ //
+ // Verify length
+ //
+
+ if (OidLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+ WD_MOVE_MEM(&Open->ProtOptionFlags, InfoBuffer, 4);
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ break;
+
+ }
+
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = BytesLeft;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ }
+
+
+ IF_LOUD( DbgPrint("Out SetInfo\n");)
+
+ return(StatusToReturn);
+}
+
+
+STATIC
+NDIS_STATUS
+WdSetPacketFilter(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT PacketFilter
+ )
+
+/*++
+
+Routine Description:
+
+ The WdSetPacketFilter request allows a protocol to control the types
+ of packets that it receives from the MAC.
+
+Arguments:
+
+ Adapter - A pointer to the adapter structure.
+
+ Open - A pointer to the open block giving the request.
+
+ NdisRequest - The NDIS_REQUEST with the set packet filter command in it.
+
+ PacketFilter - A bit mask that contains flags that correspond to specific
+ classes of received packets. If a particular bit is set in the mask,
+ then packet reception for that class of packet is enabled. If the
+ bit is clear, then packets that fall into that class are not received
+ by the client. A single exception to this rule is that if the promiscuous
+ bit is set, then the client receives all packets on the network, regardless
+ of the state of the other flags.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the filter change action routine is called.
+ //
+ NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("In SetFilter\n");)
+
+ if (!Open->Closing) {
+
+ //
+ // Increment the open while it is going through the filtering
+ // routines.
+ //
+
+ Open->ReferenceCount++;
+
+ StatusOfFilterChange = EthFilterAdjust(
+ Adapter->LMAdapter.FilterDB,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+
+ Open->ReferenceCount--;
+
+ } else {
+
+ StatusOfFilterChange = NDIS_STATUS_CLOSING;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Out SetFilter\n");)
+
+ return StatusOfFilterChange;
+}
+
+
+
+
+STATIC
+NDIS_STATUS
+WdSetMulticastAddresses(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest,
+ IN UINT NumAddresses,
+ IN CHAR AddressList[][ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ This function calls into the filter package in order to set the
+ multicast address list for the card to the specified list.
+
+Arguments:
+
+ Adapter - A pointer to the adapter block.
+
+ Open - A pointer to the open block submitting the request.
+
+ NdisRequest - The NDIS_REQUEST with the set multicast address list command
+ in it.
+
+ NumAddresses - A count of the number of addresses in the addressList.
+
+ AddressList - An array of multicast addresses that this open instance
+ wishes to accept.
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // Keeps track of the *MAC's* status. The status will only be
+ // reset if the filter change action routine is called.
+ //
+ NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
+
+ IF_LOUD( DbgPrint("In SetMulticast\n");)
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if (!Open->Closing) {
+
+ //
+ // Increment the open while it is going through the filtering
+ // routines.
+ //
+
+ Open->ReferenceCount++;
+
+ StatusOfFilterChange = EthChangeFilterAddresses(
+ Adapter->LMAdapter.FilterDB,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ NumAddresses,
+ AddressList,
+ TRUE
+ );
+ Open->ReferenceCount--;
+
+ } else {
+
+ StatusOfFilterChange = NDIS_STATUS_CLOSING;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Out SetMulticast\n");)
+
+ return StatusOfFilterChange;
+}
+
+
+
+NDIS_STATUS
+WdFillInGlobalData(
+ IN PWD_ADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a GlobalStatistics request. It is critical that
+ if information is needed from the Adapter->* fields, they have been
+ updated before this routine is called.
+
+Arguments:
+
+ Adapter - A pointer to the Adapter.
+
+ NdisRequest - A structure which contains the request type (Global
+ Query), an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ //
+ // General Algorithm:
+ //
+ // Switch(Request)
+ // Get requested information
+ // Store results in a common variable.
+ // default:
+ // Try protocol query information
+ // If that fails, fail query.
+ //
+ // Copy result in common variable to result buffer.
+ // Finish processing
+
+ UINT BytesWritten = 0;
+ UINT BytesNeeded = 0;
+ UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
+ PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // This variable holds result of query
+ //
+
+ ULONG GenericULong;
+
+ //
+ // Make sure that long is 4 bytes. Else GenericULong must change
+ // to something of size 4.
+ //
+ ASSERT(sizeof(ULONG) == 4);
+
+
+ StatusToReturn = WdQueryProtocolInformation(
+ Adapter,
+ NULL,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ TRUE,
+ InfoBuffer,
+ BytesLeft,
+ &BytesNeeded,
+ &BytesWritten
+ );
+
+
+ if (StatusToReturn == NDIS_STATUS_NOT_SUPPORTED) {
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Switch on request type
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
+
+ case OID_GEN_XMIT_OK:
+
+ GenericULong = (ULONG)(Adapter->FramesXmitGood);
+
+ break;
+
+ case OID_GEN_RCV_OK:
+
+ GenericULong = (ULONG)(Adapter->FramesRcvGood);
+
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+
+ GenericULong = (ULONG)(Adapter->FramesXmitBad);
+
+ break;
+
+ case OID_GEN_RCV_ERROR:
+
+ GenericULong = (ULONG)(Adapter->CrcErrors);
+
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+
+ GenericULong = (ULONG)(Adapter->MissedPackets);
+
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+
+ GenericULong = (ULONG)(Adapter->FrameAlignmentErrors);
+
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+
+ GenericULong = (ULONG)(Adapter->FramesXmitOneCollision);
+
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ GenericULong = (ULONG)(Adapter->FramesXmitManyCollisions);
+
+ break;
+
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+
+ }
+
+
+ //
+ // Check to make sure there is enough room in the
+ // buffer to store the result.
+ //
+
+ if (BytesLeft >= sizeof(ULONG)) {
+
+ //
+ // Store the result.
+ //
+
+ WD_MOVE_MEM(
+ (PVOID)InfoBuffer,
+ (PVOID)(&GenericULong),
+ sizeof(ULONG)
+ );
+
+ BytesWritten += sizeof(ULONG);
+
+ }
+
+ }
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;
+
+ NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;
+
+ return(StatusToReturn);
+}
+
+NDIS_STATUS
+WdQueryGlobalStatistics(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ The WdQueryGlobalStatistics is used by the protocol to query
+ global information about the MAC.
+
+Arguments:
+
+ MacAdapterContext - The value associated with the adapter that is being
+ opened when the MAC registered the adapter with NdisRegisterAdapter.
+
+ NdisRequest - A structure which contains the request type (Query),
+ an array of operations to perform, and an array for holding
+ the results of the operations.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+ //
+ // General Algorithm:
+ //
+ //
+ // Check if a request is going to pend...
+ // If so, pend the entire operation.
+ //
+ // Else
+ // Fill in the request block.
+ //
+ //
+
+ PWD_ADAPTER Adapter = (PWD_ADAPTER)(MacAdapterContext);
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Check if a request is valid and going to pend...
+ // If so, pend the entire operation.
+ //
+
+
+ //
+ // Switch on request type
+ //
+
+ switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
+ case OID_GEN_SUPPORTED_LIST:
+ case OID_GEN_HARDWARE_STATUS:
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_MAC_OPTIONS:
+ case OID_GEN_LINK_SPEED:
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ case OID_GEN_VENDOR_ID:
+ case OID_GEN_VENDOR_DESCRIPTION:
+ case OID_GEN_DRIVER_VERSION:
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ case OID_GEN_XMIT_OK:
+ case OID_GEN_RCV_OK:
+ case OID_GEN_XMIT_ERROR:
+ case OID_GEN_RCV_ERROR:
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+ case OID_GEN_RCV_NO_BUFFER:
+ case OID_802_3_MULTICAST_LIST:
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+ }
+
+ NdisInterlockedAddUlong(&Adapter->References, 1, &Adapter->Lock);
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ StatusToReturn = WdFillInGlobalData(Adapter, NdisRequest);
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ WD_DO_DEFERRED(Adapter);
+
+ return(StatusToReturn);
+}
+
+
+VOID
+WdRemoveAdapter(
+ IN PVOID MacAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ WdRemoveAdapter removes an adapter previously registered
+ with NdisRegisterAdapter.
+
+Arguments:
+
+ MacAdapterContext - The context value that the MAC passed
+ to NdisRegisterAdapter; actually as pointer to an
+ WD_ADAPTER.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PWD_ADAPTER Adapter;
+ BOOLEAN Canceled;
+
+ Adapter = PWD_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+
+ LM_Free_Resources(&Adapter->LMAdapter);
+
+ ASSERT(Adapter->OpenQueue == (PWD_OPEN)NULL);
+
+ //
+ // There are no opens left, so remove ourselves.
+ //
+
+ NdisCancelTimer(&Adapter->WakeUpTimer, &Canceled);
+
+ if ( !Canceled ) {
+ NdisStallExecution(500000);
+ }
+
+ //
+ // Take us out of the AdapterQueue.
+ //
+
+ NdisAcquireSpinLock(&WdMacBlock.SpinLock);
+
+ Adapter->Removed = TRUE;
+
+ if (WdMacBlock.AdapterQueue == Adapter) {
+
+ WdMacBlock.AdapterQueue = Adapter->NextAdapter;
+
+ } else {
+
+ PWD_ADAPTER TmpAdaptP = WdMacBlock.AdapterQueue;
+
+ while (TmpAdaptP->NextAdapter != Adapter) {
+
+ TmpAdaptP = TmpAdaptP->NextAdapter;
+
+ }
+
+ TmpAdaptP->NextAdapter = TmpAdaptP->NextAdapter->NextAdapter;
+ }
+
+ NdisReleaseSpinLock(&WdMacBlock.SpinLock);
+
+ NdisRemoveInterrupt(&(Adapter->LMAdapter.NdisInterrupt));
+
+ NdisUnmapIoSpace(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ Adapter->LMAdapter.ram_access,
+ Adapter->LMAdapter.ram_size * 1024);
+
+ EthDeleteFilter(Adapter->LMAdapter.FilterDB);
+
+ NdisDeregisterAdapter(Adapter->LMAdapter.NdisAdapterHandle);
+
+ NdisFreeSpinLock(&Adapter->Lock);
+
+ NdisFreeMemory(Adapter, sizeof(WD_ADAPTER), 0);
+
+ return;
+}
+
+VOID
+WdUnload(
+ IN NDIS_HANDLE MacMacContext
+ )
+
+/*++
+
+Routine Description:
+
+ WdUnload is called when the MAC is to unload itself.
+
+Arguments:
+
+ MacMacContext - actually a pointer to WdMacBlock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS InitStatus;
+
+ UNREFERENCED_PARAMETER(MacMacContext);
+
+ NdisDeregisterMac(
+ &InitStatus,
+ WdMacBlock.NdisMacHandle
+ );
+
+ NdisFreeSpinLock(&WdMacBlock.SpinLock);
+
+ NdisTerminateWrapper(
+ WdMacBlock.NdisWrapperHandle,
+ NULL
+ );
+
+ return;
+}
+
+NDIS_STATUS
+WdSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ NDIS function. Sends a packet on the wire
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PWD_OPEN Open = PWD_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+ PWD_ADAPTER Adapter = Open->Adapter;
+ PMAC_RESERVED Reserved = RESERVED(Packet);
+ UINT PacketLength;
+ NDIS_STATUS Status;
+
+
+ //
+ // Check that the packet is not too short or too long.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength);
+
+ if (PacketLength < (ETH_LENGTH_OF_ADDRESS*2) || PacketLength > 1514) {
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+
+
+
+ if (Adapter->HardwareFailure) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ }
+
+ if (Adapter->ResetInProgress) {
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+
+ }
+
+ //
+ // Ensure that the open won't close during this function.
+ //
+
+ if (Open->Closing) {
+
+ return NDIS_STATUS_CLOSING;
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOG(LOG('s'));
+
+ Open->ReferenceCount++;
+
+ Adapter->References++;
+
+ //
+ // Set up the MacReserved section of the packet.
+ //
+
+ Reserved->Open = Open;
+
+ Reserved->NextPacket = (PNDIS_PACKET)NULL;
+
+
+
+
+ //
+ // Set Reserved->Loopback
+ //
+
+ WdSetLoopbackFlag(Adapter, Open, Packet);
+
+
+
+
+ IF_LOUD( DbgPrint("Sending a packet for Open 0x%lx\n", Reserved->Open);)
+
+
+ //
+ // We do not Open->ReferenceCount-- because that will be done when
+ // then send completes.
+ //
+
+
+ if (Reserved->Directed) {
+
+ //
+ // Put it directly on loopback queue.
+ //
+
+ IF_VERY_LOUD( DbgPrint("Putting Packet 0x%lx on Loopback queue\n",Packet);)
+
+ IF_LOG(LOG('l'));
+
+ if (Adapter->LoopbackQueue == NULL) {
+
+ Adapter->LoopbackQueue = Adapter->LoopbackQTail = Packet;
+
+ } else {
+
+ RESERVED(Adapter->LoopbackQTail)->NextPacket = Packet;
+
+ Adapter->LoopbackQTail = Packet;
+
+ }
+
+ Status = NDIS_STATUS_PENDING;
+
+ } else {
+
+ //
+ // Put Packet on queue to hit the wire.
+ //
+
+ if (Adapter->XmitQueue != NULL) {
+
+ IF_LOG(LOG('q'));
+
+ RESERVED(Adapter->XmitQTail)->NextPacket = Packet;
+
+ Adapter->XmitQTail = Packet;
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ } else {
+
+ PNDIS_PACKET PreviousTail;
+
+ //
+ // We have to assume it will be sent. In case the send completes
+ // before we have time to add it.
+ //
+
+ ASSERT(Packet != NULL);
+
+ if (Adapter->PacketsOnCard == NULL) {
+
+ PreviousTail = NULL;
+
+ Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = Packet;
+
+ } else {
+
+ PreviousTail = Adapter->PacketsOnCardTail;
+
+ RESERVED(Adapter->PacketsOnCardTail)->NextPacket = Packet;
+
+ Adapter->PacketsOnCardTail = Packet;
+
+ }
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ IF_LOG(LOG('t'));
+
+ if (LM_Send(Packet, &Adapter->LMAdapter) == OUT_OF_RESOURCES) {
+
+ IF_LOG(LOG('Q'));
+
+ ASSERT(Packet != NULL);
+
+ //
+ // Remove it from list of packets on card and add it to xmit
+ // queue.
+ //
+
+ if (PreviousTail == NULL) {
+
+ Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = NULL;
+
+ } else {
+
+ Adapter->PacketsOnCardTail = PreviousTail;
+
+ RESERVED(Adapter->PacketsOnCardTail)->NextPacket = NULL;
+
+ ASSERT(Adapter->PacketsOnCard != NULL);
+
+ }
+
+ Adapter->XmitQueue = Packet;
+
+ Adapter->XmitQTail = Packet;
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ }
+
+ }
+
+ Status = NDIS_STATUS_PENDING;
+
+ }
+
+
+ WD_DO_DEFERRED(Adapter);
+
+ IF_LOG(LOG('S'));
+
+ return Status;
+
+}
+
+UINT
+WdCompareMemory(
+ IN PUCHAR String1,
+ IN PUCHAR String2,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Determines if two arrays of bytes are equal.
+
+Arguments:
+
+ String1, String2 - the two arrays to check.
+
+ Length - the first length bytes to compare.
+
+Return Value:
+
+ 0 if equal, -1 if not.
+
+--*/
+{
+ UINT i;
+
+ for (i=0; i<Length; i++) {
+ if (String1[i] != String2[i]) {
+ return (UINT)(-1);
+ }
+ }
+ return 0;
+}
+
+VOID
+WdSetLoopbackFlag(
+ IN PWD_ADAPTER Adapter,
+ IN PWD_OPEN Open,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the loopback flag in the reserved section of the packet
+ to indicate if it should be looped back.
+
+Arguments:
+
+ Packet - the packet to check.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMAC_RESERVED Reserved = RESERVED(Packet);
+ UCHAR AddrBuf[ETH_LENGTH_OF_ADDRESS];
+ UINT Filter;
+
+
+ Reserved->Directed = FALSE;
+ Reserved->Loopback = FALSE;
+
+ //
+ // Check the destination address to see which filter to use.
+ //
+
+ WdCopyOver(AddrBuf, Packet, 0, ETH_LENGTH_OF_ADDRESS);
+
+ Filter = ETH_QUERY_FILTER_CLASSES(Adapter->LMAdapter.FilterDB);
+
+ if (WdAddressEqual(Adapter->LMAdapter.node_address, AddrBuf)) {
+
+ //
+ // Packet directed to this adapter.
+ //
+
+ Reserved->Directed = (BOOLEAN)(Filter & NDIS_PACKET_TYPE_DIRECTED);
+
+ }
+
+ if (Open->ProtOptionFlags & NDIS_PROT_OPTION_NO_LOOPBACK) {
+
+ Reserved->Loopback = FALSE;
+
+ } else if (Filter & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ //
+ // Somebody is promiscuous, everything is looped back.
+ //
+
+ Reserved->Loopback = TRUE;
+
+ } else {
+
+ if (WdAddressEqual(WdBroadcastAddress, AddrBuf)) {
+
+ //
+ // Broadcast packet.
+ //
+
+ Reserved->Loopback = (BOOLEAN)(Filter & NDIS_PACKET_TYPE_BROADCAST);
+
+ } else if ((AddrBuf[0] & 1) != 0) {
+
+ //
+ // Multicast packet.
+ //
+
+ Reserved->Loopback = (BOOLEAN)(Filter &
+ (NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST));
+
+ } else if (Reserved->Directed) {
+
+ Reserved->Loopback = TRUE;
+
+ } else {
+
+ //
+ // Packet directed to another adapter.
+ //
+
+ Reserved->Loopback = FALSE;
+ }
+
+ }
+
+}
+
+
+NDIS_STATUS
+WdReset(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ See NDIS 3.0 spec.
+
+--*/
+
+{
+ PWD_OPEN Open = ((PWD_OPEN)MacBindingHandle);
+ PWD_ADAPTER Adapter = Open->Adapter;
+
+
+ if (Open->Closing) {
+
+ return(NDIS_STATUS_CLOSING);
+
+ }
+
+ if (Adapter->ResetRequested) {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("In WdReset\n");)
+
+ IF_LOG(LOG('r'));
+
+ //
+ // Ensure that the open does not close while in this function.
+ //
+
+ Open->ReferenceCount++;
+
+ Adapter->References++;
+
+
+ Adapter->ResetRequested = TRUE;
+
+ //
+ // Needed in case the reset pends somewhere along the line.
+ //
+
+ Adapter->ResetOpen = Open;
+
+ WD_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("Out WdReset\n");)
+
+ return(NDIS_STATUS_PENDING);
+
+}
+
+STATIC
+NDIS_STATUS
+WdChangeMulticastAddresses(
+ IN UINT OldFilterCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewFilterCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+
+ OldFilterCount - The number of addresses that used to be on the card.
+
+ OldAddresses - A list of all the addresses that used to be on the card.
+
+ NewFilterCount - The number of addresses that should now be on the card.
+
+ NewAddresses - A list of addresses that should be put on the card.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to WD_OPEN.
+
+ NdisRequest - The request which submitted the filter change.
+ Must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+
+ PWD_ADAPTER Adapter = PWD_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ UNREFERENCED_PARAMETER(Set);
+ UNREFERENCED_PARAMETER(NdisRequest);
+ UNREFERENCED_PARAMETER(OldAddresses);
+ UNREFERENCED_PARAMETER(OldFilterCount);
+
+ if (LM_Set_Multi_Address(NewAddresses, NewFilterCount, &Adapter->LMAdapter)
+ != SUCCESS) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ } else {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+}
+
+STATIC
+NDIS_STATUS
+WdChangeFilterClasses(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when an address is added to
+ the filter that wasn't referenced by any other open binding.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFilterClasses - A bit mask that is currently on the card telling
+ which packet types to accept.
+
+ NewFilterClasses - A bit mask that should be put on the card telling
+ which packet types to accept.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to WD_OPEN.
+
+ NdisRequest - The NDIS_REQUEST which submitted the filter change command.
+
+ Set - A flag telling if the command is a result of a close or not.
+
+Return Value:
+
+ Status of the change (successful or pending).
+
+
+--*/
+
+{
+
+ PWD_ADAPTER Adapter = PWD_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ UNREFERENCED_PARAMETER(Set);
+ UNREFERENCED_PARAMETER(OldFilterClasses);
+ UNREFERENCED_PARAMETER(NewFilterClasses);
+ UNREFERENCED_PARAMETER(NdisRequest);
+
+
+ if (LM_Set_Receive_Mask(&(Adapter->LMAdapter)) != SUCCESS) {
+
+ return(NDIS_STATUS_FAILURE);
+
+ } else {
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+}
+
+STATIC
+VOID
+WdCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular binding
+ was closed while it was indicating through NdisIndicateReceive
+
+ All this routine needs to do is to decrement the reference count
+ of the binding.
+
+ NOTE: This routine assumes that it is called with the lock acquired.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to WD_OPEN.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+ PWD_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->ReferenceCount--;
+
+}
+
+BOOLEAN
+WdInterruptHandler(
+ IN PVOID ServiceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt handler which is registered with the operating
+ system. Only one interrupt is handled at one time, even if several
+ are pending (i.e. transmit complete and receive).
+
+Arguments:
+
+ ServiceContext - pointer to the adapter object
+
+Return Value:
+
+ TRUE, if the DPC is to be executed, otherwise FALSE.
+
+--*/
+
+{
+ PWD_ADAPTER Adapter = ((PWD_ADAPTER)ServiceContext);
+
+ IF_LOUD( DbgPrint("In WdISR\n");)
+
+ IF_LOG(LOG('i'));
+
+ //
+ // Force the INT signal from the chip low. When the
+ // interrupt is acknowledged interrupts will be unblocked,
+ // which will cause a rising edge on the interrupt line
+ // if there is another interrupt pending on the card.
+ //
+
+ IF_LOUD( DbgPrint( " blocking interrupts\n" );)
+
+ LM_Disable_Adapter(&Adapter->LMAdapter);
+
+ IF_LOG(LOG('I'));
+
+ return(TRUE);
+
+}
+
+VOID
+WdInterruptDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ This is the deffered processing routine for interrupts, it examines the
+ global 'InterruptReg' to determine what deffered processing is necessary
+ and dispatches control to the Rcv and Xmt handlers.
+
+Arguments:
+ SystemSpecific1, SystemSpecific2, SystemSpecific3 - not used
+ InterruptContext - a handle to the adapter block.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+ PWD_ADAPTER Adapter = ((PWD_ADAPTER)InterruptContext);
+ BOOLEAN RequeueRcv = FALSE;
+
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ IF_LOG(LOG('d'));
+
+
+ IF_LOUD( DbgPrint("==>IntDpc\n");)
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ if ( Adapter->ProcessingDpc ) {
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ return;
+ }
+
+ Adapter->ProcessingDpc = TRUE;
+ Adapter->References++;
+
+ do {
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ RequeueRcv = WdReceiveEvents(Adapter);
+
+ WdTransmitEvents(Adapter);
+
+ //
+ // This causes any transmit that may have caused a tranmitted packet
+ // to loopback and indicate the packet.
+ //
+
+ } while ( Adapter->LoopbackQueue != (PNDIS_PACKET) NULL || RequeueRcv );
+
+ //
+ // We're done with this DPC.
+ //
+
+ Adapter->ProcessingDpc = FALSE;
+
+ //
+ // Reenable interrupts
+ //
+
+ Adapter->LMAdapter.InterruptMask = PACKET_RECEIVE_ENABLE |
+ PACKET_TRANSMIT_ENABLE |
+ RECEIVE_ERROR_ENABLE |
+ TRANSMIT_ERROR_ENABLE |
+ OVERWRITE_WARNING_ENABLE |
+ COUNTER_OVERFLOW_ENABLE;
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapter->LMAdapter.NdisInterrupt),
+ LM_Enable_Adapter,
+ &Adapter->LMAdapter
+ );
+
+ WD_DO_DEFERRED(Adapter);
+
+ IF_LOUD( DbgPrint("<==IntDpc\n");)
+
+ IF_LOG(LOG('D'));
+
+}
+
+
+VOID
+WdIndicateLoopbackPacket(
+ IN PWD_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine indicates a packet to the current host.
+
+ NOTE: THIS ROUTINE MUST BE CALLED WITH THE SPINLOCK HELD.
+
+Arguments:
+
+ Adapter - Pointer to the adapter structure.
+
+ Packet - Pointer to the packet to indicate.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+ UINT IndicateLen;
+ UINT PacketLen;
+
+ //
+ // Store that we are indicating a loopback packet
+ //
+
+ Adapter->IndicatingPacket = Packet;
+ Adapter->IndicatedAPacket = TRUE;
+
+ //
+ // Indicate packet.
+ //
+
+ IF_LOUD( DbgPrint("Indicating loopback packet\n");)
+
+ //
+ // Indicate up to 252 bytes.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLen);
+
+ if (PacketLen >= ETH_LENGTH_OF_ADDRESS) {
+
+ IndicateLen = (PacketLen > (Adapter->MaxLookAhead + WD_HEADER_SIZE) ?
+ (Adapter->MaxLookAhead + WD_HEADER_SIZE) :
+ PacketLen
+ );
+
+ //
+ // Copy the lookahead data into a contiguous buffer.
+ //
+
+ WdCopyOver(Adapter->LookAhead,
+ Packet,
+ 0,
+ IndicateLen
+ );
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+
+ //
+ // Indicate packet
+ //
+
+ if (PacketLen < WD_HEADER_SIZE) {
+
+ //
+ // Runt packet
+ //
+
+ EthFilterIndicateReceive(
+ Adapter->LMAdapter.FilterDB,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)Adapter->LookAhead,
+ Adapter->LookAhead,
+ PacketLen,
+ NULL,
+ 0,
+ 0
+ );
+
+ } else {
+
+ EthFilterIndicateReceive(
+ Adapter->LMAdapter.FilterDB,
+ (NDIS_HANDLE)Adapter,
+ (PCHAR)Adapter->LookAhead,
+ Adapter->LookAhead,
+ WD_HEADER_SIZE,
+ Adapter->LookAhead + WD_HEADER_SIZE,
+ IndicateLen - WD_HEADER_SIZE,
+ PacketLen - WD_HEADER_SIZE
+ );
+
+ }
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+}
+
+
+BOOLEAN
+WdReceiveEvents(
+ IN PWD_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine handles all Receive deferred processing, this includes any
+ packets that never went through the XmitQueue and need to be indicated
+ (Loopbacked), and all card events.
+
+ NOTE: THIS ROUTINE MUST BE CALLED WITH THE SPINLOCK HELD.
+
+ NOTE: The Adapter->ProcessingReceiveEvents MUST be set upon entry and
+ with the spinlock held.
+
+Arguments:
+
+ Context - a handle to the adapter block.
+
+Return Value:
+
+ Do we need to requeue this Rcv.
+
+--*/
+{
+ PNDIS_PACKET Packet;
+ PWD_OPEN TmpOpen;
+ NDIS_STATUS Status;
+ BOOLEAN RequeueRcv;
+
+ IF_LOG(LOG('e'));
+
+ RequeueRcv = (BOOLEAN)(LM_Service_Receive_Events(&Adapter->LMAdapter) ==
+ REQUEUE_LATER);
+
+ while (Adapter->LoopbackQueue != NULL) {
+
+ //
+ // Take packet off queue.
+ //
+
+ Packet = Adapter->LoopbackQueue;
+
+ if (Packet == Adapter->LoopbackQTail) {
+
+ Adapter->LoopbackQTail = NULL;
+
+ }
+
+ Adapter->LoopbackQueue = RESERVED(Packet)->NextPacket;
+
+ //
+ // Indicate the packet
+ //
+
+ WdIndicateLoopbackPacket(Adapter,Packet);
+
+
+ //
+ // Complete the packet send.
+ //
+
+ Adapter->FramesXmitGood++;
+
+ //
+ // Save this, since once we complete the send
+ // Reserved is no longer valid.
+ //
+
+ TmpOpen = RESERVED(Packet)->Open;
+
+ IF_VERY_LOUD( DbgPrint("Completing send for packet 0x%x\n",Packet);)
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(TmpOpen->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(TmpOpen);
+
+ }
+
+ //
+ // If any indications done, then
+ //
+ // CompleteIndications();
+ //
+
+ if (Adapter->IndicatedAPacket) {
+
+ Adapter->IndicatedAPacket = FALSE;
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ EthFilterIndicateReceiveComplete(Adapter->LMAdapter.FilterDB);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+ if ((Adapter->ResetRequested) && (Adapter->References == 1)) {
+
+ PNDIS_PACKET Packet;
+ PWD_OPEN TmpOpen;
+
+ IF_LOG(LOG('R'));
+ IF_VERY_LOUD( DbgPrint("Starting Reset\n");)
+
+ Adapter->ResetInProgress = TRUE;
+
+ NdisSynchronizeWithInterrupt(
+ &(Adapter->LMAdapter.NdisInterrupt),
+ LM_Disable_Adapter,
+ &Adapter->LMAdapter
+ );
+
+ //
+ // Indicate Status to all opens
+ //
+
+ IF_VERY_LOUD( DbgPrint("Indicating status\n");)
+
+ TmpOpen = Adapter->OpenQueue;
+
+ while (TmpOpen != (PWD_OPEN)NULL) {
+
+ AddRefWhileHoldingSpinLock(Adapter, TmpOpen);
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisIndicateStatus(TmpOpen->NdisBindingContext,
+ NDIS_STATUS_RESET_START,
+ NULL,
+ 0
+ );
+
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(TmpOpen);
+
+ TmpOpen = TmpOpen->NextOpen;
+
+ }
+
+ //
+ // Reset the Card.
+ //
+
+ IF_VERY_LOUD( DbgPrint("Resetting the card\n");)
+
+ if (LM_Initialize_Adapter(&Adapter->LMAdapter) != SUCCESS) {
+
+ Adapter->HardwareFailure = TRUE;
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ } else {
+
+ Adapter->HardwareFailure = FALSE;
+
+ }
+
+
+
+ //
+ // Put packets that were on the card on to the front of the xmit
+ // queue.
+ //
+
+ if (Adapter->PacketsOnCard != NULL) {
+
+ IF_VERY_LOUD( DbgPrint("Moving Packets On card\n");)
+
+ RESERVED(Adapter->PacketsOnCardTail)->NextPacket = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = Adapter->PacketsOnCard;
+
+ Adapter->PacketsOnCard = Adapter->PacketsOnCardTail = NULL;
+
+ }
+
+
+ //
+ // Put packets on loopback queue on xmit queue
+ //
+
+ if (Adapter->LoopbackQueue != NULL) {
+
+ RESERVED(Adapter->LoopbackQTail)->NextPacket = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = Adapter->LoopbackQueue;
+
+ }
+
+
+ //
+ // Wipe out loopback queue.
+ //
+
+ Adapter->LoopbackQueue = Adapter->LoopbackQTail = (PNDIS_PACKET)NULL;
+
+
+ //
+ // Abort all xmits
+ //
+
+ IF_VERY_LOUD( DbgPrint("Killing Xmits\n");)
+
+ while (Adapter->XmitQueue != NULL) {
+
+ Packet = Adapter->XmitQueue;
+
+ Adapter->XmitQueue = RESERVED(Packet)->NextPacket;
+
+ TmpOpen = RESERVED(Packet)->Open;
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(TmpOpen->NdisBindingContext,
+ Packet,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(TmpOpen);
+
+ }
+
+ Adapter->XmitQTail = NULL;
+
+ if (!Adapter->HardwareFailure) {
+
+ LM_Open_Adapter(&Adapter->LMAdapter);
+
+ }
+
+ Adapter->ResetInProgress = FALSE;
+
+ IF_VERY_LOUD( DbgPrint("Indicating Done\n");)
+
+ //
+ // Indicate Reset is done
+ //
+
+ //
+ // Indicate Status to all opens
+ //
+
+ IF_VERY_LOUD( DbgPrint("Indicating status\n");)
+
+ TmpOpen = Adapter->OpenQueue;
+
+ while (TmpOpen != (PWD_OPEN)NULL) {
+
+ AddRefWhileHoldingSpinLock(Adapter, TmpOpen);
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ if (Adapter->HardwareFailure) {
+
+ NdisIndicateStatus(TmpOpen->NdisBindingContext,
+ NDIS_STATUS_CLOSED,
+ NULL,
+ 0
+ );
+
+ }
+
+ Status = (Adapter->HardwareFailure) ?
+ NDIS_STATUS_FAILURE :
+ NDIS_STATUS_SUCCESS;
+
+
+ NdisIndicateStatus(TmpOpen->NdisBindingContext,
+ NDIS_STATUS_RESET_END,
+ &Status,
+ sizeof(Status)
+ );
+
+ NdisIndicateStatusComplete(TmpOpen->NdisBindingContext);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(TmpOpen);
+
+ TmpOpen = TmpOpen->NextOpen;
+
+ }
+
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteReset(Adapter->ResetOpen->NdisBindingContext,
+ (Adapter->HardwareFailure) ?
+ NDIS_STATUS_FAILURE :
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+
+ WdRemoveReference(Adapter->ResetOpen);
+
+ //
+ // Reset the flag
+ //
+
+
+ IF_VERY_LOUD( DbgPrint("Restarting Adapter\n");)
+
+ Adapter->ResetRequested = FALSE;
+
+ LM_Open_Adapter(&Adapter->LMAdapter);
+
+ }
+
+#if DBG
+
+ else if (Adapter->ResetRequested) {
+
+ IF_LOUD( DbgPrint("No reset because count is... 0x%x\n", Adapter->References);)
+
+ }
+
+#endif
+
+ IF_LOG(LOG('E'));
+
+ return RequeueRcv;
+}
+
+
+VOID
+WdTransmitEvents(
+ IN PWD_ADAPTER Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine handles all transmit deferred processing.
+
+ NOTE : Called with lock held!!
+
+Arguments:
+
+ Adapter - pointer to the adapter structure.
+
+Return Value:
+
+ NONE.
+
+--*/
+{
+
+ if (Adapter->ResetInProgress) {
+
+ return;
+
+ }
+
+ IF_LOG(LOG('w'));
+
+ LM_Service_Transmit_Events(&Adapter->LMAdapter);
+
+ IF_LOG(LOG('W'));
+
+}
+
+UINT
+WdCopyOver(
+ OUT PUCHAR Buf, // destination
+ IN PNDIS_PACKET Packet, // source packet
+ IN UINT Offset, // offset in packet
+ IN UINT Length // number of bytes to copy
+ )
+
+/*++
+
+Routine Description:
+
+ Copies bytes from a packet into a buffer. Used to copy data
+ out of a packet during loopback indications.
+
+Arguments:
+
+ Buf - the destination buffer
+ Packet - the source packet
+ Offset - the offset in the packet to start copying at
+ Length - the number of bytes to copy
+
+Return Value:
+
+ The actual number of bytes copied; will be less than Length if
+ the packet length is less than Offset+Length.
+
+--*/
+
+{
+ PNDIS_BUFFER CurBuffer;
+ UINT BytesCopied;
+ PUCHAR BufVA;
+ UINT BufLen;
+ UINT ToCopy;
+ UINT CurOffset;
+
+
+ BytesCopied = 0;
+
+ //
+ // First find a spot Offset bytes into the packet.
+ //
+
+ CurOffset = 0;
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
+
+ while (CurBuffer != (PNDIS_BUFFER)NULL) {
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufVA, &BufLen);
+
+ if (CurOffset + BufLen > Offset) {
+
+ break;
+
+ }
+
+ CurOffset += BufLen;
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ }
+
+
+ //
+ // See if the end of the packet has already been passed.
+ //
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ return 0;
+
+ }
+
+
+ //
+ // Now copy over Length bytes.
+ //
+
+ BufVA += (Offset - CurOffset);
+
+ BufLen -= (Offset - CurOffset);
+
+ for (;;) {
+
+ ToCopy = (BytesCopied+BufLen > Length) ? Length - BytesCopied : BufLen;
+
+ WD_MOVE_MEM(Buf+BytesCopied, BufVA, ToCopy);
+
+ BytesCopied += ToCopy;
+
+
+ if (BytesCopied == Length) {
+
+ return BytesCopied;
+
+ }
+
+ NdisGetNextBuffer(CurBuffer, &CurBuffer);
+
+ if (CurBuffer == (PNDIS_BUFFER)NULL) {
+
+ break;
+
+ }
+
+ NdisQueryBuffer(CurBuffer, (PVOID *)&BufVA, &BufLen);
+
+ }
+
+ return BytesCopied;
+
+}
+
+
+
+NDIS_STATUS
+WdTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ NDIS function.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ - The MacReceiveContext will be a pointer to the open block for
+ the packet.
+ - The LoopbackPacket field in the adapter block will be NULL if this
+ is a call for a normal packet, otherwise it will be set to point
+ to the loopback packet.
+
+--*/
+{
+ PWD_OPEN Open = PWD_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+ PWD_ADAPTER Adapter = Open->Adapter;
+ PNDIS_BUFFER CurrentBuffer;
+ PUCHAR BufferVA;
+ UINT BufferLength, Copied;
+ UINT CurrentOffset;
+
+ UNREFERENCED_PARAMETER(MacReceiveContext);
+
+ ByteOffset += WD_HEADER_SIZE;
+
+ if (Adapter->IndicatingPacket != NULL) {
+
+ IF_LOUD( DbgPrint("Transferring data for loopback packet\n");)
+
+ //
+ // It is a loopback packet
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &CurrentBuffer, NULL);
+
+ CurrentOffset = ByteOffset;
+
+ while (CurrentBuffer != (PNDIS_BUFFER)NULL) {
+
+ NdisQueryBuffer(CurrentBuffer, (PVOID *)&BufferVA, &BufferLength);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Copied =
+ WdCopyOver(BufferVA,
+ Adapter->IndicatingPacket,
+ CurrentOffset,
+ BufferLength
+ );
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ CurrentOffset += Copied;
+
+ if (Copied < BufferLength) {
+
+ break;
+
+ }
+
+ NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
+
+ }
+
+ //
+ // We are done, return.
+ //
+
+ *BytesTransferred = CurrentOffset - ByteOffset;
+
+ if ( *BytesTransferred > BytesToTransfer ) {
+
+ *BytesTransferred = BytesToTransfer;
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+
+ } else if (Adapter->IndicatedAPacket) {
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ IF_LOUD( DbgPrint("Transferring data for card packet\n");)
+
+ if (LM_Receive_Copy(
+ BytesTransferred,
+ BytesToTransfer,
+ ByteOffset,
+ Packet,
+ &(Adapter->LMAdapter)) != SUCCESS) {
+
+ //
+ // Copy failed.
+ //
+
+ *BytesTransferred = 0;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return(NDIS_STATUS_FAILURE);
+
+ } else {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return(NDIS_STATUS_SUCCESS);
+
+ }
+
+ } else {
+
+ return(NDIS_STATUS_NOT_INDICATING);
+
+ }
+
+}
+
+BOOLEAN
+WdSyncCloseAdapter(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to synchronize with the lower MAC layer close
+ calls that may access the same areas of the LM that are accessed in
+ the ISR.
+
+Arguments:
+
+ see NDIS 3.0 spec.
+
+Notes:
+
+ returns TRUE on success, else FALSE.
+
+--*/
+{
+
+ if (LM_Close_Adapter((Ptr_Adapter_Struc)Context) == SUCCESS) {
+
+ return(TRUE);
+
+ } else {
+
+ return(FALSE);
+
+ }
+
+}
+
+
+VOID
+WdWakeUpDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ This DPC routine is queued every 5 seconds to check on the
+ queues. If an interrupt was not received
+ in the last 5 seconds and there should have been one,
+ then we abort all operations.
+
+Arguments:
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PWD_ADAPTER Adapter = (PWD_ADAPTER)Context;
+ PWD_OPEN TmpOpen;
+ PNDIS_PACKET TransmitPacket;
+ PMAC_RESERVED Reserved;
+
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ if ((Adapter->WakeUpTimeout) &&
+ Adapter->LMAdapter.TransmitInterruptPending) {
+
+ //
+ // We had a pending operation the last time we ran,
+ // and it has not been completed...we need to complete
+ // it now.
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ Adapter->HardwareFailure = TRUE;
+
+ //
+ // Disable adapter
+ //
+ IF_LOG(LOG('*'));
+ LM_Disable_Adapter(&Adapter->LMAdapter);
+
+ if (Adapter->WakeUpErrorCount < 10) {
+
+ Adapter->WakeUpErrorCount++;
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ }
+
+ while (Adapter->PacketsOnCard != NULL) {
+
+ TransmitPacket = Adapter->PacketsOnCard;
+
+ Reserved = RESERVED(TransmitPacket);
+
+ Adapter->PacketsOnCard = Reserved->NextPacket;
+
+ if (Adapter->PacketsOnCard == NULL) {
+
+ Adapter->PacketsOnCardTail = NULL;
+
+ }
+
+ TmpOpen = Reserved->Open;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ TmpOpen->NdisBindingContext,
+ TransmitPacket,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ TmpOpen->ReferenceCount--;
+
+ }
+
+ while (Adapter->XmitQueue != NULL) {
+
+ TransmitPacket = Adapter->XmitQueue;
+
+ Reserved = RESERVED(TransmitPacket);
+
+ //
+ // Remove the packet from the queue.
+ //
+
+ Adapter->XmitQueue = Reserved->NextPacket;
+
+ if (Adapter->XmitQueue == NULL) {
+
+ Adapter->XmitQTail = NULL;
+
+ }
+
+ TmpOpen = Reserved->Open;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ TmpOpen->NdisBindingContext,
+ TransmitPacket,
+ NDIS_STATUS_SUCCESS
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ TmpOpen->ReferenceCount--;
+
+ }
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ Adapter->LMAdapter.TransmitInterruptPending = FALSE;
+
+ //
+ // reinitialize the card
+ //
+
+ if (LM_Initialize_Adapter(&Adapter->LMAdapter) != SUCCESS) {
+
+ Adapter->HardwareFailure = TRUE;
+
+ NdisWriteErrorLogEntry(
+ Adapter->LMAdapter.NdisAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 0
+ );
+
+ } else {
+
+ Adapter->HardwareFailure = FALSE;
+
+ }
+
+ //
+ // reenable interrupts
+ //
+
+ LM_Enable_Adapter(&Adapter->LMAdapter);
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ } else {
+
+ if ((Adapter->PacketsOnCard != NULL) ||
+ (Adapter->XmitQueue != NULL)) {
+
+ Adapter->WakeUpTimeout = TRUE;
+
+ }
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+
+ }
+
+ //
+ // Fire off another Dpc to execute after 5 seconds
+ //
+
+ NdisSetTimer(
+ &Adapter->WakeUpTimer,
+ 5000
+ );
+
+}