[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
This commit is contained in:
Dmitry Borisov 2023-10-18 23:12:36 +06:00 committed by GitHub
parent a8e8add0c0
commit 59d8a77df6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 9751 additions and 2 deletions

View file

@ -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

View file

@ -1,4 +1,5 @@
add_subdirectory(dc21x4)
add_subdirectory(e1000)
add_subdirectory(ne2000)
add_subdirectory(netkvm)

View file

@ -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)

View file

@ -0,0 +1,401 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Miniport driver entry
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* FUNCTIONS ******************************************************************/
ULONG
DcEthernetCrc(
_In_reads_bytes_(Size) const VOID* Buffer,
_In_ ULONG Size)
{
ULONG i, j, Crc;
const UCHAR* Data = Buffer;
Crc = 0xFFFFFFFF;
for (i = 0; i < Size; ++i)
{
Crc ^= Data[i];
for (j = 8; j > 0; j--)
{
/* CRC-32 polynomial little-endian */
Crc = (Crc >> 1) ^ (-(LONG)(Crc & 1) & 0xEDB88320);
}
}
return Crc;
}
static
VOID
DcFlushTransmitQueue(
_In_ PDC21X4_ADAPTER Adapter)
{
LIST_ENTRY DoneList;
PLIST_ENTRY Entry;
PNDIS_PACKET Packet;
PDC_TCB Tcb;
InitializeListHead(&DoneList);
NdisAcquireSpinLock(&Adapter->SendLock);
/* Remove pending transmissions from the transmit ring */
for (Tcb = Adapter->LastTcb;
Tcb != Adapter->CurrentTcb;
Tcb = DC_NEXT_TCB(Adapter, Tcb))
{
Packet = Tcb->Packet;
if (!Packet)
continue;
InsertTailList(&DoneList, DC_LIST_ENTRY_FROM_PACKET(Packet));
DC_RELEASE_TCB(Adapter, Tcb);
}
Adapter->CurrentTcb = Tcb;
/* Remove pending transmissions from the internal queue */
while (!IsListEmpty(&Adapter->SendQueueList))
{
Entry = RemoveHeadList(&Adapter->SendQueueList);
InsertTailList(&DoneList, Entry);
}
NdisReleaseSpinLock(&Adapter->SendLock);
while (!IsListEmpty(&DoneList))
{
Entry = RemoveHeadList(&DoneList);
NdisMSendComplete(Adapter->AdapterHandle,
DC_PACKET_FROM_LIST_ENTRY(Entry),
NDIS_STATUS_FAILURE);
}
}
static
VOID
DcStopReceivePath(
_In_ PDC21X4_ADAPTER Adapter)
{
BOOLEAN RxStopped;
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
#if DBG
NdisAcquireSpinLock(&Adapter->ReceiveLock);
if (Adapter->RcbFree != Adapter->RcbCount)
{
INFO("RX packets: %u/%u\n", Adapter->RcbFree, Adapter->RcbCount);
}
NdisReleaseSpinLock(&Adapter->ReceiveLock);
#endif
while (TRUE)
{
NdisAcquireSpinLock(&Adapter->ReceiveLock);
RxStopped = (Adapter->RcbFree == Adapter->RcbCount);
NdisReleaseSpinLock(&Adapter->ReceiveLock);
if (RxStopped)
break;
NdisMSleep(10);
}
}
DECLSPEC_NOINLINE /* Called from pageable code */
VOID
DcStopAdapter(
_In_ PDC21X4_ADAPTER Adapter,
_In_ BOOLEAN WaitForPackets)
{
BOOLEAN TimerCancelled;
/* Attempt to disable interrupts to complete more quickly */
DC_WRITE(Adapter, DcCsr7_IrqMask, 0);
/* Prevent DPCs from executing and stop accepting incoming packets */
NdisAcquireSpinLock(&Adapter->SendLock);
Adapter->Flags &= ~DC_ACTIVE;
NdisReleaseSpinLock(&Adapter->SendLock);
NdisMCancelTimer(&Adapter->MediaMonitorTimer, &TimerCancelled);
/* Wait for any DPCs to complete */
KeFlushQueuedDpcs();
/* Disable interrupts */
DC_WRITE(Adapter, DcCsr7_IrqMask, 0);
/* Wait for completion of TX/RX and stop the DMA engine inside the NIC */
DcStopTxRxProcess(Adapter);
Adapter->OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE);
DcFlushTransmitQueue(Adapter);
/* Wait for the packets to be returned to the driver */
if (WaitForPackets)
{
DcStopReceivePath(Adapter);
}
/* Make sure there is no pending OID request */
if (Adapter->OidPending)
{
NdisMSetInformationComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS);
Adapter->OidPending = FALSE;
}
}
CODE_SEG("PAGE")
VOID
DcStartAdapter(
_In_ PDC21X4_ADAPTER Adapter)
{
PAGED_CODE();
/* Enable interrupts */
_InterlockedExchange((PLONG)&Adapter->CurrentInterruptMask, Adapter->InterruptMask);
DC_WRITE(Adapter, DcCsr7_IrqMask, Adapter->InterruptMask);
Adapter->Flags |= DC_ACTIVE;
/* Start the RX process */
Adapter->OpMode |= DC_OPMODE_RX_ENABLE;
DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
/* Start the media monitor, wait the selected media to become ready */
NdisMSetTimer(&Adapter->MediaMonitorTimer, 2400);
}
CODE_SEG("PAGE")
VOID
NTAPI
DcResetWorker(
_In_ PNDIS_WORK_ITEM WorkItem,
_In_opt_ PVOID Context)
{
PDC21X4_ADAPTER Adapter = Context;
NDIS_STATUS Status;
ULONG InterruptStatus;
LONG ResetReason;
UNREFERENCED_PARAMETER(WorkItem);
PAGED_CODE();
Status = NDIS_STATUS_SUCCESS;
/* Check if the device is present */
InterruptStatus = DC_READ(Adapter, DcCsr5_Status);
if (InterruptStatus == 0xFFFFFFFF)
{
ERR("Hardware is gone...\n");
/* Remove this adapter */
NdisMRemoveMiniport(Adapter->AdapterHandle);
Status = NDIS_STATUS_HARD_ERRORS;
goto Done;
}
DcStopAdapter(Adapter, FALSE);
if (Adapter->LinkUp)
{
Adapter->LinkUp = FALSE;
NdisMIndicateStatus(Adapter->AdapterHandle,
NDIS_STATUS_MEDIA_DISCONNECT,
NULL,
0);
NdisMIndicateStatusComplete(Adapter->AdapterHandle);
}
DcSetupAdapter(Adapter);
DcStartAdapter(Adapter);
Done:
ResetReason = _InterlockedExchange(&Adapter->ResetLock, 0);
/* Complete the pending reset request */
if (ResetReason == 1)
{
NdisMResetComplete(Adapter->AdapterHandle, Status, FALSE);
}
}
VOID
NTAPI
DcTransmitTimeoutRecoveryWorker(
_In_ PNDIS_WORK_ITEM WorkItem,
_In_opt_ PVOID Context)
{
PDC21X4_ADAPTER Adapter = Context;
UNREFERENCED_PARAMETER(WorkItem);
NdisAcquireSpinLock(&Adapter->ModeLock);
DcStopTxRxProcess(Adapter);
DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
NdisDprAcquireSpinLock(&Adapter->SendLock);
DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL);
NdisDprReleaseSpinLock(&Adapter->SendLock);
NdisReleaseSpinLock(&Adapter->ModeLock);
}
static
BOOLEAN
NTAPI
DcCheckForHang(
_In_ NDIS_HANDLE MiniportAdapterContext)
{
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
ULONG TcbCompleted;
BOOLEAN TxHang = FALSE;
if (!(Adapter->Flags & DC_ACTIVE))
return FALSE;
NdisDprAcquireSpinLock(&Adapter->SendLock);
if (Adapter->TcbSlots != (DC_TRANSMIT_BLOCKS - DC_TCB_RESERVE))
{
TcbCompleted = Adapter->TcbCompleted;
TxHang = (TcbCompleted == Adapter->LastTcbCompleted);
Adapter->LastTcbCompleted = TcbCompleted;
}
NdisDprReleaseSpinLock(&Adapter->SendLock);
if (TxHang)
{
WARN("Transmit timeout, CSR12 %08lx, CSR5 %08lx\n",
DC_READ(Adapter, DcCsr12_SiaStatus),
DC_READ(Adapter, DcCsr5_Status));
NdisScheduleWorkItem(&Adapter->TxRecoveryWorkItem);
}
return FALSE;
}
static
NDIS_STATUS
NTAPI
DcReset(
_Out_ PBOOLEAN AddressingReset,
_In_ NDIS_HANDLE MiniportAdapterContext)
{
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
WARN("Called\n");
if (_InterlockedCompareExchange(&Adapter->ResetLock, 1, 0))
{
return NDIS_STATUS_RESET_IN_PROGRESS;
}
NdisScheduleWorkItem(&Adapter->ResetWorkItem);
return NDIS_STATUS_PENDING;
}
static
CODE_SEG("PAGE")
VOID
NTAPI
DcHalt(
_In_ NDIS_HANDLE MiniportAdapterContext)
{
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
PAGED_CODE();
INFO("Called\n");
DcStopAdapter(Adapter, TRUE);
DcDisableHw(Adapter);
DcFreeAdapter(Adapter);
}
static
VOID
NTAPI
DcShutdown(
_In_ NDIS_HANDLE MiniportAdapterContext)
{
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
INFO("Called\n");
DcDisableHw(Adapter);
}
CODE_SEG("INIT")
NTSTATUS
NTAPI
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath)
{
NDIS_HANDLE WrapperHandle;
NDIS_STATUS Status;
NDIS_MINIPORT_CHARACTERISTICS Characteristics = { 0 };
INFO("Called\n");
NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, NULL);
if (!WrapperHandle)
return NDIS_STATUS_FAILURE;
Characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
Characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
Characteristics.CheckForHangHandler = DcCheckForHang;
Characteristics.HaltHandler = DcHalt;
Characteristics.HandleInterruptHandler = DcHandleInterrupt;
Characteristics.InitializeHandler = DcInitialize;
Characteristics.ISRHandler = DcIsr;
Characteristics.QueryInformationHandler = DcQueryInformation;
Characteristics.ResetHandler = DcReset;
Characteristics.SetInformationHandler = DcSetInformation;
Characteristics.ReturnPacketHandler = DcReturnPacket;
Characteristics.SendPacketsHandler = DcSendPackets;
Characteristics.CancelSendPacketsHandler = DcCancelSendPackets;
Characteristics.AdapterShutdownHandler = DcShutdown;
Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics));
if (Status != NDIS_STATUS_SUCCESS)
{
NdisTerminateWrapper(WrapperHandle, NULL);
return Status;
}
InitializeListHead(&SRompAdapterList);
return NDIS_STATUS_SUCCESS;
}

View file

@ -0,0 +1,541 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Main header file
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
#if !DBG
#define NO_KERNEL_LIST_ENTRY_CHECKS
#endif
#include <ndis.h>
#include <section_attribs.h>
#include "dc21x4hw.h"
#include "eeprom.h"
#include "media.h"
#include "util.h"
#define DC21X4_TAG '4x12'
#define DC_TRANSMIT_DESCRIPTORS 64
#define DC_TRANSMIT_BLOCKS 48
#define DC_TRANSMIT_BUFFERS 4
#define DC_LOOPBACK_FRAMES 4
#define DC_RECEIVE_BUFFERS_DEFAULT 64
#define DC_RECEIVE_BUFFERS_MIN 8
#define DC_RECEIVE_BUFFERS_EXTRA 16
#define DC_RECEIVE_ARRAY_SIZE 16
#define DC_MULTICAST_LIST_SIZE 36
#define DC_MAXIMUM_FRAME_SIZE 1514
#define DC_TRANSMIT_BLOCK_SIZE 1536
#define DC_RECEIVE_BLOCK_SIZE 1536
#define DC_ETHERNET_HEADER_SIZE 14
#define DC_TX_UNDERRUN_LIMIT 5
#define DC_INTERRUPT_PROCESSING_LIMIT 8
#define DC_FRAGMENTATION_THRESHOLD 32
#define DC_PACKET_FILTERS ( \
NDIS_PACKET_TYPE_DIRECTED | \
NDIS_PACKET_TYPE_MULTICAST | \
NDIS_PACKET_TYPE_BROADCAST | \
NDIS_PACKET_TYPE_PROMISCUOUS | \
NDIS_PACKET_TYPE_ALL_MULTICAST)
#define DC_LOOPBACK_FRAME_SIZE 64
/* Transmit descriptors reserved for internal use */
#define DC_TBD_RESERVE (2 + DC_LOOPBACK_FRAMES) /* (+2 for setup frame) */
#define DC_TCB_RESERVE (1 + DC_LOOPBACK_FRAMES) /* (+1 for setup frame) */
#define DC_EVENT_SETUP_FRAME_COMPLETED 0x00000001
typedef struct _DC21X4_ADAPTER DC21X4_ADAPTER, *PDC21X4_ADAPTER;
typedef struct _DC_TCB DC_TCB, *PDC_TCB;
typedef struct _DC_RCB DC_RCB, *PDC_RCB;
typedef struct _DC_COALESCE_BUFFER DC_COALESCE_BUFFER, *PDC_COALESCE_BUFFER;
typedef VOID
(MEDIA_HANDLE_LINK_STATE_CHANGE)(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG InterruptStatus);
typedef MEDIA_HANDLE_LINK_STATE_CHANGE *PMEDIA_HANDLE_LINK_STATE_CHANGE;
typedef struct _DC_TX_BUFFER_DATA
{
PVOID VirtualAddress;
NDIS_PHYSICAL_ADDRESS PhysicalAddress;
} DC_TX_BUFFER_DATA, *PDC_TX_BUFFER_DATA;
typedef struct _DC_STATISTICS
{
ULONG64 TransmitOk;
ULONG64 TransmitDeferred;
ULONG64 TransmitHeartbeatErrors;
ULONG64 TransmitOneRetry;
ULONG64 TransmitMoreCollisions;
ULONG64 TransmitErrors;
ULONG64 TransmitExcessiveCollisions;
ULONG64 TransmitUnderrunErrors;
ULONG64 TransmitLostCarrierSense;
ULONG64 TransmitLateCollisions;
ULONG64 ReceiveOk;
ULONG64 ReceiveBroadcast;
ULONG64 ReceiveMulticast;
ULONG64 ReceiveUnicast;
ULONG64 ReceiveErrors;
ULONG64 ReceiveOverrunErrors;
ULONG64 ReceiveNoBuffers;
ULONG64 ReceiveCrcErrors;
ULONG64 ReceiveAlignmentErrors;
} DC_STATISTICS, *PDC_STATISTICS;
typedef struct _DC21X4_ADAPTER
{
PUCHAR IoBase;
ULONG InterruptMask;
ULONG CurrentInterruptMask;
ULONG Features;
#define DC_NEED_RX_OVERFLOW_WORKAROUND 0x80000000
#define DC_SIA_GPIO 0x00000001
#define DC_SIA_ANALOG_CONTROL 0x00000002
#define DC_HAS_POWER_MANAGEMENT 0x00000004
#define DC_HAS_POWER_SAVING 0x00000008
#define DC_HAS_MII 0x00000010
#define DC_PERFECT_FILTERING_ONLY 0x00000020
#define DC_ENABLE_PCI_COMMANDS 0x00000040
#define DC_MII_AUTOSENSE 0x00000080
#define DC_HAS_TIMER 0x00000100
ULONG Flags;
#define DC_ACTIVE 0x80000000
#define DC_IO_MAPPED 0x00000001
#define DC_IRQ_SHARED 0x00000002
#define DC_FIRST_SETUP 0x00000004
#define DC_AUTOSENSE 0x00000008
ULONG InterruptStatus;
PMEDIA_HANDLE_LINK_STATE_CHANGE HandleLinkStateChange;
DECLSPEC_CACHEALIGN NDIS_SPIN_LOCK SendLock;
PDC_TCB TailTcb;
PDC_TCB LastTcb;
PDC_TCB CurrentTcb;
PDC_TBD CurrentTbd;
PDC_TBD HeadTbd;
PDC_TBD TailTbd;
LIST_ENTRY SendQueueList;
ULONG TcbSlots;
ULONG TbdSlots;
ULONG TcbCompleted;
ULONG LastTcbCompleted;
PDC_TCB HeadTcb;
SINGLE_LIST_ENTRY SendBufferList;
SCATTER_GATHER_LIST LocalSgList;
DECLSPEC_CACHEALIGN NDIS_SPIN_LOCK ReceiveLock;
PDC_RCB* RcbArray;
PDC_RBD CurrentRbd;
PDC_RBD HeadRbd;
PDC_RBD TailRbd;
SINGLE_LIST_ENTRY FreeRcbList;
ULONG RcbFree;
ULONG TransmitUnderruns;
ULONG PacketFilter;
DC_STATISTICS Statistics;
NDIS_HANDLE AdapterHandle;
NDIS_HANDLE WrapperConfigurationHandle;
DECLSPEC_CACHEALIGN NDIS_SPIN_LOCK ModeLock;
ULONG ModeFlags;
#define DC_MODE_AUTONEG_MASK 0x0000000F
#define DC_MODE_PORT_AUTOSENSE 0x00000010
#define DC_MODE_TEST_PACKET 0x00000020
#define DC_MODE_AUI_FAILED 0x00000040
#define DC_MODE_BNC_FAILED 0x00000080
#define DC_MODE_AUTONEG_NONE 0x00000000
#define DC_MODE_AUTONEG_WAIT_INTERRUPT 0x00000001
#define DC_MODE_AUTONEG_LINK_STATUS_CHECK 0x00000002
ULONG OpMode;
ULONG MediaNumber;
ULONG MediaBitmap;
BOOLEAN LinkUp;
ULONG PhyAddress;
ULONG SiaSetting;
ULONG LastReceiveActivity;
volatile LONG MediaTestStatus;
NDIS_MINIPORT_TIMER MediaMonitorTimer;
DC_MII_MEDIA MiiMedia;
DC_MEDIA Media[MEDIA_LIST_MAX];
ULONG AnalogControl;
ULONG SymAdvertising;
ULONG MiiAdvertising;
ULONG MiiControl;
DC_CHIP_TYPE ChipType;
ULONG LinkStateChangeMask;
ULONG WakeUpFlags;
NDIS_DEVICE_POWER_STATE PowerState;
NDIS_DEVICE_POWER_STATE PrevPowerState;
ULONG HpnaInitBitmap;
UCHAR HpnaRegister[32];
UCHAR PermanentMacAddress[ETH_LENGTH_OF_ADDRESS];
UCHAR CurrentMacAddress[ETH_LENGTH_OF_ADDRESS];
ULONG MulticastMaxEntries;
_Field_range_(0, MulticastMaxEntries)
ULONG MulticastCount;
struct
{
UCHAR MacAddress[ETH_LENGTH_OF_ADDRESS];
} MulticastList[DC_MULTICAST_LIST_SIZE];
ULONG LinkSpeedMbps;
ULONG BusMode;
ULONG DefaultMedia;
ULONG RcbCount;
BOOLEAN OidPending;
BOOLEAN ProgramHashPerfectFilter;
PULONG SetupFrame;
PULONG SetupFrameSaved;
ULONG SetupFramePhys;
ULONG LoopbackFrameSlots;
ULONG LoopbackFrameNumber;
ULONG LoopbackFramePhys[DC_LOOPBACK_FRAMES];
ULONG BusNumber;
UCHAR DeviceNumber;
UCHAR RevisionId;
UCHAR ControllerIndex;
UCHAR ResetStreamLength;
USHORT ResetStream[SROM_MAX_STREAM_REGS];
USHORT DeviceId;
SINGLE_LIST_ENTRY AllocRcbList;
SINGLE_LIST_ENTRY UsedRcbList;
NDIS_MINIPORT_INTERRUPT Interrupt;
ULONG InterruptVector;
ULONG InterruptLevel;
ULONG InterruptFlags;
ULONG AdapterSize;
NDIS_WORK_ITEM PowerWorkItem;
NDIS_WORK_ITEM ResetWorkItem;
NDIS_WORK_ITEM TxRecoveryWorkItem;
_Interlocked_ volatile LONG ResetLock;
NDIS_PHYSICAL_ADDRESS IoBaseAddress;
PDC_SROM_ENTRY SRomEntry;
PVOID AdapterOriginal;
PVOID TbdOriginal;
PVOID RbdOriginal;
ULONG TbdPhys;
ULONG RbdPhys;
NDIS_HANDLE BufferPool;
NDIS_HANDLE PacketPool;
NDIS_PHYSICAL_ADDRESS TbdPhysOriginal;
NDIS_PHYSICAL_ADDRESS RbdPhysOriginal;
PVOID LoopbackFrame[DC_LOOPBACK_FRAMES];
PDC_COALESCE_BUFFER CoalesceBuffer;
DC_TX_BUFFER_DATA SendBufferData[DC_TRANSMIT_BUFFERS];
} DC21X4_ADAPTER, *PDC21X4_ADAPTER;
#include "sendrcv.h"
extern LIST_ENTRY SRompAdapterList;
FORCEINLINE
ULONG
DC_READ(
_In_ PDC21X4_ADAPTER Adapter,
_In_ DC_CSR Register)
{
ULONG Value;
NdisRawReadPortUlong((PULONG)(Adapter->IoBase + Register), &Value);
return Value;
}
#define DC_WRITE(Adapter, Register, Value) \
NdisRawWritePortUlong((PULONG)((Adapter)->IoBase + (Register)), (Value));
CODE_SEG("INIT")
DRIVER_INITIALIZE DriverEntry;
CODE_SEG("PAGE")
NDIS_STATUS
NTAPI
DcInitialize(
_Out_ PNDIS_STATUS OpenErrorStatus,
_Out_ PUINT SelectedMediumIndex,
_In_ PNDIS_MEDIUM MediumArray,
_In_ UINT MediumArraySize,
_In_ NDIS_HANDLE MiniportAdapterHandle,
_In_ NDIS_HANDLE WrapperConfigurationContext);
VOID
NTAPI
DcSendPackets(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ PPNDIS_PACKET PacketArray,
_In_ UINT NumberOfPackets);
VOID
NTAPI
DcCancelSendPackets(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ PVOID CancelId);
VOID
DcProcessPendingPackets(
_In_ PDC21X4_ADAPTER Adapter);
VOID
NTAPI
DcReturnPacket(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ PNDIS_PACKET Packet);
NDIS_STATUS
NTAPI
DcQueryInformation(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ NDIS_OID Oid,
_In_ PVOID InformationBuffer,
_In_ ULONG InformationBufferLength,
_Out_ PULONG BytesWritten,
_Out_ PULONG BytesNeeded);
NDIS_STATUS
NTAPI
DcSetInformation(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ NDIS_OID Oid,
_In_ PVOID InformationBuffer,
_In_ ULONG InformationBufferLength,
_Out_ PULONG BytesRead,
_Out_ PULONG BytesNeeded);
VOID
NTAPI
DcIsr(
_Out_ PBOOLEAN InterruptRecognized,
_Out_ PBOOLEAN QueueMiniportHandleInterrupt,
_In_ NDIS_HANDLE MiniportAdapterContext);
VOID
NTAPI
DcHandleInterrupt(
_In_ NDIS_HANDLE MiniportAdapterContext);
CODE_SEG("PAGE")
VOID
NTAPI
DcPowerWorker(
_In_ PNDIS_WORK_ITEM WorkItem,
_In_opt_ PVOID Context);
NDIS_STATUS
DcSetPower(
_In_ PDC21X4_ADAPTER Adapter,
_In_ NDIS_DEVICE_POWER_STATE PowerState);
NDIS_STATUS
DcAddWakeUpPattern(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PNDIS_PM_PACKET_PATTERN PmPattern);
NDIS_STATUS
DcRemoveWakeUpPattern(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PNDIS_PM_PACKET_PATTERN PmPattern);
CODE_SEG("PAGE")
VOID
DcFreeAdapter(
_In_ __drv_freesMem(Mem) PDC21X4_ADAPTER Adapter);
CODE_SEG("PAGE")
VOID
NTAPI
DcResetWorker(
_In_ PNDIS_WORK_ITEM WorkItem,
_In_opt_ PVOID Context);
DECLSPEC_NOINLINE
VOID
DcStopAdapter(
_In_ PDC21X4_ADAPTER Adapter,
_In_ BOOLEAN WaitForPackets);
CODE_SEG("PAGE")
VOID
DcStartAdapter(
_In_ PDC21X4_ADAPTER Adapter);
CODE_SEG("PAGE")
NDIS_STATUS
DcSetupAdapter(
_In_ PDC21X4_ADAPTER Adapter);
CODE_SEG("PAGE")
NDIS_STATUS
DcReadEeprom(
_In_ PDC21X4_ADAPTER Adapter);
CODE_SEG("PAGE")
VOID
DcFreeEeprom(
_In_ PDC21X4_ADAPTER Adapter);
CODE_SEG("PAGE")
VOID
DcInitTxRing(
_In_ PDC21X4_ADAPTER Adapter);
CODE_SEG("PAGE")
VOID
DcInitRxRing(
_In_ PDC21X4_ADAPTER Adapter);
ULONG
DcEthernetCrc(
_In_reads_bytes_(Size) const VOID* Buffer,
_In_ ULONG Size);
VOID
DcDisableHw(
_In_ PDC21X4_ADAPTER Adapter);
VOID
DcStopTxRxProcess(
_In_ PDC21X4_ADAPTER Adapter);
VOID
DcWriteGpio(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG Value);
VOID
DcWriteSia(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG Csr13,
_In_ ULONG Csr14,
_In_ ULONG Csr15);
VOID
DcTestPacket(
_In_ PDC21X4_ADAPTER Adapter);
CODE_SEG("PAGE")
VOID
DcSetupFrameInitialize(
_In_ PDC21X4_ADAPTER Adapter);
BOOLEAN
DcSetupFrameDownload(
_In_ PDC21X4_ADAPTER Adapter,
_In_ BOOLEAN WaitForCompletion);
NDIS_STATUS
DcApplyPacketFilter(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG PacketFilter);
NDIS_STATUS
DcUpdateMulticastList(
_In_ PDC21X4_ADAPTER Adapter);
VOID
DcPowerSave(
_In_ PDC21X4_ADAPTER Adapter,
_In_ BOOLEAN Enable);
CODE_SEG("PAGE")
BOOLEAN
DcFindMiiPhy(
_In_ PDC21X4_ADAPTER Adapter);
BOOLEAN
MiiWrite(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG PhyAddress,
_In_ ULONG RegAddress,
_In_ ULONG Data);
BOOLEAN
MiiRead(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG PhyAddress,
_In_ ULONG RegAddress,
_Out_ PULONG Data);
CODE_SEG("PAGE")
VOID
HpnaPhyInit(
_In_ PDC21X4_ADAPTER Adapter);
VOID
NTAPI
DcTransmitTimeoutRecoveryWorker(
_In_ PNDIS_WORK_ITEM WorkItem,
_In_opt_ PVOID Context);
NDIS_TIMER_FUNCTION MediaMonitor21040Dpc;
NDIS_TIMER_FUNCTION MediaMonitor21041Dpc;
NDIS_TIMER_FUNCTION MediaMonitor21140Dpc;
NDIS_TIMER_FUNCTION MediaMonitor21143Dpc;
MEDIA_HANDLE_LINK_STATE_CHANGE MediaLinkStateChange21040;
MEDIA_HANDLE_LINK_STATE_CHANGE MediaLinkStateChange21041;
MEDIA_HANDLE_LINK_STATE_CHANGE MediaLinkStateChange21143;
CODE_SEG("PAGE")
VOID
MediaInitMediaList(
_In_ PDC21X4_ADAPTER Adapter);
CODE_SEG("PAGE")
VOID
MediaInitDefaultMedia(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG MediaNumber);
VOID
MediaIndicateConnect(
_In_ PDC21X4_ADAPTER Adapter,
_In_ BOOLEAN LinkUp);
VOID
MediaSelectMiiPort(
_In_ PDC21X4_ADAPTER Adapter,
_In_ BOOLEAN ResetPhy);
VOID
MediaMiiSelect(
_In_ PDC21X4_ADAPTER Adapter);
BOOLEAN
MediaMiiCheckLink(
_In_ PDC21X4_ADAPTER Adapter);
VOID
MediaSiaSelect(
_In_ PDC21X4_ADAPTER Adapter);
VOID
MediaGprSelect(
_In_ PDC21X4_ADAPTER Adapter);

View file

@ -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>

View file

@ -0,0 +1,597 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Hardware specific definitions
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
typedef enum _DC_CHIP_TYPE
{
DC21040,
DC21041,
DC21140,
DC21143,
DC21145,
} DC_CHIP_TYPE;
/*
* PCI Vendor and Device IDs
*/
#define DC_DEV_DECCHIP_21040 0x00021011
#define DC_DEV_DECCHIP_21041 0x00141011
#define DC_DEV_DECCHIP_21140 0x00091011
#define DC_DEV_INTEL_21143 0x00191011
#define DC_DEV_INTEL_21145 0x00398086
#define DC_DESCRIPTOR_ALIGNMENT 4
#define DC_SETUP_FRAME_ALIGNMENT 4
#define DC_RECEIVE_BUFFER_ALIGNMENT 4
#define DC_RECEIVE_BUFFER_SIZE_MULTIPLE 4
#define DC_IO_LENGTH 128
#define DC_SETUP_FRAME_SIZE 192
/* Multicast perfect filter */
#define DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES 16
/* -1 for physical address and -1 for broadcast address */
#define DC_SETUP_FRAME_ADDRESSES (16 - 2)
/* Computed hash of FF:FF:FF:FF:FF:FF */
#define DC_SETUP_FRAME_BROADCAST_HASH 0xFF
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define DC_SETUP_FRAME_ENTRY(Value) (Value)
#else
#define DC_SETUP_FRAME_ENTRY(Value) ((Value) << 16)
#endif
#include <pshpack1.h>
/*
* Transmit Buffer Descriptor
*/
typedef struct _DC_TBD
{
ULONG Status;
#define DC_TBD_STATUS_DEFFERED 0x00000001
#define DC_TBD_STATUS_UNDERFLOW 0x00000002
#define DC_TBD_STATUS_LINK_FAIL 0x00000004
#define DC_TBD_STATUS_COLLISIONS_MASK 0x00000078
#define DC_TBD_STATUS_HEARTBEAT_FAIL 0x00000080
#define DC_TBD_STATUS_RETRY_ERROR 0x00000100
#define DC_TBD_STATUS_LATE_COLLISION 0x00000200
#define DC_TBD_STATUS_NO_CARRIER 0x00000400
#define DC_TBD_STATUS_CARRIER_LOST 0x00000800
#define DC_TBD_STATUS_JABBER_TIMEOUT 0x00004000
#define DC_TBD_STATUS_ERROR_SUMMARY 0x00008000
#define DC_TBD_STATUS_OWNED 0x80000000
#define DC_TBD_STATUS_SETUP_FRAME 0x7FFFFFFF
#define DC_TBD_STATUS_COLLISIONS_SHIFT 3
ULONG Control;
#define DC_TBD_CONTROL_LENGTH_MASK_1 0x000007FF
#define DC_TBD_CONTROL_LENGTH_MASK_2 0x003FF800
#define DC_TBD_CONTROL_NO_PAD 0x00800000
#define DC_TBD_CONTROL_CHAINED 0x01000000
#define DC_TBD_CONTROL_END_OF_RING 0x02000000
#define DC_TBD_CONTROL_NO_CRC 0x04000000
#define DC_TBD_CONTROL_SETUP_FRAME 0x08000000
#define DC_TBD_CONTROL_FIRST_FRAGMENT 0x20000000
#define DC_TBD_CONTROL_LAST_FRAGMENT 0x40000000
#define DC_TBD_CONTROL_REQUEST_INTERRUPT 0x80000000
#define DC_TBD_CONTROL_PERFECT_FILTER 0x00000000
#define DC_TBD_CONTROL_HASH_PERFECT_FILTER 0x00400000
#define DC_TBD_CONTROL_INVERSE_FILTER 0x10000000
#define DC_TBD_CONTROL_IMPERFECT_FILTER 0x10400000
#define DC_TBD_CONTROL_LENGTH_2_SHIFT 11
ULONG Address1;
ULONG Address2;
} DC_TBD, *PDC_TBD;
C_ASSERT(sizeof(DC_TBD) == 16);
/*
* Receive Buffer Descriptor
*/
typedef struct _DC_RBD
{
ULONG Status;
#define DC_RBD_STATUS_OVERRUN 0x00000001
#define DC_RBD_STATUS_CRC_ERROR 0x00000002
#define DC_RBD_STATUS_DRIBBLE 0x00000004
#define DC_RBD_STATUS_MII_ERROR 0x00000008
#define DC_RBD_STATUS_WDT_EXPIRED 0x00000010
#define DC_RBD_STATUS_FRAME_TYPE 0x00000020
#define DC_RBD_STATUS_COLLISION_SEEN 0x00000040
#define DC_RBD_STATUS_TOO_LONG 0x00000080
#define DC_RBD_STATUS_LAST_DESCRIPTOR 0x00000100
#define DC_RBD_STATUS_FIRST_DESCRIPTOR 0x00000200
#define DC_RBD_STATUS_MULTICAST 0x00000400
#define DC_RBD_STATUS_RUNT 0x00000800
#define DC_RBD_STATUS_DATA_TYPE_MASK 0x00003000
#define DC_RBD_STATUS_LENGTH_ERROR 0x00004000
#define DC_RBD_STATUS_ERROR_SUMMARY 0x00008000
#define DC_RBD_STATUS_FRAME_LENGTH_MASK 0x3FFF0000
#define DC_RBD_STATUS_FILTERING_FAIL 0x40000000
#define DC_RBD_STATUS_OWNED 0x80000000
#define DC_RBD_STATUS_FRAME_LENGTH_SHIFT 16
ULONG Control;
#define DC_RBD_CONTROL_BUFFER_LENGTH_MASK_1 0x000007FF
#define DC_RBD_CONTROL_BUFFER_LENGTH_MASK_2 0x003FF800
#define DC_RBD_CONTROL_CHAINED 0x01000000
#define DC_RBD_CONTROL_END_OF_RING 0x02000000
ULONG Address1;
ULONG Address2;
} DC_RBD, *PDC_RBD;
C_ASSERT(sizeof(DC_RBD) == 16);
#define DC_PATTERN_FILTERS 4
/*
* Wake-Up Filter Register Block
*/
typedef union _DC_PATTERN_FILTER_BLOCK
{
struct
{
ULONG Mask[DC_PATTERN_FILTERS];
UCHAR Command[DC_PATTERN_FILTERS];
#define DC_PATTERN_FILTER_CMD_ENABLE 0x01
#define DC_PATTERN_FILTER_CMD_INVERSE_MODE 0x02
#define DC_PATTERN_FILTER_CMD_ADD_PREV 0x04
#define DC_PATTERN_FILTER_CMD_MULTICAST 0x08
UCHAR Offset[DC_PATTERN_FILTERS];
USHORT Crc[DC_PATTERN_FILTERS];
};
ULONG AsULONG[8];
} DC_PATTERN_FILTER_BLOCK, *PDC_PATTERN_FILTER_BLOCK;
C_ASSERT(sizeof(DC_PATTERN_FILTER_BLOCK) == 32);
#include <poppack.h>
/*
* NIC Control and Status Registers
*/
typedef enum _DC_CSR
{
DcCsr0_BusMode = 0x00,
DcCsr1_TxPoll = 0x08,
DcCsr1_WakeUpFilter = 0x08,
DcCsr2_RxPoll = 0x10,
DcCsr2_WakeUpControl = 0x10,
DcCsr3_RxRingAddress = 0x18,
DcCsr4_TxRingAddress = 0x20,
DcCsr5_Status = 0x28,
DcCsr6_OpMode = 0x30,
DcCsr7_IrqMask = 0x38,
DcCsr8_RxCounters = 0x40,
DcCsr9_SerialInterface = 0x48,
DcCsr10_BootRom = 0x50,
DcCsr11_FullDuplex = 0x58,
DcCsr11_Timer = 0x58,
DcCsr12_Gpio = 0x60,
DcCsr12_SiaStatus = 0x60,
DcCsr13_SiaConnectivity = 0x68,
DcCsr14_SiaTxRx = 0x70,
DcCsr15_SiaGeneral = 0x78,
} DC_CSR;
/*
* CSR0 Bus Mode
*/
#define DC_BUS_MODE_SOFT_RESET 0x00000001
#define DC_BUS_MODE_BUS_ARB 0x00000002
#define DC_BUS_MODE_DESC_SKIP_LENGTH_MASK 0x0000007C
#define DC_BUS_MODE_BUFFERS_BIG_ENDIAN 0x00000080
#define DC_BUS_MODE_BURST_LENGTH_MASK 0x00003F00
#define DC_BUS_MODE_CACHE_ALIGNMENT_MASK 0x0000C000
#define DC_BUS_MODE_DIAGNOSTIC_ADDRESS_SPACE 0x00010000
#define DC_BUS_MODE_TX_POLL_MASK 0x000E0000
#define DC_BUS_MODE_DESC_BIG_ENDIAN 0x00100000
#define DC_BUS_MODE_READ_MULTIPLE 0x00200000
#define DC_BUS_MODE_READ_LINE 0x00800000
#define DC_BUS_MODE_WRITE_INVALIDATE 0x01000000
#define DC_BUS_MODE_ON_NOW_UNLOCK 0x04000000
#define DC_BUS_MODE_BURST_LENGTH_NO_LIMIT 0x00000000
#define DC_BUS_MODE_BURST_LENGTH_1 0x00000100
#define DC_BUS_MODE_BURST_LENGTH_2 0x00000200
#define DC_BUS_MODE_BURST_LENGTH_4 0x00000400
#define DC_BUS_MODE_BURST_LENGTH_8 0x00000800
#define DC_BUS_MODE_BURST_LENGTH_16 0x00001000
#define DC_BUS_MODE_BURST_LENGTH_32 0x00002000
#define DC_BUS_MODE_CACHE_ALIGNMENT_NONE 0x00000000
#define DC_BUS_MODE_CACHE_ALIGNMENT_8 0x00004000
#define DC_BUS_MODE_CACHE_ALIGNMENT_16 0x00008000
#define DC_BUS_MODE_CACHE_ALIGNMENT_32 0x0000C000
#define DC_BUS_MODE_TX_POLL_DISABLED 0x00000000
#define DC_BUS_MODE_TX_POLL_1 0x00020000
#define DC_BUS_MODE_TX_POLL_2 0x00040000
#define DC_BUS_MODE_TX_POLL_3 0x00060000
#define DC_BUS_MODE_TX_POLL_4 0x00080000
#define DC_BUS_MODE_TX_POLL_5 0x000A0000
#define DC_BUS_MODE_TX_POLL_6 0x000C0000
#define DC_BUS_MODE_TX_POLL_7 0x000E0000
#define DC_BUS_MODE_DESC_SKIP_LENGTH_0 0x00000000
#define DC_BUS_MODE_DESC_SKIP_LENGTH_1 0x00000004
#define DC_BUS_MODE_DESC_SKIP_LENGTH_2 0x00000008
#define DC_BUS_MODE_DESC_SKIP_LENGTH_4 0x00000010
#define DC_BUS_MODE_DESC_SKIP_LENGTH_8 0x00000020
#define DC_BUS_MODE_DESC_SKIP_LENGTH_16 0x00000040
#define DC_BUS_MODE_DESC_SKIP_LENGTH_32 0x00000080
/*
* CSR1 Transmit Poll Demand
*/
#define DC_TX_POLL_DOORBELL 0x00000001
/*
* CSR2 Receive Poll Demand
*/
#define DC_RX_POLL_DOORBELL 0x00000001
/*
* CSR2 Wake Up Control
*/
#define DC_WAKE_UP_CONTROL_LINK_CHANGE 0x00000001
#define DC_WAKE_UP_CONTROL_MAGIC_PACKET 0x00000002
#define DC_WAKE_UP_CONTROL_PATTERN_MATCH 0x00000004
#define DC_WAKE_UP_STATUS_LINK_CHANGE 0x00000010
#define DC_WAKE_UP_STATUS_MAGIC_PACKET 0x00000020
#define DC_WAKE_UP_STATUS_PATTERN_MATCH 0x00000040
#define DC_WAKE_UP_CONTROL_GLOBAL_UNICAST 0x00000200
#define DC_WAKE_UP_CONTROL_VLAN_ENABLE 0x00000800
#define DC_WAKE_UP_CONTROL_VLAN_TYPE_MASK 0xFFFF0000
/*
* CSR5 Status, CSR7 Irq Mask
*/
#define DC_IRQ_TX_OK 0x00000001
#define DC_IRQ_TX_STOPPED 0x00000002
#define DC_IRQ_TX_NO_BUFFER 0x00000004
#define DC_IRQ_TX_JABBER_TIMEOUT 0x00000008
#define DC_IRQ_LINK_PASS 0x00000010
#define DC_IRQ_TX_UNDERFLOW 0x00000020
#define DC_IRQ_RX_OK 0x00000040
#define DC_IRQ_RX_NO_BUFFER 0x00000080
#define DC_IRQ_RX_STOPPED 0x00000100
#define DC_IRQ_RX_WDT_TIMEOUT 0x00000200
#define DC_IRQ_AUI 0x00000400
#define DC_IRQ_TX_EARLY 0x00000400
#define DC_IRQ_FD_FRAME_RECEIVED 0x00000800
#define DC_IRQ_TIMER_TIMEOUT 0x00000800
#define DC_IRQ_LINK_FAIL 0x00001000
#define DC_IRQ_SYSTEM_ERROR 0x00002000
#define DC_IRQ_RX_EARLY 0x00004000
#define DC_IRQ_ABNORMAL_SUMMARY 0x00008000
#define DC_IRQ_NORMAL_SUMMARY 0x00010000
#define DC_STATUS_RX_STATE_MASK 0x000E0000
#define DC_STATUS_TX_STATE_MASK 0x00700000
#define DC_STATUS_SYSTEM_ERROR_MASK 0x03800000
#define DC_IRQ_GPIO_PORT 0x04000000
#define DC_IRQ_LINK_CHANGED 0x08000000
#define DC_IRQ_HPNA_PHY 0x10000000
#define DC_STATUS_TX_STATE_STOPPED 0x00000000
#define DC_STATUS_TX_STATE_FETCH 0x00100000
#define DC_STATUS_TX_STATE_WAIT_FOR_END 0x00200000
#define DC_STATUS_TX_STATE_READ 0x00300000
#define DC_STATUS_TX_STATE_RESERVED 0x00400000
#define DC_STATUS_TX_STATE_SETUP_PACKET 0x00500000
#define DC_STATUS_TX_STATE_SUSPENDED 0x00600000
#define DC_STATUS_TX_STATE_CLOSE 0x00700000
#define DC_STATUS_RX_STATE_STOPPED 0x00000000
#define DC_STATUS_RX_STATE_FETCH 0x00020000
#define DC_STATUS_RX_STATE_CHECK_END 0x00040000
#define DC_STATUS_RX_STATE_WAIT_FOR_RCV 0x00060000
#define DC_STATUS_RX_STATE_SUSPENDED 0x00080000
#define DC_STATUS_RX_STATE_CLOSE_DESC 0x000A0000
#define DC_STATUS_RX_STATE_FLUSH 0x000C0000
#define DC_STATUS_RX_STATE_DEQUEUE 0x000E0000
#define DC_STATUS_SYSTEM_ERROR_PARITY 0x00000000
#define DC_STATUS_SYSTEM_ERROR_MASTER_ABORT 0x00800000
#define DC_STATUS_SYSTEM_ERROR_TARGET_ABORT 0x01000000
/*
* CSR6 Operation Mode
*/
#define DC_OPMODE_RX_HASH_PERFECT_FILT 0x00000001
#define DC_OPMODE_RX_ENABLE 0x00000002
#define DC_OPMODE_RX_HASH_ONLY_FILT 0x00000004
#define DC_OPMODE_RX_RUNTS 0x00000008
#define DC_OPMODE_RX_INVERSE_FILT 0x00000010
#define DC_OPMODE_BACKOFF_COUNTER 0x00000020
#define DC_OPMODE_RX_PROMISCUOUS 0x00000040
#define DC_OPMODE_RX_ALL_MULTICAST 0x00000080
#define DC_OPMODE_FKD 0x00000100
#define DC_OPMODE_FULL_DUPLEX 0x00000200
#define DC_OPMODE_LOOPBACK_MASK 0x00000C00
#define DC_OPMODE_FORCE_COLLISIONS 0x00001000
#define DC_OPMODE_TX_ENABLE 0x00002000
#define DC_OPMODE_TX_THRESHOLD_CTRL_MASK 0x0000C000
#define DC_OPMODE_TX_BACK_PRESSURE 0x00010000
#define DC_OPMODE_TX_CAPTURE_EFFECT 0x00020000
#define DC_OPMODE_PORT_SELECT 0x00040000
#define DC_OPMODE_PORT_HEARTBEAT_DISABLE 0x00080000
#define DC_OPMODE_STORE_AND_FORWARD 0x00200000
#define DC_OPMODE_PORT_XMIT_10 0x00400000
#define DC_OPMODE_PORT_PCS 0x00800000
#define DC_OPMODE_PORT_SCRAMBLER 0x01000000
#define DC_OPMODE_PORT_ALWAYS 0x02000000
#define DC_OPMODE_ADDR_LSB_IGNORE 0x04000000
#define DC_OPMODE_RX_RECEIVE_ALL 0x40000000
#define DC_OPMODE_TX_SPECIAL_CAPTURE_EFFECT 0x80000000
#define DC_OPMODE_LOOPBACK_NORMAL 0x00000000
#define DC_OPMODE_LOOPBACK_INTERNAL 0x00000400
#define DC_OPMODE_LOOPBACK_EXTERNAL 0x00000800
#define DC_OPMODE_TX_THRESHOLD_LEVEL 0x00004000
#define DC_OPMODE_TX_THRESHOLD_MAX 0x0000C000
#define DC_OPMODE_MEDIA_MASK ( \
DC_OPMODE_TX_THRESHOLD_CTRL_MASK | \
DC_OPMODE_LOOPBACK_MASK | \
DC_OPMODE_FULL_DUPLEX | \
DC_OPMODE_PORT_SELECT | \
DC_OPMODE_PORT_HEARTBEAT_DISABLE | \
DC_OPMODE_PORT_XMIT_10 | \
DC_OPMODE_PORT_PCS | \
DC_OPMODE_PORT_SCRAMBLER)
/*
* CSR8 Receive Counters
*/
#define DC_COUNTER_RX_NO_BUFFER_MASK 0x0001FFFF
#define DC_COUNTER_RX_OVERFLOW_MASK 0x1FFE0000
#define DC_COUNTER_RX_OVERFLOW_SHIFT 17
/*
* CSR9 Serial Interface
*/
#define DC_SERIAL_EE_CS 0x00000001
#define DC_SERIAL_EE_SK 0x00000002
#define DC_SERIAL_EE_DI 0x00000004
#define DC_SERIAL_EE_DO 0x00000008
#define DC_SERIAL_EE_REG 0x00000400
#define DC_SERIAL_EE_SR 0x00000800
#define DC_SERIAL_EE_WR 0x00002000
#define DC_SERIAL_EE_RD 0x00004000
#define DC_SERIAL_EE_MOD 0x00008000
#define DC_SERIAL_MII_MDC 0x00010000
#define DC_SERIAL_MII_MDO 0x00020000
#define DC_SERIAL_MII_MII 0x00040000
#define DC_SERIAL_MII_MDI 0x00080000
#define DC_SERIAL_EAR_DN 0x80000000
#define DC_SERIAL_EAR_DT 0x000000FF
#define DC_SERIAL_SPI_CS 0x00100000
#define DC_SERIAL_SPI_SK 0x00200000
#define DC_SERIAL_SPI_DI 0x00400000
#define DC_SERIAL_SPI_DO 0x00800000
#define DC_SERIAL_EE_DI_SHIFT 2
#define DC_SERIAL_EE_DO_SHIFT 3
#define DC_SERIAL_MII_MDO_SHIFT 17
#define DC_SERIAL_MII_MDI_SHIFT 19
#define DC_SERIAL_SPI_DI_SHIFT 22
#define DC_SERIAL_SPI_DO_SHIFT 23
/*
* CSR11 Timer
*/
#define DC_TIMER_VALUE_MASK 0x0000FFFF
#define DC_TIMER_CONTINUOUS 0x00010000
#define DC_TIMER_RX_NUMBER_MASK 0x000E0000
#define DC_TIMER_RX_TIMER_MASK 0x00F00000
#define DC_TIMER_TX_NUMBER_MASK 0x07000000
#define DC_TIMER_TX_TIMER_MASK 0x78000000
#define DC_TIMER_CYCLE_SIZE 0x80000000
#define DC_TIMER_RX_NUMBER_SHIFT 17
#define DC_TIMER_RX_TIMER_SHIFT 20
#define DC_TIMER_TX_NUMBER_SHIFT 24
#define DC_TIMER_TX_TIMER_SHIFT 27
/*
* CSR12 SIA Status
*/
#define DC_SIA_STATUS_MII_RECEIVE_ACTIVITY 0x00000001
#define DC_SIA_STATUS_NETWORK_CONNECTION_ERROR 0x00000002
#define DC_SIA_STATUS_100T_LINK_FAIL 0x00000002
#define DC_SIA_STATUS_10T_LINK_FAIL 0x00000004
#define DC_SIA_STATUS_SELECTED_PORT_ACTIVITY 0x00000100
#define DC_SIA_STATUS_AUI_ACTIVITY 0x00000100
#define DC_SIA_STATUS_HPNA_ACTIVITY 0x00000100
#define DC_SIA_STATUS_NONSEL_PORT_ACTIVITY 0x00000200
#define DC_SIA_STATUS_10T_ACTIVITY 0x00000200
#define DC_SIA_STATUS_NSN 0x00000400
#define DC_SIA_STATUS_TX_REMOTE_FAULT 0x00000800
#define DC_SIA_STATUS_ANS_MASK 0x00007000
#define DC_SIA_STATUS_LP_AUTONED_SUPPORTED 0x00008000
#define DC_SIA_STATUS_LP_CODE_WORD_MASK 0xFFFF0000
#define DC_SIA_STATUS_ANS_AUTONEG_DISABLED 0x00000000
#define DC_SIA_STATUS_ANS_TX_DISABLE 0x00001000
#define DC_SIA_STATUS_ANS_ABILITY_DETECT 0x00002000
#define DC_SIA_STATUS_ANS_ACK_DETECT 0x00003000
#define DC_SIA_STATUS_ANS_ACK_COMPLETE 0x00004000
#define DC_SIA_STATUS_ANS_AUTONEG_COMPLETE 0x00005000
#define DC_SIA_STATUS_ANS_LINK_CHECK 0x00006000
#define DC_SIA_STATUS_LP_CODE_WORD_SHIFT 16
#define DC_GPIO_CONTROL 0x100
/*
* CSR13 SIA Connectivity
*/
#define DC_SIA_CONN_RESET 0x00000000
#define DC_SIA_CONN_HPNA 0x00000008
/*
* CSR14 SIA Transmit and Receive
*/
#define DC_SIA_TXRX_ENCODER 0x00000001
#define DC_SIA_TXRX_LOOPBACK 0x00000002
#define DC_SIA_TXRX_DRIVER 0x00000004
#define DC_SIA_TXRX_LINK_PULSE 0x00000008
#define DC_SIA_TXRX_COMPENSATION 0x00000030
#define DC_SIA_TXRX_ADV_10T_HD 0x00000040
#define DC_SIA_TXRX_AUTONEG 0x00000080
#define DC_SIA_TXRX_RX_SQUELCH 0x00000100
#define DC_SIA_TXRX_COLLISION_SQUELCH 0x00000200
#define DC_SIA_TXRX_COLLISION_DETECT 0x00000400
#define DC_SIA_TXRX_HEARTBEAT 0x00000800
#define DC_SIA_TXRX_LINK_TEST 0x00001000
#define DC_SIA_TXRX_AUTOPOLARITY 0x00002000
#define DC_SIA_TXRX_SET_POLARITY_PLUS 0x00004000
#define DC_SIA_TXRX_10T_AUTOSENSE 0x00008000
#define DC_SIA_TXRX_ADV_100TX_HD 0x00010000
#define DC_SIA_TXRX_ADV_100TX_FD 0x00020000
#define DC_SIA_TXRX_ADV_100T4 0x00040000
/*
* CSR15 SIA and GPIO
*/
#define DC_SIA_GENERAL_JABBER_DISABLE 0x00000001
#define DC_SIA_GENERAL_HOST_UNJAB 0x00000002
#define DC_SIA_GENERAL_JABBER_CLOCK 0x00000004
#define DC_SIA_GENERAL_AUI_BNC_MODE 0x00000008
#define DC_SIA_GENERAL_RX_WDT_DISABLE 0x00000010
#define DC_SIA_GENERAL_RX_WDT_RELEASE 0x00000020
#define DC_SIA_GENERAL_LINK_EXTEND 0x00000800
#define DC_SIA_GENERAL_RX_MAGIC_PACKET 0x00004000
#define DC_SIA_GENERAL_HCKR 0x00008000
#define DC_SIA_GENERAL_GPIO_MASK 0x000F0000
#define DC_SIA_GENERAL_LGS3 0x00100000
#define DC_SIA_GENERAL_LGS2 0x00200000
#define DC_SIA_GENERAL_LGS1 0x00400000
#define DC_SIA_GENERAL_LGS0 0x00800000
#define DC_SIA_GENERAL_GEI0 0x01000000
#define DC_SIA_GENERAL_GEI1 0x02000000
#define DC_SIA_GENERAL_RECEIVE_MATCH 0x04000000
#define DC_SIA_GENERAL_CONTROL_WRITE 0x08000000
#define DC_SIA_GENERAL_GI0 0x10000000
#define DC_SIA_GENERAL_GI1 0x20000000
#define DC_SIA_GENERAL_IRQ_RX_MATCH 0x40000000
#define DC_RBD_STATUS_INVALID \
(DC_RBD_STATUS_OVERRUN | \
DC_RBD_STATUS_CRC_ERROR | \
DC_RBD_STATUS_WDT_EXPIRED | \
DC_RBD_STATUS_COLLISION_SEEN | \
DC_RBD_STATUS_TOO_LONG | \
DC_RBD_STATUS_RUNT | \
DC_RBD_STATUS_LENGTH_ERROR)
#define DC_GENERIC_IRQ_MASK \
(DC_IRQ_TX_OK | DC_IRQ_TX_STOPPED | DC_IRQ_TX_JABBER_TIMEOUT | \
DC_IRQ_RX_OK | DC_IRQ_TX_UNDERFLOW | \
DC_IRQ_RX_STOPPED | \
DC_IRQ_SYSTEM_ERROR | DC_IRQ_ABNORMAL_SUMMARY | DC_IRQ_NORMAL_SUMMARY)
/* Errata: The programming guide incorrectly stated that CSR13 must be set to 0x30480009 */
#define DC_HPNA_ANALOG_CTRL 0x708A0000
/*
* PCI Configuration Registers
*/
#define DC_PCI_DEVICE_CONFIG 0x40
#define DC_PCI_DEVICE_CONFIG_SNOOZE 0x40000000
#define DC_PCI_DEVICE_CONFIG_SLEEP 0x80000000
/*
* SPI Interface
*/
#define DC_SPI_BYTE_WRITE_OPERATION 2
#define DC_SPI_BYTE_READ_OPERATION 3
#define DC_SPI_CLEAR_WRITE_ENABLE 4
#define DC_SPI_SET_WRITE_ENABLE 6
/*
* HomePNA PHY Registers
*/
#define HPNA_CONTROL_LOW 0x00
#define HPNA_CONTROL_HIGH 0x01
#define HPNA_NOISE 0x10
#define HPNA_NOISE_FLOOR 0x12
#define HPNA_NOISE_CEILING 0x13
#define HPNA_NOISE_ATTACK 0x14
/*
* MDIO Protocol (IEEE 802.3)
*/
#define MDIO_START 0x01
#define MDIO_WRITE 0x01
#define MDIO_READ 0x02
#define MDIO_TA 0x02
#define MDIO_PREAMBLE 0xFFFFFFFF
#define MII_MAX_PHY_ADDRESSES 32
/*
* PHY register definitions (IEEE 802.3)
*/
#define MII_CONTROL 0x00
#define MII_CR_COLLISION_TEST 0x0080
#define MII_CR_FULL_DUPLEX 0x0100
#define MII_CR_AUTONEG_RESTART 0x0200
#define MII_CR_ISOLATE 0x0400
#define MII_CR_POWER_DOWN 0x0800
#define MII_CR_AUTONEG 0x1000
#define MII_CR_SPEED_SELECTION 0x2000
#define MII_CR_LOOPBACK 0x4000
#define MII_CR_RESET 0x8000
#define MII_STATUS 0x01
#define MII_SR_LINK_STATUS 0x0004
#define MII_SR_AUTONEG_COMPLETE 0x0020
#define MII_PHY_ID1 0x02
#define MII_PHY_ID2 0x03
#define MII_AUTONEG_ADVERTISE 0x04
#define MII_ADV_CSMA 0x0001
#define MII_ADV_10T_HD 0x0020
#define MII_ADV_10T_FD 0x0040
#define MII_ADV_100T_HD 0x0080
#define MII_ADV_100T_FD 0x0100
#define MII_ADV_100T4 0x0200
#define MII_ADV_PAUSE_SYM 0x0400
#define MII_ADV_PAUSE_ASYM 0x0800
#define MII_AUTONEG_LINK_PARTNER 0x05
#define MII_LP_10T_HD 0x0020
#define MII_LP_10T_FD 0x0040
#define MII_LP_100T_HD 0x0080
#define MII_LP_100T_FD 0x0100
#define MII_LP_100T4 0x0200
#define MII_LP_PAUSE_SYM 0x0400
#define MII_LP_PAUSE_ASYM 0x0800
#define MII_AUTONEG_EXPANSION 0x06
#define MII_EXP_LP_AUTONEG 0x0001
#define MII_MASTER_SLAVE_CONTROL 0x09
#define MII_MS_CR_1000T_HD 0x0100
#define MII_MS_CR_1000T_FD 0x0200
#define MII_MASTER_SLAVE_STATUS 0x0A
#define MII_MS_SR_1000T_FD 0x0800
#define MII_ADV_100 \
(MII_ADV_100T_HD | MII_ADV_100T_FD | MII_ADV_100T4)

View file

@ -0,0 +1,70 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Debug routines
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
/* GLOBALS ********************************************************************/
static PCSTR MediaName[MEDIA_MAX] =
{
"10Base-T",
"10Base-2 (BNC)",
"10Base-5 (AUI)",
"100Base-TX HD",
"10Base-T FD",
"100Base-TX FD",
"100Base-T4",
"100Base-FX HD",
"100Base-FX FD",
"HomePNA",
"MII",
};
/* FUNCTIONS ******************************************************************/
PCSTR
MediaNumber2Str(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG MediaNumber)
{
switch (MediaNumber)
{
case MEDIA_100TX_HD:
{
if (Adapter->ChipType == DC21041)
return "10Base-T HD";
break;
}
default:
break;
}
ASSERT(MediaNumber < MEDIA_MAX);
return MediaName[MediaNumber];
}
PCSTR
DcDbgBusError(
_In_ ULONG InterruptStatus)
{
switch (InterruptStatus & DC_STATUS_SYSTEM_ERROR_MASK)
{
case DC_STATUS_SYSTEM_ERROR_PARITY:
return "Parity Error";
case DC_STATUS_SYSTEM_ERROR_MASTER_ABORT:
return "Master Abort";
case DC_STATUS_SYSTEM_ERROR_TARGET_ABORT:
return "Target Abort";
default:
return "<unknown>";
}
}

View file

@ -0,0 +1,96 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Debug support header file
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
#ifndef __RELFILE__
#define __RELFILE__ __FILE__
#endif
#if DBG
// #define DEBUG_TRACE
// #define DEBUG_INFO
#define DEBUG_INFO_VERB
#define DEBUG_WARN
#define DEBUG_ERR
#ifdef DEBUG_TRACE
#define TRACE(fmt, ...) \
do { \
if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \
DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
} while (0)
#else
#define TRACE
#endif
#ifdef DEBUG_INFO
#define INFO(fmt, ...) \
do { \
if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \
DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
} while (0)
#else
#define INFO
#endif
#ifdef DEBUG_INFO_VERB
#define INFO_VERB(fmt, ...) \
do { \
if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \
DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
} while (0)
#else
#define INFO_VERB
#endif
#ifdef DEBUG_WARN
#define WARN(fmt, ...) \
do { \
if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \
DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
} while (0)
#else
#define WARN
#endif
#ifdef DEBUG_ERR
#define ERR(fmt, ...) \
do { \
if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \
DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
} while (0)
#else
#define ERR
#endif
PCSTR
MediaNumber2Str(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG MediaNumber);
PCSTR
DcDbgBusError(
_In_ ULONG InterruptStatus);
#else
#define TRACE
#define INFO
#define INFO_VERB
#define WARN
#define ERR
#define MediaNumber2Str
#define DcDbgBusError
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,108 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: EEPROM specific definitions
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
#include <pshpack1.h>
typedef struct _DC_SROM_COMPACT_BLOCK
{
USHORT SelectedConnectionType;
UCHAR GpioDirection; /* 21140 only */
UCHAR BlockCount;
} DC_SROM_COMPACT_BLOCK, *PDC_SROM_COMPACT_BLOCK;
#include <poppack.h>
typedef struct _DC_SROM_REPAIR_ENTRY
{
#if DBG
PCSTR Name;
#endif
PUCHAR InfoLeaf;
ULONG Length;
} DC_SROM_REPAIR_ENTRY, *PDC_SROM_REPAIR_ENTRY;
typedef struct _DC_SROM_ENTRY
{
LIST_ENTRY ListEntry;
ULONG BusNumber;
DC_CHIP_TYPE ChipType;
UCHAR DeviceNumber;
ULONG InterruptLevel;
ULONG InterruptVector;
ULONG DeviceBitmap;
UCHAR SRomImage[ANYSIZE_ARRAY];
} DC_SROM_ENTRY, *PDC_SROM_ENTRY;
#define SRomIsBlockExtended(Byte) ((Byte) & 0x80)
#define SRomGetExtendedBlockLength(Byte) (((Byte) & 0x7F) + 1)
#define SRomGetMediaCode(Byte) ((Byte) & 0x3F)
#define SRomBlockHasExtendedData(Byte) ((Byte) & 0x40)
#define SRomIsDefaultMedia(Word) ((Word) & 0x4000)
#define SRomMediaHasActivityIndicator(Word) (((Word) & 0x8000) == 0)
#define SRomMediaActivityIsActiveLow(Word) ((Word) & 0x80)
#define SRomMediaGetSenseMask(Word) (1 << (((Word) & 0x0E) >> 1))
#define SRomCommandToOpMode(Word) (((Word) & 0x71) << 18)
#define SRomMediaAutoSense(Media) ((Media) & 0x800)
#define SRomMediaToMediaNumber(Word) ((Word) & 0x1F)
#define SRomHmrRegAddress(Byte) ((Byte) & 0x1F)
#define SROM_OPMODE_MASK \
(DC_OPMODE_PORT_SELECT | \
DC_OPMODE_PORT_XMIT_10 | \
DC_OPMODE_PORT_PCS | \
DC_OPMODE_PORT_SCRAMBLER)
#define EE_SIZE 128
#define EAR_SIZE 32
#define EAR_TEST_PATTERN 0xAA5500FFAA5500FFULL
#define EEPROM_CMD_WRITE 5
#define EEPROM_CMD_READ 6
#define EEPROM_CMD_ERASE 7
#define EEPROM_CMD_LENGTH 3
/*
* Various offsets in the SROM
*/
#define SROM_VERSION 18
#define SROM_CONTROLLER_COUNT 19
#define SROM_MAC_ADDRESS 20
#define SROM_DEVICE_NUMBER(n) (26 + ((n) * 3))
#define SROM_LEAF_OFFSET(n) (27 + ((n) * 3))
#define SROM_CHECKSUM_V1 126
#define SROM_CHECKSUM_V2 94
/*
* SROM compact and extended format types
*/
#define SROM_BLOCK_TYPE_GPR 0
#define SROM_BLOCK_TYPE_MII_1 1
#define SROM_BLOCK_TYPE_SIA 2
#define SROM_BLOCK_TYPE_MII_2 3
#define SROM_BLOCK_TYPE_SYM 4
#define SROM_BLOCK_TYPE_RESET 5
#define SROM_BLOCK_TYPE_PHY_SHUTDOWN 6
#define SROM_BLOCK_TYPE_HOMERUN 7
#define SROM_MAX_STREAM_REGS 6
/*
* SROM media codes
*/
#define SROM_MEDIA_10T 0
#define SROM_MEDIA_BNC 1
#define SROM_MEDIA_AUI 2
#define SROM_MEDIA_100T_HD 3
#define SROM_MEDIA_10T_FD 4
#define SROM_MEDIA_100TX_FD 5
#define SROM_MEDIA_100T4 6
#define SROM_MEDIA_100FX_HD 7
#define SROM_MEDIA_100FX_FD 8
#define SROM_MEDIA_MAX 8
#define SROM_MEDIA_HMR 18

View file

@ -0,0 +1,219 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: EEPROM data for boards without the standard SROM Format
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* Adapted from the Linux tulip driver written by Donald Becker */
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
/* GLOBALS ********************************************************************/
/* Asante */
static DC_PG_DATA UCHAR SRompLeafAsante[] =
{
0x00, 0x00, 0x94,
0x00, 0x08, // Default Autoselect
0x00, // GPIO direction
0x01, // 1 block
0x80 + 12, // Extended block, 12 bytes
0x01, // MII
0x00, // PHY #0
0x00, // GPIO stream length
0x00, // Reset stream length
0x00, 0x78, // Capabilities
0xE0, 0x01, // Advertisement
0x00, 0x50, // FDX
0x00, 0x18, // TTM
};
/* SMC 9332DST */
static DC_PG_DATA UCHAR SRompLeaf9332[] =
{
0x00, 0x00, 0xC0,
0x00, 0x08, // Default Autoselect
0x1F, // GPIO direction
0x04, // 4 blocks
0x00, // GPR 0
0x00, // GPIO data
0x9E, 0x00, // Command 0x009E
0x04, // GPR 4
0x00, // GPIO data
0x9E, 0x00, // Command 0x009E
0x03, // GPR 3
0x09, // GPIO data
0x6D, 0x00, // Command 0x006D
0x05, // GPR 5
0x09, // GPIO data
0x6D, 0x00, // Command 0x006D
};
/* Cogent EM100 */
static DC_PG_DATA UCHAR SRompLeafEm100[] =
{
0x00, 0x00, 0x92,
0x00, 0x08, // Default Autoselect
0x3F, // GPIO direction
0x06, // 6 blocks
0x07, // GPR 7
0x01, // GPIO data
0x21, 0x80, // Command 0x8021
0x08, // GPR 8
0x01, // GPIO data
0x21, 0x80, // Command 0x8021
0x00, // GPR 0
0x01, // GPIO data
0x9E, 0x00, // Command 0x009E
0x04, // GPR 4
0x01, // GPIO data
0x9E, 0x00, // Command 0x009E
0x03, // GPR 3
0x01, // GPIO data
0x6D, 0x00, // Command 0x006D
0x05, // GPR 5
0x01, // GPIO data
0x6D, 0x00, // Command 0x006D
};
/* Maxtech NX-110 */
static DC_PG_DATA UCHAR SRompLeafNx110[] =
{
0x00, 0x00, 0xE8,
0x00, 0x08, // Default Autoselect
0x13, // GPIO direction
0x05, // 5 blocks
0x01, // GPR 1
0x10, // GPIO data
0x9E, 0x00, // Command 0x009E
0x00, // GPR 0
0x00, // GPIO data
0x9E, 0x00, // Command 0x009E
0x04, // GPR 4
0x00, // GPIO data
0x9E, 0x00, // Command 0x009E
0x03, // GPR 3
0x03, // GPIO data
0x6D, 0x00, // Command 0x006D
0x05, // GPR 5
0x03, // GPIO data
0x6D, 0x00, // Command 0x006D
};
/* Accton EN1207 */
static DC_PG_DATA UCHAR SRompLeafEn1207[] =
{
0x00, 0x00, 0xE8,
0x00, 0x08, // Default Autoselect
0x1F, // GPIO direction
0x05, // 5 blocks
0x01, // GPR 1
0x1B, // GPIO data
0x00, 0x00, // Command 0x0000
0x00, // GPR 0
0x0B, // GPIO data
0x9E, 0x00, // Command 0x009E
0x04, // GPR 4
0x0B, // GPIO data
0x9E, 0x00, // Command 0x009E
0x03, // GPR 3
0x1B, // GPIO data
0x6D, 0x00, // Command 0x006D
0x05, // GPR 5
0x1B, // GPIO data
0x6D, 0x00, // Command 0x006D
};
/* NetWinder */
static DC_PG_DATA UCHAR SRompLeafNetWinder[] =
{
0x00, 0x10, 0x57,
0x00, 0x08, // Default Autoselect
0x01, // 1 block
0x80 + 21, // Extended block, 21 bytes
0x03, // MII
0x01, // PHY #1
0x00, // GPIO stream length
0x03, // Reset stream length
0x21, 0x08,
0x00, 0x00,
0x01, 0x00,
0x00, 0x00, // Capabilities
0xE1, 0x01, // Advertisement
0x00, 0x00, // FDX
0x00, 0x00, // TTM
0x00, // PHY cannot be unplugged
};
/* Cobalt Microserver */
static DC_PG_DATA UCHAR SRompLeafCobaltMicroserver[] =
{
0x00, 0x10, 0xE0,
0x00, 0x08, // Default Autoselect
0x01, // 1 block
0x80 + 21, // Extended block, 21 bytes
0x03, // MII
0x00, // PHY #0
0x00, // GPIO stream length
0x04, // Reset stream length
0x01, 0x08, // Set control mode, GP0 output
0x00, 0x00, // Drive GP0 Low (RST is active low)
0x00, 0x08, // Control mode, GP0 input (undriven)
0x00, 0x00, // Clear control mode
0x00, 0x78, // Capabilities: 100TX FDX + HDX, 10bT FDX + HDX
0xE0, 0x01, // Advertise all above
0x00, 0x50, // FDX all above
0x00, 0x18, // Set fast TTM in 100bt modes
0x00, // PHY cannot be unplugged
};
#if DBG
#define DEFINE_BOARD(Leaf, Name) { Name, Leaf, sizeof(Leaf) - 3 /* OUI (3 bytes) */}
#else
#define DEFINE_BOARD(Leaf, Name) { Leaf, sizeof(Leaf) - 3 }
#endif
DC_PG_DATA
DC_SROM_REPAIR_ENTRY SRompRepairData[] =
{
DEFINE_BOARD(SRompLeafAsante, "Asante"),
DEFINE_BOARD(SRompLeaf9332, "SMC 9332DST"),
DEFINE_BOARD(SRompLeafEm100, "Cogent EM100"),
DEFINE_BOARD(SRompLeafNx110, "Maxtech NX-110"),
DEFINE_BOARD(SRompLeafEn1207, "Accton EN1207"), // Must be defined after the NX-110
DEFINE_BOARD(SRompLeafNetWinder, "NetWinder"),
DEFINE_BOARD(SRompLeafCobaltMicroserver, "Cobalt Microserver"),
DEFINE_BOARD(NULL, NULL),
};

View file

@ -0,0 +1,585 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Hardware specific functions
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* FUNCTIONS ******************************************************************/
VOID
DcDisableHw(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG OpMode;
/* Disable interrupts */
DC_WRITE(Adapter, DcCsr7_IrqMask, 0);
/* Stop DMA */
OpMode = Adapter->OpMode;
OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE);
DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
/* Put the adapter to snooze mode */
DcPowerSave(Adapter, TRUE);
/* Perform a software reset */
DC_WRITE(Adapter, DcCsr0_BusMode, DC_BUS_MODE_SOFT_RESET);
}
VOID
DcStopTxRxProcess(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG i, OpMode, Status;
OpMode = Adapter->OpMode;
OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE);
DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
for (i = 0; i < 5000; ++i)
{
Status = DC_READ(Adapter, DcCsr5_Status);
if (((Status & DC_STATUS_TX_STATE_MASK) == DC_STATUS_TX_STATE_STOPPED) &&
((Status & DC_STATUS_RX_STATE_MASK) == DC_STATUS_RX_STATE_STOPPED))
{
return;
}
NdisStallExecution(10);
}
WARN("Failed to stop the TX/RX process 0x%08lx\n", Status);
}
VOID
DcWriteGpio(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG Value)
{
ULONG Data, Register;
/* Some chips don't have a separate GPIO register */
if (Adapter->Features & DC_SIA_GPIO)
{
Data = Adapter->SiaSetting;
Data &= 0x0000FFFF; /* SIA */
Data |= Value << 16; /* GPIO */
Adapter->SiaSetting = Data;
Register = DcCsr15_SiaGeneral;
}
else
{
Data = Value;
Register = DcCsr12_Gpio;
}
DC_WRITE(Adapter, Register, Data);
}
VOID
DcWriteSia(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG Csr13,
_In_ ULONG Csr14,
_In_ ULONG Csr15)
{
ULONG SiaConn, SiaGen;
TRACE("CSR13 %08lx, CSR14 %08lx, CSR15 %08lx\n", Csr13, Csr14, Csr15);
SiaConn = 0;
/* The 21145 comes with 16 new bits in CSR13 */
if (Adapter->Features & DC_SIA_ANALOG_CONTROL)
{
SiaConn = Adapter->AnalogControl;
}
/* Reset the transceiver */
DC_WRITE(Adapter, DcCsr13_SiaConnectivity, SiaConn | DC_SIA_CONN_RESET);
NdisStallExecution(20);
/* Some chips don't have a separate GPIO register */
if (Adapter->Features & DC_SIA_GPIO)
{
SiaGen = Adapter->SiaSetting;
SiaGen &= 0xFFFF0000; /* GPIO */
SiaGen |= Csr15; /* SIA */
Adapter->SiaSetting = SiaGen;
}
else
{
SiaGen = Csr15;
}
DC_WRITE(Adapter, DcCsr14_SiaTxRx, Csr14);
DC_WRITE(Adapter, DcCsr15_SiaGeneral, SiaGen);
/* Don't reset the transceiver twice */
if (Csr13 == DC_SIA_CONN_RESET)
return;
DC_WRITE(Adapter, DcCsr13_SiaConnectivity, SiaConn | Csr13);
}
VOID
DcTestPacket(
_In_ PDC21X4_ADAPTER Adapter)
{
PDC_TCB Tcb;
PDC_TBD Tbd;
ULONG FrameNumber;
Adapter->MediaTestStatus = FALSE;
Adapter->ModeFlags |= DC_MODE_TEST_PACKET;
if (!Adapter->LoopbackFrameSlots)
{
ERR("Failed to complete test packets, CSR12 %08lx, CSR5 %08lx\n",
DC_READ(Adapter, DcCsr12_SiaStatus),
DC_READ(Adapter, DcCsr5_Status));
/* Try to recover the lost TX buffers */
NdisScheduleWorkItem(&Adapter->TxRecoveryWorkItem);
return;
}
--Adapter->LoopbackFrameSlots;
FrameNumber = (Adapter->LoopbackFrameNumber++) % DC_LOOPBACK_FRAMES;
Tbd = Adapter->CurrentTbd;
Adapter->CurrentTbd = DC_NEXT_TBD(Adapter, Tbd);
Tcb = Adapter->CurrentTcb;
Adapter->CurrentTcb = DC_NEXT_TCB(Adapter, Tcb);
Tcb->Tbd = Tbd;
Tcb->Packet = NULL;
ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED));
/* Put the loopback frame on the transmit ring */
Tbd->Address1 = Adapter->LoopbackFramePhys[FrameNumber];
Tbd->Address2 = 0;
Tbd->Control &= DC_TBD_CONTROL_END_OF_RING;
Tbd->Control |= DC_LOOPBACK_FRAME_SIZE |
DC_TBD_CONTROL_FIRST_FRAGMENT |
DC_TBD_CONTROL_LAST_FRAGMENT |
DC_TBD_CONTROL_REQUEST_INTERRUPT;
DC_WRITE_BARRIER();
Tbd->Status = DC_TBD_STATUS_OWNED;
/* Send the loopback packet to verify connectivity of a media */
DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL);
}
BOOLEAN
DcSetupFrameDownload(
_In_ PDC21X4_ADAPTER Adapter,
_In_ BOOLEAN WaitForCompletion)
{
PDC_TCB Tcb;
PDC_TBD Tbd;
ULONG i, Control;
Tbd = Adapter->CurrentTbd;
/* Ensure correct setup frame processing */
if (Tbd != Adapter->HeadTbd)
{
ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED));
/* Put the null frame on the transmit ring */
Tbd->Control &= DC_TBD_CONTROL_END_OF_RING;
Tbd->Address1 = 0;
Tbd->Address2 = 0;
DC_WRITE_BARRIER();
Tbd->Status = DC_TBD_STATUS_OWNED;
Tbd = DC_NEXT_TBD(Adapter, Tbd);
}
Adapter->CurrentTbd = DC_NEXT_TBD(Adapter, Tbd);
Tcb = Adapter->CurrentTcb;
Adapter->CurrentTcb = DC_NEXT_TCB(Adapter, Tcb);
Tcb->Tbd = Tbd;
Tcb->Packet = NULL;
ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED));
/* Prepare the setup frame */
Tbd->Address1 = Adapter->SetupFramePhys;
Tbd->Address2 = 0;
Tbd->Control &= DC_TBD_CONTROL_END_OF_RING;
Control = DC_SETUP_FRAME_SIZE | DC_TBD_CONTROL_SETUP_FRAME;
if (!WaitForCompletion)
Control |= DC_TBD_CONTROL_REQUEST_INTERRUPT;
if (Adapter->ProgramHashPerfectFilter)
Control |= DC_TBD_CONTROL_HASH_PERFECT_FILTER;
Tbd->Control |= Control;
DC_WRITE_BARRIER();
Tbd->Status = DC_TBD_STATUS_OWNED;
DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL);
if (!WaitForCompletion)
return TRUE;
/* Wait up to 500 ms for the chip to process the setup frame */
for (i = 50000; i > 0; --i)
{
NdisStallExecution(10);
KeMemoryBarrierWithoutFence();
if (!(Tbd->Status & DC_TBD_STATUS_OWNED))
break;
}
if (i == 0)
{
ERR("Failed to complete setup frame %08lx\n", Tbd->Status);
return FALSE;
}
return TRUE;
}
CODE_SEG("PAGE")
VOID
DcSetupFrameInitialize(
_In_ PDC21X4_ADAPTER Adapter)
{
PULONG SetupFrame, SetupFrameStart;
PUSHORT MacAddress;
ULONG i;
PAGED_CODE();
SetupFrame = Adapter->SetupFrame;
/* Add the physical address entry */
MacAddress = (PUSHORT)Adapter->CurrentMacAddress;
*SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]);
*SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]);
*SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]);
/* Pad to 16 addresses */
SetupFrameStart = Adapter->SetupFrame;
for (i = 1; i < DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES; ++i)
{
*SetupFrame++ = SetupFrameStart[0];
*SetupFrame++ = SetupFrameStart[1];
*SetupFrame++ = SetupFrameStart[2];
}
}
static
VOID
DcSetupFramePerfectFiltering(
_In_ PDC21X4_ADAPTER Adapter)
{
PULONG SetupFrame, SetupFrameStart;
PUSHORT MacAddress;
ULONG i;
SetupFrame = Adapter->SetupFrame;
/* Add the physical address entry */
MacAddress = (PUSHORT)Adapter->CurrentMacAddress;
*SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]);
*SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]);
*SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]);
/* Store multicast addresses */
for (i = 0; i < Adapter->MulticastCount; ++i)
{
MacAddress = (PUSHORT)Adapter->MulticastList[i].MacAddress;
*SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]);
*SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]);
*SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]);
}
++i;
/* Add the broadcast address entry */
if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
{
*SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF);
*SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF);
*SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF);
++i;
}
/* Pad to 16 addresses */
SetupFrameStart = Adapter->SetupFrame;
while (i < DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES)
{
*SetupFrame++ = SetupFrameStart[0];
*SetupFrame++ = SetupFrameStart[1];
*SetupFrame++ = SetupFrameStart[2];
++i;
}
}
static
VOID
DcSetupFrameImperfectFiltering(
_In_ PDC21X4_ADAPTER Adapter)
{
PULONG SetupFrame = Adapter->SetupFrame;
PUSHORT MacAddress;
ULONG Hash, i;
RtlZeroMemory(SetupFrame, DC_SETUP_FRAME_SIZE);
/* Fill up the 512-bit multicast hash table */
for (i = 0; i < Adapter->MulticastCount; ++i)
{
MacAddress = (PUSHORT)Adapter->MulticastList[i].MacAddress;
/* Only need lower 9 bits of the hash */
Hash = DcEthernetCrc(MacAddress, ETH_LENGTH_OF_ADDRESS);
Hash &= 512 - 1;
SetupFrame[Hash / 16] |= 1 << (Hash % 16);
}
/* Insert the broadcast address hash to the bin */
if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
{
Hash = DC_SETUP_FRAME_BROADCAST_HASH;
SetupFrame[Hash / 16] |= 1 << (Hash % 16);
}
/* Add the physical address entry */
MacAddress = (PUSHORT)Adapter->CurrentMacAddress;
SetupFrame[39] = DC_SETUP_FRAME_ENTRY(MacAddress[0]);
SetupFrame[40] = DC_SETUP_FRAME_ENTRY(MacAddress[1]);
SetupFrame[41] = DC_SETUP_FRAME_ENTRY(MacAddress[2]);
}
NDIS_STATUS
DcUpdateMulticastList(
_In_ PDC21X4_ADAPTER Adapter)
{
BOOLEAN UsePerfectFiltering;
/* If more than 14 addresses are requested, switch to hash filtering mode */
UsePerfectFiltering = (Adapter->MulticastCount <= DC_SETUP_FRAME_ADDRESSES);
Adapter->ProgramHashPerfectFilter = UsePerfectFiltering;
Adapter->OidPending = TRUE;
if (UsePerfectFiltering)
DcSetupFramePerfectFiltering(Adapter);
else
DcSetupFrameImperfectFiltering(Adapter);
NdisAcquireSpinLock(&Adapter->SendLock);
DcSetupFrameDownload(Adapter, FALSE);
NdisReleaseSpinLock(&Adapter->SendLock);
return NDIS_STATUS_PENDING;
}
NDIS_STATUS
DcApplyPacketFilter(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG PacketFilter)
{
ULONG OpMode, OldPacketFilter;
INFO("Packet filter value 0x%lx\n", PacketFilter);
NdisAcquireSpinLock(&Adapter->ModeLock);
/* Update the filtering mode */
OpMode = Adapter->OpMode;
OpMode &= ~(DC_OPMODE_RX_PROMISCUOUS | DC_OPMODE_RX_ALL_MULTICAST);
if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
{
OpMode |= DC_OPMODE_RX_PROMISCUOUS;
}
else if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
{
OpMode |= DC_OPMODE_RX_ALL_MULTICAST;
}
Adapter->OpMode = OpMode;
DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
NdisReleaseSpinLock(&Adapter->ModeLock);
OldPacketFilter = Adapter->PacketFilter;
Adapter->PacketFilter = PacketFilter;
/* Program the NIC to receive or reject broadcast frames */
if ((OldPacketFilter ^ PacketFilter) & NDIS_PACKET_TYPE_BROADCAST)
{
return DcUpdateMulticastList(Adapter);
}
return NDIS_STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
VOID
DcSoftReset(
_In_ PDC21X4_ADAPTER Adapter)
{
PAGED_CODE();
/* Linux driver does this */
if (Adapter->Features & DC_HAS_MII)
{
/* Select the MII/SYM port */
DC_WRITE(Adapter, DcCsr6_OpMode, DC_OPMODE_PORT_SELECT);
}
/* Perform a software reset */
DC_WRITE(Adapter, DcCsr0_BusMode, DC_BUS_MODE_SOFT_RESET);
NdisMSleep(100);
DC_WRITE(Adapter, DcCsr0_BusMode, Adapter->BusMode);
}
CODE_SEG("PAGE")
NDIS_STATUS
DcSetupAdapter(
_In_ PDC21X4_ADAPTER Adapter)
{
PAGED_CODE();
DcInitTxRing(Adapter);
DcInitRxRing(Adapter);
/* Initial values */
if (!MEDIA_IS_FIXED(Adapter))
{
Adapter->LinkSpeedMbps = 10;
}
Adapter->MediaNumber = Adapter->DefaultMedia;
Adapter->ModeFlags &= ~(DC_MODE_PORT_AUTOSENSE | DC_MODE_AUI_FAILED | DC_MODE_BNC_FAILED |
DC_MODE_TEST_PACKET | DC_MODE_AUTONEG_MASK);
DcSoftReset(Adapter);
/* Receive descriptor ring buffer */
DC_WRITE(Adapter, DcCsr3_RxRingAddress, Adapter->RbdPhys);
/* Transmit descriptor ring buffer */
DC_WRITE(Adapter, DcCsr4_TxRingAddress, Adapter->TbdPhys);
switch (Adapter->ChipType)
{
case DC21040:
{
DcWriteSia(Adapter,
Adapter->Media[Adapter->MediaNumber].Csr13,
Adapter->Media[Adapter->MediaNumber].Csr14,
Adapter->Media[Adapter->MediaNumber].Csr15);
/* Explicitly specifed by user */
if (Adapter->MediaNumber == MEDIA_10T_FD)
{
Adapter->OpMode |= DC_OPMODE_FULL_DUPLEX;
}
break;
}
case DC21041:
{
MediaSiaSelect(Adapter);
break;
}
case DC21140:
{
if (Adapter->MediaNumber == MEDIA_MII)
{
MediaSelectMiiPort(Adapter, !(Adapter->Flags & DC_FIRST_SETUP));
MediaMiiSelect(Adapter);
}
else
{
/* All media use the same GPIO directon */
DC_WRITE(Adapter, DcCsr12_Gpio, Adapter->Media[Adapter->MediaNumber].GpioCtrl);
NdisStallExecution(10);
MediaGprSelect(Adapter);
}
break;
}
case DC21143:
case DC21145:
{
/* Init the HPNA PHY */
if ((Adapter->MediaBitmap & (1 << MEDIA_HMR)) && Adapter->HpnaInitBitmap)
{
HpnaPhyInit(Adapter);
}
if (Adapter->MediaNumber == MEDIA_MII)
{
MediaSelectMiiPort(Adapter, !(Adapter->Flags & DC_FIRST_SETUP));
MediaMiiSelect(Adapter);
break;
}
/* If the current media is FX, assume we have a link */
if (MEDIA_IS_FX(Adapter->MediaNumber))
{
Adapter->LinkUp = TRUE;
NdisMIndicateStatus(Adapter->AdapterHandle,
NDIS_STATUS_MEDIA_CONNECT,
NULL,
0);
NdisMIndicateStatusComplete(Adapter->AdapterHandle);
}
MediaSiaSelect(Adapter);
break;
}
default:
ASSERT(FALSE);
UNREACHABLE;
break;
}
/* Start the TX process */
Adapter->OpMode |= DC_OPMODE_TX_ENABLE;
DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
/* Load the address recognition RAM */
if (!DcSetupFrameDownload(Adapter, TRUE))
{
/* This normally should not happen */
ASSERT(FALSE);
NdisWriteErrorLogEntry(Adapter->AdapterHandle,
NDIS_ERROR_CODE_HARDWARE_FAILURE,
1,
__LINE__);
return NDIS_STATUS_HARD_ERRORS;
}
return NDIS_STATUS_SUCCESS;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,625 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Interrupt handling
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* FUNCTIONS ******************************************************************/
static
VOID
DcAdjustTxFifoThreshold(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG OpMode;
TRACE("TX underrun\n");
/* Maximum threshold reached */
if ((Adapter->OpMode & DC_OPMODE_STORE_AND_FORWARD) ||
(++Adapter->TransmitUnderruns < DC_TX_UNDERRUN_LIMIT))
{
NdisDprAcquireSpinLock(&Adapter->SendLock);
/* Start the transmit process if it was suspended */
DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL);
NdisDprReleaseSpinLock(&Adapter->SendLock);
return;
}
Adapter->TransmitUnderruns = 0;
NdisDprAcquireSpinLock(&Adapter->ModeLock);
OpMode = Adapter->OpMode;
/* Update the FIFO threshold level to minimize Tx FIFO underrun */
if ((OpMode & DC_OPMODE_TX_THRESHOLD_CTRL_MASK) != DC_OPMODE_TX_THRESHOLD_MAX)
{
OpMode += DC_OPMODE_TX_THRESHOLD_LEVEL;
INFO("New OP Mode %08lx\n", OpMode);
}
else
{
OpMode |= DC_OPMODE_STORE_AND_FORWARD;
INFO("Store & Forward\n");
}
DcStopTxRxProcess(Adapter);
Adapter->OpMode = OpMode;
/* Restart the transmit process */
DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
NdisDprReleaseSpinLock(&Adapter->ModeLock);
}
static
VOID
DcHandleTxJabberTimeout(
_In_ PDC21X4_ADAPTER Adapter)
{
WARN("Transmit jabber timer timed out\n");
NdisWriteErrorLogEntry(Adapter->AdapterHandle, NDIS_ERROR_CODE_HARDWARE_FAILURE, 1, __LINE__);
NdisDprAcquireSpinLock(&Adapter->ModeLock);
/* Start the transmit process if it was stopped */
DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
NdisDprReleaseSpinLock(&Adapter->ModeLock);
}
static
VOID
DcHandleTxCompletedFrames(
_In_ PDC21X4_ADAPTER Adapter,
_Inout_ PLIST_ENTRY SendReadyList,
_Out_ PULONG DpcEvents)
{
PDC_TCB Tcb;
PDC_TBD Tbd;
ULONG TbdStatus, Collisions;
for (Tcb = Adapter->LastTcb;
Tcb != Adapter->CurrentTcb;
Tcb = DC_NEXT_TCB(Adapter, Tcb))
{
Tbd = Tcb->Tbd;
TbdStatus = Tbd->Status;
if (TbdStatus & DC_TBD_STATUS_OWNED)
break;
++Adapter->TcbCompleted;
/* Complete the packet filter change request asynchronously */
if (Tbd->Control & DC_TBD_CONTROL_SETUP_FRAME)
{
Tbd->Control &= ~DC_TBD_CONTROL_SETUP_FRAME;
if (Tbd->Control & DC_TBD_CONTROL_REQUEST_INTERRUPT)
{
*DpcEvents |= DC_EVENT_SETUP_FRAME_COMPLETED;
}
continue;
}
/* This is our media test packet, so no need to update the TX statistics */
if (!Tcb->Packet)
{
_InterlockedExchange(&Adapter->MediaTestStatus,
!(TbdStatus & DC_TBD_STATUS_ERROR_SUMMARY));
ASSERT(Adapter->LoopbackFrameSlots < DC_LOOPBACK_FRAMES);
++Adapter->LoopbackFrameSlots;
continue;
}
if (TbdStatus & DC_TBD_STATUS_ERROR_SUMMARY)
{
++Adapter->Statistics.TransmitErrors;
if (TbdStatus & DC_TBD_STATUS_UNDERFLOW)
++Adapter->Statistics.TransmitUnderrunErrors;
else if (TbdStatus & DC_TBD_STATUS_LATE_COLLISION)
++Adapter->Statistics.TransmitLateCollisions;
if (TbdStatus & DC_TBD_STATUS_RETRY_ERROR)
++Adapter->Statistics.TransmitExcessiveCollisions;
if (TbdStatus & DC_TBD_STATUS_CARRIER_LOST)
++Adapter->Statistics.TransmitLostCarrierSense;
}
else
{
++Adapter->Statistics.TransmitOk;
if (TbdStatus & DC_TBD_STATUS_DEFFERED)
++Adapter->Statistics.TransmitDeferred;
if (TbdStatus & DC_TBD_STATUS_HEARTBEAT_FAIL)
++Adapter->Statistics.TransmitHeartbeatErrors;
Collisions = (TbdStatus & DC_TBD_STATUS_COLLISIONS_MASK) >>
DC_TBD_STATUS_COLLISIONS_SHIFT;
if (Collisions == 1)
++Adapter->Statistics.TransmitOneRetry;
else if (Collisions > 1)
++Adapter->Statistics.TransmitMoreCollisions;
}
InsertTailList(SendReadyList, DC_LIST_ENTRY_FROM_PACKET(Tcb->Packet));
DC_RELEASE_TCB(Adapter, Tcb);
}
Adapter->LastTcb = Tcb;
}
static
VOID
DcHandleTx(
_In_ PDC21X4_ADAPTER Adapter)
{
LIST_ENTRY SendReadyList;
ULONG DpcEvents;
TRACE("Handle TX\n");
InitializeListHead(&SendReadyList);
DpcEvents = 0;
NdisDprAcquireSpinLock(&Adapter->SendLock);
DcHandleTxCompletedFrames(Adapter, &SendReadyList, &DpcEvents);
if (!IsListEmpty(&Adapter->SendQueueList))
{
DcProcessPendingPackets(Adapter);
}
NdisDprReleaseSpinLock(&Adapter->SendLock);
while (!IsListEmpty(&SendReadyList))
{
PLIST_ENTRY Entry = RemoveHeadList(&SendReadyList);
TRACE("Complete TX packet %p\n", DC_PACKET_FROM_LIST_ENTRY(Entry));
NdisMSendComplete(Adapter->AdapterHandle,
DC_PACKET_FROM_LIST_ENTRY(Entry),
NDIS_STATUS_SUCCESS);
}
/* We have to complete the OID request outside of the spinlock */
if (DpcEvents & DC_EVENT_SETUP_FRAME_COMPLETED)
{
TRACE("SP completed\n");
Adapter->OidPending = FALSE;
NdisMSetInformationComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS);
}
}
static
VOID
DcStopRxProcess(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG i, OpMode, Status;
OpMode = Adapter->OpMode;
OpMode &= ~DC_OPMODE_RX_ENABLE;
DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
for (i = 0; i < 5000; ++i)
{
Status = DC_READ(Adapter, DcCsr5_Status);
if ((Status & DC_STATUS_RX_STATE_MASK) == DC_STATUS_RX_STATE_STOPPED)
return;
NdisStallExecution(10);
}
WARN("Failed to stop the RX process 0x%08lx\n", Status);
}
VOID
NTAPI
DcReturnPacket(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ PNDIS_PACKET Packet)
{
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
PDC_RCB Rcb;
Rcb = *DC_RCB_FROM_PACKET(Packet);
NdisAcquireSpinLock(&Adapter->ReceiveLock);
PushEntryList(&Adapter->FreeRcbList, &Rcb->ListEntry);
++Adapter->RcbFree;
NdisReleaseSpinLock(&Adapter->ReceiveLock);
}
static
VOID
DcIndicateReceivePackets(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PNDIS_PACKET* ReceiveArray,
_In_ ULONG PacketsToIndicate)
{
PNDIS_PACKET Packet;
PDC_RBD Rbd;
PDC_RCB Rcb;
ULONG i;
NdisDprReleaseSpinLock(&Adapter->ReceiveLock);
NdisMIndicateReceivePacket(Adapter->AdapterHandle,
ReceiveArray,
PacketsToIndicate);
NdisDprAcquireSpinLock(&Adapter->ReceiveLock);
for (i = 0; i < PacketsToIndicate; ++i)
{
Packet = ReceiveArray[i];
Rcb = *DC_RCB_FROM_PACKET(Packet);
/* Reuse the RCB immediately */
if (Rcb->Flags & DC_RCB_FLAG_RECLAIM)
{
Rbd = *DC_RBD_FROM_PACKET(Packet);
Rbd->Status = DC_RBD_STATUS_OWNED;
}
}
}
static
VOID
DcHandleRxReceivedFrames(
_In_ PDC21X4_ADAPTER Adapter)
{
PDC_RBD Rbd, StartRbd, LastRbd;
ULONG PacketsToIndicate;
PNDIS_PACKET ReceiveArray[DC_RECEIVE_ARRAY_SIZE];
Rbd = StartRbd = LastRbd = Adapter->CurrentRbd;
PacketsToIndicate = 0;
while (PacketsToIndicate < RTL_NUMBER_OF(ReceiveArray))
{
PDC_RCB Rcb;
PDC_RCB* RcbSlot;
PNDIS_PACKET Packet;
ULONG RbdStatus, PacketLength, RxCounters;
if (Rbd->Status & DC_RBD_STATUS_OWNED)
break;
/* Work around the RX overflow bug */
if ((Adapter->Features & DC_NEED_RX_OVERFLOW_WORKAROUND) && (Rbd == LastRbd))
{
/* Find the last received packet, to correctly catch invalid packets */
do
{
LastRbd = DC_NEXT_RBD(Adapter, LastRbd);
if (LastRbd->Status & DC_RBD_STATUS_OWNED)
break;
}
while (LastRbd != Rbd);
RxCounters = DC_READ(Adapter, DcCsr8_RxCounters);
Adapter->Statistics.ReceiveNoBuffers += RxCounters & DC_COUNTER_RX_NO_BUFFER_MASK;
/* A receive overflow might indicate a data corruption */
if (RxCounters & DC_COUNTER_RX_OVERFLOW_MASK)
{
ERR("RX overflow, dropping the packets\n");
Adapter->Statistics.ReceiveOverrunErrors +=
(RxCounters & DC_COUNTER_RX_OVERFLOW_MASK) >> DC_COUNTER_RX_OVERFLOW_SHIFT;
NdisDprAcquireSpinLock(&Adapter->ModeLock);
/* Stop the receive process */
DcStopRxProcess(Adapter);
/* Drop all received packets regardless of what the status indicates */
while (TRUE)
{
if (Rbd->Status & DC_RBD_STATUS_OWNED)
break;
++Adapter->Statistics.ReceiveOverrunErrors;
Rbd->Status = DC_RBD_STATUS_OWNED;
Rbd = DC_NEXT_RBD(Adapter, Rbd);
}
LastRbd = Rbd;
/* Restart the receive process */
DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
NdisDprReleaseSpinLock(&Adapter->ModeLock);
continue;
}
}
RbdStatus = Rbd->Status;
/* Ignore oversized packets */
if (!(RbdStatus & DC_RBD_STATUS_LAST_DESCRIPTOR))
{
Rbd->Status = DC_RBD_STATUS_OWNED;
goto NextRbd;
}
/* Check for an invalid packet */
if (RbdStatus & DC_RBD_STATUS_INVALID)
{
++Adapter->Statistics.ReceiveErrors;
if (RbdStatus & DC_RBD_STATUS_OVERRUN)
++Adapter->Statistics.ReceiveOverrunErrors;
if (RbdStatus & DC_RBD_STATUS_CRC_ERROR)
{
if (RbdStatus & DC_RBD_STATUS_DRIBBLE)
++Adapter->Statistics.ReceiveAlignmentErrors;
else
++Adapter->Statistics.ReceiveCrcErrors;
}
Rbd->Status = DC_RBD_STATUS_OWNED;
goto NextRbd;
}
++Adapter->Statistics.ReceiveOk;
PacketLength = (RbdStatus & DC_RBD_STATUS_FRAME_LENGTH_MASK) >>
DC_RBD_STATUS_FRAME_LENGTH_SHIFT;
/* Omit the CRC */
PacketLength -= 4;
RcbSlot = DC_GET_RCB_SLOT(Adapter, Rbd);
Rcb = *RcbSlot;
TRACE("RX packet (len %u), RCB %p\n", PacketLength, Rcb);
NdisAdjustBufferLength(Rcb->NdisBuffer, PacketLength);
/* Receive buffers are in cached memory */
NdisFlushBuffer(Rcb->NdisBuffer, FALSE);
if (RbdStatus & DC_RBD_STATUS_MULTICAST)
{
if (ETH_IS_BROADCAST(Rcb->VirtualAddress))
++Adapter->Statistics.ReceiveBroadcast;
else
++Adapter->Statistics.ReceiveMulticast;
}
else
{
++Adapter->Statistics.ReceiveUnicast;
}
Packet = Rcb->Packet;
ReceiveArray[PacketsToIndicate++] = Packet;
if (Adapter->FreeRcbList.Next)
{
Rcb->Flags = 0;
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_SUCCESS);
Rcb = (PDC_RCB)DcPopEntryList(&Adapter->FreeRcbList);
*RcbSlot = Rcb;
ASSERT(Adapter->RcbFree > 0);
--Adapter->RcbFree;
Rbd->Address1 = Rcb->PhysicalAddress;
DC_WRITE_BARRIER();
Rbd->Status = DC_RBD_STATUS_OWNED;
}
else
{
Rcb->Flags = DC_RCB_FLAG_RECLAIM;
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
*DC_RBD_FROM_PACKET(Packet) = Rbd;
}
NextRbd:
Rbd = DC_NEXT_RBD(Adapter, Rbd);
/*
* Check the next descriptor to prevent wrap-around.
* Since we don't use a fixed-sized ring,
* the receive ring may be smaller in length than the ReceiveArray[].
*/
if (Rbd == StartRbd)
break;
}
Adapter->CurrentRbd = Rbd;
/* Pass the packets up */
if (PacketsToIndicate)
{
DcIndicateReceivePackets(Adapter, ReceiveArray, PacketsToIndicate);
}
}
static
VOID
DcHandleRx(
_In_ PDC21X4_ADAPTER Adapter)
{
NdisDprAcquireSpinLock(&Adapter->ReceiveLock);
do
{
DcHandleRxReceivedFrames(Adapter);
}
while (!(Adapter->CurrentRbd->Status & DC_RBD_STATUS_OWNED));
NdisDprReleaseSpinLock(&Adapter->ReceiveLock);
}
static
VOID
DcHandleSystemError(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG InterruptStatus)
{
ERR("%s error occured, CSR5 %08lx\n", DcDbgBusError(InterruptStatus), InterruptStatus);
NdisWriteErrorLogEntry(Adapter->AdapterHandle, NDIS_ERROR_CODE_HARDWARE_FAILURE, 1, __LINE__);
/* Issue a software reset, which also enables the interrupts */
if (_InterlockedCompareExchange(&Adapter->ResetLock, 2, 0) == 0)
{
NdisScheduleWorkItem(&Adapter->ResetWorkItem);
}
}
VOID
NTAPI
DcHandleInterrupt(
_In_ NDIS_HANDLE MiniportAdapterContext)
{
ULONG InterruptStatus, IoLimit;
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
TRACE("Events %08lx\n", Adapter->InterruptStatus);
if (!(Adapter->Flags & DC_ACTIVE))
return;
IoLimit = DC_INTERRUPT_PROCESSING_LIMIT;
InterruptStatus = Adapter->InterruptStatus;
/* Loop until the condition to stop is encountered */
while (TRUE)
{
/* Uncommon interrupts */
if (InterruptStatus & DC_IRQ_ABNORMAL_SUMMARY)
{
/* PCI bus error detected */
if (InterruptStatus & DC_IRQ_SYSTEM_ERROR)
{
DcHandleSystemError(Adapter, InterruptStatus);
return;
}
/* Transmit jabber timeout */
if (InterruptStatus & DC_IRQ_TX_JABBER_TIMEOUT)
{
DcHandleTxJabberTimeout(Adapter);
}
/* Link state changed */
if (InterruptStatus & Adapter->LinkStateChangeMask)
{
Adapter->HandleLinkStateChange(Adapter, InterruptStatus);
}
}
/* Handling receive interrupts */
if (InterruptStatus & (DC_IRQ_RX_OK | DC_IRQ_RX_STOPPED))
{
DcHandleRx(Adapter);
}
/* Handling transmit interrupts */
if (InterruptStatus & (DC_IRQ_TX_OK | DC_IRQ_TX_STOPPED))
{
DcHandleTx(Adapter);
}
/* Transmit underflow error detected */
if (InterruptStatus & DC_IRQ_TX_UNDERFLOW)
{
DcAdjustTxFifoThreshold(Adapter);
}
/* Limit in order to avoid doing too much work at DPC level */
if (!--IoLimit)
break;
/* Check if new events have occurred */
InterruptStatus = DC_READ(Adapter, DcCsr5_Status);
if (InterruptStatus == 0xFFFFFFFF || !(InterruptStatus & Adapter->InterruptMask))
break;
/* Acknowledge the events */
DC_WRITE(Adapter, DcCsr5_Status, InterruptStatus);
}
/* TODO: Add interrupt mitigation (CSR11) */
/* Reenable interrupts */
_InterlockedExchange((PLONG)&Adapter->CurrentInterruptMask, Adapter->InterruptMask);
DC_WRITE(Adapter, DcCsr7_IrqMask, Adapter->InterruptMask);
}
VOID
NTAPI
DcIsr(
_Out_ PBOOLEAN InterruptRecognized,
_Out_ PBOOLEAN QueueMiniportHandleInterrupt,
_In_ NDIS_HANDLE MiniportAdapterContext)
{
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
ULONG InterruptStatus;
if (Adapter->CurrentInterruptMask == 0)
goto NotOurs;
InterruptStatus = DC_READ(Adapter, DcCsr5_Status);
if (InterruptStatus == 0xFFFFFFFF || !(InterruptStatus & Adapter->CurrentInterruptMask))
goto NotOurs;
/* Disable further interrupts */
DC_WRITE(Adapter, DcCsr7_IrqMask, 0);
/* Clear all pending events */
DC_WRITE(Adapter, DcCsr5_Status, InterruptStatus);
Adapter->InterruptStatus = InterruptStatus;
Adapter->CurrentInterruptMask = 0;
*InterruptRecognized = TRUE;
*QueueMiniportHandleInterrupt = TRUE;
return;
NotOurs:
*InterruptRecognized = FALSE;
*QueueMiniportHandleInterrupt = FALSE;
}

View file

@ -0,0 +1,634 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Media common code
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* FUNCTIONS ******************************************************************/
VOID
MediaIndicateConnect(
_In_ PDC21X4_ADAPTER Adapter,
_In_ BOOLEAN LinkUp)
{
/* Nothing to do */
if (Adapter->LinkUp == LinkUp)
return;
Adapter->LinkUp = LinkUp;
INFO_VERB("Link %sconnected, media is %s\n",
LinkUp ? "" : "dis",
MediaNumber2Str(Adapter, Adapter->MediaNumber));
NdisDprReleaseSpinLock(&Adapter->ModeLock);
NdisMIndicateStatus(Adapter->AdapterHandle,
LinkUp ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
NULL,
0);
NdisMIndicateStatusComplete(Adapter->AdapterHandle);
NdisDprAcquireSpinLock(&Adapter->ModeLock);
}
static
ULONG
MediaMiiNextMedia(
_In_ PDC21X4_ADAPTER Adapter)
{
Adapter->ModeFlags &= ~(DC_MODE_TEST_PACKET | DC_MODE_AUI_FAILED | DC_MODE_BNC_FAILED);
Adapter->LastReceiveActivity = (ULONG)Adapter->Statistics.ReceiveOk;
/*
* In MII mode, we don't know exactly which port is active.
* Switch to the media with a higher priority.
*/
if (Adapter->MediaBitmap & (1 << MEDIA_HMR))
return MEDIA_HMR;
else if (Adapter->MediaBitmap & (1 << MEDIA_AUI))
return MEDIA_AUI;
else
return MEDIA_BNC;
}
static
VOID
MediaMiiSetSpeedAndDuplex(
_In_ PDC21X4_ADAPTER Adapter,
_In_ BOOLEAN FullDuplex,
_In_ BOOLEAN Speed100)
{
ULONG OpMode = Adapter->OpMode;
if (FullDuplex)
OpMode |= DC_OPMODE_FULL_DUPLEX;
else
OpMode &= ~DC_OPMODE_FULL_DUPLEX;
if (Speed100)
OpMode &= ~DC_OPMODE_PORT_XMIT_10;
else
OpMode |= DC_OPMODE_PORT_XMIT_10;
/* Nothing to do */
if (OpMode == Adapter->OpMode)
return;
INFO_VERB("Configuring MAC from %u %s-duplex to %u %s-duplex\n",
Adapter->LinkSpeedMbps,
(Adapter->OpMode & DC_OPMODE_FULL_DUPLEX) ? "full" : "half",
Speed100 ? 100 : 10,
FullDuplex ? "full" : "half");
Adapter->LinkSpeedMbps = Speed100 ? 100 : 10;
DcStopTxRxProcess(Adapter);
Adapter->OpMode = OpMode;
DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
}
static
VOID
MediaMiiGetSpeedAndDuplex(
_In_ PDC21X4_ADAPTER Adapter,
_Out_ PBOOLEAN FullDuplex,
_Out_ PBOOLEAN Speed100)
{
ULONG MiiLinkPartnerAbility, AdvLpa;
MiiRead(Adapter, Adapter->PhyAddress, MII_AUTONEG_LINK_PARTNER, &MiiLinkPartnerAbility);
TRACE("MII LPA %04lx\n", MiiLinkPartnerAbility);
AdvLpa = Adapter->MiiMedia.Advertising & MiiLinkPartnerAbility;
if (AdvLpa & MII_LP_100T_FD)
{
*FullDuplex = TRUE;
*Speed100 = TRUE;
}
else if (AdvLpa & MII_LP_100T4)
{
*FullDuplex = FALSE;
*Speed100 = TRUE;
}
else if (AdvLpa & MII_LP_100T_HD)
{
*FullDuplex = FALSE;
*Speed100 = TRUE;
}
else if (AdvLpa & MII_LP_10T_FD)
{
*FullDuplex = TRUE;
*Speed100 = FALSE;
}
else
{
*FullDuplex = FALSE;
*Speed100 = FALSE;
}
}
BOOLEAN
MediaMiiCheckLink(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG MiiStatus;
BOOLEAN FullDuplex, Speed100;
/* The link status is a latched-low bit, read it twice */
if (!MiiRead(Adapter, Adapter->PhyAddress, MII_STATUS, &MiiStatus))
{
goto NoLink;
}
if (!(MiiStatus & MII_SR_LINK_STATUS))
{
MiiRead(Adapter, Adapter->PhyAddress, MII_STATUS, &MiiStatus);
}
TRACE("MII Status %04lx\n", MiiStatus);
/* Check the link status */
if (!(MiiStatus & MII_SR_LINK_STATUS))
{
NoLink:
/* No link detected, check the other port */
if (Adapter->MediaBitmap & ((1 << MEDIA_HMR) | (1 << MEDIA_AUI) | (1 << MEDIA_BNC)))
{
if ((Adapter->Features & DC_MII_AUTOSENSE) && !MEDIA_IS_FIXED(Adapter))
{
Adapter->MediaNumber = MediaMiiNextMedia(Adapter);
MediaSiaSelect(Adapter);
}
}
return FALSE;
}
/* If we are forcing speed and duplex */
if (MEDIA_IS_FIXED(Adapter))
{
FullDuplex = !!(Adapter->MiiControl & MII_CR_FULL_DUPLEX);
Speed100 = !!(Adapter->MiiControl & MII_CR_SPEED_SELECTION);
}
else
{
/* Check auto-negotiation is complete */
if (!(MiiStatus & MII_SR_AUTONEG_COMPLETE))
return FALSE;
MediaMiiGetSpeedAndDuplex(Adapter, &FullDuplex, &Speed100);
}
/* Set the link speed and duplex */
MediaMiiSetSpeedAndDuplex(Adapter, FullDuplex, Speed100);
return TRUE;
}
VOID
MediaMiiSelect(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG MiiControl, MiiAdvertise;
MiiRead(Adapter, Adapter->PhyAddress, MII_CONTROL, &MiiControl);
MiiControl &= ~(MII_CR_POWER_DOWN | MII_CR_ISOLATE | MII_CR_RESET | MII_CR_SPEED_SELECTION |
MII_CR_FULL_DUPLEX | MII_CR_AUTONEG | MII_CR_AUTONEG_RESTART);
MiiWrite(Adapter, Adapter->PhyAddress, MII_CONTROL, MiiControl);
MiiControl |= Adapter->MiiControl;
MiiAdvertise = Adapter->MiiAdvertising;
MiiWrite(Adapter, Adapter->PhyAddress, MII_AUTONEG_ADVERTISE, MiiAdvertise | MII_ADV_CSMA);
MiiWrite(Adapter, Adapter->PhyAddress, MII_CONTROL, MiiControl);
}
VOID
MediaSelectMiiPort(
_In_ PDC21X4_ADAPTER Adapter,
_In_ BOOLEAN ResetPhy)
{
ULONG OpMode, i;
if (Adapter->ChipType != DC21140)
{
DcWriteSia(Adapter, 0, 0, 0);
}
OpMode = Adapter->OpMode;
OpMode &= ~DC_OPMODE_MEDIA_MASK;
OpMode |= DC_OPMODE_PORT_SELECT | DC_OPMODE_PORT_HEARTBEAT_DISABLE;
Adapter->OpMode = OpMode;
DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
NdisStallExecution(10);
if (ResetPhy)
{
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
/* Execute the GPIO reset sequence */
if (Adapter->MiiMedia.ResetStreamLength)
{
/* Set the GPIO direction */
DcWriteGpio(Adapter, Adapter->MiiMedia.SetupStream[0]);
for (i = 0; i < Adapter->MiiMedia.ResetStreamLength; ++i)
{
NdisMSleep(100);
DcWriteGpio(Adapter, Adapter->MiiMedia.ResetStream[i]);
}
/* Give the PHY some time to reset */
NdisMSleep(5000);
}
}
/* Set the GPIO direction */
DcWriteGpio(Adapter, Adapter->MiiMedia.SetupStream[0]);
/* Execute the GPIO setup sequence */
for (i = 1; i < Adapter->MiiMedia.SetupStreamLength; ++i)
{
NdisStallExecution(10);
DcWriteGpio(Adapter, Adapter->MiiMedia.SetupStream[i]);
}
}
VOID
MediaSiaSelect(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG OpMode;
PDC_MEDIA Media;
INFO_VERB("Selected media %s\n",
MediaNumber2Str(Adapter, Adapter->MediaNumber));
Media = &Adapter->Media[Adapter->MediaNumber];
DcStopTxRxProcess(Adapter);
if (Adapter->ChipType != DC21041)
{
/* Make sure the reset pulse is wide enough */
NdisStallExecution(100);
DcWriteGpio(Adapter, Media->GpioCtrl);
NdisStallExecution(100);
DcWriteGpio(Adapter, Media->GpioData);
}
DcWriteSia(Adapter, Media->Csr13, Media->Csr14, Media->Csr15);
NdisStallExecution(10);
OpMode = Adapter->OpMode;
OpMode &= ~DC_OPMODE_MEDIA_MASK;
OpMode |= Media->OpMode;
Adapter->OpMode = OpMode;
DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
}
VOID
MediaGprSelect(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG OpMode;
PDC_MEDIA Media;
INFO("Selected media %s\n", MediaNumber2Str(Adapter, Adapter->MediaNumber));
Media = &Adapter->Media[Adapter->MediaNumber];
DC_WRITE(Adapter, DcCsr12_Gpio, Media->GpioData);
OpMode = Adapter->OpMode;
OpMode &= ~DC_OPMODE_MEDIA_MASK;
OpMode |= Media->OpMode;
Adapter->OpMode = OpMode;
DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
}
CODE_SEG("PAGE")
VOID
MediaInitDefaultMedia(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG MediaNumber)
{
ULONG Csr14, MiiAdvertising, MiiControl, i;
BOOLEAN UseMii;
PAGED_CODE();
/* Media auto-detection */
if (MediaNumber == MEDIA_AUTO)
{
Adapter->Flags |= DC_AUTOSENSE;
/* Initial value for all boards */
Adapter->DefaultMedia = MEDIA_10T;
Adapter->MiiAdvertising = Adapter->MiiMedia.Advertising;
Adapter->MiiControl = MII_CR_AUTONEG | MII_CR_AUTONEG_RESTART;
switch (Adapter->ChipType)
{
case DC21041:
{
/* Errata: don't enable auto-negotiation */
if (Adapter->RevisionId < 0x20)
break;
/* Advertise 10T HD and 10T FD. The chip chooses the 10T FD mode automatically */
Adapter->Media[MEDIA_10T].Csr14 |= DC_SIA_TXRX_AUTONEG | DC_SIA_TXRX_ADV_10T_HD;
Adapter->Media[MEDIA_10T].OpMode |= DC_OPMODE_FULL_DUPLEX;
break;
}
case DC21140:
{
/* Pick the default media */
if (Adapter->Features & DC_HAS_MII)
{
Adapter->DefaultMedia = MEDIA_MII;
break;
}
/* The final entry in the media list should be checked first */
_BitScanReverse(&Adapter->DefaultMedia, Adapter->MediaBitmap);
/*
* Select the first half-duplex media.
* If you want to be able to use 21140 boards without MII in full-duplex mode,
* you have to manually select the media.
*/
for (i = Adapter->DefaultMedia; i > 0; --i)
{
if ((Adapter->MediaBitmap & (1 << i)) && !MEDIA_IS_FD(i))
break;
}
Adapter->DefaultMedia = i;
break;
}
case DC21143:
case DC21145:
{
/* Pick the default media */
if (Adapter->Features & DC_HAS_MII)
{
Adapter->DefaultMedia = MEDIA_MII;
}
else if (Adapter->MediaBitmap & (1 << MEDIA_10T))
{
/* Start at 10mbps to do internal auto-negotiation */
Adapter->DefaultMedia = MEDIA_10T;
}
else
{
/* The final entry in the media list should be checked first */
_BitScanReverse(&Adapter->DefaultMedia, Adapter->MediaBitmap);
}
/* Enable the PCS function to do 100mbps parallel detection */
if (Adapter->SymAdvertising & MII_ADV_100)
{
Adapter->Media[MEDIA_10T].OpMode |= DC_OPMODE_PORT_PCS;
Adapter->Media[MEDIA_10T_FD].OpMode |= DC_OPMODE_PORT_PCS;
Adapter->Media[MEDIA_AUI].OpMode |= DC_OPMODE_PORT_PCS;
Adapter->Media[MEDIA_BNC].OpMode |= DC_OPMODE_PORT_PCS;
Adapter->Media[MEDIA_HMR].OpMode |= DC_OPMODE_PORT_PCS;
}
Csr14 = DC_SIA_TXRX_AUTONEG;
if (Adapter->SymAdvertising & MII_ADV_10T_HD)
Csr14 |= DC_SIA_TXRX_ADV_10T_HD;
/* When NWay is turned on, the FDX bit advertises 10T FD */
if (Adapter->SymAdvertising & MII_ADV_10T_FD)
Adapter->Media[MEDIA_10T].OpMode |= DC_OPMODE_FULL_DUPLEX;
if (Adapter->SymAdvertising & MII_ADV_100T_HD)
Csr14 |= DC_SIA_TXRX_ADV_100TX_HD;
if (Adapter->SymAdvertising & MII_ADV_100T_FD)
Csr14 |= DC_SIA_TXRX_ADV_100TX_FD;
if (Adapter->SymAdvertising & MII_ADV_100T4)
Csr14 |= DC_SIA_TXRX_ADV_100T4;
/* Advertise the PHY capability */
Adapter->Media[MEDIA_10T].Csr14 |= Csr14;
/* This media may use GPIO data different from the 10T HD */
Adapter->Media[MEDIA_10T_FD].Csr14 |= Csr14;
break;
}
default:
break;
}
}
else /* Forced speed and duplex */
{
UseMii = FALSE;
if (Adapter->Features & DC_HAS_MII)
{
if (!MEDIA_MII_OVERRIDE(MediaNumber))
{
UseMii = TRUE;
}
}
if (!UseMii)
{
Adapter->DefaultMedia = MediaNumber;
if (MEDIA_IS_10T(MediaNumber))
{
Adapter->InterruptMask &= ~DC_IRQ_LINK_CHANGED;
Adapter->LinkStateChangeMask &= ~DC_IRQ_LINK_CHANGED;
}
if (MEDIA_IS_100(MediaNumber))
{
Adapter->InterruptMask &= ~(DC_IRQ_LINK_FAIL | DC_IRQ_LINK_PASS);
Adapter->LinkStateChangeMask &= ~(DC_IRQ_LINK_FAIL | DC_IRQ_LINK_PASS);
}
}
else
{
Adapter->DefaultMedia = MEDIA_MII;
switch (MediaNumber)
{
case MEDIA_10T:
MiiAdvertising = MII_ADV_10T_HD;
break;
case MEDIA_10T_FD:
MiiAdvertising = MII_ADV_10T_FD;
MiiControl = MII_CR_FULL_DUPLEX;
break;
case MEDIA_100TX_HD:
MiiAdvertising = MII_ADV_100T_HD;
MiiControl = MII_CR_SPEED_SELECTION;
break;
case MEDIA_100TX_FD:
MiiAdvertising = MII_ADV_100T_FD;
MiiControl = MII_CR_FULL_DUPLEX | MII_CR_SPEED_SELECTION;
break;
case MEDIA_100T4:
MiiAdvertising = MII_ADV_100T4 | MII_CR_SPEED_SELECTION;
break;
default:
MiiAdvertising = 0;
MiiControl = 0;
break;
}
if (MiiControl & MII_CR_SPEED_SELECTION)
Adapter->LinkSpeedMbps = 100;
else
Adapter->LinkSpeedMbps = 10;
Adapter->MiiAdvertising = MiiAdvertising;
Adapter->MiiControl = MiiControl;
}
}
INFO("Default media is %s\n", MediaNumber2Str(Adapter, Adapter->DefaultMedia));
}
static
CODE_SEG("PAGE")
VOID
MediaInitOpMode2114x(
_In_ PDC21X4_ADAPTER Adapter)
{
PAGED_CODE();
Adapter->Media[MEDIA_10T ].OpMode = 0;
Adapter->Media[MEDIA_BNC ].OpMode = 0;
Adapter->Media[MEDIA_AUI ].OpMode = 0;
Adapter->Media[MEDIA_100TX_HD].OpMode = DC_OPMODE_PORT_SELECT |
DC_OPMODE_PORT_HEARTBEAT_DISABLE;
Adapter->Media[MEDIA_10T_FD ].OpMode = DC_OPMODE_FULL_DUPLEX;
Adapter->Media[MEDIA_100TX_FD].OpMode = DC_OPMODE_PORT_SELECT | DC_OPMODE_FULL_DUPLEX |
DC_OPMODE_PORT_HEARTBEAT_DISABLE;
Adapter->Media[MEDIA_100T4 ].OpMode = DC_OPMODE_PORT_SELECT |
DC_OPMODE_PORT_HEARTBEAT_DISABLE;
Adapter->Media[MEDIA_100FX_HD].OpMode = DC_OPMODE_PORT_SELECT |
DC_OPMODE_PORT_HEARTBEAT_DISABLE |
DC_OPMODE_PORT_PCS;
Adapter->Media[MEDIA_100FX_FD].OpMode = DC_OPMODE_PORT_SELECT | DC_OPMODE_FULL_DUPLEX |
DC_OPMODE_PORT_HEARTBEAT_DISABLE |
DC_OPMODE_PORT_PCS;
Adapter->Media[MEDIA_HMR ].OpMode = DC_OPMODE_PORT_HEARTBEAT_DISABLE;
}
CODE_SEG("PAGE")
VOID
MediaInitMediaList(
_In_ PDC21X4_ADAPTER Adapter)
{
PAGED_CODE();
/*
* Set the default internal values for the SIA/SYM operating modes.
* The SROM parsing code may later overwrite them.
*/
switch (Adapter->ChipType)
{
case DC21040:
{
Adapter->Media[MEDIA_10T].Csr13 = 0x8F01;
Adapter->Media[MEDIA_10T].Csr14 = 0xFFFF;
Adapter->Media[MEDIA_10T].Csr15 = 0x0000;
Adapter->Media[MEDIA_BNC].Csr13 = 0x8F09;
Adapter->Media[MEDIA_BNC].Csr14 = 0x0705;
Adapter->Media[MEDIA_BNC].Csr15 = 0x0006;
Adapter->Media[MEDIA_10T_FD].Csr13 = 0x8F01;
Adapter->Media[MEDIA_10T_FD].Csr14 = 0xFFFD;
Adapter->Media[MEDIA_10T_FD].Csr15 = 0x0000;
Adapter->Media[MEDIA_10T_FD].OpMode = DC_OPMODE_FULL_DUPLEX;
break;
}
case DC21041:
{
Adapter->Media[MEDIA_10T].Csr13 = 0xEF01;
Adapter->Media[MEDIA_10T].Csr14 = 0xFF3F;
Adapter->Media[MEDIA_10T].Csr15 = 0x0008;
Adapter->Media[MEDIA_BNC].Csr13 = 0xEF09;
Adapter->Media[MEDIA_BNC].Csr14 = 0xF7FD;
Adapter->Media[MEDIA_BNC].Csr15 = 0x0006;
Adapter->Media[MEDIA_AUI].Csr13 = 0xEF09;
Adapter->Media[MEDIA_AUI].Csr14 = 0xF7FD;
Adapter->Media[MEDIA_AUI].Csr15 = 0x000E;
Adapter->Media[MEDIA_10T_HD].Csr13 = 0xEF01;
Adapter->Media[MEDIA_10T_HD].Csr14 = 0x7F3F;
Adapter->Media[MEDIA_10T_HD].Csr15 = 0x0008;
Adapter->Media[MEDIA_10T_FD].Csr13 = 0xEF01;
Adapter->Media[MEDIA_10T_FD].Csr14 = 0x7F3D;
Adapter->Media[MEDIA_10T_FD].Csr15 = 0x0008;
Adapter->Media[MEDIA_10T_FD].OpMode = DC_OPMODE_FULL_DUPLEX;
break;
}
case DC21140:
{
MediaInitOpMode2114x(Adapter);
break;
}
case DC21143:
case DC21145:
{
Adapter->Media[MEDIA_10T].Csr13 = 0x0001;
Adapter->Media[MEDIA_10T].Csr14 = 0x7F3F;
Adapter->Media[MEDIA_10T].Csr15 = 0x0008;
Adapter->Media[MEDIA_BNC].Csr13 = 0x0009;
Adapter->Media[MEDIA_BNC].Csr14 = 0x0705;
Adapter->Media[MEDIA_BNC].Csr15 = 0x0006;
Adapter->Media[MEDIA_AUI].Csr13 = 0x0009;
Adapter->Media[MEDIA_AUI].Csr14 = 0x0705;
Adapter->Media[MEDIA_AUI].Csr15 = 0x000E;
Adapter->Media[MEDIA_10T_FD].Csr13 = 0x0001;
Adapter->Media[MEDIA_10T_FD].Csr14 = 0x7F3D;
Adapter->Media[MEDIA_10T_FD].Csr15 = 0x0008;
Adapter->Media[MEDIA_HMR].Csr13 = 0x0009;
Adapter->Media[MEDIA_HMR].Csr14 = 0x0505;
Adapter->Media[MEDIA_HMR].Csr15 = 0x0010;
MediaInitOpMode2114x(Adapter);
break;
}
default:
break;
}
}

View file

@ -0,0 +1,127 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Media support header file
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
typedef struct _DC_MEDIA
{
ULONG OpMode;
USHORT GpioCtrl;
USHORT GpioData;
union
{
struct _DC_MEDIA_SIA_DATA
{
ULONG Csr13;
ULONG Csr14;
ULONG Csr15;
};
struct _DC_MEDIA_GPR_DATA
{
ULONG LinkMask;
ULONG Polarity;
};
};
} DC_MEDIA, *PDC_MEDIA;
typedef struct _DC_MII_MEDIA
{
UCHAR SetupStreamLength;
UCHAR ResetStreamLength;
USHORT Advertising;
USHORT SetupStream[SROM_MAX_STREAM_REGS + 1]; // +1 for GPIO direction (21140)
USHORT ResetStream[SROM_MAX_STREAM_REGS];
} DC_MII_MEDIA, *PDC_MII_MEDIA;
/*
* SROM-defined media values
*/
#define MEDIA_10T 0
#define MEDIA_BNC 1
#define MEDIA_AUI 2
#define MEDIA_100TX_HD 3
#define MEDIA_10T_HD MEDIA_100TX_HD /* 21041 only */
#define MEDIA_10T_FD 4
#define MEDIA_100TX_FD 5
#define MEDIA_100T4 6
#define MEDIA_100FX_HD 7
#define MEDIA_100FX_FD 8
#define MEDIA_HMR 9
#define MEDIA_LIST_MAX 10
/*
* Registry configuration
*/
#define MEDIA_AUTO MEDIA_LIST_MAX
/*
* Extra codes
*/
#define MEDIA_MII MEDIA_LIST_MAX
#define MEDIA_MAX (MEDIA_LIST_MAX + 1)
#define MEDIA_MII_OVERRIDE_MASK \
((1 << MEDIA_AUI) | \
(1 << MEDIA_BNC) | \
(1 << MEDIA_100FX_HD) | \
(1 << MEDIA_100FX_FD) | \
(1 << MEDIA_HMR))
#define MEDIA_FD_MASK \
((1 << MEDIA_10T_FD) | \
(1 << MEDIA_100TX_FD) | \
(1 << MEDIA_100FX_FD))
#define MEDIA_AUI_BNC_MASK \
((1 << MEDIA_AUI) | \
(1 << MEDIA_BNC))
#define MEDIA_10T_MASK \
((1 << MEDIA_10T) | \
(1 << MEDIA_10T_FD))
#define MEDIA_100_MASK \
((1 << MEDIA_100TX_HD) | \
(1 << MEDIA_100TX_FD) | \
(1 << MEDIA_100T4) | \
(1 << MEDIA_100FX_HD) | \
(1 << MEDIA_100FX_FD))
#define MEDIA_FX_MASK \
((1 << MEDIA_100FX_HD) | \
(1 << MEDIA_100FX_FD))
/* Specifying this media code override the default MII selection */
#define MEDIA_MII_OVERRIDE(MediaNumber) \
(((1 << (MediaNumber)) & MEDIA_MII_OVERRIDE_MASK) != 0)
/* Full-duplex media */
#define MEDIA_IS_FD(MediaNumber) \
(((1 << (MediaNumber)) & MEDIA_FD_MASK) != 0)
/* AUI or BNC media */
#define MEDIA_IS_AUI_BNC(MediaNumber) \
(((1 << (MediaNumber)) & MEDIA_AUI_BNC_MASK) != 0)
/* 10Base-T media */
#define MEDIA_IS_10T(MediaNumber) \
(((1 << (MediaNumber)) & MEDIA_10T_MASK) != 0)
/* 100mbps media */
#define MEDIA_IS_100(MediaNumber) \
(((1 << (MediaNumber)) & MEDIA_100_MASK) != 0)
/* 100Base-FX media */
#define MEDIA_IS_FX(MediaNumber) \
(((1 << (MediaNumber)) & MEDIA_FX_MASK) != 0)
/* Forced speed and duplex */
#define MEDIA_IS_FIXED(Adapter) \
(((Adapter)->Flags & DC_AUTOSENSE) == 0)

View file

@ -0,0 +1,143 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: 21040 media support code
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* FUNCTIONS ******************************************************************/
VOID
MediaLinkStateChange21040(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG InterruptStatus)
{
UNREFERENCED_PARAMETER(InterruptStatus);
INFO_VERB("Link failed, CSR12 %08lx\n", DC_READ(Adapter, DcCsr12_SiaStatus));
NdisDprAcquireSpinLock(&Adapter->ModeLock);
/* Start the media timer when the 10Base-T link has changed state */
if (Adapter->MediaNumber != MEDIA_BNC)
{
MediaIndicateConnect(Adapter, FALSE);
NdisMSetTimer(&Adapter->MediaMonitorTimer, 3000);
}
NdisDprReleaseSpinLock(&Adapter->ModeLock);
}
VOID
NTAPI
MediaMonitor21040Dpc(
_In_ PVOID SystemSpecific1,
_In_ PVOID FunctionContext,
_In_ PVOID SystemSpecific2,
_In_ PVOID SystemSpecific3)
{
PDC21X4_ADAPTER Adapter = FunctionContext;
BOOLEAN LinkUp, Report, RunAgain;
UNREFERENCED_PARAMETER(SystemSpecific1);
UNREFERENCED_PARAMETER(SystemSpecific2);
UNREFERENCED_PARAMETER(SystemSpecific3);
if (!(Adapter->Flags & DC_ACTIVE))
return;
LinkUp = FALSE;
Report = FALSE;
RunAgain = TRUE;
NdisDprAcquireSpinLock(&Adapter->ModeLock);
if (Adapter->MediaNumber != MEDIA_BNC)
{
ULONG SiaStatus = DC_READ(Adapter, DcCsr12_SiaStatus);
Report = TRUE;
LinkUp = !(SiaStatus & (DC_SIA_STATUS_NETWORK_CONNECTION_ERROR |
DC_SIA_STATUS_10T_LINK_FAIL));
if (!LinkUp)
{
/* Select the other port */
if (!MEDIA_IS_FIXED(Adapter))
{
Adapter->MediaNumber = MEDIA_BNC;
DcWriteSia(Adapter,
Adapter->Media[MEDIA_BNC].Csr13,
Adapter->Media[MEDIA_BNC].Csr14,
Adapter->Media[MEDIA_BNC].Csr15);
Adapter->LastReceiveActivity = (ULONG)Adapter->Statistics.ReceiveOk;
}
}
else
{
/* Wait until the next link change event */
RunAgain = FALSE;
}
}
else
{
ULONG ReceiveActivity = (ULONG)Adapter->Statistics.ReceiveOk;
if (!(Adapter->ModeFlags & DC_MODE_TEST_PACKET))
{
/* Check for any received packets */
if (ReceiveActivity != Adapter->LastReceiveActivity)
{
LinkUp = TRUE;
Report = TRUE;
}
else
{
/* Send a loopback packet */
NdisDprAcquireSpinLock(&Adapter->SendLock);
DcTestPacket(Adapter);
NdisDprReleaseSpinLock(&Adapter->SendLock);
}
}
else
{
Adapter->ModeFlags &= ~DC_MODE_TEST_PACKET;
LinkUp = !!Adapter->MediaTestStatus;
Report = TRUE;
/* Select the other port */
if (!LinkUp && !MEDIA_IS_FIXED(Adapter))
{
Adapter->MediaNumber = MEDIA_10T;
DcWriteSia(Adapter,
Adapter->Media[MEDIA_10T].Csr13,
Adapter->Media[MEDIA_10T].Csr14,
Adapter->Media[MEDIA_10T].Csr15);
}
}
Adapter->LastReceiveActivity = ReceiveActivity;
}
if (Report)
{
MediaIndicateConnect(Adapter, LinkUp);
}
NdisDprReleaseSpinLock(&Adapter->ModeLock);
if (RunAgain)
{
NdisMSetTimer(&Adapter->MediaMonitorTimer, LinkUp ? 6000 : 3000);
}
}

View file

@ -0,0 +1,222 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: 21041 media support code
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* FUNCTIONS ******************************************************************/
VOID
MediaLinkStateChange21041(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG InterruptStatus)
{
NdisDprAcquireSpinLock(&Adapter->ModeLock);
if (InterruptStatus & DC_IRQ_LINK_PASS)
{
INFO_VERB("Link passed, CSR12 %08lx\n", DC_READ(Adapter, DcCsr12_SiaStatus));
/* 10Base-T is the active port now */
if (MEDIA_IS_AUI_BNC(Adapter->MediaNumber))
{
/* Switch to TP medium */
if (!MEDIA_IS_FIXED(Adapter))
{
Adapter->MediaNumber = MEDIA_10T;
MediaSiaSelect(Adapter);
NdisMSetTimer(&Adapter->MediaMonitorTimer, 3000);
}
}
/* 10Base-T link is up */
if (!MEDIA_IS_AUI_BNC(Adapter->MediaNumber))
{
MediaIndicateConnect(Adapter, TRUE);
}
}
else // DC_IRQ_LINK_FAIL
{
INFO_VERB("Link failed, CSR12 %08lx\n", DC_READ(Adapter, DcCsr12_SiaStatus));
/* 10Base-T link is down */
if (!MEDIA_IS_AUI_BNC(Adapter->MediaNumber))
{
MediaIndicateConnect(Adapter, FALSE);
}
}
NdisDprReleaseSpinLock(&Adapter->ModeLock);
}
static
VOID
Media041SelectNextMedia(
_In_ PDC21X4_ADAPTER Adapter)
{
if (Adapter->MediaNumber == MEDIA_AUI)
Adapter->ModeFlags |= DC_MODE_AUI_FAILED;
else if (Adapter->MediaNumber == MEDIA_BNC)
Adapter->ModeFlags |= DC_MODE_BNC_FAILED;
if ((Adapter->ModeFlags & (DC_MODE_AUI_FAILED | DC_MODE_BNC_FAILED)) ==
(DC_MODE_AUI_FAILED | DC_MODE_BNC_FAILED))
{
Adapter->MediaNumber = MEDIA_10T;
}
else
{
Adapter->MediaNumber = (MEDIA_BNC + MEDIA_AUI) - Adapter->MediaNumber;
}
MediaSiaSelect(Adapter);
}
VOID
NTAPI
MediaMonitor21041Dpc(
_In_ PVOID SystemSpecific1,
_In_ PVOID FunctionContext,
_In_ PVOID SystemSpecific2,
_In_ PVOID SystemSpecific3)
{
PDC21X4_ADAPTER Adapter = FunctionContext;
BOOLEAN LinkUp, Report;
ULONG DelayMs, SiaStatus;
UNREFERENCED_PARAMETER(SystemSpecific1);
UNREFERENCED_PARAMETER(SystemSpecific2);
UNREFERENCED_PARAMETER(SystemSpecific3);
if (!(Adapter->Flags & DC_ACTIVE))
return;
Report = FALSE;
DelayMs = 5000;
NdisDprAcquireSpinLock(&Adapter->ModeLock);
SiaStatus = DC_READ(Adapter, DcCsr12_SiaStatus);
if (MEDIA_IS_AUI_BNC(Adapter->MediaNumber))
{
if ((Adapter->ModeFlags & DC_MODE_PORT_AUTOSENSE))
{
Adapter->ModeFlags &= ~DC_MODE_PORT_AUTOSENSE;
/* Select the other port */
if (!(SiaStatus & DC_SIA_STATUS_SELECTED_PORT_ACTIVITY))
{
Adapter->MediaNumber = MEDIA_BNC;
MediaSiaSelect(Adapter);
}
DelayMs = 1000;
}
else
{
ULONG ReceiveActivity = (ULONG)Adapter->Statistics.ReceiveOk;
if (!(Adapter->ModeFlags & DC_MODE_TEST_PACKET))
{
if ((Adapter->MediaNumber == MEDIA_AUI) &&
(SiaStatus & DC_SIA_STATUS_SELECTED_PORT_ACTIVITY))
{
/* Clear the selected port activity bit */
DC_WRITE(Adapter, DcCsr12_SiaStatus, DC_SIA_STATUS_SELECTED_PORT_ACTIVITY);
LinkUp = TRUE;
Report = TRUE;
}
/* Check for any received packets */
else if (ReceiveActivity != Adapter->LastReceiveActivity)
{
LinkUp = TRUE;
Report = TRUE;
DelayMs = 3000;
}
else
{
/* Send a loopback packet */
NdisDprAcquireSpinLock(&Adapter->SendLock);
DcTestPacket(Adapter);
NdisDprReleaseSpinLock(&Adapter->SendLock);
DelayMs = 3000;
}
}
else
{
Adapter->ModeFlags &= ~DC_MODE_TEST_PACKET;
LinkUp = !!Adapter->MediaTestStatus;
Report = TRUE;
/* Select the other port */
if (!LinkUp && !MEDIA_IS_FIXED(Adapter))
{
Media041SelectNextMedia(Adapter);
DelayMs = 3000;
}
}
Adapter->LastReceiveActivity = ReceiveActivity;
}
}
else // 10Base-T
{
Report = TRUE;
LinkUp = !(SiaStatus & (DC_SIA_STATUS_NETWORK_CONNECTION_ERROR |
DC_SIA_STATUS_10T_LINK_FAIL));
if (!LinkUp)
{
DelayMs = 3000;
/* Select the AUI or BNC port */
if (!MEDIA_IS_FIXED(Adapter) && (Adapter->MediaBitmap & MEDIA_AUI_BNC_MASK))
{
Adapter->ModeFlags &= ~(DC_MODE_AUI_FAILED |
DC_MODE_BNC_FAILED |
DC_MODE_TEST_PACKET);
if (SiaStatus & DC_SIA_STATUS_NONSEL_PORT_ACTIVITY)
{
Adapter->MediaNumber = MEDIA_AUI;
Adapter->ModeFlags |= DC_MODE_PORT_AUTOSENSE;
}
else
{
Adapter->MediaNumber = MEDIA_BNC;
}
MediaSiaSelect(Adapter);
Adapter->LastReceiveActivity = (ULONG)Adapter->Statistics.ReceiveOk;
/* Clear the port activity bits */
DC_WRITE(Adapter, DcCsr12_SiaStatus, DC_SIA_STATUS_SELECTED_PORT_ACTIVITY |
DC_SIA_STATUS_NONSEL_PORT_ACTIVITY);
DelayMs = 1000;
}
}
}
if (Report)
{
MediaIndicateConnect(Adapter, LinkUp);
}
NdisDprReleaseSpinLock(&Adapter->ModeLock);
NdisMSetTimer(&Adapter->MediaMonitorTimer, DelayMs);
}

View file

@ -0,0 +1,136 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: 21140 media support code
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* FUNCTIONS ******************************************************************/
static
BOOLEAN
MediaGprCheckLink(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG GpioData;
PDC_MEDIA Media;
Media = &Adapter->Media[Adapter->MediaNumber];
/* No media activity indicator */
if (Media->LinkMask == 0)
{
TRACE("No activity indicator\n");
/* Assume we have a link */
if (MEDIA_IS_FIXED(Adapter))
return TRUE;
return FALSE;
}
GpioData = DC_READ(Adapter, DcCsr12_Gpio);
TRACE("CSR12 %08lx\n", GpioData);
/* This media supports link indication via GPIO pins */
return !!((GpioData & Media->LinkMask) ^ Media->Polarity);
}
static
ULONG
MediaGprNextMedia(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG i;
/* No half-duplex media in the media list */
if (!(Adapter->MediaBitmap & ~MEDIA_FD_MASK))
{
return Adapter->MediaNumber;
}
/* Find the next half-duplex media */
i = Adapter->MediaNumber;
while (TRUE)
{
/* We have reached the end of the media list, try the first media */
if (i == 0)
{
_BitScanReverse(&i, Adapter->MediaBitmap);
}
else
{
--i;
}
if ((Adapter->MediaBitmap & (1 << i)) && !MEDIA_IS_FD(i))
{
return i;
}
}
}
VOID
NTAPI
MediaMonitor21140Dpc(
_In_ PVOID SystemSpecific1,
_In_ PVOID FunctionContext,
_In_ PVOID SystemSpecific2,
_In_ PVOID SystemSpecific3)
{
PDC21X4_ADAPTER Adapter = FunctionContext;
ULONG DelayMs, MediaNumber;
BOOLEAN LinkUp;
UNREFERENCED_PARAMETER(SystemSpecific1);
UNREFERENCED_PARAMETER(SystemSpecific2);
UNREFERENCED_PARAMETER(SystemSpecific3);
if (!(Adapter->Flags & DC_ACTIVE))
return;
NdisDprAcquireSpinLock(&Adapter->ModeLock);
if (Adapter->MediaNumber == MEDIA_MII)
{
LinkUp = MediaMiiCheckLink(Adapter);
DelayMs = 5000;
}
else
{
LinkUp = MediaGprCheckLink(Adapter);
/* This media is unconnected, try the next media */
if (!LinkUp && !MEDIA_IS_FIXED(Adapter))
{
MediaNumber = MediaGprNextMedia(Adapter);
if (Adapter->MediaNumber != MediaNumber)
{
Adapter->MediaNumber = MediaNumber;
MediaGprSelect(Adapter);
}
DelayMs = 3000;
}
else
{
/* If we are forcing media, then we need to poll the media less frequently */
DelayMs = 5000;
}
}
MediaIndicateConnect(Adapter, LinkUp);
NdisDprReleaseSpinLock(&Adapter->ModeLock);
NdisMSetTimer(&Adapter->MediaMonitorTimer, DelayMs);
}

View file

@ -0,0 +1,510 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: 21142/21143/21145 media support code
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* FUNCTIONS ******************************************************************/
static
VOID
Media143SelectNextSerialMedia(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG MediaNumber;
MediaNumber = Adapter->MediaNumber;
/* The HMR media isn't checked as HMR boards use it instead of AUI and BNC */
if (MediaNumber == MEDIA_AUI || MediaNumber == MEDIA_BNC)
{
if (MediaNumber == MEDIA_AUI)
Adapter->ModeFlags |= DC_MODE_AUI_FAILED;
else if (MediaNumber == MEDIA_BNC)
Adapter->ModeFlags |= DC_MODE_BNC_FAILED;
if ((Adapter->ModeFlags & (DC_MODE_AUI_FAILED | DC_MODE_BNC_FAILED)) !=
(DC_MODE_AUI_FAILED | DC_MODE_BNC_FAILED))
{
MediaNumber = (MEDIA_BNC + MEDIA_AUI) - MediaNumber;
if (Adapter->MediaBitmap & (1 << MediaNumber))
{
Adapter->MediaNumber = MediaNumber;
MediaSiaSelect(Adapter);
return;
}
}
}
if (Adapter->Features & DC_HAS_MII)
{
Adapter->MediaNumber = MEDIA_MII;
DcStopTxRxProcess(Adapter);
MediaSelectMiiPort(Adapter, FALSE);
MediaMiiSelect(Adapter);
}
else
{
Adapter->MediaNumber = MEDIA_10T;
MediaSiaSelect(Adapter);
}
}
static
VOID
Media143SelectNextMedia(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG SiaStatus)
{
ULONG MediaBitmap, MediaNumber;
MediaIndicateConnect(Adapter, FALSE);
MediaBitmap = Adapter->MediaBitmap;
if (MediaBitmap & (1 << MEDIA_HMR))
{
MediaNumber = MEDIA_HMR;
}
else if ((MediaBitmap & MEDIA_AUI_BNC_MASK) == MEDIA_AUI_BNC_MASK)
{
if (SiaStatus & DC_SIA_STATUS_AUI_ACTIVITY)
{
MediaNumber = MEDIA_AUI;
}
else
{
MediaNumber = MEDIA_BNC;
}
}
else if (MediaBitmap & (1 << MEDIA_AUI))
{
MediaNumber = MEDIA_AUI;
}
else if (MediaBitmap & (1 << MEDIA_BNC))
{
MediaNumber = MEDIA_BNC;
}
else
{
MediaNumber = MEDIA_10T;
}
Adapter->ModeFlags &= ~DC_MODE_AUTONEG_MASK;
Adapter->ModeFlags |= DC_MODE_AUTONEG_NONE;
NdisMSetTimer(&Adapter->MediaMonitorTimer, 3000);
if (Adapter->MediaNumber != MediaNumber)
{
Adapter->MediaNumber = MediaNumber;
MediaSiaSelect(Adapter);
}
Adapter->ModeFlags &= ~(DC_MODE_TEST_PACKET |
DC_MODE_AUI_FAILED |
DC_MODE_BNC_FAILED);
Adapter->LastReceiveActivity = (ULONG)Adapter->Statistics.ReceiveOk;
}
static
VOID
Media143Handle10LinkFail(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG SiaStatus)
{
INFO_VERB("Link failed, CSR12 %08lx\n", SiaStatus);
/* 10Base-T link is down */
MediaIndicateConnect(Adapter, FALSE);
/* Select the other port */
if (!MEDIA_IS_FIXED(Adapter))
{
Media143SelectNextMedia(Adapter, SiaStatus);
}
}
static
VOID
Media143Handle10LinkPass(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG SiaStatus)
{
INFO_VERB("Link passed, CSR12 %08lx\n", SiaStatus);
/* 10Base-T is the active port now */
if (!MEDIA_IS_10T(Adapter->MediaNumber))
{
/* Switch to TP medium */
if (!MEDIA_IS_FIXED(Adapter))
{
Adapter->MediaNumber = MEDIA_10T;
MediaSiaSelect(Adapter);
/* Wait for a link pass interrupt to signal the link test completed */
Adapter->ModeFlags &= ~DC_MODE_AUTONEG_MASK;
Adapter->ModeFlags |= DC_MODE_AUTONEG_WAIT_INTERRUPT;
NdisMSetTimer(&Adapter->MediaMonitorTimer, 3000);
}
}
else
{
/* 10Base-T link is up */
MediaIndicateConnect(Adapter, TRUE);
}
}
static
VOID
Media143Handle100LinkChange(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG SiaStatus)
{
BOOLEAN LinkUp;
INFO_VERB("Link changed, CSR12 %08lx\n", SiaStatus);
LinkUp = !(SiaStatus & DC_SIA_STATUS_100T_LINK_FAIL);
if (MEDIA_IS_FIXED(Adapter))
{
MediaIndicateConnect(Adapter, LinkUp);
}
else
{
/* Select the other port */
if (!LinkUp)
{
Media143SelectNextMedia(Adapter, SiaStatus);
}
else
{
/* Ignore this hint */
}
}
}
static
VOID
Media143HandleNWayComplete(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG SiaStatus)
{
ULONG MediaNumber, AdvLpa;
/* Select media according to auto-negotiation result */
if (SiaStatus & DC_SIA_STATUS_LP_AUTONED_SUPPORTED)
{
INFO_VERB("Auto-negotiation has completed, LPA %08lx ADV %08lx\n",
SiaStatus, Adapter->SymAdvertising);
AdvLpa = (SiaStatus >> DC_SIA_STATUS_LP_CODE_WORD_SHIFT) & Adapter->SymAdvertising;
if (AdvLpa & MII_ADV_100T_FD)
{
MediaNumber = MEDIA_100TX_FD;
}
else if (AdvLpa & MII_ADV_100T4)
{
MediaNumber = MEDIA_100T4;
}
else if (AdvLpa & MII_ADV_100T_HD)
{
MediaNumber = MEDIA_100TX_HD;
}
else if (AdvLpa & MII_ADV_10T_FD)
{
MediaNumber = MEDIA_10T_FD;
}
else if (AdvLpa & MII_ADV_10T_HD)
{
MediaNumber = MEDIA_10T;
}
else
{
INFO_VERB("No common mode\n");
/* No common mode, select the other port */
Media143SelectNextMedia(Adapter, SiaStatus);
return;
}
}
else
{
INFO_VERB("Link partner does not support auto-negotiation, CSR12 %08lx\n", SiaStatus);
/* Check the results of parallel detection */
if (!(SiaStatus & DC_SIA_STATUS_100T_LINK_FAIL))
{
MediaNumber = MEDIA_100TX_HD;
}
else if (!(SiaStatus & DC_SIA_STATUS_10T_LINK_FAIL))
{
MediaNumber = MEDIA_10T;
}
else
{
/* No link detected, select the other port */
Media143SelectNextMedia(Adapter, SiaStatus);
return;
}
}
if (MEDIA_IS_10T(MediaNumber) && (MediaNumber != Adapter->MediaNumber))
{
/* Set the time limit for auto-negotiation */
Adapter->ModeFlags &= ~DC_MODE_AUTONEG_MASK;
Adapter->ModeFlags |= DC_MODE_AUTONEG_WAIT_INTERRUPT;
NdisMSetTimer(&Adapter->MediaMonitorTimer, 5000);
}
else
{
/* Wait for the link integrity test to complete before we can read the link status */
Adapter->ModeFlags &= ~DC_MODE_AUTONEG_MASK;
Adapter->ModeFlags |= DC_MODE_AUTONEG_LINK_STATUS_CHECK;
NdisMSetTimer(&Adapter->MediaMonitorTimer, 1000);
}
if (Adapter->MediaNumber != MediaNumber)
{
Adapter->MediaNumber = MediaNumber;
MediaSiaSelect(Adapter);
}
}
VOID
MediaLinkStateChange21143(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG InterruptStatus)
{
ULONG SiaStatus;
INFO_VERB("Link interrupt, CSR5 %08lx\n", InterruptStatus);
NdisDprAcquireSpinLock(&Adapter->ModeLock);
/* Ignore link changes caused by media being estabilished */
if ((Adapter->ModeFlags & DC_MODE_AUTONEG_MASK) == DC_MODE_AUTONEG_LINK_STATUS_CHECK)
{
NdisDprReleaseSpinLock(&Adapter->ModeLock);
return;
}
SiaStatus = DC_READ(Adapter, DcCsr12_SiaStatus);
if ((InterruptStatus & DC_IRQ_LINK_FAIL) && MEDIA_IS_10T(Adapter->MediaNumber))
{
/* Link has failed */
Media143Handle10LinkFail(Adapter, SiaStatus);
}
else if (InterruptStatus & DC_IRQ_LINK_PASS)
{
if (DC_READ(Adapter, DcCsr14_SiaTxRx) & DC_SIA_TXRX_AUTONEG)
{
/* Auto-negotiation has completed */
Media143HandleNWayComplete(Adapter, SiaStatus);
}
else
{
/* Link has passed */
Media143Handle10LinkPass(Adapter, SiaStatus);
}
}
else
{
/* NOTE: The Link Changed bit is reserved on the 21142 and always reads as 1 */
if (InterruptStatus & Adapter->LinkStateChangeMask & DC_IRQ_LINK_CHANGED)
{
/* Link has changed */
Media143Handle100LinkChange(Adapter, SiaStatus);
}
}
NdisDprReleaseSpinLock(&Adapter->ModeLock);
}
static
BOOLEAN
Media143CheckLink(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG SiaStatus)
{
if (MEDIA_IS_100(Adapter->MediaNumber))
{
if (SiaStatus & DC_SIA_STATUS_100T_LINK_FAIL)
return FALSE;
}
else
{
/* The auto-negotiation process can be restarted upon link failure in 10Base-T mode */
if ((SiaStatus & DC_SIA_STATUS_ANS_MASK) != DC_SIA_STATUS_ANS_AUTONEG_COMPLETE)
return FALSE;
if (SiaStatus & DC_SIA_STATUS_10T_LINK_FAIL)
return FALSE;
}
return TRUE;
}
static
VOID
MediaMonitor143(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG SiaStatus;
BOOLEAN LinkUp;
SiaStatus = DC_READ(Adapter, DcCsr12_SiaStatus);
switch (Adapter->ModeFlags & DC_MODE_AUTONEG_MASK)
{
case DC_MODE_AUTONEG_WAIT_INTERRUPT:
{
/* Timeout, select the other port */
Media143SelectNextMedia(Adapter, SiaStatus);
break;
}
case DC_MODE_AUTONEG_LINK_STATUS_CHECK:
{
/* Check the link status */
LinkUp = Media143CheckLink(Adapter, SiaStatus);
if (LinkUp)
{
Adapter->ModeFlags &= ~DC_MODE_AUTONEG_MASK;
Adapter->ModeFlags |= DC_MODE_AUTONEG_NONE;
MediaIndicateConnect(Adapter, TRUE);
}
else
{
/* No link detected, select the other port */
Media143SelectNextMedia(Adapter, SiaStatus);
}
break;
}
case DC_MODE_AUTONEG_NONE:
{
break;
}
default:
ASSERT(FALSE);
UNREACHABLE;
break;
}
}
VOID
NTAPI
MediaMonitor21143Dpc(
_In_ PVOID SystemSpecific1,
_In_ PVOID FunctionContext,
_In_ PVOID SystemSpecific2,
_In_ PVOID SystemSpecific3)
{
PDC21X4_ADAPTER Adapter = FunctionContext;
ULONG DelayMs;
BOOLEAN LinkUp;
UNREFERENCED_PARAMETER(SystemSpecific1);
UNREFERENCED_PARAMETER(SystemSpecific2);
UNREFERENCED_PARAMETER(SystemSpecific3);
if (!(Adapter->Flags & DC_ACTIVE))
return;
NdisDprAcquireSpinLock(&Adapter->ModeLock);
switch (Adapter->MediaNumber)
{
case MEDIA_MII:
{
LinkUp = MediaMiiCheckLink(Adapter);
MediaIndicateConnect(Adapter, LinkUp);
NdisMSetTimer(&Adapter->MediaMonitorTimer, 5000);
break;
}
case MEDIA_AUI:
case MEDIA_BNC:
case MEDIA_HMR:
{
ULONG ReceiveActivity = (ULONG)Adapter->Statistics.ReceiveOk;
if (!(Adapter->ModeFlags & DC_MODE_TEST_PACKET))
{
if ((Adapter->MediaNumber == MEDIA_AUI || Adapter->MediaNumber == MEDIA_HMR) &&
(DC_READ(Adapter, DcCsr12_SiaStatus) & DC_SIA_STATUS_AUI_ACTIVITY))
{
/* Clear the AUI/HMR port activity bit */
DC_WRITE(Adapter, DcCsr12_SiaStatus, DC_SIA_STATUS_AUI_ACTIVITY);
MediaIndicateConnect(Adapter, TRUE);
DelayMs = 5000;
}
/* Check for any received packets */
else if (ReceiveActivity != Adapter->LastReceiveActivity)
{
MediaIndicateConnect(Adapter, TRUE);
DelayMs = 3000;
}
else
{
/* Send a loopback packet */
NdisDprAcquireSpinLock(&Adapter->SendLock);
DcTestPacket(Adapter);
NdisDprReleaseSpinLock(&Adapter->SendLock);
DelayMs = 3000;
}
}
else
{
Adapter->ModeFlags &= ~DC_MODE_TEST_PACKET;
LinkUp = !!Adapter->MediaTestStatus;
MediaIndicateConnect(Adapter, LinkUp);
/* Select the other port */
if (!LinkUp && !MEDIA_IS_FIXED(Adapter))
{
Media143SelectNextSerialMedia(Adapter);
DelayMs = 3000;
}
else
{
DelayMs = 5000;
}
}
Adapter->LastReceiveActivity = ReceiveActivity;
NdisMSetTimer(&Adapter->MediaMonitorTimer, DelayMs);
break;
}
default:
{
MediaMonitor143(Adapter);
break;
}
}
NdisDprReleaseSpinLock(&Adapter->ModeLock);
}

View file

@ -0,0 +1,158 @@
; NET21X4.INF
; Installation file for DC21x4-based NICs
[Version]
Signature = "$Windows NT$"
;Signature = "$ReactOS$"
LayoutFile = layout.inf
Class = Net
ClassGUID = {4D36E972-E325-11CE-BFC1-08002BE10318}
Provider = %ReactOS%
DriverVer = 08/24/2023,1.00
[DestinationDirs]
DefaultDestDir = 12
[Manufacturer]
%IntelMfg% = IntelMfg
[ControlFlags]
ExcludeFromSelect = *
[IntelMfg]
%DC21040.DeviceDesc% = DC21040.ndi,PCI\VEN_1011&DEV_0002
%DC21041.DeviceDesc% = DC21041.ndi,PCI\VEN_1011&DEV_0014
%DC21140.DeviceDesc% = DC21140.ndi,PCI\VEN_1011&DEV_0009
%DC21143.DeviceDesc% = DC21143.ndi,PCI\VEN_1011&DEV_0019
%DC21145.DeviceDesc% = DC21145.ndi,PCI\VEN_8086&DEV_0039
%DC21140_VPC.DeviceDesc% = DC21140.ndi,PCI\VEN_1011&DEV_0009&SUBSYS_21140A00&REV_20
[DC21040.ndi.NT]
Characteristics = 0x84 ; NCF_PHYSICAL | NCF_HAS_UI
BusType = 5 ; PCIBus
CopyFiles = DC_CopyFiles.NT
AddReg = Common, DC_SD, DC_AUIBNC, DC_10
[DC21041.ndi.NT]
Characteristics = 0x84
BusType = 5
CopyFiles = DC_CopyFiles.NT
AddReg = Common, DC_SD, DC_AUI_BNC, DC_10
[DC21140.ndi.NT]
Characteristics = 0x84
BusType = 5
CopyFiles = DC_CopyFiles.NT
AddReg = Common, DC_SD, DC_10, DC_100
[DC21143.ndi.NT]
Characteristics = 0x84
BusType = 5
CopyFiles = DC_CopyFiles.NT
AddReg = Common, DC_SD, DC_AUI_BNC, DC_10, DC_100
[DC21145.ndi.NT]
Characteristics = 0x84
BusType = 5
CopyFiles = DC_CopyFiles.NT
AddReg = Common, DC_SD, DC_10, DC_HMR
[DC_CopyFiles.NT]
dc21x4.sys
[DC21040.ndi.NT.Services]
AddService = dc21x4, 2, DC_Service_Inst, DC_EventLog
[DC21041.ndi.NT.Services]
AddService = dc21x4, 2, DC_Service_Inst, DC_EventLog
[DC21140.ndi.NT.Services]
AddService = dc21x4, 2, DC_Service_Inst, DC_EventLog
[DC21143.ndi.NT.Services]
AddService = dc21x4, 2, DC_Service_Inst, DC_EventLog
[DC21145.ndi.NT.Services]
AddService = dc21x4, 2, DC_Service_Inst, DC_EventLog
[Common]
HKR, Ndi, Service, 0, "dc21x4"
HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
HKR, Ndi\params\NetworkAddress, ParamDesc, 0, %NA%
HKR, Ndi\params\NetworkAddress, type, 0, "edit"
HKR, Ndi\params\NetworkAddress, LimitText, 0, "12"
HKR, Ndi\params\NetworkAddress, UpperCase, 0, "1"
HKR, Ndi\params\NetworkAddress, default, 0, " "
HKR, Ndi\params\NetworkAddress, optional, 0, "1"
[DC_SD]
HKR, Ndi\params\SpeedDuplex, ParamDesc, 0, %SD%
HKR, Ndi\params\SpeedDuplex, type, 0, "enum"
HKR, Ndi\params\SpeedDuplex, default, 0, "0"
HKR, Ndi\params\SpeedDuplex\enum, "10", 0, "%Auto%"
[DC_AUIBNC]
HKR, Ndi\params\SpeedDuplex\enum, "1", 0, "AUI/BNC"
[DC_AUI_BNC]
HKR, Ndi\params\SpeedDuplex\enum, "1", 0, "BNC"
HKR, Ndi\params\SpeedDuplex\enum, "2", 0, "AUI"
[DC_10]
HKR, Ndi\params\SpeedDuplex\enum, "0", 0, "10T HD"
HKR, Ndi\params\SpeedDuplex\enum, "4", 0, "10T FD"
[DC_100]
HKR, Ndi\params\SpeedDuplex\enum, "3", 0, "100TX HD"
HKR, Ndi\params\SpeedDuplex\enum, "5", 0, "100TX FD"
HKR, Ndi\params\SpeedDuplex\enum, "6", 0, "100T4"
HKR, Ndi\params\SpeedDuplex\enum, "7", 0, "100FX HD"
HKR, Ndi\params\SpeedDuplex\enum, "8", 0, "100FX FD"
[DC_HMR]
HKR, Ndi\params\SpeedDuplex\enum, "9", 0, "HomePNA"
[DC_Service_Inst]
ServiceType = 1
StartType = 3
ErrorControl = 1
ServiceBinary = %12%\dc21x4.sys
LoadOrderGroup = NDIS
[DC_EventLog]
AddReg = DC_EventLog_AddReg
[DC_EventLog_AddReg]
HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll"
HKR, , TypesSupported, 0x00010001, 7
[Strings]
; Non-localizable
ReactOS="ReactOS Team"
IntelMfg="Intel"
NA="Network Address"
SD="Speed & Duplex"
Auto="Auto"
DC21040.DeviceDesc="Intel 21040-based PCI Ethernet Adapter"
DC21041.DeviceDesc="Intel 21041-based PCI Ethernet Adapter"
DC21140.DeviceDesc="Intel 21140-based PCI Ethernet Adapter"
DC21143.DeviceDesc="Intel 21143-based PCI Ethernet Adapter"
DC21145.DeviceDesc="Intel 21145-based PCI Ethernet Adapter"
DC21140_VPC.DeviceDesc="Intel 21140-based PCI Ethernet Adapter (emulated)"
[Strings.0419]
NA="Сетевой адрес"
SD="Скорость и дуплекс"
Auto="Авто"
DC21040.DeviceDesc="Intel 21040-based PCI сетевой адаптер"
DC21041.DeviceDesc="Intel 21041-based PCI сетевой адаптер"
DC21140.DeviceDesc="Intel 21140-based PCI сетевой адаптер"
DC21143.DeviceDesc="Intel 21143-based PCI сетевой адаптер"
DC21145.DeviceDesc="Intel 21145-based PCI сетевой адаптер"
DC21140_VPC.DeviceDesc="Intel 21140-based PCI сетевой адаптер (эмуляция)"

View file

@ -0,0 +1,263 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: PHY layer setup and management
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* GLOBALS ********************************************************************/
#define MII_READ(Adapter, Data) \
do { \
*Data = DC_READ((Adapter), DcCsr9_SerialInterface); \
NdisStallExecution(2); \
} while (0)
#define MII_WRITE(Adapter, Value) \
do { \
DC_WRITE((Adapter), DcCsr9_SerialInterface, Value); \
NdisStallExecution(2); \
} while (0)
/* FUNCTIONS ******************************************************************/
static
VOID
MiiMdioPacket(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG Sequence,
_In_ ULONG BitCount)
{
LONG i;
for (i = BitCount - 1; i >= 0; --i)
{
ULONG Mdo = ((Sequence >> i) & 1) << DC_SERIAL_MII_MDO_SHIFT;
MII_WRITE(Adapter, Mdo);
MII_WRITE(Adapter, Mdo | DC_SERIAL_MII_MDC);
}
}
static
ULONG
MiiMdioShiftIn(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG i, Csr;
ULONG Result = 0;
for (i = 0; i < RTL_BITS_OF(USHORT); ++i)
{
MII_WRITE(Adapter, DC_SERIAL_MII_MII);
MII_WRITE(Adapter, DC_SERIAL_MII_MII | DC_SERIAL_MII_MDC);
MII_READ(Adapter, &Csr);
Result = (Result << 1) | ((Csr >> DC_SERIAL_MII_MDI_SHIFT) & 1);
}
return Result;
}
static
VOID
MiiMdioClearExtraBits(
_In_ PDC21X4_ADAPTER Adapter)
{
MII_WRITE(Adapter, DC_SERIAL_MII_MII);
MII_WRITE(Adapter, DC_SERIAL_MII_MII | DC_SERIAL_MII_MDC);
}
BOOLEAN
MiiWrite(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG PhyAddress,
_In_ ULONG RegAddress,
_In_ ULONG Data)
{
MiiMdioPacket(Adapter, MDIO_PREAMBLE, 32);
MiiMdioPacket(Adapter,
(MDIO_START << 30) |
(MDIO_WRITE << 28) |
(PhyAddress << 23) |
(RegAddress << 18) |
(MDIO_TA << 16) |
Data,
32);
/* Idle state */
MiiMdioClearExtraBits(Adapter);
return TRUE;
}
BOOLEAN
MiiRead(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG PhyAddress,
_In_ ULONG RegAddress,
_Out_ PULONG Data)
{
ULONG Csr;
BOOLEAN Success;
MiiMdioPacket(Adapter, MDIO_PREAMBLE, 32);
MiiMdioPacket(Adapter,
(MDIO_START << 12) |
(MDIO_READ << 10) |
(PhyAddress << 5) |
RegAddress,
14);
/* Turnaround */
MiiMdioClearExtraBits(Adapter);
Csr = DC_READ(Adapter, DcCsr9_SerialInterface);
Success = !(Csr & DC_SERIAL_MII_MDI);
*Data = MiiMdioShiftIn(Adapter);
/* Idle state */
MiiMdioClearExtraBits(Adapter);
return Success;
}
static
CODE_SEG("PAGE")
VOID
HpnaSpiClose(
_In_ PDC21X4_ADAPTER Adapter)
{
PAGED_CODE();
DC_WRITE(Adapter, DcCsr9_SerialInterface, 0);
DC_WRITE(Adapter, DcCsr9_SerialInterface, DC_SERIAL_SPI_SK);
}
static
CODE_SEG("PAGE")
VOID
HpnaSpiShiftOut(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG Sequence,
_In_ ULONG BitCount)
{
LONG i;
PAGED_CODE();
DC_WRITE(Adapter, DcCsr9_SerialInterface, 0);
DC_WRITE(Adapter, DcCsr9_SerialInterface, DC_SERIAL_SPI_CS);
for (i = BitCount - 1; i >= 0; --i)
{
ULONG DataIn = ((Sequence >> i) & 1) << DC_SERIAL_SPI_DI_SHIFT;
DC_WRITE(Adapter, DcCsr9_SerialInterface, DataIn | DC_SERIAL_SPI_CS);
DC_WRITE(Adapter, DcCsr9_SerialInterface, DataIn | DC_SERIAL_SPI_CS | DC_SERIAL_SPI_SK);
}
DC_WRITE(Adapter, DcCsr9_SerialInterface, 0);
DC_WRITE(Adapter, DcCsr9_SerialInterface, DC_SERIAL_SPI_SK);
}
static
CODE_SEG("PAGE")
VOID
HpnaWrite(
_In_ PDC21X4_ADAPTER Adapter,
_In_ ULONG RegAddress,
_In_ ULONG Data)
{
PAGED_CODE();
HpnaSpiShiftOut(Adapter, DC_SPI_SET_WRITE_ENABLE, 8);
HpnaSpiClose(Adapter);
HpnaSpiShiftOut(Adapter,
(Data << 16) |
(RegAddress << 8) |
DC_SPI_BYTE_WRITE_OPERATION,
RTL_BITS_OF(UCHAR) * 3);
HpnaSpiClose(Adapter);
}
CODE_SEG("PAGE")
VOID
HpnaPhyInit(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG SiaConn, i;
PAGED_CODE();
/* Select the HPNA interface */
SiaConn = DC_READ(Adapter, DcCsr13_SiaConnectivity);
SiaConn |= DC_SIA_CONN_HPNA;
DC_WRITE(Adapter, DcCsr13_SiaConnectivity, SiaConn);
for (i = 0; i < RTL_NUMBER_OF(Adapter->HpnaRegister); ++i)
{
if (Adapter->HpnaInitBitmap & (1 << i))
{
HpnaWrite(Adapter, i, Adapter->HpnaRegister[i]);
}
}
}
CODE_SEG("PAGE")
BOOLEAN
DcFindMiiPhy(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG Phy;
PAGED_CODE();
/* Look for the first connected PHY */
for (Phy = 1; Phy <= MII_MAX_PHY_ADDRESSES; ++Phy)
{
ULONG PhyAddress = Phy % MII_MAX_PHY_ADDRESSES; /* Check the PHY 0 last */
ULONG MiiStatus;
#if DBG
ULONG PhyIdLow, PhyIdHigh, MiiControl, MiiAdvertise;
#endif
/*
* Read the status register. Some PHYs, such as the ML6692,
* don't implement the IEEE ID registers.
*/
if (!MiiRead(Adapter, PhyAddress, MII_STATUS, &MiiStatus))
continue;
if (MiiStatus == 0xFFFF || MiiStatus == 0)
continue;
#if DBG
MiiRead(Adapter, PhyAddress, MII_PHY_ID1, &PhyIdLow);
MiiRead(Adapter, PhyAddress, MII_PHY_ID2, &PhyIdHigh);
MiiRead(Adapter, PhyAddress, MII_CONTROL, &MiiControl);
MiiRead(Adapter, PhyAddress, MII_AUTONEG_ADVERTISE, &MiiAdvertise);
INFO_VERB("Found PHY at address %u: ID %04lx:%04lx, Ctrl %04lx, Status %04lx, Adv %04lx\n",
PhyAddress,
PhyIdLow,
PhyIdHigh,
MiiControl,
MiiStatus,
MiiAdvertise);
#endif
Adapter->PhyAddress = PhyAddress;
return TRUE;
}
return FALSE;
}

View file

@ -0,0 +1,252 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Power management
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* FUNCTIONS ******************************************************************/
static
CODE_SEG("PAGE")
VOID
DcDownloadPatternFilter(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PDC_PATTERN_FILTER_BLOCK FilterBlock)
{
ULONG i;
PAGED_CODE();
for (i = 0; i < sizeof(*FilterBlock) / sizeof(ULONG); ++i)
{
DC_WRITE(Adapter, DcCsr1_WakeUpFilter, FilterBlock->AsULONG[i]);
}
}
static
CODE_SEG("PAGE")
VOID
DcSetupWakeUpFilter(
_In_ PDC21X4_ADAPTER Adapter)
{
DC_PATTERN_FILTER_BLOCK FilterBlock;
PAGED_CODE();
/* Save the address filtering */
NdisMoveMemory(Adapter->SetupFrameSaved, Adapter->SetupFrame, DC_SETUP_FRAME_SIZE);
NdisZeroMemory(&FilterBlock, sizeof(FilterBlock));
// TODO: Convert NDIS patterns to HW filter and prepare a setup frame
DcDownloadPatternFilter(Adapter, &FilterBlock);
}
static
CODE_SEG("PAGE")
VOID
DcProgramWakeUpEvents(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG WakeUpControl;
PAGED_CODE();
/* Clear the wake-up events */
WakeUpControl = (DC_WAKE_UP_STATUS_LINK_CHANGE |
DC_WAKE_UP_STATUS_MAGIC_PACKET |
DC_WAKE_UP_CONTROL_PATTERN_MATCH);
/* Convert NDIS flags to hardware-specific values */
if (Adapter->WakeUpFlags & NDIS_PNP_WAKE_UP_LINK_CHANGE)
WakeUpControl |= DC_WAKE_UP_CONTROL_LINK_CHANGE;
if (Adapter->WakeUpFlags & NDIS_PNP_WAKE_UP_MAGIC_PACKET)
WakeUpControl |= DC_WAKE_UP_CONTROL_MAGIC_PACKET;
#if 0 // TODO: Pattern matching is not yet supported
if (Adapter->WakeUpFlags & NDIS_PNP_WAKE_UP_PATTERN_MATCH)
WakeUpControl |= DC_WAKE_UP_CONTROL_PATTERN_MATCH;
#endif
DC_WRITE(Adapter, DcCsr2_WakeUpControl, WakeUpControl);
}
static
CODE_SEG("PAGE")
VOID
DcPowerDown(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG SiaState, SerialInterface;
PAGED_CODE();
/* Stop the receive and transmit processes */
DcStopAdapter(Adapter, FALSE);
Adapter->CurrentInterruptMask = 0;
/* Enable the link integrity test bit */
switch (Adapter->MediaNumber)
{
case MEDIA_AUI:
case MEDIA_BNC:
case MEDIA_HMR:
{
SiaState = DC_READ(Adapter, DcCsr14_SiaTxRx);
if (!(SiaState & DC_SIA_TXRX_LINK_TEST))
{
SiaState |= DC_SIA_TXRX_LINK_TEST;
DC_WRITE(Adapter, DcCsr14_SiaTxRx, SiaState);
}
break;
}
default:
break;
}
/* Clear the MDC bit */
SerialInterface = DC_READ(Adapter, DcCsr9_SerialInterface);
if (SerialInterface & DC_SERIAL_MII_MDC)
{
SerialInterface &= ~DC_SERIAL_MII_MDC;
DC_WRITE(Adapter, DcCsr9_SerialInterface, SerialInterface);
}
/* Unprotect PM access */
DC_WRITE(Adapter, DcCsr0_BusMode, Adapter->BusMode | DC_BUS_MODE_ON_NOW_UNLOCK);
/* Program the requested WOL events */
DcSetupWakeUpFilter(Adapter);
DcProgramWakeUpEvents(Adapter);
/* Protect PM access */
DC_WRITE(Adapter, DcCsr0_BusMode, Adapter->BusMode);
}
static
CODE_SEG("PAGE")
VOID
DcPowerUp(
_In_ PDC21X4_ADAPTER Adapter)
{
PAGED_CODE();
/* Restore the address filtering */
NdisMoveMemory(Adapter->SetupFrame, Adapter->SetupFrameSaved, DC_SETUP_FRAME_SIZE);
/* Re-initialize the chip to leave D3 state */
if (Adapter->PrevPowerState == NdisDeviceStateD3)
{
NT_VERIFY(DcSetupAdapter(Adapter) == TRUE);
}
else
{
/* Start the transmit process */
Adapter->OpMode |= DC_OPMODE_TX_ENABLE;
DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode);
/* Load the address recognition RAM */
NT_VERIFY(DcSetupFrameDownload(Adapter, TRUE) == TRUE);
}
DcStartAdapter(Adapter);
}
CODE_SEG("PAGE")
VOID
NTAPI
DcPowerWorker(
_In_ PNDIS_WORK_ITEM WorkItem,
_In_opt_ PVOID Context)
{
PDC21X4_ADAPTER Adapter = Context;
UNREFERENCED_PARAMETER(WorkItem);
PAGED_CODE();
if (Adapter->PowerState == NdisDeviceStateD0)
{
DcPowerUp(Adapter);
}
else
{
DcPowerDown(Adapter);
}
Adapter->PrevPowerState = Adapter->PowerState;
NdisMSetInformationComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS);
}
NDIS_STATUS
DcSetPower(
_In_ PDC21X4_ADAPTER Adapter,
_In_ NDIS_DEVICE_POWER_STATE PowerState)
{
INFO("Power state %u\n", PowerState);
Adapter->PowerState = PowerState;
NdisScheduleWorkItem(&Adapter->PowerWorkItem);
return NDIS_STATUS_PENDING;
}
NDIS_STATUS
DcRemoveWakeUpPattern(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PNDIS_PM_PACKET_PATTERN PmPattern)
{
// TODO: Not implemented
ERR("FIXME: Not implemented\n");
return NDIS_STATUS_NOT_SUPPORTED;
}
NDIS_STATUS
DcAddWakeUpPattern(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PNDIS_PM_PACKET_PATTERN PmPattern)
{
// TODO: Not implemented
ERR("FIXME: Not implemented\n");
return NDIS_STATUS_NOT_SUPPORTED;
}
VOID
DcPowerSave(
_In_ PDC21X4_ADAPTER Adapter,
_In_ BOOLEAN Enable)
{
ULONG ConfigValue;
if (!(Adapter->Features & DC_HAS_POWER_SAVING))
return;
NdisReadPciSlotInformation(Adapter->AdapterHandle,
0,
DC_PCI_DEVICE_CONFIG,
&ConfigValue,
sizeof(ConfigValue));
ConfigValue &= ~DC_PCI_DEVICE_CONFIG_SLEEP;
if (Enable)
ConfigValue |= DC_PCI_DEVICE_CONFIG_SNOOZE;
else
ConfigValue &= ~DC_PCI_DEVICE_CONFIG_SNOOZE;
NdisWritePciSlotInformation(Adapter->AdapterHandle,
0,
DC_PCI_DEVICE_CONFIG,
&ConfigValue,
sizeof(ConfigValue));
}

View file

@ -0,0 +1,660 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Miniport information callbacks
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* GLOBALS ********************************************************************/
static const NDIS_OID DcpSupportedOidList[] =
{
OID_GEN_SUPPORTED_LIST,
OID_GEN_CURRENT_PACKET_FILTER,
OID_GEN_HARDWARE_STATUS,
OID_GEN_MEDIA_SUPPORTED,
OID_GEN_MEDIA_IN_USE,
OID_GEN_MAXIMUM_LOOKAHEAD,
OID_GEN_MAXIMUM_FRAME_SIZE,
OID_GEN_MAXIMUM_SEND_PACKETS,
OID_GEN_LINK_SPEED,
OID_GEN_TRANSMIT_BUFFER_SPACE,
OID_GEN_RECEIVE_BUFFER_SPACE,
OID_GEN_RECEIVE_BLOCK_SIZE,
OID_GEN_TRANSMIT_BLOCK_SIZE,
OID_GEN_VENDOR_ID,
OID_GEN_VENDOR_DESCRIPTION,
OID_GEN_VENDOR_DRIVER_VERSION,
OID_GEN_CURRENT_LOOKAHEAD,
OID_GEN_DRIVER_VERSION,
OID_GEN_MAXIMUM_TOTAL_SIZE,
OID_GEN_MAC_OPTIONS,
OID_GEN_MEDIA_CONNECT_STATUS,
OID_802_3_PERMANENT_ADDRESS,
OID_802_3_CURRENT_ADDRESS,
OID_802_3_MULTICAST_LIST,
OID_802_3_MAXIMUM_LIST_SIZE,
/* Statistics */
OID_GEN_XMIT_OK,
OID_GEN_RCV_OK,
OID_GEN_XMIT_ERROR,
OID_GEN_RCV_ERROR,
OID_GEN_RCV_NO_BUFFER,
OID_GEN_DIRECTED_FRAMES_RCV,
OID_GEN_MULTICAST_FRAMES_RCV,
OID_GEN_BROADCAST_FRAMES_RCV,
OID_GEN_RCV_CRC_ERROR,
OID_GEN_TRANSMIT_QUEUE_LENGTH,
OID_802_3_RCV_ERROR_ALIGNMENT,
OID_802_3_XMIT_ONE_COLLISION,
OID_802_3_XMIT_MORE_COLLISIONS,
OID_802_3_XMIT_DEFERRED,
OID_802_3_XMIT_MAX_COLLISIONS,
OID_802_3_RCV_OVERRUN,
OID_802_3_XMIT_UNDERRUN,
OID_802_3_XMIT_HEARTBEAT_FAILURE,
OID_802_3_XMIT_TIMES_CRS_LOST,
OID_802_3_XMIT_LATE_COLLISIONS,
/* Power management */
OID_PNP_CAPABILITIES,
OID_PNP_SET_POWER,
OID_PNP_QUERY_POWER,
OID_PNP_ADD_WAKE_UP_PATTERN,
OID_PNP_REMOVE_WAKE_UP_PATTERN,
OID_PNP_ENABLE_WAKE_UP
};
/* FUNCTIONS ******************************************************************/
static
VOID
DcQueryStatisticCounter(
_In_ PDC21X4_ADAPTER Adapter,
_In_ NDIS_OID Oid,
_Out_ PULONG64 Counter)
{
/* When there is no workaround, this function is used to read the hardware RX counters */
if (!(Adapter->Features & DC_NEED_RX_OVERFLOW_WORKAROUND))
{
ULONG RxCounters;
/*
* Read the RX missed frame counter. Note that the RX overflow counter is not supported
* on older chips without the workaround enabled and reads will return 0xFFFE****.
*/
RxCounters = DC_READ(Adapter, DcCsr8_RxCounters);
Adapter->Statistics.ReceiveNoBuffers += RxCounters & DC_COUNTER_RX_NO_BUFFER_MASK;
}
switch (Oid)
{
case OID_GEN_XMIT_OK:
*Counter = Adapter->Statistics.TransmitOk;
break;
case OID_GEN_RCV_OK:
*Counter = Adapter->Statistics.ReceiveOk;
break;
case OID_GEN_XMIT_ERROR:
*Counter = Adapter->Statistics.TransmitErrors;
break;
case OID_GEN_RCV_ERROR:
*Counter = Adapter->Statistics.ReceiveErrors;
break;
case OID_GEN_RCV_NO_BUFFER:
*Counter = Adapter->Statistics.ReceiveNoBuffers;
break;
case OID_GEN_DIRECTED_FRAMES_RCV:
*Counter = Adapter->Statistics.ReceiveUnicast;
break;
case OID_GEN_MULTICAST_FRAMES_RCV:
*Counter = Adapter->Statistics.ReceiveMulticast;
break;
case OID_GEN_BROADCAST_FRAMES_RCV:
*Counter = Adapter->Statistics.ReceiveBroadcast;
break;
case OID_GEN_RCV_CRC_ERROR:
*Counter = Adapter->Statistics.ReceiveCrcErrors;
break;
case OID_802_3_RCV_ERROR_ALIGNMENT:
*Counter = Adapter->Statistics.ReceiveAlignmentErrors;
break;
case OID_802_3_XMIT_ONE_COLLISION:
*Counter = Adapter->Statistics.TransmitOneRetry;
break;
case OID_802_3_XMIT_MORE_COLLISIONS:
*Counter = Adapter->Statistics.TransmitMoreCollisions;
break;
case OID_802_3_XMIT_DEFERRED:
*Counter = Adapter->Statistics.TransmitDeferred;
break;
case OID_802_3_XMIT_MAX_COLLISIONS:
*Counter = Adapter->Statistics.TransmitExcessiveCollisions;
break;
case OID_802_3_RCV_OVERRUN:
*Counter = Adapter->Statistics.ReceiveOverrunErrors;
break;
case OID_802_3_XMIT_UNDERRUN:
*Counter = Adapter->Statistics.TransmitUnderrunErrors;
break;
case OID_802_3_XMIT_HEARTBEAT_FAILURE:
*Counter = Adapter->Statistics.TransmitHeartbeatErrors;
break;
case OID_802_3_XMIT_TIMES_CRS_LOST:
*Counter = Adapter->Statistics.TransmitLostCarrierSense;
break;
case OID_802_3_XMIT_LATE_COLLISIONS:
*Counter = Adapter->Statistics.TransmitLateCollisions;
break;
default:
ASSERT(FALSE);
UNREACHABLE;
break;
}
}
static
ULONG
DcGetLinkSpeed(
_In_ PDC21X4_ADAPTER Adapter)
{
ULONG LinkSpeedMbps;
switch (Adapter->MediaNumber)
{
case MEDIA_HMR:
LinkSpeedMbps = 1;
break;
case MEDIA_10T:
case MEDIA_BNC:
case MEDIA_AUI:
case MEDIA_10T_FD:
LinkSpeedMbps = 10;
break;
case MEDIA_100TX_HD:
case MEDIA_100TX_FD:
case MEDIA_100T4:
case MEDIA_100FX_HD:
case MEDIA_100FX_FD:
LinkSpeedMbps = 100;
break;
case MEDIA_MII:
LinkSpeedMbps = Adapter->LinkSpeedMbps;
break;
default:
ASSERT(FALSE);
UNREACHABLE;
break;
}
return LinkSpeedMbps;
}
NDIS_STATUS
NTAPI
DcQueryInformation(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ NDIS_OID Oid,
_In_ PVOID InformationBuffer,
_In_ ULONG InformationBufferLength,
_Out_ PULONG BytesWritten,
_Out_ PULONG BytesNeeded)
{
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
ULONG InfoLength;
PVOID InfoPtr;
union _GENERIC_INFORMATION
{
USHORT Ushort;
ULONG Ulong;
ULONG64 Ulong64;
NDIS_MEDIUM Medium;
NDIS_HARDWARE_STATUS Status;
NDIS_DEVICE_POWER_STATE PowerState;
} GenericInfo;
InfoLength = sizeof(ULONG);
InfoPtr = &GenericInfo;
switch (Oid)
{
case OID_GEN_SUPPORTED_LIST:
InfoPtr = (PVOID)&DcpSupportedOidList;
InfoLength = sizeof(DcpSupportedOidList);
break;
case OID_GEN_CURRENT_PACKET_FILTER:
GenericInfo.Ulong = Adapter->PacketFilter;
break;
case OID_802_3_MULTICAST_LIST:
InfoPtr = Adapter->MulticastList;
InfoLength = Adapter->MulticastCount * ETH_LENGTH_OF_ADDRESS;
break;
case OID_802_3_MAXIMUM_LIST_SIZE:
GenericInfo.Ulong = Adapter->MulticastMaxEntries;
break;
case OID_GEN_MEDIA_SUPPORTED:
case OID_GEN_MEDIA_IN_USE:
{
GenericInfo.Medium = NdisMedium802_3;
InfoLength = sizeof(NDIS_MEDIUM);
break;
}
case OID_GEN_HARDWARE_STATUS:
{
ULONG InterruptStatus;
/* NOTE: Reading the status register has no effect on the events */
InterruptStatus = DC_READ(Adapter, DcCsr5_Status);
/* Inserted into the motherboard */
if (InterruptStatus != 0xFFFFFFFF)
GenericInfo.Status = NdisHardwareStatusReady;
else
GenericInfo.Status = NdisHardwareStatusNotReady;
InfoLength = sizeof(NDIS_HARDWARE_STATUS);
break;
}
case OID_GEN_MAXIMUM_FRAME_SIZE:
case OID_GEN_MAXIMUM_LOOKAHEAD:
case OID_GEN_CURRENT_LOOKAHEAD:
GenericInfo.Ulong = DC_MAXIMUM_FRAME_SIZE - DC_ETHERNET_HEADER_SIZE;
break;
case OID_GEN_MAXIMUM_TOTAL_SIZE:
GenericInfo.Ulong = DC_MAXIMUM_FRAME_SIZE;
break;
case OID_GEN_TRANSMIT_BLOCK_SIZE:
GenericInfo.Ulong = DC_TRANSMIT_BLOCK_SIZE;
break;
case OID_GEN_TRANSMIT_BUFFER_SPACE:
GenericInfo.Ulong = DC_TRANSMIT_BLOCK_SIZE * DC_TRANSMIT_BLOCKS;
break;
case OID_GEN_RECEIVE_BLOCK_SIZE:
GenericInfo.Ulong = DC_RECEIVE_BLOCK_SIZE;
break;
case OID_GEN_RECEIVE_BUFFER_SPACE:
GenericInfo.Ulong = DC_RECEIVE_BLOCK_SIZE * Adapter->RcbCount;
break;
case OID_GEN_LINK_SPEED:
GenericInfo.Ulong = DcGetLinkSpeed(Adapter) * 10000;
break;
case OID_GEN_VENDOR_ID:
GenericInfo.Ulong = 0;
GenericInfo.Ulong |= (Adapter->PermanentMacAddress[0] << 16);
GenericInfo.Ulong |= (Adapter->PermanentMacAddress[1] << 8);
GenericInfo.Ulong |= (Adapter->PermanentMacAddress[2] & 0xFF);
break;
case OID_GEN_VENDOR_DESCRIPTION:
{
static const CHAR VendorDesc[] = "DC21x4 compatible Ethernet Adapter";
InfoPtr = (PVOID)&VendorDesc;
InfoLength = sizeof(VendorDesc);
break;
}
case OID_GEN_VENDOR_DRIVER_VERSION:
/* 1.0.0 */
GenericInfo.Ulong = 0x100;
break;
case OID_GEN_DRIVER_VERSION:
{
InfoLength = sizeof(USHORT);
GenericInfo.Ushort = (NDIS_MINIPORT_MAJOR_VERSION << 8) | NDIS_MINIPORT_MINOR_VERSION;
break;
}
case OID_GEN_MAXIMUM_SEND_PACKETS:
GenericInfo.Ulong = DC_TRANSMIT_BLOCKS - DC_TCB_RESERVE;
break;
case OID_GEN_MAC_OPTIONS:
GenericInfo.Ulong = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
NDIS_MAC_OPTION_NO_LOOPBACK;
break;
case OID_GEN_MEDIA_CONNECT_STATUS:
GenericInfo.Ulong = Adapter->LinkUp ? NdisMediaStateConnected
: NdisMediaStateDisconnected;
break;
case OID_802_3_PERMANENT_ADDRESS:
InfoPtr = Adapter->PermanentMacAddress;
InfoLength = ETH_LENGTH_OF_ADDRESS;
break;
case OID_802_3_CURRENT_ADDRESS:
InfoPtr = Adapter->CurrentMacAddress;
InfoLength = ETH_LENGTH_OF_ADDRESS;
break;
case OID_GEN_XMIT_OK:
case OID_GEN_RCV_OK:
case OID_GEN_XMIT_ERROR:
case OID_GEN_RCV_ERROR:
case OID_GEN_RCV_NO_BUFFER:
case OID_GEN_DIRECTED_FRAMES_RCV:
case OID_GEN_MULTICAST_FRAMES_RCV:
case OID_GEN_BROADCAST_FRAMES_RCV:
case OID_GEN_RCV_CRC_ERROR:
case OID_802_3_RCV_ERROR_ALIGNMENT:
case OID_802_3_XMIT_ONE_COLLISION:
case OID_802_3_XMIT_MORE_COLLISIONS:
case OID_802_3_XMIT_DEFERRED:
case OID_802_3_XMIT_MAX_COLLISIONS:
case OID_802_3_RCV_OVERRUN:
case OID_802_3_XMIT_UNDERRUN:
case OID_802_3_XMIT_HEARTBEAT_FAILURE:
case OID_802_3_XMIT_TIMES_CRS_LOST:
case OID_802_3_XMIT_LATE_COLLISIONS:
{
DcQueryStatisticCounter(Adapter, Oid, &GenericInfo.Ulong64);
*BytesNeeded = sizeof(ULONG64);
if (InformationBufferLength < sizeof(ULONG))
{
*BytesWritten = 0;
return NDIS_STATUS_BUFFER_TOO_SHORT;
}
if (InformationBufferLength >= sizeof(ULONG64))
{
*BytesWritten = sizeof(ULONG64);
NdisMoveMemory(InformationBuffer, InfoPtr, sizeof(ULONG64));
}
else
{
*BytesWritten = sizeof(ULONG);
NdisMoveMemory(InformationBuffer, InfoPtr, sizeof(ULONG));
}
return NDIS_STATUS_SUCCESS;
}
case OID_GEN_TRANSMIT_QUEUE_LENGTH:
GenericInfo.Ulong = (DC_TRANSMIT_BLOCKS - DC_TCB_RESERVE) - Adapter->TcbSlots;
break;
case OID_PNP_CAPABILITIES:
{
PNDIS_PNP_CAPABILITIES Capabilities;
InfoLength = sizeof(NDIS_PNP_CAPABILITIES);
if (InformationBufferLength < InfoLength)
{
*BytesWritten = 0;
*BytesNeeded = InfoLength;
return NDIS_STATUS_BUFFER_TOO_SHORT;
}
if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT))
return NDIS_STATUS_NOT_SUPPORTED;
*BytesWritten = InfoLength;
*BytesNeeded = 0;
Capabilities = InformationBuffer;
Capabilities->WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateD3;
Capabilities->WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateD3;
Capabilities->WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateD3;
return NDIS_STATUS_SUCCESS;
}
case OID_PNP_QUERY_POWER:
{
if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT))
return NDIS_STATUS_NOT_SUPPORTED;
return NDIS_STATUS_SUCCESS;
}
case OID_PNP_ENABLE_WAKE_UP:
{
if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT))
return NDIS_STATUS_NOT_SUPPORTED;
GenericInfo.Ulong = Adapter->WakeUpFlags & (NDIS_PNP_WAKE_UP_MAGIC_PACKET |
NDIS_PNP_WAKE_UP_PATTERN_MATCH |
NDIS_PNP_WAKE_UP_LINK_CHANGE);
break;
}
default:
Status = NDIS_STATUS_INVALID_OID;
break;
}
if (Status == NDIS_STATUS_SUCCESS)
{
if (InfoLength > InformationBufferLength)
{
*BytesWritten = 0;
*BytesNeeded = InfoLength;
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
}
else
{
NdisMoveMemory(InformationBuffer, InfoPtr, InfoLength);
*BytesWritten = InfoLength;
*BytesNeeded = 0;
}
}
else
{
*BytesWritten = 0;
*BytesNeeded = 0;
}
return Status;
}
NDIS_STATUS
NTAPI
DcSetInformation(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ NDIS_OID Oid,
_In_ PVOID InformationBuffer,
_In_ ULONG InformationBufferLength,
_Out_ PULONG BytesRead,
_Out_ PULONG BytesNeeded)
{
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
ULONG GenericUlong;
*BytesRead = 0;
*BytesNeeded = 0;
switch (Oid)
{
case OID_GEN_CURRENT_PACKET_FILTER:
{
if (InformationBufferLength < sizeof(ULONG))
{
*BytesNeeded = sizeof(ULONG);
Status = NDIS_STATUS_INVALID_LENGTH;
break;
}
*BytesRead = sizeof(ULONG);
NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
if (GenericUlong & ~DC_PACKET_FILTERS)
{
Status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
Status = DcApplyPacketFilter(Adapter, GenericUlong);
break;
}
case OID_802_3_MULTICAST_LIST:
{
ULONG Size;
if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS)
{
*BytesNeeded = (InformationBufferLength / ETH_LENGTH_OF_ADDRESS) *
ETH_LENGTH_OF_ADDRESS;
Status = NDIS_STATUS_INVALID_LENGTH;
break;
}
Size = Adapter->MulticastMaxEntries * ETH_LENGTH_OF_ADDRESS;
if (InformationBufferLength > Size)
{
*BytesNeeded = Size;
Status = NDIS_STATUS_MULTICAST_FULL;
break;
}
*BytesRead = InformationBufferLength;
NdisMoveMemory(Adapter->MulticastList, InformationBuffer, InformationBufferLength);
Adapter->MulticastCount = InformationBufferLength / ETH_LENGTH_OF_ADDRESS;
Status = DcUpdateMulticastList(Adapter);
break;
}
case OID_GEN_CURRENT_LOOKAHEAD:
{
if (InformationBufferLength < sizeof(ULONG))
{
*BytesNeeded = sizeof(ULONG);
Status = NDIS_STATUS_INVALID_LENGTH;
break;
}
/* Nothing to do */
*BytesRead = sizeof(ULONG);
break;
}
case OID_PNP_ENABLE_WAKE_UP:
{
if (InformationBufferLength < sizeof(ULONG))
{
*BytesNeeded = sizeof(ULONG);
Status = NDIS_STATUS_INVALID_LENGTH;
break;
}
if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT))
{
return NDIS_STATUS_NOT_SUPPORTED;
}
*BytesRead = sizeof(ULONG);
NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
Adapter->WakeUpFlags = GenericUlong;
break;
}
case OID_PNP_ADD_WAKE_UP_PATTERN:
{
if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
{
*BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
Status = NDIS_STATUS_INVALID_LENGTH;
break;
}
if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT))
{
return NDIS_STATUS_NOT_SUPPORTED;
}
*BytesRead = sizeof(NDIS_PM_PACKET_PATTERN);
Status = DcAddWakeUpPattern(Adapter, InformationBuffer);
break;
}
case OID_PNP_REMOVE_WAKE_UP_PATTERN:
{
if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
{
*BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
Status = NDIS_STATUS_INVALID_LENGTH;
break;
}
if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT))
{
return NDIS_STATUS_NOT_SUPPORTED;
}
*BytesRead = sizeof(NDIS_PM_PACKET_PATTERN);
Status = DcRemoveWakeUpPattern(Adapter, InformationBuffer);
break;
}
case OID_PNP_SET_POWER:
{
if (InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE))
{
*BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE);
Status = NDIS_STATUS_INVALID_LENGTH;
break;
}
if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT))
{
return NDIS_STATUS_NOT_SUPPORTED;
}
*BytesRead = sizeof(ULONG);
NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
if (GenericUlong < NdisDeviceStateD0 || GenericUlong > NdisDeviceStateD3)
{
ASSERT(FALSE);
Status = NDIS_STATUS_INVALID_DATA;
break;
}
DcSetPower(Adapter, GenericUlong);
break;
}
default:
Status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
return Status;
}

View file

@ -0,0 +1,313 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Packet sending
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "dc21x4.h"
#include <debug.h>
/* FUNCTIONS ******************************************************************/
static
VOID
DcTransmitPacket(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PDC_TCB Tcb,
_In_ PSCATTER_GATHER_LIST SgList)
{
PDC_TBD Tbd, NextTbd, FirstTbd, LastTbd;
ULONG i, TbdStatus;
TbdStatus = 0;
Tbd = Adapter->CurrentTbd;
for (i = 0; i < SgList->NumberOfElements; ++i)
{
ULONG Address, Length;
LastTbd = Tbd;
/* Not owned by NIC */
ASSERT(!(((i % 2) == 0) && (Tbd->Status & DC_TBD_STATUS_OWNED)));
Tbd->Status = TbdStatus;
/* 32-bit DMA */
ASSERT(SgList->Elements[i].Address.HighPart == 0);
Address = SgList->Elements[i].Address.LowPart;
Length = SgList->Elements[i].Length;
/* Two data buffers per descriptor */
if ((i % 2) == 0)
{
Tbd->Control &= DC_TBD_CONTROL_END_OF_RING;
Tbd->Control |= Length;
Tbd->Address1 = Address;
NextTbd = DC_NEXT_TBD(Adapter, Tbd);
}
else
{
Tbd->Control |= Length << DC_TBD_CONTROL_LENGTH_2_SHIFT;
Tbd->Address2 = Address;
Tbd = NextTbd;
TbdStatus = DC_TBD_STATUS_OWNED;
}
}
/* Enable IRQ on last element */
LastTbd->Control |= DC_TBD_CONTROL_LAST_FRAGMENT | DC_TBD_CONTROL_REQUEST_INTERRUPT;
Tcb->Tbd = LastTbd;
FirstTbd = Adapter->CurrentTbd;
Adapter->CurrentTbd = NextTbd;
/* Not owned by NIC */
ASSERT(!(FirstTbd->Status & DC_TBD_STATUS_OWNED));
FirstTbd->Control |= DC_TBD_CONTROL_FIRST_FRAGMENT;
DC_WRITE_BARRIER();
FirstTbd->Status = DC_TBD_STATUS_OWNED;
}
static
BOOLEAN
DcCopyPacket(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PNDIS_PACKET Packet,
_In_ PDC_COALESCE_BUFFER Buffer)
{
PNDIS_BUFFER CurrentBuffer;
PVOID Address;
UINT CurrentLength, PacketLength;
PUCHAR Destination;
NdisGetFirstBufferFromPacketSafe(Packet,
&CurrentBuffer,
&Address,
&CurrentLength,
&PacketLength,
HighPagePriority);
if (!Address)
return FALSE;
Destination = Buffer->VirtualAddress;
while (TRUE)
{
NdisMoveMemory(Destination, Address, CurrentLength);
Destination += CurrentLength;
NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
if (!CurrentBuffer)
break;
NdisQueryBufferSafe(CurrentBuffer,
&Address,
&CurrentLength,
HighPagePriority);
if (!Address)
return FALSE;
}
return TRUE;
}
static
NDIS_STATUS
DcSendPacket(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ PNDIS_PACKET Packet)
{
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
PSCATTER_GATHER_LIST SgList;
PDC_TCB Tcb;
ULONG SlotsUsed;
if (!Adapter->TcbSlots)
return NDIS_STATUS_RESOURCES;
SgList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo);
if (SgList->NumberOfElements > DC_FRAGMENTATION_THRESHOLD)
{
PDC_COALESCE_BUFFER CoalesceBuffer;
UINT PacketLength;
if (!Adapter->TbdSlots || !Adapter->SendBufferList.Next)
{
return NDIS_STATUS_RESOURCES;
}
NdisQueryPacketLength(Packet, &PacketLength);
CoalesceBuffer = (PDC_COALESCE_BUFFER)PopEntryList(&Adapter->SendBufferList);
if (!DcCopyPacket(Adapter, Packet, CoalesceBuffer))
{
PushEntryList(&Adapter->SendBufferList, &CoalesceBuffer->ListEntry);
return NDIS_STATUS_RESOURCES;
}
SgList = &Adapter->LocalSgList;
SgList->Elements[0].Address.LowPart = CoalesceBuffer->PhysicalAddress;
SgList->Elements[0].Length = PacketLength;
SgList->NumberOfElements = 1;
SlotsUsed = 1;
Tcb = Adapter->CurrentTcb;
Tcb->SlotsUsed = 1;
Tcb->Buffer = CoalesceBuffer;
}
else
{
/* We use two data buffers per descriptor */
SlotsUsed = (SgList->NumberOfElements + 1) / 2;
if (SlotsUsed > Adapter->TbdSlots)
return NDIS_STATUS_RESOURCES;
Tcb = Adapter->CurrentTcb;
Tcb->SlotsUsed = SlotsUsed;
Tcb->Buffer = NULL;
}
--Adapter->TcbSlots;
Adapter->CurrentTcb = DC_NEXT_TCB(Adapter, Tcb);
Tcb->Packet = Packet;
ASSERT(Adapter->TbdSlots >= Tcb->SlotsUsed);
Adapter->TbdSlots -= SlotsUsed;
DcTransmitPacket(Adapter, Tcb, SgList);
DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL);
return NDIS_STATUS_PENDING;
}
VOID
DcProcessPendingPackets(
_In_ PDC21X4_ADAPTER Adapter)
{
PLIST_ENTRY Entry;
NDIS_STATUS Status;
PNDIS_PACKET Packet;
ASSERT(!IsListEmpty(&Adapter->SendQueueList));
do
{
Entry = RemoveHeadList(&Adapter->SendQueueList);
Packet = DC_PACKET_FROM_LIST_ENTRY(Entry);
Status = DcSendPacket(Adapter, Packet);
if (Status == NDIS_STATUS_RESOURCES)
{
InsertHeadList(&Adapter->SendQueueList, DC_LIST_ENTRY_FROM_PACKET(Packet));
break;
}
}
while (!IsListEmpty(&Adapter->SendQueueList));
}
VOID
NTAPI
DcSendPackets(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ PPNDIS_PACKET PacketArray,
_In_ UINT NumberOfPackets)
{
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
NDIS_STATUS Status;
ULONG i;
NdisAcquireSpinLock(&Adapter->SendLock);
if (!(Adapter->Flags & DC_ACTIVE))
{
NdisReleaseSpinLock(&Adapter->SendLock);
for (i = 0; i < NumberOfPackets; ++i)
{
NdisMSendComplete(Adapter->AdapterHandle,
PacketArray[i],
NDIS_STATUS_NOT_ACCEPTED);
}
return;
}
TRACE("Send packets %u\n", NumberOfPackets);
for (i = 0; i < NumberOfPackets; ++i)
{
PNDIS_PACKET Packet = PacketArray[i];
Status = DcSendPacket(Adapter, Packet);
if (Status == NDIS_STATUS_RESOURCES)
{
InsertTailList(&Adapter->SendQueueList, DC_LIST_ENTRY_FROM_PACKET(Packet));
}
}
NdisReleaseSpinLock(&Adapter->SendLock);
}
VOID
NTAPI
DcCancelSendPackets(
_In_ NDIS_HANDLE MiniportAdapterContext,
_In_ PVOID CancelId)
{
PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext;
LIST_ENTRY DoneList;
PLIST_ENTRY Entry, NextEntry;
TRACE("Called\n");
InitializeListHead(&DoneList);
NdisAcquireSpinLock(&Adapter->SendLock);
NextEntry = Adapter->SendQueueList.Flink;
while (NextEntry != &Adapter->SendQueueList)
{
PNDIS_PACKET Packet;
Entry = NextEntry;
NextEntry = NextEntry->Flink;
Packet = DC_PACKET_FROM_LIST_ENTRY(Entry);
if (NDIS_GET_PACKET_CANCEL_ID(Packet) == CancelId)
{
RemoveEntryList(DC_LIST_ENTRY_FROM_PACKET(Packet));
InsertTailList(&DoneList, DC_LIST_ENTRY_FROM_PACKET(Packet));
}
}
NdisReleaseSpinLock(&Adapter->SendLock);
while (!IsListEmpty(&DoneList))
{
Entry = RemoveHeadList(&DoneList);
NdisMSendComplete(Adapter->AdapterHandle,
DC_PACKET_FROM_LIST_ENTRY(Entry),
NDIS_STATUS_REQUEST_ABORTED);
}
}

View file

@ -0,0 +1,115 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Send and receive definitions
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
#define DC_LIST_ENTRY_FROM_PACKET(Packet) \
((PLIST_ENTRY)(&(Packet)->MiniportReservedEx[0]))
#define DC_PACKET_FROM_LIST_ENTRY(ListEntry) \
(CONTAINING_RECORD(ListEntry, NDIS_PACKET, MiniportReservedEx))
#define DC_RCB_FROM_PACKET(Packet) \
((PDC_RCB*)&(Packet)->MiniportReservedEx[0])
#define DC_RBD_FROM_PACKET(Packet) \
((PDC_RBD*)&(Packet)->MiniportReservedEx[sizeof(PVOID)])
typedef struct _DC_COALESCE_BUFFER
{
/* Must be the first entry */
SINGLE_LIST_ENTRY ListEntry;
PVOID VirtualAddress;
ULONG PhysicalAddress;
} DC_COALESCE_BUFFER, *PDC_COALESCE_BUFFER;
typedef struct _DC_TCB
{
PDC_TBD Tbd;
PNDIS_PACKET Packet;
PDC_COALESCE_BUFFER Buffer;
ULONG SlotsUsed;
} DC_TCB, *PDC_TCB;
typedef struct _DC_RCB
{
/* Must be the first entry */
SINGLE_LIST_ENTRY ListEntry;
ULONG PhysicalAddress;
ULONG Flags;
#define DC_RCB_FLAG_RECLAIM 0x80000000
PNDIS_PACKET Packet;
PNDIS_BUFFER NdisBuffer;
PVOID VirtualAddress;
PVOID VirtualAddressOriginal;
NDIS_PHYSICAL_ADDRESS PhysicalAddressOriginal;
SINGLE_LIST_ENTRY AllocListEntry;
} DC_RCB, *PDC_RCB;
FORCEINLINE
VOID
DC_RELEASE_TCB(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PDC_TCB Tcb)
{
if (Tcb->Buffer)
{
PushEntryList(&Adapter->SendBufferList, &Tcb->Buffer->ListEntry);
}
++Adapter->TcbSlots;
Adapter->TbdSlots += Tcb->SlotsUsed;
}
FORCEINLINE
PDC_TCB
DC_NEXT_TCB(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PDC_TCB Tcb)
{
if (Tcb++ == Adapter->TailTcb)
return Adapter->HeadTcb;
else
return Tcb;
}
FORCEINLINE
PDC_TBD
DC_NEXT_TBD(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PDC_TBD Tbd)
{
if (Tbd++ == Adapter->TailTbd)
return Adapter->HeadTbd;
else
return Tbd;
}
FORCEINLINE
PDC_RBD
DC_NEXT_RBD(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PDC_RBD Rbd)
{
if (Rbd++ == Adapter->TailRbd)
return Adapter->HeadRbd;
else
return Rbd;
}
FORCEINLINE
PDC_RCB*
DC_GET_RCB_SLOT(
_In_ PDC21X4_ADAPTER Adapter,
_In_ PDC_RBD Rbd)
{
return Adapter->RcbArray + (((ULONG_PTR)(Rbd - Adapter->HeadRbd)));
}

View file

@ -0,0 +1,84 @@
/*
* PROJECT: ReactOS DC21x4 Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Utility header file
* COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
#include <pshpack1.h>
typedef struct _ETH_HEADER
{
UCHAR Destination[ETH_LENGTH_OF_ADDRESS];
UCHAR Source[ETH_LENGTH_OF_ADDRESS];
USHORT PayloadType;
} ETH_HEADER, *PETH_HEADER;
#include <poppack.h>
#define ETH_IS_LOCALLY_ADMINISTERED(Address) \
((BOOLEAN)(((PUCHAR)(Address))[0] & ((UCHAR)0x02)))
#define ETH_IS_EMPTY(Address) \
((BOOLEAN)((((PUCHAR)(Address))[0] | ((PUCHAR)(Address))[1] | ((PUCHAR)(Address))[2] | \
((PUCHAR)(Address))[3] | ((PUCHAR)(Address))[4] | ((PUCHAR)(Address))[5]) == 0))
#if defined(_M_IX86) || defined(_M_AMD64)
/* Strict memory model, does not reorder Write-Write operations */
#define DC_WRITE_BARRIER() KeMemoryBarrierWithoutFence()
#else
#define DC_WRITE_BARRIER() KeMemoryBarrier()
#endif
#if defined(_MSC_VER)
/*
* Merge with PAGE, we don't need a new pageable section. For a small amount of data,
* there is additional size overhead if the actual data size is smaller than section alignment.
* GCC doesn't seem to appreciate this idea.
*/
#define DC_PG_DATA DATA_SEG("PAGE")
#else
#define DC_PG_DATA
#endif
/* Access to unaligned memory */
FORCEINLINE
USHORT
DcRetrieveWord(
_In_ const VOID* Data)
{
#if defined(_M_IX86) || defined(_M_AMD64)
/* Supported by ISA */
return *(const UNALIGNED USHORT*)Data;
#else
USHORT Result;
NdisMoveMemory(&Result, Data, sizeof(Result));
return Result;
#endif
}
#if DBG
#define DcPopEntryList PopEntryList
#else
/*
* This is an optimized version of the PopEntryList() function.
* We assume that the next entry has already been checked for nullability
* so we don't need to.
*/
FORCEINLINE
PSINGLE_LIST_ENTRY
DcPopEntryList(
_Inout_ PSINGLE_LIST_ENTRY ListHead)
{
PSINGLE_LIST_ENTRY FirstEntry;
FirstEntry = ListHead->Next;
ASSERT(FirstEntry);
ListHead->Next = FirstEntry->Next;
return FirstEntry;
}
#endif