// BootModeObj.cpp : Defines the initialization routines for the DLL.
//

#include "stdafx.h"
//#include <initguid.h>
#include "BootModeObj.h"
#include <atlconv.h>
#include <process.h>

#include "OptionHelpper.h"

extern COptionHelpper ohObject;

#define DEFAULT_MAX_LENGTH          0x3000
#define MAX_UINT_SLEEP_TIME         500

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// CBootModeObj
CBootModeObj::CBootModeObj()
{
    m_hBMThread        = NULL;
    m_bExitThread      = FALSE;
    
    m_mapObserverRegs.RemoveAll();
    m_dwOprCookie  = 0; 
    
    m_dwWaitTime = 0;
    m_dwNextObserverCookie = 1;

    m_dwOprCookie = 0;

}

CBootModeObj::~CBootModeObj()
{
    POSITION pos = m_mapObserverRegs.GetStartPosition();
    DWORD dwCookie;
    IBMOprObserver* pReg;
    while( pos ){
        m_mapObserverRegs.GetNextAssoc( pos, dwCookie, pReg );
        pReg->Release();
    }            
    m_mapObserverRegs.RemoveAll();
}

BOOL CBootModeObj::GenerateEndNotification( DWORD dwOprCookie , DWORD dwResult )
{
	DWORD dwErrorCode = 1;
	if(dwResult == 1) // success
	{
		dwErrorCode = 0;
	}

    POSITION pos = m_mapObserverRegs.GetStartPosition();
    DWORD dwCookie;
    IBMOprObserver* pReg = NULL;
    while( pos ){
        pReg = NULL;
        dwCookie = 0;
        m_mapObserverRegs.GetNextAssoc( pos, dwCookie, pReg );
        if( pReg == NULL )
            continue;
        HRESULT hr = pReg->OnEnd( dwOprCookie ,dwErrorCode );
        if( FAILED(hr) )
        {
            return FALSE;
        }
    }
    return TRUE;
}

BOOL CBootModeObj::GenerateStartNotification( DWORD dwOprCookie, DWORD dwResult  )
{  
	DWORD dwErrorCode = 1; //fail
	if(dwResult == 1) // success
	{
		dwErrorCode = 0;
	}

    POSITION pos = m_mapObserverRegs.GetStartPosition();
    DWORD dwCookie;
    IBMOprObserver* pReg = NULL;
    while( pos ){
        pReg = NULL;
        dwCookie = 0;
        m_mapObserverRegs.GetNextAssoc( pos, dwCookie, pReg );
        if( pReg == NULL )
            continue;
        HRESULT hr = pReg->OnStart( dwOprCookie , dwErrorCode );
        if( FAILED(hr) )
        {
            return FALSE;
        }
    }   
    return TRUE;
}


BOOL CBootModeObj::GenerateEndFileOprNotification( DWORD dwOprCookie, 
												  LPCTSTR lpszFileId,
                                                  LPCTSTR lpszFileType,
                                                  DWORD dwResult )
{
	USES_CONVERSION;

	DWORD dwErrorCode = 1; // fail
	if(dwResult == 1) // success
	{
		dwErrorCode = 0;
	}
    
    POSITION pos = m_mapObserverRegs.GetStartPosition();
    DWORD dwCookie = 0;
    IBMOprObserver* pReg = NULL;
    while( pos ){
        dwCookie = 0;
        pReg = NULL;
        m_mapObserverRegs.GetNextAssoc( pos, dwCookie, pReg );
        if( pReg == NULL )
            continue;
        HRESULT hr = pReg->OnFileOprEnd( dwOprCookie, T2OLE((_TCHAR *)lpszFileId),T2OLE((_TCHAR *)lpszFileType), dwErrorCode );
        if( FAILED(hr) )
        {				
			return FALSE;		
        }
    }    
    return TRUE;
}

BOOL CBootModeObj::GenerateStartFileOprNotification( DWORD dwOprCookie, 
													LPCTSTR lpszFileId,
                                                    LPCTSTR lpszFileType  )
{
    USES_CONVERSION;
    
    POSITION pos = m_mapObserverRegs.GetStartPosition();
    DWORD dwCookie;
    IBMOprObserver* pReg = NULL;
    while( pos ){
        dwCookie = 0;
        pReg = NULL;
        m_mapObserverRegs.GetNextAssoc( pos, dwCookie, pReg );
        if( pReg == NULL )
            continue;
        HRESULT hr = pReg->OnFileOprStart( dwOprCookie, T2OLE((_TCHAR *)lpszFileId),
                        T2OLE((_TCHAR *)lpszFileType), (DWORD)(&m_BMFileImpl) );
        if( FAILED(hr) )
        {
            return FALSE;
        }
    }        
    return TRUE;
}

BOOL CBootModeObj::GenerateEndOprNotification( DWORD dwOprCookie, 
											  LPCTSTR lpszFileId,
                                              LPCTSTR lpszFileType, 
                                              LPCTSTR lpszOperationType,
                                              DWORD dwResult )
{
    USES_CONVERSION;

	DWORD dwErrorCode = 1;
	if(dwResult == 1) // success
	{
		dwErrorCode = 0;
	}
	else // get operation error code
	{
		dwErrorCode = m_OprDriver.GetOprLastErrorCode();
	}
    
    POSITION pos = m_mapObserverRegs.GetStartPosition();
    DWORD dwCookie;
    IBMOprObserver* pReg = NULL;

    while( pos ){
        dwCookie = 0;
        pReg = NULL;
        m_mapObserverRegs.GetNextAssoc( pos, dwCookie, pReg );
        if( pReg == NULL )
            continue;
        HRESULT hr = pReg->OnOperationEnd( dwOprCookie,T2OLE((_TCHAR *)lpszFileId), T2OLE((_TCHAR *)lpszFileType),
                    T2OLE((_TCHAR *)lpszOperationType) , dwErrorCode , (DWORD)(&m_BMFileImpl) );
        if( FAILED(hr) )
        {
            return FALSE;
        }
    }        
    return TRUE;
}

BOOL CBootModeObj::GenerateStartOprNotification( DWORD dwOprCookie, 
												LPCTSTR lpszFileID,
                                                LPCTSTR lpszFileType, 
                                                LPCTSTR lpszOperationType )
{
    USES_CONVERSION;
    
    POSITION pos = m_mapObserverRegs.GetStartPosition();
    DWORD dwCookie;
    IBMOprObserver* pReg = NULL;
    while( pos ){
        dwCookie = 0;
        pReg = NULL;
        m_mapObserverRegs.GetNextAssoc( pos, dwCookie, pReg );
        if( pReg == NULL )
            continue;
        HRESULT hr = pReg->OnOperationStart( dwOprCookie, T2OLE((_TCHAR *)lpszFileID),T2OLE((_TCHAR *)lpszFileType),
            T2OLE((_TCHAR *)lpszOperationType), (DWORD)(&m_BMFileImpl) );
        if( FAILED(hr) )
        {
            return FALSE;
        }
    }        
    return TRUE;
}

void CBootModeObj::EndProc(  BOOL bEndSuccess  )
{
    if( m_bExitThread )
    {
        return;
    }
    
    DWORD dwEnd = bEndSuccess;    
    BOOL bEndNotify = FALSE;
    if( m_dwWaitTime == 0 )
    {
        m_bExitThread = TRUE;
        bEndNotify = GenerateEndNotification( m_dwOprCookie, dwEnd );      
    }
    else
    {
        m_BMFileImpl.MoveFirst(); 
        ICommChannel* pChannel;
        HRESULT hr = GetCommunicateChannelPtr( (LPVOID*)&pChannel );
        if( SUCCEEDED(hr) )
        {
			DWORD dwBaud = DEFAULT_BAUDRATE;
			pChannel->SetProperty(0,CH_PROP_BAUD,(LPCVOID)&dwBaud);
        }
//@hongliang.xin 2010-1-25  not used 
//      dwEnd |= FACTORY_MODE;
        bEndNotify = GenerateEndNotification( m_dwOprCookie, dwEnd );    
        UINT uiSleepCount = m_dwWaitTime / MAX_UINT_SLEEP_TIME;
        for( unsigned int i = 0; i < uiSleepCount && !m_bExitThread; i++)
        {
            Sleep( MAX_UINT_SLEEP_TIME );        
        }
    }
    if( bEndNotify && bEndSuccess )
    {
        Log( _T("Finish Successful."));
    }
    else
    {
        Log( _T("Finish Failed."));
    }

}

BOOL CBootModeObj::CreateBMThread( )
{
    Log( _T("Create boot mode thread."));
    m_hBMThread = (HANDLE)_beginthreadex(NULL,
								0,
                                (PBEGINTHREADEX_THREADFUNC)GetBMThreadFunc,
                                this,
                                NULL,
                                NULL);
    if(m_hBMThread == NULL)
    {
        return FALSE;		
    }
    m_bExitThread = FALSE;

    return TRUE;
}

void CBootModeObj::DestroyBMThread()
{
    if(m_hBMThread != NULL )
    {
        m_bExitThread = TRUE;        
	
		m_OprDriver.StopOpr();

        Log( _T("End boot mode thread."));

        WaitForSingleObject( m_hBMThread, INFINITE );  
        
        CloseHandle( m_hBMThread );
        m_hBMThread = NULL;
    }
}

DWORD WINAPI CBootModeObj::GetBMThreadFunc( LPVOID lpParam )
{
    CBootModeObj *pThis = (CBootModeObj *)lpParam;
    
    return pThis->BMThreadFunc();
}

DWORD CBootModeObj::BMThreadFunc( )
{
    m_BMFileImpl.MoveFirst();
    CString strLog;

	//add by hongliang.xin 2009-3-2
	VARIANT varTimes;
	ohObject.GetProperty(0,_T("CheckNVTimes"),&varTimes);
	UINT nCheckNVTimes = varTimes.uintVal;	// check nv and redownload times
	int nReadNVCount = 0; // checked nv times, begin to check NV after downloaded all files
	BOOL bCheckNVSuccess = TRUE; // check nv success flag
	BOOL bEof = FALSE; // the end flag of download files  


    while( !m_bExitThread )
	{
        if( m_BMFileImpl.GetCurFileIndex() == 0 &&
            !GenerateStartNotification( m_dwOprCookie, 1 ) ) 
        {
            Log( _T("Fail at start notification.") );
            EndProc( FALSE );            
            continue;
        }

        BMFileInfo* pFileInfo = m_BMFileImpl.GetCurrentBMFileInfo();

        CStringArray aryKeyAndData;
        if( !ohObject.GetFileOperations( pFileInfo->szFileType,&aryKeyAndData ) )
        //if( 0 == EnumKeys(szSection,&aryKeyAndData))
        {
            strLog.Format( _T("Can not read file operations for file type %s "), pFileInfo->szFileType );
            Log( strLog );
            EndProc( FALSE );
            continue;
        }

        if( !GenerateStartFileOprNotification( m_dwOprCookie, pFileInfo->szFileID, 
			                                   pFileInfo->szFileType) )
        {
            GenerateEndFileOprNotification( m_dwOprCookie, pFileInfo->szFileID,
				                            pFileInfo->szFileType ,FALSE);
            strLog.Format( _T("Fail at start [ID:%s] %s  file notification"), 
                            pFileInfo->szFileID,pFileInfo->szFileType );
            Log( strLog );
            EndProc( FALSE );           
            continue;
        }

        DWORD dwMaxLength = 
            ohObject.GetPacketLength( pFileInfo->szFileType );
        m_BMFileImpl.SetCurMaxLength( dwMaxLength );
        
    	static BYTE parms[] =  VTS_I4;
		BOOL result;

		if(ohObject.GetDebugModeFlag(pFileInfo->szFileID))
		{
			result = m_OprDriver.SetDebugLogState(TRUE);	
			if(!result)
			{
				strLog.Format( _T("Fail at setting [%s] debug mode: [TRUE]"), pFileInfo->szFileID );
                Log( strLog );
			}
		}   
        
        if( _tcscmp( pFileInfo->szFileType , _T("FDL") ) == 0)
        {
			m_OprDriver.SetIsCheckCrc(TRUE);       
        }
        else
        {
            m_OprDriver.SetIsCheckCrc(FALSE);             
        }

        
        if( m_BMFileImpl.GetCurFileIndex() < 2  && 0 == nReadNVCount )
        {
			result = m_OprDriver.Connect((long)pFileInfo);   
            if( !result )
            {
                GenerateEndFileOprNotification( 
                    m_dwOprCookie, pFileInfo->szFileID, pFileInfo->szFileType, FALSE );

                strLog.Format( _T("Fail at %s---connect operation"), 
                    pFileInfo->szFileType );
                Log( strLog );

				if(ohObject.GetDebugModeFlag(pFileInfo->szFileID))
				{
					result =m_OprDriver.SetDebugLogState(FALSE);			
					if(!result)
					{
						strLog.Format( _T("Fail at setting [%s] debug mode: [FALSE]"), pFileInfo->szFileID );
						Log( strLog );
					}
				}

                EndProc( FALSE );
                continue;                
            }
        }

        if( m_BMFileImpl.GetCurFileIndex() == 1 && 0 == nReadNVCount )
        {
			result = m_OprDriver.ChangeBaud(NULL);
            if( !result )
            {
                GenerateEndFileOprNotification(  m_dwOprCookie, 
					pFileInfo->szFileID,pFileInfo->szFileType, FALSE );
                
                strLog.Format( _T("Fail at %s---ChangeBaud operation"), 
                    pFileInfo->szFileType );
                Log( strLog );

				if(ohObject.GetDebugModeFlag(pFileInfo->szFileID))
				{
					result =m_OprDriver.SetDebugLogState(FALSE);		
					if(!result)
					{
						strLog.Format( _T("Fail at setting [%s] debug mode: [FALSE]"), pFileInfo->szFileID );
						Log( strLog );
					}
				}

                EndProc( FALSE );
                continue;                  
            }
        }

        for( int i = 0; i < aryKeyAndData.GetSize(); i+=2 )
        { 
            CString str;
            
            //OLECHAR FAR* szName = aryKeyAndData.GetAt( i + 1).AllocSysString() ;
			CString strName = aryKeyAndData.GetAt( i + 1);
			strName.TrimLeft();
			strName.TrimRight();
            DISPID dispid;
            
            dispid = m_OprDriver.GetIDsOfNames( strName );
            if( dispid == -1 )
            {
                strLog.Format( _T("%s---%s operation is not implemented"), 
                    pFileInfo->szFileType, aryKeyAndData.GetAt( i + 1 ));
                Log( strLog );
                continue;
            }

            if( !GenerateStartOprNotification( m_dwOprCookie,pFileInfo->szFileID,
                pFileInfo->szFileType, aryKeyAndData.GetAt( i + 1 ) ) )
            {
                GenerateEndOprNotification( m_dwOprCookie, pFileInfo->szFileID,
                    pFileInfo->szFileType, aryKeyAndData.GetAt( i + 1 ) , FALSE ) ;
                strLog.Format( _T("Fail at start [ID:%s]%s---%s operation"), 
                    pFileInfo->szFileID, pFileInfo->szFileType, aryKeyAndData.GetAt( i + 1 ) );
                Log( strLog );
                break;
            }

                
            result = m_OprDriver.Invoke( dispid, (long)pFileInfo );   
            
            if( !GenerateEndOprNotification( m_dwOprCookie,pFileInfo->szFileID, 
                pFileInfo->szFileType, aryKeyAndData.GetAt( i + 1 ) , result ) )
            {				
				strLog.Format( _T("Fail at end %s---%s operation"), 
					pFileInfo->szFileType, aryKeyAndData.GetAt( i + 1 ) );
				Log( strLog ); 

				/**
				 * @hongliang.xin 2009-3-2
				 * if checked NV times is zero (means all files have not download completely) 
				 * or need check NV time is zero, break directly. 
				 */
				if(0 == nReadNVCount)
				{
					break;		
				}
				else
				{
					if(0 == i) //read flash and check NV failed
					{	
						bCheckNVSuccess = FALSE;
						strLog.Format( _T("Check NV failed and download %s again"), pFileInfo->szFileID );
						Log( strLog ); 
					}
				}

            }
/*
//#ifdef _DEBUG
#if 0
			// read flash failed
			if(nReadNVCount == 1 && i== 0)
			{
				result = 0;
			}
#else
			if(nReadNVCount == 1 && i== 0)
			{
				bCheckNVSuccess = FALSE;
			}
			// download failed
			if(nReadNVCount == 1 && i== 2)
			{
				result = 0;
			}
#endif
//#endif
*/
            if( !result )
            {				
                strLog.Format( _T("Fail at %s---%s operation"), 
                    pFileInfo->szFileType, aryKeyAndData.GetAt( i + 1 ) );
                Log( strLog );

				/**
				 * @hongliang.xin 2009-3-2
				 */
				if( nReadNVCount > 0)			
				{
					// read or download NV failed
					// recheck and download again
					i=aryKeyAndData.GetSize();
					strLog.Format( _T("Recheck and download %s again"), pFileInfo->szFileID );
				    Log( strLog );
				}

				break;    
            }	
			else
			{
			    /**
				 * @hongliang.xin 2009-3-2
				 * nReadNVCount>0 means checking NV is going on
				 * "i==0  && bCheckNVSuccess" means read NV and check successs
				 * notice: maybe uplevel need not backup NV, so callback always return S_OK
				 * so that there is no check action in uplevel actually
				 */
				if(nReadNVCount>0 && 0 == i && bCheckNVSuccess)
				{	
					i=aryKeyAndData.GetSize(); // set NV BMFiles process over
					nReadNVCount = -1;   // set success flag     
					strLog.Format( _T("Check %s success"), pFileInfo->szFileID );
					Log( strLog ); 
					break; //check success, end the rest process
				}//else bCheckNVSuccess == false, download again
			}
			
        }

		if(ohObject.GetDebugModeFlag(pFileInfo->szFileID))
		{
			result = m_OprDriver.SetDebugLogState( FALSE );
			if(!result)
			{
				strLog.Format( _T("Fail at setting [%s] debug mode: [FALSE]"), pFileInfo->szFileID );
                Log( strLog );
			}
		} 


        BOOL bSuccessful = TRUE;
        if( i < aryKeyAndData.GetSize())
        {
            bSuccessful = FALSE;
        }

        if( !GenerateEndFileOprNotification( m_dwOprCookie, pFileInfo->szFileID,
                    pFileInfo->szFileType, bSuccessful )  )
        {
            strLog.Format( _T("Fail at end %s file notification"), 
                pFileInfo->szFileType );
            Log( strLog );   
            EndProc( FALSE );
            continue;
        }

        if( !bSuccessful )
        {
            EndProc( FALSE );
            continue;
        }

		if(0 == nCheckNVTimes) // not need check NV
		{
			m_BMFileImpl.MoveNext();    

			if( m_BMFileImpl.IsEOF() )
			{
				// All file have been downloaded
				EndProc( TRUE );		
			}
		}
		else
		{
			//add by hongliang.xin 2009-3-2
			if( 0 == nReadNVCount) // has not start to check NV
			{
				m_BMFileImpl.MoveNext();
			}     

			if( m_BMFileImpl.IsEOF() )
			{
				bEof = TRUE;			
			}	

			if( -1 == nReadNVCount) // check NV success
			{
				bCheckNVSuccess = TRUE;
				nReadNVCount = 0;
				bEof = FALSE;
				EndProc( TRUE );
				continue;
			}
			else if(nReadNVCount>=(int)nCheckNVTimes)
			{
				strLog.Format( _T("Check NV %d times failed and terminate"),nCheckNVTimes);
				Log( strLog ); 
				bCheckNVSuccess = TRUE;
				nReadNVCount = 0;
				bEof = FALSE;
				EndProc( FALSE );
				continue;
			} 
			
			if(bEof && nReadNVCount < (int)nCheckNVTimes) 
			{
				if(m_BMFileImpl.SetCurBMFileInfo(_T("NV")))
				{
					BMFileInfo* pFileInfoTmp = m_BMFileImpl.GetCurrentBMFileInfo();
					_tcscpy(pFileInfoTmp->szFileID,_T("NV_REPEAT")); //start to check NV
					bCheckNVSuccess = TRUE;					

					/** 
					 * @hongliang.xin 2009-3-24
					 * if NV file type is "NV", it need recheck the NV
					 * not support "NV_NAND" to recheck.
					 */
					if(_tcsicmp( pFileInfoTmp->szFileType, _T("NV")) != 0 )
					{
						bCheckNVSuccess = TRUE;
						nReadNVCount = 0;
						bEof = FALSE;
						EndProc( TRUE );						
						continue;
					}
					
					nReadNVCount++;					
				}
				else
				{
					bCheckNVSuccess = TRUE;
					nReadNVCount = 0;
					bEof = FALSE;
					EndProc( TRUE );
				}
			}
		}

	}	
    	
    return 0L;
}

// Format of pSection
// "Key1 = data1\0Key2 = data2\0....Keyn = datan\0\0"
int CBootModeObj::EnumKeys(char* pSection,CStringArray* pKeys)
{
    ASSERT(pSection != NULL);
    ASSERT(pKeys != NULL);
    
    int number = 0;
    while(1)
    {
        CString strLine = pSection;
        int nLen = strLine.GetLength();
        if(0 == nLen)
        {
            // All keys are read
            break;
        }
        
        int nIndex = strLine.Find('=');
        if(-1 == nIndex)
        {
            // Not a valid key
            continue;
        }
        CString strKey = strLine.Left(nIndex);
        strKey.TrimLeft();
        strKey.TrimRight();
        pKeys->Add(strKey);
        
        CString strData = strLine.Right(nLen - nIndex - 1);
        strData.TrimLeft();
        strData.TrimRight();
        pKeys->Add(strData);
        
        number++;
        
        pSection += nLen + 1;        
    }
    
    return number;
}

void CBootModeObj::Log( LPCTSTR lpszLog )
{
    m_OprDriver.Log( lpszLog );    
}

STDMETHODIMP CBootModeObj::StartBootModeOperation(   DWORD lpBMFileInfo, 
                                                     UINT uFileCount, 
                                                     DWORD pOpenArgument, 
                                                     BOOL bBigEndian, 
                                                     DWORD dwOprCookie,
                                                     BOOL bRcvThread, 
                                                     const DWORD pReceiver,
                                                     BSTR lpbstrProgID)
{
    USES_CONVERSION;

    ASSERT( lpBMFileInfo != NULL );
    ASSERT( uFileCount > 0 );
    
// 	SAFE_FREE(m_pOprDriver);
// 
// 	m_pOprDriver = new CBootModeIntegOpr();
//     
//     if( m_pOprDriver == NULL )
//     {
//         Log( _T("The BootModeOperation object is not registered. "));
//         return BM_E_OPR_NOTREG;
//     }
    
    m_dwOprCookie = dwOprCookie;
    
    if(!m_BMFileImpl.InitBMFiles( (PBMFileInfo)lpBMFileInfo,uFileCount))
    {
        GenerateStartNotification( m_dwOprCookie, 0 );
        Log( _T("The  using file( FDL, NV ,etc ) is error. ") );
		//SAFE_FREE(m_pOprDriver);
        return BM_E_FILEINFO_ERROR;
    }  
	
    BOOL result = m_OprDriver.Initialize(OLE2T(lpbstrProgID),
											pOpenArgument,
											bBigEndian,
											dwOprCookie,
											bRcvThread,
											pReceiver);
    
    if( !result )
    {
        GenerateStartNotification( m_dwOprCookie, 0 );
        Log( _T("The channel occurs error. ") );
        m_BMFileImpl.ClearUpBMFiles();
        //SAFE_FREE(m_pOprDriver);  
        return BM_E_CHANNEL_FAILED;
    }
    
    if(!CreateBMThread( ))
    {
        GenerateStartNotification( m_dwOprCookie, 0 );
        Log( _T("Create download  thread fail. ") );   
		m_OprDriver.Uninitialize();
        m_BMFileImpl.ClearUpBMFiles();            
        //SAFE_FREE(m_pOprDriver);    
        return BM_E_CREATETHREAD_FAILED;
    }
    
    Log( _T("Start Boot Mode Operation success.") ); 
    return BM_S_OK;    
}

STDMETHODIMP CBootModeObj::StopBootModeOperation()
{    
    DestroyBMThread();

    Log( _T("Stop Boot Mode Operation") );    

	m_OprDriver.Uninitialize();

    m_BMFileImpl.ClearUpBMFiles();    
        
//    SAFE_FREE(m_pOprDriver);   

    return BM_S_OK;
}

STDMETHODIMP CBootModeObj::SetWaitTimeForNextChip( DWORD dwWaitTime /* = CHANGE_CHIP_TIMEOUT  */)
{
    m_dwWaitTime = dwWaitTime ;
    
    return BM_S_OK;
}

STDMETHODIMP CBootModeObj::SetCommunicateChannelPtr( LPVOID pCommunicateChannel  )
{
	m_OprDriver.SetChannel((long)pCommunicateChannel);    
    return S_OK;
}

STDMETHODIMP CBootModeObj::GetCommunicateChannelPtr( LPVOID* ppCommunicateChannel )
{
    long result = m_OprDriver.GetChannelPtr();
    *ppCommunicateChannel = (LPVOID)result;

    if( result ==  NULL )
    {
        return BM_E_FAILED;
    }
    return BM_S_OK ;
}

STDMETHODIMP CBootModeObj::SubscribeOperationObserver(THIS_ IBMOprObserver* pSink, 
                                                         ULONG uFlags,
                                                         LPDWORD lpdwCookie )
{  
	UNUSED_ALWAYS(uFlags);
    CSingleLock _lock( &m_CS, TRUE);
    
    DWORD dwCookie = m_dwNextObserverCookie;
    IBMOprObserver* p = NULL;
    do{
        p = NULL;
        if( !m_mapObserverRegs.Lookup( dwCookie, p) )
            break;
        dwCookie++;
        if( dwCookie == 0 )
            dwCookie++;
    }while( dwCookie != m_dwNextObserverCookie );
    
    if( p != NULL )
    {
        Log( _T("Subscribe Operation Observer fail."));
        return BM_E_REG_OBSERVER_FAILED;
    }
    
    m_mapObserverRegs.SetAt( dwCookie, pSink );
    pSink->AddRef();

    m_dwNextObserverCookie = dwCookie + 1;
    if( m_dwNextObserverCookie == 0 )
        m_dwNextObserverCookie++;
    
    *lpdwCookie = dwCookie;

    Log( _T("Subscribe Operation Observer success."));
    return BM_S_OK;
}

STDMETHODIMP CBootModeObj::UnsubscribeOperationObserver( THIS_ DWORD dwCookie )
{
    CSingleLock _lock( &m_CS, TRUE);

    IBMOprObserver* pObserver;
    if( !m_mapObserverRegs.Lookup( dwCookie, pObserver ) )
        return BM_E_FAILED;
        
    pObserver->Release();
    m_mapObserverRegs.RemoveKey( dwCookie );
	/* can not invoke log, maybe some object is not created */
//    Log( _T("Unsubscribe Operation Observer."));
    return BM_S_OK;
}

STDMETHODIMP_(const LPBYTE) CBootModeObj::GetReadBuffer( THIS )
{    
    long rlt = m_OprDriver.GetRecvBuffer();    
    return (const LPBYTE)rlt;
}

STDMETHODIMP_( DWORD) CBootModeObj::GetReadBufferSize( THIS )
{
    long dwSize = m_OprDriver.GetRecvBufferSize(); 
    return dwSize;    
}

