// driver.cpp: implementation of the NIC_DRIVER_OBJECT class.
//
// Copyright (c) 2000-2007 Davicom Inc.  All rights reserved.
// 
//////////////////////////////////////////////////////////////////////

#include	"stdAfx.h"
#include	"exception.h"
#include	"mutex.h"
#include	"queue.h"
#include	"driver.h"
#include	"device.h"
#include	"ver.h"  // [package]

/****************************************************************************************
 *
 * Driver-wide global data declaration
 *
 ****************************************************************************************/

NDIS_OID gszNICSupportedOid[] = {
		OID_GEN_SUPPORTED_LIST,
        OID_GEN_HARDWARE_STATUS,
        OID_GEN_MEDIA_SUPPORTED,
        OID_GEN_MEDIA_IN_USE,
        OID_GEN_MEDIA_CONNECT_STATUS,
        OID_GEN_MAXIMUM_SEND_PACKETS,
        OID_GEN_VENDOR_DRIVER_VERSION,
        OID_GEN_MAXIMUM_LOOKAHEAD,
        OID_GEN_MAXIMUM_FRAME_SIZE,
        OID_GEN_MAXIMUM_TOTAL_SIZE,
        OID_GEN_MAC_OPTIONS,
        OID_GEN_PROTOCOL_OPTIONS,
        OID_GEN_LINK_SPEED,
        OID_GEN_TRANSMIT_BUFFER_SPACE,
        OID_GEN_RECEIVE_BUFFER_SPACE,
        OID_GEN_TRANSMIT_BLOCK_SIZE,
        OID_GEN_RECEIVE_BLOCK_SIZE,
        OID_GEN_VENDOR_ID,
        OID_GEN_VENDOR_DESCRIPTION,
        OID_GEN_CURRENT_PACKET_FILTER,
        OID_GEN_CURRENT_LOOKAHEAD,
        OID_GEN_DRIVER_VERSION,
        OID_GEN_XMIT_OK,
        OID_GEN_RCV_OK,
        OID_GEN_XMIT_ERROR,
        OID_GEN_RCV_ERROR,
        OID_GEN_RCV_NO_BUFFER,
        OID_GEN_RCV_CRC_ERROR,
        OID_802_3_PERMANENT_ADDRESS,
        OID_802_3_CURRENT_ADDRESS,
        OID_802_3_MULTICAST_LIST,
        OID_802_3_MAXIMUM_LIST_SIZE,
        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_XMIT_UNDERRUN,
        OID_802_3_XMIT_HEARTBEAT_FAILURE,
        OID_802_3_XMIT_TIMES_CRS_LOST,
        OID_802_3_XMIT_LATE_COLLISIONS,
    };

/********************************************************************************************
 *
 * NIC_DRIVER_OBJECT Implementation
 *
 ********************************************************************************************/

NIC_DRIVER_OBJECT::NIC_DRIVER_OBJECT(
	NDIS_HANDLE hMiniportAdapter,
	NDIS_HANDLE hWrapperConfigurationContext)
{
	m_hMiniportAdapter = hMiniportAdapter;
	m_hWrapperConfiguration = hWrapperConfigurationContext;
	
	m_fSystemHang = FALSE;
	m_fOutOfResources = FALSE;
	m_pLower = NULL;
}

NIC_DRIVER_OBJECT::~NIC_DRIVER_OBJECT()
{
}

NDIS_HANDLE	NIC_DRIVER_OBJECT::GetNdisMiniportAdapterHandle() 
{ 
	return m_hMiniportAdapter; 
}

NDIS_HANDLE	NIC_DRIVER_OBJECT::GetNdisWrapperConfigurationHandle() 
{ 
	return m_hWrapperConfiguration; 
}

U32	NIC_DRIVER_OBJECT::GetRecentInterruptStatus() 
{ 
	return m_uRecentInterruptStatus; 
}


void NIC_DRIVER_OBJECT::DriverStart(void)
{
	m_pLower->DeviceStart();
}

void NIC_DRIVER_OBJECT::MiniportInitialize(
		OUT PNDIS_STATUS OpenErrorStatus,
		OUT PUINT SelectedMediaIndex, 
		IN PNDIS_MEDIUM MediaArray, 
		IN UINT MediaArraySize)
{
	SETFNAME("NIC_DRIVER_OBJECT::MiniportInitialize");
//.	FUNCTION_ENTER_MSG();
	m_uRecentInterruptStatus = 0;
	
	if(!m_pLower)
		m_pLower = DeviceEntry(this,NULL);
		
	if(!m_pLower)
		THROW((ERR_STRING("NIC_DRIVER_OBJECT::MiniportInitialize - Error in creating device\r\n")));
	
	PRINTF(_T("==============================================\r\n"));
	PRINTF(_T("Davicom Semiconductor, Inc.\r\n"));
//	PRINTF(_T("Davicom Ethernet Device Driver.\r\n"));
//.	PRINTF(_T("----------------------------------------------\r\n"));
	PRINTF(_T("Package Version      : %s\r\n"),DAVICOM_NIC_PACKAGE_VERSION);
//.	PRINTF(_T("Package Release Date : %s\r\n"),DAVICOM_NIC_PACKAGE_RELEASE);
	PRINTF(_T("Driver Version       : %s\r\n"),m_pLower->GetDriverVersion());
//.	PRINTF(_T("Release Date         : %s\r\n"),m_pLower->GetReleaseDate());
	PRINTF(_T("==============================================\r\n"));	 	

	UINT i;

	// Determinate media type
	for(i=0; i<MediaArraySize; i++) 
		if(MediaArray[i] == NdisMedium802_3)
			break;

    if (i == MediaArraySize)
    	THROW((ERR_STRING("NIC_DRIVER_OBJECT::MiniportInitialize - Unsupported media\r\n"),NDIS_STATUS_UNSUPPORTED_MEDIA));
		

	*SelectedMediaIndex = i;

	// Read registry configurations
	m_pLower->InitialConfigurations(m_hWrapperConfiguration);
	m_pLower->DeviceRegisterAdapter();

	//(+)add by bill, 20070-12-11
	m_pLower->DeviceInitializeTimer();
	//(-)add by bill, 20070-12-11
	
	/* init tx buffers */
	U32		dwNumber,dwAddr;
	if(!(dwAddr = (U32)malloc(sizeof(DATA_BLOCK)*
		(dwNumber=m_pLower->m_szConfigures[CID_TXBUFFER_NUMBER]*2)))) 
		THROW((ERR_STRING("NIC_DRIVER_OBJECT::MiniportInitialize - Insufficient memory\r\n")));

	for(;dwNumber--;dwAddr+=sizeof(DATA_BLOCK))
		m_objTxQueue.Enqueue((PCQUEUE_GEN_HEADER)dwAddr);

	m_pLower->RegisterConfigurations();

	_RPT_STR( WSTR("@DriverStart@MiniportInitialize.\r\n") );
	DriverStart();

//.	FUNCTION_LEAVE_MSG();
}

PVOID NIC_DRIVER_OBJECT::DriverBindAddress(
	U32		uPhysicalAddress,
	U32		uLength)
{
	void	*pvoid;
	// allocate memory for the work space
	
    if(!(pvoid = VirtualAlloc(
		NULL, 
		uLength,
		MEM_RESERVE, 
		PAGE_NOACCESS))) return NULL;

	/* binding this virtual addr to physical location */
	VirtualCopy(
		pvoid,
		(PVOID)uPhysicalAddress,
		uLength,
		PAGE_READWRITE | PAGE_NOCACHE);

	return pvoid;
}


void NIC_DRIVER_OBJECT::DriverIndication(U32 uIndication)
{
	switch (uIndication)
	{
		case NIC_IND_TX_IDLE:
			if(m_fOutOfResources)
			{
				m_fOutOfResources = FALSE;
				NdisMSendResourcesAvailable(m_hMiniportAdapter);
			}
			break;
			
		case AID_ERROR:
		case AID_LARGE_INCOME_PACKET:
			m_fSystemHang = TRUE;
		default:
			break;
	} // of switch
	
}

void NIC_DRIVER_OBJECT::MiniportIsr(
		OUT PBOOLEAN InterruptRecognized, 
		OUT PBOOLEAN QueueInterrupt)	//U32 intstat;	
{
	m_pLower->DeviceDisableInterrupt();

	U32	intstat= m_uRecentInterruptStatus= m_pLower->DeviceGetInterruptStatus();
		/* clear it immediately */
		//m_pLower->DeviceSetInterruptStatus(
		//	m_uRecentInterruptStatus = intstat);

	if(intstat & MAKE_MASK4(3,2,1,0))
	{
		if (intstat & MAKE_MASK2(3,2))
		  DEBUG_PRINTF(TEXT("[GIGABIT:::Int RxOvrFlw Bit3~Bit2]%02XH\r\n"),intstat);
			
		*InterruptRecognized = TRUE;
		*QueueInterrupt = TRUE;
		m_pLower->DeviceEnableInterrupt();
		return;
	}

//	if (intstat & MAKE_MASK2(5,4))
//	{ 
		#ifdef	IMPL_DEVICE_ISR

		    //[Link-change::-->do it (==>DM9KS_LINK_INTR)]
			if (intstat & MAKE_MASK1(5)) {
				DEBUG_PRINTF(TEXT("[GIGABIT:::Int Bit5]%02XH\r\n"),m_uRecentInterruptStatus);
				m_pLower->DeviceIsr(intstat);
				*InterruptRecognized = TRUE;
				*QueueInterrupt = TRUE;
				m_pLower->DeviceEnableInterrupt();
				return;
			}
			if (intstat & MAKE_MASK1(4)) {
				DEBUG_PRINTF(TEXT("[GIGABIT:::Int Bit4]%02XH\r\n"),m_uRecentInterruptStatus);
				*InterruptRecognized = TRUE;
				*QueueInterrupt = TRUE;
				m_pLower->DeviceEnableInterrupt();
				return;
			}
		#endif

		DEBUG_PRINTF(TEXT("[GIGABIT:::Int NoBit]%02XH\r\n"),m_uRecentInterruptStatus);
		*InterruptRecognized = FALSE;
		*QueueInterrupt = FALSE;
		m_pLower->DeviceEnableInterrupt();
		return;
//	}
}

void NIC_DRIVER_OBJECT::MiniportInterruptHandler(void)
{
	m_pLower->DeviceInterruptEventHandler(m_uRecentInterruptStatus);
	m_pLower->DeviceEnableInterrupt();
}

#define	HANDLE_QUERY(event,ptr,len)	\
	case event: if(InfoBufferLength < (*BytesNeeded=len)) \
		{ status = NDIS_STATUS_INVALID_LENGTH; break; }	\
	panswer = (void*)(ptr); *BytesWritten = len; break;


NDIS_STATUS NIC_DRIVER_OBJECT::MiniportQueryInformation(
		IN NDIS_OID		Oid,
		IN PVOID		InfoBuffer, 
		IN ULONG		InfoBufferLength, 
		OUT PULONG		BytesWritten,
		OUT PULONG		BytesNeeded)
{
	NDIS_STATUS	status = NDIS_STATUS_SUCCESS;
	
	PVOID	panswer;
	U8		szbuffer[32];
	U32		tmp32;
	
	// pass to lower object, to see if it can handle this query,
	// if it can, return TRUE and set status.
	if(m_pLower->DeviceQueryInformation(
		&status,
		Oid,
		InfoBuffer,
		InfoBufferLength,
		BytesWritten,
		BytesNeeded)) return status;
		
	switch (Oid) {
		HANDLE_QUERY( OID_GEN_SUPPORTED_LIST,
			&gszNICSupportedOid,sizeof(gszNICSupportedOid));
			
		HANDLE_QUERY( OID_GEN_HARDWARE_STATUS,
			&m_pLower->m_szCurrentSettings[SID_HW_STATUS],sizeof(U32));
			
		HANDLE_QUERY( OID_GEN_MEDIA_IN_USE,
			&m_pLower->m_szCurrentSettings[SID_MEDIA_IN_USE],sizeof(U32));

		HANDLE_QUERY( OID_GEN_MEDIA_SUPPORTED,
			&m_pLower->m_szCurrentSettings[SID_MEDIA_SUPPORTED],sizeof(U32));
			
		HANDLE_QUERY( OID_GEN_MEDIA_CONNECT_STATUS,
			&m_pLower->m_szCurrentSettings[SID_MEDIA_CONNECTION_STATUS],sizeof(U32));

		HANDLE_QUERY( OID_GEN_MAXIMUM_LOOKAHEAD,
			&m_pLower->m_szCurrentSettings[SID_MAXIMUM_LOOKAHEAD],sizeof(U32));

		HANDLE_QUERY( OID_GEN_MAXIMUM_FRAME_SIZE,
 			&m_pLower->m_szCurrentSettings[SID_MAXIMUM_FRAME_SIZE],sizeof(U32));
       
		HANDLE_QUERY( OID_GEN_MAXIMUM_TOTAL_SIZE,
 			&m_pLower->m_szCurrentSettings[SID_MAXIMUM_TOTAL_SIZE],sizeof(U32));
        
		HANDLE_QUERY( OID_GEN_MAXIMUM_SEND_PACKETS,
 			&m_pLower->m_szCurrentSettings[SID_MAXIMUM_SEND_PACKETS],sizeof(U32));
        
		HANDLE_QUERY( OID_GEN_LINK_SPEED,
 			&m_pLower->m_szCurrentSettings[SID_LINK_SPEED],sizeof(U32));

		HANDLE_QUERY( OID_GEN_XMIT_OK,
			&m_pLower->m_szStatistics[TID_GEN_XMIT_OK],sizeof(U32));
		HANDLE_QUERY( OID_GEN_RCV_OK,
			&m_pLower->m_szStatistics[TID_GEN_RCV_OK],sizeof(U32));
		HANDLE_QUERY( OID_GEN_XMIT_ERROR,
			&m_pLower->m_szStatistics[TID_GEN_XMIT_ERROR],sizeof(U32));
		HANDLE_QUERY( OID_GEN_RCV_ERROR,
			&m_pLower->m_szStatistics[TID_GEN_RCV_ERROR],sizeof(U32));
		HANDLE_QUERY( OID_GEN_RCV_NO_BUFFER,
			&m_pLower->m_szStatistics[TID_GEN_RCV_NO_BUFFER],sizeof(U32));
		HANDLE_QUERY( OID_GEN_RCV_CRC_ERROR,
			&m_pLower->m_szStatistics[TID_GEN_RCV_CRC_ERROR],sizeof(U32));

		HANDLE_QUERY( OID_802_3_RCV_ERROR_ALIGNMENT,
			&m_pLower->m_szStatistics[TID_802_3_RCV_ERROR_ALIGNMENT],sizeof(U32));			
        HANDLE_QUERY( OID_802_3_RCV_OVERRUN,
			&m_pLower->m_szStatistics[TID_802_3_RCV_OVERRUN],sizeof(U32));
		HANDLE_QUERY( OID_802_3_XMIT_ONE_COLLISION,
			&m_pLower->m_szStatistics[TID_802_3_XMIT_ONE_COLLISION],sizeof(U32));
		HANDLE_QUERY( OID_802_3_XMIT_MORE_COLLISIONS,
			&m_pLower->m_szStatistics[TID_802_3_XMIT_MORE_COLLISIONS],sizeof(U32));
		HANDLE_QUERY( OID_802_3_XMIT_DEFERRED,
			&m_pLower->m_szStatistics[TID_802_3_XMIT_DEFERRED],sizeof(U32));
		HANDLE_QUERY( OID_802_3_XMIT_MAX_COLLISIONS,
			&m_pLower->m_szStatistics[TID_802_3_XMIT_MAX_COLLISIONS],sizeof(U32));
		HANDLE_QUERY( OID_802_3_XMIT_UNDERRUN,
			&m_pLower->m_szStatistics[TID_802_3_XMIT_UNDERRUN],sizeof(U32));
		HANDLE_QUERY( OID_802_3_XMIT_HEARTBEAT_FAILURE,
			&m_pLower->m_szStatistics[TID_802_3_XMIT_HEARTBEAT_FAILURE],sizeof(U32));
		HANDLE_QUERY( OID_802_3_XMIT_TIMES_CRS_LOST,
			&m_pLower->m_szStatistics[TID_802_3_XMIT_TIMES_CRS_LOST],sizeof(U32));
		HANDLE_QUERY( OID_802_3_XMIT_LATE_COLLISIONS,
			&m_pLower->m_szStatistics[TID_802_3_XMIT_LATE_COLLISIONS],sizeof(U32));


		HANDLE_QUERY( OID_GEN_MAC_OPTIONS,
 			&m_pLower->m_szCurrentSettings[SID_GEN_MAC_OPTIONS],sizeof(U32));

		HANDLE_QUERY( OID_802_3_PERMANENT_ADDRESS,
			m_pLower->GetMacAddress(&szbuffer[0]),ETH_ADDRESS_LENGTH);
		HANDLE_QUERY( OID_802_3_CURRENT_ADDRESS,
			m_pLower->GetMacAddress(&szbuffer[0]),ETH_ADDRESS_LENGTH);

		HANDLE_QUERY( OID_802_3_MAXIMUM_LIST_SIZE,
 			&m_pLower->m_szCurrentSettings[SID_802_3_MAXIMUM_LIST_SIZE],sizeof(U32));
    
		HANDLE_QUERY( OID_802_3_MULTICAST_LIST,
 			&m_pLower->m_szMulticastList[0][0],
 			m_pLower->m_nMulticasts*ETH_ADDRESS_LENGTH);

		HANDLE_QUERY( OID_GEN_CURRENT_PACKET_FILTER,
 			&m_pLower->m_szCurrentSettings[SID_GEN_CURRENT_PACKET_FILTER],sizeof(U32));

		HANDLE_QUERY( OID_GEN_TRANSMIT_BUFFER_SPACE,
 			&m_pLower->m_szCurrentSettings[SID_GEN_TRANSMIT_BUFFER_SPACE],sizeof(U32));
		HANDLE_QUERY( OID_GEN_RECEIVE_BUFFER_SPACE,
 			&m_pLower->m_szCurrentSettings[SID_GEN_RECEIVE_BUFFER_SPACE],sizeof(U32));

		HANDLE_QUERY( OID_GEN_TRANSMIT_BLOCK_SIZE,
 			&m_pLower->m_szCurrentSettings[SID_GEN_TRANSMIT_BLOCK_SIZE],sizeof(U32));
		HANDLE_QUERY( OID_GEN_RECEIVE_BLOCK_SIZE,
 			&m_pLower->m_szCurrentSettings[SID_GEN_RECEIVE_BLOCK_SIZE],sizeof(U32));
		
		HANDLE_QUERY( OID_GEN_VENDOR_ID,
 			(tmp32=(U32)m_pLower->GetVendorID(),&tmp32),sizeof(U32));
		
		HANDLE_QUERY( OID_GEN_VENDOR_DESCRIPTION,
 			VENDOR_DESC,strlen(VENDOR_DESC));
		
		HANDLE_QUERY( OID_GEN_CURRENT_LOOKAHEAD,
 			&m_pLower->m_szCurrentSettings[SID_GEN_CURRENT_LOOKAHEAD],sizeof(U32));
		HANDLE_QUERY( OID_GEN_DRIVER_VERSION,
 			&m_pLower->m_szCurrentSettings[SID_GEN_DRIVER_VERSION],sizeof(U32));
		HANDLE_QUERY( OID_GEN_VENDOR_DRIVER_VERSION,
 			&m_pLower->m_szCurrentSettings[SID_GEN_VENDOR_DRIVER_VERSION],sizeof(U32));
		HANDLE_QUERY( OID_GEN_PROTOCOL_OPTIONS,
 			&m_pLower->m_szCurrentSettings[SID_GEN_PROTOCOL_OPTIONS],sizeof(U32));
			
		default:
			status = NDIS_STATUS_INVALID_OID;
			break;
	} // of switch

	if(status == NDIS_STATUS_SUCCESS)
	{
		NdisMoveMemory(InfoBuffer,panswer,*BytesWritten);
	}

	return status;
}

//; 20080219
//; #define	HANDLE_SET(event,len)	\
//; 	case event: if(InfoBufferLength < (*BytesNeeded=len)) \
//; 		{ status = NDIS_STATUS_INVALID_LENGTH; break; }	\
//; 		*BytesRead = len; HANDLE_SET_##event(); break;

//; 20080219
//; #define	HANDLE_SET_OID_GEN_CURRENT_PACKET_FILTER()	\
//; 	m_pLower->_DeviceOnSetupFilter(*(U32*)InfoBuffer)

	
NDIS_STATUS NIC_DRIVER_OBJECT::MiniportSetInformation(
	IN NDIS_OID		Oid,
	IN PVOID		InfoBuffer, 
	IN ULONG		InfoBufferLength, 
	OUT PULONG		BytesRead,
	OUT PULONG		BytesNeeded)
{
	NDIS_STATUS	status = NDIS_STATUS_SUCCESS;

	// pass to lower object, to see if it can handle this request,
	// if it can, return TRUE and set status.
	if(m_pLower->DeviceSetInformation(
		&status,
		Oid,
		InfoBuffer,
		InfoBufferLength,
		BytesRead,
		BytesNeeded)) return status;

	switch (Oid)
	{
		
		//; 20080219
		//  HANDLE_SET( OID_GEN_CURRENT_PACKET_FILTER,sizeof(U32));
		//=
		case OID_GEN_CURRENT_PACKET_FILTER: 
			if(InfoBufferLength < (*BytesNeeded=sizeof(U32)))
			{ 
				status= NDIS_STATUS_INVALID_LENGTH; 
				break; 
			}	
			*BytesRead = sizeof(U32); 
			//HANDLE_SET_OID_GEN_CURRENT_PACKET_FILTER(); 
			//=
	_RPT_STR(_T("MiniportSetInformation:PACKET_FILTER: DeviceOnSetupFilter(0x%08X) \r\n"), *(U32*)InfoBuffer); // '+'
			   m_pLower->DeviceOnSetupFilter(*(U32*)InfoBuffer);
			break;
		
		case OID_802_3_MULTICAST_LIST:
			NdisMoveMemory(
				&m_pLower->m_szMulticastList[0][0],
				InfoBuffer,
				InfoBufferLength);

			m_pLower->m_nMulticasts = 
				InfoBufferLength / ETH_ADDRESS_LENGTH;

	_RPT_STR(_T("MiniportSetInformation:802_3_MULTICAST: DeviceOnSetupFilter(0x%08X) \r\n"),
				m_pLower->m_szCurrentSettings[SID_GEN_CURRENT_PACKET_FILTER]
				| NDIS_PACKET_TYPE_MULTICAST);
			m_pLower->DeviceOnSetupFilter(
				m_pLower->m_szCurrentSettings[SID_GEN_CURRENT_PACKET_FILTER]
				| NDIS_PACKET_TYPE_MULTICAST);
			break;

		// don't care oids
		case OID_GEN_CURRENT_LOOKAHEAD:
			break;

		case OID_GEN_NETWORK_LAYER_ADDRESSES:
		default:
			status = NDIS_STATUS_INVALID_OID;
		
	} // of switch Oid
	
	return status;
}

void NIC_DRIVER_OBJECT::MiniportEnableInterrupt(void)
{
	SETFNAME("NIC_DRIVER_OBJECT::MiniportEnableInterrupt()");
	FUNCTION_ENTER_MSG();
	m_pLower->DeviceEnableInterrupt();
	FUNCTION_LEAVE_MSG();
}

void NIC_DRIVER_OBJECT::MiniportDisableInterrupt(void)
{
	SETFNAME("NIC_DRIVER_OBJECT::MiniportDisableInterrupt()");
	FUNCTION_ENTER_MSG();
	m_pLower->DeviceDisableInterrupt();
	FUNCTION_LEAVE_MSG();
}

BOOL NIC_DRIVER_OBJECT::MiniportCheckForHang(void)
{
	if(m_fSystemHang) return TRUE;
	return m_pLower->DeviceCheckForHang();
}

VOID NIC_DRIVER_OBJECT::MiniportHalt(void)
{
	SETFNAME("NIC_DRIVER_OBJECT::MiniportHalt()");
	
	FUNCTION_ENTER_MSG();
	m_pLower->DeviceHalt();
	FUNCTION_LEAVE_MSG();
}

NDIS_STATUS NIC_DRIVER_OBJECT::MiniportReset(
	OUT PBOOLEAN	pbAddressingReset)
{
	SETFNAME("NIC_DRIVER_OBJECT::MiniportReset()");
	
	m_pLower->DbgDUMP_REGs(_T("MiniportReset.Start"));
	FUNCTION_ENTER_MSG();
	// Reset activities
	// 1. Abort all current tx and rx.
	// 2. Cleanup waiting and standby queues.
	// 3. Re-init tx and rx descriptors.
	// 4. Softreset MAC, PHY and set registers angain.

	*pbAddressingReset = TRUE;
#ifndef	IMPL_RESET
	return	NDIS_STATUS_SUCCESS;
#endif

	m_pLower->DeviceReset();
	
	FUNCTION_MDL_MSG("DriverStart="); //PRINTF(_T("MiniportReset.DriverStart==\r\n"));
	
	DriverStart();
	
	m_fSystemHang = FALSE;
	m_fOutOfResources = FALSE;

	m_pLower->DbgDUMP_REGs(_T("MiniportReset.Leave"));
	FUNCTION_LEAVE_MSG();
	return NDIS_STATUS_SUCCESS;
}

NDIS_STATUS	NIC_DRIVER_OBJECT::MiniportSend(
	IN PNDIS_PACKET	pPacket,
	IN UINT			uFlags)
{
	//SETFNAME("NIC_DRIVER_OBJECT::MiniportSend()");
	//FUNCTION_ENTER_MSG();

#if !defined(IMPL_TX_QUEUE)
	if(!m_pLower->DeviceQueryTxResources())
		return NDIS_STATUS_RESOURCES;
#endif

	
	PCQUEUE_GEN_HEADER	pobj;
	
	if(!(pobj = m_objTxQueue.Dequeue())) 
	{
		m_fOutOfResources = TRUE;
		DEBUG_PRINTF(TEXT("<NIC_DRIVER_OBJECT:m_fOutOfResources\n"));
		return NDIS_STATUS_RESOURCES;
	}
	
	PNDIS_BUFFER	pndisFirstBuffer;
	UINT			uPhysicalBufferCount;
	UINT			uBufferCount;
	UINT			uTotalPacketLength;

	PNDIS_BUFFER	pndisCurrBuffer;
	PU8		pcurr = (PU8)CQueueGetUserPointer(pobj);

	PVOID	ptrBuffer;
	UINT	nBuffer;
	U32		idx,check;

	//VOID NdisQueryPacket(
    //IN PNDIS_PACKET  Packet,
    //OUT PUINT  PhysicalBufferCount  (OPTIONAL),
    //OUT PUINT  BufferCount  (OPTIONAL),
    //OUT PNDIS_BUFFER  *FirstBuffer  (OPTIONAL),
    //OUT PUINT  TotalPacketLength  (OPTIONAL)
    //);
	NdisQueryPacket(
		pPacket, 
		&uPhysicalBufferCount, 
		&uBufferCount,
		&pndisFirstBuffer,
        &uTotalPacketLength);

    if (uTotalPacketLength > ETH_MAX_FRAME_SIZE) {
        return NDIS_STATUS_FAILURE;
    }

	uPhysicalBufferCount &= 0xFFFF;

	for(idx=0,check=0,pndisCurrBuffer=pndisFirstBuffer;
		idx < uBufferCount;
		idx++, pndisCurrBuffer = pndisCurrBuffer->Next)
	{
		NdisQueryBuffer(
			pndisCurrBuffer,
			&ptrBuffer,
			&nBuffer);

		if(!nBuffer) continue;
		
		NdisMoveMemory(pcurr, ptrBuffer, nBuffer);
		pcurr += nBuffer;
		check += nBuffer;
        
	} // of for gathering buffer

	if(uTotalPacketLength != check) return NDIS_STATUS_FAILURE;


	pobj->pPacket = (PVOID)pPacket;
	pobj->dwFlags = uFlags;
	pobj->usLength = uTotalPacketLength;	
	m_pLower->DeviceSend(pobj);
	
	//FUNCTION_LEAVE_MSG();
	
#ifdef	IMPL_SEND_INDICATION
	return NDIS_STATUS_PENDING;
#else
	return NDIS_STATUS_SUCCESS;
#endif
}

void NIC_DRIVER_OBJECT::DriverReceiveIndication(
	int		nCurr,
	PVOID	pVoid,
	int		nLength)
{
	NdisMEthIndicateReceive(
		m_hMiniportAdapter,
		(PNDIS_HANDLE)nCurr,
		(char*)pVoid,
		ETH_HEADER_SIZE,
		((char*)pVoid + ETH_HEADER_SIZE),
		nLength - ETH_HEADER_SIZE,
		nLength - ETH_HEADER_SIZE);
	
	NdisMEthIndicateReceiveComplete(m_hMiniportAdapter);
	return;
}
	
void NIC_DRIVER_OBJECT::DriverSendCompleted(PCQUEUE_GEN_HEADER	pObject)
{

	m_objTxQueue.Enqueue(pObject);
	
#ifdef	IMPL_SEND_INDICATION
	NdisMSendResourcesAvailable(m_hMiniportAdapter);
	NdisMSendComplete(m_hMiniportAdapter,(PNDIS_PACKET)(pObject->pPacket),NDIS_STATUS_SUCCESS);
#endif
}

BOOL NIC_DRIVER_OBJECT::DriverIsOutOfResource(void)
{
	return m_fOutOfResources;
}

int NIC_DRIVER_OBJECT::GetQueueSize()
{
	return m_objTxQueue.Size();
}
	

/********************************************************************************************
 *
 * Trunk Functions
 *
 ********************************************************************************************/

#ifdef	__cplusplus
extern "C" {	// miniport driver trunk functions
#endif


VOID MiniportISRHandler(
		OUT PBOOLEAN InterruptRecognized, 
		OUT PBOOLEAN QueueInterrupt,
		IN  NDIS_HANDLE MiniportContext)
{
	((NIC_DRIVER_OBJECT*)MiniportContext)->MiniportIsr(
		InterruptRecognized,
		QueueInterrupt);
}

VOID MiniportInterruptHandler(IN NDIS_HANDLE  MiniportContext)
{
	((NIC_DRIVER_OBJECT*)MiniportContext)->MiniportInterruptHandler();
}

NDIS_STATUS MiniportQueryInformation(
	IN NDIS_HANDLE	MiniportContext,
	IN NDIS_OID		Oid,
	IN PVOID		InfoBuffer, 
	IN ULONG		InfoBufferLength, 
	OUT PULONG		BytesWritten,
	OUT PULONG		BytesNeeded)
{
	return ((NIC_DRIVER_OBJECT*)MiniportContext)->MiniportQueryInformation(
			Oid,
			InfoBuffer, 
			InfoBufferLength, 
			BytesWritten,
			BytesNeeded);
}

NDIS_STATUS MiniportSetInformation(
	IN NDIS_HANDLE	MiniportContext, 
	IN NDIS_OID		Oid,
	IN PVOID		InfoBuffer, 
	IN ULONG		InfoBufferLength, 
	OUT PULONG		BytesRead,
	OUT PULONG		BytesNeeded)
{
	return ((NIC_DRIVER_OBJECT*)MiniportContext)->MiniportSetInformation(
			Oid,
			InfoBuffer, 
			InfoBufferLength, 
			BytesRead,
			BytesNeeded);
}

VOID MiniportEnableInterrupt(IN NDIS_HANDLE  MiniportContext)
{
	((NIC_DRIVER_OBJECT*)MiniportContext)->MiniportEnableInterrupt();
}

VOID MiniportDisableInterrupt(IN NDIS_HANDLE  MiniportContext)
{
	((NIC_DRIVER_OBJECT*)MiniportContext)->MiniportDisableInterrupt();
}

BOOLEAN	MiniportCheckForHang(IN NDIS_HANDLE  MiniportContext)
{
	return ((NIC_DRIVER_OBJECT*)MiniportContext)->MiniportCheckForHang();
}
 
VOID MiniportHalt(IN NDIS_HANDLE  MiniportContext)
{
	((NIC_DRIVER_OBJECT*)MiniportContext)->MiniportHalt();
}
 

NDIS_STATUS MiniportReset(
    OUT PBOOLEAN  AddressingReset,
    IN NDIS_HANDLE  MiniportContext)
{
	return ((NIC_DRIVER_OBJECT*)MiniportContext)->MiniportReset(AddressingReset);
}

NDIS_STATUS	MiniportSend(
	IN NDIS_HANDLE	MiniportContext,
	IN PNDIS_PACKET	Packet,
	IN UINT			Flags)
{
	return ((NIC_DRIVER_OBJECT*)MiniportContext)->MiniportSend(Packet,Flags);
}



#ifdef	__cplusplus   
}	// of miniport trunk functions
#endif
