#include <basedef.h>
#include <vmm.h>
#include <debug.h>
#include <vmmreg.h>
#include <vxdwraps.h>
#include <configmg.h>
#include <driver.h>
#include <mmdevldr.h>
#include "viwd.h"

static char *cpy = "Copyright 1995 Advanced Micro Devices, Inc. All rights reserved.";

#pragma CM_PAGEABLE_DATA

#pragma CM_PAGEABLE_CODE

#pragma warning (disable:4100)	// Parameter unused
CMCONFIG theConfig;
char DeviceID[80];
extern INTERWAVEINFO gIWI;
extern IWRESOURCEINFO gIW_ResTbl[];
void VIWD_Init_Logical_Device();
void VIWD_Uninit_Logical_Device();

/****************************************************************************
 *
 *	ConfigHandler - Handler of the config manager config call
 *
 *	Exported.
 *
 *	ENTRY:	Standard config handler.
 *
 *	EXIT:	Standard config manager return value.
 *
 ***************************************************************************/
CONFIGRET CM_HANDLER
ConfigHandler(CONFIGFUNC cfFuncName, SUBCONFIGFUNC scfSubFuncName, DEVNODE dnToDevNode, DWORD dwRefData, ULONG ulFlags)
{        
    DWORD	dw;
    int x;
    
	switch (cfFuncName) {

		case CONFIG_START:

                        // CM_Get_Device_Driver_Private_DWord(dnToDevNode, &dw, 0);
                        DeviceID[0] = (char)dwRefData + '0';
			// You may or may not treat CONFIG_START_FIRST_START
			// different from CONFIG_START_DYNAMIC_START.
                        
                        CM_Get_Alloc_Log_Conf(&theConfig,dnToDevNode,0);
                        switch (dwRefData) {
				case 0:		// Audio Device
					gIWI.iwi_bIRQ1 = theConfig.bIRQRegisters[0];
					gIW_ResTbl[0].iwri_dwResourceID = gIWI.iwi_bIRQ1;
					gIWI.iwi_bIRQ2 = theConfig.bIRQRegisters[1];
					gIW_ResTbl[1].iwri_dwResourceID = gIWI.iwi_bIRQ2;
					gIWI.iwi_bDMA1 = theConfig.bDMALst[0];
					gIW_ResTbl[2].iwri_dwResourceID = gIWI.iwi_bDMA1;
					gIWI.iwi_bDMA2 = theConfig.bDMALst[1];
					gIW_ResTbl[3].iwri_dwResourceID = gIWI.iwi_bDMA2;

					gIWI.iwi_wSynthBase2X = theConfig.wIOPortBase[0];
					gIWI.iwi_wSynthBase3X = theConfig.wIOPortBase[1];
					gIWI.iwi_wCodecBase = theConfig.wIOPortBase[2];

					if (gIWI.iwi_bIRQ1==4 || gIWI.iwi_bIRQ2==4 ||
					    gIWI.iwi_bIRQ1==10 || gIWI.iwi_bIRQ2==10) {
					    if (gIWI.iwi_wSynthBase3X) {
						_asm {
						    mov dx,gIWI.iwi_wSynthBase3X
						    add dx,3
						    mov al,60h
						    out dx,al
						    mov dx,gIWI.iwi_wSynthBase3X
						    add dx,5
						    in  al,dx
						    and al,7fh
						    out dx,al
						}
					    }
					}

                                        if (theConfig.wNumIRQs == 1 || gIWI.iwi_bIRQ1==gIWI.iwi_bIRQ2) {
					    gIW_ResTbl[1].iwri_wStatus |= IWRIS_OTHER;
					}

                                        if (theConfig.wNumDMAs == 1 || gIWI.iwi_bDMA1==gIWI.iwi_bDMA2) {
					    gIW_ResTbl[3].iwri_wStatus |= IWRIS_OTHER;
					}

					_asm  mov	eax,0
                                        _asm  call	VIWD_Init_Logical_Device
                                        gIWI.iwi_bDeviceInit |= IWINFO_DEV0_INIT;
					break;
				case 3:		// Adlib Device
                                        if (gIWI.iwi_bDeviceInit & IWINFO_DEV3_INIT) {
                                            gIWI.iwi_bDeviceInit |= IWINFO_DEV_RECONFIG;
                                            _asm  mov       eax,3
                                            _asm  call      VIWD_Uninit_Logical_Device
                                        }
					gIWI.iwi_wAdlibBase = theConfig.wIOPortBase[0];
					gIWI.iwi_bSBIRQ = theConfig.bIRQRegisters[0];
					_asm  mov	eax,3
					_asm  call	VIWD_Init_Logical_Device
                                        gIWI.iwi_bDeviceInit |= IWINFO_DEV3_INIT;
					break;
				case 4:		// MPU401 Device
                                        if (gIWI.iwi_bDeviceInit & IWINFO_DEV4_INIT) {
                                            gIWI.iwi_bDeviceInit |= IWINFO_DEV_RECONFIG;
                                            _asm  mov       eax,4
                                            _asm  call      VIWD_Uninit_Logical_Device
                                        }
					gIWI.iwi_wMPUBase = theConfig.wIOPortBase[0];
					gIWI.iwi_bMPUIRQ = theConfig.bIRQRegisters[0];
					_asm  mov	eax,4
					_asm  call	VIWD_Init_Logical_Device
                                        gIWI.iwi_bDeviceInit |= IWINFO_DEV4_INIT;
					break;
                        }
			// As far as CM goes, the first time it would
			// have called with CONFIG_START_DYNAMIC_START, 
			// it will call with CONFIG_START_FIRST_START
			// instead.

			return(CR_SUCCESS);

		case CONFIG_TEST:
                        switch (dwRefData) {
			    case 0:		// Audio Device
			    case 3:		// Adlib Device
			    case 4:		// MPU401 Device
                                for(x=0;x<16;x++){
				    if(gIW_ResTbl[x].iwri_dwCurOwner){
		                        return(CR_FAILURE);
				    }
				}
	                        return(CR_SUCCESS);
                        }
                        return(CR_FAILURE);

		case CONFIG_STOP:
                        switch (dwRefData) {
			    case 0:		// Audio Device
                                gIWI.iwi_bDeviceInit &= ~IWINFO_DEV0_INIT;
				gIWI.iwi_bDeviceInit |= IWINFO_DEV_RECONFIG;
				_asm  mov	eax,0
                                _asm  call	VIWD_Uninit_Logical_Device
                                break;
			    case 3:		// Adlib Device
                                gIWI.iwi_bDeviceInit &= ~IWINFO_DEV3_INIT;
				gIWI.iwi_bDeviceInit |= IWINFO_DEV_RECONFIG;
				_asm  mov	eax,3
                                _asm  call	VIWD_Uninit_Logical_Device
                                break;
			    case 4:		// MPU401 Device
                                gIWI.iwi_bDeviceInit &= ~IWINFO_DEV4_INIT;
				gIWI.iwi_bDeviceInit |= IWINFO_DEV_RECONFIG;
				_asm  mov	eax,4
                                _asm  call	VIWD_Uninit_Logical_Device
                                break;
                        }
			return(CR_SUCCESS);

                case CONFIG_REMOVE:
			// deallocate per instance data.

                        return(CR_SUCCESS);

		default:
			return(CR_DEFAULT);
	}
}
        
        
        
#pragma warning (default:4100)		// Parameter unused

/****************************************************************************
 *
 *	NewDriver - Register a new driver for the new devnode
 *
 *	Exported.
 *
 *	ENTRY:	DevNode is the new devnode that has just been created.
 *
 *	EXIT:	Standard config manager return value.
 *   7
 ***************************************************************************/
CONFIGRET CM_INTERNAL
NewDriver(DEVNODE DevNode)
{
	LOG_CONF	lc;
	RES_DES		rd1, rd2;
	DWORD		dw;

	// Any failure should use LeaveInstance to unload the DLVxD if
	// it is the only instance. Only if it is success will we not
	// return with an "OR"ed CR_UNLOAD.

	// BUGBUG error checking

	CM_Get_Device_ID(DevNode, DeviceID, 80, 0);	    
	gIWI.iwi_bDeviceInit |= IWINFO_DEVICE_ID_INIT;
	
        dw = DeviceID[21] - '0';
	
	if(dw==0){
	    MMDEVLDR_Register_Device_Driver(DevNode, (DWORD)ConfigHandler, dw);
	}else{
	    CM_Register_Device_Driver(DevNode, ConfigHandler, dw, 0);
	}

	// Allocate per instance data

	return(CR_SUCCESS);
}


/****************************************************************************
 *
 *	VIWD_Exit - This procedure gets called when the DLVxD is unloading
 *
 *	Exported.
 *
 *	ENTRY:	None.
 *
 *	EXIT:	VXD_SUCCESS or VXD_FAILURE.
 *
 ***************************************************************************/
CM_VXD_RESULT CM_SYSCTRL
VIWD_Exit(VOID)
{
	// This procedure must deallocate any global data allocated by 
	// SAMPLE_Init (like a global table of COM ports or ISA RTR ids).
	// SAMPLE will be unloaded by Configuration Manager when
	// the ConfigHandler or the EnumHandler or the NewDevNode return
	// an error code that is "OR"ed with CR_UNLOAD.

	return(VXD_SUCCESS);
}

/****************************************************************************
 *
 *	VIWD_NewDevNode - This procedure gets called when a new devnode
 *			  has been created
 *
 *	Exported.
 *
 *	ENTRY:	DevNode is the new devnode that has just been created.
 *
 *		LoadType is the type of functionality configuration manager
 *		(or a devloader) wants this DLVxD to handle. It can be
 *		devloader, driver or enumerator.
 *
 *	EXIT:	Standard config manager return value.
 *
 ***************************************************************************/
CONFIGRET CM_SYSCTRL
VIWD_NewDevNode(DEVNODE Devnode, LOAD_TYPE LoadType)
{
	// A DLVxD can be any combination of being a devloader, a driver or
	// an enumerator.
	//
	// A DevLoader's job is to load the enumerator and driver for a
	// devnode (using CM_Load_DLVxD) and usually maintain some info
	// on the enumerator/driver it loaded.
	//
	// An enumerator's job is to do a CM_Register_Enumerator to
	// install an handler that will be called to enumerate children.
	//
	// A driver's job is to make the devnode work, which means installing
	// a configuration handler with CM_Register_Device_Driver.
	//
	// This sample code does all three functions.

        if (LoadType == DLVXD_LOAD_DRIVER) {
             return(NewDriver(Devnode));
	}
        return(CR_DEFAULT);
}


/****************************************************************************
 *
 *	VIWD_CD_Device_Init - reads the configuration of the CD device
 *
 *	ENTRY:	None.
 *
 *	EXIT:	will set the IWINFO_DEV1_INIT flag in the info structure on success
 *
 ***************************************************************************/
void VIWD_CD_Device_Init(void)
{               
    DEVNODE Devnode;
    unsigned long dnStatus;
    unsigned long dnProblem;

    DeviceID[21] = '1';
    if(CM_Locate_DevNode(&Devnode,DeviceID,0)==CR_SUCCESS){ 
	if(CM_Get_DevNode_Status(&dnStatus,&dnProblem,Devnode,0)==CR_SUCCESS){
	    if(dnStatus & DN_STARTED){
	        if(CM_Get_Alloc_Log_Conf(&theConfig,Devnode,0)==CR_SUCCESS){
	            gIWI.iwi_wCDBase = theConfig.wIOPortBase[0];
	            gIWI.iwi_wATAPIBase = theConfig.wIOPortBase[1];
	            gIWI.iwi_bCDIRQ = theConfig.bIRQRegisters[0];
	            gIWI.iwi_bCDDMA = theConfig.bDMALst[0];
                    gIWI.iwi_bDeviceInit |= IWINFO_DEV1_INIT;
	        }
	    }
	}
    }
}

/****************************************************************************
 *
 *	VIWD_Game_Device_Init - reads the configuration of the joystick device
 *
 *	ENTRY:	None.
 *
 *	EXIT:	will set the IWINFO_DEV2_INIT flag in the info structure on success
 *
 ***************************************************************************/
void VIWD_Game_Device_Init(void)
{
    DEVNODE Devnode;
    unsigned long dnStatus;
    unsigned long dnProblem;
    
    DeviceID[21] = '2';
    if(CM_Locate_DevNode(&Devnode,DeviceID,0)==CR_SUCCESS){ 
	if(CM_Get_DevNode_Status(&dnStatus,&dnProblem,Devnode,0)==CR_SUCCESS){
	    if(dnStatus & DN_STARTED){
	        if(CM_Get_Alloc_Log_Conf(&theConfig,Devnode,0)==CR_SUCCESS){
	            gIWI.iwi_wGameBase = theConfig.wIOPortBase[0];
                    gIWI.iwi_bDeviceInit |= IWINFO_DEV2_INIT;
	        }
	    }
	}
    }
}
