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

#include	"dm9usb.h"

CONFIG_PARAMETER	g_szDm9UsbConfigParams[] =
{
	{ CID_CONNECTION_TYPE, -1, NDIS_STRING_CONST("ConnectionType") },
	{ CID_SLOT_NUMBER, -1, NDIS_STRING_CONST("SlotNumber")},
	{ CID_BUFFER_PHYSICAL_ADDRESS, 0, NDIS_STRING_CONST("BufferPhysicalAddress")},
	{ CID_TXBUFFER_NUMBER, 0x20, NDIS_STRING_CONST("XmitBuffer")},
	{ CID_RXBUFFER_NUMBER, 0x10, NDIS_STRING_CONST("RecvBuffer")},
	{ CID_ADAPTER_NUMBER, 0, NDIS_STRING_CONST("AdapterNumber")},
	{ CID_IO_BASE_ADDRESS, 0x300, NDIS_STRING_CONST("IoAddress")},
	{ CID_IO_RANGE, 0x10, NDIS_STRING_CONST("IoRange")},
	{ CID_IRQ_NUMBER, 3, NDIS_STRING_CONST("IrqNumber")},
	{ -1,-1,NULL}
};

/*******************************************************************************
 *
 * Device attributes and characteristics
 *
 ********************************************************************************/
PCONFIG_PARAMETER DM9USB::GetConfigureParameters(void)
{
	return (PCONFIG_PARAMETER)&g_szDm9UsbConfigParams[0];
}

DM9USB::DM9USB(NIC_DRIVER_OBJECT *pUpper,PVOID pVoid) 
		: NIC_DEVICE_OBJECT(pUpper,pVoid)
{
	m_uLastAddressPort = (U32)-1;
}



void DM9USB::InitialEepromFieldPosition(void)
{
	m_dwEepromFiledPosition[EID_MAC_ADDRESS] = 0;
	m_dwEepromFiledPosition[EID_VENDOR_ID] = 8;
	m_dwEepromFiledPosition[EID_PRODUCT_ID] = 10;
}

DWORD DM9USB::GetChipID(void) 
{ 
	DWORD	dwChipID;

	dwChipID = GetProductID()<<16;
	dwChipID |= GetVendorID();

	if (dwChipID == 0)	// Read from Register
	{
		dwChipID  = DeviceReadPort(0x28);
		dwChipID |= DeviceReadPort(0x29)<<8;
		dwChipID |= DeviceReadPort(0x2a)<<16;
		dwChipID |= DeviceReadPort(0x2b)<<24;
	}

	DEBUG_PRINTF(TEXT("GetChipID:: Chip signature is %08X\r\n"), dwChipID);
	return dwChipID;
}

void DM9USB::ValidateConfigurations(void)
{
	/* USB CHANGED */
	m_szConfigures[CID_TXBUFFER_NUMBER] = 30;
	m_szConfigures[CID_RXBUFFER_NUMBER] = 10;
	m_szConfigures[CID_INTERMEDIATE] = 1;
	m_szConfigures[CID_NEED_IO_SPACE] = 0;
	m_szConfigures[CID_NEED_INTERRUPT] = 0;

	m_szCurrentSettings[SID_LINK_SPEED] = 1000;
	
	m_szCurrentSettings[SID_GEN_TRANSMIT_BUFFER_SPACE] = 
		m_szConfigures[CID_TXBUFFER_NUMBER]
		* ETH_MAX_FRAME_SIZE;
	m_szCurrentSettings[SID_GEN_RECEIVE_BUFFER_SPACE] = 
		m_szConfigures[CID_RXBUFFER_NUMBER]
		* ETH_MAX_FRAME_SIZE;

	m_szConfigures[CID_CHECK_FOR_HANG_PERIOD] = 3;


	// set receive mode
	// <5> discard long packet
	// <4> discard CRC error packet
	// <0> rx enable
	m_szCurrentSettings[SID_OP_MODE] = MAKE_MASK3(5,4,0);

	m_szCurrentSettings[SID_802_3_MAXIMUM_LIST_SIZE] = DM9_MULTICAST_LIST;
}

void DM9USB::InitialUsbParameters(
	USB_HANDLE		hUsbHandle,
	LPCUSB_FUNCS	lpUsbFuncs,
	LPCUSB_INTERFACE lpUsbInterface)
{
	m_hUsbHandle = hUsbHandle;
	m_lpUsbFuncs = lpUsbFuncs;
	m_lpUsbInterface = lpUsbInterface;

	USB_ENDPOINT_DESCRIPTOR	const *pdesc;

	m_pipeIn = m_pipeOut = NULL;
	
	U32	n;
	for(n=0;
		(n<m_lpUsbInterface->Descriptor.bNumEndpoints);
		n++)
	{
		pdesc = &(m_lpUsbInterface->lpEndpoints[n].Descriptor);
		
		switch (pdesc->bmAttributes & USB_ENDPOINT_TYPE_MASK)
		{
			case USB_ENDPOINT_TYPE_BULK:
				if( !m_pipeIn &&
					USB_ENDPOINT_DIRECTION_IN(pdesc->bEndpointAddress))
				{
					m_pipeIn =
						(*m_lpUsbFuncs->lpOpenPipe)(m_hUsbHandle,pdesc);
					break;
				}
				
				if( !m_pipeOut &&
					USB_ENDPOINT_DIRECTION_OUT(pdesc->bEndpointAddress))
				{
					m_pipeOut =
						(*m_lpUsbFuncs->lpOpenPipe)(m_hUsbHandle,pdesc);
				}
				break;
#if IMPL_USB_INTERRUPT
			case USB_ENDPOINT_TYPE_INTERRUPT:
				if(m_pipeInt) break;
				m_pipeInt =
					(*m_lpUsbFuncs->lpOpenPipe)(m_hUsbHandle,pdesc);
				break;
#endif			
			default:
				// not supported endpoint type
				break;
		} // of switch endpoint type
	} // of open pipe loop

	if( !m_pipeIn || !m_pipeOut) 
		THROW((ERR_STRING("DM9USB::InitialUsbParameters - Cannot open pipe\r\n")));
}

/*******************************************************************************
 *
 * Device access routines
 *
 ********************************************************************************/
#define	ENTER_CRITICAL_SECTION
#define	LEAVE_CRITICAL_SECTION
#define	VALIDATE_ADDR_PORT(p)

DWORD DM9USB::DeviceWritePort(DWORD dwPort, DWORD dwValue)
{
	DWORD dwRet=dwValue;
	
	ENTER_CRITICAL_SECTION

	VALIDATE_ADDR_PORT(dwPort);

	USB_DEVICE_REQUEST	urb;
	
	urb.bmRequestType = USB_REQUEST_VENDOR;	
	urb.bRequest = 0x03;	// Write1_Register
	urb.wValue = (WORD)(dwValue & 0xFF);
	urb.wIndex = (WORD)(dwPort & 0xFF);
	urb.wLength = 0x00;
		
	USB_HANDLE	uhandle;
	uhandle = (*m_lpUsbFuncs->lpIssueVendorTransfer)(
		m_hUsbHandle,// USB device handle
		NULL,		// callback address
		NULL,		// callback parameter
		0,			// flags
		&urb,		// request header
		NULL,		// data buffer(if any)
		0);			// physical address
		
	if(!uhandle) return (DWORD)-1;
	
	U32	count,err;
	if(!(*m_lpUsbFuncs->lpGetTransferStatus)(uhandle,&count,&err) ||
		(err != 0) ) 
		dwRet = (DWORD)-1;
	
	(*m_lpUsbFuncs->lpCloseTransfer)(uhandle);
	return dwRet;
}

DWORD DM9USB::DeviceReadPort(DWORD uPort)
{
	U32	val=0;

	ENTER_CRITICAL_SECTION

	VALIDATE_ADDR_PORT(uPort);

	USB_DEVICE_REQUEST	urb;
	
	urb.bmRequestType = 
		USB_REQUEST_VENDOR | USB_REQUEST_DEVICE_TO_HOST;
	urb.bRequest = 0x00;	// Read_Register
	urb.wValue = 0;
	urb.wIndex = (WORD)(uPort & 0xFF);
	urb.wLength = sizeof(char);
		
	USB_HANDLE	uhandle;
	uhandle = (*m_lpUsbFuncs->lpIssueVendorTransfer)(
		m_hUsbHandle,	// USB device handle
		NULL,			// callback address
		NULL,			// callback parameter
		USB_IN_TRANSFER,// flags
		&urb,			// request header
		(PVOID)&val,	// data buffer(if any)
		0);				// physical address
		
	if(!uhandle) return (DWORD)-1;

	DWORD	count,err;
	if(!(*m_lpUsbFuncs->lpGetTransferStatus)(uhandle,&count,&err) ||
		(err != 0) ) 
	{
		BREAK; 
		val = (DWORD)-1;
	}

	(*m_lpUsbFuncs->lpCloseTransfer)(uhandle);

	LEAVE_CRITICAL_SECTION
	
	return (DWORD)val;
}

WORD DM9USB::DeviceReadEeprom(DWORD uWordAddress)
{
	U16		highbyte,lowbyte;
	
	// assign the register offset
	DeviceWritePort(DM9_EPADDR,uWordAddress);
	
	// issue EEPROM read command<2>
	DeviceWritePort(DM9_EPCNTL,MAKE_MASK(2));
	
	// wait until status bit<0> cleared
	DevicePolling(DM9_EPCNTL,MAKE_MASK(0),0x00);
	
	// stop command
	DeviceWritePort(DM9_EPCNTL,0);

	// retrive data
	lowbyte  = (WORD)DeviceReadPort(DM9_EPLOW);
	highbyte = (WORD)DeviceReadPort(DM9_EPHIGH);
	
	return MAKE_WORD(lowbyte,highbyte);
}

WORD DM9USB::DeviceWriteEeprom(DWORD uWordAddress,WORD	uValue)
{
	// assign the register offset
	DeviceWritePort(DM9_EPADDR,uWordAddress);

	// put data
	DeviceWritePort(DM9_EPLOW, LOW_BYTE(uValue));
	DeviceWritePort(DM9_EPHIGH,HIGH_BYTE(uValue));
		
	// issue EEPROM write enable<4> and write command<1>
	DeviceWritePort(DM9_EPCNTL,MAKE_MASK2(4,1));
	
	// wait until status bit<0> cleared
	DevicePolling(DM9_EPCNTL,MAKE_MASK(0),0x00);
	
	// stop command
	DeviceWritePort(DM9_EPCNTL,0);

	return uValue;
}

WORD DM9USB::DeviceReadPhy(DWORD dwPhyRegister, DWORD dwOffset)
{
	WORD		highbyte,lowbyte;
	
	// assign the phy register offset, 
	// internal phy(0x40) plus phy offset
	DeviceWritePort(DM9_EPADDR,(0x40|(dwOffset&0x3F)));
	
	// issue PHY select<3> and PHY read command<2>
	DeviceWritePort(DM9_EPCNTL,MAKE_MASK2(3,2));
	
	// wait until status bit<0> cleared
	DevicePolling(DM9_EPCNTL,MAKE_MASK(0),0x00);
	
	// stop command
	DeviceWritePort(DM9_EPCNTL,0);

	// retrive data
	lowbyte  = (WORD)DeviceReadPort(DM9_EPLOW);
	highbyte = (WORD)DeviceReadPort(DM9_EPHIGH);
	
	return MAKE_WORD(lowbyte,highbyte);
}

WORD DM9USB::DeviceWritePhy(DWORD dwPhyRegister, DWORD dwOffset, WORD wValue)
{
	// assign the phy register offset, 
	// internal phy(0x40) plus phy offset
	DeviceWritePort(DM9_EPADDR,(0x40|(dwOffset&0x3F)));

	// put data
	DeviceWritePort(DM9_EPLOW, LOW_BYTE(wValue));
	DeviceWritePort(DM9_EPHIGH,HIGH_BYTE(wValue));

	// issue PHY select<3> and write command<1>		
	DeviceWritePort(DM9_EPCNTL, MAKE_MASK2(3,1));
	
	// wait until status bit<0> cleared
	DevicePolling(DM9_EPCNTL,MAKE_MASK(0),0x00);
	
	// stop command
	DeviceWritePort(DM9_EPCNTL,0);

	return wValue;
}

DWORD DM9USB::DeviceReadData(void)
{
	DWORD value;

	return	*(PDWORD)DeviceReadData((PU8)&value,sizeof(value));
}

PBYTE DM9USB::DeviceReadData(PBYTE pbtBuffer, int nLength)
{
	USB_HANDLE	hUsbHandle;
	PBYTE		pbtRet=pbtBuffer;

	hUsbHandle = (*m_lpUsbFuncs->lpIssueBulkTransfer)(
		m_pipeIn,	// in pipe
		NULL,		// callback address
		NULL,		// callback parameter
		USB_IN_TRANSFER | USB_SHORT_TRANSFER_OK,	// flags
		nLength,	// buffer length
		pbtBuffer,	// data buffer
		0);			// physical address
		
	if(!hUsbHandle) 
		return NULL;
	
	U32	dwCount,dwError;
	if(!(*m_lpUsbFuncs->lpGetTransferStatus)(hUsbHandle,&dwCount,&dwError) || (dwError != 0) ) 
	{
		BREAK; 
		pbtRet = NULL;
	}

	(*m_lpUsbFuncs->lpCloseTransfer)(hUsbHandle);

	return pbtRet;
	
}

PBYTE DM9USB::DeviceWriteData(PBYTE pbtBuffer, int nLength)
{
	USB_HANDLE	hUsbHandle;
	PBYTE		pbtRet=pbtBuffer;

	hUsbHandle = (*m_lpUsbFuncs->lpIssueBulkTransfer)(
		m_pipeOut,	// out pipe
		NULL,		// callback address
		NULL,		// callback parameter
		USB_OUT_TRANSFER,	// flags
		nLength,	// buffer length
		pbtBuffer,	// data buffer
		0);			// physical address
		
	if(!hUsbHandle) 
		return NULL;
	
	DWORD dwCount,dwError;
	if(!(*m_lpUsbFuncs->lpGetTransferStatus)(hUsbHandle,&dwCount,&dwError) ||	(dwError != 0) ) 
		pbtRet = NULL;
	
	(*m_lpUsbFuncs->lpCloseTransfer)(hUsbHandle);

	return pbtRet;	
}

/********************************************************************************
 *
 * Devcie control routines
 *
 ********************************************************************************/

void DM9USB::DeviceEnableInterrupt(void)
{
}

void DM9USB::DeviceDisableInterrupt(void)
{
}

void DM9USB::DeviceEnableReceive(void)
{
	// RX enable RXCR<0>
	//(+)remove by bill, 20071211
	//if(m_szCurrentSettings[SID_OP_MODE] & MAKE_MASK(0)) return;
	//(-)remove by bill, 20071211
	
	//(+)bill, 20071211
	PRINTF(_T("DM9USB::DeviceEnableReceive\r\n"));
	// enable PROMISCUOUS mode for debug by bill.
	//m_szCurrentSettings[SID_OP_MODE] |= MAKE_MASK(0);
	m_szCurrentSettings[SID_OP_MODE] |= MAKE_MASK2(0,1);	
	//(-)bill, 20071211
		
	DeviceWritePort(DM9_RXCR,m_szCurrentSettings[SID_OP_MODE]);
	PRINTF(_T("[DM9USB: DM9_RXCR=%x\r\n"),DeviceReadPort(DM9_RXCR));
}

void 	DM9USB::DeviceDisableReceive(void)
{
	// RX enable RXCR<0>
	if(!(m_szCurrentSettings[SID_OP_MODE] & MAKE_MASK(0))) return;
		
	m_szCurrentSettings[SID_OP_MODE] &= ~MAKE_MASK(0);
		
	DeviceWritePort(DM9_RXCR,m_szCurrentSettings[SID_OP_MODE]);
}

U32	DM9USB::DeviceGetInterruptStatus(void)
{
	return 0;
}

U32	DM9USB::DeviceSetInterruptStatus(U32 uValue)
{
	return 0;
}

U32	DM9USB::DeviceGetReceiveStatus(void)
{
	U32	cr;

	cr = DeviceReadPort(DM9_ROCR);
	
	return ((cr>>7)&1)<<31 | (cr&0x7F);
}

void	DM9USB::DeviceStart(void)
{
	SETFNAME("DM9USB::DeviceStart()");
	FUNCTION_ENTER_MSG();
#ifdef	IMPL_FLOW_CONTROL	

	U32		val;

	// check full-duplex mode or not<3>
	val = DeviceReadPort(DM9_NCR);
	if( val & MAKE_MASK(3))
	{
		/* full duplex mode */
		val = DeviceReadPort(DM9_PAUSETH);
		DeviceWritePort(DM9_PAUSETH,(U8)val);
		
		// enable flow control<0>
		// enable pause packet<5>
		DeviceWritePort(DM9_FLOW,MAKE_MASK2(5,0));
	}
	else
	{
		/* non full duplex mode */
		val = DeviceReadPort(DM9_BACKTH);
		DeviceWritePort(DM9_BACKTH,(U8)val);

		// enable back pressure<half dumplex mode)<4,3>
		DeviceWritePort(DM9_FLOW,MAKE_MASK2(4,3));
	}
#endif

	// enable interrupt
	DeviceEnableInterrupt();

	DeviceEnableTransmit();

	DeviceEnableReceive();
	
	DeviceWritePort(DM9_RXCR,m_szCurrentSettings[SID_OP_MODE]);
	DeviceSetTimer(3000);
	FUNCTION_LEAVE_MSG();
}

void DM9USB::DeviceReset(void)
{
	SETFNAME("DM9USB::DeviceReset()");
	FUNCTION_ENTER_MSG();

	// announce shutdown
	m_fShutdown = TRUE;
	
	// wait until all activities are fi.
	m_mutexRxValidate.Lock();
	m_mutexTxValidate.Lock();
		
	
	CException	*pexp;
	
	TRY
	{
	
		InitialHardware(++m_nResetCounts);
	
		DeviceOnSetupFilter(0);
		
		FI;
	}
	CATCH(pexp){
		// nothing to do
		CLEAN(pexp);
	} // of catch

	// dequeue for all objects in waiting and standby queue
	PCQUEUE_GEN_HEADER	pcurr;
	for(;(pcurr=m_TQWaiting.Dequeue());)
		DeviceSendCompleted(pcurr);
	for(;(pcurr=m_TQStandby.Dequeue());)
		DeviceSendCompleted(pcurr);
		
	m_mutexRxValidate.Release();
	m_mutexTxValidate.Release();

	m_fShutdown = FALSE;
	FUNCTION_LEAVE_MSG();
}

WORD DM9USB::LinkState_Get_BMSR(int i){
	return GetLinkState();
}
WORD DM9USB::LinkState_Get_DSCSR(LPWSTR head, int i){
	return 0;
}
WORD DM9USB::LinkState_Get_DSCSR_EX(LPWSTR head, LPWSTR regname, int i){
	return 0;
}
WORD DM9USB::LinkState_Get_SCFG(LPWSTR head, int i){
	return 0;
}
	
void DM9USB::PrintMessageCtrl(WORD wLinkState){
}
BOOL DM9USB::LinkState_LinkUp(int i)
{
	BOOL Result;
	LPWSTR head= WSTR("Wait");
	LPWSTR modename= WSTR("Wait");
	LPWSTR linkname= WSTR("Wait");
	LARGE_INTEGER   TS, TE, TD; 
	WORD cnt;

	if (i==AUTO_MDIX_MODE){
		DeviceWritePhy(0, 20, 0x0000);      // 20.5|20.4=x0 Auto-MDIX mode
		NdisMSleep(uSec500);
	}
	
	cnt= 0;
	TD.QuadPart= 0;
	NdisGetCurrentSystemTime(&TS); //then = GetTimes();
	while (! (Result=(DeviceReadPort(DM9_NSR) & MAKE_MASK(6))) ){
		cnt++;
		NdisMSleep(mSec1); //NdisMSleep(mSec100); [* Wait 1ms *] [* Wait 100ms *]

		NdisGetCurrentSystemTime(&TE);
		TD.QuadPart = TE.QuadPart - TS.QuadPart;
		TD.QuadPart /= 10000;   // Convert to ms
		if (TD.QuadPart>2000)	/* 2sec */
			break;
	}
	if (Result)
	 _RPT_STR(_T("[%s].[%s].[%s -test %d]---[%dms].LinkUp \r\n"), head, modename, linkname, cnt, TD.QuadPart);
	else
	 _RPT_STR(_T("[%s].[%s].[%s -test %d]---[%dms].LinkDown \r\n"), head, modename, linkname, cnt, TD.QuadPart);
	return Result;
}
int DM9USB::LnkStat_GetLinkStatus(void){
	return 0;
}
void DM9USB::DbgDUMP_REGs(TCHAR *CFN){
	DEBUG_PRINTF(_T(" %s: "), CFN); /*DbgDumpChip();*/ _RPT_NextLine();
}

void DM9USB::InitialChip()
{

}

void DM9USB::InitialHardware(int nResetCounts)
{
	// reset member varialbes
	m_fTxSubmitted = FALSE;
	m_fTxPreloaded = FALSE;
	m_uLastAddressPort = (U32)-1;
	m_fShutdown = 0;
	m_fShutdownPending = 0;
	
	// software reset the device
	DeviceWritePort(DM9_NCR, 0x01);
	//(+)2007-12-11 Bill
	//NdisStallExecution(20);
	//DeviceWritePort(DM9_NCR, 0x00);
	while(DeviceReadPort(DM9_NCR)& 0x1);
	//(-)2007-12-11 Bill
	
	// activate internal phy
	// select GPIO 0<0>, set it to output
	DeviceWritePort(DM9_GPCR, (1<<0));
	// output zero to activate internal phy
	DeviceWritePort(DM9_GPR,  0x00);
	
	// clear TX status
	DeviceWritePort(DM9_NSR, 0x00);

	// Initial Chip for each driver
	InitialChip();

}

void	DM9USB::DeviceResetPHYceiver(void)
{
	return;
}

/********************************************************************************
 *
 * Devcie handler routines
 *
 ********************************************************************************/
#ifdef	IMPL_DEVICE_ISR
void	DM9USB::DeviceIsr(
	U32		uState)
{

}
#endif


int	DM9USB::DeviceOnSetupFilter(
	U32		uFilter)
{
	int		n;
	U8		sz[8];
	U32		hashval;
	U32		newmode;
	
	// save old op mode
	newmode = m_szCurrentSettings[SID_OP_MODE];
	// clear filter related bits,
	// pass all multicast<3> and promiscuous<1>
	newmode	&= ~MAKE_MASK2(3,1);

	// zero input means one reset request
	if(!(m_szCurrentSettings[SID_GEN_CURRENT_PACKET_FILTER]=uFilter)) 
	{
		
		/* 1. set unicast */
		// retrive node address
		GetMacAddress(&sz[0]);
		// set node address
		for(n=0;n<ETH_ADDRESS_LENGTH;n++)
			DeviceWritePort(DM9_PAR0+n,(U32)sz[n]);
			
		/* 2. clear multicast list and count */
		m_nMulticasts = 0;
		memset((void*)&m_szMulticastList,0,sizeof(m_szMulticastList));
		
		/* 3. clear hash table */
		// clear hash table
		memset((void*)(&sz[0]),0,sizeof(sz));
		for(n=0;n<sizeof(sz);n++)
			DeviceWritePort(DM9_MAR0+n,(U32)sz[n]);

		return uFilter;		
	}
	

	// if promiscuous mode<1> is requested,
	// just set this bit and return
	if( (uFilter & NDIS_PACKET_TYPE_PROMISCUOUS) )
	{
		// add promiscuous<1>
		newmode |= MAKE_MASK(1);
		DeviceWritePort(DM9_RXCR,m_szCurrentSettings[SID_OP_MODE]=newmode);
		return uFilter;
	}

	// if pass all multicast<3> is requested,
	if(uFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) newmode |= MAKE_MASK(3);

	// prepare new hash table
	memset((void*)(&sz[0]),0,sizeof(sz));
	
	// if broadcast, its hash value is known as 63.
	if(uFilter & NDIS_PACKET_TYPE_BROADCAST) sz[7] |= 0x80;

	if(uFilter & NDIS_PACKET_TYPE_MULTICAST)
		for(n=0;n<m_nMulticasts;n++)
		{
			hashval = DeviceCalculateCRC32(
				&m_szMulticastList[n][0],ETH_ADDRESS_LENGTH,FALSE) & 0x3f;
			sz[hashval/8] |= 1 << (hashval%8);
		} // of calculate hash table

	// submit the new hash table
	for(n=0;n<sizeof(sz);n++)
		DeviceWritePort(DM9_MAR0+n,(U32)sz[n]);
	
	DeviceWritePort(DM9_RXCR,m_szCurrentSettings[SID_OP_MODE]=newmode);

	return uFilter;
}



void DM9USB::DeviceInterruptEventHandler(
	U32	uValue)
{
	
	if(m_fShutdown || m_fShutdownPending) return;
	
	// check and do indications if rx available	
	Dm9LookupRxBuffers();
	
	// check and dequeue if tx comp-indication
	Dm9ValidateTxBuffers();
	
}

U32	DM9USB::DeviceHardwareStatus(void)
{
	U32		ret=0;

	// should also check link status here !

	return ret;
}

				
int	DM9USB::DeviceSend(
	PCQUEUE_GEN_HEADER	pObject)
{
	m_TQStandby.Enqueue(pObject);
	
	if(!m_fTxEnabled) return 0;
	
	Dm9ValidateTxBuffers();

	return 0;
}

int	DM9USB::Dm9ValidateTxBuffers(void)
{
	int		counts=0;
	
	//U32		val,status;
	DWORD		val;//,status;
	PCQUEUE_GEN_HEADER	pcurr;

	if(!m_mutexTxValidate.TryLock()) return 0;

	for(;!m_TQStandby.IsQueueEmpty();counts++)
	{
		if((val = DeviceReadPort(DM9_USBSTAT)) == (U32)-1) break;

		CHECK_SHUTDOWN();
		
		// TX buffer status: 
		// two packets in buffer<2>
		// one packet in buffer<1>
		// no packet in buffer<0>
		// quit if already two packets in buffer<2>
		//(+)2007-12-11 Bill
		//Original
		//if(val & MAKE_MASK(2)) break;
		//Modified
		if(val & MAKE_MASK(2)) 
		{
			PRINTF(_T("[dm9usb:out of TX FIFO\r\n"));
			break;
		}
		//(-)2007-12-11 Bill	
		pcurr = m_TQStandby.Dequeue();

		if (!((pcurr->usLength+2) & 0x3F))
			pcurr->usLength++;
		DeviceWriteData(
			(PU8)CQueueGetUserPointer(pcurr)-2,pcurr->usLength+2);
		
		DeviceSendCompleted(pcurr);			
		
	} // of for TQStandby not empty

	if(counts)	
		DeviceIndication(NIC_IND_TX_IDLE);

	m_mutexTxValidate.Release();

	REPORT(TID_GEN_XMIT_OK, counts);
	
	return 0;
}

#pragma pack(1)
typedef	struct _EP1_FORMAT
{
	U8		bStatus;
	U16		nLength;
	U8		pData[1];
} EP1_FORMAT, *PEP1_FORMAT;

#pragma pack()

int	DM9USB::Dm9LookupRxBuffers(void)
{
	int		counts=0;
	U8		szbuf[USB_BUFFER_SIZE];
	PEP1_FORMAT pbuf = (PEP1_FORMAT)&szbuf[0];


	if(!m_mutexRxValidate.TryLock()) return 0;

	// check EP1RDY 0xF2<5> to see data available or not
	U32	usbstat;
	for(;
		(usbstat=DeviceReadPort(DM9_USBSTAT)) != (U32)-1;
		)
	{
		if(!(usbstat & MAKE_MASK(5))) break;
		
		CHECK_SHUTDOWN();
		
		if(!DeviceReadData((PU8)pbuf,sizeof(szbuf)))
			break;

		// check status, as specified in DM9_RXSR,
		// the following bits are error
		// <3> PLE
		// <2> AE
		// <1> CE
		// <0> FOE
		if(pbuf->bStatus & MAKE_MASK4(3,2,1,0)) continue;
		
		DeviceReceiveIndication(
			0,
 			(PVOID)pbuf->pData,
 			pbuf->nLength-ETH_CRC_SIZE);
		
		counts++;
	} // of for EP1RDY loop

	REPORT(TID_GEN_RCV_OK, counts);
	
	m_mutexRxValidate.Release();

	return counts;
}

void DM9USB::DeviceOnTimer(void)
{
	//PRINTF(_T("DM9USB::DeviceOnTimer\r\n"));
	DeviceInterruptEventHandler(0);
	DeviceSetTimer(1);
}

void DM9USB::DeviceHalt(void)
{
	DeviceCancelTimer();
}

WORD DM9USB::GetLinkState()
{
	WORD wLinkState=0;
	wLinkState = DeviceReadPhy(0, 0x1);
	wLinkState = DeviceReadPhy(0, 0x1);
	DEBUG_PRINTF(TEXT("[9USB-]Link=%d\r\n"), (wLinkState&0x4));
	return wLinkState;
}

BOOL DM9USB::DeviceQueryTxResources(void)
{
	return TRUE;
}

