📄 i2script.cpp
字号:
// 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;
OutputDebugTrace(( "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 : PHW_STREAM_REQUEST_BLOCK pSrb : pointer to the current SRB
* 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 PHW_STREAM_REQUEST_BLOCK pSrb,
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
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;
bResult = LocateAttachI2CProvider( pI2CInterface, pDeviceObject, IRP_MJ_PNP);
if(( pI2CInterface->i2cOpen == NULL) || ( pI2CInterface->i2cAccess == NULL))
{
TRAP;
OutputDebugError(( "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;
OutputDebugError(( "CI2CScript(): can not allocate IRP\n"));
FAIL;
}
pNextStack = IoGetNextIrpStackLocation( pIrp);
if( pNextStack == NULL)
{
TRAP;
OutputDebugError(( "CI2CScript(): can not allocate NextStack\n"));
FAIL;
}
pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
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))
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);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -