//==========================================================================; // // // Gpio.cpp // Gpio Class implementation // Based on code from ATI Technologies Inc. Copyright (c) 1996 - 1997 // // ATIConfg.CPP // WDM MiniDrivers development. // ATIHwConfiguration class implementation. // Copyright (c) 1996 - 1997 ATI Technologies Inc. All Rights Reserved. // //==========================================================================; extern "C" { #include } #include #include "ks.h" #include "ksmedia.h" #include #include "gpio.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 /*^^* * CGpio() * Purpose : CGpio Class constructor * Determines I2CExpander address and all possible hardware IDs and addresses * * Inputs : PDEVICE_OBJECT pDeviceObject : pointer to the creator DeviceObject * CI2CScript * pCScript : pointer to the I2CScript class object * PUINT puiError : pointer to return Error code * * Outputs : none * Author : IKLEBANOV *^^*/ CGpio::CGpio( PDEVICE_OBJECT pDeviceObject, NTSTATUS * pStatus) { *pStatus = STATUS_SUCCESS; ENSURE { m_gpioProviderInterface.gpioOpen = NULL; m_gpioProviderInterface.gpioAccess = NULL; m_pdoDriver = NULL; if( InitializeAttachGPIOProvider( &m_gpioProviderInterface, pDeviceObject)) { // There was no error to get GPIOInterface from the MiniVDD // m_pdoDriver = pDeviceObject; } else { * pStatus = STATUS_NOINTERFACE; FAIL; } } END_ENSURE; _DbgPrintF( DEBUGLVL_VERBOSE, ( "CGPio:CGpio() Status=%x\n", * pStatus)); } /*^^* * GPIOIoSynchCompletionRoutine() * 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 GPIOIoSynchCompletionRoutine( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID Event) { KeSetEvent(( PKEVENT)Event, 0, FALSE); return( STATUS_MORE_PROCESSING_REQUIRED); } /*^^* * InitializeAttachGPIOProvider() * Purpose : determines the pointer to the parent GPIO Provider interface * This function will be called at Low priority * * Inputs : GPIOINTERFACE * pGPIOInterface : pointer to the Interface to be filled in * PDEVICE_OBJECT pDeviceObject : MiniDriver device object, which is a child of GPIO Master * * Outputs : BOOL - returns TRUE, if the interface was found * Author : IKLEBANOV *^^*/ BOOL CGpio::InitializeAttachGPIOProvider( GPIOINTERFACE * pGPIOInterface, PDEVICE_OBJECT pDeviceObject) { BOOL bResult; // Find the GPIO provider bResult = LocateAttachGPIOProvider( pGPIOInterface, pDeviceObject, IRP_MJ_PNP); if(( pGPIOInterface->gpioOpen == NULL) || ( pGPIOInterface->gpioAccess == NULL)) { // TRAP; _DbgPrintF( DEBUGLVL_ERROR, ( "CGpio(): GPIO interface has NULL pointers\n") ); bResult = FALSE; } return( bResult); } /*^^* * LocateAttachGPIOProvider() * Purpose : gets the pointer to the parent GPIO Provider interface * This function will be called at Low priority * * Inputs : GPIOINTERFACE * pGPIOInterface : 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 GPIO Interface * * Outputs : BOOL - returns TRUE, if the interface was found * Author : IKLEBANOV *^^*/ BOOL CGpio::LocateAttachGPIOProvider( GPIOINTERFACE * pGPIOInterface, 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, ("CGpio(): can not allocate IRP\n")); FAIL; } pNextStack = IoGetNextIrpStackLocation( pIrp); if( pNextStack == NULL) { // TRAP; _DbgPrintF( DEBUGLVL_ERROR, ("CATIHwConfig(): 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, GPIOIoSynchCompletionRoutine, &Event, TRUE, TRUE, TRUE); pNextStack->Parameters.QueryInterface.InterfaceType = ( struct _GUID *)&GUID_GPIO_INTERFACE; pNextStack->Parameters.QueryInterface.Size = sizeof( GPIOINTERFACE); pNextStack->Parameters.QueryInterface.Version = 1; pNextStack->Parameters.QueryInterface.Interface = ( PINTERFACE)pGPIOInterface; pNextStack->Parameters.QueryInterface.InterfaceSpecificData = NULL; ntStatus = IoCallDriver( pDeviceObject, pIrp); if( ntStatus == STATUS_PENDING) KeWaitForSingleObject( &Event, Suspended, KernelMode, FALSE, NULL); if(( pGPIOInterface->gpioOpen == NULL) || ( pGPIOInterface->gpioAccess == NULL)) { _DbgPrintF( DEBUGLVL_ERROR, ( "CATIHwConfig(): GPIO interface has NULL pointers\n") ); FAIL; } bResult = TRUE; } END_ENSURE; if( pIrp != NULL) IoFreeIrp( pIrp); return( bResult); } /*^^* * QueryGPIOProvider() * Purpose : queries the GPIOProvider for the pins supported and private interfaces * * Inputs : PGPIOControl pgpioAccessBlock : pointer to GPIO control structure * * Outputs : BOOL : retunrs TRUE, if the query function was carried on successfully * Author : IKLEBANOV *^^*/ BOOL CGpio::QueryGPIOProvider( PGPIOControl pgpioAccessBlock) { ENSURE { if(( m_gpioProviderInterface.gpioOpen == NULL) || ( m_gpioProviderInterface.gpioAccess == NULL) || ( m_pdoDriver == NULL)) FAIL; pgpioAccessBlock->Status = GPIO_STATUS_NOERROR; pgpioAccessBlock->Command = GPIO_COMMAND_QUERY; pgpioAccessBlock->AsynchCompleteCallback = NULL; if(( !NT_SUCCESS( m_gpioProviderInterface.gpioOpen( m_pdoDriver, TRUE, pgpioAccessBlock))) || ( pgpioAccessBlock->Status != GPIO_STATUS_NOERROR)) FAIL; return( TRUE); } END_ENSURE; return( FALSE); } /*^^* * LockGPIOProviderEx() * Purpose : locks the GPIOProvider for exclusive use * * Inputs : PGPIOControl pgpioAccessBlock : pointer to GPIO control structure * * Outputs : BOOL : retunrs TRUE, if the GPIOProvider is locked * Author : IKLEBANOV *^^*/ BOOL CGpio::LockGPIOProviderEx( PGPIOControl pgpioAccessBlock) { NTSTATUS ntStatus; LARGE_INTEGER liStartTime, liCurrentTime; KeQuerySystemTime( &liStartTime); ENSURE { if(( m_gpioProviderInterface.gpioOpen == NULL) || ( m_gpioProviderInterface.gpioAccess == NULL) || ( m_pdoDriver == NULL)) FAIL; pgpioAccessBlock->Status = GPIO_STATUS_NOERROR; pgpioAccessBlock->Command = GPIO_COMMAND_OPEN_PINS; while( TRUE) { KeQuerySystemTime( &liCurrentTime); if(( liCurrentTime.QuadPart - liStartTime.QuadPart) >= GPIO_TIMELIMIT_OPENPROVIDER) { // time has expired for attempting to lock GPIO provider return (FALSE); } ntStatus = m_gpioProviderInterface.gpioOpen( m_pdoDriver, TRUE, pgpioAccessBlock); if(( NT_SUCCESS( ntStatus)) && ( pgpioAccessBlock->Status == GPIO_STATUS_NOERROR)) break; } // the GPIO Provider has granted access - save dwCookie for further use m_dwGPIOAccessKey = pgpioAccessBlock->dwCookie; return( TRUE); } END_ENSURE; return( FALSE); } /*^^* * ReleaseGPIOProvider() * Purpose : releases the GPIOProvider for other clients' use * * Inputs : PGPIOControl pgpioAccessBlock : pointer to a composed GPIO access block * * Outputs : BOOL : retunrs TRUE, if the GPIOProvider is released * Author : IKLEBANOV *^^*/ BOOL CGpio::ReleaseGPIOProvider( PGPIOControl pgpioAccessBlock) { NTSTATUS ntStatus; ENSURE { if(( m_gpioProviderInterface.gpioOpen == NULL) || ( m_gpioProviderInterface.gpioAccess == NULL) || ( m_pdoDriver == NULL)) FAIL; pgpioAccessBlock->Status = GPIO_STATUS_NOERROR; pgpioAccessBlock->Command = GPIO_COMMAND_CLOSE_PINS; pgpioAccessBlock->dwCookie = m_dwGPIOAccessKey; ntStatus = m_gpioProviderInterface.gpioOpen( m_pdoDriver, FALSE, pgpioAccessBlock); if( !NT_SUCCESS( ntStatus)) { _DbgPrintF( DEBUGLVL_ERROR, ( "CGpio: ReleaseGPIOProvider() NTSTATUS = %x\n", ntStatus) ); FAIL; } if( pgpioAccessBlock->Status != GPIO_STATUS_NOERROR) { _DbgPrintF( DEBUGLVL_ERROR, ( "CGpio: ReleaseGPIOProvider() Status = %x\n", pgpioAccessBlock->Status) ); FAIL; } m_dwGPIOAccessKey = 0; return ( TRUE); } END_ENSURE; return( FALSE); } /*^^* * AccessGPIOProvider() * Purpose : provide synchronous type of access to GPIOProvider * * Inputs : PDEVICE_OBJECT pdoDriver : pointer to the client's device object * PGPIOControl pgpioAccessBlock : pointer to a composed GPIO access block * * Outputs : BOOL, TRUE if acsepted by the GPIO Provider * * Author : IKLEBANOV *^^*/ //BOOL CGpio::AccessGPIOProvider( PDEVICE_OBJECT pdoClient, PGPIOControl pgpioAccessBlock) BOOL CGpio::AccessGPIOProvider( PGPIOControl pgpioAccessBlock) { NTSTATUS ntStatus; ENSURE { if(( m_gpioProviderInterface.gpioOpen == NULL) || ( m_gpioProviderInterface.gpioAccess == NULL) || ( m_pdoDriver == NULL)) FAIL; //ntStatus = m_gpioProviderInterface.gpioAccess( pdoClient, pgpioAccessBlock); ntStatus = m_gpioProviderInterface.gpioAccess( m_pdoDriver, pgpioAccessBlock); if( !NT_SUCCESS( ntStatus)) { _DbgPrintF( DEBUGLVL_ERROR, ( "CGpio: AccessGPIOProvider() NTSTATUS = %x\n", ntStatus) ); FAIL; } if( pgpioAccessBlock->Status != GPIO_STATUS_NOERROR) { _DbgPrintF( DEBUGLVL_ERROR, ( "CGpio: AccessGPIOProvider() Status = %x\n", pgpioAccessBlock->Status) ); FAIL; } return TRUE; } END_ENSURE; return( FALSE); } /* * WriteGPIO() * Purpose : write to GPIO * * Inputs : PDEVICE_OBJECT pdoDriver : pointer to the client's device object * PGPIOControl pgpioAccessBlock : pointer to a composed GPIO access block * * Outputs : BOOL, TRUE if write succeeds * * Author : MM * */ BOOL CGpio::WriteGPIO(PGPIOControl pgpioAccessBlock) { ENSURE { // Put cookie value in the structure pgpioAccessBlock->dwCookie = m_dwGPIOAccessKey; pgpioAccessBlock->Command = GPIO_COMMAND_WRITE_BUFFER; pgpioAccessBlock->Flags = GPIO_FLAGS_BYTE; pgpioAccessBlock->nBytes = 1; pgpioAccessBlock->nBufferSize = 1; // Put cookie value in the structure pgpioAccessBlock->dwCookie = m_dwGPIOAccessKey; if (AccessGPIOProvider(pgpioAccessBlock) == FALSE) { _DbgPrintF( DEBUGLVL_ERROR, ("CGpio: GPIO Write Error\n")); FAIL; } return TRUE; } END_ENSURE; return( FALSE); } /* * ReadGPIO() * Purpose : Read From GPIO * * Inputs : PDEVICE_OBJECT pdoDriver : pointer to the client's device object * PGPIOControl pgpioAccessBlock : pointer to a composed GPIO access block * * Outputs : BOOL, TRUE if write succeeds * * Author : MM * */ BOOL CGpio::ReadGPIO(PGPIOControl pgpioAccessBlock) { ENSURE { // Put cookie value in the structure pgpioAccessBlock->dwCookie = m_dwGPIOAccessKey; pgpioAccessBlock->Command = GPIO_COMMAND_READ_BUFFER; pgpioAccessBlock->Flags = GPIO_FLAGS_BYTE; pgpioAccessBlock->nBytes = 1; pgpioAccessBlock->nBufferSize = 1; // Put cookie value in the structure pgpioAccessBlock->dwCookie = m_dwGPIOAccessKey; if (AccessGPIOProvider(pgpioAccessBlock) == FALSE) { _DbgPrintF( DEBUGLVL_ERROR, ("CGpio: GPIO Read Error\n")); FAIL; } else _DbgPrintF( DEBUGLVL_BLAB, ("CGpio: GPIO Read OK\n")); return TRUE; } END_ENSURE; return( FALSE); } /* WriteGPIO() * Purpose : write to GPIO * * Inputs : UCHAR *p_uchPin : the pin number * UCHAR *p_uchValue : the pin value * * Outputs : BOOL, TRUE if write succeeds * * Author : MM * */ BOOL CGpio::WriteGPIO(UCHAR *p_uchPin,UCHAR *p_uchValue ) { GPIOControl gpioAccessBlock; BOOL bResult = FALSE; ENSURE { // Put cookie value in the structure gpioAccessBlock.Flags = GPIO_FLAGS_BYTE; gpioAccessBlock.nBytes = 1; gpioAccessBlock.nBufferSize = 1; gpioAccessBlock.AsynchCompleteCallback = NULL; int counter = 0; LARGE_INTEGER liTime; // Somewhat arbitrary max of 1 second. while (!LockGPIOProviderEx( &gpioAccessBlock)) { if (counter++ >= 100) { _DbgPrintF( DEBUGLVL_ERROR,("PhilTune: unable to lock GPIOProvider\n")); FAIL; } liTime.QuadPart = 100000; KeDelayExecutionThread(KernelMode, FALSE, &liTime); // = 10 milliseconds } // try to get GPIO Provider gpioAccessBlock.Command = GPIO_COMMAND_WRITE_BUFFER; gpioAccessBlock.Pins = p_uchPin; // Put cookie value in the structure gpioAccessBlock.dwCookie = m_dwGPIOAccessKey; gpioAccessBlock.Buffer = p_uchValue; if (AccessGPIOProvider(&gpioAccessBlock) == FALSE) { _DbgPrintF( DEBUGLVL_ERROR,("CGpio: GPIO Write Error\n")); FAIL; } bResult = TRUE; } END_ENSURE; ReleaseGPIOProvider(&gpioAccessBlock); return bResult; } /* * ReadGPIO() * Purpose : Read From GPIO * * Inputs : UCHAR *p_uchPin : the pin number * UCHAR *p_uchValue : the pin value * * Outputs : BOOL, TRUE if write succeeds * * Author : MM * */ BOOL CGpio::ReadGPIO(UCHAR *p_uchPin,UCHAR *p_uchValue ) { GPIOControl gpioAccessBlock; BOOL bResult = FALSE; ENSURE { // Put cookie value in the structure gpioAccessBlock.Flags = GPIO_FLAGS_BYTE; gpioAccessBlock.nBytes = 1; gpioAccessBlock.nBufferSize = 1; gpioAccessBlock.AsynchCompleteCallback = NULL; int counter = 0; LARGE_INTEGER liTime; // Somewhat arbitrary max of 1 second. while (!LockGPIOProviderEx( &gpioAccessBlock)) { if (counter++ >= 100) { _DbgPrintF( DEBUGLVL_ERROR,("PhilTune: unable to lock GPIOProvider")); FAIL; } liTime.QuadPart = 100000; KeDelayExecutionThread(KernelMode, FALSE, &liTime); // = 10 milliseconds } // try to get GPIO Provider gpioAccessBlock.Command = GPIO_COMMAND_READ_BUFFER; gpioAccessBlock.Pins = p_uchPin; // Put cookie value in the structure gpioAccessBlock.dwCookie = m_dwGPIOAccessKey; gpioAccessBlock.Buffer = p_uchValue; if (AccessGPIOProvider(&gpioAccessBlock) == FALSE) { _DbgPrintF( DEBUGLVL_ERROR,("CGpio: GPIO Read Error\n")); FAIL; } else { _DbgPrintF( DEBUGLVL_TERSE,("CGpio: GPIO Read OK\n")); } bResult = TRUE; } END_ENSURE; ReleaseGPIOProvider(&gpioAccessBlock); return bResult; }