NTSTATUS CHardwareSimulation:: GeneratePhotoConfirmation( _In_ ULONG PfsFrameNumber, _In_ LONGLONG time ) /*++ Routine Description: So a photo sim can ask a preview sim for a confirmation frame. Arguments: PfsFrameNumber - The VPS shot number. time - The precise time of the associated photo. Return Value: None --*/ { PAGED_CODE(); KScopedMutex Lock( m_ListLock ); if( PinRunning != m_PinState ) { return STATUS_DEVICE_NOT_READY; } DBG_ENTER("( Index=%d, Time=0x%016llX )", PfsFrameNumber, time ); m_PhotoConfirmationEntry = PHOTOCONFIRMATION_INFO( PfsFrameNumber, time ); // We basically used the previously synthesized preview image NTSTATUS status = FillScatterGatherBuffers(); //Clean up the photo confiramtion flag m_PhotoConfirmationEntry = PHOTOCONFIRMATION_INFO(); if(NT_SUCCESS(status)) { m_Sensor->Interrupt (m_PinID); } DBG_LEAVE("() = 0x%08X", status); return status; }
ULONG CHardwareSimulation:: ProgramScatterGatherMappings ( IN PKSSTREAM_POINTER *Clone, IN PUCHAR *Buffer, IN PKSMAPPING Mappings, IN ULONG MappingsCount, IN ULONG MappingStride ) /*++ Routine Description: Add a single entry to our queue. In practice our simulation can only accept one frame at a time, but we still base this code off of the avshws sample. Arguments: Buffer - The virtual address of the buffer mapped by the mapping list ClonePointer The KSStreamClone Pointer to be associated with the entry item Mappings - The KSMAPPINGS array corresponding to the buffer MappingsCount - The number of mappings in the mappings array MappingStride - The mapping stride used in initialization of AVStream DMA Return Value: Number of mappings actually inserted. --*/ { PAGED_CODE(); ULONG MappingsInserted = 0; DBG_ENTER("(Clone=%p, Buffer=%p, MappingsCount=%d)", Clone, Buffer, MappingsCount); // // Protect our S/G list with a spinlock. // KScopedMutex Lock( m_ListLock ); // // Loop through the scatter / gather list and break the buffer up into // chunks equal to the scatter / gather mappings. Stuff the virtual // addresses of these chunks on a list somewhere. We update the buffer // pointer the caller passes as a more convenient way of doing this. // // If I could just remap physical in the list to virtual easily here, // I wouldn't need to do it. // do { PSCATTER_GATHER_ENTRY Entry = reinterpret_cast <PSCATTER_GATHER_ENTRY> ( ExAllocateFromNPagedLookasideList ( &m_ScatterGatherLookaside ) ); if (!Entry) { break; } Entry ->CloneEntry = nullptr; Entry -> Virtual = nullptr; Entry -> ByteCount = 0; Entry ->CloneEntry = *Clone; Entry -> CloneEntry -> StreamHeader -> PresentationTime.Time = 0; Entry -> CloneEntry -> StreamHeader -> OptionsFlags &= ~KSSTREAM_HEADER_OPTIONSF_TIMEVALID; Entry -> Virtual = *Buffer; Entry -> ByteCount = MappingsCount; Entry->PhotoConfirmationInfo = PHOTOCONFIRMATION_INFO(); // // Move forward a specific number of bytes in chunking this into // mapping sized va buffers. // *Buffer += MappingsCount; Mappings = reinterpret_cast <PKSMAPPING> ( (reinterpret_cast <PUCHAR> (Mappings) + MappingStride) ); InsertTailList (&m_ScatterGatherMappings, &(Entry -> ListEntry)); m_ScatterGatherMappingsQueued++; MappingsInserted = MappingsCount; DBG_TRACE("m_ScatterGatherMappingsQueued=%d", m_ScatterGatherMappingsQueued); m_ScatterGatherBytesQueued += MappingsCount; } while(FALSE); DBG_LEAVE(" MappingsInserted=%d", MappingsInserted ); return MappingsInserted; }
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; } }