Example #1
0
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;
}
Example #2
0
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;
    }
}