NTSTATUS CHardwareSimulation:: FillScatterGatherBuffers() /*++ Routine Description: The hardware has synthesized a buffer and we're to fill a frame buffer. Arguments: None Return Value: Success / Failure --*/ { PAGED_CODE(); DBG_ENTER("() m_PinState=%s, m_PinID=0x%08X, m_ImageSize=0x%08X, m_ScatterGatherMappingsQueued=%u, " "m_ScatterGatherBytesQueue=0x%08X", GetPinStateTxt(m_PinState), m_PinID, m_ImageSize, m_ScatterGatherMappingsQueued, m_ScatterGatherBytesQueued); NTSTATUS ntStatus = STATUS_SUCCESS; ULONG BufferRemaining = m_ImageSize; // // If there isn't a frame buffer queued, we justskip the frame and consider // it starvation. // while (BufferRemaining && !IsListEmpty(&m_ScatterGatherMappings) && m_ScatterGatherBytesQueued >= BufferRemaining) { LIST_ENTRY *listEntry = RemoveHeadList (&m_ScatterGatherMappings); m_ScatterGatherMappingsQueued--; PSCATTER_GATHER_ENTRY SGEntry = reinterpret_cast <PSCATTER_GATHER_ENTRY> ( CONTAINING_RECORD ( listEntry, SCATTER_GATHER_ENTRY, ListEntry ) ); // Deal with cancellation. PIRP pIrp = KsStreamPointerGetIrp(SGEntry->CloneEntry, FALSE, FALSE); if (pIrp) { if (pIrp->Cancel) { DBG_TRACE( "Cancelling..." ); FreeSGEntry( listEntry, L"StreamPointer Cancel SG List" ); continue; } } // // Since we're software, we'll be accessing this by virtual address... // ULONG Stride = 0; if ( SGEntry->CloneEntry -> StreamHeader -> Size >= sizeof (KSSTREAM_HEADER) + sizeof (KS_FRAME_INFO)) { PKS_FRAME_INFO FrameInfo = reinterpret_cast <PKS_FRAME_INFO> (SGEntry->CloneEntry->StreamHeader+1); Stride = (ULONG) ABS(FrameInfo->lSurfacePitch); } // Have the synthesizer output a frame to the buffer. ULONG BytesCopied = m_Synthesizer->DoCommit( SGEntry->Virtual, SGEntry->ByteCount, Stride ); NT_ASSERT( BytesCopied ); DBG_TRACE( "BytesCopied = %d", BytesCopied ); //Adding time stamp if(m_PhotoConfirmationEntry.isRequired()) { SGEntry -> CloneEntry -> StreamHeader -> PresentationTime.Time = m_PhotoConfirmationEntry.getTime(); DBG_TRACE("Using Photo Confirmation time = 0x%016llX", m_PhotoConfirmationEntry.getTime()); } else { SGEntry -> CloneEntry -> StreamHeader -> PresentationTime.Time = ConvertQPCtoTimeStamp(NULL); DBG_TRACE("PresentationTime = 0x%016llX", SGEntry->CloneEntry->StreamHeader->PresentationTime.Time ); } SGEntry -> CloneEntry -> StreamHeader -> PresentationTime.Numerator = SGEntry -> CloneEntry -> StreamHeader -> PresentationTime.Denominator = 1; SGEntry -> CloneEntry -> StreamHeader -> OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_TIMEVALID ; // Add metadata to the sample. EmitMetadata( SGEntry -> CloneEntry -> StreamHeader ); BufferRemaining = 0; //-= BytesCopied; m_NumMappingsCompleted++; m_ScatterGatherBytesQueued -= SGEntry -> ByteCount; // // Release the scatter / gather entry back to our lookaside. // ExFreeToNPagedLookasideList ( &m_ScatterGatherLookaside, reinterpret_cast <PVOID> (SGEntry) ); } // Report an error if we used the last buffer. if (BufferRemaining) { //DBG_TRACE("BufferRemaining=%u", BufferRemaining); ntStatus = STATUS_INSUFFICIENT_RESOURCES; } DBG_LEAVE("() = 0x%08X", ntStatus); return ntStatus; }
NTSTATUS CImageHardwareSimulation:: FillScatterGatherBuffers() /*++ Routine Description: The hardware has synthesized a buffer in scratch space and we're to fill scatter / gather buffers. Arguments: None Return Value: Success / Failure --*/ { PAGED_CODE(); DBG_ENTER("() m_PinID=0x%08X, m_ImageSize=0x%08X, m_ScatterGatherMappingsQueued=%d, " "m_ScatterGatherBytesQueue=0x%08X", m_PinID, m_ImageSize, m_ScatterGatherMappingsQueued, m_ScatterGatherBytesQueued); // // We're using this list lock to protect our scatter / gather lists instead // of some hardware mechanism / KeSynchronizeExecution / whatever. // //KeAcquireSpinLockAtDpcLevel (&m_ListLock); ULONG BufferRemaining = m_ImageSize; // // If there aren't enough scatter / gather buffers queued, consider it starvation. // while( BufferRemaining && !IsListEmpty(&m_ScatterGatherMappings) && m_ScatterGatherBytesQueued >= BufferRemaining) { DBG_TRACE( "BufferRemaining=0x%08X, m_ScatterGatherBytesQueued=0x%08X, m_ScatterGatherMappingsQueued=%d", BufferRemaining, m_ScatterGatherBytesQueued, m_ScatterGatherMappingsQueued ); LIST_ENTRY *listEntry = RemoveHeadList (&m_ScatterGatherMappings); m_ScatterGatherMappingsQueued--; PSCATTER_GATHER_ENTRY SGEntry = reinterpret_cast <PSCATTER_GATHER_ENTRY> ( CONTAINING_RECORD ( listEntry, SCATTER_GATHER_ENTRY, ListEntry ) ); // Deal with cancellation. PIRP pIrp = KsStreamPointerGetIrp(SGEntry->CloneEntry, FALSE, FALSE); if (pIrp) { if (pIrp->Cancel) { DBG_TRACE( "Cancelling..." ); FreeSGEntry( listEntry, L"StreamPointer Cancel SG List" ); continue; } } // // Since we're software, we'll be accessing this by virtual address... // ULONG BytesToCopy = min( BufferRemaining, SGEntry->ByteCount ); // Have the synthesizer output a frame to the buffer. DBG_TRACE( "DataUsed before Commit() = %d", SGEntry->CloneEntry->StreamHeader->DataUsed ); ULONG BytesCopied = m_Synthesizer->DoCommit( SGEntry->Virtual, BytesToCopy ); NT_ASSERT(BytesCopied); DBG_TRACE( "BytesCopied = %d", BytesCopied ); BufferRemaining = 0; //-= BytesCopied; // Add metadata to the sample. EmitMetadata( SGEntry -> CloneEntry -> StreamHeader ); ULONGLONG time = ConvertQPCtoTimeStamp(NULL); if (IsPhotoConfirmationNeeded()) { DBG_TRACE( "PhotoConfirmation is needed. Frame=%d, Time=0x%016llX", m_PfsFrameNumber, (LONGLONG) time ); SGEntry->PhotoConfirmationInfo = PHOTOCONFIRMATION_INFO( m_PfsFrameNumber, (LONGLONG) time ); } SGEntry -> CloneEntry -> StreamHeader -> PresentationTime.Time = time; DBG_TRACE("PresentationTime = 0x%016llX", SGEntry->CloneEntry->StreamHeader->PresentationTime.Time ); SGEntry -> CloneEntry -> StreamHeader -> OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_TIMEVALID; DBG_TRACE("m_FlashStatus=0x%016llX", m_FlashStatus); if(m_FlashStatus & KSCAMERA_EXTENDEDPROP_FLASH_ON || m_FlashStatus & KSCAMERA_EXTENDEDPROP_FLASH_ON_ADJUSTABLEPOWER || m_FlashStatus & KSCAMERA_EXTENDEDPROP_FLASH_AUTO || m_FlashStatus & KSCAMERA_EXTENDEDPROP_FLASH_AUTO_ADJUSTABLEPOWER) { if(m_FlashStatus & KSCAMERA_EXTENDEDPROP_FLASH_SINGLEFLASH && time >= m_TriggerTime && m_TriggerTime != 0 && !m_bFlashed) { m_bFlashed = TRUE; DBG_TRACE("(Single) FLASHED!!!"); } } // // Release the scatter / gather entry back to our lookaside. // if( m_bTriggered && !IsPfsEOS() ) { DBG_TRACE("m_PinMode=%d", m_PinMode); m_pClone = SGEntry->CloneEntry; m_PhotoConfirmationInfo = SGEntry->PhotoConfirmationInfo; m_NumMappingsCompleted++; m_ScatterGatherBytesQueued -= SGEntry -> ByteCount; DBG_TRACE( "m_NumMappingsCompleted=%d, m_PhotoConfirmationInfo.isRequired()=%s", m_NumMappingsCompleted, m_PhotoConfirmationInfo.isRequired()?"TRUE":"FALSE" ); if(m_PinMode != PinBurstMode) { m_bTriggered = FALSE; DBG_TRACE("m_bTriggered=FALSE"); } // Update the VPS frame and loop numbers here. Mark the frame as the EOS // if we've completed the sequence. // // Note: It's actually up to DevProxy to stop feeding us frames! if( AdvanceFrameCounter() ) { // We've reached the end of a VPS sequence! Mark the frame as EOS. SGEntry->CloneEntry->StreamHeader->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_ENDOFPHOTOSEQUENCE; m_bEndOfSequence = TRUE; } ExFreeToNPagedLookasideList ( &m_ScatterGatherLookaside, reinterpret_cast <PVOID> (SGEntry) ); } else { InsertTailList( &m_ScatterGatherMappings, listEntry ); m_ScatterGatherMappingsQueued++; m_pClone = NULL; } } DBG_LEAVE("()"); if (BufferRemaining) { return STATUS_INSUFFICIENT_RESOURCES; } else { return STATUS_SUCCESS; } }