/***************************************************************************** * waveclk.cpp - wave clock implementation ***************************************************************************** * Copyright (c) 1998-2000 Microsoft Corporation. All rights reserved. */ #include "private.h" /***************************************************************************** * IIrpTargetInit ***************************************************************************** * IIrpTargetInit plus CWaveClock's Init. */ DECLARE_INTERFACE_(IIrpTargetInit,IIrpTarget) { DEFINE_ABSTRACT_UNKNOWN() // For IUnknown DEFINE_ABSTRACT_IRPTARGETFACTORY() // For IIrpTargetFactory DEFINE_ABSTRACT_IRPTARGET() // For IIrpTarget STDMETHOD_(NTSTATUS,Init) ( THIS_ IN PIRPSTREAMCONTROL pIrpStreamControl, IN PKSPIN_LOCK pKSpinLock, IN PLIST_ENTRY pListEntry ) PURE; }; typedef IIrpTargetInit *PIRPTARGETINIT; /***************************************************************************** * CWaveClock ***************************************************************************** * Wave clock implementation. */ class CWaveClock : public IIrpTargetInit, public IWaveClock, public CUnknown { private: WAVECLOCKNODE m_waveClockNode; PKSPIN_LOCK m_pKSpinLock; PIRPSTREAMCONTROL m_pIrpStreamControl; KSPIN_LOCK m_ClockLock, m_EventLock; LIST_ENTRY m_EventList; KMUTEX m_StateMutex; LONGLONG m_LastTime, m_LastPhysicalTime, m_LastPhysicalPosition; KSSTATE m_DeviceState; LONGLONG m_GetCurrentTime ( void ); public: DECLARE_STD_UNKNOWN(); DEFINE_STD_CONSTRUCTOR(CWaveClock); ~CWaveClock(); IMP_IIrpTarget; IMP_IWaveClock; STDMETHODIMP_(NTSTATUS) Init ( IN PIRPSTREAMCONTROL pIrpStreamControl, IN PKSPIN_LOCK pKSpinLock, IN PLIST_ENTRY pListEntry ); // // helper functions (also the DPC interface) // static LONGLONG FASTCALL GetCurrentTime( IN PFILE_OBJECT FileObject ); static LONGLONG FASTCALL GetCurrentPhysicalTime( IN PFILE_OBJECT FileObject ); static LONGLONG FASTCALL GetCurrentCorrelatedTime( IN PFILE_OBJECT FileObject, OUT PLONGLONG SystemTime ); static LONGLONG FASTCALL GetCurrentCorrelatedPhysicalTime( IN PFILE_OBJECT FileObject, OUT PLONGLONG SystemTime ); // // property handlers and event handlers // static NTSTATUS AddEvent( IN PIRP Irp, IN PKSEVENT_TIME_INTERVAL EventTime, IN PKSEVENT_ENTRY EventEntry ); static NTSTATUS GetFunctionTable( IN PIRP Irp, IN PKSPROPERTY Property, OUT PKSCLOCK_FUNCTIONTABLE FunctionTable ); static NTSTATUS GetCorrelatedTime( IN PIRP Irp, IN PKSPROPERTY Property, OUT PKSCORRELATED_TIME CorrelatedTime ); static NTSTATUS GetTime( IN PIRP Irp, IN PKSPROPERTY Property, OUT PLONGLONG Time ); static NTSTATUS GetCorrelatedPhysicalTime( IN PIRP Irp, IN PKSPROPERTY Property, OUT PKSCORRELATED_TIME CorrelatedTime ); static NTSTATUS GetPhysicalTime( IN PIRP Irp, IN PKSPROPERTY Property, OUT PLONGLONG Time ); static NTSTATUS GetResolution( IN PIRP Irp, IN PKSPROPERTY Property, OUT PKSRESOLUTION Resolution ); static NTSTATUS GetState( IN PIRP Irp, IN PKSPROPERTY Property, OUT PKSSTATE State ); }; DEFINE_KSPROPERTY_CLOCKSET( ClockPropertyHandlers, CWaveClock::GetTime, CWaveClock::GetPhysicalTime, CWaveClock::GetCorrelatedTime, CWaveClock::GetCorrelatedPhysicalTime, CWaveClock::GetResolution, CWaveClock::GetState, CWaveClock::GetFunctionTable ); DEFINE_KSPROPERTY_SET_TABLE( ClockPropertyTable ) { DEFINE_KSPROPERTY_SET( &KSPROPSETID_Clock, SIZEOF_ARRAY( ClockPropertyHandlers ), ClockPropertyHandlers, 0, NULL) }; DEFINE_KSEVENT_TABLE( ClockEventHandlers ) { DEFINE_KSEVENT_ITEM( KSEVENT_CLOCK_INTERVAL_MARK, sizeof( KSEVENT_TIME_INTERVAL ), sizeof( ULONGLONG ) + sizeof( ULONGLONG ), (PFNKSADDEVENT) CWaveClock::AddEvent, NULL, NULL), DEFINE_KSEVENT_ITEM( KSEVENT_CLOCK_POSITION_MARK, sizeof( KSEVENT_TIME_MARK ), sizeof( ULONGLONG ), (PFNKSADDEVENT) CWaveClock::AddEvent, NULL, NULL) }; DEFINE_KSEVENT_SET_TABLE( ClockEventTable ) { DEFINE_KSEVENT_SET( &KSEVENTSETID_Clock, SIZEOF_ARRAY( ClockEventHandlers ), ClockEventHandlers) }; #pragma code_seg("PAGE") /***************************************************************************** * CreateWaveClock() ***************************************************************************** * Creates a CWaveClock object. */ NTSTATUS CreateWaveClock ( OUT PUNKNOWN * pUnknown, IN REFCLSID, IN PUNKNOWN pUnknownOuter OPTIONAL, IN POOL_TYPE poolType ) { PAGED_CODE(); ASSERT(pUnknown); _DbgPrintF(DEBUGLVL_LIFETIME,("Creating WAVECLK")); STD_CREATE_BODY_ ( CWaveClock, pUnknown, pUnknownOuter, poolType, PIRPTARGET ); } /***************************************************************************** * PcNewWaveClock() ***************************************************************************** * Creates a new wave clock. */ NTSTATUS PcNewWaveClock ( OUT PIRPTARGET * ppIrpTarget, IN PUNKNOWN pUnknownOuter, IN POOL_TYPE poolType, IN PIRPSTREAMCONTROL pIrpStreamControl, IN PKSPIN_LOCK pKSpinLock, IN PLIST_ENTRY pListEntry ) { PAGED_CODE(); ASSERT(pIrpStreamControl); ASSERT(pKSpinLock); ASSERT(pListEntry); PUNKNOWN pUnknown; NTSTATUS ntStatus = CreateWaveClock ( &pUnknown, GUID_NULL, pUnknownOuter, poolType ); if (NT_SUCCESS(ntStatus)) { PIRPTARGETINIT pIrpTargetInit; ntStatus = pUnknown->QueryInterface ( IID_IIrpTarget, (PVOID *) &pIrpTargetInit ); if (NT_SUCCESS(ntStatus)) { ntStatus = pIrpTargetInit->Init ( pIrpStreamControl, pKSpinLock, pListEntry ); if (NT_SUCCESS(ntStatus)) { *ppIrpTarget = pIrpTargetInit; } else { pIrpTargetInit->Release(); } } pUnknown->Release(); } return ntStatus; } /***************************************************************************** * CWaveClock::Init() ***************************************************************************** * Initializes a wave clock. */ NTSTATUS CWaveClock:: Init ( IN PIRPSTREAMCONTROL pIrpStreamControl, IN PKSPIN_LOCK pKSpinLock, IN PLIST_ENTRY pListEntry ) { PAGED_CODE(); _DbgPrintF(DEBUGLVL_LIFETIME,("Initializing WAVECLK (0x%08x)",this)); ASSERT(pIrpStreamControl); ASSERT(pKSpinLock); ASSERT(pListEntry); // // Save parameters. // m_pIrpStreamControl = pIrpStreamControl; m_pIrpStreamControl->AddRef(); m_pKSpinLock = pKSpinLock; // // Initialize other members. // KeInitializeMutex(&m_StateMutex,0); KeInitializeSpinLock(&m_EventLock); KeInitializeSpinLock(&m_ClockLock); InitializeListHead(&m_EventList); // // Point the wave clock node to the IWaveClock interface. // m_waveClockNode.pWaveClock = PWAVECLOCK(this); // // Add this clock to the list of clocks. We don't need to keep the list // head because removal does not require it. The spinlock will come in // handy, though. // ExInterlockedInsertTailList ( pListEntry, &m_waveClockNode.listEntry, pKSpinLock ); return STATUS_SUCCESS; } #pragma code_seg() /***************************************************************************** * MyInterlockedRemoveEntryList() ***************************************************************************** * Interlocked RemoveEntryList. */ void MyInterlockedRemoveEntryList ( IN PLIST_ENTRY pListEntry, IN PKSPIN_LOCK pKSpinLock ) { KIRQL kIrqlOld; KeAcquireSpinLock(pKSpinLock,&kIrqlOld); RemoveEntryList(pListEntry); KeReleaseSpinLock(pKSpinLock,kIrqlOld); } #pragma code_seg("PAGE") /***************************************************************************** * CWaveClock::~CWaveClock() ***************************************************************************** * Destructor. */ CWaveClock::~CWaveClock() { _DbgPrintF(DEBUGLVL_LIFETIME,("Destroying WAVECLK (0x%08x)",this)); // // Remove us from the list if we are in it. // if (m_waveClockNode.listEntry.Flink) { MyInterlockedRemoveEntryList(&m_waveClockNode.listEntry,m_pKSpinLock); } // // Release the control interface if we have a reference. // if (m_pIrpStreamControl) { m_pIrpStreamControl->Release(); } } /***************************************************************************** * CWaveClock::NonDelegatingQueryInterface() ***************************************************************************** * Get an interface. */ STDMETHODIMP_(NTSTATUS) CWaveClock::NonDelegatingQueryInterface ( IN REFIID riid, OUT PVOID * ppvObject ) { PAGED_CODE(); ASSERT(ppvObject); _DbgPrintF(DEBUGLVL_BLAB,("CWaveClock::NonDelegatingQueryInterface")); if ( IsEqualGUIDAligned(riid,IID_IUnknown) || IsEqualGUIDAligned(riid,IID_IIrpTarget) ) { *ppvObject = PVOID(PIRPTARGETINIT(this)); } else if (IsEqualGUIDAligned(riid,IID_IWaveClock)) { *ppvObject = PVOID(PWAVECLOCK(this)); } else { *ppvObject = NULL; } if (*ppvObject) { PUNKNOWN(*ppvObject)->AddRef(); return STATUS_SUCCESS; } return STATUS_INVALID_PARAMETER; } STDMETHODIMP_(NTSTATUS) CWaveClock::DeviceIoControl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Processes device I/O control for this file object on this device object Arguments: IN PDEVICE_OBJECT DeviceObject - pointer to the device object IN PIRP Irp - pointer to I/O request packet Return: STATUS_SUCCESS or an appropriate error code --*/ { NTSTATUS Status; PIO_STACK_LOCATION irpSp; PAGED_CODE(); ASSERT( DeviceObject ); ASSERT( Irp ); _DbgPrintF( DEBUGLVL_BLAB, ("CWaveClock::DeviceIoControl")); irpSp = IoGetCurrentIrpStackLocation( Irp ); switch (irpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_KS_PROPERTY: Status = KsPropertyHandler( Irp, SIZEOF_ARRAY( ClockPropertyTable ), (PKSPROPERTY_SET) ClockPropertyTable ); break; case IOCTL_KS_ENABLE_EVENT: _DbgPrintF( DEBUGLVL_VERBOSE, ("CWaveClock::EnableEvent")); Status = KsEnableEvent( Irp, SIZEOF_ARRAY( ClockEventTable ), (PKSEVENT_SET) ClockEventTable, NULL, KSEVENTS_NONE, NULL); break; case IOCTL_KS_DISABLE_EVENT: _DbgPrintF( DEBUGLVL_VERBOSE, ("CWaveClock::DisableEvent")); Status = KsDisableEvent( Irp, &m_EventList, KSEVENTS_SPINLOCK, &m_EventLock ); break; default: return KsDefaultDeviceIoCompletion( DeviceObject, Irp ); } Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } STDMETHODIMP_(NTSTATUS) CWaveClock::Close( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Close handler for the clock file object Arguments: IN PDEVICE_OBJECT DeviceObject - pointer to the device object IN PIRP Irp - pointer to the I/O request packet Return: STATUS success or an appropriate error code --*/ { PIO_STACK_LOCATION irpSp; PAGED_CODE(); ASSERT(DeviceObject); ASSERT(Irp); _DbgPrintF( DEBUGLVL_VERBOSE, ("CWaveClock::Close")); irpSp = IoGetCurrentIrpStackLocation(Irp); // // Free events associated with this pin. // KsFreeEventList( irpSp->FileObject, &m_EventList, KSEVENTS_SPINLOCK, &m_EventLock ); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp,IO_NO_INCREMENT); return STATUS_SUCCESS; } DEFINE_INVALID_CREATE(CWaveClock); DEFINE_INVALID_READ(CWaveClock); DEFINE_INVALID_WRITE(CWaveClock); DEFINE_INVALID_FLUSH(CWaveClock); DEFINE_INVALID_QUERYSECURITY(CWaveClock); DEFINE_INVALID_SETSECURITY(CWaveClock); DEFINE_INVALID_FASTDEVICEIOCONTROL(CWaveClock); DEFINE_INVALID_FASTREAD(CWaveClock); DEFINE_INVALID_FASTWRITE(CWaveClock); #pragma code_seg() STDMETHODIMP_(NTSTATUS) CWaveClock:: GenerateEvents ( void ) { LONGLONG Time; PLIST_ENTRY ListEntry; if (m_DeviceState == KSSTATE_RUN) { Time = m_GetCurrentTime(); ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL ); KeAcquireSpinLockAtDpcLevel( &m_EventLock ); for(ListEntry = m_EventList.Flink; ListEntry != &m_EventList;) { PKSEVENT_ENTRY EventEntry; PKSINTERVAL Interval; EventEntry = (PKSEVENT_ENTRY) CONTAINING_RECORD( ListEntry, KSEVENT_ENTRY, ListEntry ); // // Pre-inc, KsGenerateEvent() can remove this item from the list. // ListEntry = ListEntry->Flink; // // The event-specific data was added onto the end of the entry. // Interval = (PKSINTERVAL)(EventEntry + 1); // // Time for this event to go off. // if (Interval->TimeBase <= Time) { _DbgPrintF( DEBUGLVL_VERBOSE, ("Generating event for time: %ld at time: %ld", Interval->TimeBase, Time) ); if (EventEntry->EventItem->EventId != KSEVENT_CLOCK_INTERVAL_MARK) { // // A single-shot should only go off once, so make // it a value which will never be reached again. // Interval->TimeBase = 0x7fffffffffffffff; } else { LONGLONG Intervals; // // An interval timer should only go off once per time, // so update it to the next timeout. // Intervals = (Time - Interval->TimeBase + Interval->Interval - 1) / Interval->Interval; Interval->TimeBase += Intervals * Interval->Interval; } KsGenerateEvent( EventEntry ); } } KeReleaseSpinLockFromDpcLevel( &m_EventLock ); } return STATUS_SUCCESS; } STDMETHODIMP_(NTSTATUS) CWaveClock::SetState( KSSTATE State ) /*++ Routine Description: This method is called by the port to notify of a state change. Arguments: KSSTATE State - New state Return: STATUS_SUCCESS --*/ { // // Synchronize with GetState, // KeWaitForMutexObject( &m_StateMutex, Executive, KernelMode, FALSE, NULL ); // // set the new state, // m_DeviceState = State; switch (State) { case KSSTATE_STOP: m_LastTime = m_LastPhysicalTime = m_LastPhysicalPosition = 0; break; case KSSTATE_RUN: break; } // // and then release the mutex. // KeReleaseMutex( &m_StateMutex, FALSE ); return STATUS_SUCCESS; } NTSTATUS CWaveClock::AddEvent( IN PIRP Irp, IN PKSEVENT_TIME_INTERVAL EventTime, IN PKSEVENT_ENTRY EventEntry ) /*++ Routine Description: This is the AddEvent() handler for the clock events. NOTE: This routine acquires a spinlock, must be in non-paged code. Arguments: IN PIRP Irp - pointer to the I/O request packet IN PKSEVENT_TIME_INTERVAL EventTime - specified time interval or one shot IN PKSEVENT_ENTRY EventEntry - pointer to event entry structure Return Value: STATUS_SUCCESS --*/ { KIRQL irqlOld; PKSINTERVAL Interval; CWaveClock *pCWaveClock = (CWaveClock *) KsoGetIrpTargetFromIrp(Irp); ASSERT( pCWaveClock ); _DbgPrintF( DEBUGLVL_VERBOSE, ("CWaveClock::AddEvent")); // // Space for the interval is located at the end of the basic // event structure. // Interval = (PKSINTERVAL)(EventEntry + 1); // // Either just an event time was passed, or a time base plus an // interval. In both cases the first LONGLONG is present and saved. // Interval->TimeBase = EventTime->TimeBase; if (EventEntry->EventItem->EventId == KSEVENT_CLOCK_INTERVAL_MARK) { Interval->Interval = EventTime->Interval; } KeAcquireSpinLock( &pCWaveClock->m_EventLock, &irqlOld ); InsertHeadList( &pCWaveClock->m_EventList, &EventEntry->ListEntry ); KeReleaseSpinLock( &pCWaveClock->m_EventLock, irqlOld ); // // If this event is passed, signal immediately. // Note, KS_CLOCK_POSITION_MARK is a single-shot event // pCWaveClock->GenerateEvents(); return STATUS_SUCCESS; } LONGLONG FASTCALL CWaveClock:: GetCurrentTime ( PFILE_OBJECT FileObject ) /*++ Routine Description: Computes the current presentation time. NOTE: This routine acquires a spinlock, must be in non-paged code. Arguments: PFILE_OBJECT FileObject - this clock's file object Return: resultant presentation time normalized to 100ns units. --*/ { CWaveClock *pCWaveClock = (CWaveClock *) KsoGetIrpTargetFromFileObject(FileObject); return pCWaveClock->m_GetCurrentTime(); } LONGLONG CWaveClock:: m_GetCurrentTime ( void ) /*++ Routine Description: Computes the current presentation time. NOTE: This routine acquires a spinlock, must be in non-paged code. Arguments: Return: resultant presentation time normalized to 100ns units. --*/ { IRPSTREAMPACKETINFO irpStreamPacketInfoUnmapping; KIRQL irqlOld; LONGLONG StreamTime; NTSTATUS Status; PIRPSTREAMCONTROL pIrpStreamControl; StreamTime = 0; // // Query the position from the IRP stream. // pIrpStreamControl = m_pIrpStreamControl; ASSERT(pIrpStreamControl); IRPSTREAM_POSITION irpStreamPosition; Status = pIrpStreamControl->GetPosition(&irpStreamPosition); if (NT_SUCCESS(Status)) { // // Never exceed current stream extent. // if ( irpStreamPosition.ullStreamPosition > irpStreamPosition.ullCurrentExtent ) { StreamTime = irpStreamPosition.ullCurrentExtent; } else { StreamTime = irpStreamPosition.ullStreamPosition; } StreamTime = pIrpStreamControl->NormalizePosition(StreamTime); } KeAcquireSpinLock( &m_ClockLock, &irqlOld ); if (NT_SUCCESS( Status )) { if (StreamTime < m_LastTime) { _DbgPrintF( DEBUGLVL_VERBOSE, ("new time is less than last reported time! (%I64d, %I64d)", StreamTime, m_LastTime) ); StreamTime = m_LastTime; } else { m_LastTime = StreamTime; } } else { StreamTime = m_LastTime; } KeReleaseSpinLock( &m_ClockLock, irqlOld ); return StreamTime; } LONGLONG FASTCALL CWaveClock::GetCurrentCorrelatedTime( PFILE_OBJECT FileObject, PLONGLONG SystemTime ) /*++ Routine Description: Arguments: PFILE_OBJECT FileObject - PLONGLONG SystemTime - pointer Return: current presentation time in 100ns --*/ { LARGE_INTEGER Time, Frequency; Time = KeQueryPerformanceCounter( &Frequency ); // // Convert ticks to 100ns units. // *SystemTime = KSCONVERT_PERFORMANCE_TIME(Frequency.QuadPart,Time); return GetCurrentTime( FileObject ); } LONGLONG FASTCALL CWaveClock::GetCurrentPhysicalTime( PFILE_OBJECT FileObject ) /*++ Routine Description: Computes the current physical time. NOTE: This routine acquires a spinlock, must be in non-paged code. Arguments: PFILE_OBJECT FileObject - this clock's file object Return: current physical time in 100ns --*/ { KIRQL irqlOld; LONGLONG PhysicalTime; NTSTATUS Status; ULONG CurrentPosition; CWaveClock *pCWaveClock = (CWaveClock *) KsoGetIrpTargetFromFileObject(FileObject); PhysicalTime = 0; // // Query the position from the IRP stream. // PIRPSTREAMCONTROL pIrpStreamControl = pCWaveClock->m_pIrpStreamControl; ASSERT( pIrpStreamControl ); IRPSTREAM_POSITION irpStreamPosition; Status = pIrpStreamControl->GetPosition(&irpStreamPosition); if (NT_SUCCESS(Status)) { PhysicalTime = pIrpStreamControl->NormalizePosition ( irpStreamPosition.ullStreamPosition + irpStreamPosition.ullPhysicalOffset ); } KeAcquireSpinLock( &pCWaveClock->m_ClockLock, &irqlOld ); if (NT_SUCCESS( Status )) { // // Verify that this new physical time is >= to the last // reported physical time. If not, set the time to the // last reported time. Flag this as an error in debug. // if (PhysicalTime < pCWaveClock->m_LastPhysicalTime) { _DbgPrintF( DEBUGLVL_VERBOSE, ("new physical time is less than last reported physical time! (%I64d, %I64d)", PhysicalTime, pCWaveClock->m_LastPhysicalTime) ); PhysicalTime = pCWaveClock->m_LastPhysicalTime; } else { // // Set m_LastPhysicalTime to the updated time. // pCWaveClock->m_LastPhysicalTime = PhysicalTime; } } else { PhysicalTime = pCWaveClock->m_LastPhysicalTime; } KeReleaseSpinLock( &pCWaveClock->m_ClockLock, irqlOld ); return PhysicalTime; } LONGLONG FASTCALL CWaveClock::GetCurrentCorrelatedPhysicalTime( PFILE_OBJECT FileObject, PLONGLONG SystemTime ) /*++ Routine Description: Retrieves the current physical time correlated with the system time. Arguments: PFILE_OBJECT FileObject - this clock's file object PLONGLONG SystemTime - pointer to the resultant system time Return: current physical time in 100ns --*/ { LARGE_INTEGER Time, Frequency; Time = KeQueryPerformanceCounter( &Frequency ); // // Convert ticks to 100ns units. // *SystemTime = KSCONVERT_PERFORMANCE_TIME(Frequency.QuadPart,Time); return GetCurrentTime( FileObject ); } #pragma code_seg("PAGE") NTSTATUS CWaveClock::GetFunctionTable( IN PIRP Irp, IN PKSPROPERTY Property, OUT PKSCLOCK_FUNCTIONTABLE FunctionTable ) /*++ Routine Description: Retrieves the DPC interface function table for this clock. Arguments: IN PIRP Irp - pointer to the I/O request packet IN PKSPROPERTY Property - pointer to the property structure OUT PKSCLOCK_FUNCTIONTABLE FunctionTable - pointer to the resultant function table Return: --*/ { PAGED_CODE(); FunctionTable->GetTime = GetCurrentTime; FunctionTable->GetPhysicalTime = GetCurrentPhysicalTime; FunctionTable->GetCorrelatedTime = GetCurrentCorrelatedTime; FunctionTable->GetCorrelatedPhysicalTime = GetCurrentCorrelatedPhysicalTime; Irp->IoStatus.Information = sizeof(*FunctionTable); return STATUS_SUCCESS; } NTSTATUS CWaveClock::GetCorrelatedTime( IN PIRP Irp, IN PKSPROPERTY Property, OUT PKSCORRELATED_TIME CorrelatedTime ) /*++ Routine Description: Retrieves the current presentation time correlated with the system time. Arguments: IN PIRP Irp - pointer to the I/O request packet IN PKSPROPERTY Property - pointer to the property structure OUT PKSCORRELATED_TIME CorrelatedTime - resultant correlated presentation time Return: STATUS_SUCCESS else an appropriate error code --*/ { PAGED_CODE(); CWaveClock *pCWaveClock = (CWaveClock *) KsoGetIrpTargetFromIrp(Irp); CorrelatedTime->Time = pCWaveClock->GetCurrentCorrelatedTime( IoGetCurrentIrpStackLocation( Irp )->FileObject, &CorrelatedTime->SystemTime ); Irp->IoStatus.Information = sizeof( KSCORRELATED_TIME ); return STATUS_SUCCESS; } NTSTATUS CWaveClock::GetTime( IN PIRP Irp, IN PKSPROPERTY Property, OUT PLONGLONG Time ) /*++ Routine Description: Retrieves the current presentation time. Arguments: IN PIRP Irp - pointer to the I/O request packet IN PKSPROPERTY Property - pointer to the property structure OUT PLONGLONG Time - resultant presentation time Return: STATUS_SUCCESS else an appropriate error code --*/ { PAGED_CODE(); CWaveClock *pCWaveClock = (CWaveClock *) KsoGetIrpTargetFromIrp(Irp); *Time = pCWaveClock->GetCurrentTime( IoGetCurrentIrpStackLocation( Irp )->FileObject ); Irp->IoStatus.Information = sizeof( LONGLONG ); return STATUS_SUCCESS; } NTSTATUS CWaveClock::GetCorrelatedPhysicalTime( IN PIRP Irp, IN PKSPROPERTY Property, OUT PKSCORRELATED_TIME CorrelatedTime ) /*++ Routine Description: Retrieves the current physical time correlated with the system time. Arguments: IN PIRP Irp - pointer to the I/O request packet IN PKSPROPERTY Property - pointer to the property structure OUT PKSCORRELATED_TIME CorrelatedTime - resultant correlated physical time Return: STATUS_SUCCESS else an appropriate error code --*/ { PAGED_CODE(); CWaveClock *pCWaveClock = (CWaveClock *) KsoGetIrpTargetFromIrp(Irp); CorrelatedTime->Time = pCWaveClock->GetCurrentCorrelatedPhysicalTime( IoGetCurrentIrpStackLocation( Irp )->FileObject, &CorrelatedTime->SystemTime ); Irp->IoStatus.Information = sizeof( KSCORRELATED_TIME ); return STATUS_SUCCESS; } NTSTATUS CWaveClock::GetPhysicalTime( IN PIRP Irp, IN PKSPROPERTY Property, OUT PLONGLONG Time ) /*++ Routine Description: Returns the clock's physical time. This is the actual clock physical time which is not halted for starvation, etc. Arguments: IN PIRP Irp - pointer to the I/O request packet IN PKSPROPERTY Property - pointer to the property structure OUT PLONGLONG Time - resultant time in 100 ns units Return: STATUS_SUCCESS or an appropriate error code --*/ { PAGED_CODE(); CWaveClock *pCWaveClock = (CWaveClock *) KsoGetIrpTargetFromIrp(Irp); *Time = pCWaveClock->GetCurrentPhysicalTime( IoGetCurrentIrpStackLocation( Irp )->FileObject ); Irp->IoStatus.Information = sizeof( LONGLONG ); return STATUS_SUCCESS; } NTSTATUS CWaveClock::GetResolution( IN PIRP Irp, IN PKSPROPERTY Property, OUT PKSRESOLUTION Resolution ) /*++ Routine Description: Retrieves the resolution of this clock. Arguments: IN PIRP Irp - pointer to the I/O request packet IN PKSPROPERTY Property - pointer to the property structure OUT PKSRESOLUTIONM Resolution - pointer to the resultant resolution structure which stores the granularity and error in 100ns units. Return Value: STATUS_SUCCESS --*/ { PAGED_CODE(); CWaveClock *pCWaveClock = (CWaveClock *) KsoGetIrpTargetFromIrp(Irp); // // This clock has a resolution dependant on the data format. Assume // that for cyclic devices, a byte position is computed for the DMA // controller and convert this to 100ns units. The error (event // notification error) is +/- NotificationFrequency/2 Resolution->Granularity = pCWaveClock->m_pIrpStreamControl->NormalizePosition(1); Resolution->Error = (_100NS_UNITS_PER_SECOND / 1000 * WAVECYC_NOTIFICATION_FREQUENCY) / 2; Irp->IoStatus.Information = sizeof(*Resolution); return STATUS_SUCCESS; } NTSTATUS CWaveClock::GetState( IN PIRP Irp, IN PKSPROPERTY Property, OUT PKSSTATE State ) /*++ Routine Description: Returns the underlying pin's state. Arguments: IN PIRP Irp - pointer to the I/O request packet IN PKSPROPERTY Property - pointer to the property structure OUT PKSSTATE State - pointer to resultant KSSTATE Return: STATUS_SUCCESS --*/ { PAGED_CODE(); CWaveClock *pCWaveClock = (CWaveClock *) KsoGetIrpTargetFromIrp(Irp); // // Synchronize with SetState, // KeWaitForMutexObject( &pCWaveClock->m_StateMutex, Executive, KernelMode, FALSE, NULL ); // // retrieve the state // *State = pCWaveClock->m_DeviceState; // // and then release the mutex // KeReleaseMutex( &pCWaveClock->m_StateMutex, FALSE ); Irp->IoStatus.Information = sizeof(*State); return STATUS_SUCCESS; }