mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
b79fbe2333
The driver supports all nVidia chipset models from 2001 until 2010, starting from nForce. All NICs are compatible with x86 and amd64 devices only. Tested by Daniel Reimer on OG Xbox and by me on MCP board. CORE-15872 CORE-16216
298 lines
7.6 KiB
C
298 lines
7.6 KiB
C
/*
|
|
* PROJECT: ReactOS nVidia nForce Ethernet Controller Driver
|
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
|
* PURPOSE: Miniport driver entrypoint
|
|
* COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "nvnet.h"
|
|
|
|
#define NDEBUG
|
|
#include "debug.h"
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
CODE_SEG("INIT")
|
|
DRIVER_INITIALIZE DriverEntry;
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
CODE_SEG("PAGE")
|
|
VOID
|
|
NvNetFlushTransmitQueue(
|
|
_In_ PNVNET_ADAPTER Adapter,
|
|
_In_ NDIS_STATUS CompleteStatus)
|
|
{
|
|
PNVNET_TCB Tcb;
|
|
|
|
PAGED_CODE();
|
|
|
|
for (Tcb = Adapter->Send.LastTcb;
|
|
Tcb != Adapter->Send.CurrentTcb;
|
|
Tcb = NV_NEXT_TCB(Adapter, Tcb))
|
|
{
|
|
NdisMSendComplete(Adapter->AdapterHandle,
|
|
Tcb->Packet,
|
|
CompleteStatus);
|
|
|
|
NV_RELEASE_TCB(Adapter, Tcb);
|
|
}
|
|
}
|
|
|
|
DECLSPEC_NOINLINE /* Called from pageable code */
|
|
VOID
|
|
NvNetPauseProcessing(
|
|
_In_ PNVNET_ADAPTER Adapter)
|
|
{
|
|
NvNetDisableInterrupts(Adapter);
|
|
|
|
NdisAcquireSpinLock(&Adapter->Send.Lock);
|
|
Adapter->Flags &= ~NV_ACTIVE;
|
|
NdisReleaseSpinLock(&Adapter->Send.Lock);
|
|
}
|
|
|
|
CODE_SEG("PAGE")
|
|
VOID
|
|
NvNetStopAdapter(
|
|
_In_ PNVNET_ADAPTER Adapter)
|
|
{
|
|
BOOLEAN Dummy;
|
|
|
|
PAGED_CODE();
|
|
|
|
NdisMCancelTimer(&Adapter->MediaDetectionTimer, &Dummy);
|
|
|
|
NvNetDisableInterrupts(Adapter);
|
|
|
|
KeFlushQueuedDpcs();
|
|
}
|
|
|
|
CODE_SEG("PAGE")
|
|
VOID
|
|
NvNetStartAdapter(
|
|
_In_ PNVNET_ADAPTER Adapter)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NdisMSynchronizeWithInterrupt(&Adapter->Interrupt,
|
|
NvNetInitPhaseSynchronized,
|
|
Adapter);
|
|
|
|
/* Setup the link timer right after the NIC is initialized */
|
|
if (Adapter->Features & DEV_NEED_LINKTIMER)
|
|
{
|
|
NdisMSetPeriodicTimer(&Adapter->MediaDetectionTimer,
|
|
NVNET_MEDIA_DETECTION_INTERVAL);
|
|
}
|
|
}
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
VOID
|
|
NTAPI
|
|
NvNetResetWorker(
|
|
_In_ PNDIS_WORK_ITEM WorkItem,
|
|
_In_opt_ PVOID Context)
|
|
{
|
|
PNVNET_ADAPTER Adapter = Context;
|
|
|
|
PAGED_CODE();
|
|
|
|
NvNetStopAdapter(Adapter);
|
|
|
|
NvNetIdleTransmitter(Adapter, TRUE);
|
|
NvNetStopTransmitter(Adapter);
|
|
NvNetStopReceiver(Adapter);
|
|
NV_WRITE(Adapter, NvRegTxRxControl,
|
|
Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
|
|
NdisStallExecution(NV_TXRX_RESET_DELAY);
|
|
|
|
NvNetFlushTransmitQueue(Adapter, NDIS_STATUS_FAILURE);
|
|
|
|
NT_VERIFY(NvNetInitNIC(Adapter, FALSE) == NDIS_STATUS_SUCCESS);
|
|
|
|
NvNetStartAdapter(Adapter);
|
|
|
|
_InterlockedDecrement(&Adapter->ResetLock);
|
|
|
|
NdisMResetComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS, TRUE);
|
|
}
|
|
|
|
/* NDIS CALLBACKS *************************************************************/
|
|
|
|
static
|
|
BOOLEAN
|
|
NTAPI
|
|
MiniportCheckForHang(
|
|
_In_ NDIS_HANDLE MiniportAdapterContext)
|
|
{
|
|
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
|
|
|
|
NdisDprAcquireSpinLock(&Adapter->Send.Lock);
|
|
|
|
if (Adapter->Flags & NV_ACTIVE &&
|
|
Adapter->Send.TcbSlots < NVNET_TRANSMIT_BLOCKS)
|
|
{
|
|
if (++Adapter->Send.StuckCount > NVNET_TRANSMIT_HANG_THRESHOLD)
|
|
{
|
|
NDIS_DbgPrint(MAX_TRACE, ("Transmit timeout!\n"));
|
|
|
|
#if defined(SARCH_XBOX)
|
|
/* Apply a HACK to make XQEMU happy... */
|
|
NvNetDisableInterrupts(Adapter);
|
|
NvNetApplyInterruptMask(Adapter);
|
|
#endif
|
|
|
|
Adapter->Send.StuckCount = 0;
|
|
}
|
|
}
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->Send.Lock);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
VOID
|
|
NTAPI
|
|
MiniportHalt(
|
|
_In_ NDIS_HANDLE MiniportAdapterContext)
|
|
{
|
|
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
|
|
BOOLEAN IsActive = !!(Adapter->Flags & NV_ACTIVE);
|
|
|
|
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
|
|
|
|
PAGED_CODE();
|
|
|
|
if (IsActive)
|
|
{
|
|
NvNetPauseProcessing(Adapter);
|
|
}
|
|
|
|
NvNetStopAdapter(Adapter);
|
|
|
|
if (IsActive)
|
|
{
|
|
NvNetIdleTransmitter(Adapter, TRUE);
|
|
NvNetStopTransmitter(Adapter);
|
|
NvNetStopReceiver(Adapter);
|
|
NV_WRITE(Adapter, NvRegTxRxControl,
|
|
Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
|
|
NdisStallExecution(NV_TXRX_RESET_DELAY);
|
|
}
|
|
|
|
NvNetFlushTransmitQueue(Adapter, NDIS_STATUS_FAILURE);
|
|
|
|
NvNetToggleClockPowerGating(Adapter, TRUE);
|
|
|
|
NV_WRITE(Adapter, NvRegMacAddrA, Adapter->OriginalMacAddress[0]);
|
|
NV_WRITE(Adapter, NvRegMacAddrB, Adapter->OriginalMacAddress[1]);
|
|
NV_WRITE(Adapter, NvRegTransmitPoll,
|
|
NV_READ(Adapter, NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV);
|
|
|
|
SidebandUnitReleaseSemaphore(Adapter);
|
|
|
|
NvNetFreeAdapter(Adapter);
|
|
}
|
|
|
|
static
|
|
NDIS_STATUS
|
|
NTAPI
|
|
MiniportReset(
|
|
_Out_ PBOOLEAN AddressingReset,
|
|
_In_ NDIS_HANDLE MiniportAdapterContext)
|
|
{
|
|
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
|
|
|
|
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
|
|
|
|
if (_InterlockedCompareExchange(&Adapter->ResetLock, 1, 0))
|
|
{
|
|
return NDIS_STATUS_RESET_IN_PROGRESS;
|
|
}
|
|
|
|
NvNetPauseProcessing(Adapter);
|
|
|
|
NdisInitializeWorkItem(&Adapter->ResetWorkItem, NvNetResetWorker, Adapter);
|
|
NdisScheduleWorkItem(&Adapter->ResetWorkItem);
|
|
|
|
return NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
NTAPI
|
|
MiniportShutdown(
|
|
_In_ NDIS_HANDLE MiniportAdapterContext)
|
|
{
|
|
PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
|
|
|
|
NDIS_DbgPrint(MIN_TRACE, ("()\n"));
|
|
|
|
if (Adapter->Flags & NV_ACTIVE)
|
|
{
|
|
if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
|
|
{
|
|
NvNetPauseProcessing(Adapter);
|
|
}
|
|
|
|
NvNetIdleTransmitter(Adapter, TRUE);
|
|
NvNetStopTransmitter(Adapter);
|
|
NvNetStopReceiver(Adapter);
|
|
NV_WRITE(Adapter, NvRegTxRxControl,
|
|
Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
|
|
NdisStallExecution(NV_TXRX_RESET_DELAY);
|
|
|
|
SidebandUnitReleaseSemaphore(Adapter);
|
|
}
|
|
|
|
NvNetDisableInterrupts(Adapter);
|
|
|
|
NvNetSetPowerState(Adapter, NdisDeviceStateD3, 0);
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
NTSTATUS
|
|
NTAPI
|
|
DriverEntry(
|
|
_In_ PDRIVER_OBJECT DriverObject,
|
|
_In_ PUNICODE_STRING RegistryPath)
|
|
{
|
|
NDIS_HANDLE WrapperHandle;
|
|
NDIS_MINIPORT_CHARACTERISTICS Characteristics = { 0 };
|
|
NDIS_STATUS Status;
|
|
|
|
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 = MiniportCheckForHang;
|
|
Characteristics.HaltHandler = MiniportHalt;
|
|
Characteristics.HandleInterruptHandler = MiniportHandleInterrupt;
|
|
Characteristics.InitializeHandler = MiniportInitialize;
|
|
Characteristics.ISRHandler = MiniportISR;
|
|
Characteristics.QueryInformationHandler = MiniportQueryInformation;
|
|
Characteristics.ResetHandler = MiniportReset;
|
|
Characteristics.SendHandler = MiniportSend; /* TODO */
|
|
Characteristics.SetInformationHandler = MiniportSetInformation;
|
|
// Characteristics.ReturnPacketHandler = MiniportReturnPacket; /* TODO */
|
|
// Characteristics.SendPacketsHandler = MiniportSendPackets; /* TODO */
|
|
Characteristics.AdapterShutdownHandler = MiniportShutdown;
|
|
|
|
Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics));
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
NdisTerminateWrapper(WrapperHandle, NULL);
|
|
return Status;
|
|
}
|
|
|
|
return Status;
|
|
}
|