You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
339 lines
12 KiB
339 lines
12 KiB
//==========================================================================;
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
|
|
|