CNXT_SMC_STATUS cnxt_smc_get_state ( CNXT_SMC_HANDLE Handle, CNXT_SMC_STATE *pState ) { CNXT_SMC_INST *pInst = (CNXT_SMC_INST*)Handle; u_int32 uUnit; IS_DRIVER_INITED(SMC,pDriverInst->bInit); IS_VALID_HANDLE(SMC, pInst, &(pDriverInst->pUnitInst[pInst->uUnitNumber].pFirstInst)); /* * Put Driver Specific code here. */ uUnit = pInst->uUnitNumber; /* check if a card is in the slot */ if ( CNXT_GET ( SMC_ICC_STAT_REG_ADDR ( BANK_FROM_SLOT_ID ( uUnit ) ), SMC_ICC_STAT_CARDPRESENT_MASK ) == 0 ) { *pState = CNXT_SMC_EMPTY; } else { if ( Card[uUnit].State == SMC_ATR_PARSED ) { *pState = CNXT_SMC_READY; } else { *pState = CNXT_SMC_NOT_READY; } } return CNXT_SMC_OK; } /* end cnxt_smc_query_state */
CNXT_SMC_STATUS cnxt_smc_get_atr ( CNXT_SMC_HANDLE Handle, void *pAtr, u_int32 *puBufLength ) { CNXT_SMC_INST *pInst = (CNXT_SMC_INST*)Handle; u_int32 uUnit; IS_DRIVER_INITED(SMC,pDriverInst->bInit); IS_VALID_HANDLE(SMC, pInst, &(pDriverInst->pUnitInst[pInst->uUnitNumber].pFirstInst)); IS_NOT_NULL_POINTER(SMC, puBufLength); /* * Put Driver Specific code here. */ uUnit = pInst->uUnitNumber; /* check state of the card */ if ( Card[uUnit].State < SMC_ATR_RECEIVED ) { return CNXT_SMC_NOT_AVAILABLE; } if ( pAtr == NULL ) { /* get size of ATR only */ *puBufLength = Card[uUnit].uAtrLength; return CNXT_SMC_OK; } if ( *puBufLength < Card[uUnit].uAtrLength ) { /* input buffer is too small */ *puBufLength = Card[uUnit].uAtrLength; return CNXT_SMC_BAD_PARAMETER; } /* copy ATR */ memcpy ( pAtr, Card[uUnit].uAtr, Card[uUnit].uAtrLength ); *puBufLength = Card[uUnit].uAtrLength; return CNXT_SMC_OK; } /* end cnxt_smc_get_atr */
CNXT_SMC_STATUS cnxt_smc_close ( CNXT_SMC_HANDLE Handle ) { CNXT_SMC_INST *pInst = (CNXT_SMC_INST*)Handle; CNXT_SMC_UNIT_INST *pUnitInst; IS_DRIVER_INITED(SMC,pDriverInst->bInit); IS_VALID_HANDLE(SMC, pInst, &(pDriverInst->pUnitInst[pInst->uUnitNumber].pFirstInst)); if (sem_get(pDriverInst->DriverSem, KAL_WAIT_FOREVER) != RC_OK) { return CNXT_SMC_INTERNAL_ERROR; } /* * Put Driver Specific code here. */ pUnitInst = &(pDriverInst->pUnitInst[pInst->uUnitNumber]); /* release the resource of the instance */ if (REMOVE_HANDLE(&(pUnitInst->pFirstInst), pInst) == FALSE) { sem_put(pDriverInst->DriverSem); /* must be last line of routine! */ return CNXT_SMC_INTERNAL_ERROR; } DESTROY_HANDLE(&(pDriverInst->pInstList), pInst); /* set the unit to be shared if no instance opened for the unit */ if ( pUnitInst->pFirstInst == NULL ) { pUnitInst->bExclusive = FALSE; } sem_put(pDriverInst->DriverSem); /* must be last line of routine! */ return CNXT_SMC_OK; } /* end cnxt_smc_close() */
CNXT_SMC_STATUS cnxt_smc_powerdown_card ( CNXT_SMC_HANDLE Handle, bool bAsync, void *Tag ) { CNXT_SMC_INST *pInst = (CNXT_SMC_INST*)Handle; SMC_RW_JOB_DESCRIPTOR *pRwJob; u_int32 uUnit; bool bKs; IS_DRIVER_INITED(SMC,pDriverInst->bInit); IS_VALID_HANDLE(SMC, pInst, &(pDriverInst->pUnitInst[pInst->uUnitNumber].pFirstInst)); /* * Put Driver Specific code here. */ uUnit = pInst->uUnitNumber; /* check if there is resetting/power down pending */ bKs = critical_section_begin (); if ( Card[uUnit].ResetJob.pInst ) { critical_section_end ( bKs ); return CNXT_SMC_NOT_AVAILABLE; } if ( Card[uUnit].PowerdownJob.pInst ) { critical_section_end ( bKs ); return CNXT_SMC_OK; } Card[uUnit].PowerdownJob.pInst = pInst; critical_section_end ( bKs ); /* clear all pending RW jobs */ bKs = critical_section_begin (); while ( Card[uUnit].pRwJob ) { pRwJob = Card[uUnit].pRwJob; Card[uUnit].pRwJob = pRwJob->pNext; smc_term_rw_job ( pRwJob, CNXT_SMC_TIMEOUT ); } critical_section_end ( bKs ); if ( Card[uUnit].State == SMC_NOT_INSERT ) { Card[uUnit].PowerdownJob.pInst = NULL; return CNXT_SMC_NOT_AVAILABLE; } /* save bAsync & Tag */ Card[uUnit].PowerdownJob.bAsync = bAsync; Card[uUnit].PowerdownJob.Tag = Tag; /* check if the card is up */ if ( CNXT_GET ( SMC_ICC_STAT_REG_ADDR ( BANK_FROM_SLOT_ID ( uUnit ) ), SMC_ICC_STAT_CARDPOWER_MASK ) == 0 ) { /* card is down, clear power down job */ Card[uUnit].PowerdownJob.pInst = NULL; } else { /* initiate deactivate */ *(LPREG)( SMC_ICC_CTRL_REG_ADDR ( BANK_FROM_SLOT_ID ( uUnit ) ) ) = SMC_ICC_CTRL_DEACTIVATECARD_MASK; } if ( Card[uUnit].PowerdownJob.bAsync == FALSE ) { if ( sem_get ( Card[uUnit].PowerdownJob.SyncSem, Card[uUnit].Config.uTimeout ) != RC_OK ) { return CNXT_SMC_TIMEOUT; } } return CNXT_SMC_OK; } /* end cnxt_smc_reset_card */
CNXT_SMC_STATUS cnxt_smc_reset_card ( CNXT_SMC_HANDLE Handle, bool bAsync, void *Tag ) { CNXT_SMC_INST *pInst = (CNXT_SMC_INST*)Handle; SMC_RW_JOB_DESCRIPTOR *pRwJob; u_int32 uUnit, uBank; bool bKs; IS_DRIVER_INITED(SMC,pDriverInst->bInit); IS_VALID_HANDLE(SMC, pInst, &(pDriverInst->pUnitInst[pInst->uUnitNumber].pFirstInst)); /* * Put Driver Specific code here. */ uUnit = pInst->uUnitNumber; /* check if there is another resetting pending */ bKs = critical_section_begin (); if ( Card[uUnit].ResetJob.pInst ) { critical_section_end ( bKs ); return CNXT_SMC_OK; } Card[uUnit].ResetJob.pInst = pInst; critical_section_end ( bKs ); /* clear other pending transactions */ bKs = critical_section_begin (); if ( Card[uUnit].PowerdownJob.pInst ) { if ( ( Card[uUnit].PowerdownJob.bAsync ) && ( (Card[uUnit].PowerdownJob.pInst)->pNotifyFn ) ) { (Card[uUnit].PowerdownJob.pInst)->pNotifyFn ( (CNXT_SMC_HANDLE)Card[uUnit].PowerdownJob.pInst, (Card[uUnit].PowerdownJob.pInst)->pUserData, CNXT_SMC_EVENT_CARD_POWER_DOWN_TIMEOUT, NULL, Card[uUnit].PowerdownJob.Tag ); } Card[uUnit].PowerdownJob.pInst = NULL; } critical_section_end ( bKs ); /* clear all pending RW jobs */ while ( Card[uUnit].pRwJob ) { bKs = critical_section_begin (); pRwJob = Card[uUnit].pRwJob; Card[uUnit].pRwJob = pRwJob->pNext; critical_section_end ( bKs ); smc_term_rw_job ( pRwJob, CNXT_SMC_TIMEOUT ); } /* save bAsync & Tag */ Card[uUnit].ResetJob.bAsync = bAsync; Card[uUnit].ResetJob.Tag = Tag; uBank = BANK_FROM_SLOT_ID ( uUnit ); /* initialize card descriptor */ smc_descriptor_init ( &Card[uUnit], uUnit ); /* check if there is card in the slot */ if ( Card[uUnit].State == SMC_NOT_INSERT ) { Card[uUnit].ResetJob.pInst = NULL; return CNXT_SMC_NOT_AVAILABLE; } /* initialize card HW */ smc_hw_init ( &Card[uUnit], uUnit ); /* set receive mode to receive ATR */ CNXT_SET_VAL ( SMC_TERM_CTRL_REG_ADDR ( uBank ), SMC_TERM_CTRL_MODE_MASK, SMC_MODE_RX ); /* Enable Rx Interrupt */ CNXT_SET_VAL ( SMC_INT_MASK_REG_ADDR ( uBank ), SMC_INT_RXREAD_MASK, SMC_ENABLE ); /* initiate reset */ if (CNXT_GET (SMC_ICC_STAT_REG_ADDR (uBank), SMC_ICC_STAT_CARDPOWER_MASK)) { /* do a warm reset */ *(LPREG)(SMC_ICC_CTRL_REG_ADDR (uBank)) = SMC_ICC_CTRL_WARMRESET_MASK; } else { /* do a cold reset */ *(LPREG)(SMC_ICC_CTRL_REG_ADDR (uBank)) = ( SMC_ICC_CTRL_ACTIVATECARD_MASK | SMC_ICC_CTRL_DEACTIVATECARD_MASK ); } if ( Card[uUnit].ResetJob.bAsync == FALSE ) { if ( sem_get ( Card[uUnit].ResetJob.SyncSem, Card[uUnit].Config.uTimeout ) != RC_OK ) { return CNXT_SMC_TIMEOUT; } } return CNXT_SMC_OK; } /* end cnxt_smc_reset_card */
CNXT_SMC_STATUS cnxt_smc_read_write ( CNXT_SMC_HANDLE Handle, bool bAsync, void *pOutBuf, u_int32 uOutLength, void *pInBuf, u_int32 *pInLength, void *Tag ) { CNXT_SMC_INST *pInst = (CNXT_SMC_INST*)Handle; u_int32 uUnit; SMC_RW_JOB_DESCRIPTOR *pRwJob, *pJobNode; bool bKs; CNXT_SMC_STATUS RetCode = CNXT_SMC_OK; IS_DRIVER_INITED(SMC,pDriverInst->bInit); IS_VALID_HANDLE(SMC, pInst, &(pDriverInst->pUnitInst[pInst->uUnitNumber].pFirstInst)); if ( ( ( pOutBuf == NULL ) || ( uOutLength == 0 ) ) && ( ( pInBuf == NULL ) || ( pInLength == NULL ) || ( *pInLength == 0 ) ) ) { return CNXT_SMC_BAD_PARAMETER; } uUnit = pInst->uUnitNumber; /* check the state of the card */ if ( Card[uUnit].State != SMC_ATR_PARSED ) { return CNXT_SMC_NOT_AVAILABLE; } /* set up Rw job */ bKs = critical_section_begin (); if ( ( pRwJob = cnxt_smc_new_rw_job () ) == NULL ) { critical_section_end(bKs); return CNXT_SMC_RESOURCE_ERROR; } critical_section_end(bKs); #ifdef TFCAS CNXT_SET_VAL ( SMC_CHTIME_REG_ADDR ( uUnit ), SMC_TIME_CYCLES_MASK, 9600 ); CNXT_SET_VAL ( SMC_BLKTIME_REG_ADDR ( uUnit ), SMC_TIME_CYCLES_MASK, 9600 ); #endif pRwJob->pInst = pInst; pRwJob->bAsync = bAsync; pRwJob->pTxPtr = pOutBuf; pRwJob->uBytesToTx = uOutLength; pRwJob->pRxPtr = pInBuf; pRwJob->pBytesRecved = pInLength; pRwJob->pRxBufEnd = (u_int8*)pInBuf + *pInLength; pRwJob->Tag = Tag; pRwJob->pNext = NULL; *(pRwJob->pBytesRecved) = 0; /* add the job to the execution list */ bKs = critical_section_begin (); if ( Card[uUnit].pRwJob ) { pJobNode = Card[uUnit].pRwJob; while ( pJobNode->pNext ) { pJobNode = pJobNode->pNext; } pJobNode->pNext = pRwJob; } else { Card[uUnit].pRwJob = pRwJob; smc_start_rw_job ( pRwJob ); } critical_section_end ( bKs ); if ( ( bAsync == FALSE ) && pRwJob->SyncSem ) { if ( sem_get ( pRwJob->SyncSem, KAL_WAIT_FOREVER ) == RC_OK ) { /* rw job finished */ RetCode = pRwJob->Status; bKs = critical_section_begin (); cnxt_smc_free_rw_job ( pRwJob ); critical_section_end ( bKs ); } else { RetCode = CNXT_SMC_INTERNAL_ERROR; } } #ifdef TFCAS CNXT_SET_VAL ( SMC_CHTIME_REG_ADDR ( uUnit ), SMC_TIME_CYCLES_MASK, 9600 ); CNXT_SET_VAL ( SMC_BLKTIME_REG_ADDR ( uUnit ), SMC_TIME_CYCLES_MASK, 9600 ); #endif return RetCode; }
CNXT_SMC_STATUS cnxt_smc_get_config ( CNXT_SMC_HANDLE Handle, CNXT_SMC_CONFIG_ITEM Item, u_int32 *puValue ) { CNXT_SMC_INST *pInst = (CNXT_SMC_INST*)Handle; u_int32 uUnit; IS_DRIVER_INITED(SMC,pDriverInst->bInit); IS_VALID_HANDLE(SMC, pInst, &(pDriverInst->pUnitInst[pInst->uUnitNumber].pFirstInst)); /* * Put Driver Specific code here. */ uUnit = pInst->uUnitNumber; /* check the state of the card */ if ( Card[uUnit].State != SMC_ATR_PARSED ) { return CNXT_SMC_NOT_AVAILABLE; } switch ( Item ) { case CNXT_SMC_CONFIG_CONVENTION: *puValue = (u_int32)Card[uUnit].Config.uConvention; break; case CNXT_SMC_CONFIG_PROTOCOL: *puValue = (u_int32)Card[uUnit].Config.uProtocol; break; case CNXT_SMC_CONFIG_FI: *puValue = (u_int32)Card[uUnit].Config.uFI; break; case CNXT_SMC_CONFIG_DI: *puValue = (u_int32)Card[uUnit].Config.uDI; break; case CNXT_SMC_CONFIG_PI1: *puValue = (u_int32)Card[uUnit].Config.uPI1; break; case CNXT_SMC_CONFIG_PI2: *puValue = (u_int32)Card[uUnit].Config.uPI2; break; case CNXT_SMC_CONFIG_II: *puValue = (u_int32)Card[uUnit].Config.uII; break; case CNXT_SMC_CONFIG_N: *puValue = (u_int32)Card[uUnit].Config.uN; break; case CNXT_SMC_CONFIG_HISTORICAL: *puValue = (u_int32)Card[uUnit].Config.pHistorical; break; case CNXT_SMC_CONFIG_HISTORICAL_LEN: *puValue = (u_int32)Card[uUnit].Config.uHistoricalLength; break; case CNXT_SMC_CONFIG_TIMEOUT: *puValue = (u_int32)Card[uUnit].Config.uTimeout; break; case CNXT_SMC_CONFIG_RETRY: *puValue = (u_int32)Card[uUnit].Config.uRetry; break; default: return CNXT_SMC_BAD_PARAMETER; } return CNXT_SMC_OK; } /* end cnxt_smc_get_config */
CNXT_SMC_STATUS cnxt_smc_set_config ( CNXT_SMC_HANDLE Handle, CNXT_SMC_CONFIG_ITEM Item, u_int32 uValue ) { CNXT_SMC_INST *pInst = (CNXT_SMC_INST*)Handle; u_int32 uUnit, uBank; IS_DRIVER_INITED(SMC,pDriverInst->bInit); IS_VALID_HANDLE(SMC, pInst, &(pDriverInst->pUnitInst[pInst->uUnitNumber].pFirstInst)); /* * Put Driver Specific code here. */ uUnit = pInst->uUnitNumber; /* check the state of the card */ if ( Card[uUnit].State != SMC_ATR_PARSED ) { return CNXT_SMC_NOT_AVAILABLE; } uBank = BANK_FROM_SLOT_ID ( uUnit ); switch ( Item ) { case CNXT_SMC_CONFIG_CONVENTION: if ( (CNXT_SMC_CONVENTION)uValue == CNXT_SMC_CONV_DIRECT ) { CNXT_SET_VAL ( SMC_CONV_REG_ADDR ( uBank ), SMC_CONV_SENSE_MASK, SMC_SENSE_DIRECT ); CNXT_SET_VAL ( SMC_CONV_REG_ADDR ( uBank ), SMC_CONV_ORDER_MASK, SMC_ORDER_DIRECT ); } else if ( (CNXT_SMC_CONVENTION)uValue == CNXT_SMC_CONV_INVERSE ) { CNXT_SET_VAL ( SMC_CONV_REG_ADDR ( uBank ), SMC_CONV_SENSE_MASK, SMC_SENSE_INVERSE ); CNXT_SET_VAL ( SMC_CONV_REG_ADDR ( uBank ), SMC_CONV_ORDER_MASK, SMC_ORDER_INVERSE ); } else { return CNXT_SMC_BAD_PARAMETER; } Card[uUnit].Config.uConvention = (u_int8)uValue; break; case CNXT_SMC_CONFIG_PROTOCOL: /* Protocol is a software/driver state. No change required to the hw */ if ( ( (CNXT_SMC_PROTOCOL)uValue == CNXT_SMC_PROTOCOL_T0 ) || ( (CNXT_SMC_PROTOCOL)uValue == CNXT_SMC_PROTOCOL_T1 ) ) { Card[uUnit].Config.uProtocol = (u_int8)uValue; } else { return CNXT_SMC_BAD_PARAMETER; } break; case CNXT_SMC_CONFIG_FI: if ( ( uValue > 0 ) && ( uValue <= 15 ) ) { /* set the new F */ smc_set_fi ( uBank, uValue ); Card[uUnit].Config.uFI = (u_int8)uValue; } else { return CNXT_SMC_BAD_PARAMETER; } break; case CNXT_SMC_CONFIG_DI: if ( ( uValue > 0 ) && ( uValue <= 15 ) ) { /* set the new D */ smc_set_di ( uBank, uValue ); Card[uUnit].Config.uDI = (u_int8)uValue; } else { return CNXT_SMC_BAD_PARAMETER; } break; case CNXT_SMC_CONFIG_PI1: case CNXT_SMC_CONFIG_PI2: case CNXT_SMC_CONFIG_II: /* these config parameters cannot be set */ return CNXT_SMC_BAD_PARAMETER; case CNXT_SMC_CONFIG_N: if ( ( uValue > 0 ) && ( uValue <= 255 ) ) { /* set new N */ CNXT_SET_VAL ( SMC_CHGUARD_REG_ADDR ( uBank ), SMC_GUARD_CYCLES_MASK, uValue ); Card[uUnit].Config.uN = (u_int8)uValue; } else { return CNXT_SMC_BAD_PARAMETER; } break; case CNXT_SMC_CONFIG_TIMEOUT: Card[uUnit].Config.uTimeout = (u_int16)uValue; break; case CNXT_SMC_CONFIG_RETRY: Card[uUnit].Config.uRetry = (u_int8)uValue; break; default: return CNXT_SMC_BAD_PARAMETER; } return CNXT_SMC_OK; } /* end cnxt_smc_set_config */
VOID WINAPI ThirdPartyVDDBop(LPWORD Stack) { /* Get the Function Number and skip it */ BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP()); setIP(getIP() + 1); switch (FuncNum) { /* RegisterModule */ case 0: { BOOL Success = TRUE; WORD RetVal = 0; WORD Entry = 0; LPCSTR DllName = NULL, InitRoutineName = NULL, DispatchRoutineName = NULL; HMODULE hDll = NULL; VDD_PROC InitRoutine = NULL, DispatchRoutine = NULL; DPRINT("RegisterModule() called\n"); /* Clear the Carry Flag (no error happened so far) */ setCF(0); /* Retrieve the next free entry in the table (used later on) */ Entry = GetNextFreeVDDEntry(); if (Entry >= MAX_VDD_MODULES) { DPRINT1("Failed to create a new VDD module entry\n"); Success = FALSE; RetVal = 4; goto Quit; } /* Retrieve the VDD name in DS:SI */ DllName = (LPCSTR)SEG_OFF_TO_PTR(getDS(), getSI()); /* Retrieve the initialization routine API name in ES:DI (optional --> ES=DI=0) */ if (TO_LINEAR(getES(), getDI()) != 0) InitRoutineName = (LPCSTR)SEG_OFF_TO_PTR(getES(), getDI()); /* Retrieve the dispatch routine API name in DS:BX */ DispatchRoutineName = (LPCSTR)SEG_OFF_TO_PTR(getDS(), getBX()); DPRINT1("DllName = '%s' - InitRoutineName = '%s' - DispatchRoutineName = '%s'\n", (DllName ? DllName : "n/a"), (InitRoutineName ? InitRoutineName : "n/a"), (DispatchRoutineName ? DispatchRoutineName : "n/a")); /* Load the VDD DLL */ hDll = LoadLibraryA(DllName); if (hDll == NULL) { DWORD LastError = GetLastError(); Success = FALSE; if (LastError == ERROR_NOT_ENOUGH_MEMORY) { DPRINT1("Not enough memory to load DLL '%s'\n", DllName); RetVal = 4; goto Quit; } else { DPRINT1("Failed to load DLL '%s'; last error = %d\n", DllName, LastError); RetVal = 1; goto Quit; } } /* Load the initialization routine if needed */ if (InitRoutineName) { InitRoutine = (VDD_PROC)GetProcAddress(hDll, InitRoutineName); if (InitRoutine == NULL) { DPRINT1("Failed to load the initialization routine '%s'\n", InitRoutineName); Success = FALSE; RetVal = 3; goto Quit; } } /* Load the dispatch routine */ DispatchRoutine = (VDD_PROC)GetProcAddress(hDll, DispatchRoutineName); if (DispatchRoutine == NULL) { DPRINT1("Failed to load the dispatch routine '%s'\n", DispatchRoutineName); Success = FALSE; RetVal = 2; goto Quit; } /* If we arrived there, that means everything is OK */ /* Register the VDD DLL */ VDDList[Entry].hDll = hDll; VDDList[Entry].DispatchRoutine = DispatchRoutine; /* Call the initialization routine if needed */ if (InitRoutine) InitRoutine(); /* We succeeded. RetVal will contain a valid VDD DLL handle */ Success = TRUE; RetVal = ENTRY_TO_HANDLE(Entry); // Convert the entry to a valid handle Quit: if (!Success) { /* Unload the VDD DLL */ if (hDll) FreeLibrary(hDll); /* Set the Carry Flag to indicate that an error happened */ setCF(1); } // else // { // /* Clear the Carry Flag (success) */ // setCF(0); // } setAX(RetVal); break; } /* UnRegisterModule */ case 1: { WORD Handle = getAX(); WORD Entry = HANDLE_TO_ENTRY(Handle); // Convert the handle to a valid entry DPRINT("UnRegisterModule() called\n"); /* Sanity checks */ if (!IS_VALID_HANDLE(Handle) || VDDList[Entry].hDll == NULL) { DPRINT1("Invalid VDD DLL Handle: %d\n", Entry); /* Stop the VDM */ EmulatorTerminate(); return; } /* Unregister the VDD DLL */ FreeLibrary(VDDList[Entry].hDll); VDDList[Entry].hDll = NULL; VDDList[Entry].DispatchRoutine = NULL; break; } /* DispatchCall */ case 2: { WORD Handle = getAX(); WORD Entry = HANDLE_TO_ENTRY(Handle); // Convert the handle to a valid entry DPRINT("DispatchCall() called\n"); /* Sanity checks */ if (!IS_VALID_HANDLE(Handle) || VDDList[Entry].hDll == NULL || VDDList[Entry].DispatchRoutine == NULL) { DPRINT1("Invalid VDD DLL Handle: %d\n", Entry); /* Stop the VDM */ EmulatorTerminate(); return; } /* Call the dispatch routine */ VDDList[Entry].DispatchRoutine(); break; } default: { DPRINT1("Unknown 3rd-party VDD BOP Function: 0x%02X\n", FuncNum); setCF(1); break; } } }