https://git.reactos.org/?p=reactos.git;a=commitdiff;h=59d8a77df6a7245654bdd4f31ebc5825282411bf

commit 59d8a77df6a7245654bdd4f31ebc5825282411bf
Author:     Dmitry Borisov <[email protected]>
AuthorDate: Wed Oct 18 23:12:36 2023 +0600
Commit:     GitHub <[email protected]>
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 <[email protected]>
+ */
+
+/* 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 <[email protected]>
+ */
+
+#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 <[email protected]>
+ */
+
+#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 <[email protected]>
+ */
+
+/* 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 <[email protected]>
+ */
+
+#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 <[email protected]>
+ */
+
+/* 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 <[email protected]>
+ */
+
+#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 <[email protected]>
+ */
+
+/* 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 <[email protected]>
+ */
+
+/* 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 <[email protected]>
+ */
+
+/* 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 ...

Reply via email to