
#include "pch.h"
#pragma hdrstop
#include <ndis.h>


NDIS_STATUS
MPInitialize(
	OUT PNDIS_STATUS			OpenErrorStatus,
	OUT PUINT					SelectedMediumIndex,
	IN	PNDIS_MEDIUM			MediumArray,
	IN	UINT					MediumArraySize,
	IN	NDIS_HANDLE				MiniportAdapterHandle,
	IN	NDIS_HANDLE				WrapperConfigurationContext
	)

{
	UINT			i;
	PADAPT			pAdapt;
	NDIS_STATUS		Status = NDIS_STATUS_FAILURE;
	NDIS_MEDIUM     Medium;

	do
	{
	
		pAdapt = NdisIMGetDeviceContext(MiniportAdapterHandle);
		pAdapt->MiniportHandle = MiniportAdapterHandle;

		DBGPRINT(("==> Miniport Initialize: Adapt %p\n", pAdapt));

		Medium = pAdapt->Medium;

		if (Medium == NdisMediumWan)
		{
			Medium = NdisMedium802_3;
		}

		for (i = 0; i < MediumArraySize; i++)
		{
			if (MediumArray[i] == Medium)
			{
				*SelectedMediumIndex = i;
				break;
			}
		}

		if (i == MediumArraySize)
		{
			Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
			break;
		}

		NdisMSetAttributesEx(MiniportAdapterHandle,
 							pAdapt,
 							0,										// CheckForHangTimeInSeconds
 							NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT	|
								NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT|
								NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER |
								NDIS_ATTRIBUTE_DESERIALIZE |
								NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
 							0);
        pAdapt->LastIndicatedStatus = NDIS_STATUS_MEDIA_CONNECT;
		pAdapt->MPDeviceState = NdisDeviceStateD0;
		pAdapt->PTDeviceState = NdisDeviceStateD0;
		NdisAcquireSpinLock(&GlobalLock);

		pAdapt->Next = pAdaptList;
		pAdaptList = pAdapt;

		NdisReleaseSpinLock(&GlobalLock);
		(VOID)PtRegisterDevice();

		Status = NDIS_STATUS_SUCCESS;
	}
	while (FALSE);
	ASSERT(pAdapt->MiniportInitPending == TRUE);
	pAdapt->MiniportInitPending = FALSE;
	NdisSetEvent(&pAdapt->MiniportInitEvent);

	DBGPRINT(("<== Miniport Initialize: Adapt %p, Status %x\n", pAdapt, Status));

	return Status;
}


NDIS_STATUS
MPSend(
	IN	NDIS_HANDLE				MiniportAdapterContext,
	IN	PNDIS_PACKET			Packet,
	IN	UINT					Flags
	)
{
	PADAPT				pAdapt = (PADAPT)MiniportAdapterContext;
	NDIS_STATUS			Status;
	PNDIS_PACKET		MyPacket;
	PVOID				MediaSpecificInfo = NULL;
	ULONG				MediaSpecificInfoSize = 0;
	DbgPrint("%s","·¢ËÍÊý¾Ý MPSend");
#ifdef NDIS51
	{
		PNDIS_PACKET_STACK		pStack;
		BOOLEAN					Remaining;
		pStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
		if (Remaining)
		{
			ASSERT(pStack);

			NdisSend(&Status,
 					 pAdapt->BindingHandle,
 					 Packet);

			return(Status);
		}
	}
#endif // NDIS51

	NdisAllocatePacket(&Status,
					   &MyPacket,
					   pAdapt->SendPacketPoolHandle);
	if (Status == NDIS_STATUS_SUCCESS)
	{
		PSEND_RSVD			SendRsvd;
		SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
		SendRsvd->OriginalPkt = Packet;

		MyPacket->Private.Flags = Flags;
		MyPacket->Private.Head = Packet->Private.Head;
		MyPacket->Private.Tail = Packet->Private.Tail;

#ifdef WIN9X
		MyPacket->Private.ValidCounts = FALSE;
#endif
		NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),NDIS_OOB_DATA_FROM_PACKET(Packet),sizeof(NDIS_PACKET_OOB_DATA));

#ifndef WIN9X
		NdisIMCopySendPerPacketInfo(MyPacket, Packet);
#endif
		
		NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
											&MediaSpecificInfo,
											&MediaSpecificInfoSize);

		if (MediaSpecificInfo || MediaSpecificInfoSize)
		{
			NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
												MediaSpecificInfo,
												MediaSpecificInfoSize);
		}

		NdisSend(&Status,
				 pAdapt->BindingHandle,
				 MyPacket);


		if (Status != NDIS_STATUS_PENDING)
		{

#ifndef WIN9X
			NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
#endif
			NdisFreePacket(MyPacket);
		}
	}
	else
	{
	
	}

	return(Status);
}


VOID
MPSendPackets(
	IN	NDIS_HANDLE				MiniportAdapterContext,
	IN	PPNDIS_PACKET			PacketArray,
	IN	UINT					NumberOfPackets
	)
{
	PADAPT				pAdapt = (PADAPT)MiniportAdapterContext;
	NDIS_STATUS			Status;
	UINT				i;
	PVOID				MediaSpecificInfo = NULL;
	UINT				MediaSpecificInfoSize = 0;

	for (i = 0; i < NumberOfPackets; i++)
	{
		PNDIS_PACKET	Packet, MyPacket;

		Packet = PacketArray[i];

#ifdef NDIS51

		{
			PNDIS_PACKET_STACK		pStack;
			BOOLEAN					Remaining;
			pStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
			if (Remaining)
			{
				ASSERT(pStack);

				NdisSend(&Status,
 						 pAdapt->BindingHandle,
 						 Packet);
		
				if (Status != NDIS_STATUS_PENDING)
				{
					NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
  									  Packet,
  									  Status);
				}

				continue;
			}
		}
#endif

		NdisAllocatePacket(&Status,
						   &MyPacket,
						   pAdapt->SendPacketPoolHandle);

		if (Status == NDIS_STATUS_SUCCESS)
		{
			PSEND_RSVD		SendRsvd;

			SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
			SendRsvd->OriginalPkt = Packet;

			MyPacket->Private.Flags = NdisGetPacketFlags(Packet);

			MyPacket->Private.Head = Packet->Private.Head;
			MyPacket->Private.Tail = Packet->Private.Tail;
#ifdef WIN9X
			MyPacket->Private.ValidCounts = FALSE;
#endif // WIN9X
			NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
						   NDIS_OOB_DATA_FROM_PACKET(Packet),
						   sizeof(NDIS_PACKET_OOB_DATA));
#ifndef WIN9X
			NdisIMCopySendPerPacketInfo(MyPacket, Packet);
#endif

			NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
												&MediaSpecificInfo,
												&MediaSpecificInfoSize);

			if (MediaSpecificInfo || MediaSpecificInfoSize)
			{
				NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
													MediaSpecificInfo,
													MediaSpecificInfoSize);
			}

			NdisSend(&Status,
					 pAdapt->BindingHandle,
					 MyPacket);

			if (Status != NDIS_STATUS_PENDING)
			{
#ifndef WIN9X
				NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
#endif
				NdisFreePacket(MyPacket);
			}
		}

		if (Status != NDIS_STATUS_PENDING)
		{
			NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
							  Packet,
							  Status);
		}
	}
}


NDIS_STATUS
MPQueryInformation(
	IN	NDIS_HANDLE				MiniportAdapterContext,
	IN	NDIS_OID				Oid,
	IN	PVOID					InformationBuffer,
	IN	ULONG					InformationBufferLength,
	OUT PULONG					BytesWritten,
	OUT PULONG					BytesNeeded
	)
{
	PADAPT		pAdapt = (PADAPT)MiniportAdapterContext;
	NDIS_STATUS	Status = NDIS_STATUS_FAILURE;

	do
	{
		if (Oid == OID_PNP_QUERY_POWER)
		{
			Status = NDIS_STATUS_SUCCESS;
			break;
		}

		if (Oid == OID_GEN_SUPPORTED_GUIDS)
		{
		
			Status = NDIS_STATUS_NOT_SUPPORTED;
			break;
		}

		if (Oid == OID_TCP_TASK_OFFLOAD)
		{
	
		}

		if (pAdapt->MPDeviceState > NdisDeviceStateD0 || pAdapt->StandingBy == TRUE)
		{
			Status = NDIS_STATUS_FAILURE;
			break;
		}

		pAdapt->Request.RequestType = NdisRequestQueryInformation;
		pAdapt->Request.DATA.QUERY_INFORMATION.Oid = Oid;
		pAdapt->Request.DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
		pAdapt->Request.DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength;
		pAdapt->BytesNeeded = BytesNeeded;
		pAdapt->BytesReadOrWritten = BytesWritten;
		pAdapt->OutstandingRequests = TRUE;

		if (pAdapt->PTDeviceState > NdisDeviceStateD0)
		{
			pAdapt->QueuedRequest = TRUE;
			Status = NDIS_STATUS_PENDING;
			break;
		}

		NdisRequest(&Status,
					pAdapt->BindingHandle,
					&pAdapt->Request);


		if (Status != NDIS_STATUS_PENDING)
		{
			PtRequestComplete(pAdapt, &pAdapt->Request, Status);
			Status = NDIS_STATUS_PENDING;
		}

	} while (FALSE);

	return(Status);

}


VOID
MPQueryPNPCapabilities(
	IN OUT	PADAPT			pAdapt,
	OUT		PNDIS_STATUS	pStatus
	)
{
	PNDIS_PNP_CAPABILITIES			pPNPCapabilities;
	PNDIS_PM_WAKE_UP_CAPABILITIES	pPMstruct;

	if (pAdapt->Request.DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(NDIS_PNP_CAPABILITIES))
	{
		pPNPCapabilities = (PNDIS_PNP_CAPABILITIES)(pAdapt->Request.DATA.QUERY_INFORMATION.InformationBuffer);

		pPMstruct= & pPNPCapabilities->WakeUpCapabilities;
		pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
		pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified;
		pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
		*pAdapt->BytesReadOrWritten = sizeof(NDIS_PNP_CAPABILITIES);
		*pAdapt->BytesNeeded = 0;
		pAdapt->MPDeviceState = NdisDeviceStateD0;
		pAdapt->PTDeviceState = NdisDeviceStateD0;

		*pStatus = NDIS_STATUS_SUCCESS;
	}
	else
	{
		*pAdapt->BytesNeeded= sizeof(NDIS_PNP_CAPABILITIES);
		*pStatus = NDIS_STATUS_RESOURCES;
	}
}


NDIS_STATUS
MPSetInformation(
	IN	NDIS_HANDLE				MiniportAdapterContext,
	IN	NDIS_OID				Oid,
	IN	PVOID					InformationBuffer,
	IN	ULONG					InformationBufferLength,
	OUT PULONG					BytesRead,
	OUT PULONG					BytesNeeded
	)
{
	PADAPT		pAdapt = (PADAPT)MiniportAdapterContext;
	NDIS_STATUS	Status;

	Status = NDIS_STATUS_FAILURE;

	do
	{
		if (Oid == OID_PNP_SET_POWER)
		{
			MPProcessSetPowerOid(&Status, 
								 pAdapt, 
								 InformationBuffer, 
								 InformationBufferLength, 
								 BytesRead, 
								 BytesNeeded);
			break;

		}
		if (pAdapt->MPDeviceState > NdisDeviceStateD0 || pAdapt->StandingBy == TRUE)
		{
			Status = NDIS_STATUS_FAILURE;
			break;
		}
		pAdapt->Request.RequestType = NdisRequestSetInformation;
		pAdapt->Request.DATA.SET_INFORMATION.Oid = Oid;
		pAdapt->Request.DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
		pAdapt->Request.DATA.SET_INFORMATION.InformationBufferLength = InformationBufferLength;
		pAdapt->BytesNeeded = BytesNeeded;
		pAdapt->BytesReadOrWritten = BytesRead;
		pAdapt->OutstandingRequests = TRUE;
		if (pAdapt->PTDeviceState > NdisDeviceStateD0)
		{
			pAdapt->QueuedRequest = TRUE;
			Status = NDIS_STATUS_PENDING;
			break;
		}
		NdisRequest(&Status,
					pAdapt->BindingHandle,
					&pAdapt->Request);

		if (Status == NDIS_STATUS_SUCCESS)
		{
			*BytesRead = pAdapt->Request.DATA.SET_INFORMATION.BytesRead;
			*BytesNeeded = pAdapt->Request.DATA.SET_INFORMATION.BytesNeeded;
		}


		if (Status != NDIS_STATUS_PENDING)
		{
			pAdapt->OutstandingRequests = FALSE;
		}

	} while (FALSE);

	return(Status);
}


VOID
MPProcessSetPowerOid(
	IN OUT PNDIS_STATUS			pNdisStatus,
	IN  PADAPT					pAdapt,
	IN	PVOID					InformationBuffer,
	IN	ULONG					InformationBufferLength,
	OUT PULONG					BytesRead,
	OUT PULONG					BytesNeeded
	)
{

	
	NDIS_DEVICE_POWER_STATE NewDeviceState;

	DBGPRINT(("==>MPProcessSetPowerOid: Adapt %p\n", pAdapt)); 

	ASSERT (InformationBuffer != NULL);

	*pNdisStatus = NDIS_STATUS_FAILURE;

	do 
	{
		if (InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE))
		{
			*pNdisStatus = NDIS_STATUS_INVALID_LENGTH;
			break;
		}

		NewDeviceState = (*(PNDIS_DEVICE_POWER_STATE)InformationBuffer);

		if ((pAdapt->MPDeviceState > NdisDeviceStateD0) && (NewDeviceState != NdisDeviceStateD0))
		{
			ASSERT (!(pAdapt->MPDeviceState > NdisDeviceStateD0) && (NewDeviceState != NdisDeviceStateD0));

			*pNdisStatus = NDIS_STATUS_FAILURE;
			break;
		}	

		if (pAdapt->MPDeviceState == NdisDeviceStateD0 && NewDeviceState > NdisDeviceStateD0)
		{
			pAdapt->StandingBy = TRUE;
		}

		if (pAdapt->MPDeviceState > NdisDeviceStateD0 &&  NewDeviceState == NdisDeviceStateD0)
		{
			pAdapt->StandingBy = FALSE;
		}
		
		pAdapt->MPDeviceState = NewDeviceState;
		
		*pNdisStatus = NDIS_STATUS_SUCCESS;
	

	} while (FALSE);	
		
	if (*pNdisStatus == NDIS_STATUS_SUCCESS)
	{
      
        if (pAdapt->StandingBy == FALSE)
        {
          
            if (pAdapt->LastIndicatedStatus != pAdapt->LatestUnIndicateStatus)
            {
               NdisMIndicateStatus(pAdapt->MiniportHandle,
                                        pAdapt->LatestUnIndicateStatus,
                                        (PVOID)NULL,
                                        0);
               NdisMIndicateStatusComplete(pAdapt->MiniportHandle);
               pAdapt->LastIndicatedStatus = pAdapt->LatestUnIndicateStatus;
            }
        }
        else
        {
        
            pAdapt->LatestUnIndicateStatus = pAdapt->LastIndicatedStatus;
        }
		*BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
		*BytesNeeded = 0;
	}
	else
	{
		*BytesRead = 0;
		*BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE);
	}

	DBGPRINT(("<==MPProcessSetPowerOid: Adapt %p\n", pAdapt)); 
}


VOID
MPReturnPacket(
	IN	NDIS_HANDLE				MiniportAdapterContext,
	IN	PNDIS_PACKET			Packet
	)
{
	PADAPT			pAdapt = (PADAPT)MiniportAdapterContext;

#ifdef NDIS51
	if (NdisGetPoolFromPacket(Packet) != pAdapt->RecvPacketPoolHandle)
	{
		NdisReturnPackets(&Packet, 1);
	}
	else
#endif // NDIS51
	{

		PNDIS_PACKET	MyPacket;
		PRECV_RSVD		RecvRsvd;
	
		RecvRsvd = (PRECV_RSVD)(Packet->MiniportReserved);
		MyPacket = RecvRsvd->OriginalPkt;
	
		NdisFreePacket(Packet);
		NdisReturnPackets(&MyPacket, 1);
	}
}


NDIS_STATUS
MPTransferData(
	OUT PNDIS_PACKET			Packet,
	OUT PUINT					BytesTransferred,
	IN	NDIS_HANDLE				MiniportAdapterContext,
	IN	NDIS_HANDLE				MiniportReceiveContext,
	IN	UINT					ByteOffset,
	IN	UINT					BytesToTransfer
	)
{
	PADAPT		pAdapt = (PADAPT)MiniportAdapterContext;
	NDIS_STATUS	Status;

	if (IsIMDeviceStateOn(pAdapt) == FALSE)
	{
		return NDIS_STATUS_FAILURE;
	}

	NdisTransferData(&Status,
					 pAdapt->BindingHandle,
					 MiniportReceiveContext,
					 ByteOffset,
					 BytesToTransfer,
					 Packet,
					 BytesTransferred);

	return(Status);
}

VOID
MPHalt(
	IN	NDIS_HANDLE				MiniportAdapterContext
	)
{
	PADAPT			pAdapt = (PADAPT)MiniportAdapterContext;
	NDIS_STATUS		Status;
	PADAPT			*ppCursor;
	PADAPT			pPromoteAdapt = NULL;

	DBGPRINT(("==>MiniportHalt: Adapt %p\n", pAdapt));
	NdisAcquireSpinLock(&GlobalLock);

	for (ppCursor = &pAdaptList; *ppCursor != NULL; ppCursor = &(*ppCursor)->Next)
	{
		if (*ppCursor == pAdapt)
		{
			*ppCursor = pAdapt->Next;
			break;
		}
	}

	NdisReleaseSpinLock(&GlobalLock);

	(VOID)PtDeregisterDevice();
	if (pAdapt->BindingHandle != NULL)
	{
		NdisResetEvent(&pAdapt->Event);

		NdisCloseAdapter(&Status, pAdapt->BindingHandle);

		if (Status == NDIS_STATUS_PENDING)
		{
			NdisWaitEvent(&pAdapt->Event, 0);
			Status = pAdapt->Status;
		}

		ASSERT (Status == NDIS_STATUS_SUCCESS);

		pAdapt->BindingHandle = NULL;
	}


	MPFreeAllPacketPools (pAdapt);

	NdisFreeMemory(pAdapt, sizeof(ADAPT), 0);

	DBGPRINT(("<== MiniportHalt: pAdapt %p\n", pAdapt));
}


NDIS_STATUS
MPReset(
	OUT PBOOLEAN				AddressingReset,
	IN	NDIS_HANDLE				MiniportAdapterContext
	)
{
	PADAPT	pAdapt = (PADAPT)MiniportAdapterContext;

	*AddressingReset = FALSE;

	return(NDIS_STATUS_SUCCESS);
}


#ifdef NDIS51_MINIPORT

VOID
MPCancelSendPackets(
	IN	NDIS_HANDLE			MiniportAdapterContext,
	IN	PVOID				CancelId
	)
{
	PADAPT	pAdapt = (PADAPT)MiniportAdapterContext;
	NdisCancelSendPackets(pAdapt->BindingHandle, CancelId);

	return;
}

VOID
MPDevicePnPEvent(
	IN NDIS_HANDLE				MiniportAdapterContext,
	IN NDIS_DEVICE_PNP_EVENT	DevicePnPEvent,
	IN PVOID					InformationBuffer,
	IN ULONG					InformationBufferLength
	)
{
	return;
}

VOID
MPAdapterShutdown(
	IN NDIS_HANDLE				MiniportAdapterContext
	)
{
	return;
}

#endif


VOID
MPFreeAllPacketPools(
	PADAPT					pAdapt
	)
{
	if (pAdapt->RecvPacketPoolHandle != NULL)
	{
		NdisFreePacketPool(pAdapt->RecvPacketPoolHandle);

		pAdapt->RecvPacketPoolHandle = NULL;
	}

	if (pAdapt->SendPacketPoolHandle != NULL)
	{


		NdisFreePacketPool(pAdapt->SendPacketPoolHandle);

		pAdapt->SendPacketPoolHandle = NULL;

	}
}

