https://git.reactos.org/?p=reactos.git;a=commitdiff;h=59d8a77df6a7245654bdd…
commit 59d8a77df6a7245654bdd4f31ebc5825282411bf
Author: Dmitry Borisov <di.sean(a)protonmail.com>
AuthorDate: Wed Oct 18 23:12:36 2023 +0600
Commit: GitHub <noreply(a)github.com>
CommitDate: Wed Oct 18 20:12:36 2023 +0300
[DC21X4] Add driver for DECchip 21x4-compatible network adapters (#5614)
These adapters were common in DEC Alpha boxes and they are really rare
nowadays. The 21140 chip is emulated in Connectix / Microsoft Virtual PC
and Hyper-V Gen 1 VM.
This is an experimental driver, not yet tested on real hardware.
CORE-8724
---
boot/bootdata/packages/reactos.dff.in | 2 -
drivers/network/dd/CMakeLists.txt | 1 +
drivers/network/dd/dc21x4/CMakeLists.txt | 40 +
drivers/network/dd/dc21x4/dc21x4.c | 401 ++++++++
drivers/network/dd/dc21x4/dc21x4.h | 541 +++++++++++
drivers/network/dd/dc21x4/dc21x4.rc | 5 +
drivers/network/dd/dc21x4/dc21x4hw.h | 597 ++++++++++++
drivers/network/dd/dc21x4/debug.c | 70 ++
drivers/network/dd/dc21x4/debug.h | 96 ++
drivers/network/dd/dc21x4/eeprom.c | 1525 ++++++++++++++++++++++++++++++
drivers/network/dd/dc21x4/eeprom.h | 108 +++
drivers/network/dd/dc21x4/eeprom_data.c | 219 +++++
drivers/network/dd/dc21x4/hardware.c | 585 ++++++++++++
drivers/network/dd/dc21x4/init.c | 1321 ++++++++++++++++++++++++++
drivers/network/dd/dc21x4/interrupt.c | 625 ++++++++++++
drivers/network/dd/dc21x4/media.c | 634 +++++++++++++
drivers/network/dd/dc21x4/media.h | 127 +++
drivers/network/dd/dc21x4/media040.c | 143 +++
drivers/network/dd/dc21x4/media041.c | 222 +++++
drivers/network/dd/dc21x4/media140.c | 136 +++
drivers/network/dd/dc21x4/media143.c | 510 ++++++++++
drivers/network/dd/dc21x4/net21x4.inf | 158 ++++
drivers/network/dd/dc21x4/phy.c | 263 ++++++
drivers/network/dd/dc21x4/power.c | 252 +++++
drivers/network/dd/dc21x4/requests.c | 660 +++++++++++++
drivers/network/dd/dc21x4/send.c | 313 ++++++
drivers/network/dd/dc21x4/sendrcv.h | 115 +++
drivers/network/dd/dc21x4/util.h | 84 ++
28 files changed, 9751 insertions(+), 2 deletions(-)
diff --git a/boot/bootdata/packages/reactos.dff.in
b/boot/bootdata/packages/reactos.dff.in
index dbf0737ff83..04ad4dc83a0 100644
--- a/boot/bootdata/packages/reactos.dff.in
+++ b/boot/bootdata/packages/reactos.dff.in
@@ -138,8 +138,6 @@ Signature = "$Windows NT$"
"modules/optional/bcmwl5.sys" 3 optional
"modules/optional/alcxwdm.inf" 6 optional
"modules/optional/alcxwdm.sys" 3 optional
-"modules/optional/net21x4.inf" 6 optional
-"modules/optional/dc21x4.sys" 3 optional
"modules/optional/mfc42.dll" 2 optional
"modules/optional/mfc42u.dll" 2 optional
"modules/optional/mfc71.dll" 2 optional
diff --git a/drivers/network/dd/CMakeLists.txt b/drivers/network/dd/CMakeLists.txt
index f8b967412a3..122b82823f7 100644
--- a/drivers/network/dd/CMakeLists.txt
+++ b/drivers/network/dd/CMakeLists.txt
@@ -1,4 +1,5 @@
+add_subdirectory(dc21x4)
add_subdirectory(e1000)
add_subdirectory(ne2000)
add_subdirectory(netkvm)
diff --git a/drivers/network/dd/dc21x4/CMakeLists.txt
b/drivers/network/dd/dc21x4/CMakeLists.txt
new file mode 100644
index 00000000000..74f6927076f
--- /dev/null
+++ b/drivers/network/dd/dc21x4/CMakeLists.txt
@@ -0,0 +1,40 @@
+
+add_definitions(
+ -DNDIS_MINIPORT_DRIVER
+ -DNDIS51_MINIPORT=1)
+
+list(APPEND SOURCE
+ dc21x4.c
+ dc21x4.h
+ dc21x4hw.h
+ debug.h
+ eeprom.c
+ eeprom.h
+ eeprom_data.c
+ hardware.c
+ init.c
+ interrupt.c
+ media.c
+ media040.c
+ media041.c
+ media140.c
+ media143.c
+ phy.c
+ power.c
+ requests.c
+ send.c
+ util.h)
+
+if(DBG)
+ list(APPEND SOURCE debug.c)
+endif()
+
+add_library(dc21x4 MODULE ${SOURCE} dc21x4.rc)
+if(DBG)
+ target_link_libraries(dc21x4 memcmp)
+endif()
+add_pch(dc21x4 dc21x4.h SOURCE)
+set_module_type(dc21x4 kernelmodedriver)
+add_importlibs(dc21x4 ndis ntoskrnl hal)
+add_cd_file(TARGET dc21x4 DESTINATION reactos/system32/drivers FOR all)
+add_driver_inf(dc21x4 net21x4.inf)
diff --git a/drivers/network/dd/dc21x4/dc21x4.c b/drivers/network/dd/dc21x4/dc21x4.c
new file mode 100644
index 00000000000..f061c7f5fd5
--- /dev/null
+++ b/drivers/network/dd/dc21x4/dc21x4.c
@@ -0,0 +1,401 @@
+/*
+ * PROJECT: ReactOS DC21x4 Driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Miniport driver entry
+ * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean(a)protonmail.com>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include "dc21x4.h"
+
+#include <debug.h>
+
+/* FUNCTIONS ******************************************************************/
+
+ULONG
+DcEthernetCrc(
+ _In_reads_bytes_(Size) const VOID* Buffer,
+ _In_ ULONG Size)
+{
+ ULONG i, j, Crc;
+ const UCHAR* Data = Buffer;
+
+ Crc = 0xFFFFFFFF;
+ for (i = 0; i < Size; ++i)
+ {
+ Crc ^= Data[i];
+ for (j = 8; j > 0; j--)
+ {
+ /* CRC-32 polynomial little-endian */
+ Crc = (Crc >> 1) ^ (-(LONG)(Crc & 1) & 0xEDB88320);
+ }
+ }
+
+ return Crc;
+}
+
+static
+VOID
+DcFlushTransmitQueue(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ LIST_ENTRY DoneList;
+ PLIST_ENTRY Entry;
+ PNDIS_PACKET Packet;
+ PDC_TCB Tcb;
+
+ InitializeListHead(&DoneList);
+
+ NdisAcquireSpinLock(&Adapter->SendLock);
+
+ /* Remove pending transmissions from the transmit ring */
+ for (Tcb = Adapter->LastTcb;
+ Tcb != Adapter->CurrentTcb;
+ Tcb = DC_NEXT_TCB(Adapter, Tcb))
+ {
+ Packet = Tcb->Packet;
+
+ if (!Packet)
+ continue;
+
+ InsertTailList(&DoneList, DC_LIST_ENTRY_FROM_PACKET(Packet));
+
+ DC_RELEASE_TCB(Adapter, Tcb);
+ }
+ Adapter->CurrentTcb = Tcb;
+
+ /* Remove pending transmissions from the internal queue */
+ while (!IsListEmpty(&Adapter->SendQueueList))
+ {
+ Entry = RemoveHeadList(&Adapter->SendQueueList);
+
+ InsertTailList(&DoneList, Entry);
+ }
+
+ NdisReleaseSpinLock(&Adapter->SendLock);
+
+ while (!IsListEmpty(&DoneList))
+ {
+ Entry = RemoveHeadList(&DoneList);
+
+ NdisMSendComplete(Adapter->AdapterHandle,
+ DC_PACKET_FROM_LIST_ENTRY(Entry),
+ NDIS_STATUS_FAILURE);
+ }
+}
+
+static
+VOID
+DcStopReceivePath(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ BOOLEAN RxStopped;
+
+ ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+#if DBG
+ NdisAcquireSpinLock(&Adapter->ReceiveLock);
+ if (Adapter->RcbFree != Adapter->RcbCount)
+ {
+ INFO("RX packets: %u/%u\n", Adapter->RcbFree,
Adapter->RcbCount);
+ }
+ NdisReleaseSpinLock(&Adapter->ReceiveLock);
+#endif
+
+ while (TRUE)
+ {
+ NdisAcquireSpinLock(&Adapter->ReceiveLock);
+
+ RxStopped = (Adapter->RcbFree == Adapter->RcbCount);
+
+ NdisReleaseSpinLock(&Adapter->ReceiveLock);
+
+ if (RxStopped)
+ break;
+
+ NdisMSleep(10);
+ }
+}
+
+DECLSPEC_NOINLINE /* Called from pageable code */
+VOID
+DcStopAdapter(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ BOOLEAN WaitForPackets)
+{
+ BOOLEAN TimerCancelled;
+
+ /* Attempt to disable interrupts to complete more quickly */
+ DC_WRITE(Adapter, DcCsr7_IrqMask, 0);
+
+ /* Prevent DPCs from executing and stop accepting incoming packets */
+ NdisAcquireSpinLock(&Adapter->SendLock);
+ Adapter->Flags &= ~DC_ACTIVE;
+ NdisReleaseSpinLock(&Adapter->SendLock);
+
+ NdisMCancelTimer(&Adapter->MediaMonitorTimer, &TimerCancelled);
+
+ /* Wait for any DPCs to complete */
+ KeFlushQueuedDpcs();
+
+ /* Disable interrupts */
+ DC_WRITE(Adapter, DcCsr7_IrqMask, 0);
+
+ /* Wait for completion of TX/RX and stop the DMA engine inside the NIC */
+ DcStopTxRxProcess(Adapter);
+ Adapter->OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE);
+
+ DcFlushTransmitQueue(Adapter);
+
+ /* Wait for the packets to be returned to the driver */
+ if (WaitForPackets)
+ {
+ DcStopReceivePath(Adapter);
+ }
+
+ /* Make sure there is no pending OID request */
+ if (Adapter->OidPending)
+ {
+ NdisMSetInformationComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS);
+
+ Adapter->OidPending = FALSE;
+ }
+}
+
+CODE_SEG("PAGE")
+VOID
+DcStartAdapter(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PAGED_CODE();
+
+ /* Enable interrupts */
+ _InterlockedExchange((PLONG)&Adapter->CurrentInterruptMask,
Adapter->InterruptMask);
+ DC_WRITE(Adapter, DcCsr7_IrqMask, Adapter->InterruptMask);
+
+ Adapter->Flags |= DC_ACTIVE;
+
+ /* Start the RX process */
+ Adapter->OpMode |= DC_OPMODE_RX_ENABLE;
+ DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
+
+ /* Start the media monitor, wait the selected media to become ready */
+ NdisMSetTimer(&Adapter->MediaMonitorTimer, 2400);
+}
+
+CODE_SEG("PAGE")
+VOID
+NTAPI
+DcResetWorker(
+ _In_ PNDIS_WORK_ITEM WorkItem,
+ _In_opt_ PVOID Context)
+{
+ PDC21X4_ADAPTER Adapter = Context;
+ NDIS_STATUS Status;
+ ULONG InterruptStatus;
+ LONG ResetReason;
+
+ UNREFERENCED_PARAMETER(WorkItem);
+
+ PAGED_CODE();
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ /* Check if the device is present */
+ InterruptStatus = DC_READ(Adapter, DcCsr5_Status);
+ if (InterruptStatus == 0xFFFFFFFF)
+ {
+ ERR("Hardware is gone...\n");
+
+ /* Remove this adapter */
+ NdisMRemoveMiniport(Adapter->AdapterHandle);
+
+ Status = NDIS_STATUS_HARD_ERRORS;
+ goto Done;
+ }
+
+ DcStopAdapter(Adapter, FALSE);
+
+ if (Adapter->LinkUp)
+ {
+ Adapter->LinkUp = FALSE;
+
+ NdisMIndicateStatus(Adapter->AdapterHandle,
+ NDIS_STATUS_MEDIA_DISCONNECT,
+ NULL,
+ 0);
+ NdisMIndicateStatusComplete(Adapter->AdapterHandle);
+ }
+
+ DcSetupAdapter(Adapter);
+
+ DcStartAdapter(Adapter);
+
+Done:
+ ResetReason = _InterlockedExchange(&Adapter->ResetLock, 0);
+
+ /* Complete the pending reset request */
+ if (ResetReason == 1)
+ {
+ NdisMResetComplete(Adapter->AdapterHandle, Status, FALSE);
+ }
+}
+
+VOID
+NTAPI
+DcTransmitTimeoutRecoveryWorker(
+ _In_ PNDIS_WORK_ITEM WorkItem,
+ _In_opt_ PVOID Context)
+{
+ PDC21X4_ADAPTER Adapter = Context;
+
+ UNREFERENCED_PARAMETER(WorkItem);
+
+ NdisAcquireSpinLock(&Adapter->ModeLock);
+
+ DcStopTxRxProcess(Adapter);
+ DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
+
+ NdisDprAcquireSpinLock(&Adapter->SendLock);
+
+ DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL);
+
+ NdisDprReleaseSpinLock(&Adapter->SendLock);
+
+ NdisReleaseSpinLock(&Adapter->ModeLock);
+}
+
+static
+BOOLEAN
+NTAPI
+DcCheckForHang(
+ _In_ NDIS_HANDLE MiniportAdapterContext)
+{
+ PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+ ULONG TcbCompleted;
+ BOOLEAN TxHang = FALSE;
+
+ if (!(Adapter->Flags & DC_ACTIVE))
+ return FALSE;
+
+ NdisDprAcquireSpinLock(&Adapter->SendLock);
+
+ if (Adapter->TcbSlots != (DC_TRANSMIT_BLOCKS - DC_TCB_RESERVE))
+ {
+ TcbCompleted = Adapter->TcbCompleted;
+ TxHang = (TcbCompleted == Adapter->LastTcbCompleted);
+ Adapter->LastTcbCompleted = TcbCompleted;
+ }
+
+ NdisDprReleaseSpinLock(&Adapter->SendLock);
+
+ if (TxHang)
+ {
+ WARN("Transmit timeout, CSR12 %08lx, CSR5 %08lx\n",
+ DC_READ(Adapter, DcCsr12_SiaStatus),
+ DC_READ(Adapter, DcCsr5_Status));
+
+ NdisScheduleWorkItem(&Adapter->TxRecoveryWorkItem);
+ }
+
+ return FALSE;
+}
+
+static
+NDIS_STATUS
+NTAPI
+DcReset(
+ _Out_ PBOOLEAN AddressingReset,
+ _In_ NDIS_HANDLE MiniportAdapterContext)
+{
+ PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+
+ WARN("Called\n");
+
+ if (_InterlockedCompareExchange(&Adapter->ResetLock, 1, 0))
+ {
+ return NDIS_STATUS_RESET_IN_PROGRESS;
+ }
+
+ NdisScheduleWorkItem(&Adapter->ResetWorkItem);
+
+ return NDIS_STATUS_PENDING;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+NTAPI
+DcHalt(
+ _In_ NDIS_HANDLE MiniportAdapterContext)
+{
+ PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+
+ PAGED_CODE();
+
+ INFO("Called\n");
+
+ DcStopAdapter(Adapter, TRUE);
+
+ DcDisableHw(Adapter);
+
+ DcFreeAdapter(Adapter);
+}
+
+static
+VOID
+NTAPI
+DcShutdown(
+ _In_ NDIS_HANDLE MiniportAdapterContext)
+{
+ PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
+
+ INFO("Called\n");
+
+ DcDisableHw(Adapter);
+}
+
+CODE_SEG("INIT")
+NTSTATUS
+NTAPI
+DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath)
+{
+ NDIS_HANDLE WrapperHandle;
+ NDIS_STATUS Status;
+ NDIS_MINIPORT_CHARACTERISTICS Characteristics = { 0 };
+
+ INFO("Called\n");
+
+ NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, NULL);
+ if (!WrapperHandle)
+ return NDIS_STATUS_FAILURE;
+
+ Characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
+ Characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
+ Characteristics.CheckForHangHandler = DcCheckForHang;
+ Characteristics.HaltHandler = DcHalt;
+ Characteristics.HandleInterruptHandler = DcHandleInterrupt;
+ Characteristics.InitializeHandler = DcInitialize;
+ Characteristics.ISRHandler = DcIsr;
+ Characteristics.QueryInformationHandler = DcQueryInformation;
+ Characteristics.ResetHandler = DcReset;
+ Characteristics.SetInformationHandler = DcSetInformation;
+ Characteristics.ReturnPacketHandler = DcReturnPacket;
+ Characteristics.SendPacketsHandler = DcSendPackets;
+ Characteristics.CancelSendPacketsHandler = DcCancelSendPackets;
+ Characteristics.AdapterShutdownHandler = DcShutdown;
+
+ Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics,
sizeof(Characteristics));
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NdisTerminateWrapper(WrapperHandle, NULL);
+ return Status;
+ }
+
+ InitializeListHead(&SRompAdapterList);
+
+ return NDIS_STATUS_SUCCESS;
+}
diff --git a/drivers/network/dd/dc21x4/dc21x4.h b/drivers/network/dd/dc21x4/dc21x4.h
new file mode 100644
index 00000000000..20d62fc15ae
--- /dev/null
+++ b/drivers/network/dd/dc21x4/dc21x4.h
@@ -0,0 +1,541 @@
+/*
+ * PROJECT: ReactOS DC21x4 Driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Main header file
+ * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean(a)protonmail.com>
+ */
+
+#pragma once
+
+#if !DBG
+#define NO_KERNEL_LIST_ENTRY_CHECKS
+#endif
+#include <ndis.h>
+#include <section_attribs.h>
+
+#include "dc21x4hw.h"
+#include "eeprom.h"
+#include "media.h"
+#include "util.h"
+
+#define DC21X4_TAG '4x12'
+
+#define DC_TRANSMIT_DESCRIPTORS 64
+#define DC_TRANSMIT_BLOCKS 48
+#define DC_TRANSMIT_BUFFERS 4
+#define DC_LOOPBACK_FRAMES 4
+
+#define DC_RECEIVE_BUFFERS_DEFAULT 64
+#define DC_RECEIVE_BUFFERS_MIN 8
+#define DC_RECEIVE_BUFFERS_EXTRA 16
+
+#define DC_RECEIVE_ARRAY_SIZE 16
+
+#define DC_MULTICAST_LIST_SIZE 36
+
+#define DC_MAXIMUM_FRAME_SIZE 1514
+#define DC_TRANSMIT_BLOCK_SIZE 1536
+#define DC_RECEIVE_BLOCK_SIZE 1536
+#define DC_ETHERNET_HEADER_SIZE 14
+
+#define DC_TX_UNDERRUN_LIMIT 5
+#define DC_INTERRUPT_PROCESSING_LIMIT 8
+
+#define DC_FRAGMENTATION_THRESHOLD 32
+
+#define DC_PACKET_FILTERS ( \
+ NDIS_PACKET_TYPE_DIRECTED | \
+ NDIS_PACKET_TYPE_MULTICAST | \
+ NDIS_PACKET_TYPE_BROADCAST | \
+ NDIS_PACKET_TYPE_PROMISCUOUS | \
+ NDIS_PACKET_TYPE_ALL_MULTICAST)
+
+#define DC_LOOPBACK_FRAME_SIZE 64
+
+/* Transmit descriptors reserved for internal use */
+#define DC_TBD_RESERVE (2 + DC_LOOPBACK_FRAMES) /* (+2 for setup frame) */
+#define DC_TCB_RESERVE (1 + DC_LOOPBACK_FRAMES) /* (+1 for setup frame) */
+
+#define DC_EVENT_SETUP_FRAME_COMPLETED 0x00000001
+
+typedef struct _DC21X4_ADAPTER DC21X4_ADAPTER, *PDC21X4_ADAPTER;
+typedef struct _DC_TCB DC_TCB, *PDC_TCB;
+typedef struct _DC_RCB DC_RCB, *PDC_RCB;
+typedef struct _DC_COALESCE_BUFFER DC_COALESCE_BUFFER, *PDC_COALESCE_BUFFER;
+
+typedef VOID
+(MEDIA_HANDLE_LINK_STATE_CHANGE)(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG InterruptStatus);
+typedef MEDIA_HANDLE_LINK_STATE_CHANGE *PMEDIA_HANDLE_LINK_STATE_CHANGE;
+
+typedef struct _DC_TX_BUFFER_DATA
+{
+ PVOID VirtualAddress;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+} DC_TX_BUFFER_DATA, *PDC_TX_BUFFER_DATA;
+
+typedef struct _DC_STATISTICS
+{
+ ULONG64 TransmitOk;
+ ULONG64 TransmitDeferred;
+ ULONG64 TransmitHeartbeatErrors;
+ ULONG64 TransmitOneRetry;
+ ULONG64 TransmitMoreCollisions;
+ ULONG64 TransmitErrors;
+ ULONG64 TransmitExcessiveCollisions;
+ ULONG64 TransmitUnderrunErrors;
+ ULONG64 TransmitLostCarrierSense;
+ ULONG64 TransmitLateCollisions;
+ ULONG64 ReceiveOk;
+ ULONG64 ReceiveBroadcast;
+ ULONG64 ReceiveMulticast;
+ ULONG64 ReceiveUnicast;
+ ULONG64 ReceiveErrors;
+ ULONG64 ReceiveOverrunErrors;
+ ULONG64 ReceiveNoBuffers;
+ ULONG64 ReceiveCrcErrors;
+ ULONG64 ReceiveAlignmentErrors;
+} DC_STATISTICS, *PDC_STATISTICS;
+
+typedef struct _DC21X4_ADAPTER
+{
+ PUCHAR IoBase;
+ ULONG InterruptMask;
+ ULONG CurrentInterruptMask;
+
+ ULONG Features;
+#define DC_NEED_RX_OVERFLOW_WORKAROUND 0x80000000
+#define DC_SIA_GPIO 0x00000001
+#define DC_SIA_ANALOG_CONTROL 0x00000002
+#define DC_HAS_POWER_MANAGEMENT 0x00000004
+#define DC_HAS_POWER_SAVING 0x00000008
+#define DC_HAS_MII 0x00000010
+#define DC_PERFECT_FILTERING_ONLY 0x00000020
+#define DC_ENABLE_PCI_COMMANDS 0x00000040
+#define DC_MII_AUTOSENSE 0x00000080
+#define DC_HAS_TIMER 0x00000100
+
+ ULONG Flags;
+#define DC_ACTIVE 0x80000000
+#define DC_IO_MAPPED 0x00000001
+#define DC_IRQ_SHARED 0x00000002
+#define DC_FIRST_SETUP 0x00000004
+#define DC_AUTOSENSE 0x00000008
+
+ ULONG InterruptStatus;
+ PMEDIA_HANDLE_LINK_STATE_CHANGE HandleLinkStateChange;
+
+ DECLSPEC_CACHEALIGN NDIS_SPIN_LOCK SendLock;
+ PDC_TCB TailTcb;
+ PDC_TCB LastTcb;
+ PDC_TCB CurrentTcb;
+ PDC_TBD CurrentTbd;
+ PDC_TBD HeadTbd;
+ PDC_TBD TailTbd;
+ LIST_ENTRY SendQueueList;
+ ULONG TcbSlots;
+ ULONG TbdSlots;
+ ULONG TcbCompleted;
+ ULONG LastTcbCompleted;
+ PDC_TCB HeadTcb;
+ SINGLE_LIST_ENTRY SendBufferList;
+ SCATTER_GATHER_LIST LocalSgList;
+
+ DECLSPEC_CACHEALIGN NDIS_SPIN_LOCK ReceiveLock;
+ PDC_RCB* RcbArray;
+ PDC_RBD CurrentRbd;
+ PDC_RBD HeadRbd;
+ PDC_RBD TailRbd;
+ SINGLE_LIST_ENTRY FreeRcbList;
+ ULONG RcbFree;
+
+ ULONG TransmitUnderruns;
+ ULONG PacketFilter;
+
+ DC_STATISTICS Statistics;
+
+ NDIS_HANDLE AdapterHandle;
+ NDIS_HANDLE WrapperConfigurationHandle;
+
+ DECLSPEC_CACHEALIGN NDIS_SPIN_LOCK ModeLock;
+ ULONG ModeFlags;
+#define DC_MODE_AUTONEG_MASK 0x0000000F
+#define DC_MODE_PORT_AUTOSENSE 0x00000010
+#define DC_MODE_TEST_PACKET 0x00000020
+#define DC_MODE_AUI_FAILED 0x00000040
+#define DC_MODE_BNC_FAILED 0x00000080
+
+#define DC_MODE_AUTONEG_NONE 0x00000000
+#define DC_MODE_AUTONEG_WAIT_INTERRUPT 0x00000001
+#define DC_MODE_AUTONEG_LINK_STATUS_CHECK 0x00000002
+
+ ULONG OpMode;
+ ULONG MediaNumber;
+ ULONG MediaBitmap;
+ BOOLEAN LinkUp;
+ ULONG PhyAddress;
+ ULONG SiaSetting;
+ ULONG LastReceiveActivity;
+ volatile LONG MediaTestStatus;
+ NDIS_MINIPORT_TIMER MediaMonitorTimer;
+ DC_MII_MEDIA MiiMedia;
+ DC_MEDIA Media[MEDIA_LIST_MAX];
+
+ ULONG AnalogControl;
+ ULONG SymAdvertising;
+ ULONG MiiAdvertising;
+ ULONG MiiControl;
+ DC_CHIP_TYPE ChipType;
+ ULONG LinkStateChangeMask;
+
+ ULONG WakeUpFlags;
+ NDIS_DEVICE_POWER_STATE PowerState;
+ NDIS_DEVICE_POWER_STATE PrevPowerState;
+
+ ULONG HpnaInitBitmap;
+ UCHAR HpnaRegister[32];
+
+ UCHAR PermanentMacAddress[ETH_LENGTH_OF_ADDRESS];
+ UCHAR CurrentMacAddress[ETH_LENGTH_OF_ADDRESS];
+
+ ULONG MulticastMaxEntries;
+ _Field_range_(0, MulticastMaxEntries)
+ ULONG MulticastCount;
+ struct
+ {
+ UCHAR MacAddress[ETH_LENGTH_OF_ADDRESS];
+ } MulticastList[DC_MULTICAST_LIST_SIZE];
+
+ ULONG LinkSpeedMbps;
+ ULONG BusMode;
+ ULONG DefaultMedia;
+ ULONG RcbCount;
+ BOOLEAN OidPending;
+ BOOLEAN ProgramHashPerfectFilter;
+ PULONG SetupFrame;
+ PULONG SetupFrameSaved;
+ ULONG SetupFramePhys;
+ ULONG LoopbackFrameSlots;
+ ULONG LoopbackFrameNumber;
+ ULONG LoopbackFramePhys[DC_LOOPBACK_FRAMES];
+ ULONG BusNumber;
+ UCHAR DeviceNumber;
+ UCHAR RevisionId;
+ UCHAR ControllerIndex;
+ UCHAR ResetStreamLength;
+ USHORT ResetStream[SROM_MAX_STREAM_REGS];
+ USHORT DeviceId;
+ SINGLE_LIST_ENTRY AllocRcbList;
+ SINGLE_LIST_ENTRY UsedRcbList;
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+ ULONG InterruptVector;
+ ULONG InterruptLevel;
+ ULONG InterruptFlags;
+ ULONG AdapterSize;
+ NDIS_WORK_ITEM PowerWorkItem;
+ NDIS_WORK_ITEM ResetWorkItem;
+ NDIS_WORK_ITEM TxRecoveryWorkItem;
+ _Interlocked_ volatile LONG ResetLock;
+ NDIS_PHYSICAL_ADDRESS IoBaseAddress;
+ PDC_SROM_ENTRY SRomEntry;
+ PVOID AdapterOriginal;
+ PVOID TbdOriginal;
+ PVOID RbdOriginal;
+ ULONG TbdPhys;
+ ULONG RbdPhys;
+ NDIS_HANDLE BufferPool;
+ NDIS_HANDLE PacketPool;
+ NDIS_PHYSICAL_ADDRESS TbdPhysOriginal;
+ NDIS_PHYSICAL_ADDRESS RbdPhysOriginal;
+ PVOID LoopbackFrame[DC_LOOPBACK_FRAMES];
+ PDC_COALESCE_BUFFER CoalesceBuffer;
+ DC_TX_BUFFER_DATA SendBufferData[DC_TRANSMIT_BUFFERS];
+} DC21X4_ADAPTER, *PDC21X4_ADAPTER;
+
+#include "sendrcv.h"
+
+extern LIST_ENTRY SRompAdapterList;
+
+FORCEINLINE
+ULONG
+DC_READ(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ DC_CSR Register)
+{
+ ULONG Value;
+
+ NdisRawReadPortUlong((PULONG)(Adapter->IoBase + Register), &Value);
+ return Value;
+}
+
+#define DC_WRITE(Adapter, Register, Value) \
+ NdisRawWritePortUlong((PULONG)((Adapter)->IoBase + (Register)), (Value));
+
+CODE_SEG("INIT")
+DRIVER_INITIALIZE DriverEntry;
+
+CODE_SEG("PAGE")
+NDIS_STATUS
+NTAPI
+DcInitialize(
+ _Out_ PNDIS_STATUS OpenErrorStatus,
+ _Out_ PUINT SelectedMediumIndex,
+ _In_ PNDIS_MEDIUM MediumArray,
+ _In_ UINT MediumArraySize,
+ _In_ NDIS_HANDLE MiniportAdapterHandle,
+ _In_ NDIS_HANDLE WrapperConfigurationContext);
+
+VOID
+NTAPI
+DcSendPackets(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ PPNDIS_PACKET PacketArray,
+ _In_ UINT NumberOfPackets);
+
+VOID
+NTAPI
+DcCancelSendPackets(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ PVOID CancelId);
+
+VOID
+DcProcessPendingPackets(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+VOID
+NTAPI
+DcReturnPacket(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ PNDIS_PACKET Packet);
+
+NDIS_STATUS
+NTAPI
+DcQueryInformation(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ NDIS_OID Oid,
+ _In_ PVOID InformationBuffer,
+ _In_ ULONG InformationBufferLength,
+ _Out_ PULONG BytesWritten,
+ _Out_ PULONG BytesNeeded);
+
+NDIS_STATUS
+NTAPI
+DcSetInformation(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ NDIS_OID Oid,
+ _In_ PVOID InformationBuffer,
+ _In_ ULONG InformationBufferLength,
+ _Out_ PULONG BytesRead,
+ _Out_ PULONG BytesNeeded);
+
+VOID
+NTAPI
+DcIsr(
+ _Out_ PBOOLEAN InterruptRecognized,
+ _Out_ PBOOLEAN QueueMiniportHandleInterrupt,
+ _In_ NDIS_HANDLE MiniportAdapterContext);
+
+VOID
+NTAPI
+DcHandleInterrupt(
+ _In_ NDIS_HANDLE MiniportAdapterContext);
+
+CODE_SEG("PAGE")
+VOID
+NTAPI
+DcPowerWorker(
+ _In_ PNDIS_WORK_ITEM WorkItem,
+ _In_opt_ PVOID Context);
+
+NDIS_STATUS
+DcSetPower(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ NDIS_DEVICE_POWER_STATE PowerState);
+
+NDIS_STATUS
+DcAddWakeUpPattern(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PNDIS_PM_PACKET_PATTERN PmPattern);
+
+NDIS_STATUS
+DcRemoveWakeUpPattern(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PNDIS_PM_PACKET_PATTERN PmPattern);
+
+CODE_SEG("PAGE")
+VOID
+DcFreeAdapter(
+ _In_ __drv_freesMem(Mem) PDC21X4_ADAPTER Adapter);
+
+CODE_SEG("PAGE")
+VOID
+NTAPI
+DcResetWorker(
+ _In_ PNDIS_WORK_ITEM WorkItem,
+ _In_opt_ PVOID Context);
+
+DECLSPEC_NOINLINE
+VOID
+DcStopAdapter(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ BOOLEAN WaitForPackets);
+
+CODE_SEG("PAGE")
+VOID
+DcStartAdapter(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+CODE_SEG("PAGE")
+NDIS_STATUS
+DcSetupAdapter(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+CODE_SEG("PAGE")
+NDIS_STATUS
+DcReadEeprom(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+CODE_SEG("PAGE")
+VOID
+DcFreeEeprom(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+CODE_SEG("PAGE")
+VOID
+DcInitTxRing(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+CODE_SEG("PAGE")
+VOID
+DcInitRxRing(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+ULONG
+DcEthernetCrc(
+ _In_reads_bytes_(Size) const VOID* Buffer,
+ _In_ ULONG Size);
+
+VOID
+DcDisableHw(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+VOID
+DcStopTxRxProcess(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+VOID
+DcWriteGpio(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG Value);
+
+VOID
+DcWriteSia(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG Csr13,
+ _In_ ULONG Csr14,
+ _In_ ULONG Csr15);
+
+VOID
+DcTestPacket(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+CODE_SEG("PAGE")
+VOID
+DcSetupFrameInitialize(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+BOOLEAN
+DcSetupFrameDownload(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ BOOLEAN WaitForCompletion);
+
+NDIS_STATUS
+DcApplyPacketFilter(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG PacketFilter);
+
+NDIS_STATUS
+DcUpdateMulticastList(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+VOID
+DcPowerSave(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ BOOLEAN Enable);
+
+CODE_SEG("PAGE")
+BOOLEAN
+DcFindMiiPhy(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+BOOLEAN
+MiiWrite(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG PhyAddress,
+ _In_ ULONG RegAddress,
+ _In_ ULONG Data);
+
+BOOLEAN
+MiiRead(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG PhyAddress,
+ _In_ ULONG RegAddress,
+ _Out_ PULONG Data);
+
+CODE_SEG("PAGE")
+VOID
+HpnaPhyInit(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+VOID
+NTAPI
+DcTransmitTimeoutRecoveryWorker(
+ _In_ PNDIS_WORK_ITEM WorkItem,
+ _In_opt_ PVOID Context);
+
+NDIS_TIMER_FUNCTION MediaMonitor21040Dpc;
+NDIS_TIMER_FUNCTION MediaMonitor21041Dpc;
+NDIS_TIMER_FUNCTION MediaMonitor21140Dpc;
+NDIS_TIMER_FUNCTION MediaMonitor21143Dpc;
+
+MEDIA_HANDLE_LINK_STATE_CHANGE MediaLinkStateChange21040;
+MEDIA_HANDLE_LINK_STATE_CHANGE MediaLinkStateChange21041;
+MEDIA_HANDLE_LINK_STATE_CHANGE MediaLinkStateChange21143;
+
+CODE_SEG("PAGE")
+VOID
+MediaInitMediaList(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+CODE_SEG("PAGE")
+VOID
+MediaInitDefaultMedia(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG MediaNumber);
+
+VOID
+MediaIndicateConnect(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ BOOLEAN LinkUp);
+
+VOID
+MediaSelectMiiPort(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ BOOLEAN ResetPhy);
+
+VOID
+MediaMiiSelect(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+BOOLEAN
+MediaMiiCheckLink(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+VOID
+MediaSiaSelect(
+ _In_ PDC21X4_ADAPTER Adapter);
+
+VOID
+MediaGprSelect(
+ _In_ PDC21X4_ADAPTER Adapter);
diff --git a/drivers/network/dd/dc21x4/dc21x4.rc b/drivers/network/dd/dc21x4/dc21x4.rc
new file mode 100644
index 00000000000..1ecd5c02f7d
--- /dev/null
+++ b/drivers/network/dd/dc21x4/dc21x4.rc
@@ -0,0 +1,5 @@
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "DC21x4 Ethernet Adapter Driver"
+#define REACTOS_STR_INTERNAL_NAME "dc21x4"
+#define REACTOS_STR_ORIGINAL_FILENAME "dc21x4.sys"
+#include <reactos/version.rc>
diff --git a/drivers/network/dd/dc21x4/dc21x4hw.h b/drivers/network/dd/dc21x4/dc21x4hw.h
new file mode 100644
index 00000000000..fc53adc1b9d
--- /dev/null
+++ b/drivers/network/dd/dc21x4/dc21x4hw.h
@@ -0,0 +1,597 @@
+/*
+ * PROJECT: ReactOS DC21x4 Driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Hardware specific definitions
+ * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean(a)protonmail.com>
+ */
+
+#pragma once
+
+typedef enum _DC_CHIP_TYPE
+{
+ DC21040,
+ DC21041,
+ DC21140,
+ DC21143,
+ DC21145,
+} DC_CHIP_TYPE;
+
+/*
+ * PCI Vendor and Device IDs
+ */
+#define DC_DEV_DECCHIP_21040 0x00021011
+#define DC_DEV_DECCHIP_21041 0x00141011
+#define DC_DEV_DECCHIP_21140 0x00091011
+#define DC_DEV_INTEL_21143 0x00191011
+#define DC_DEV_INTEL_21145 0x00398086
+
+#define DC_DESCRIPTOR_ALIGNMENT 4
+#define DC_SETUP_FRAME_ALIGNMENT 4
+#define DC_RECEIVE_BUFFER_ALIGNMENT 4
+#define DC_RECEIVE_BUFFER_SIZE_MULTIPLE 4
+
+#define DC_IO_LENGTH 128
+
+#define DC_SETUP_FRAME_SIZE 192
+
+/* Multicast perfect filter */
+#define DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES 16
+
+/* -1 for physical address and -1 for broadcast address */
+#define DC_SETUP_FRAME_ADDRESSES (16 - 2)
+
+/* Computed hash of FF:FF:FF:FF:FF:FF */
+#define DC_SETUP_FRAME_BROADCAST_HASH 0xFF
+
+#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define DC_SETUP_FRAME_ENTRY(Value) (Value)
+#else
+#define DC_SETUP_FRAME_ENTRY(Value) ((Value) << 16)
+#endif
+
+#include <pshpack1.h>
+
+/*
+ * Transmit Buffer Descriptor
+ */
+typedef struct _DC_TBD
+{
+ ULONG Status;
+#define DC_TBD_STATUS_DEFFERED 0x00000001
+#define DC_TBD_STATUS_UNDERFLOW 0x00000002
+#define DC_TBD_STATUS_LINK_FAIL 0x00000004
+#define DC_TBD_STATUS_COLLISIONS_MASK 0x00000078
+#define DC_TBD_STATUS_HEARTBEAT_FAIL 0x00000080
+#define DC_TBD_STATUS_RETRY_ERROR 0x00000100
+#define DC_TBD_STATUS_LATE_COLLISION 0x00000200
+#define DC_TBD_STATUS_NO_CARRIER 0x00000400
+#define DC_TBD_STATUS_CARRIER_LOST 0x00000800
+#define DC_TBD_STATUS_JABBER_TIMEOUT 0x00004000
+#define DC_TBD_STATUS_ERROR_SUMMARY 0x00008000
+#define DC_TBD_STATUS_OWNED 0x80000000
+
+#define DC_TBD_STATUS_SETUP_FRAME 0x7FFFFFFF
+
+#define DC_TBD_STATUS_COLLISIONS_SHIFT 3
+
+ ULONG Control;
+#define DC_TBD_CONTROL_LENGTH_MASK_1 0x000007FF
+#define DC_TBD_CONTROL_LENGTH_MASK_2 0x003FF800
+#define DC_TBD_CONTROL_NO_PAD 0x00800000
+#define DC_TBD_CONTROL_CHAINED 0x01000000
+#define DC_TBD_CONTROL_END_OF_RING 0x02000000
+#define DC_TBD_CONTROL_NO_CRC 0x04000000
+#define DC_TBD_CONTROL_SETUP_FRAME 0x08000000
+#define DC_TBD_CONTROL_FIRST_FRAGMENT 0x20000000
+#define DC_TBD_CONTROL_LAST_FRAGMENT 0x40000000
+#define DC_TBD_CONTROL_REQUEST_INTERRUPT 0x80000000
+#define DC_TBD_CONTROL_PERFECT_FILTER 0x00000000
+#define DC_TBD_CONTROL_HASH_PERFECT_FILTER 0x00400000
+#define DC_TBD_CONTROL_INVERSE_FILTER 0x10000000
+#define DC_TBD_CONTROL_IMPERFECT_FILTER 0x10400000
+
+#define DC_TBD_CONTROL_LENGTH_2_SHIFT 11
+
+ ULONG Address1;
+ ULONG Address2;
+} DC_TBD, *PDC_TBD;
+
+C_ASSERT(sizeof(DC_TBD) == 16);
+
+/*
+ * Receive Buffer Descriptor
+ */
+typedef struct _DC_RBD
+{
+ ULONG Status;
+#define DC_RBD_STATUS_OVERRUN 0x00000001
+#define DC_RBD_STATUS_CRC_ERROR 0x00000002
+#define DC_RBD_STATUS_DRIBBLE 0x00000004
+#define DC_RBD_STATUS_MII_ERROR 0x00000008
+#define DC_RBD_STATUS_WDT_EXPIRED 0x00000010
+#define DC_RBD_STATUS_FRAME_TYPE 0x00000020
+#define DC_RBD_STATUS_COLLISION_SEEN 0x00000040
+#define DC_RBD_STATUS_TOO_LONG 0x00000080
+#define DC_RBD_STATUS_LAST_DESCRIPTOR 0x00000100
+#define DC_RBD_STATUS_FIRST_DESCRIPTOR 0x00000200
+#define DC_RBD_STATUS_MULTICAST 0x00000400
+#define DC_RBD_STATUS_RUNT 0x00000800
+#define DC_RBD_STATUS_DATA_TYPE_MASK 0x00003000
+#define DC_RBD_STATUS_LENGTH_ERROR 0x00004000
+#define DC_RBD_STATUS_ERROR_SUMMARY 0x00008000
+#define DC_RBD_STATUS_FRAME_LENGTH_MASK 0x3FFF0000
+#define DC_RBD_STATUS_FILTERING_FAIL 0x40000000
+#define DC_RBD_STATUS_OWNED 0x80000000
+
+#define DC_RBD_STATUS_FRAME_LENGTH_SHIFT 16
+
+ ULONG Control;
+#define DC_RBD_CONTROL_BUFFER_LENGTH_MASK_1 0x000007FF
+#define DC_RBD_CONTROL_BUFFER_LENGTH_MASK_2 0x003FF800
+#define DC_RBD_CONTROL_CHAINED 0x01000000
+#define DC_RBD_CONTROL_END_OF_RING 0x02000000
+
+ ULONG Address1;
+ ULONG Address2;
+} DC_RBD, *PDC_RBD;
+
+C_ASSERT(sizeof(DC_RBD) == 16);
+
+#define DC_PATTERN_FILTERS 4
+
+/*
+ * Wake-Up Filter Register Block
+ */
+typedef union _DC_PATTERN_FILTER_BLOCK
+{
+ struct
+ {
+ ULONG Mask[DC_PATTERN_FILTERS];
+
+ UCHAR Command[DC_PATTERN_FILTERS];
+#define DC_PATTERN_FILTER_CMD_ENABLE 0x01
+#define DC_PATTERN_FILTER_CMD_INVERSE_MODE 0x02
+#define DC_PATTERN_FILTER_CMD_ADD_PREV 0x04
+#define DC_PATTERN_FILTER_CMD_MULTICAST 0x08
+
+ UCHAR Offset[DC_PATTERN_FILTERS];
+ USHORT Crc[DC_PATTERN_FILTERS];
+ };
+ ULONG AsULONG[8];
+} DC_PATTERN_FILTER_BLOCK, *PDC_PATTERN_FILTER_BLOCK;
+
+C_ASSERT(sizeof(DC_PATTERN_FILTER_BLOCK) == 32);
+
+#include <poppack.h>
+
+/*
+ * NIC Control and Status Registers
+ */
+typedef enum _DC_CSR
+{
+ DcCsr0_BusMode = 0x00,
+ DcCsr1_TxPoll = 0x08,
+ DcCsr1_WakeUpFilter = 0x08,
+ DcCsr2_RxPoll = 0x10,
+ DcCsr2_WakeUpControl = 0x10,
+ DcCsr3_RxRingAddress = 0x18,
+ DcCsr4_TxRingAddress = 0x20,
+ DcCsr5_Status = 0x28,
+ DcCsr6_OpMode = 0x30,
+ DcCsr7_IrqMask = 0x38,
+ DcCsr8_RxCounters = 0x40,
+ DcCsr9_SerialInterface = 0x48,
+ DcCsr10_BootRom = 0x50,
+ DcCsr11_FullDuplex = 0x58,
+ DcCsr11_Timer = 0x58,
+ DcCsr12_Gpio = 0x60,
+ DcCsr12_SiaStatus = 0x60,
+ DcCsr13_SiaConnectivity = 0x68,
+ DcCsr14_SiaTxRx = 0x70,
+ DcCsr15_SiaGeneral = 0x78,
+} DC_CSR;
+
+/*
+ * CSR0 Bus Mode
+ */
+#define DC_BUS_MODE_SOFT_RESET 0x00000001
+#define DC_BUS_MODE_BUS_ARB 0x00000002
+#define DC_BUS_MODE_DESC_SKIP_LENGTH_MASK 0x0000007C
+#define DC_BUS_MODE_BUFFERS_BIG_ENDIAN 0x00000080
+#define DC_BUS_MODE_BURST_LENGTH_MASK 0x00003F00
+#define DC_BUS_MODE_CACHE_ALIGNMENT_MASK 0x0000C000
+#define DC_BUS_MODE_DIAGNOSTIC_ADDRESS_SPACE 0x00010000
+#define DC_BUS_MODE_TX_POLL_MASK 0x000E0000
+#define DC_BUS_MODE_DESC_BIG_ENDIAN 0x00100000
+#define DC_BUS_MODE_READ_MULTIPLE 0x00200000
+#define DC_BUS_MODE_READ_LINE 0x00800000
+#define DC_BUS_MODE_WRITE_INVALIDATE 0x01000000
+#define DC_BUS_MODE_ON_NOW_UNLOCK 0x04000000
+
+#define DC_BUS_MODE_BURST_LENGTH_NO_LIMIT 0x00000000
+#define DC_BUS_MODE_BURST_LENGTH_1 0x00000100
+#define DC_BUS_MODE_BURST_LENGTH_2 0x00000200
+#define DC_BUS_MODE_BURST_LENGTH_4 0x00000400
+#define DC_BUS_MODE_BURST_LENGTH_8 0x00000800
+#define DC_BUS_MODE_BURST_LENGTH_16 0x00001000
+#define DC_BUS_MODE_BURST_LENGTH_32 0x00002000
+
+#define DC_BUS_MODE_CACHE_ALIGNMENT_NONE 0x00000000
+#define DC_BUS_MODE_CACHE_ALIGNMENT_8 0x00004000
+#define DC_BUS_MODE_CACHE_ALIGNMENT_16 0x00008000
+#define DC_BUS_MODE_CACHE_ALIGNMENT_32 0x0000C000
+
+#define DC_BUS_MODE_TX_POLL_DISABLED 0x00000000
+#define DC_BUS_MODE_TX_POLL_1 0x00020000
+#define DC_BUS_MODE_TX_POLL_2 0x00040000
+#define DC_BUS_MODE_TX_POLL_3 0x00060000
+#define DC_BUS_MODE_TX_POLL_4 0x00080000
+#define DC_BUS_MODE_TX_POLL_5 0x000A0000
+#define DC_BUS_MODE_TX_POLL_6 0x000C0000
+#define DC_BUS_MODE_TX_POLL_7 0x000E0000
+
+#define DC_BUS_MODE_DESC_SKIP_LENGTH_0 0x00000000
+#define DC_BUS_MODE_DESC_SKIP_LENGTH_1 0x00000004
+#define DC_BUS_MODE_DESC_SKIP_LENGTH_2 0x00000008
+#define DC_BUS_MODE_DESC_SKIP_LENGTH_4 0x00000010
+#define DC_BUS_MODE_DESC_SKIP_LENGTH_8 0x00000020
+#define DC_BUS_MODE_DESC_SKIP_LENGTH_16 0x00000040
+#define DC_BUS_MODE_DESC_SKIP_LENGTH_32 0x00000080
+
+/*
+ * CSR1 Transmit Poll Demand
+ */
+#define DC_TX_POLL_DOORBELL 0x00000001
+
+/*
+ * CSR2 Receive Poll Demand
+ */
+#define DC_RX_POLL_DOORBELL 0x00000001
+
+/*
+ * CSR2 Wake Up Control
+ */
+#define DC_WAKE_UP_CONTROL_LINK_CHANGE 0x00000001
+#define DC_WAKE_UP_CONTROL_MAGIC_PACKET 0x00000002
+#define DC_WAKE_UP_CONTROL_PATTERN_MATCH 0x00000004
+#define DC_WAKE_UP_STATUS_LINK_CHANGE 0x00000010
+#define DC_WAKE_UP_STATUS_MAGIC_PACKET 0x00000020
+#define DC_WAKE_UP_STATUS_PATTERN_MATCH 0x00000040
+#define DC_WAKE_UP_CONTROL_GLOBAL_UNICAST 0x00000200
+#define DC_WAKE_UP_CONTROL_VLAN_ENABLE 0x00000800
+#define DC_WAKE_UP_CONTROL_VLAN_TYPE_MASK 0xFFFF0000
+
+/*
+ * CSR5 Status, CSR7 Irq Mask
+ */
+#define DC_IRQ_TX_OK 0x00000001
+#define DC_IRQ_TX_STOPPED 0x00000002
+#define DC_IRQ_TX_NO_BUFFER 0x00000004
+#define DC_IRQ_TX_JABBER_TIMEOUT 0x00000008
+#define DC_IRQ_LINK_PASS 0x00000010
+#define DC_IRQ_TX_UNDERFLOW 0x00000020
+#define DC_IRQ_RX_OK 0x00000040
+#define DC_IRQ_RX_NO_BUFFER 0x00000080
+#define DC_IRQ_RX_STOPPED 0x00000100
+#define DC_IRQ_RX_WDT_TIMEOUT 0x00000200
+#define DC_IRQ_AUI 0x00000400
+#define DC_IRQ_TX_EARLY 0x00000400
+#define DC_IRQ_FD_FRAME_RECEIVED 0x00000800
+#define DC_IRQ_TIMER_TIMEOUT 0x00000800
+#define DC_IRQ_LINK_FAIL 0x00001000
+#define DC_IRQ_SYSTEM_ERROR 0x00002000
+#define DC_IRQ_RX_EARLY 0x00004000
+#define DC_IRQ_ABNORMAL_SUMMARY 0x00008000
+#define DC_IRQ_NORMAL_SUMMARY 0x00010000
+#define DC_STATUS_RX_STATE_MASK 0x000E0000
+#define DC_STATUS_TX_STATE_MASK 0x00700000
+#define DC_STATUS_SYSTEM_ERROR_MASK 0x03800000
+#define DC_IRQ_GPIO_PORT 0x04000000
+#define DC_IRQ_LINK_CHANGED 0x08000000
+#define DC_IRQ_HPNA_PHY 0x10000000
+
+#define DC_STATUS_TX_STATE_STOPPED 0x00000000
+#define DC_STATUS_TX_STATE_FETCH 0x00100000
+#define DC_STATUS_TX_STATE_WAIT_FOR_END 0x00200000
+#define DC_STATUS_TX_STATE_READ 0x00300000
+#define DC_STATUS_TX_STATE_RESERVED 0x00400000
+#define DC_STATUS_TX_STATE_SETUP_PACKET 0x00500000
+#define DC_STATUS_TX_STATE_SUSPENDED 0x00600000
+#define DC_STATUS_TX_STATE_CLOSE 0x00700000
+
+#define DC_STATUS_RX_STATE_STOPPED 0x00000000
+#define DC_STATUS_RX_STATE_FETCH 0x00020000
+#define DC_STATUS_RX_STATE_CHECK_END 0x00040000
+#define DC_STATUS_RX_STATE_WAIT_FOR_RCV 0x00060000
+#define DC_STATUS_RX_STATE_SUSPENDED 0x00080000
+#define DC_STATUS_RX_STATE_CLOSE_DESC 0x000A0000
+#define DC_STATUS_RX_STATE_FLUSH 0x000C0000
+#define DC_STATUS_RX_STATE_DEQUEUE 0x000E0000
+
+#define DC_STATUS_SYSTEM_ERROR_PARITY 0x00000000
+#define DC_STATUS_SYSTEM_ERROR_MASTER_ABORT 0x00800000
+#define DC_STATUS_SYSTEM_ERROR_TARGET_ABORT 0x01000000
+
+/*
+ * CSR6 Operation Mode
+ */
+#define DC_OPMODE_RX_HASH_PERFECT_FILT 0x00000001
+#define DC_OPMODE_RX_ENABLE 0x00000002
+#define DC_OPMODE_RX_HASH_ONLY_FILT 0x00000004
+#define DC_OPMODE_RX_RUNTS 0x00000008
+#define DC_OPMODE_RX_INVERSE_FILT 0x00000010
+#define DC_OPMODE_BACKOFF_COUNTER 0x00000020
+#define DC_OPMODE_RX_PROMISCUOUS 0x00000040
+#define DC_OPMODE_RX_ALL_MULTICAST 0x00000080
+#define DC_OPMODE_FKD 0x00000100
+#define DC_OPMODE_FULL_DUPLEX 0x00000200
+#define DC_OPMODE_LOOPBACK_MASK 0x00000C00
+#define DC_OPMODE_FORCE_COLLISIONS 0x00001000
+#define DC_OPMODE_TX_ENABLE 0x00002000
+#define DC_OPMODE_TX_THRESHOLD_CTRL_MASK 0x0000C000
+#define DC_OPMODE_TX_BACK_PRESSURE 0x00010000
+#define DC_OPMODE_TX_CAPTURE_EFFECT 0x00020000
+#define DC_OPMODE_PORT_SELECT 0x00040000
+#define DC_OPMODE_PORT_HEARTBEAT_DISABLE 0x00080000
+#define DC_OPMODE_STORE_AND_FORWARD 0x00200000
+#define DC_OPMODE_PORT_XMIT_10 0x00400000
+#define DC_OPMODE_PORT_PCS 0x00800000
+#define DC_OPMODE_PORT_SCRAMBLER 0x01000000
+#define DC_OPMODE_PORT_ALWAYS 0x02000000
+#define DC_OPMODE_ADDR_LSB_IGNORE 0x04000000
+#define DC_OPMODE_RX_RECEIVE_ALL 0x40000000
+#define DC_OPMODE_TX_SPECIAL_CAPTURE_EFFECT 0x80000000
+
+#define DC_OPMODE_LOOPBACK_NORMAL 0x00000000
+#define DC_OPMODE_LOOPBACK_INTERNAL 0x00000400
+#define DC_OPMODE_LOOPBACK_EXTERNAL 0x00000800
+
+#define DC_OPMODE_TX_THRESHOLD_LEVEL 0x00004000
+#define DC_OPMODE_TX_THRESHOLD_MAX 0x0000C000
+
+#define DC_OPMODE_MEDIA_MASK ( \
+ DC_OPMODE_TX_THRESHOLD_CTRL_MASK | \
+ DC_OPMODE_LOOPBACK_MASK | \
+ DC_OPMODE_FULL_DUPLEX | \
+ DC_OPMODE_PORT_SELECT | \
+ DC_OPMODE_PORT_HEARTBEAT_DISABLE | \
+ DC_OPMODE_PORT_XMIT_10 | \
+ DC_OPMODE_PORT_PCS | \
+ DC_OPMODE_PORT_SCRAMBLER)
+
+/*
+ * CSR8 Receive Counters
+ */
+#define DC_COUNTER_RX_NO_BUFFER_MASK 0x0001FFFF
+#define DC_COUNTER_RX_OVERFLOW_MASK 0x1FFE0000
+
+#define DC_COUNTER_RX_OVERFLOW_SHIFT 17
+
+/*
+ * CSR9 Serial Interface
+ */
+#define DC_SERIAL_EE_CS 0x00000001
+#define DC_SERIAL_EE_SK 0x00000002
+#define DC_SERIAL_EE_DI 0x00000004
+#define DC_SERIAL_EE_DO 0x00000008
+#define DC_SERIAL_EE_REG 0x00000400
+#define DC_SERIAL_EE_SR 0x00000800
+#define DC_SERIAL_EE_WR 0x00002000
+#define DC_SERIAL_EE_RD 0x00004000
+#define DC_SERIAL_EE_MOD 0x00008000
+#define DC_SERIAL_MII_MDC 0x00010000
+#define DC_SERIAL_MII_MDO 0x00020000
+#define DC_SERIAL_MII_MII 0x00040000
+#define DC_SERIAL_MII_MDI 0x00080000
+#define DC_SERIAL_EAR_DN 0x80000000
+#define DC_SERIAL_EAR_DT 0x000000FF
+#define DC_SERIAL_SPI_CS 0x00100000
+#define DC_SERIAL_SPI_SK 0x00200000
+#define DC_SERIAL_SPI_DI 0x00400000
+#define DC_SERIAL_SPI_DO 0x00800000
+
+#define DC_SERIAL_EE_DI_SHIFT 2
+#define DC_SERIAL_EE_DO_SHIFT 3
+#define DC_SERIAL_MII_MDO_SHIFT 17
+#define DC_SERIAL_MII_MDI_SHIFT 19
+#define DC_SERIAL_SPI_DI_SHIFT 22
+#define DC_SERIAL_SPI_DO_SHIFT 23
+
+/*
+ * CSR11 Timer
+ */
+#define DC_TIMER_VALUE_MASK 0x0000FFFF
+#define DC_TIMER_CONTINUOUS 0x00010000
+#define DC_TIMER_RX_NUMBER_MASK 0x000E0000
+#define DC_TIMER_RX_TIMER_MASK 0x00F00000
+#define DC_TIMER_TX_NUMBER_MASK 0x07000000
+#define DC_TIMER_TX_TIMER_MASK 0x78000000
+#define DC_TIMER_CYCLE_SIZE 0x80000000
+
+#define DC_TIMER_RX_NUMBER_SHIFT 17
+#define DC_TIMER_RX_TIMER_SHIFT 20
+#define DC_TIMER_TX_NUMBER_SHIFT 24
+#define DC_TIMER_TX_TIMER_SHIFT 27
+
+/*
+ * CSR12 SIA Status
+ */
+#define DC_SIA_STATUS_MII_RECEIVE_ACTIVITY 0x00000001
+#define DC_SIA_STATUS_NETWORK_CONNECTION_ERROR 0x00000002
+#define DC_SIA_STATUS_100T_LINK_FAIL 0x00000002
+#define DC_SIA_STATUS_10T_LINK_FAIL 0x00000004
+#define DC_SIA_STATUS_SELECTED_PORT_ACTIVITY 0x00000100
+#define DC_SIA_STATUS_AUI_ACTIVITY 0x00000100
+#define DC_SIA_STATUS_HPNA_ACTIVITY 0x00000100
+#define DC_SIA_STATUS_NONSEL_PORT_ACTIVITY 0x00000200
+#define DC_SIA_STATUS_10T_ACTIVITY 0x00000200
+#define DC_SIA_STATUS_NSN 0x00000400
+#define DC_SIA_STATUS_TX_REMOTE_FAULT 0x00000800
+#define DC_SIA_STATUS_ANS_MASK 0x00007000
+#define DC_SIA_STATUS_LP_AUTONED_SUPPORTED 0x00008000
+#define DC_SIA_STATUS_LP_CODE_WORD_MASK 0xFFFF0000
+
+#define DC_SIA_STATUS_ANS_AUTONEG_DISABLED 0x00000000
+#define DC_SIA_STATUS_ANS_TX_DISABLE 0x00001000
+#define DC_SIA_STATUS_ANS_ABILITY_DETECT 0x00002000
+#define DC_SIA_STATUS_ANS_ACK_DETECT 0x00003000
+#define DC_SIA_STATUS_ANS_ACK_COMPLETE 0x00004000
+#define DC_SIA_STATUS_ANS_AUTONEG_COMPLETE 0x00005000
+#define DC_SIA_STATUS_ANS_LINK_CHECK 0x00006000
+
+#define DC_SIA_STATUS_LP_CODE_WORD_SHIFT 16
+
+#define DC_GPIO_CONTROL 0x100
+
+/*
+ * CSR13 SIA Connectivity
+ */
+#define DC_SIA_CONN_RESET 0x00000000
+#define DC_SIA_CONN_HPNA 0x00000008
+
+/*
+ * CSR14 SIA Transmit and Receive
+ */
+#define DC_SIA_TXRX_ENCODER 0x00000001
+#define DC_SIA_TXRX_LOOPBACK 0x00000002
+#define DC_SIA_TXRX_DRIVER 0x00000004
+#define DC_SIA_TXRX_LINK_PULSE 0x00000008
+#define DC_SIA_TXRX_COMPENSATION 0x00000030
+#define DC_SIA_TXRX_ADV_10T_HD 0x00000040
+#define DC_SIA_TXRX_AUTONEG 0x00000080
+#define DC_SIA_TXRX_RX_SQUELCH 0x00000100
+#define DC_SIA_TXRX_COLLISION_SQUELCH 0x00000200
+#define DC_SIA_TXRX_COLLISION_DETECT 0x00000400
+#define DC_SIA_TXRX_HEARTBEAT 0x00000800
+#define DC_SIA_TXRX_LINK_TEST 0x00001000
+#define DC_SIA_TXRX_AUTOPOLARITY 0x00002000
+#define DC_SIA_TXRX_SET_POLARITY_PLUS 0x00004000
+#define DC_SIA_TXRX_10T_AUTOSENSE 0x00008000
+#define DC_SIA_TXRX_ADV_100TX_HD 0x00010000
+#define DC_SIA_TXRX_ADV_100TX_FD 0x00020000
+#define DC_SIA_TXRX_ADV_100T4 0x00040000
+
+/*
+ * CSR15 SIA and GPIO
+ */
+#define DC_SIA_GENERAL_JABBER_DISABLE 0x00000001
+#define DC_SIA_GENERAL_HOST_UNJAB 0x00000002
+#define DC_SIA_GENERAL_JABBER_CLOCK 0x00000004
+#define DC_SIA_GENERAL_AUI_BNC_MODE 0x00000008
+#define DC_SIA_GENERAL_RX_WDT_DISABLE 0x00000010
+#define DC_SIA_GENERAL_RX_WDT_RELEASE 0x00000020
+#define DC_SIA_GENERAL_LINK_EXTEND 0x00000800
+#define DC_SIA_GENERAL_RX_MAGIC_PACKET 0x00004000
+#define DC_SIA_GENERAL_HCKR 0x00008000
+#define DC_SIA_GENERAL_GPIO_MASK 0x000F0000
+#define DC_SIA_GENERAL_LGS3 0x00100000
+#define DC_SIA_GENERAL_LGS2 0x00200000
+#define DC_SIA_GENERAL_LGS1 0x00400000
+#define DC_SIA_GENERAL_LGS0 0x00800000
+#define DC_SIA_GENERAL_GEI0 0x01000000
+#define DC_SIA_GENERAL_GEI1 0x02000000
+#define DC_SIA_GENERAL_RECEIVE_MATCH 0x04000000
+#define DC_SIA_GENERAL_CONTROL_WRITE 0x08000000
+#define DC_SIA_GENERAL_GI0 0x10000000
+#define DC_SIA_GENERAL_GI1 0x20000000
+#define DC_SIA_GENERAL_IRQ_RX_MATCH 0x40000000
+
+#define DC_RBD_STATUS_INVALID \
+ (DC_RBD_STATUS_OVERRUN | \
+ DC_RBD_STATUS_CRC_ERROR | \
+ DC_RBD_STATUS_WDT_EXPIRED | \
+ DC_RBD_STATUS_COLLISION_SEEN | \
+ DC_RBD_STATUS_TOO_LONG | \
+ DC_RBD_STATUS_RUNT | \
+ DC_RBD_STATUS_LENGTH_ERROR)
+
+#define DC_GENERIC_IRQ_MASK \
+ (DC_IRQ_TX_OK | DC_IRQ_TX_STOPPED | DC_IRQ_TX_JABBER_TIMEOUT | \
+ DC_IRQ_RX_OK | DC_IRQ_TX_UNDERFLOW | \
+ DC_IRQ_RX_STOPPED | \
+ DC_IRQ_SYSTEM_ERROR | DC_IRQ_ABNORMAL_SUMMARY | DC_IRQ_NORMAL_SUMMARY)
+
+/* Errata: The programming guide incorrectly stated that CSR13 must be set to 0x30480009
*/
+#define DC_HPNA_ANALOG_CTRL 0x708A0000
+
+/*
+ * PCI Configuration Registers
+ */
+#define DC_PCI_DEVICE_CONFIG 0x40
+#define DC_PCI_DEVICE_CONFIG_SNOOZE 0x40000000
+#define DC_PCI_DEVICE_CONFIG_SLEEP 0x80000000
+
+/*
+ * SPI Interface
+ */
+#define DC_SPI_BYTE_WRITE_OPERATION 2
+#define DC_SPI_BYTE_READ_OPERATION 3
+#define DC_SPI_CLEAR_WRITE_ENABLE 4
+#define DC_SPI_SET_WRITE_ENABLE 6
+
+/*
+ * HomePNA PHY Registers
+ */
+#define HPNA_CONTROL_LOW 0x00
+#define HPNA_CONTROL_HIGH 0x01
+#define HPNA_NOISE 0x10
+#define HPNA_NOISE_FLOOR 0x12
+#define HPNA_NOISE_CEILING 0x13
+#define HPNA_NOISE_ATTACK 0x14
+
+/*
+ * MDIO Protocol (IEEE 802.3)
+ */
+#define MDIO_START 0x01
+#define MDIO_WRITE 0x01
+#define MDIO_READ 0x02
+#define MDIO_TA 0x02
+#define MDIO_PREAMBLE 0xFFFFFFFF
+
+#define MII_MAX_PHY_ADDRESSES 32
+
+/*
+ * PHY register definitions (IEEE 802.3)
+ */
+#define MII_CONTROL 0x00
+#define MII_CR_COLLISION_TEST 0x0080
+#define MII_CR_FULL_DUPLEX 0x0100
+#define MII_CR_AUTONEG_RESTART 0x0200
+#define MII_CR_ISOLATE 0x0400
+#define MII_CR_POWER_DOWN 0x0800
+#define MII_CR_AUTONEG 0x1000
+#define MII_CR_SPEED_SELECTION 0x2000
+#define MII_CR_LOOPBACK 0x4000
+#define MII_CR_RESET 0x8000
+#define MII_STATUS 0x01
+#define MII_SR_LINK_STATUS 0x0004
+#define MII_SR_AUTONEG_COMPLETE 0x0020
+#define MII_PHY_ID1 0x02
+#define MII_PHY_ID2 0x03
+#define MII_AUTONEG_ADVERTISE 0x04
+#define MII_ADV_CSMA 0x0001
+#define MII_ADV_10T_HD 0x0020
+#define MII_ADV_10T_FD 0x0040
+#define MII_ADV_100T_HD 0x0080
+#define MII_ADV_100T_FD 0x0100
+#define MII_ADV_100T4 0x0200
+#define MII_ADV_PAUSE_SYM 0x0400
+#define MII_ADV_PAUSE_ASYM 0x0800
+#define MII_AUTONEG_LINK_PARTNER 0x05
+#define MII_LP_10T_HD 0x0020
+#define MII_LP_10T_FD 0x0040
+#define MII_LP_100T_HD 0x0080
+#define MII_LP_100T_FD 0x0100
+#define MII_LP_100T4 0x0200
+#define MII_LP_PAUSE_SYM 0x0400
+#define MII_LP_PAUSE_ASYM 0x0800
+#define MII_AUTONEG_EXPANSION 0x06
+#define MII_EXP_LP_AUTONEG 0x0001
+#define MII_MASTER_SLAVE_CONTROL 0x09
+#define MII_MS_CR_1000T_HD 0x0100
+#define MII_MS_CR_1000T_FD 0x0200
+#define MII_MASTER_SLAVE_STATUS 0x0A
+#define MII_MS_SR_1000T_FD 0x0800
+
+#define MII_ADV_100 \
+ (MII_ADV_100T_HD | MII_ADV_100T_FD | MII_ADV_100T4)
diff --git a/drivers/network/dd/dc21x4/debug.c b/drivers/network/dd/dc21x4/debug.c
new file mode 100644
index 00000000000..3dc9e5f073f
--- /dev/null
+++ b/drivers/network/dd/dc21x4/debug.c
@@ -0,0 +1,70 @@
+/*
+ * PROJECT: ReactOS DC21x4 Driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Debug routines
+ * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean(a)protonmail.com>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include "dc21x4.h"
+
+/* GLOBALS ********************************************************************/
+
+static PCSTR MediaName[MEDIA_MAX] =
+{
+ "10Base-T",
+ "10Base-2 (BNC)",
+ "10Base-5 (AUI)",
+ "100Base-TX HD",
+ "10Base-T FD",
+ "100Base-TX FD",
+ "100Base-T4",
+ "100Base-FX HD",
+ "100Base-FX FD",
+ "HomePNA",
+ "MII",
+};
+
+/* FUNCTIONS ******************************************************************/
+
+PCSTR
+MediaNumber2Str(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG MediaNumber)
+{
+ switch (MediaNumber)
+ {
+ case MEDIA_100TX_HD:
+ {
+ if (Adapter->ChipType == DC21041)
+ return "10Base-T HD";
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ ASSERT(MediaNumber < MEDIA_MAX);
+
+ return MediaName[MediaNumber];
+}
+
+PCSTR
+DcDbgBusError(
+ _In_ ULONG InterruptStatus)
+{
+ switch (InterruptStatus & DC_STATUS_SYSTEM_ERROR_MASK)
+ {
+ case DC_STATUS_SYSTEM_ERROR_PARITY:
+ return "Parity Error";
+ case DC_STATUS_SYSTEM_ERROR_MASTER_ABORT:
+ return "Master Abort";
+ case DC_STATUS_SYSTEM_ERROR_TARGET_ABORT:
+ return "Target Abort";
+
+ default:
+ return "<unknown>";
+ }
+}
diff --git a/drivers/network/dd/dc21x4/debug.h b/drivers/network/dd/dc21x4/debug.h
new file mode 100644
index 00000000000..f1a4e178de3
--- /dev/null
+++ b/drivers/network/dd/dc21x4/debug.h
@@ -0,0 +1,96 @@
+/*
+ * PROJECT: ReactOS DC21x4 Driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Debug support header file
+ * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean(a)protonmail.com>
+ */
+
+#pragma once
+
+#ifndef __RELFILE__
+#define __RELFILE__ __FILE__
+#endif
+
+#if DBG
+
+// #define DEBUG_TRACE
+// #define DEBUG_INFO
+#define DEBUG_INFO_VERB
+#define DEBUG_WARN
+#define DEBUG_ERR
+
+#ifdef DEBUG_TRACE
+#define TRACE(fmt, ...) \
+ do { \
+ if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__,
##__VA_ARGS__)) \
+ DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+ } while (0)
+
+#else
+#define TRACE
+#endif
+
+#ifdef DEBUG_INFO
+#define INFO(fmt, ...) \
+ do { \
+ if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__,
##__VA_ARGS__)) \
+ DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+ } while (0)
+
+#else
+#define INFO
+#endif
+
+#ifdef DEBUG_INFO_VERB
+#define INFO_VERB(fmt, ...) \
+ do { \
+ if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__,
##__VA_ARGS__)) \
+ DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+ } while (0)
+
+#else
+#define INFO_VERB
+#endif
+
+#ifdef DEBUG_WARN
+#define WARN(fmt, ...) \
+ do { \
+ if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__,
##__VA_ARGS__)) \
+ DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+ } while (0)
+
+#else
+#define WARN
+#endif
+
+#ifdef DEBUG_ERR
+#define ERR(fmt, ...) \
+ do { \
+ if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__,
##__VA_ARGS__)) \
+ DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+ } while (0)
+
+#else
+#define ERR
+#endif
+
+PCSTR
+MediaNumber2Str(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG MediaNumber);
+
+PCSTR
+DcDbgBusError(
+ _In_ ULONG InterruptStatus);
+
+#else
+
+#define TRACE
+#define INFO
+#define INFO_VERB
+#define WARN
+#define ERR
+#define MediaNumber2Str
+#define DcDbgBusError
+
+#endif
diff --git a/drivers/network/dd/dc21x4/eeprom.c b/drivers/network/dd/dc21x4/eeprom.c
new file mode 100644
index 00000000000..6937a5723df
--- /dev/null
+++ b/drivers/network/dd/dc21x4/eeprom.c
@@ -0,0 +1,1525 @@
+/*
+ * PROJECT: ReactOS DC21x4 Driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: EEPROM manipulation and parsing
+ * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean(a)protonmail.com>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include "dc21x4.h"
+
+#include <debug.h>
+
+/* GLOBALS ********************************************************************/
+
+#define SROM_READ(Adapter, Data) \
+ do { \
+ *Data = DC_READ((Adapter), DcCsr9_SerialInterface); \
+ NdisStallExecution(10); \
+ } while (0)
+
+#define SROM_WRITE(Adapter, Value) \
+ do { \
+ DC_WRITE((Adapter), DcCsr9_SerialInterface, Value); \
+ NdisStallExecution(10); \
+ } while (0)
+
+extern DC_PG_DATA DC_SROM_REPAIR_ENTRY SRompRepairData[];
+
+LIST_ENTRY SRompAdapterList;
+
+_Interlocked_
+static volatile LONG SRompAdapterLock = 0;
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+static
+CODE_SEG("PAGE")
+VOID
+SRomAcquireListMutex(VOID)
+{
+ PAGED_CODE();
+
+ while (_InterlockedCompareExchange(&SRompAdapterLock, 1, 0))
+ {
+ NdisMSleep(10);
+ }
+}
+
+static inline
+CODE_SEG("PAGE")
+VOID
+SRomReleaseListMutex(VOID)
+{
+ PAGED_CODE();
+
+ _InterlockedDecrement(&SRompAdapterLock);
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+SRomIsAdapterInList(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ BOOLEAN SearchForMaster,
+ _Out_opt_ PDC_SROM_ENTRY* FoundEntry)
+{
+ PLIST_ENTRY PrevEntry;
+ PDC_SROM_ENTRY SRomEntry;
+
+ PAGED_CODE();
+
+ /* Loop the adapter list backwards */
+ for (PrevEntry = (&SRompAdapterList)->Blink;
+ PrevEntry != &SRompAdapterList;
+ PrevEntry = PrevEntry->Blink)
+ {
+ SRomEntry = CONTAINING_RECORD(PrevEntry, DC_SROM_ENTRY, ListEntry);
+
+ if ((SRomEntry->ChipType == Adapter->ChipType) &&
+ (SRomEntry->BusNumber == Adapter->BusNumber) &&
+ (!SearchForMaster || (SRomEntry->DeviceNumber ==
Adapter->DeviceNumber)))
+ {
+ if (FoundEntry)
+ *FoundEntry = SRomEntry;
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+SRomRegisterMasterAdapter(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PDC_SROM_ENTRY SRomEntry)
+{
+ BOOLEAN Success;
+
+ PAGED_CODE();
+
+ SRomAcquireListMutex();
+
+ /* Check if board is already registered */
+ if (SRomIsAdapterInList(Adapter, TRUE, NULL))
+ {
+ Success = FALSE;
+ goto Exit;
+ }
+
+ Adapter->SRomEntry = SRomEntry;
+
+ SRomEntry->ChipType = Adapter->ChipType;
+ SRomEntry->BusNumber = Adapter->BusNumber;
+ SRomEntry->DeviceNumber = Adapter->DeviceNumber;
+ SRomEntry->InterruptLevel = Adapter->InterruptLevel;
+ SRomEntry->InterruptVector = Adapter->InterruptVector;
+
+ /* Register the port */
+ SRomEntry->DeviceBitmap |= 1 << Adapter->DeviceNumber;
+
+ /*
+ * On some multiport boards only the first port contains an EEPROM.
+ * We put their references to the global adapter list.
+ */
+ InsertTailList(&SRompAdapterList, &SRomEntry->ListEntry);
+ Success = TRUE;
+
+Exit:
+ SRomReleaseListMutex();
+
+ return Success;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+SRomFindMasterAdapter(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _Out_ PDC_SROM_ENTRY* FoundEntry)
+{
+ PDC_SROM_ENTRY SRomEntry;
+ ULONG i;
+ BOOLEAN Found;
+
+ PAGED_CODE();
+
+ SRomAcquireListMutex();
+
+ if (!SRomIsAdapterInList(Adapter, FALSE, &SRomEntry))
+ {
+ Found = FALSE;
+ goto Exit;
+ }
+
+ Adapter->SRomEntry = SRomEntry;
+
+ /* Register the port */
+ SRomEntry->DeviceBitmap |= 1 << Adapter->DeviceNumber;
+
+ /*
+ * Determine the port index that should be used in order to
+ * (possibly) update the base MAC address.
+ */
+ for (i = 0; i < PCI_MAX_DEVICES; ++i)
+ {
+ if (i == Adapter->DeviceNumber)
+ break;
+
+ if (SRomEntry->DeviceBitmap & (1 << i))
+ ++Adapter->ControllerIndex;
+ }
+
+ /*
+ * On a multiport board there can be up to 4 ports
+ * connected through a 21050 or 21152 PCI-to-PCI Bridge.
+ * These boards share a single IRQ line between all of the chips.
+ * Some BIOSes incorrectly assign different IRQs to the different ports.
+ */
+ Adapter->InterruptLevel = SRomEntry->InterruptLevel;
+ Adapter->InterruptVector = SRomEntry->InterruptVector;
+
+ WARN("EEPROM is missing on controller %u, using image from the master at
%u:%u\n",
+ Adapter->DeviceNumber,
+ SRomEntry->BusNumber,
+ SRomEntry->DeviceNumber);
+
+ *FoundEntry = SRomEntry;
+ Found = TRUE;
+
+Exit:
+ SRomReleaseListMutex();
+
+ return Found;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+SRomIsEmpty(
+ _In_reads_bytes_(Length) const VOID* Buffer,
+ _In_ ULONG Length)
+{
+ const UCHAR* Data = Buffer;
+ const UCHAR FirstByte = Data[0];
+ ULONG i;
+
+ PAGED_CODE();
+
+ for (i = 1; i < Length; ++i)
+ {
+ if (FirstByte != Data[i])
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+SRomNWayAdvertise(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG MediaCode)
+{
+ PAGED_CODE();
+
+ switch (MediaCode)
+ {
+ case MEDIA_10T:
+ Adapter->SymAdvertising |= MII_ADV_10T_HD;
+ break;
+ case MEDIA_10T_FD:
+ Adapter->SymAdvertising |= MII_ADV_10T_FD;
+ break;
+ case MEDIA_100TX_HD:
+ Adapter->SymAdvertising |= MII_ADV_100T_HD;
+ break;
+ case MEDIA_100TX_FD:
+ Adapter->SymAdvertising |= MII_ADV_100T_FD;
+ break;
+ case MEDIA_100T4:
+ Adapter->SymAdvertising |= MII_ADV_100T4;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+SRomDecodeBlockGpr(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PUCHAR SRomEnd,
+ _In_ PUCHAR BlockData)
+{
+ PDC_MEDIA Media;
+ ULONG MediaCode, OpMode;
+ USHORT Command;
+
+ PAGED_CODE();
+
+ if (BlockData > (SRomEnd - 4))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ MediaCode = SRomGetMediaCode(*BlockData++);
+ if (MediaCode > SROM_MEDIA_MAX)
+ {
+ WARN("Unknown media code %u\n", MediaCode);
+ return NDIS_STATUS_SUCCESS;
+ }
+ Adapter->MediaBitmap |= 1 << MediaCode;
+
+ Media = &Adapter->Media[MediaCode];
+
+ Media->GpioData = *BlockData++;
+
+ Command = DcRetrieveWord(BlockData);
+
+ OpMode = Media->OpMode;
+ OpMode &= ~SROM_OPMODE_MASK;
+ OpMode |= SRomCommandToOpMode(Command);
+ Media->OpMode = OpMode;
+
+ if (SRomMediaHasActivityIndicator(Command))
+ {
+ Media->LinkMask = SRomMediaGetSenseMask(Command);
+ }
+ if (SRomMediaActivityIsActiveLow(Command))
+ {
+ Media->Polarity = 0xFFFFFFFF;
+ }
+
+ INFO("GPR #%u %s, Command %04lx, Data %02lx\n",
+ MediaCode,
+ MediaNumber2Str(Adapter, MediaCode),
+ Command,
+ Media->GpioData);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+SRomDecodeBlockMii(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PUCHAR SRomEnd,
+ _In_ PUCHAR BlockData,
+ _In_ BOOLEAN IsOldVersion)
+{
+ PDC_MII_MEDIA Media;
+ ULONG i, Bytes, Offset;
+ UCHAR PhyNumber, StreamLength, InterruptInfo;
+ USHORT Capabilities, Fdx, Ttm;
+
+ PAGED_CODE();
+
+ if (BlockData > (SRomEnd - 2))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ PhyNumber = *BlockData++;
+
+ /*
+ * Even though the SROM specification allows several
+ * PHY devices to be connected to the same chip on a board,
+ * most if not all boards never use more than 1 MII PHY device.
+ */
+ if (Adapter->Features & DC_HAS_MII)
+ {
+ WARN("Unsupported PHY %u\n", PhyNumber);
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ Media = &Adapter->MiiMedia;
+
+ /*
+ * PHY selection sequence
+ */
+
+ StreamLength = *BlockData++;
+ if (StreamLength > SROM_MAX_STREAM_REGS)
+ {
+ WARN("Too much registers %u\n", StreamLength);
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ Bytes = StreamLength;
+ if (!IsOldVersion)
+ {
+ /* In words */
+ Bytes *= 2;
+ }
+ if ((BlockData + Bytes) > (SRomEnd - 1))
+ {
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+ }
+
+ Media->SetupStreamLength = StreamLength;
+
+ /* Check if we already have the GPIO direction data */
+ if (Media->SetupStream[0] != 0)
+ {
+ Offset = 1;
+ ++Media->SetupStreamLength;
+ }
+ else
+ {
+ Offset = 0;
+ }
+
+ for (i = 0; i < StreamLength; ++i)
+ {
+ if (IsOldVersion)
+ {
+ Media->SetupStream[i + Offset] = *BlockData++;
+ }
+ else
+ {
+ Media->SetupStream[i + Offset] = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+ }
+ }
+
+ /*
+ * PHY reset sequence
+ */
+
+ if (BlockData > (SRomEnd - 1))
+ {
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+ }
+
+ StreamLength = *BlockData++;
+ if (StreamLength > SROM_MAX_STREAM_REGS)
+ {
+ WARN("Too much registers %u\n", StreamLength);
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ Bytes = StreamLength;
+ if (!IsOldVersion)
+ {
+ /* In words */
+ Bytes *= 2;
+ }
+ if ((BlockData + Bytes) > (SRomEnd - 1))
+ {
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+ }
+
+ Media->ResetStreamLength = StreamLength;
+
+ for (i = 0; i < StreamLength; ++i)
+ {
+ if (IsOldVersion)
+ {
+ Media->ResetStream[i] = *BlockData++;
+ }
+ else
+ {
+ Media->ResetStream[i] = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+ }
+ }
+
+ /*
+ * MII data
+ */
+
+ Bytes = 4 * sizeof(USHORT);
+ if (!IsOldVersion)
+ {
+ Bytes += 1;
+ }
+ if (BlockData > (SRomEnd - Bytes))
+ {
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+ }
+
+ Capabilities = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ Media->Advertising = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ Fdx = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ Ttm = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ InterruptInfo = IsOldVersion ? 0 : *BlockData;
+
+ Adapter->Features |= DC_HAS_MII;
+
+ INFO("MII #%u, Caps %04lx, Adv %04lx, Fdx %04lx, Ttm %04lx, Int %02x\n",
+ PhyNumber,
+ Capabilities,
+ Media->Advertising,
+ Fdx,
+ Ttm,
+ InterruptInfo);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+SRomDecodeBlockSia(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PUCHAR SRomEnd,
+ _In_ PUCHAR BlockData)
+{
+ PDC_MEDIA Media;
+ UCHAR BlockStart;
+ ULONG MediaCode;
+ BOOLEAN HasExtendedData;
+
+ PAGED_CODE();
+
+ if (BlockData > (SRomEnd - 1))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ BlockStart = *BlockData++;
+
+ HasExtendedData = SRomBlockHasExtendedData(BlockStart);
+ if (BlockData > (SRomEnd - (HasExtendedData ? 10 : 4)))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ MediaCode = SRomGetMediaCode(BlockStart);
+ if (MediaCode > SROM_MEDIA_MAX && MediaCode != SROM_MEDIA_HMR)
+ {
+ WARN("Unknown media code %u\n", MediaCode);
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ /* TODO: There were a few 21143-based boards with HMR media */
+ if ((MediaCode == SROM_MEDIA_HMR) && (Adapter->ChipType != DC21145))
+ {
+ ERR("FIXME: 21143 HMR is not supported yet\n");
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ /* Map the code to our internal value */
+ if (MediaCode == SROM_MEDIA_HMR)
+ {
+ MediaCode = MEDIA_HMR;
+ }
+
+ Adapter->MediaBitmap |= 1 << MediaCode;
+
+ Media = &Adapter->Media[MediaCode];
+
+ if (HasExtendedData)
+ {
+ Media->Csr13 = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ Media->Csr14 = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ Media->Csr15 = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+ }
+
+ Media->GpioCtrl = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ Media->GpioData = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ SRomNWayAdvertise(Adapter, MediaCode);
+
+ INFO("SIA #%u %s, %sCSR13 %04lx CSR14 %04lx CSR15 %04lx, "
+ "Ctrl %04lx, Data %04lx\n",
+ MediaCode,
+ MediaNumber2Str(Adapter, MediaCode),
+ HasExtendedData ? "EXT " : "",
+ Media->Csr13,
+ Media->Csr14,
+ Media->Csr15,
+ Media->GpioCtrl,
+ Media->GpioData);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+SRomDecodeBlockSym(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PUCHAR SRomEnd,
+ _In_ PUCHAR BlockData)
+{
+ PDC_MEDIA Media;
+ ULONG MediaCode, OpMode;
+ USHORT Command;
+
+ PAGED_CODE();
+
+ if (BlockData > (SRomEnd - 7))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ MediaCode = SRomGetMediaCode(*BlockData++);
+ if (MediaCode > SROM_MEDIA_MAX)
+ {
+ WARN("Unknown media code %u\n", MediaCode);
+ return NDIS_STATUS_SUCCESS;
+ }
+ Adapter->MediaBitmap |= 1 << MediaCode;
+
+ Media = &Adapter->Media[MediaCode];
+
+ Media->GpioCtrl = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ Media->GpioData = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ Command = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ OpMode = Media->OpMode;
+ OpMode &= ~SROM_OPMODE_MASK;
+ OpMode |= SRomCommandToOpMode(Command);
+ Media->OpMode = OpMode;
+
+ SRomNWayAdvertise(Adapter, MediaCode);
+
+ INFO("SYM #%u %s, Command %04lx, Ctrl %04lx, Data %04lx\n",
+ MediaCode,
+ MediaNumber2Str(Adapter, MediaCode),
+ Command,
+ Media->GpioCtrl,
+ Media->GpioData);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+SRomDecodeBlockReset(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PUCHAR SRomEnd,
+ _In_ PUCHAR BlockData)
+{
+ UCHAR i, StreamLength;
+
+ PAGED_CODE();
+
+ if (BlockData > (SRomEnd - 1))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ StreamLength = *BlockData++;
+ if (StreamLength > SROM_MAX_STREAM_REGS)
+ {
+ WARN("Too much registers %u\n", StreamLength);
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ if ((BlockData + StreamLength * 2) > (SRomEnd - 1))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ Adapter->ResetStreamLength = StreamLength;
+
+ for (i = 0; i < StreamLength; ++i)
+ {
+ Adapter->ResetStream[i] = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+ }
+
+ INFO("RESET, length %u\n", StreamLength);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+SRomDecodeBlockHmr(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PUCHAR SRomEnd,
+ _In_ PUCHAR BlockData,
+ _In_ UCHAR BlockLength)
+{
+ ULONG Offset, ExtraData, i;
+
+ PAGED_CODE();
+
+ if (BlockData > (SRomEnd - (2 + 6)))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ Adapter->AnalogControl = DcRetrieveWord(BlockData) << 16;
+ BlockData += sizeof(USHORT);
+
+ Adapter->HpnaRegister[HPNA_CONTROL_LOW] = *BlockData++;
+ Adapter->HpnaRegister[HPNA_CONTROL_HIGH] = *BlockData++;
+ Adapter->HpnaRegister[HPNA_NOISE] = *BlockData++;
+ Adapter->HpnaRegister[HPNA_NOISE_FLOOR] = *BlockData++;
+ Adapter->HpnaRegister[HPNA_NOISE_CEILING] = *BlockData++;
+ Adapter->HpnaRegister[HPNA_NOISE_ATTACK] = *BlockData++;
+ Adapter->HpnaInitBitmap |= ((1 << HPNA_CONTROL_LOW) |
+ (1 << HPNA_CONTROL_HIGH) |
+ (1 << HPNA_NOISE) |
+ (1 << HPNA_NOISE_FLOOR) |
+ (1 << HPNA_NOISE_CEILING) |
+ (1 << HPNA_NOISE_ATTACK));
+
+ Offset = 2 /* Length and type fields */ + 2 /* Analog ctrl */ + 6; /* Regs */
+ ExtraData = (BlockLength - Offset);
+
+ if ((BlockData + ExtraData) > (SRomEnd - 1))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ for (i = 0; i < ExtraData / sizeof(USHORT); ++i)
+ {
+ UCHAR RegAddress = SRomHmrRegAddress(*BlockData++);
+ UCHAR RegValue = *BlockData++;
+
+ Adapter->HpnaRegister[RegAddress] = RegValue;
+ Adapter->HpnaInitBitmap |= 1 << RegAddress;
+ }
+
+#if DBG
+ INFO_VERB("Analog Ctrl %04lx\n", Adapter->AnalogControl);
+
+ for (i = 0; i < RTL_NUMBER_OF(Adapter->HpnaRegister); ++i)
+ {
+ if (Adapter->HpnaInitBitmap & (1 << i))
+ {
+ INFO_VERB("HR Reg %02x = %02x\n", i, Adapter->HpnaRegister[i]);
+ }
+ }
+
+ if (ExtraData % sizeof(USHORT))
+ {
+ INFO_VERB("HR Data = %02x\n", *BlockData);
+ }
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+SRomParseExtendedBlock(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PUCHAR SRomEnd,
+ _In_ PUCHAR BlockData,
+ _Out_ PULONG BlockSize)
+{
+ NDIS_STATUS Status;
+ ULONG Length, Type;
+
+ PAGED_CODE();
+
+ if (BlockData > (SRomEnd - 2))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ Length = SRomGetExtendedBlockLength(*BlockData++);
+ Type = *BlockData++;
+
+ *BlockSize = Length;
+
+ switch (Type)
+ {
+ case SROM_BLOCK_TYPE_GPR:
+ Status = SRomDecodeBlockGpr(Adapter, SRomEnd, BlockData);
+ break;
+ case SROM_BLOCK_TYPE_MII_1:
+ case SROM_BLOCK_TYPE_MII_2:
+ Status = SRomDecodeBlockMii(Adapter,
+ SRomEnd,
+ BlockData,
+ (Type == SROM_BLOCK_TYPE_MII_1));
+ break;
+ case SROM_BLOCK_TYPE_SIA:
+ Status = SRomDecodeBlockSia(Adapter, SRomEnd, BlockData);
+ break;
+ case SROM_BLOCK_TYPE_SYM:
+ Status = SRomDecodeBlockSym(Adapter, SRomEnd, BlockData);
+ break;
+ case SROM_BLOCK_TYPE_RESET:
+ Status = SRomDecodeBlockReset(Adapter, SRomEnd, BlockData);
+ break;
+ case SROM_BLOCK_TYPE_HOMERUN:
+ Status = SRomDecodeBlockHmr(Adapter, SRomEnd, BlockData, Length);
+ break;
+
+ /* Skip over the unused or unknown blocks */
+ default:
+ WARN("Unknown block type %u, length %u\n", Type, Length);
+ case SROM_BLOCK_TYPE_PHY_SHUTDOWN:
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+
+ return Status;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+SRomParse21041Block(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PUCHAR SRomEnd,
+ _In_ PUCHAR BlockData,
+ _Out_ PULONG BlockSize)
+{
+ PDC_MEDIA Media;
+ UCHAR BlockStart;
+ ULONG MediaCode;
+ BOOLEAN HasExtendedData;
+
+ PAGED_CODE();
+
+ if (BlockData > (SRomEnd - 1))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ BlockStart = *BlockData++;
+
+ HasExtendedData = SRomBlockHasExtendedData(BlockStart);
+ if (BlockData > (SRomEnd - (HasExtendedData ? 7 : 1)))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ *BlockSize = HasExtendedData ? 7 : 1;
+
+ MediaCode = SRomGetMediaCode(BlockStart);
+ if (MediaCode > SROM_MEDIA_MAX)
+ {
+ WARN("Unknown media code %u\n", MediaCode);
+ return NDIS_STATUS_SUCCESS;
+ }
+ Adapter->MediaBitmap |= 1 << MediaCode;
+
+ Media = &Adapter->Media[MediaCode];
+
+ if (HasExtendedData)
+ {
+ Media->Csr13 = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ Media->Csr14 = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+
+ Media->Csr15 = DcRetrieveWord(BlockData);
+ BlockData += sizeof(USHORT);
+ }
+
+ INFO("SIA #%u %s, %sCSR13 %04lx CSR14 %04lx CSR15 %04lx\n",
+ MediaCode,
+ MediaNumber2Str(Adapter, MediaCode),
+ HasExtendedData ? "EXT " : "",
+ Media->Csr13,
+ Media->Csr14,
+ Media->Csr15);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+SRomChecksumValid(
+ _In_ PUCHAR SRom)
+{
+ USHORT Checksum;
+
+ PAGED_CODE();
+
+ Checksum = ~DcEthernetCrc(SRom, SROM_CHECKSUM_V1);
+ if (Checksum == DcRetrieveWord(&SRom[SROM_CHECKSUM_V1]))
+ return TRUE;
+
+ Checksum = ~DcEthernetCrc(SRom, SROM_CHECKSUM_V2);
+ if (Checksum == DcRetrieveWord(&SRom[SROM_CHECKSUM_V2]))
+ return TRUE;
+
+ return FALSE;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+AddressRomChecksumValid(
+ _In_reads_bytes_(EAR_SIZE) PVOID AddressRom)
+{
+ const UCHAR* Octet = AddressRom;
+ ULONG64 TestPatterm;
+ ULONG Checksum, i;
+
+ NdisMoveMemory(&TestPatterm, &Octet[24], 8);
+ if (TestPatterm != EAR_TEST_PATTERN)
+ return FALSE;
+
+ for (i = 0; i < 8; ++i)
+ {
+ if (Octet[i] != Octet[15 - i])
+ return FALSE;
+ }
+
+ Checksum = (Octet[0] << 10) + (Octet[2] << 9) + (Octet[4] << 8) +
+ (Octet[1] << 2) + (Octet[3] << 1) + Octet[5];
+ Checksum %= 0xFFFF;
+
+ return ((USHORT)Checksum == ((Octet[6] << 8) | Octet[7]));
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+SRomReadMacAddress(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PUCHAR SRom,
+ _Out_opt_ PULONG AddressOffset)
+{
+ ULONG MacOffset;
+
+ /* Check if we have a board with an old EAR format */
+ if (NdisEqualMemory(SRom, &SRom[16], 8))
+ {
+ /* Validate the EAR checksum */
+ if (!AddressRomChecksumValid(SRom))
+ {
+ ERR("EAR has an invalid checksum\n");
+ return FALSE;
+ }
+
+ MacOffset = 0;
+ goto ReadMac;
+ }
+
+ /* Check for a new SROM format */
+ if (Adapter->ChipType != DC21040)
+ {
+ /* Validate the SROM checksum */
+ if (SRomChecksumValid(SRom))
+ {
+ MacOffset = SROM_MAC_ADDRESS;
+ goto ReadMac;
+ }
+ }
+
+ /* Sanity check */
+ if (*(PULONG)SRom == 0xFFFFFFF || *(PULONG)SRom == 0)
+ return FALSE;
+
+ WARN("Legacy/unknown board found\n");
+ MacOffset = 0;
+
+ReadMac:
+ if (AddressOffset)
+ *AddressOffset = MacOffset;
+
+ NdisMoveMemory(Adapter->PermanentMacAddress,
+ &SRom[MacOffset],
+ ETH_LENGTH_OF_ADDRESS);
+
+ return TRUE;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+SRomParseHeader(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PUCHAR SRom,
+ _Out_ PUCHAR* InfoLeaf,
+ _Out_ PUCHAR* SRomEnd)
+{
+ ULONG i, MacOffset, LeafOffset;
+
+ PAGED_CODE();
+
+ if (!SRomReadMacAddress(Adapter, SRom, &MacOffset))
+ {
+ ERR("Unable to read the MAC address\n");
+ return NDIS_STATUS_FAILURE;
+ }
+
+ /* Assign our own fake info leaf */
+ if (MacOffset != SROM_MAC_ADDRESS)
+ {
+ for (i = 0; SRompRepairData[i].InfoLeaf; ++i)
+ {
+ /* Check for a MAC match */
+ if (NdisEqualMemory(SRompRepairData[i].InfoLeaf,
&Adapter->PermanentMacAddress, 3))
+ {
+ /* This check is used to distinguish Accton EN1207 from Maxtech */
+ if ((Adapter->PermanentMacAddress[0] == 0xE8) && (SRom[0x1A]
== 0x55))
+ ++i;
+
+ break;
+ }
+ }
+ if (!SRompRepairData[i].InfoLeaf)
+ {
+ ERR("Non-standard SROM format, OUI %02x:%02x:%02x\n",
+ Adapter->PermanentMacAddress[0],
+ Adapter->PermanentMacAddress[1],
+ Adapter->PermanentMacAddress[2]);
+
+ return NDIS_STATUS_ADAPTER_NOT_FOUND;
+ }
+
+ *InfoLeaf = &SRompRepairData[i].InfoLeaf[3];
+ *SRomEnd = *InfoLeaf + SRompRepairData[i].Length;
+
+ /* Update the base address on multiport boards */
+ Adapter->PermanentMacAddress[5] += Adapter->ControllerIndex;
+
+#if DBG
+ WARN("Non-standard SROM format, using '%s' info leaf\n",
SRompRepairData[i].Name);
+#endif
+ return STATUS_SUCCESS;
+ }
+
+ /* Check if the SROM chip is shared between multiple controllers on a multiport board
*/
+ if (SRom[SROM_CONTROLLER_COUNT] > 1)
+ {
+ INFO("Multiport board, controller number %u (%u/%u)\n",
+ Adapter->DeviceNumber,
+ Adapter->ControllerIndex + 1,
+ SRom[SROM_CONTROLLER_COUNT]);
+
+ for (i = 0; i < SRom[SROM_CONTROLLER_COUNT]; ++i)
+ {
+ if (SROM_DEVICE_NUMBER(i) >= EE_SIZE)
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ if (SRom[SROM_DEVICE_NUMBER(i)] == Adapter->DeviceNumber)
+ break;
+ }
+ if (i == SRom[SROM_CONTROLLER_COUNT])
+ {
+ ERR("Controller %u was not found in the SROM\n",
Adapter->DeviceNumber);
+ return NDIS_STATUS_ADAPTER_NOT_FOUND;
+ }
+
+ if (SROM_LEAF_OFFSET(i) >= EE_SIZE)
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ /* Update the base address */
+ Adapter->PermanentMacAddress[5] += i;
+ }
+ else
+ {
+ i = 0;
+ }
+
+ /* Controller info block offset */
+ LeafOffset = DcRetrieveWord(SRom + SROM_LEAF_OFFSET(i));
+ if (LeafOffset > (EE_SIZE - sizeof(DC_SROM_COMPACT_BLOCK)))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ /* Controller info leaf */
+ *InfoLeaf = &SRom[LeafOffset];
+
+ *SRomEnd = SRom + EE_SIZE;
+
+ return STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+SRomParse(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ PUCHAR SRom)
+{
+ ULONG Index, BlockCount, BlockSize, DefaultMedia;
+ NDIS_STATUS Status;
+ USHORT GpioCtrl;
+ PUCHAR Data, SRomEnd;
+
+ PAGED_CODE();
+
+ INFO("SROM Version %u, Controller count %u\n",
+ SRom[SROM_VERSION],
+ SRom[SROM_CONTROLLER_COUNT]);
+
+ Status = SRomParseHeader(Adapter, SRom, &Data, &SRomEnd);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ DefaultMedia = DcRetrieveWord(Data);
+ Data += sizeof(USHORT);
+
+ INFO("Default Media: %04lx\n", DefaultMedia);
+
+ /* Direction of the GPIO pins */
+ if (Adapter->ChipType == DC21140)
+ {
+ GpioCtrl = *Data++;
+
+ INFO("GPIO Direction: %04lx\n", GpioCtrl);
+
+ GpioCtrl |= DC_GPIO_CONTROL;
+
+ for (Index = 0; Index < MEDIA_LIST_MAX; ++Index)
+ {
+ Adapter->Media[Index].GpioCtrl = GpioCtrl;
+ }
+
+ /* Control word for block type 1 */
+ Adapter->MiiMedia.SetupStream[0] = GpioCtrl;
+ }
+
+ BlockCount = *Data++;
+
+ INFO("Block Count: %u\n", BlockCount);
+
+ if (BlockCount == 0 || BlockCount == 0xFF)
+ {
+ WARN("No media information found\n");
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ /* Analyze and decode blocks */
+ for (Index = 0; Index < BlockCount; ++Index)
+ {
+ if (Adapter->ChipType == DC21041)
+ {
+ Status = SRomParse21041Block(Adapter, SRomEnd, Data, &BlockSize);
+ }
+ else
+ {
+ if (Data > (SRomEnd - 1))
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+
+ if (SRomIsBlockExtended(*Data))
+ {
+ Status = SRomParseExtendedBlock(Adapter, SRomEnd, Data, &BlockSize);
+ }
+ else
+ {
+ Status = SRomDecodeBlockGpr(Adapter, SRomEnd, Data);
+ BlockSize = 4;
+ }
+ }
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ Data += BlockSize;
+ }
+
+ if ((Adapter->MediaBitmap == 0) && !(Adapter->Features &
DC_HAS_MII))
+ {
+ WARN("No media information found\n");
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+SRomShiftOut(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG Sequence,
+ _In_ ULONG BitCount)
+{
+ LONG i;
+
+ PAGED_CODE();
+
+ for (i = BitCount - 1; i >= 0; --i)
+ {
+ ULONG DataIn = ((Sequence >> i) & 1) << DC_SERIAL_EE_DI_SHIFT;
+
+ SROM_WRITE(Adapter, DataIn | DC_SERIAL_EE_RD | DC_SERIAL_EE_SR |
DC_SERIAL_EE_CS);
+ SROM_WRITE(Adapter, DataIn | DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS
|
+ DC_SERIAL_EE_SK);
+ SROM_WRITE(Adapter, DataIn | DC_SERIAL_EE_RD | DC_SERIAL_EE_SR |
DC_SERIAL_EE_CS);
+ }
+}
+
+static
+CODE_SEG("PAGE")
+USHORT
+SRomShiftIn(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ ULONG i, Csr;
+ USHORT SerialData;
+
+ PAGED_CODE();
+
+ /* Shift the data out of the EEPROM */
+ SerialData = 0;
+ for (i = 0; i < RTL_BITS_OF(USHORT); ++i)
+ {
+ SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS |
DC_SERIAL_EE_SK);
+
+ SROM_READ(Adapter, &Csr);
+ SerialData = (SerialData << 1) | ((Csr >> DC_SERIAL_EE_DO_SHIFT)
& 1);
+
+ SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS);
+ }
+
+ /* End the read cycle */
+ SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR);
+
+ return SerialData;
+}
+
+static
+CODE_SEG("PAGE")
+ULONG
+SRomDetectAddressBusWidth(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ ULONG Csr, BusWidth;
+
+ PAGED_CODE();
+
+ /* Assume the SROM is a 1kB ROM, send the read command and zero address (6 bits) */
+ SRomShiftOut(Adapter, EEPROM_CMD_READ << 6, EEPROM_CMD_LENGTH + 6);
+
+ /* Check the preceding dummy zero bit */
+ Csr = DC_READ(Adapter, DcCsr9_SerialInterface);
+ if (Csr & DC_SERIAL_EE_DO)
+ {
+ /* 4kB EEPROM */
+ BusWidth = 8;
+
+ /* Send the remaining part of the address */
+ SRomShiftOut(Adapter, 0, 8 - 6);
+
+ /* The preceding dummy bit must be zero */
+ Csr = DC_READ(Adapter, DcCsr9_SerialInterface);
+ if (Csr & DC_SERIAL_EE_DO)
+ return 0;
+ }
+ else
+ {
+ /* 1kB EEPROM */
+ BusWidth = 6;
+ }
+
+ /* Complete the read cycle */
+ (VOID)SRomShiftIn(Adapter);
+
+ return BusWidth;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+SRomReadSRom(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _Out_writes_all_(EE_SIZE) PVOID SRom)
+{
+ PUSHORT SRomWord = SRom;
+ BOOLEAN Success = TRUE;
+ ULONG BusWidth, Address;
+
+ PAGED_CODE();
+
+ /* Select the device */
+ SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR);
+ SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS);
+
+ BusWidth = SRomDetectAddressBusWidth(Adapter);
+ if (BusWidth == 0)
+ {
+ Success = FALSE;
+ goto Done;
+ }
+ INFO("SROM Bus width: %u\n", BusWidth);
+
+ /* Read the SROM contents once */
+ for (Address = 0; Address < (EE_SIZE / sizeof(USHORT)); ++Address)
+ {
+ /* Send the command and address */
+ SRomShiftOut(Adapter,
+ (EEPROM_CMD_READ << BusWidth) | Address,
+ EEPROM_CMD_LENGTH + BusWidth);
+
+ /* Read the data */
+ SRomWord[Address] = SRomShiftIn(Adapter);
+ }
+
+Done:
+ /* End chip select */
+ DC_WRITE(Adapter, DcCsr9_SerialInterface, 0);
+
+ return Success;
+}
+
+#if DBG
+static
+CODE_SEG("PAGE")
+VOID
+SRomDumpContents(
+ _In_reads_bytes_(Length) const VOID* Buffer,
+ _In_ ULONG Length)
+{
+ ULONG Offset, Count, i;
+ const UCHAR* Data = Buffer;
+
+ PAGED_CODE();
+
+ DbgPrint("SROM data:\n");
+
+ Offset = 0;
+ while (Offset < Length)
+ {
+ DbgPrint("%04x:\t", Offset);
+
+ Count = min(Length - Offset, 16);
+ for (i = 0; i < Count; ++i, ++Offset)
+ {
+ DbgPrint("0x%02x, ", Data[Offset], (i == 7) ? '-' : '
');
+ }
+
+ DbgPrint("\n");
+ }
+}
+#endif // DBG
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+SRomRead(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PDC_SROM_ENTRY SRomEntry;
+ NDIS_STATUS Status;
+ BOOLEAN ReleaseImage;
+
+ PAGED_CODE();
+
+ Status = NdisAllocateMemoryWithTag((PVOID*)&SRomEntry,
+ FIELD_OFFSET(DC_SROM_ENTRY, SRomImage[EE_SIZE]),
+ DC21X4_TAG);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return NDIS_STATUS_RESOURCES;
+ NdisZeroMemory(SRomEntry, FIELD_OFFSET(DC_SROM_ENTRY, SRomImage));
+
+ ReleaseImage = FALSE;
+
+ if (SRomReadSRom(Adapter, SRomEntry->SRomImage))
+ {
+ if (!SRomRegisterMasterAdapter(Adapter, SRomEntry))
+ ReleaseImage = TRUE;
+ }
+ else
+ {
+ NdisFreeMemory(SRomEntry, 0, 0);
+
+ if (!SRomFindMasterAdapter(Adapter, &SRomEntry))
+ {
+ ERR("Failed to retrieve the SROM contents\n");
+ return NDIS_STATUS_FAILURE;
+ }
+ }
+
+ Status = SRomParse(Adapter, SRomEntry->SRomImage);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ ERR("Failed to parse SROM\n");
+ }
+
+#if DBG
+ if (Status != NDIS_STATUS_SUCCESS)
+ SRomDumpContents(SRomEntry->SRomImage, EE_SIZE);
+#endif
+
+ if (ReleaseImage)
+ NdisFreeMemory(SRomEntry, 0, 0);
+
+ return Status;
+}
+
+static
+CODE_SEG("PAGE")
+BOOLEAN
+AddressRomReadData(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _Out_writes_all_(EAR_SIZE) PUCHAR AddressRom)
+{
+ ULONG Data, i, j;
+
+ PAGED_CODE();
+
+ /* Reset the ROM pointer */
+ DC_WRITE(Adapter, DcCsr9_SerialInterface, 0);
+
+ for (i = 0; i < EAR_SIZE; ++i)
+ {
+ for (j = 10000; j > 0; --j)
+ {
+ NdisStallExecution(1);
+ Data = DC_READ(Adapter, DcCsr9_SerialInterface);
+
+ if (!(Data & DC_SERIAL_EAR_DN))
+ break;
+ }
+ AddressRom[i] = Data & DC_SERIAL_EAR_DT;
+ }
+
+ if (SRomIsEmpty(AddressRom, EAR_SIZE))
+ return FALSE;
+
+ return TRUE;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+AddressRomRead(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PDC_SROM_ENTRY SRomEntry;
+ NDIS_STATUS Status;
+ BOOLEAN ReleaseImage;
+
+ PAGED_CODE();
+
+ Status = NdisAllocateMemoryWithTag((PVOID*)&SRomEntry,
+ FIELD_OFFSET(DC_SROM_ENTRY, SRomImage[EAR_SIZE]),
+ DC21X4_TAG);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return NDIS_STATUS_RESOURCES;
+ NdisZeroMemory(SRomEntry, FIELD_OFFSET(DC_SROM_ENTRY, SRomImage));
+
+ ReleaseImage = FALSE;
+
+ if (AddressRomReadData(Adapter, SRomEntry->SRomImage))
+ {
+ if (!SRomRegisterMasterAdapter(Adapter, SRomEntry))
+ ReleaseImage = TRUE;
+ }
+ else
+ {
+ NdisFreeMemory(SRomEntry, 0, 0);
+
+ if (!SRomFindMasterAdapter(Adapter, &SRomEntry))
+ {
+ ERR("Failed to retrieve the EAR contents\n");
+ return NDIS_STATUS_FAILURE;
+ }
+ }
+
+ if (!SRomReadMacAddress(Adapter, SRomEntry->SRomImage, NULL))
+ {
+ ERR("Unable to read the MAC address\n");
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ /* Update the base address on multiport boards */
+ Adapter->PermanentMacAddress[5] += Adapter->ControllerIndex;
+
+#if DBG
+ if (Status != NDIS_STATUS_SUCCESS)
+ SRomDumpContents(SRomEntry->SRomImage, EAR_SIZE);
+#endif
+
+ if (ReleaseImage)
+ NdisFreeMemory(SRomEntry, 0, 0);
+
+ return Status;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+CODE_SEG("PAGE")
+VOID
+DcFreeEeprom(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PDC_SROM_ENTRY SRomEntry;
+
+ PAGED_CODE();
+
+ SRomEntry = Adapter->SRomEntry;
+ if (!SRomEntry)
+ return;
+
+ SRomAcquireListMutex();
+
+ /* Unregister the port */
+ SRomEntry->DeviceBitmap &= ~(1 << Adapter->DeviceNumber);
+
+ /*
+ * Free the SROM as soon as the last registered port has removed.
+ * We can't free it in an unload handler
+ * as the bus numbers can be changed by a resource rebalance.
+ */
+ if (SRomEntry->DeviceBitmap == 0)
+ {
+ INFO("Freeing SROM %p at %u:%u\n",
+ SRomEntry,
+ SRomEntry->BusNumber,
+ SRomEntry->DeviceNumber);
+
+ RemoveEntryList(&SRomEntry->ListEntry);
+
+ NdisFreeMemory(SRomEntry, 0, 0);
+ }
+
+ SRomReleaseListMutex();
+}
+
+CODE_SEG("PAGE")
+NDIS_STATUS
+DcReadEeprom(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ NDIS_STATUS Status;
+
+ PAGED_CODE();
+
+ if (Adapter->ChipType == DC21040)
+ {
+ /* Ethernet Address ROM */
+ Status = AddressRomRead(Adapter);
+ }
+ else
+ {
+ /* MicroWire Compatible Serial EEPROM */
+ Status = SRomRead(Adapter);
+ }
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ INFO("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ Adapter->PermanentMacAddress[0],
+ Adapter->PermanentMacAddress[1],
+ Adapter->PermanentMacAddress[2],
+ Adapter->PermanentMacAddress[3],
+ Adapter->PermanentMacAddress[4],
+ Adapter->PermanentMacAddress[5]);
+
+ if (ETH_IS_BROADCAST(Adapter->PermanentMacAddress) ||
+ ETH_IS_EMPTY(Adapter->PermanentMacAddress) ||
+ ETH_IS_MULTICAST(Adapter->PermanentMacAddress))
+ {
+ ERR("Invalid permanent MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ Adapter->PermanentMacAddress[0],
+ Adapter->PermanentMacAddress[1],
+ Adapter->PermanentMacAddress[2],
+ Adapter->PermanentMacAddress[3],
+ Adapter->PermanentMacAddress[4],
+ Adapter->PermanentMacAddress[5]);
+
+ NdisWriteErrorLogEntry(Adapter->AdapterHandle,
NDIS_ERROR_CODE_NETWORK_ADDRESS, 0);
+
+ return NDIS_STATUS_INVALID_ADDRESS;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
diff --git a/drivers/network/dd/dc21x4/eeprom.h b/drivers/network/dd/dc21x4/eeprom.h
new file mode 100644
index 00000000000..58d44202def
--- /dev/null
+++ b/drivers/network/dd/dc21x4/eeprom.h
@@ -0,0 +1,108 @@
+/*
+ * PROJECT: ReactOS DC21x4 Driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: EEPROM specific definitions
+ * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean(a)protonmail.com>
+ */
+
+#pragma once
+
+#include <pshpack1.h>
+typedef struct _DC_SROM_COMPACT_BLOCK
+{
+ USHORT SelectedConnectionType;
+ UCHAR GpioDirection; /* 21140 only */
+ UCHAR BlockCount;
+} DC_SROM_COMPACT_BLOCK, *PDC_SROM_COMPACT_BLOCK;
+#include <poppack.h>
+
+typedef struct _DC_SROM_REPAIR_ENTRY
+{
+#if DBG
+ PCSTR Name;
+#endif
+ PUCHAR InfoLeaf;
+ ULONG Length;
+} DC_SROM_REPAIR_ENTRY, *PDC_SROM_REPAIR_ENTRY;
+
+typedef struct _DC_SROM_ENTRY
+{
+ LIST_ENTRY ListEntry;
+ ULONG BusNumber;
+ DC_CHIP_TYPE ChipType;
+ UCHAR DeviceNumber;
+ ULONG InterruptLevel;
+ ULONG InterruptVector;
+ ULONG DeviceBitmap;
+ UCHAR SRomImage[ANYSIZE_ARRAY];
+} DC_SROM_ENTRY, *PDC_SROM_ENTRY;
+
+#define SRomIsBlockExtended(Byte) ((Byte) & 0x80)
+#define SRomGetExtendedBlockLength(Byte) (((Byte) & 0x7F) + 1)
+#define SRomGetMediaCode(Byte) ((Byte) & 0x3F)
+#define SRomBlockHasExtendedData(Byte) ((Byte) & 0x40)
+#define SRomIsDefaultMedia(Word) ((Word) & 0x4000)
+#define SRomMediaHasActivityIndicator(Word) (((Word) & 0x8000) == 0)
+#define SRomMediaActivityIsActiveLow(Word) ((Word) & 0x80)
+#define SRomMediaGetSenseMask(Word) (1 << (((Word) & 0x0E) >>
1))
+#define SRomCommandToOpMode(Word) (((Word) & 0x71) << 18)
+#define SRomMediaAutoSense(Media) ((Media) & 0x800)
+#define SRomMediaToMediaNumber(Word) ((Word) & 0x1F)
+#define SRomHmrRegAddress(Byte) ((Byte) & 0x1F)
+
+#define SROM_OPMODE_MASK \
+ (DC_OPMODE_PORT_SELECT | \
+ DC_OPMODE_PORT_XMIT_10 | \
+ DC_OPMODE_PORT_PCS | \
+ DC_OPMODE_PORT_SCRAMBLER)
+
+#define EE_SIZE 128
+#define EAR_SIZE 32
+
+#define EAR_TEST_PATTERN 0xAA5500FFAA5500FFULL
+
+#define EEPROM_CMD_WRITE 5
+#define EEPROM_CMD_READ 6
+#define EEPROM_CMD_ERASE 7
+
+#define EEPROM_CMD_LENGTH 3
+
+/*
+ * Various offsets in the SROM
+ */
+#define SROM_VERSION 18
+#define SROM_CONTROLLER_COUNT 19
+#define SROM_MAC_ADDRESS 20
+#define SROM_DEVICE_NUMBER(n) (26 + ((n) * 3))
+#define SROM_LEAF_OFFSET(n) (27 + ((n) * 3))
+#define SROM_CHECKSUM_V1 126
+#define SROM_CHECKSUM_V2 94
+
+/*
+ * SROM compact and extended format types
+ */
+#define SROM_BLOCK_TYPE_GPR 0
+#define SROM_BLOCK_TYPE_MII_1 1
+#define SROM_BLOCK_TYPE_SIA 2
+#define SROM_BLOCK_TYPE_MII_2 3
+#define SROM_BLOCK_TYPE_SYM 4
+#define SROM_BLOCK_TYPE_RESET 5
+#define SROM_BLOCK_TYPE_PHY_SHUTDOWN 6
+#define SROM_BLOCK_TYPE_HOMERUN 7
+
+#define SROM_MAX_STREAM_REGS 6
+
+/*
+ * SROM media codes
+ */
+#define SROM_MEDIA_10T 0
+#define SROM_MEDIA_BNC 1
+#define SROM_MEDIA_AUI 2
+#define SROM_MEDIA_100T_HD 3
+#define SROM_MEDIA_10T_FD 4
+#define SROM_MEDIA_100TX_FD 5
+#define SROM_MEDIA_100T4 6
+#define SROM_MEDIA_100FX_HD 7
+#define SROM_MEDIA_100FX_FD 8
+#define SROM_MEDIA_MAX 8
+#define SROM_MEDIA_HMR 18
diff --git a/drivers/network/dd/dc21x4/eeprom_data.c
b/drivers/network/dd/dc21x4/eeprom_data.c
new file mode 100644
index 00000000000..f00f80b293d
--- /dev/null
+++ b/drivers/network/dd/dc21x4/eeprom_data.c
@@ -0,0 +1,219 @@
+/*
+ * PROJECT: ReactOS DC21x4 Driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: EEPROM data for boards without the standard SROM Format
+ * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean(a)protonmail.com>
+ */
+
+/* Adapted from the Linux tulip driver written by Donald Becker */
+
+/* INCLUDES *******************************************************************/
+
+#include "dc21x4.h"
+
+/* GLOBALS ********************************************************************/
+
+/* Asante */
+static DC_PG_DATA UCHAR SRompLeafAsante[] =
+{
+ 0x00, 0x00, 0x94,
+
+ 0x00, 0x08, // Default Autoselect
+ 0x00, // GPIO direction
+ 0x01, // 1 block
+
+ 0x80 + 12, // Extended block, 12 bytes
+ 0x01, // MII
+ 0x00, // PHY #0
+ 0x00, // GPIO stream length
+ 0x00, // Reset stream length
+ 0x00, 0x78, // Capabilities
+ 0xE0, 0x01, // Advertisement
+ 0x00, 0x50, // FDX
+ 0x00, 0x18, // TTM
+};
+
+/* SMC 9332DST */
+static DC_PG_DATA UCHAR SRompLeaf9332[] =
+{
+ 0x00, 0x00, 0xC0,
+
+ 0x00, 0x08, // Default Autoselect
+ 0x1F, // GPIO direction
+ 0x04, // 4 blocks
+
+ 0x00, // GPR 0
+ 0x00, // GPIO data
+ 0x9E, 0x00, // Command 0x009E
+
+ 0x04, // GPR 4
+ 0x00, // GPIO data
+ 0x9E, 0x00, // Command 0x009E
+ 0x03, // GPR 3
+ 0x09, // GPIO data
+ 0x6D, 0x00, // Command 0x006D
+
+ 0x05, // GPR 5
+ 0x09, // GPIO data
+ 0x6D, 0x00, // Command 0x006D
+};
+
+/* Cogent EM100 */
+static DC_PG_DATA UCHAR SRompLeafEm100[] =
+{
+ 0x00, 0x00, 0x92,
+
+ 0x00, 0x08, // Default Autoselect
+ 0x3F, // GPIO direction
+ 0x06, // 6 blocks
+
+ 0x07, // GPR 7
+ 0x01, // GPIO data
+ 0x21, 0x80, // Command 0x8021
+
+ 0x08, // GPR 8
+ 0x01, // GPIO data
+ 0x21, 0x80, // Command 0x8021
+
+ 0x00, // GPR 0
+ 0x01, // GPIO data
+ 0x9E, 0x00, // Command 0x009E
+
+ 0x04, // GPR 4
+ 0x01, // GPIO data
+ 0x9E, 0x00, // Command 0x009E
+
+ 0x03, // GPR 3
+ 0x01, // GPIO data
+ 0x6D, 0x00, // Command 0x006D
+
+ 0x05, // GPR 5
+ 0x01, // GPIO data
+ 0x6D, 0x00, // Command 0x006D
+};
+
+/* Maxtech NX-110 */
+static DC_PG_DATA UCHAR SRompLeafNx110[] =
+{
+ 0x00, 0x00, 0xE8,
+
+ 0x00, 0x08, // Default Autoselect
+ 0x13, // GPIO direction
+ 0x05, // 5 blocks
+
+ 0x01, // GPR 1
+ 0x10, // GPIO data
+ 0x9E, 0x00, // Command 0x009E
+
+ 0x00, // GPR 0
+ 0x00, // GPIO data
+ 0x9E, 0x00, // Command 0x009E
+
+ 0x04, // GPR 4
+ 0x00, // GPIO data
+ 0x9E, 0x00, // Command 0x009E
+
+ 0x03, // GPR 3
+ 0x03, // GPIO data
+ 0x6D, 0x00, // Command 0x006D
+
+ 0x05, // GPR 5
+ 0x03, // GPIO data
+ 0x6D, 0x00, // Command 0x006D
+};
+
+/* Accton EN1207 */
+static DC_PG_DATA UCHAR SRompLeafEn1207[] =
+{
+ 0x00, 0x00, 0xE8,
+
+ 0x00, 0x08, // Default Autoselect
+ 0x1F, // GPIO direction
+ 0x05, // 5 blocks
+
+ 0x01, // GPR 1
+ 0x1B, // GPIO data
+ 0x00, 0x00, // Command 0x0000
+
+ 0x00, // GPR 0
+ 0x0B, // GPIO data
+ 0x9E, 0x00, // Command 0x009E
+
+ 0x04, // GPR 4
+ 0x0B, // GPIO data
+ 0x9E, 0x00, // Command 0x009E
+
+ 0x03, // GPR 3
+ 0x1B, // GPIO data
+ 0x6D, 0x00, // Command 0x006D
+
+ 0x05, // GPR 5
+ 0x1B, // GPIO data
+ 0x6D, 0x00, // Command 0x006D
+};
+
+/* NetWinder */
+static DC_PG_DATA UCHAR SRompLeafNetWinder[] =
+{
+ 0x00, 0x10, 0x57,
+
+ 0x00, 0x08, // Default Autoselect
+ 0x01, // 1 block
+
+ 0x80 + 21, // Extended block, 21 bytes
+ 0x03, // MII
+ 0x01, // PHY #1
+ 0x00, // GPIO stream length
+ 0x03, // Reset stream length
+ 0x21, 0x08,
+ 0x00, 0x00,
+ 0x01, 0x00,
+ 0x00, 0x00, // Capabilities
+ 0xE1, 0x01, // Advertisement
+ 0x00, 0x00, // FDX
+ 0x00, 0x00, // TTM
+ 0x00, // PHY cannot be unplugged
+};
+
+/* Cobalt Microserver */
+static DC_PG_DATA UCHAR SRompLeafCobaltMicroserver[] =
+{
+ 0x00, 0x10, 0xE0,
+
+ 0x00, 0x08, // Default Autoselect
+ 0x01, // 1 block
+
+ 0x80 + 21, // Extended block, 21 bytes
+ 0x03, // MII
+ 0x00, // PHY #0
+ 0x00, // GPIO stream length
+ 0x04, // Reset stream length
+ 0x01, 0x08, // Set control mode, GP0 output
+ 0x00, 0x00, // Drive GP0 Low (RST is active low)
+ 0x00, 0x08, // Control mode, GP0 input (undriven)
+ 0x00, 0x00, // Clear control mode
+ 0x00, 0x78, // Capabilities: 100TX FDX + HDX, 10bT FDX + HDX
+ 0xE0, 0x01, // Advertise all above
+ 0x00, 0x50, // FDX all above
+ 0x00, 0x18, // Set fast TTM in 100bt modes
+ 0x00, // PHY cannot be unplugged
+};
+
+#if DBG
+#define DEFINE_BOARD(Leaf, Name) { Name, Leaf, sizeof(Leaf) - 3 /* OUI (3 bytes) */}
+#else
+#define DEFINE_BOARD(Leaf, Name) { Leaf, sizeof(Leaf) - 3 }
+#endif
+
+DC_PG_DATA
+DC_SROM_REPAIR_ENTRY SRompRepairData[] =
+{
+ DEFINE_BOARD(SRompLeafAsante, "Asante"),
+ DEFINE_BOARD(SRompLeaf9332, "SMC 9332DST"),
+ DEFINE_BOARD(SRompLeafEm100, "Cogent EM100"),
+ DEFINE_BOARD(SRompLeafNx110, "Maxtech NX-110"),
+ DEFINE_BOARD(SRompLeafEn1207, "Accton EN1207"), // Must be defined after
the NX-110
+ DEFINE_BOARD(SRompLeafNetWinder, "NetWinder"),
+ DEFINE_BOARD(SRompLeafCobaltMicroserver, "Cobalt Microserver"),
+ DEFINE_BOARD(NULL, NULL),
+};
diff --git a/drivers/network/dd/dc21x4/hardware.c b/drivers/network/dd/dc21x4/hardware.c
new file mode 100644
index 00000000000..971c10d6d1a
--- /dev/null
+++ b/drivers/network/dd/dc21x4/hardware.c
@@ -0,0 +1,585 @@
+/*
+ * PROJECT: ReactOS DC21x4 Driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Hardware specific functions
+ * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean(a)protonmail.com>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include "dc21x4.h"
+
+#include <debug.h>
+
+/* FUNCTIONS ******************************************************************/
+
+VOID
+DcDisableHw(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ ULONG OpMode;
+
+ /* Disable interrupts */
+ DC_WRITE(Adapter, DcCsr7_IrqMask, 0);
+
+ /* Stop DMA */
+ OpMode = Adapter->OpMode;
+ OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE);
+ DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
+
+ /* Put the adapter to snooze mode */
+ DcPowerSave(Adapter, TRUE);
+
+ /* Perform a software reset */
+ DC_WRITE(Adapter, DcCsr0_BusMode, DC_BUS_MODE_SOFT_RESET);
+}
+
+VOID
+DcStopTxRxProcess(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ ULONG i, OpMode, Status;
+
+ OpMode = Adapter->OpMode;
+ OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE);
+ DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
+
+ for (i = 0; i < 5000; ++i)
+ {
+ Status = DC_READ(Adapter, DcCsr5_Status);
+
+ if (((Status & DC_STATUS_TX_STATE_MASK) == DC_STATUS_TX_STATE_STOPPED)
&&
+ ((Status & DC_STATUS_RX_STATE_MASK) == DC_STATUS_RX_STATE_STOPPED))
+ {
+ return;
+ }
+
+ NdisStallExecution(10);
+ }
+
+ WARN("Failed to stop the TX/RX process 0x%08lx\n", Status);
+}
+
+VOID
+DcWriteGpio(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG Value)
+{
+ ULONG Data, Register;
+
+ /* Some chips don't have a separate GPIO register */
+ if (Adapter->Features & DC_SIA_GPIO)
+ {
+ Data = Adapter->SiaSetting;
+ Data &= 0x0000FFFF; /* SIA */
+ Data |= Value << 16; /* GPIO */
+ Adapter->SiaSetting = Data;
+
+ Register = DcCsr15_SiaGeneral;
+ }
+ else
+ {
+ Data = Value;
+ Register = DcCsr12_Gpio;
+ }
+ DC_WRITE(Adapter, Register, Data);
+}
+
+VOID
+DcWriteSia(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG Csr13,
+ _In_ ULONG Csr14,
+ _In_ ULONG Csr15)
+{
+ ULONG SiaConn, SiaGen;
+
+ TRACE("CSR13 %08lx, CSR14 %08lx, CSR15 %08lx\n", Csr13, Csr14, Csr15);
+
+ SiaConn = 0;
+
+ /* The 21145 comes with 16 new bits in CSR13 */
+ if (Adapter->Features & DC_SIA_ANALOG_CONTROL)
+ {
+ SiaConn = Adapter->AnalogControl;
+ }
+
+ /* Reset the transceiver */
+ DC_WRITE(Adapter, DcCsr13_SiaConnectivity, SiaConn | DC_SIA_CONN_RESET);
+ NdisStallExecution(20);
+
+ /* Some chips don't have a separate GPIO register */
+ if (Adapter->Features & DC_SIA_GPIO)
+ {
+ SiaGen = Adapter->SiaSetting;
+ SiaGen &= 0xFFFF0000; /* GPIO */
+ SiaGen |= Csr15; /* SIA */
+ Adapter->SiaSetting = SiaGen;
+ }
+ else
+ {
+ SiaGen = Csr15;
+ }
+
+ DC_WRITE(Adapter, DcCsr14_SiaTxRx, Csr14);
+ DC_WRITE(Adapter, DcCsr15_SiaGeneral, SiaGen);
+
+ /* Don't reset the transceiver twice */
+ if (Csr13 == DC_SIA_CONN_RESET)
+ return;
+
+ DC_WRITE(Adapter, DcCsr13_SiaConnectivity, SiaConn | Csr13);
+}
+
+VOID
+DcTestPacket(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PDC_TCB Tcb;
+ PDC_TBD Tbd;
+ ULONG FrameNumber;
+
+ Adapter->MediaTestStatus = FALSE;
+ Adapter->ModeFlags |= DC_MODE_TEST_PACKET;
+
+ if (!Adapter->LoopbackFrameSlots)
+ {
+ ERR("Failed to complete test packets, CSR12 %08lx, CSR5 %08lx\n",
+ DC_READ(Adapter, DcCsr12_SiaStatus),
+ DC_READ(Adapter, DcCsr5_Status));
+
+ /* Try to recover the lost TX buffers */
+ NdisScheduleWorkItem(&Adapter->TxRecoveryWorkItem);
+ return;
+ }
+
+ --Adapter->LoopbackFrameSlots;
+
+ FrameNumber = (Adapter->LoopbackFrameNumber++) % DC_LOOPBACK_FRAMES;
+
+ Tbd = Adapter->CurrentTbd;
+ Adapter->CurrentTbd = DC_NEXT_TBD(Adapter, Tbd);
+
+ Tcb = Adapter->CurrentTcb;
+ Adapter->CurrentTcb = DC_NEXT_TCB(Adapter, Tcb);
+
+ Tcb->Tbd = Tbd;
+ Tcb->Packet = NULL;
+
+ ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED));
+
+ /* Put the loopback frame on the transmit ring */
+ Tbd->Address1 = Adapter->LoopbackFramePhys[FrameNumber];
+ Tbd->Address2 = 0;
+ Tbd->Control &= DC_TBD_CONTROL_END_OF_RING;
+ Tbd->Control |= DC_LOOPBACK_FRAME_SIZE |
+ DC_TBD_CONTROL_FIRST_FRAGMENT |
+ DC_TBD_CONTROL_LAST_FRAGMENT |
+ DC_TBD_CONTROL_REQUEST_INTERRUPT;
+ DC_WRITE_BARRIER();
+ Tbd->Status = DC_TBD_STATUS_OWNED;
+
+ /* Send the loopback packet to verify connectivity of a media */
+ DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL);
+}
+
+BOOLEAN
+DcSetupFrameDownload(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ BOOLEAN WaitForCompletion)
+{
+ PDC_TCB Tcb;
+ PDC_TBD Tbd;
+ ULONG i, Control;
+
+ Tbd = Adapter->CurrentTbd;
+
+ /* Ensure correct setup frame processing */
+ if (Tbd != Adapter->HeadTbd)
+ {
+ ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED));
+
+ /* Put the null frame on the transmit ring */
+ Tbd->Control &= DC_TBD_CONTROL_END_OF_RING;
+ Tbd->Address1 = 0;
+ Tbd->Address2 = 0;
+ DC_WRITE_BARRIER();
+ Tbd->Status = DC_TBD_STATUS_OWNED;
+
+ Tbd = DC_NEXT_TBD(Adapter, Tbd);
+ }
+
+ Adapter->CurrentTbd = DC_NEXT_TBD(Adapter, Tbd);
+
+ Tcb = Adapter->CurrentTcb;
+ Adapter->CurrentTcb = DC_NEXT_TCB(Adapter, Tcb);
+
+ Tcb->Tbd = Tbd;
+ Tcb->Packet = NULL;
+
+ ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED));
+
+ /* Prepare the setup frame */
+ Tbd->Address1 = Adapter->SetupFramePhys;
+ Tbd->Address2 = 0;
+ Tbd->Control &= DC_TBD_CONTROL_END_OF_RING;
+ Control = DC_SETUP_FRAME_SIZE | DC_TBD_CONTROL_SETUP_FRAME;
+ if (!WaitForCompletion)
+ Control |= DC_TBD_CONTROL_REQUEST_INTERRUPT;
+ if (Adapter->ProgramHashPerfectFilter)
+ Control |= DC_TBD_CONTROL_HASH_PERFECT_FILTER;
+ Tbd->Control |= Control;
+ DC_WRITE_BARRIER();
+ Tbd->Status = DC_TBD_STATUS_OWNED;
+
+ DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL);
+
+ if (!WaitForCompletion)
+ return TRUE;
+
+ /* Wait up to 500 ms for the chip to process the setup frame */
+ for (i = 50000; i > 0; --i)
+ {
+ NdisStallExecution(10);
+
+ KeMemoryBarrierWithoutFence();
+ if (!(Tbd->Status & DC_TBD_STATUS_OWNED))
+ break;
+ }
+ if (i == 0)
+ {
+ ERR("Failed to complete setup frame %08lx\n", Tbd->Status);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+CODE_SEG("PAGE")
+VOID
+DcSetupFrameInitialize(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PULONG SetupFrame, SetupFrameStart;
+ PUSHORT MacAddress;
+ ULONG i;
+
+ PAGED_CODE();
+
+ SetupFrame = Adapter->SetupFrame;
+
+ /* Add the physical address entry */
+ MacAddress = (PUSHORT)Adapter->CurrentMacAddress;
+ *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]);
+ *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]);
+ *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]);
+
+ /* Pad to 16 addresses */
+ SetupFrameStart = Adapter->SetupFrame;
+ for (i = 1; i < DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES; ++i)
+ {
+ *SetupFrame++ = SetupFrameStart[0];
+ *SetupFrame++ = SetupFrameStart[1];
+ *SetupFrame++ = SetupFrameStart[2];
+ }
+}
+
+static
+VOID
+DcSetupFramePerfectFiltering(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PULONG SetupFrame, SetupFrameStart;
+ PUSHORT MacAddress;
+ ULONG i;
+
+ SetupFrame = Adapter->SetupFrame;
+
+ /* Add the physical address entry */
+ MacAddress = (PUSHORT)Adapter->CurrentMacAddress;
+ *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]);
+ *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]);
+ *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]);
+
+ /* Store multicast addresses */
+ for (i = 0; i < Adapter->MulticastCount; ++i)
+ {
+ MacAddress = (PUSHORT)Adapter->MulticastList[i].MacAddress;
+
+ *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]);
+ *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]);
+ *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]);
+ }
+
+ ++i;
+
+ /* Add the broadcast address entry */
+ if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
+ {
+ *SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF);
+ *SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF);
+ *SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF);
+
+ ++i;
+ }
+
+ /* Pad to 16 addresses */
+ SetupFrameStart = Adapter->SetupFrame;
+ while (i < DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES)
+ {
+ *SetupFrame++ = SetupFrameStart[0];
+ *SetupFrame++ = SetupFrameStart[1];
+ *SetupFrame++ = SetupFrameStart[2];
+
+ ++i;
+ }
+}
+
+static
+VOID
+DcSetupFrameImperfectFiltering(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PULONG SetupFrame = Adapter->SetupFrame;
+ PUSHORT MacAddress;
+ ULONG Hash, i;
+
+ RtlZeroMemory(SetupFrame, DC_SETUP_FRAME_SIZE);
+
+ /* Fill up the 512-bit multicast hash table */
+ for (i = 0; i < Adapter->MulticastCount; ++i)
+ {
+ MacAddress = (PUSHORT)Adapter->MulticastList[i].MacAddress;
+
+ /* Only need lower 9 bits of the hash */
+ Hash = DcEthernetCrc(MacAddress, ETH_LENGTH_OF_ADDRESS);
+ Hash &= 512 - 1;
+ SetupFrame[Hash / 16] |= 1 << (Hash % 16);
+ }
+
+ /* Insert the broadcast address hash to the bin */
+ if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
+ {
+ Hash = DC_SETUP_FRAME_BROADCAST_HASH;
+ SetupFrame[Hash / 16] |= 1 << (Hash % 16);
+ }
+
+ /* Add the physical address entry */
+ MacAddress = (PUSHORT)Adapter->CurrentMacAddress;
+ SetupFrame[39] = DC_SETUP_FRAME_ENTRY(MacAddress[0]);
+ SetupFrame[40] = DC_SETUP_FRAME_ENTRY(MacAddress[1]);
+ SetupFrame[41] = DC_SETUP_FRAME_ENTRY(MacAddress[2]);
+}
+
+NDIS_STATUS
+DcUpdateMulticastList(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ BOOLEAN UsePerfectFiltering;
+
+ /* If more than 14 addresses are requested, switch to hash filtering mode */
+ UsePerfectFiltering = (Adapter->MulticastCount <= DC_SETUP_FRAME_ADDRESSES);
+
+ Adapter->ProgramHashPerfectFilter = UsePerfectFiltering;
+ Adapter->OidPending = TRUE;
+
+ if (UsePerfectFiltering)
+ DcSetupFramePerfectFiltering(Adapter);
+ else
+ DcSetupFrameImperfectFiltering(Adapter);
+
+ NdisAcquireSpinLock(&Adapter->SendLock);
+
+ DcSetupFrameDownload(Adapter, FALSE);
+
+ NdisReleaseSpinLock(&Adapter->SendLock);
+
+ return NDIS_STATUS_PENDING;
+}
+
+NDIS_STATUS
+DcApplyPacketFilter(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ ULONG PacketFilter)
+{
+ ULONG OpMode, OldPacketFilter;
+
+ INFO("Packet filter value 0x%lx\n", PacketFilter);
+
+ NdisAcquireSpinLock(&Adapter->ModeLock);
+
+ /* Update the filtering mode */
+ OpMode = Adapter->OpMode;
+ OpMode &= ~(DC_OPMODE_RX_PROMISCUOUS | DC_OPMODE_RX_ALL_MULTICAST);
+ if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ {
+ OpMode |= DC_OPMODE_RX_PROMISCUOUS;
+ }
+ else if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
+ {
+ OpMode |= DC_OPMODE_RX_ALL_MULTICAST;
+ }
+ Adapter->OpMode = OpMode;
+ DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
+
+ NdisReleaseSpinLock(&Adapter->ModeLock);
+
+ OldPacketFilter = Adapter->PacketFilter;
+ Adapter->PacketFilter = PacketFilter;
+
+ /* Program the NIC to receive or reject broadcast frames */
+ if ((OldPacketFilter ^ PacketFilter) & NDIS_PACKET_TYPE_BROADCAST)
+ {
+ return DcUpdateMulticastList(Adapter);
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+DcSoftReset(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PAGED_CODE();
+
+ /* Linux driver does this */
+ if (Adapter->Features & DC_HAS_MII)
+ {
+ /* Select the MII/SYM port */
+ DC_WRITE(Adapter, DcCsr6_OpMode, DC_OPMODE_PORT_SELECT);
+ }
+
+ /* Perform a software reset */
+ DC_WRITE(Adapter, DcCsr0_BusMode, DC_BUS_MODE_SOFT_RESET);
+ NdisMSleep(100);
+ DC_WRITE(Adapter, DcCsr0_BusMode, Adapter->BusMode);
+}
+
+CODE_SEG("PAGE")
+NDIS_STATUS
+DcSetupAdapter(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PAGED_CODE();
+
+ DcInitTxRing(Adapter);
+ DcInitRxRing(Adapter);
+
+ /* Initial values */
+ if (!MEDIA_IS_FIXED(Adapter))
+ {
+ Adapter->LinkSpeedMbps = 10;
+ }
+ Adapter->MediaNumber = Adapter->DefaultMedia;
+ Adapter->ModeFlags &= ~(DC_MODE_PORT_AUTOSENSE | DC_MODE_AUI_FAILED |
DC_MODE_BNC_FAILED |
+ DC_MODE_TEST_PACKET | DC_MODE_AUTONEG_MASK);
+
+ DcSoftReset(Adapter);
+
+ /* Receive descriptor ring buffer */
+ DC_WRITE(Adapter, DcCsr3_RxRingAddress, Adapter->RbdPhys);
+
+ /* Transmit descriptor ring buffer */
+ DC_WRITE(Adapter, DcCsr4_TxRingAddress, Adapter->TbdPhys);
+
+ switch (Adapter->ChipType)
+ {
+ case DC21040:
+ {
+ DcWriteSia(Adapter,
+ Adapter->Media[Adapter->MediaNumber].Csr13,
+ Adapter->Media[Adapter->MediaNumber].Csr14,
+ Adapter->Media[Adapter->MediaNumber].Csr15);
+
+ /* Explicitly specifed by user */
+ if (Adapter->MediaNumber == MEDIA_10T_FD)
+ {
+ Adapter->OpMode |= DC_OPMODE_FULL_DUPLEX;
+ }
+ break;
+ }
+
+ case DC21041:
+ {
+ MediaSiaSelect(Adapter);
+ break;
+ }
+
+ case DC21140:
+ {
+ if (Adapter->MediaNumber == MEDIA_MII)
+ {
+ MediaSelectMiiPort(Adapter, !(Adapter->Flags & DC_FIRST_SETUP));
+ MediaMiiSelect(Adapter);
+ }
+ else
+ {
+ /* All media use the same GPIO directon */
+ DC_WRITE(Adapter, DcCsr12_Gpio,
Adapter->Media[Adapter->MediaNumber].GpioCtrl);
+ NdisStallExecution(10);
+
+ MediaGprSelect(Adapter);
+ }
+ break;
+ }
+
+ case DC21143:
+ case DC21145:
+ {
+ /* Init the HPNA PHY */
+ if ((Adapter->MediaBitmap & (1 << MEDIA_HMR)) &&
Adapter->HpnaInitBitmap)
+ {
+ HpnaPhyInit(Adapter);
+ }
+
+ if (Adapter->MediaNumber == MEDIA_MII)
+ {
+ MediaSelectMiiPort(Adapter, !(Adapter->Flags & DC_FIRST_SETUP));
+ MediaMiiSelect(Adapter);
+ break;
+ }
+
+ /* If the current media is FX, assume we have a link */
+ if (MEDIA_IS_FX(Adapter->MediaNumber))
+ {
+ Adapter->LinkUp = TRUE;
+
+ NdisMIndicateStatus(Adapter->AdapterHandle,
+ NDIS_STATUS_MEDIA_CONNECT,
+ NULL,
+ 0);
+ NdisMIndicateStatusComplete(Adapter->AdapterHandle);
+ }
+
+ MediaSiaSelect(Adapter);
+ break;
+ }
+
+ default:
+ ASSERT(FALSE);
+ UNREACHABLE;
+ break;
+ }
+
+ /* Start the TX process */
+ Adapter->OpMode |= DC_OPMODE_TX_ENABLE;
+ DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
+
+ /* Load the address recognition RAM */
+ if (!DcSetupFrameDownload(Adapter, TRUE))
+ {
+ /* This normally should not happen */
+ ASSERT(FALSE);
+
+ NdisWriteErrorLogEntry(Adapter->AdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 1,
+ __LINE__);
+
+ return NDIS_STATUS_HARD_ERRORS;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
diff --git a/drivers/network/dd/dc21x4/init.c b/drivers/network/dd/dc21x4/init.c
new file mode 100644
index 00000000000..1bcec4d9a65
--- /dev/null
+++ b/drivers/network/dd/dc21x4/init.c
@@ -0,0 +1,1321 @@
+/*
+ * PROJECT: ReactOS DC21x4 Driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Miniport initialization helper routines
+ * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean(a)protonmail.com>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include "dc21x4.h"
+
+#include <debug.h>
+
+/* GLOBALS ********************************************************************/
+
+/*
+ * The driver must align the buffers on a 4 byte boundary to meet the hardware
requirement.
+ * We stick with cache alignment to get better performance.
+ */
+C_ASSERT((SYSTEM_CACHE_ALIGNMENT_SIZE % DC_RECEIVE_BUFFER_ALIGNMENT) == 0);
+C_ASSERT((SYSTEM_CACHE_ALIGNMENT_SIZE % DC_DESCRIPTOR_ALIGNMENT) == 0);
+C_ASSERT((SYSTEM_CACHE_ALIGNMENT_SIZE % DC_SETUP_FRAME_ALIGNMENT) == 0);
+
+/* Errata: The end of receive buffer must not fall on a cache boundary */
+#define DC_RECEIVE_BUFFER_SIZE (DC_RECEIVE_BLOCK_SIZE - 4)
+C_ASSERT((DC_RECEIVE_BUFFER_SIZE % 32) != 0);
+
+#define DC_MEM_BLOCK_SIZE_RCB \
+ (DC_RECEIVE_BLOCK_SIZE + SYSTEM_CACHE_ALIGNMENT_SIZE - 1)
+
+#define DC_MEM_BLOCK_SIZE_RBD \
+ (sizeof(DC_RBD) * DC_RECEIVE_BUFFERS_DEFAULT + SYSTEM_CACHE_ALIGNMENT_SIZE - 1)
+
+#define DC_MEM_BLOCK_SIZE_TBD_AUX \
+ (sizeof(DC_TBD) * DC_TRANSMIT_DESCRIPTORS + SYSTEM_CACHE_ALIGNMENT_SIZE - 1 + \
+ DC_SETUP_FRAME_SIZE + SYSTEM_CACHE_ALIGNMENT_SIZE - 1 + \
+ DC_LOOPBACK_FRAME_SIZE * DC_LOOPBACK_FRAMES + SYSTEM_CACHE_ALIGNMENT_SIZE - 1)
+
+#define DC_MEM_BLOCK_SIZE_TX_BUFFER \
+ (DC_TRANSMIT_BLOCK_SIZE + SYSTEM_CACHE_ALIGNMENT_SIZE - 1)
+
+/* FUNCTIONS ******************************************************************/
+
+static
+CODE_SEG("PAGE")
+VOID
+DcConfigQueryInteger(
+ _In_ NDIS_HANDLE ConfigurationHandle,
+ _In_ PCWSTR EntryName,
+ _Out_ PULONG EntryContext,
+ _In_ ULONG DefaultValue,
+ _In_ ULONG Minimum,
+ _In_ ULONG Maximum)
+{
+ NDIS_STATUS Status;
+ UNICODE_STRING Keyword;
+ PNDIS_CONFIGURATION_PARAMETER ConfigurationParameter;
+
+ PAGED_CODE();
+
+ NdisInitUnicodeString(&Keyword, EntryName);
+ NdisReadConfiguration(&Status,
+ &ConfigurationParameter,
+ ConfigurationHandle,
+ &Keyword,
+ NdisParameterInteger);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ TRACE("'%S' request failed, default value %u\n", EntryName,
DefaultValue);
+
+ *EntryContext = DefaultValue;
+ return;
+ }
+
+ if (ConfigurationParameter->ParameterData.IntegerData >= Minimum &&
+ ConfigurationParameter->ParameterData.IntegerData <= Maximum)
+ {
+ *EntryContext = ConfigurationParameter->ParameterData.IntegerData;
+ }
+ else
+ {
+ WARN("'%S' value out of range\n", EntryName);
+
+ *EntryContext = DefaultValue;
+ }
+
+ TRACE("Set '%S' to %u\n", EntryName, *EntryContext);
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+DcReadConfiguration(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ NDIS_STATUS Status;
+ NDIS_HANDLE ConfigurationHandle;
+ PUCHAR NetworkAddress;
+ UINT Length;
+ ULONG GenericUlong;
+
+ PAGED_CODE();
+
+ NdisOpenConfiguration(&Status,
+ &ConfigurationHandle,
+ Adapter->WrapperConfigurationHandle);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ DcConfigQueryInteger(ConfigurationHandle,
+ L"SpeedDuplex",
+ &GenericUlong,
+ MEDIA_AUTO,
+ MEDIA_10T,
+ MEDIA_HMR);
+ Adapter->DefaultMedia = GenericUlong;
+
+ NdisReadNetworkAddress(&Status,
+ (PVOID*)&NetworkAddress,
+ &Length,
+ ConfigurationHandle);
+ if ((Status == NDIS_STATUS_SUCCESS) && (Length == ETH_LENGTH_OF_ADDRESS))
+ {
+ if (ETH_IS_MULTICAST(NetworkAddress) ||
+ ETH_IS_EMPTY(NetworkAddress) ||
+ ETH_IS_BROADCAST(NetworkAddress) ||
+ !ETH_IS_LOCALLY_ADMINISTERED(NetworkAddress))
+ {
+ ERR("Invalid software MAC address:
%02x:%02x:%02x:%02x:%02x:%02x\n",
+ NetworkAddress[0],
+ NetworkAddress[1],
+ NetworkAddress[2],
+ NetworkAddress[3],
+ NetworkAddress[4],
+ NetworkAddress[5]);
+ }
+ else
+ {
+ INFO("Using software MAC address\n");
+
+ /* Override the MAC address */
+ NdisMoveMemory(Adapter->CurrentMacAddress, NetworkAddress,
ETH_LENGTH_OF_ADDRESS);
+ }
+ }
+
+ NdisCloseConfiguration(ConfigurationHandle);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+DcFreeRcb(
+ _In_ PDC21X4_ADAPTER Adapter,
+ _In_ __drv_freesMem(Mem) PDC_RCB Rcb)
+{
+ PAGED_CODE();
+
+ if (Rcb->VirtualAddressOriginal)
+ {
+ NdisMFreeSharedMemory(Adapter->AdapterHandle,
+ DC_MEM_BLOCK_SIZE_RCB,
+ TRUE, /* Cached */
+ Rcb->VirtualAddressOriginal,
+ Rcb->PhysicalAddressOriginal);
+ }
+
+ if (Rcb->NdisBuffer)
+ NdisFreeBuffer(Rcb->NdisBuffer);
+ if (Rcb->Packet)
+ NdisFreePacket(Rcb->Packet);
+
+ NdisFreeMemory(Rcb, sizeof(*Rcb), 0);
+}
+
+static
+CODE_SEG("PAGE")
+PDC_RCB
+DcAllocateRcb(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ NDIS_STATUS Status;
+ PDC_RCB Rcb;
+ PVOID VirtualAddress;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+ PAGED_CODE();
+
+ Status = NdisAllocateMemoryWithTag((PVOID*)&Rcb, sizeof(*Rcb), DC21X4_TAG);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return NULL;
+ NdisZeroMemory(Rcb, sizeof(*Rcb));
+
+ NdisMAllocateSharedMemory(Adapter->AdapterHandle,
+ DC_MEM_BLOCK_SIZE_RCB,
+ TRUE, /* Cached */
+ &VirtualAddress,
+ &PhysicalAddress);
+ if (!VirtualAddress)
+ goto Failure;
+
+ /* 32-bit DMA */
+ ASSERT(PhysicalAddress.HighPart == 0);
+
+ Rcb->VirtualAddress = ALIGN_UP_POINTER_BY(VirtualAddress,
SYSTEM_CACHE_ALIGNMENT_SIZE);
+ Rcb->PhysicalAddress = ALIGN_UP_BY(PhysicalAddress.LowPart,
SYSTEM_CACHE_ALIGNMENT_SIZE);
+
+ ASSERT((Rcb->PhysicalAddress % DC_RECEIVE_BUFFER_ALIGNMENT) == 0);
+
+ Rcb->VirtualAddressOriginal = VirtualAddress;
+ Rcb->PhysicalAddressOriginal.QuadPart = PhysicalAddress.QuadPart;
+
+ NdisAllocatePacket(&Status, &Rcb->Packet, Adapter->PacketPool);
+ if (Status != NDIS_STATUS_SUCCESS)
+ goto Failure;
+
+ *DC_RCB_FROM_PACKET(Rcb->Packet) = Rcb;
+
+ NdisAllocateBuffer(&Status,
+ &Rcb->NdisBuffer,
+ Adapter->BufferPool,
+ Rcb->VirtualAddress,
+ DC_RECEIVE_BLOCK_SIZE);
+ if (Status != NDIS_STATUS_SUCCESS)
+ goto Failure;
+
+ NDIS_SET_PACKET_HEADER_SIZE(Rcb->Packet, DC_ETHERNET_HEADER_SIZE);
+ NdisChainBufferAtFront(Rcb->Packet, Rcb->NdisBuffer);
+
+ PushEntryList(&Adapter->AllocRcbList, &Rcb->AllocListEntry);
+
+ return Rcb;
+
+Failure:
+ DcFreeRcb(Adapter, Rcb);
+
+ return NULL;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+DcAllocateReceiveBuffers(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ ULONG i;
+ NDIS_STATUS Status;
+ PDC_RCB Rcb;
+
+ PAGED_CODE();
+
+ NdisAllocatePacketPool(&Status,
+ &Adapter->PacketPool,
+ DC_RECEIVE_BUFFERS_DEFAULT + DC_RECEIVE_BUFFERS_EXTRA,
+ PROTOCOL_RESERVED_SIZE_IN_PACKET);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ NdisAllocateBufferPool(&Status,
+ &Adapter->BufferPool,
+ DC_RECEIVE_BUFFERS_DEFAULT + DC_RECEIVE_BUFFERS_EXTRA);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ /* Allocate RCBs */
+ for (i = 0; i < DC_RECEIVE_BUFFERS_DEFAULT; ++i)
+ {
+ Rcb = DcAllocateRcb(Adapter);
+ if (!Rcb)
+ {
+ WARN("RCB allocation failed, total buffers %u\n",
Adapter->RcbCount);
+ break;
+ }
+
+ PushEntryList(&Adapter->UsedRcbList, &Rcb->ListEntry);
+
+ ++Adapter->RcbCount;
+ }
+
+ if (Adapter->RcbCount < DC_RECEIVE_BUFFERS_MIN)
+ return NDIS_STATUS_RESOURCES;
+
+ Adapter->RcbFree = Adapter->RcbCount;
+
+ /* Fix up the ring size */
+ Adapter->TailRbd = Adapter->HeadRbd + Adapter->RcbCount - 1;
+
+ /* Allocate extra RCBs for receive indication */
+ for (i = 0; i < DC_RECEIVE_BUFFERS_EXTRA; ++i)
+ {
+ Rcb = DcAllocateRcb(Adapter);
+ if (!Rcb)
+ {
+ WARN("Extra RCB allocation failed\n");
+ break;
+ }
+
+ PushEntryList(&Adapter->FreeRcbList, &Rcb->ListEntry);
+ }
+
+ Status = NdisAllocateMemoryWithTag((PVOID*)&Adapter->RcbArray,
+ sizeof(PVOID) * Adapter->RcbCount,
+ DC21X4_TAG);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+DcAllocateReceiveDescriptors(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PDC_RBD Rbd;
+
+ PAGED_CODE();
+
+ NdisMAllocateSharedMemory(Adapter->AdapterHandle,
+ DC_MEM_BLOCK_SIZE_RBD,
+ FALSE, /* Non-cached */
+ &Adapter->RbdOriginal,
+ &Adapter->RbdPhysOriginal);
+ if (!Adapter->RbdOriginal)
+ return NDIS_STATUS_RESOURCES;
+
+ /* 32-bit DMA */
+ ASSERT(Adapter->RbdPhysOriginal.HighPart == 0);
+
+ Adapter->RbdPhys = ALIGN_UP_BY(Adapter->RbdPhysOriginal.LowPart,
SYSTEM_CACHE_ALIGNMENT_SIZE);
+
+ ASSERT((Adapter->RbdPhys % DC_DESCRIPTOR_ALIGNMENT) == 0);
+
+ Rbd = ALIGN_UP_POINTER_BY(Adapter->RbdOriginal, SYSTEM_CACHE_ALIGNMENT_SIZE);
+
+ Adapter->HeadRbd = Rbd;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+DcAllocateTransmitBlocks(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PDC_TCB Tcb;
+ NDIS_STATUS Status;
+
+ PAGED_CODE();
+
+ Status = NdisAllocateMemoryWithTag((PVOID*)&Tcb,
+ DC_TRANSMIT_BLOCKS * sizeof(*Tcb),
+ DC21X4_TAG);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ NdisZeroMemory(Tcb, DC_TRANSMIT_BLOCKS * sizeof(*Tcb));
+
+ Adapter->HeadTcb = Tcb;
+ Adapter->TailTcb = Tcb + (DC_TRANSMIT_BLOCKS - 1);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+DcAllocateTransmitDescriptorsAndBuffers(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ ULONG_PTR BufferVa, BufferPa;
+ NDIS_STATUS Status;
+ ULONG i;
+
+ PAGED_CODE();
+
+ NdisMAllocateSharedMemory(Adapter->AdapterHandle,
+ DC_MEM_BLOCK_SIZE_TBD_AUX,
+ FALSE, /* Non-cached */
+ &Adapter->TbdOriginal,
+ &Adapter->TbdPhysOriginal);
+ if (!Adapter->TbdOriginal)
+ return NDIS_STATUS_RESOURCES;
+
+ /* 32-bit DMA */
+ ASSERT(Adapter->TbdPhysOriginal.HighPart == 0);
+
+ BufferVa = (ULONG_PTR)Adapter->TbdOriginal;
+ BufferPa = Adapter->TbdPhysOriginal.LowPart;
+
+ BufferVa = ALIGN_UP_BY(BufferVa, SYSTEM_CACHE_ALIGNMENT_SIZE);
+ BufferPa = ALIGN_UP_BY(BufferPa, SYSTEM_CACHE_ALIGNMENT_SIZE);
+
+ ASSERT((BufferPa % DC_DESCRIPTOR_ALIGNMENT) == 0);
+
+ Adapter->TbdPhys = (ULONG)BufferPa;
+ Adapter->HeadTbd = (PDC_TBD)BufferVa;
+ Adapter->TailTbd = (PDC_TBD)BufferVa + DC_TRANSMIT_DESCRIPTORS - 1;
+
+ BufferVa += sizeof(DC_TBD) * DC_TRANSMIT_DESCRIPTORS;
+ BufferPa += sizeof(DC_TBD) * DC_TRANSMIT_DESCRIPTORS;
+
+ BufferVa = ALIGN_UP_BY(BufferVa, SYSTEM_CACHE_ALIGNMENT_SIZE);
+ BufferPa = ALIGN_UP_BY(BufferPa, SYSTEM_CACHE_ALIGNMENT_SIZE);
+
+ ASSERT((BufferPa % DC_SETUP_FRAME_ALIGNMENT) == 0);
+
+ Adapter->SetupFrame = (PVOID)BufferVa;
+ Adapter->SetupFramePhys = BufferPa;
+
+ BufferVa += DC_SETUP_FRAME_SIZE;
+ BufferPa += DC_SETUP_FRAME_SIZE;
+
+ BufferVa = ALIGN_UP_BY(BufferVa, SYSTEM_CACHE_ALIGNMENT_SIZE);
+ BufferPa = ALIGN_UP_BY(BufferPa, SYSTEM_CACHE_ALIGNMENT_SIZE);
+
+ for (i = 0; i < DC_LOOPBACK_FRAMES; ++i)
+ {
+ Adapter->LoopbackFrame[i] = (PVOID)BufferVa;
+ Adapter->LoopbackFramePhys[i] = BufferPa;
+
+ BufferVa += DC_LOOPBACK_FRAME_SIZE;
+ BufferPa += DC_LOOPBACK_FRAME_SIZE;
+ }
+
+ if (Adapter->Features & DC_HAS_POWER_MANAGEMENT)
+ {
+ Status = NdisAllocateMemoryWithTag((PVOID*)&Adapter->SetupFrameSaved,
+ DC_SETUP_FRAME_SIZE,
+ DC21X4_TAG);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+DcAllocateTransmitBuffers(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PDC_COALESCE_BUFFER CoalesceBuffer;
+ NDIS_STATUS Status;
+ ULONG i;
+
+ PAGED_CODE();
+
+ Status = NdisAllocateMemoryWithTag((PVOID*)&CoalesceBuffer,
+ DC_TRANSMIT_BUFFERS * sizeof(*CoalesceBuffer),
+ DC21X4_TAG);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ NdisZeroMemory(CoalesceBuffer, DC_TRANSMIT_BUFFERS * sizeof(*CoalesceBuffer));
+
+ Adapter->CoalesceBuffer = CoalesceBuffer;
+
+ for (i = 0; i < DC_TRANSMIT_BUFFERS; ++i)
+ {
+ PVOID VirtualAddress;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
+
+ NdisMAllocateSharedMemory(Adapter->AdapterHandle,
+ DC_MEM_BLOCK_SIZE_TX_BUFFER,
+ FALSE, /* Non-cached */
+ &VirtualAddress,
+ &PhysicalAddress);
+ if (!VirtualAddress)
+ continue;
+
+ ASSERT(PhysicalAddress.HighPart == 0);
+
+ CoalesceBuffer->VirtualAddress =
+ ALIGN_UP_POINTER_BY(VirtualAddress, SYSTEM_CACHE_ALIGNMENT_SIZE);
+ CoalesceBuffer->PhysicalAddress =
+ ALIGN_UP_BY(PhysicalAddress.LowPart, SYSTEM_CACHE_ALIGNMENT_SIZE);
+
+ Adapter->SendBufferData[i].PhysicalAddress.QuadPart =
PhysicalAddress.QuadPart;
+ Adapter->SendBufferData[i].VirtualAddress = VirtualAddress;
+
+ PushEntryList(&Adapter->SendBufferList,
&CoalesceBuffer->ListEntry);
+
+ ++CoalesceBuffer;
+ }
+
+ if (!Adapter->SendBufferList.Next)
+ return NDIS_STATUS_RESOURCES;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+CODE_SEG("PAGE")
+VOID
+DcInitTxRing(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PDC_TCB Tcb;
+ PDC_TBD Tbd;
+
+ PAGED_CODE();
+
+ InitializeListHead(&Adapter->SendQueueList);
+
+ Tcb = Adapter->HeadTcb;
+
+ Adapter->CurrentTcb = Tcb;
+ Adapter->LastTcb = Tcb;
+
+ Adapter->TcbSlots = DC_TRANSMIT_BLOCKS - DC_TCB_RESERVE;
+ Adapter->TbdSlots = DC_TRANSMIT_DESCRIPTORS - DC_TBD_RESERVE;
+ Adapter->LoopbackFrameSlots = DC_LOOPBACK_FRAMES;
+ Adapter->TcbCompleted = 0;
+
+ Tbd = Adapter->HeadTbd;
+ Adapter->CurrentTbd = Tbd;
+
+ NdisZeroMemory(Tbd, sizeof(*Tbd) * DC_TRANSMIT_DESCRIPTORS);
+
+ Adapter->TailTbd->Control |= DC_TBD_CONTROL_END_OF_RING;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+DcCreateRxRing(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PDC_RCB* RcbSlot;
+ PDC_RCB Rcb;
+ PDC_RBD Rbd;
+ PSINGLE_LIST_ENTRY Entry;
+
+ PAGED_CODE();
+
+ Rbd = Adapter->HeadRbd;
+ Adapter->CurrentRbd = Rbd;
+
+ RcbSlot = DC_GET_RCB_SLOT(Adapter, Rbd);
+ Rcb = (PDC_RCB)Adapter->UsedRcbList.Next;
+
+ for (Entry = Adapter->UsedRcbList.Next;
+ Entry != NULL;
+ Entry = Entry->Next)
+ {
+ Rcb = (PDC_RCB)Entry;
+
+ C_ASSERT((DC_RECEIVE_BUFFER_SIZE % DC_RECEIVE_BUFFER_SIZE_MULTIPLE) == 0);
+
+ Rbd->Address1 = Rcb->PhysicalAddress;
+ Rbd->Address2 = 0;
+ Rbd->Control = DC_RECEIVE_BUFFER_SIZE;
+ Rbd->Status = DC_RBD_STATUS_OWNED;
+
+ *RcbSlot = Rcb;
+
+ ++RcbSlot;
+ ++Rbd;
+ Rcb = (PDC_RCB)Rcb->ListEntry.Next;
+ }
+ Rbd = Rbd - 1;
+ Rbd->Control |= DC_RBD_CONTROL_CHAINED;
+ Rbd->Address2 = Adapter->RbdPhys;
+
+ ASSERT(Rbd == Adapter->TailRbd);
+}
+
+CODE_SEG("PAGE")
+VOID
+DcInitRxRing(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ PDC_RBD Rbd;
+ ULONG i;
+
+ PAGED_CODE();
+
+ Rbd = Adapter->HeadRbd;
+ Adapter->CurrentRbd = Rbd;
+
+ for (i = 0; i < Adapter->RcbCount; ++i)
+ {
+ Rbd->Control = DC_RECEIVE_BUFFER_SIZE;
+ Rbd->Status = DC_RBD_STATUS_OWNED;
+
+ ++Rbd;
+ }
+ Rbd = Rbd - 1;
+ Rbd->Control |= DC_RBD_CONTROL_CHAINED;
+
+ ASSERT(Rbd == Adapter->TailRbd);
+}
+
+static
+CODE_SEG("PAGE")
+NDIS_STATUS
+DcAllocateMemory(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ NDIS_STATUS Status;
+
+ PAGED_CODE();
+
+ Status = NdisMInitializeScatterGatherDma(Adapter->AdapterHandle,
+ FALSE, /* 32-bit DMA */
+ DC_TRANSMIT_BLOCK_SIZE);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ Status = DcAllocateReceiveDescriptors(Adapter);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ Status = DcAllocateTransmitBlocks(Adapter);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ Status = DcAllocateTransmitBuffers(Adapter);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ Status = DcAllocateTransmitDescriptorsAndBuffers(Adapter);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ Status = DcAllocateReceiveBuffers(Adapter);
+ if (Status != NDIS_STATUS_SUCCESS)
+ return Status;
+
+ NdisAllocateSpinLock(&Adapter->SendLock);
+ NdisAllocateSpinLock(&Adapter->ReceiveLock);
+ NdisAllocateSpinLock(&Adapter->ModeLock);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+DcInitTestPacket(
+ _In_ PDC21X4_ADAPTER Adapter)
+{
+ ULONG i;
+
+ PAGED_CODE();
+
+ for (i = 0; i < DC_LOOPBACK_FRAMES; ++i)
+ {
+ PETH_HEADER PacketBuffer = Adapter->LoopbackFrame[i];
+
+ NdisZeroMemory(PacketBuffer, DC_LOOPBACK_FRAME_SIZE);
+
+ /* Destination MAC address */
+ NdisMoveMemory(PacketBuffer->Destination,
+ Adapter->CurrentMacAddress,
+ ETH_LENGTH_OF_ADDRESS);
+
+ /* Source MAC address */
+ NdisMoveMemory(PacketBuffer->Source,
+ Adapter->CurrentMacAddress,
+ ETH_LENGTH_OF_ADDRESS);
+
+ ++PacketBuffer;
+ }
+}
+
+static
+CODE_SEG("PAGE")
... 4975 lines suppressed ...