#include	"stdAfx.h"
#include	"exception.h"
#include	"mutex.h"
#include	"queue.h"
#include	"driver.h"
#include	"usbdrv.h"
#include	"ver.h"


//==============================================================================
//#define	USBDRV_ENTRY_RELEASE				_T("2007-12-13 20:00")
//==============================================================================
#define USBDRV_DEVICE_NAME					_T("DM9USB")
#define USBD_LIBRARY_NAME					_T("USBD.DLL")
#define	USBD_REGISTER_CLIENT_DRIVER_ID		_T("RegisterClientDriverID")
#define	USBD_REGISTER_CLIENT_SETTINGS		_T("RegisterClientSettings")
#define	USBD_UN_REGISTER_CLIENT_DRIVER_ID	_T("UnRegisterClientDriverID")
#define	USBD_UN_REGISTER_CLIENT_SETTINGS	_T("UnRegisterClientSettings")


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

LPCWSTR				g_lpszDriverID = USBDRV_DEVICE_NAME; 
NDIS_HANDLE			g_hNdisIntermediateHandle=NULL;
UNICODE_STRING		g_strRegistryPath; 	
int					g_nInstance=0;

USB_HANDLE 			g_hDevice;
LPCUSB_FUNCS		g_lpUsbFuncs;
LPCUSB_DEVICE		g_lpUsbDevice;
LPCUSB_INTERFACE 	g_lpInterface;

extern "C" BOOL WINAPI	USBNotificationRoutine(
	LPVOID	lpNotifyParam,
	DWORD	dwCode,
	LPDWORD	pdw1,
	LPDWORD	pdw2,
	LPDWORD	pdw3,
	LPDWORD	pdw4)
{
	((NIC_DRIVER_USB*)lpNotifyParam)->DriverOnUsbNotify(dwCode);
	g_nInstance--;
	return TRUE;
}


extern "C" WORD GetUsbProductId();
extern "C" WORD GetUsbVendorId();
extern "C" WORD GetUsbReleaseNumber();
extern "C" void USBDriverSetting(USB_DRIVER_SETTINGS * pUsbDriverSettings);


extern "C" BOOL USBInstallDriver(LPCWSTR lpszDriverName)
{
	int		nRet;
	SETFNAME("USBInstallDriver\r\n");

	HINSTANCE hUsbdInstance = LoadLibrary(USBD_LIBRARY_NAME);
	LPREGISTER_CLIENT_DRIVER_ID pRegisterClientDriverID = NULL;
	LPREGISTER_CLIENT_SETTINGS pRegisterClientSettings = NULL;
	
	// register unique client driver identifier
	if (hUsbdInstance)
	{
		pRegisterClientDriverID =
			(LPREGISTER_CLIENT_DRIVER_ID) GetProcAddress(hUsbdInstance,USBD_REGISTER_CLIENT_DRIVER_ID);

		pRegisterClientSettings =
			(LPREGISTER_CLIENT_SETTINGS) GetProcAddress(hUsbdInstance,USBD_REGISTER_CLIENT_SETTINGS);
	}

	if (pRegisterClientDriverID == NULL || pRegisterClientSettings ==NULL)
	{
		DEBUG_PRINTF(_T("USBInstallDriver::Can't get the USBD function pointer.\r\n"));
		FUNCTION_LEAVE_MSG();			
		return FALSE;
	}

	nRet = pRegisterClientDriverID(g_lpszDriverID);
		
	// sets up the LoadClients registry keys
	USB_DRIVER_SETTINGS	usbDriverSettings;
	USBDriverSetting(&usbDriverSettings);
	
	nRet = pRegisterClientSettings(lpszDriverName, g_lpszDriverID, NULL, &usbDriverSettings);

	if (hUsbdInstance)
		FreeLibrary(hUsbdInstance);
	
	DEBUG_PRINTF(_T("USBInstallDriver:%d\n"), nRet);
	FUNCTION_LEAVE_MSG();
	if(!nRet) 
		return FALSE;
	return	TRUE;
}


extern "C" BOOL USBUnInstallDriver(void)
{
	SETFNAME("USBUnInstallDriver\r\n");
	BOOL fRet;

	USB_DRIVER_SETTINGS usbDriverSettings;
	HINSTANCE hUsbdInstance = LoadLibrary(USBD_LIBRARY_NAME);
	LPUN_REGISTER_CLIENT_DRIVER_ID pUnRegisterClientDriverID = NULL;
	LPUN_REGISTER_CLIENT_SETTINGS pUnRegisterClientSettings = NULL;
	
	FUNCTION_ENTER_MSG();
	if (hUsbdInstance)
	{
		pUnRegisterClientDriverID =
			(LPUN_REGISTER_CLIENT_DRIVER_ID) GetProcAddress(hUsbdInstance,USBD_UN_REGISTER_CLIENT_DRIVER_ID);

		pUnRegisterClientSettings =
			(LPUN_REGISTER_CLIENT_SETTINGS) GetProcAddress(hUsbdInstance,USBD_UN_REGISTER_CLIENT_SETTINGS);
	}	


	if (pUnRegisterClientDriverID == NULL || pUnRegisterClientSettings ==NULL)
	{
		DEBUG_PRINTF(_T("USBUnInstallDriver::Can't get the USBD function pointer.\r\n"));
		FUNCTION_LEAVE_MSG();		
		return FALSE;	
	}

	USBDriverSetting(&usbDriverSettings);

	fRet = pUnRegisterClientSettings( g_lpszDriverID, NULL, &usbDriverSettings);

	fRet = fRet & pUnRegisterClientDriverID( g_lpszDriverID );
	
	if (hUsbdInstance)
		FreeLibrary(hUsbdInstance);

	DEBUG_PRINTF(_T("USBUnInstallDriver:%d\n"), fRet);
	FUNCTION_LEAVE_MSG();
	return fRet;
}

extern "C" NTSTATUS PostDriverEntry(
	USB_HANDLE 				hDevice, 
	LPCUSB_FUNCS			lpUsbFuncs, 
	LPCUSB_DEVICE			lpUsbDevice,
	LPCUSB_INTERFACE 		lpInterface)
{
	if(!g_hNdisIntermediateHandle) return NDIS_STATUS_FAILURE;
	
	g_hDevice = hDevice;
	g_lpUsbFuncs = lpUsbFuncs;
	g_lpUsbDevice = lpUsbDevice;
	g_lpInterface = lpInterface;
	
	NDIS_STATUS		status;
	if((status = NdisIMInitializeDeviceInstanceEx(
		g_hNdisIntermediateHandle,
		&g_strRegistryPath,
		NULL
		) != NDIS_STATUS_SUCCESS))
	{
		return status;
	}
    return NDIS_STATUS_SUCCESS;
}


extern "C" BOOL USBDeviceAttach(
	USB_HANDLE 				hDevice, 
	LPCUSB_FUNCS			lpUsbFuncs, 
	LPCUSB_INTERFACE 		lpInterface, 
	LPCWSTR 				szUniqueDriverId, 
	LPBOOL 					fAcceptControl, 
	LPCUSB_DRIVER_SETTINGS 	lpDriverSettings, 
	DWORD 					dwUnused )
{

	*fAcceptControl = TRUE;

	LPCUSB_DEVICE		pusbdev;
	LPCUSB_INTERFACE	pusbif;
	
	// retrive device and interface information
	for(pusbif=lpInterface;!pusbif;)
	{
		if(!(pusbdev = lpUsbFuncs->lpGetDeviceInfo(hDevice)))
			return FALSE;
		if(!(pusbif = lpUsbFuncs->lpFindInterface(pusbdev,0,0)))
			return FALSE;
	} // of for pusbif
	
	// check vendor and product IDs
	if( (pusbdev->Descriptor.idVendor != GetUsbVendorId()) ||	
		(pusbdev->Descriptor.idProduct != GetUsbProductId())) 
		return FALSE;
	unsigned short	wsz[512];
	wsprintf(wsz,TEXT("%s%d"),szUniqueDriverId,++g_nInstance);

	NdisInitUnicodeString(&g_strRegistryPath, wsz);

	if(PostDriverEntry(hDevice,lpUsbFuncs,pusbdev,pusbif)
		!= NDIS_STATUS_SUCCESS) 
		return (*fAcceptControl=FALSE);

	return *fAcceptControl;
}

NDIS_STATUS MiniportInitialize(
	OUT PNDIS_STATUS OpenErrorStatus,
	OUT PUINT SelectedMediaIndex, 
	IN PNDIS_MEDIUM MediaArray, 
	IN UINT MediaArraySize,
    IN NDIS_HANDLE MiniportHandle, 
	IN NDIS_HANDLE WrapperConfigHandle)
{
	SETFNAME("DM9::MiniportIntialize()");
	FUNCTION_ENTER_MSG();

	NIC_DRIVER_USB	*pnic;

	if(!(pnic = new NIC_DRIVER_USB(
		MiniportHandle,

		WrapperConfigHandle,
		g_hDevice,
		g_lpUsbFuncs,
		g_lpUsbDevice,
		g_lpInterface)))
		return	NDIS_STATUS_FAILURE;

	g_lpUsbFuncs->lpRegisterNotificationRoutine(
		g_hDevice,
		(LPDEVICE_NOTIFY_ROUTINE)USBNotificationRoutine,
		(LPVOID)pnic);


	CException	*pexp;
	TRY
	{
		pnic->MiniportInitialize(
			OpenErrorStatus,
			SelectedMediaIndex, 
			MediaArray, 
			MediaArraySize);

		FI;
	}
	CATCH(pexp)
	{
		pexp->PrintErrorMessage();
		CLEAN(pexp);
		delete pnic;
		return NDIS_STATUS_FAILURE;
	}
	
	FUNCTION_LEAVE_MSG();
	return NDIS_STATUS_SUCCESS;
}

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

/********************************************************************************************
 *
 * DriverEntry
 *
 ********************************************************************************************/

extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath)
{
	NDIS_STATUS		status;
	NDIS_HANDLE		hwrapper;

	NDIS40_MINIPORT_CHARACTERISTICS	ndischar;

  //DEBUG_PRINTF(_T("\r\n"));
	DEBUG_PRINTF(_T("==============================================\r\n"));
	DEBUG_PRINTF(_T("Davicom Semiconductor, Inc.\r\n"));
  //DEBUG_PRINTF(_T("----------------------------------------------\r\n"));
	DEBUG_PRINTF(_T("Based USBDrv Version : %s\r\n"),DAVICOM_NIC_DRIVER_VERSION);
	DEBUG_PRINTF(_T("USBDrv Release Date   : %s\r\n"),DAVICOM_NIC_DRIVER_RELEASE);
	DEBUG_PRINTF(_T("==============================================\r\n"));	 	

	NdisMInitializeWrapper(&hwrapper, pDriverObject, pRegistryPath,	NULL);

	memset((void*)&ndischar,0,sizeof(ndischar));
    
    ndischar.Ndis30Chars.MajorNdisVersion = PRJ_NDIS_MAJOR_VERSION;
	ndischar.Ndis30Chars.MinorNdisVersion = PRJ_NDIS_MINOR_VERSION;
    
	ndischar.Ndis30Chars.InitializeHandler			= MiniportInitialize;
    ndischar.Ndis30Chars.ResetHandler				= MiniportReset;
    ndischar.Ndis30Chars.CheckForHangHandler		= MiniportCheckForHang;
    ndischar.Ndis30Chars.HaltHandler				= MiniportHalt;
    ndischar.Ndis30Chars.HandleInterruptHandler		= MiniportInterruptHandler;
    ndischar.Ndis30Chars.ISRHandler					= MiniportISRHandler;
    ndischar.Ndis30Chars.QueryInformationHandler	= MiniportQueryInformation;
    ndischar.Ndis30Chars.SetInformationHandler		= MiniportSetInformation;
    ndischar.Ndis30Chars.SendHandler				= MiniportSend;


	if((status = NdisIMRegisterLayeredMiniport(
		hwrapper,
		(PNDIS_MINIPORT_CHARACTERISTICS)&ndischar,
		sizeof(ndischar),
		&g_hNdisIntermediateHandle ) != NDIS_STATUS_SUCCESS))
	{
		NdisTerminateWrapper(hwrapper,NULL);
		return status;
	}

#ifndef	IMPL_DLL_ENTRY	
	INIT_EXCEPTION();
#endif

    return NDIS_STATUS_SUCCESS;
}


