|
|
//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
//
// I2CSCRPT.C
// I2CScript class implementation.
// Main Include Module.
//
//==========================================================================;
extern "C" { #include <wdm.h>
}
#include <unknown.h>
#include "ks.h"
#include "ksmedia.h"
#include <ksdebug.h>
#include "i2script.h"
#include "wdmdebug.h"
//$REVIEW - Let's find a way to get the proper module name into this
//
#define MODULENAME "PhilTune"
#define MODULENAMEUNICODE L"PhilTune"
#define STR_MODULENAME MODULENAME
#define ENSURE do
#define END_ENSURE while( FALSE)
#define FAIL break
/*^^*
* CI2CScript() * Purpose : CI2CScript class constructor. * Performs checking of the I2C provider presence. Sets the script in the initial state. * * Inputs : PUINT puiError : pointer to return a completion error code * PHW_STREAM_REQUEST_BLOCK pSrb : pointer to HW_INITIALIZE SRB * * Outputs : none * Author : IKLEBANOV *^^*/ CI2CScript:: CI2CScript( PDEVICE_OBJECT pDeviceObject, NTSTATUS * pStatus ) { *pStatus = STATUS_SUCCESS;
m_dwI2CAccessKey = 0;
m_liOperationStartTime.QuadPart = 0;
m_i2cProviderInterface.i2cOpen = NULL; m_i2cProviderInterface.i2cAccess = NULL;
m_pdoDriver = NULL;
if( !InitializeAttachI2CProvider( &m_i2cProviderInterface, pDeviceObject)) { *pStatus = STATUS_NOINTERFACE; } else { // there was no error to get I2CInterface from the MiniVDD
m_pdoDriver = pDeviceObject; m_ulI2CAccessClockRate = I2C_FIXED_CLOCK_RATE; }
_DbgPrintF( DEBUGLVL_VERBOSE, ( "CI2CScript:CI2CScript() exit Error = %x\n", * pStatus) ); }
/*^^*
* LockI2CProvider() * Purpose : locks the I2CProvider for exclusive use * * Inputs : none * * Outputs : BOOL : retunrs TRUE, if the I2CProvider is locked * Author : IKLEBANOV *^^*/ BOOL CI2CScript::LockI2CProvider( void) { BOOL bResult; I2CControl i2cAccessBlock;
bResult = FALSE;
ENSURE { if(( m_i2cProviderInterface.i2cOpen == NULL) || ( m_i2cProviderInterface.i2cAccess == NULL) || ( m_pdoDriver == NULL)) FAIL;
i2cAccessBlock.Status = I2C_STATUS_NOERROR; if( m_i2cProviderInterface.i2cOpen( m_pdoDriver, TRUE, &i2cAccessBlock) != STATUS_SUCCESS) { _DbgPrintF( DEBUGLVL_ERROR, ( "CI2CScript: LockI2CProvider() bResult = %x\n", bResult) ); FAIL; }
if( i2cAccessBlock.Status != I2C_STATUS_NOERROR) { _DbgPrintF( DEBUGLVL_ERROR, ( "CI2CScript: LockI2CProvider() Status = %x\n", i2cAccessBlock.Status) ); FAIL; }
// the I2C Provider has granted access - save dwCookie for further use
m_dwI2CAccessKey = i2cAccessBlock.dwCookie;
bResult = TRUE;
} END_ENSURE;
return( bResult); }
/*^^*
* LockI2CProvider() * Purpose : locks the I2CProvider for exclusive use. Provides attempts to lock the * provider unless either the time-out condition or the attempt succeeded. * * Inputs : none * * Outputs : BOOL : retunrs TRUE, if the I2CProvider is locked * Author : IKLEBANOV *^^*/ BOOL CI2CScript::LockI2CProviderEx( void) { LARGE_INTEGER liTime;
m_liOperationStartTime.QuadPart = 0;
while( !LockI2CProvider()) { KeQuerySystemTime( &liTime);
if( m_liOperationStartTime.QuadPart) m_liOperationStartTime.QuadPart = liTime.QuadPart; else if( liTime.QuadPart - m_liOperationStartTime.QuadPart > I2CSCRIPT_TIMELIMIT_OPENPROVIDER) { // the time is expired - abort the initialization
return( FALSE); }
liTime.QuadPart = I2CSCRIPT_DELAY_OPENPROVIDER; KeDelayExecutionThread( KernelMode, FALSE, &liTime); }
return( TRUE); }
/*^^*
* GetI2CProviderLockStatus() * Purpose : retrieves I2CProvider lock status * * Inputs : none * * Outputs : BOOL : retunrs TRUE, if the I2CProvider has been locked * Author : IKLEBANOV *^^*/ BOOL CI2CScript::GetI2CProviderLockStatus( void) {
return( m_dwI2CAccessKey); }
/*^^*
* ReleaseI2CProvider() * Purpose : releases the I2CProvider for other clients' use * * Inputs : none * * Outputs : BOOL : retunrs TRUE, if the I2CProvider is released * Author : IKLEBANOV *^^*/ BOOL CI2CScript::ReleaseI2CProvider( void) { BOOL bResult; I2CControl i2cAccessBlock;
bResult = FALSE;
ENSURE { if(( m_i2cProviderInterface.i2cOpen == NULL) || ( m_i2cProviderInterface.i2cAccess == NULL) || ( m_pdoDriver == NULL)) // the I2CProvider was not found
FAIL;
i2cAccessBlock.Status = I2C_STATUS_NOERROR; i2cAccessBlock.dwCookie = m_dwI2CAccessKey; i2cAccessBlock.ClockRate = m_ulI2CAccessClockRate; if( m_i2cProviderInterface.i2cOpen( m_pdoDriver, FALSE, &i2cAccessBlock) != STATUS_SUCCESS) { _DbgPrintF( DEBUGLVL_ERROR, ( "CI2CScript: ReleaseI2CProvider() bResult = %x\n", bResult) ); FAIL; }
if( i2cAccessBlock.Status != I2C_STATUS_NOERROR) { _DbgPrintF( DEBUGLVL_ERROR, ( "CI2CScript: ReleaseI2CProvider() bResult = %x\n", bResult) ); FAIL; }
m_dwI2CAccessKey = 0; bResult = TRUE;
} END_ENSURE;
return( bResult); }
/*^^*
* PerformI2CPacketOperation() * Purpose : synchronosly executes I2C access packet. It assumed to be executed at Low priority. * The function does not return until the I2C session is done. The execution * is not dependent on the I2C Provider lock status * * Inputs : PI2CPacket pI2CPacket : pointer to I2C access packet * * Outputs : BOOL : returns TRUE, if I2C operation was carried out successfuly * The error status is returned via uchI2CResult field of the PI2CPacket * Author : IKLEBANOV *^^*/ BOOL CI2CScript::PerformI2CPacketOperation( IN OUT PI2CPacket pI2CPacket) { BOOL bResult;
if( GetI2CProviderLockStatus()) // the Provider was locked before and we're not going to change it
bResult = ExecuteI2CPacket( pI2CPacket); else { // the Provider was not locked and it's our responsibility to lock it first,
// execute I2C operation and release it after the use
if( LockI2CProviderEx()) { bResult = ExecuteI2CPacket( pI2CPacket); ReleaseI2CProvider(); } else bResult = FALSE; }
return( bResult); }
/*^^*
* ExecuteI2CPacket() * Purpose : synchronosly executes I2C access packet. It assumed to be executed at Low priority. * The function does not return until the I2C session is done. This kind of access * is used during initialization ( boot up) time only. This function should be * called only after the I2CProvider was locked for exclusive service * * Inputs : PI2CPacket pI2CPacket : pointer to I2C access packet * * Outputs : BOOL : returns TRUE, if I2C operation was carried out successfuly * The error status is returned via uchI2CResult field of the PI2CPacket * Author : IKLEBANOV *^^*/ BOOL CI2CScript::ExecuteI2CPacket( IN OUT PI2CPacket pI2CPacket) { UINT nError, cbCount; UCHAR uchValue; UCHAR uchI2CResult = I2C_STATUS_ERROR;
ENSURE { I2CControl i2cAccessBlock;
if(( nError = CheckI2CScriptPacket( pI2CPacket)) != I2CSCRIPT_NOERROR) FAIL;
// we'll use I2CProvider interface, assuming there is a syncronous provider
// for asynchronous provider some work has to be added. 16 bits emulation is
// not supported at this time either. This implementation does not support
// Read-Modify-Write request either
ENSURE { UINT nIndex;
i2cAccessBlock.dwCookie = m_dwI2CAccessKey; i2cAccessBlock.ClockRate = m_ulI2CAccessClockRate;
// We assume the last byte in the buffer belongs to the Write operation
// after Read-Modify, is specified.
cbCount = ( pI2CPacket->usFlags & I2COPERATION_READWRITE) ? ( pI2CPacket->cbWriteCount - 1) : ( pI2CPacket->cbWriteCount);
if( cbCount) { // implement a write request
// apply START condition with the I2C chip address first
i2cAccessBlock.Flags = I2C_FLAGS_START | I2C_FLAGS_ACK; i2cAccessBlock.Command = I2C_COMMAND_WRITE; i2cAccessBlock.Data = pI2CPacket->uchChipAddress & 0xFE; if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) != I2C_STATUS_NOERROR) FAIL;
i2cAccessBlock.Flags = I2C_FLAGS_ACK; for( nIndex = 0; nIndex < cbCount; nIndex ++) { // write the data from the buffer
i2cAccessBlock.Data = pI2CPacket->puchWriteBuffer[nIndex]; if(( nIndex == cbCount - 1) && !( pI2CPacket->usFlags & I2COPERATION_RANDOMACCESS)) // the last byte to write - apply STOP condition, if no
// I2COPERATION_RANDOMACCESS flag is specified
i2cAccessBlock.Flags |= I2C_FLAGS_STOP;
if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) != I2C_STATUS_NOERROR) break; } if( nIndex != cbCount) FAIL; /* // STOP condition is applied withe the last byte to be written
// apply stop condition as the end of write operation
i2cAccessBlock.Flags = I2C_FLAGS_STOP; i2cAccessBlock.Command = I2C_COMMAND_NULL; m_i2cProviderInterface.i2cAccess( m_pdoDriver, &i2cAccessBlock); */ }
if( pI2CPacket->cbReadCount) { // implement a read request
// apply START condition with the I2C chip address first
i2cAccessBlock.Flags = I2C_FLAGS_START | I2C_FLAGS_ACK; i2cAccessBlock.Command = I2C_COMMAND_WRITE; i2cAccessBlock.Data = pI2CPacket->uchChipAddress | 0x01; if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) != I2C_STATUS_NOERROR) FAIL;
i2cAccessBlock.Flags = I2C_FLAGS_ACK; i2cAccessBlock.Command = I2C_COMMAND_READ; for( nIndex = 0; nIndex < pI2CPacket->cbReadCount; nIndex ++) { // read the data to the buffer
if( nIndex == ( UINT)( pI2CPacket->cbReadCount - 1)) { // don't apply ACK at the last read - read operation termination
i2cAccessBlock.Flags &= ~I2C_FLAGS_ACK; // also apply STOP condition for the last byte
i2cAccessBlock.Flags |= I2C_FLAGS_STOP; }
if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) != I2C_STATUS_NOERROR) break; pI2CPacket->puchReadBuffer[nIndex] = i2cAccessBlock.Data; } if( nIndex != pI2CPacket->cbReadCount) FAIL;
/* // STOP condition is applied with the last byte to be read
// apply stop condition as the end of read operation
i2cAccessBlock.Flags = I2C_FLAGS_STOP; i2cAccessBlock.Command = I2C_COMMAND_NULL; m_i2cProviderInterface.i2cAccess( m_pdoDriver, &i2cAccessBlock); */ if( pI2CPacket->usFlags & I2COPERATION_READWRITE) { // write operation should be taken care again, the last byte in the pbyWriteBuffer
// should be constructed from the value read back and the binary operations OR and AND
// with the values specified in the packet
uchValue = pI2CPacket->puchReadBuffer[pI2CPacket->cbReadCount - 1]; uchValue &= pI2CPacket->uchANDValue; pI2CPacket->puchWriteBuffer[pI2CPacket->cbWriteCount - 1] = uchValue | pI2CPacket->uchORValue;
if( pI2CPacket->cbWriteCount) { // implement a write request
// apply START condition with the I2C chip address first
i2cAccessBlock.Flags = I2C_FLAGS_START | I2C_FLAGS_ACK; i2cAccessBlock.Command = I2C_COMMAND_WRITE; i2cAccessBlock.Data = pI2CPacket->uchChipAddress & 0xFE; if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) != I2C_STATUS_NOERROR) FAIL;
i2cAccessBlock.Flags = I2C_FLAGS_ACK; for( nIndex = 0; nIndex < pI2CPacket->cbWriteCount; nIndex ++) { // write the data from the buffer
i2cAccessBlock.Data = pI2CPacket->puchWriteBuffer[nIndex]; if( nIndex == ( UINT)( pI2CPacket->cbWriteCount - 1)) // the last byte to write - apply STOP condition
i2cAccessBlock.Flags |= I2C_FLAGS_STOP;
if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) != I2C_STATUS_NOERROR) break; }
if( nIndex != pI2CPacket->cbWriteCount) FAIL; /* // STOP condition is applied withe the last byte to be written
// apply stop condition as the end of write operation
i2cAccessBlock.Flags = I2C_FLAGS_STOP; i2cAccessBlock.Command = I2C_COMMAND_NULL; m_i2cProviderInterface.i2cAccess( m_pdoDriver, &i2cAccessBlock); */ } } }
uchI2CResult = I2C_STATUS_NOERROR;
} END_ENSURE;
if( uchI2CResult == I2C_STATUS_ERROR) { // there was an error during accessing I2C - issue Reset command
i2cAccessBlock.Command = I2C_COMMAND_RESET; AccessI2CProvider( m_pdoDriver, &i2cAccessBlock); }
pI2CPacket->uchI2CResult = uchI2CResult;
return( TRUE);
} END_ENSURE;
_DbgPrintF( DEBUGLVL_VERBOSE, ( "CI2CScript:ExecuteI2CPacket() nError = %x", nError) ); return( FALSE); }
/*^^*
* CheckI2CScriptPacket() * Purpose : checks integrity of the I2C control package * * Inputs : PI2CPacket pI2CPacket : pointer to I2C access packet * * Outputs : BOOL : returns TRUE, if I2C control package is a valid one * * Author : IKLEBANOV *^^*/ UINT CI2CScript::CheckI2CScriptPacket( IN PI2CPacket pI2CPacket) { UINT nPacketError;
ENSURE { if(( m_i2cProviderInterface.i2cOpen == NULL) || ( m_i2cProviderInterface.i2cAccess == NULL) || ( m_pdoDriver == NULL)) { // the I2CProvider was not found
nPacketError = I2CSCRIPT_ERROR_NOPROVIDER; FAIL; }
if(( !pI2CPacket->cbWriteCount) && ( !pI2CPacket->cbReadCount)) { // nothing to do
nPacketError = I2CSCRIPT_ERROR_NODATA; FAIL; }
if((( pI2CPacket->cbWriteCount) && ( pI2CPacket->puchWriteBuffer == NULL)) || (( pI2CPacket->cbReadCount) && ( pI2CPacket->puchReadBuffer == NULL))) { // NULL pointer, when the data is specified
nPacketError = I2CSCRIPT_ERROR_NOBUFFER; FAIL; }
if(( pI2CPacket->usFlags & I2COPERATION_READWRITE) && ( !pI2CPacket->cbWriteCount)) { // if Read-Modify-Write is specified, the Write data should be present
nPacketError = I2CSCRIPT_ERROR_READWRITE; FAIL; }
nPacketError = I2CSCRIPT_NOERROR;
} END_ENSURE;
return( nPacketError); }
/*^^*
* ClearScript() * Purpose : clears I2CScript to the NULL state - no I2C operations are on hold. * * Inputs : none * * Outputs : none * Author : IKLEBANOV *^^*/ void CI2CScript::ClearScript( void) {
m_nExecutionIndex = 0; m_nScriptLength = 0; m_pfnReturnWhenDone = NULL; m_bExecutionInProcess = FALSE; }
/*^^*
* AppendToScript() * Purpose : appends a I2CPacket to the bottom of the I2CScript. * The 16 bits emulation is not implemented at this time. * * Inputs : PI2CPacket pI2CPacket - pointer to the I2C packet to append * * Outputs : BOOL : returns TRUE, if the packet was successfully appended. * FALSE might happend if the I2CPacket is a bad one, or overflow occurs * Author : IKLEBANOV *^^*/ BOOL CI2CScript::AppendToScript( PI2CPacket pI2CPacket) { UINT nError, nScriptIndex; UINT nIndex, cbCount;
ENSURE { PI2CScriptPrimitive pI2CPrimitive;
if(( nError = CheckI2CScriptPacket( pI2CPacket)) != I2CSCRIPT_NOERROR) FAIL; nError = I2CSCRIPT_ERROR_OVERFLOW;
// m_nExecutionIndex is used as a Script build index. We will work with a local copy of it
// first to ensure we have no overflow
nScriptIndex = m_nExecutionIndex; pI2CPrimitive = &m_i2cScript[nScriptIndex];
// We assume the last byte in the buffer belongs to the Write operation
// after Read-Modify, is specified.
cbCount = ( pI2CPacket->usFlags & I2COPERATION_READWRITE) ? \ ( pI2CPacket->cbWriteCount - 1) : ( pI2CPacket->cbWriteCount);
if( cbCount) { // I2C Chip address should be taken care of first
pI2CPrimitive->ulCommand = I2C_COMMAND_WRITE; pI2CPrimitive->byData = pI2CPacket->uchChipAddress; pI2CPrimitive->byANDData = 0xFE; pI2CPrimitive->byORData = 0x00; pI2CPrimitive->ulProviderFlags = I2C_FLAGS_START | I2C_FLAGS_ACK; pI2CPrimitive->byFlags = 0x0;
// check the Script length
if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM) FAIL; pI2CPrimitive ++;
// I2C write buffer should be taken care of.
for( nIndex = 0; nIndex < cbCount; nIndex ++) { pI2CPrimitive->ulCommand = I2C_COMMAND_WRITE; pI2CPrimitive->byData = pI2CPacket->puchWriteBuffer[nIndex]; pI2CPrimitive->byORData = 0x00; pI2CPrimitive->byANDData = 0xFF; pI2CPrimitive->ulProviderFlags = I2C_FLAGS_ACK; pI2CPrimitive->byFlags = 0x0;
if( nIndex == cbCount - 1) // this is the last byte to be written - apply STOP
pI2CPrimitive->ulProviderFlags |= I2C_FLAGS_STOP;
// check the Script length
if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM) break; pI2CPrimitive ++; }
// check the Script length
if( nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM) FAIL;
/*
// Stop condition is applied with the last byte to be written
// We finished Write portion here, whether it's a Write only, Read-Modify-Write operation
pI2CPrimitive->ulCommand = I2C_COMMAND_NULL; pI2CPrimitive->ulProviderFlags = I2C_FLAGS_STOP; pI2CPrimitive->byFlags = 0x0;
// check the Script length
if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM) FAIL; pI2CPrimitive ++; */ }
// We have to see, if there is a Read operation involved
if( pI2CPacket->cbReadCount) { // I2C Chip address should be taken care of first
pI2CPrimitive->ulCommand = I2C_COMMAND_WRITE; pI2CPrimitive->byData = pI2CPacket->uchChipAddress; pI2CPrimitive->byANDData = 0xFE; pI2CPrimitive->byORData = 0x01; pI2CPrimitive->ulProviderFlags = I2C_FLAGS_START | I2C_FLAGS_ACK; pI2CPrimitive->byFlags = 0x0;
// check the Script length
if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM) FAIL; pI2CPrimitive ++;
// I2C read buffer should be taken care of. We assume the last byte in the buffer belongs to
// the Write operation after Read-Modify, is specified.
for( nIndex = 0; nIndex < pI2CPacket->cbReadCount; nIndex ++) { pI2CPrimitive->ulCommand = I2C_COMMAND_READ; if( nIndex == ( UINT)( pI2CPacket->cbReadCount - 1)) { pI2CPrimitive->ulProviderFlags = I2C_FLAGS_STOP; pI2CPrimitive->byFlags = pI2CPacket->usFlags & I2COPERATION_READWRITE; } else { pI2CPrimitive->ulProviderFlags = I2C_FLAGS_ACK; pI2CPrimitive->byFlags = 0x0; }
// check the Script length
if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM) break; pI2CPrimitive ++; }
// check the Script length
if( nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM) FAIL;
/* // Stop condition is applied with the last byte to be read
// We finished Read portion here, whether it's a Read only, Read-Modify-Write operation
pI2CPrimitive->ulCommand = I2C_COMMAND_NULL; pI2CPrimitive->ulProviderFlags = I2C_FLAGS_STOP; pI2CPrimitive->byFlags = 0x0;
// check the Script length
if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM) FAIL; pI2CPrimitive ++; */ }
// the last thing left to do, is to implement Write after Read-Modify, if specified
if( pI2CPacket->usFlags & I2COPERATION_READWRITE) { // I2C Chip address should be taken care of first
pI2CPrimitive->ulCommand = I2C_COMMAND_WRITE; pI2CPrimitive->byData = pI2CPacket->uchChipAddress; pI2CPrimitive->byANDData = 0xFE; pI2CPrimitive->byORData = 0x00; pI2CPrimitive->ulProviderFlags = I2C_FLAGS_START | I2C_FLAGS_ACK; pI2CPrimitive->byFlags = 0x0;
// check the Script length
if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM) FAIL; pI2CPrimitive ++;
// I2C write buffer should be taken care of.
for( nIndex = 0; nIndex < pI2CPacket->cbWriteCount; nIndex ++) { pI2CPrimitive->ulCommand = I2C_COMMAND_WRITE; pI2CPrimitive->byData = pI2CPacket->puchWriteBuffer[nIndex]; pI2CPrimitive->ulProviderFlags = I2C_FLAGS_ACK; if( nIndex == ( UINT)( pI2CPacket->cbWriteCount - 1)) { // it's time to write the byte modified after the Read operation
pI2CPrimitive->byORData = pI2CPacket->uchORValue; pI2CPrimitive->byANDData = pI2CPacket->uchANDValue; pI2CPrimitive->byFlags = I2COPERATION_READWRITE; // apply STOP condition with the last byte to be read
pI2CPrimitive->ulProviderFlags |= I2C_FLAGS_STOP; } else { pI2CPrimitive->byORData = 0x00; pI2CPrimitive->byANDData = 0xFF; pI2CPrimitive->byFlags = 0x0; }
// check the Script length
if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM) break; pI2CPrimitive ++; }
// check the Script length
if( nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM) FAIL;
/* // Stop condition is applied with the last byte to be written
// We finished Write portion here, whether it's a Write only, Read-Modify-Write operation
pI2CPrimitive->ulCommand = I2C_COMMAND_NULL; pI2CPrimitive->ulProviderFlags = I2C_FLAGS_STOP; pI2CPrimitive->byFlags = 0x0;
// check the Script length
if( ++ nScriptIndex >= I2CSCRIPT_LENGTH_MAXIMUM) FAIL; pI2CPrimitive ++; */ }
// the Packet was added succesfully to the Script. Modify the Script propertirs
m_nExecutionIndex = nScriptIndex; m_nScriptLength = nScriptIndex; return( TRUE);
} END_ENSURE;
_DbgPrintF( DEBUGLVL_VERBOSE, ( "CI2CScript:AppendToScript() nError = %x", nError) ); return( FALSE); }
/*^^*
* ExecuteScript() * Purpose : triggers the execution of previously built I2CScript. This function is also * responsible for allocating I2CProvider for its own exclusive use. * * Inputs : PIRP pIrp * PHWCompletionRoutine pfnScriptCompletion: function pointer will be called, * when the script execution is completed. Indicates the Script execution * is to be carried out asynchronously. * * Outputs : BOOL : returns TRUE, if the execution was successfully triggered. * FALSE might happend if the Script has not been built by the time of the call * * Note : if pfnScriptExecuted is NULL pointer, the Script will be executed synchronously * * Author : IKLEBANOV *^^*/ BOOL CI2CScript::ExecuteScript( IN PIRP pIrp, IN PHWCompletionRoutine pfnScriptCompletion) {
ENSURE { if( pfnScriptCompletion != NULL) // not supported at this point. The idea is to create a new system thread,
// where the Script to be executed. When the Script will be copleted,
// call-back is called and the thred terminates itself.
FAIL;
if( !m_nExecutionIndex) FAIL;
// there is not a NULL Script - proceed
m_nScriptLength = m_nExecutionIndex; m_nExecutionIndex = m_nCompletionIndex = 0;
if( !GetI2CProviderLockStatus()) // The provider was not locked prior the Script execution
if( !LockI2CProviderEx()) FAIL;
InterpreterScript();
ReleaseI2CProvider();
return( TRUE);
} END_ENSURE;
return( FALSE); }
/*^^*
* InterpreterScript() * Purpose : interpreters the I2CScript line by line. The Script is not cleaned up * after the completion to allow to client retrive the results of * the script execution. It's the client responsibility to clean it up * upon the results retrieving * * Inputs : none * Outputs : none * * Author : IKLEBANOV *^^*/ void CI2CScript::InterpreterScript( void) { UINT nScriptIndex, nIndex; I2CControl i2cAccessBlock;
m_bExecutionInProcess = TRUE;
i2cAccessBlock.dwCookie = m_dwI2CAccessKey; i2cAccessBlock.ClockRate = m_ulI2CAccessClockRate;
// We'll interpreter every line of the Script and call the I2C Provider to
// execute it. It's assumed the I2CProvider is a syncronous one. If it's not the
// case, the special care should be taken of based upon returned value I2C_STATUS_BUSY
// in the Status.
for( nScriptIndex = 0; nScriptIndex < m_nScriptLength; nScriptIndex ++) { i2cAccessBlock.Command = m_i2cScript[nScriptIndex].ulCommand; i2cAccessBlock.Flags = m_i2cScript[nScriptIndex].ulProviderFlags; if( i2cAccessBlock.Command == I2C_COMMAND_WRITE) { i2cAccessBlock.Data = m_i2cScript[nScriptIndex].byData; i2cAccessBlock.Data &= m_i2cScript[nScriptIndex].byANDData; i2cAccessBlock.Data |= m_i2cScript[nScriptIndex].byORData; }
if( AccessI2CProvider( m_pdoDriver, &i2cAccessBlock) == I2C_STATUS_ERROR) break;
// check, wether it's a Read operation - save result
if( i2cAccessBlock.Command == I2C_COMMAND_READ) { m_i2cScript[nScriptIndex].byData = i2cAccessBlock.Data; // check, if this data belongs to Read-Modify-Write operation
if( m_i2cScript[nScriptIndex].byFlags & I2COPERATION_READWRITE) { // let's look for the next I2COPERATION_READWRITE flag - it is the pair
for( nIndex = nScriptIndex; nIndex < m_nScriptLength; nIndex ++) if(( m_i2cScript[nIndex].ulCommand == I2C_COMMAND_WRITE) && ( m_i2cScript[nIndex].byFlags & I2COPERATION_READWRITE)) break;
if( nIndex >= m_nScriptLength) // the Script got corrupted
break;
m_i2cScript[nIndex].byData = i2cAccessBlock.Data; } } }
m_nCompletionIndex = nScriptIndex;
m_bExecutionInProcess = FALSE; }
/*^^*
* AccessI2CProvider() * Purpose : provide synchronous type of access to I2CProvider * * Inputs : PDEVICE_OBJECT pdoDriver : pointer to the client's device object * PI2CControl pi2cAccessBlock : pointer to a composed I2C access block * * Outputs : UINT : status of the I2C operation I2C_STATUS_NOERROR or I2C_STATUS_ERROR * * Author : IKLEBANOV *^^*/ UINT CI2CScript:: AccessI2CProvider( PDEVICE_OBJECT pdoClient, PI2CControl pi2cAccessBlock) { UINT uiStatus; LARGE_INTEGER liTime;
do { // this loop is infinitive. It has to be taken care of
ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL); if( m_i2cProviderInterface.i2cAccess( pdoClient, pi2cAccessBlock) != STATUS_SUCCESS) { uiStatus = I2C_STATUS_ERROR; break; }
if( pi2cAccessBlock->Status != I2C_STATUS_BUSY) { uiStatus = pi2cAccessBlock->Status; break; }
liTime.QuadPart = I2CSCRIPT_DELAY_GETPROVIDERSTATUS; ::KeDelayExecutionThread( KernelMode, FALSE, &liTime);
pi2cAccessBlock->Command = I2C_COMMAND_STATUS;
} while( TRUE);
return( uiStatus); }
/*^^*
* GetScriptResults() * Purpose : returns result of the executed Script * This function idealy is called twice: * first time with the puchReadBuffer = NULL to retrive the number of bytes read * second time - to fill in the pointer * Inputs : PUINT puiReadCount : pointer to the counter of the bytes were read * PUCH puchReadBuffer : pointer to the buffer to put the data * * Outputs : UINT : status of the I2C operation * If the status is I2C_STATUS_ERROR, puiReadCount will contain the step, where * I2CScript failed * Author : IKLEBANOV *^^*/ UINT CI2CScript::GetScriptResults( PUINT puiReadCount, PUCHAR puchReadBuffer) { UINT nScriptIndex, nCount;
ASSERT( puiReadCount != NULL);
if( m_bExecutionInProcess) return( I2C_STATUS_BUSY);
if( m_nScriptLength != m_nCompletionIndex) { // if the case of failure, step where I2CScript failed is return
// instead of Read Counter. The returned status indicates the
// failure
* puiReadCount = m_nCompletionIndex;
return( I2C_STATUS_ERROR); } else { nCount = 0;
for( nScriptIndex = 0; nScriptIndex < m_nCompletionIndex; nScriptIndex ++) { if( m_i2cScript[nScriptIndex].ulCommand == I2C_COMMAND_READ) { if( puchReadBuffer != NULL) // fill in the supplied buffer
puchReadBuffer[nCount] = m_i2cScript[nScriptIndex].byData; nCount ++; } }
* puiReadCount = nCount;
return( I2C_STATUS_NOERROR); } }
/*^^*
* InitializeAttachI2CProvider() * Purpose : gets the pointer to the parent I2C Provider interface using * several IRP_MJ_??? functions. * This function will be called at Low priority * * Inputs : I2CINTERFACE * pI2CInterface : pointer to the Interface to be filled in * PDEVICE_OBJECT pDeviceObject : MiniDriver device object, which is a child of I2C Master * * Outputs : BOOL - returns TRUE, if the interface was found * Author : IKLEBANOV *^^*/ BOOL CI2CScript::InitializeAttachI2CProvider( I2CINTERFACE * pI2CInterface, PDEVICE_OBJECT pDeviceObject) { BOOL bResult;
// try the new path
bResult = LocateAttachI2CProvider( pI2CInterface, pDeviceObject, IRP_MJ_PNP); if(( pI2CInterface->i2cOpen == NULL) || ( pI2CInterface->i2cAccess == NULL)) { // TRAP;
_DbgPrintF( DEBUGLVL_ERROR, ( "CI2CScript(): interface has NULL pointers\n") ); bResult = FALSE; }
return( bResult); }
/*^^*
* LocateAttachI2CProvider() * Purpose : gets the pointer to the parent I2C Provider interface * This function will be called at Low priority * * Inputs : I2CINTERFACE * pI2CInterface : pointer to the Interface to be filled in * PDEVICE_OBJECT pDeviceObject : MiniDriver device object, which is a child of I2C Master * int nIrpMajorFunction : IRP major function to query the I2C Interface * * Outputs : BOOL - returns TRUE, if the interface was found * Author : IKLEBANOV *^^*/ BOOL CI2CScript::LocateAttachI2CProvider( I2CINTERFACE * pI2CInterface, PDEVICE_OBJECT pDeviceObject, int nIrpMajorFunction) { PIRP pIrp; BOOL bResult = FALSE;
ENSURE { PIO_STACK_LOCATION pNextStack; NTSTATUS ntStatus; KEVENT Event;
pIrp = IoAllocateIrp( pDeviceObject->StackSize, FALSE); if( pIrp == NULL) { // TRAP;
_DbgPrintF( DEBUGLVL_ERROR, ( "CI2CScript(): can not allocate IRP\n") ); FAIL; }
pNextStack = IoGetNextIrpStackLocation( pIrp); if( pNextStack == NULL) { // TRAP;
_DbgPrintF( DEBUGLVL_ERROR, ( "CI2CScript(): can not allocate NextStack\n") ); FAIL; }
//$REVIEW - Should change function decl to make nIrpMajorFunction be UCHAR - TCP
pNextStack->MajorFunction = (UCHAR) nIrpMajorFunction; pNextStack->MinorFunction = IRP_MN_QUERY_INTERFACE; KeInitializeEvent( &Event, NotificationEvent, FALSE);
IoSetCompletionRoutine( pIrp, I2CScriptIoSynchCompletionRoutine, &Event, TRUE, TRUE, TRUE);
pNextStack->Parameters.QueryInterface.InterfaceType = ( struct _GUID *)&GUID_I2C_INTERFACE; pNextStack->Parameters.QueryInterface.Size = sizeof( I2CINTERFACE); pNextStack->Parameters.QueryInterface.Version = 1; pNextStack->Parameters.QueryInterface.Interface = ( PINTERFACE)pI2CInterface; pNextStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
ntStatus = IoCallDriver( pDeviceObject, pIrp);
if( ntStatus == STATUS_PENDING) KeWaitForSingleObject( &Event, Suspended, KernelMode, FALSE, NULL); if(( pI2CInterface->i2cOpen == NULL) || ( pI2CInterface->i2cAccess == NULL)) { _DbgPrintF( DEBUGLVL_ERROR, ( "CI2CScript(): interface has NULL pointers\n") ); FAIL; } bResult = TRUE;
} END_ENSURE;
if( pIrp != NULL) IoFreeIrp( pIrp);
return( bResult); }
/*^^*
* I2CScriptIoSynchCompletionRoutine() * Purpose : This routine is for use with synchronous IRP processing. * All it does is signal an event, so the driver knows it and can continue. * * Inputs : PDEVICE_OBJECT DriverObject : Pointer to driver object created by system * PIRP pIrp : Irp that just completed * PVOID Event : Event we'll signal to say Irp is done * * Outputs : none * Author : IKLEBANOV *^^*/ extern "C" NTSTATUS I2CScriptIoSynchCompletionRoutine( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID Event) {
KeSetEvent(( PKEVENT)Event, 0, FALSE); return( STATUS_MORE_PROCESSING_REQUIRED); }
/*
* WriteSeq() * Purpose : Write a specified sequence to address specified. * * * Inputs : UCHAR addr : I2CAddress * UCHAR *p_seq : sequence * USHORT len : length of the sequence * * Outputs : BOOL - TRUE if operation succeeded else FALSE * Author : MM * */ BOOL CI2CScript::WriteSeq(UCHAR addr, UCHAR *p_seq, USHORT len) {
I2CPacket i2cPacket; LARGE_INTEGER liTime;
// Init rest of I2CPacket
i2cPacket.usFlags = I2COPERATION_WRITE; i2cPacket.uchChipAddress = addr; i2cPacket.cbReadCount = 0; i2cPacket.cbWriteCount = len; i2cPacket.puchReadBuffer = NULL; i2cPacket.puchWriteBuffer = p_seq;
int counter = 0;
// Somewhat arbitrary max of 1 second.
while (!LockI2CProviderEx()) { if (counter++ >= 100) { // ReleaseI2CProvider();
return(FALSE); }
liTime.QuadPart = 100000; KeDelayExecutionThread(KernelMode, FALSE, &liTime); // = 10 milliseconds
}
/*
if(!CheckInterface(addr)) { ReleaseI2CProvider(); return FALSE; } */ ExecuteI2CPacket(&i2cPacket); ReleaseI2CProvider();
//DebugInfo(("CI2CScript::WriteSeq(): Inside\n"));
if (i2cPacket.uchI2CResult != I2C_STATUS_NOERROR) { _DbgPrintF( DEBUGLVL_ERROR,("CI2CScript::WriteSeq(): Error\n")); return(FALSE); }
return(TRUE); }
/*
* ReadSeq() * Purpose : Read a specified number of bytes from address specified. * * * Inputs : UCHAR addr : I2CAddress * UCHAR *p_seq : sequence * USHORT len : length of the sequence * * Outputs : BOOL - TRUE if operation succeeded else FALSE * Author : MM * * */ BOOL CI2CScript::ReadSeq(UCHAR addr, UCHAR *p_seq, USHORT len) {
I2CPacket i2cPacket; LARGE_INTEGER liTime;
// Init rest of I2CPacket
i2cPacket.usFlags = I2COPERATION_READ; i2cPacket.uchChipAddress = addr; i2cPacket.cbReadCount = len; i2cPacket.cbWriteCount = 0; i2cPacket.puchReadBuffer = p_seq; i2cPacket.puchWriteBuffer = NULL;
int counter = 0; // Somewhat arbitrary max of 1 second.
while (!LockI2CProviderEx()) { if (counter++ >= 100) { // ReleaseI2CProvider();
return(FALSE); }
liTime.QuadPart = 100000; KeDelayExecutionThread(KernelMode, FALSE, &liTime); // = 10 milliseconds
}
/*
if(!CheckInterface(addr)) { ReleaseI2CProvider(); return FALSE; } */ ExecuteI2CPacket(&i2cPacket); ReleaseI2CProvider();
// DebugInfo(("CI2CScript::ReadSeq(): Inside\n"));
if (i2cPacket.uchI2CResult != I2C_STATUS_NOERROR) { _DbgPrintF( DEBUGLVL_ERROR,("CI2CScript::ReadSeq(): Error\n")); return(FALSE); }
return(TRUE); }
/*
* CombinedSeq() * Purpose : Write a specified sequence and then read a specified number of * bytes from address specified. * * * Inputs : UCHAR addr : I2CAddress * UCHAR seqWr[] : write sequence * USHORT lenWr : length of the write sequence * UCHAR seqRd[] : read sequence * USHORT lenRd : length of the read sequence * * Outputs : BOOL - TRUE if operation succeeded else FALSE * Author : MM * * */
BOOL CI2CScript::CombinedSeq(UCHAR addr, UCHAR seqWr[], USHORT lenWr, UCHAR seqRd[], USHORT lenRd) {
I2CPacket i2cPacket; LARGE_INTEGER liTime;
// Init rest of I2CPacket
i2cPacket.usFlags = I2COPERATION_READWRITE; i2cPacket.uchChipAddress = addr; i2cPacket.cbReadCount = lenRd; i2cPacket.cbWriteCount = lenWr; i2cPacket.puchReadBuffer = seqRd; i2cPacket.puchWriteBuffer = seqWr;
int counter = 0; // Somewhat arbitrary max of 1 second.
while (!LockI2CProviderEx()) { if (counter++ >= 100) { // ReleaseI2CProvider();
return(FALSE); }
liTime.QuadPart = 100000; KeDelayExecutionThread(KernelMode, FALSE, &liTime); // = 10 milliseconds
}
if(!CheckInterface(addr)) { ReleaseI2CProvider(); return FALSE; }
ExecuteI2CPacket(&i2cPacket); ReleaseI2CProvider();
//DebugInfo(("CI2CScript::CombinedSeq(): Inside\n"));
if (i2cPacket.uchI2CResult != I2C_STATUS_NOERROR) { return(FALSE); }
return(TRUE); }
/*
* CheckInterface() * Purpose : Check if I2C Interface is working by reading a byte * from the specified address * * Inputs : UCHAR addr : I2CAddress * * Outputs : BOOL - TRUE if operation succeeded else FALSE * Author : MM * * */
BOOL CI2CScript::CheckInterface(UCHAR addr) {
I2CPacket i2cPacket; LARGE_INTEGER liTime; UCHAR ucData;
// Init rest of I2CPacket
i2cPacket.usFlags = I2COPERATION_READ; i2cPacket.uchChipAddress = addr; i2cPacket.cbReadCount = 1; i2cPacket.cbWriteCount = 0; i2cPacket.puchReadBuffer = &ucData; i2cPacket.puchWriteBuffer = NULL;
ExecuteI2CPacket(&i2cPacket);
if (i2cPacket.uchI2CResult != I2C_STATUS_NOERROR) { _DbgPrintF( DEBUGLVL_ERROR,("CI2CScript::CheckInterface(): Error\n")); return(FALSE); }
return(TRUE); }
|