//==========================================================================; // // 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. // // ATITVSnd.CPP // WDM TV Audio MiniDriver. // AllInWonder/AllInWonderPro development platform. // Main Source Module. // // $Date: 01 Apr 1998 13:29:14 $ // $Revision: 1.1 $ // $Author: KLEBANOV $ // //==========================================================================; extern "C" { #include "strmini.h" #include "ksmedia.h" #include "wdmdebug.h" } #include "atitvsnd.h" #include "wdmdrv.h" /*^^* * DriverEntry() * Purpose : Called when an SRB_INITIALIZE_DEVICE request is received * * Inputs : PVOID Arg1, PVOID Arg2 * * Outputs : result of StreamClassregisterAdapter() * Author : IKLEBANOV *^^*/ extern "C" ULONG DriverEntry ( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath ) { HW_INITIALIZATION_DATA HwInitData; SetMiniDriverDebugLevel( pRegistryPath); OutputDebugTrace(( "ATITVSnd: DriverEntry\n")); RtlZeroMemory( &HwInitData, sizeof( HwInitData)); HwInitData.HwInitializationDataSize = sizeof(HwInitData); // Entry points for Port Driver HwInitData.HwInterrupt = NULL; // HwInterrupt; HwInitData.HwReceivePacket = TVAudioReceivePacket; HwInitData.HwCancelPacket = TVAudioCancelPacket; HwInitData.HwRequestTimeoutHandler = TVAudioTimeoutPacket; HwInitData.DeviceExtensionSize = sizeof( ADAPTER_DATA_EXTENSION); HwInitData.PerRequestExtensionSize = sizeof( SRB_DATA_EXTENSION); HwInitData.FilterInstanceExtensionSize = 0; HwInitData.PerStreamExtensionSize = 0; HwInitData.BusMasterDMA = FALSE; HwInitData.Dma24BitAddresses = FALSE; HwInitData.BufferAlignment = 3; // HwInitData.TurnOffSynchronization = FALSE; // we turn the synchronization ON. StreamClass is expected to call the MiniDriver // at passive level only HwInitData.TurnOffSynchronization = TRUE; HwInitData.DmaBufferSize = 0; OutputDebugTrace(( "ATITVSnd: StreamClassRegisterAdapter\n")); return( StreamClassRegisterAdapter( pDriverObject, pRegistryPath, &HwInitData)); } /*^^* * TVAudioReceivePacket() * Purpose : Main entry point for receiving adapter based request SRBs from the Class Driver. * Will always be called at passive level, because the drivers * turned the synchronization ON. * Note : This is an asyncronous entry point. The request only completes when a * StreamClassDeviceNotification on this SRB, of type DeviceRequestComplete, * is issued. As soon we're running at passive level, we can do everything * synchronously during the response to the SRBs with no worry * to block somebody else for a long timer during I2C access * * Inputs : PHW_STREAM_REQUEST_BLOCK pSrb : pointer to the current Srb * * Outputs : none * Author : IKLEBANOV *^^*/ extern "C" void STREAMAPI TVAudioReceivePacket( IN OUT PHW_STREAM_REQUEST_BLOCK pSrb) { CWDMTVAudio * pCTVAudio; KIRQL irqlCurrent; PADAPTER_DATA_EXTENSION pPrivateData = ( PADAPTER_DATA_EXTENSION)( pSrb->HwDeviceExtension); PSRB_DATA_EXTENSION pSrbPrivate = ( PSRB_DATA_EXTENSION)( pSrb->SRBExtension); // check the device extension pointer if(( pPrivateData == NULL) || ( pSrbPrivate == NULL)) { TRAP; pSrb->Status = STATUS_INVALID_PARAMETER; StreamClassDeviceNotification( DeviceRequestComplete, pSrb->HwDeviceExtension, pSrb); } OutputDebugInfo(( "ATITVSnd: TVAudioReceivePacket() SRB = %x\n", pSrb)); if( pSrb->Command == SRB_INITIALIZE_DEVICE) { // this is the special case for SRB_INITIALIZE_DEVICE, because // no Queue has been initialized yet. Everything we need later on // is initialized during this SRB response TVAudioAdapterInitialize( pSrb); StreamClassDeviceNotification( DeviceRequestComplete, pSrb->HwDeviceExtension, pSrb); return; } // the rest of the SRBs are coming after SpinLock and SRBQueue have been initialized // during DRB_INITIALIZE_DEVICE SRB response. // I'll insert the SRB in the Queue first of all. The processing SRB from the Queue // can be triggered by finishing processing and SRB, or by the fact there is no SRB // is in process down here pSrbPrivate->pSrb = pSrb; // Everything we're doing with the Queue has to be protected from being interrupted KeAcquireSpinLock( &pPrivateData->adapterSpinLock, &irqlCurrent); InsertTailList( &pPrivateData->adapterSrbQueueHead, &pSrbPrivate->srbListEntry); if( pPrivateData->bSrbInProcess) { // there is another SRB being processed, and the new one will be picked up from // the Queue when it's its turn. KeReleaseSpinLock( &pPrivateData->adapterSpinLock, irqlCurrent); return; } while( !IsListEmpty( &pPrivateData->adapterSrbQueueHead)) { // turn on the semaphore for the others coming after pPrivateData->bSrbInProcess = TRUE; // be carefull here, if you've changed the place where srbListEntry is defined // within the SRB_DATA_EXTENSION structure pSrbPrivate = ( PSRB_DATA_EXTENSION)RemoveHeadList( &pPrivateData->adapterSrbQueueHead); KeReleaseSpinLock( &pPrivateData->adapterSpinLock, irqlCurrent); // here is the place to process the SRB we have retrieved from the Queue pSrb = pSrbPrivate->pSrb; pPrivateData = ( PADAPTER_DATA_EXTENSION)( pSrb->HwDeviceExtension); pCTVAudio = &pPrivateData->CTVAudio; ASSERT( pSrb->Status != STATUS_CANCELLED); switch( pSrb->Command) { case SRB_INITIALIZATION_COMPLETE: // StreamClass has completed the initialization pSrb->Status = pCTVAudio->AdapterCompleteInitialization( pSrb); break; case SRB_UNINITIALIZE_DEVICE: // close the device. pCTVAudio->AdapterUnInitialize( pSrb); break; case SRB_OPEN_STREAM: case SRB_CLOSE_STREAM: pSrb->Status = STATUS_NOT_IMPLEMENTED; break; case SRB_GET_STREAM_INFO: // return a block describing STREAM_INFO_HEADER and all the streams supported pCTVAudio->AdapterGetStreamInfo( pSrb); break; case SRB_CHANGE_POWER_STATE: pSrb->Status = pCTVAudio->AdapterSetPowerState( pSrb); break; case SRB_GET_DEVICE_PROPERTY: if( pCTVAudio->AdapterGetProperty( pSrb)) pSrb->Status = STATUS_SUCCESS; else pSrb->Status = STATUS_INVALID_PARAMETER; break; case SRB_SET_DEVICE_PROPERTY: if( pCTVAudio->AdapterSetProperty( pSrb)) pSrb->Status = STATUS_SUCCESS; else pSrb->Status = STATUS_INVALID_PARAMETER; break; // We should never get the following since this is a single instance device case SRB_OPEN_DEVICE_INSTANCE: case SRB_CLOSE_DEVICE_INSTANCE: TRAP pSrb->Status = STATUS_NOT_IMPLEMENTED; break; case SRB_UNKNOWN_DEVICE_COMMAND: // we know we're getting some of these. Why should we? pSrb->Status = STATUS_NOT_IMPLEMENTED; break; default: // TRAP // this is a request that we do not understand. Indicate invalid command and complete the request pSrb->Status = STATUS_NOT_IMPLEMENTED; } StreamClassDeviceNotification( DeviceRequestComplete, pPrivateData, pSrb); KeAcquireSpinLock( &pPrivateData->adapterSpinLock, &irqlCurrent); } // turn off the semaphore to enable the others coming after pPrivateData->bSrbInProcess = FALSE; KeReleaseSpinLock( &pPrivateData->adapterSpinLock, irqlCurrent); // there is no other SRB being processed at this time, let's start processing } extern "C" void STREAMAPI TVAudioCancelPacket( IN OUT PHW_STREAM_REQUEST_BLOCK pSrb) { pSrb->Status = STATUS_CANCELLED; } extern "C" void STREAMAPI TVAudioTimeoutPacket( IN OUT PHW_STREAM_REQUEST_BLOCK pSrb) { // not sure what to do here. } /*^^* * TVAudioAdapterInitialize() * Purpose : Called when SRB_INITIALIZE_DEVICE SRB is received. * Performs checking of the hardware presence and I2C provider availability. * Sets the hardware in an initial state. * Note : The request does not completed unless we know everything * about the hardware and we are sure it is capable to work in the current configuration. * The hardware Caps are also aquised at this point. As soon this * function is called at passive level, do everything synchronously * * Inputs : PHW_STREAM_REQUEST_BLOCK pSrb : pointer to the current Srb * * Outputs : none * Author : IKLEBANOV *^^*/ void TVAudioAdapterInitialize( IN OUT PHW_STREAM_REQUEST_BLOCK pSrb) { PPORT_CONFIGURATION_INFORMATION pConfigInfo = pSrb->CommandData.ConfigInfo; PADAPTER_DATA_EXTENSION pPrivateData = ( PADAPTER_DATA_EXTENSION)( pConfigInfo->HwDeviceExtension); NTSTATUS ntStatus = STATUS_NO_SUCH_DEVICE; CWDMTVAudio * pCTVAudio; CI2CScript * pCScript = NULL; UINT nErrorCode; OutputDebugTrace(( "ATITVSnd: TVAudioAdapterInitialize()\n")); ENSURE { if( pConfigInfo->NumberOfAccessRanges != 0) { OutputDebugError(( "ATITVSnd: illegal NumberOfAccessRanges = %lx\n", pConfigInfo->NumberOfAccessRanges)); FAIL; } // if we have I2CProvider implemented inside the MiniVDD, we have to // get a pointer to I2CInterface from the Provider. // There is an overloaded operator new provided for the CI2CScript Class. pCScript = ( CI2CScript *)new(( PVOID)&pPrivateData->CScript) CI2CScript( pConfigInfo, &nErrorCode); if( nErrorCode != WDMMINI_NOERROR) { OutputDebugError(( "ATITVSnd: CI2CScript creation failure = %lx\n", nErrorCode)); FAIL; } // The CI2CScript object was created successfully. // We'll try to allocate I2CProvider here for future possible I2C // operations needed at Initialization time. if( !pCScript->LockI2CProviderEx()) { OutputDebugError(( "ATITVSnd: unable to lock I2CProvider")); FAIL; } // we did lock the provider. // There is an overloaded operator new provided for the CWDMTVAudio Class. pCTVAudio = ( CWDMTVAudio *)new(( PVOID)&pPrivateData->CTVAudio) CWDMTVAudio( pConfigInfo, pCScript, &nErrorCode); if( nErrorCode) { OutputDebugError(( "ATITVSnd: CWDMTVAudio constructor failure = %lx\n", nErrorCode)); FAIL; } InitializeListHead ( &pPrivateData->adapterSrbQueueHead); KeInitializeSpinLock ( &pPrivateData->adapterSpinLock); pPrivateData->PhysicalDeviceObject = pConfigInfo->RealPhysicalDeviceObject; // no streams are supported pConfigInfo->StreamDescriptorSize = sizeof( HW_STREAM_HEADER); OutputDebugTrace(( "TVAudioAdapterInitialize(): exit\n")); ntStatus = STATUS_SUCCESS; } END_ENSURE; if (pCScript) pCScript->ReleaseI2CProvider(); pSrb->Status = ntStatus; return; }