diff options
| author | J M Rossy <[email protected]> | 2015-07-29 15:40:09 -0700 |
|---|---|---|
| committer | J M Rossy <[email protected]> | 2015-07-29 16:34:40 -0700 |
| commit | 5d61a4a79a1e96dc5d9af1e5e712c84507307544 (patch) | |
| tree | 49ed270893578cd18758b74ffcca16dc7ab948d6 /avstream/avshws/hwsim.cpp | |
| parent | 5d41613e26e147d2300c786bb2b34cb4b4067a25 (diff) | |
Samples update for public Windows 10 release
Fix #2 Enabling WPP Recorder in Sensors Samples causes errors
Fix #4 Add back fixed KMDOD sample
Add new BarcodeScanner sample in pos folder
Add new MagneticStripeReader sample in pos folder
Add new SynpaticsTouch sample in input folder
Add new Power Engine Plugin sample in pofx folder
Add new DeviceMft sample in avstream folder
Add new AvsCamera sample in root
Add new SimBatt sample in root
Add other pre-existing samples not yet released for Win10
Diffstat (limited to 'avstream/avshws/hwsim.cpp')
| -rw-r--r-- | avstream/avshws/hwsim.cpp | 868 |
1 files changed, 868 insertions, 0 deletions
diff --git a/avstream/avshws/hwsim.cpp b/avstream/avshws/hwsim.cpp new file mode 100644 index 00000000..9a6d5f86 --- /dev/null +++ b/avstream/avshws/hwsim.cpp @@ -0,0 +1,868 @@ +/************************************************************************** + + AVStream Simulated Hardware Sample + + Copyright (c) 2001, Microsoft Corporation. + + File: + + hwsim.cpp + + Abstract: + + This file contains the hardware simulation. It fakes "DMA" transfers, + scatter gather mapping handling, ISR's, etc... The ISR routine in + here will be called when an ISR would be generated by the fake hardware + and it will directly call into the device level ISR for more accurate + simulation. + + History: + + created 3/9/2001 + +**************************************************************************/ + +#include "avshws.h" + + +/*************************************************/ +KDEFERRED_ROUTINE SimulatedInterrupt; + +void +SimulatedInterrupt ( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArg1, + IN PVOID SystemArg2 + ) +{ + CHardwareSimulation* HardwareSim = (CHardwareSimulation*)DeferredContext; + + if (HardwareSim) + { + HardwareSim -> FakeHardware (); + } +} + + +/************************************************************************** + + PAGEABLE CODE + +**************************************************************************/ + +#ifdef ALLOC_PRAGMA +#pragma code_seg("PAGE") +#endif // ALLOC_PRAGMA + + + +CHardwareSimulation:: +CHardwareSimulation ( + IN IHardwareSink *HardwareSink + ) : + m_HardwareSink (HardwareSink), + m_ScatterGatherMappingsMax (SCATTER_GATHER_MAPPINGS_MAX) + +/*++ + +Routine Description: + + Construct a hardware simulation + +Arguments: + + HardwareSink - + The hardware sink interface. This is used to trigger + fake interrupt service routines from. + +Return Value: + + Success / Failure + +--*/ + +{ + + PAGED_CODE(); + + // + // Initialize the DPC's, timer's, and locks necessary to simulate + // this capture hardware. + // + KeInitializeDpc ( + &m_IsrFakeDpc, + SimulatedInterrupt, + this + ); + + KeInitializeEvent ( + &m_HardwareEvent, + SynchronizationEvent, + FALSE + ); + + KeInitializeTimer (&m_IsrTimer); + + KeInitializeSpinLock (&m_ListLock); + +} + +/*************************************************/ + + +CHardwareSimulation * +CHardwareSimulation:: +Initialize ( + IN KSOBJECT_BAG Bag, + IN IHardwareSink *HardwareSink + ) + +/*++ + +Routine Description: + + Initialize the hardware simulation + +Arguments: + + HardwareSink - + The hardware sink interface. This is what ISR's will be + triggered through. + +Return Value: + + A fully initialized hardware simulation or NULL if the simulation + could not be initialized. + +--*/ + +{ + + PAGED_CODE(); + + CHardwareSimulation *HwSim = + new (NonPagedPoolNx, 'miSH') CHardwareSimulation (HardwareSink); + + return HwSim; + +} + +/*************************************************/ + + +NTSTATUS +CHardwareSimulation:: +Start ( + IN CImageSynthesizer *ImageSynth, + IN LONGLONG TimePerFrame, + IN ULONG Width, + IN ULONG Height, + IN ULONG ImageSize + ) + +/*++ + +Routine Description: + + Start the hardware simulation. This will kick the interrupts on, + begin issuing DPC's, filling in capture information, etc... + We keep track of starvation starting at this point. + +Arguments: + + ImageSynth - + The image synthesizer to use to generate pictures to display + on the capture buffer. + + TimePerFrame - + The time per frame... we issue interrupts this often. + + Width - + The image width + + Height - + The image height + + ImageSize - + The size of the image. We allocate a temporary scratch buffer + based on this size to fake hardware. + +Return Value: + + Success / Failure (typical failure will be out of memory on the + scratch buffer, etc...) + +--*/ + +{ + + PAGED_CODE(); + + NTSTATUS Status = STATUS_SUCCESS; + + m_ImageSynth = ImageSynth; + m_TimePerFrame = TimePerFrame; + m_ImageSize = ImageSize; + m_Height = Height; + m_Width = Width; + + InitializeListHead (&m_ScatterGatherMappings); + m_NumMappingsCompleted = 0; + m_ScatterGatherMappingsQueued = 0; + m_NumFramesSkipped = 0; + m_InterruptTime = 0; + + KeQuerySystemTime (&m_StartTime); + + // + // Allocate a scratch buffer for the synthesizer. + // + m_SynthesisBuffer = reinterpret_cast <PUCHAR> ( + ExAllocatePoolWithTag ( + NonPagedPoolNx, + m_ImageSize, + AVSHWS_POOLTAG + ) + ); + + if (!m_SynthesisBuffer) { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + // + // If everything is ok, start issuing interrupts. + // + if (NT_SUCCESS (Status)) { + + // + // Initialize the entry lookaside. + // + ExInitializeNPagedLookasideList ( + &m_ScatterGatherLookaside, + NULL, + NULL, + POOL_NX_ALLOCATION, + sizeof (SCATTER_GATHER_ENTRY), + 'nEGS', + 0 + ); + + // + // Set up the synthesizer with the width, height, and scratch buffer. + // + m_ImageSynth -> SetImageSize (m_Width, m_Height); + m_ImageSynth -> SetBuffer (m_SynthesisBuffer); + + LARGE_INTEGER NextTime; + NextTime.QuadPart = m_StartTime.QuadPart + m_TimePerFrame; + + m_HardwareState = HardwareRunning; + KeSetTimer (&m_IsrTimer, NextTime, &m_IsrFakeDpc); + + } + + return Status; + +} + +/*************************************************/ + + +NTSTATUS +CHardwareSimulation:: +Pause ( + BOOLEAN Pausing + ) + +/*++ + +Routine Description: + + Pause the hardware simulation... When the hardware simulation is told + to pause, it stops issuing interrupts, etc... but it does not reset + the counters + +Arguments: + + Pausing - + Indicates whether the hardware is pausing or not. + + TRUE - + Pause the hardware + + FALSE - + Unpause the hardware from a previous pause + + +Return Value: + + Success / Failure + +--*/ + +{ + + PAGED_CODE(); + + if (Pausing && m_HardwareState == HardwareRunning) { + // + // If we were running, stop completing mappings, etc... + // + m_StopHardware = TRUE; + + KeWaitForSingleObject ( + &m_HardwareEvent, + Suspended, + KernelMode, + FALSE, + NULL + ); + + NT_ASSERT (m_StopHardware == FALSE); + + m_HardwareState = HardwarePaused; + + } else if (!Pausing && m_HardwareState == HardwarePaused) { + + // + // For unpausing the hardware, we need to compute the relative time + // and restart interrupts. + // + LARGE_INTEGER UnpauseTime; + + KeQuerySystemTime (&UnpauseTime); + m_InterruptTime = (ULONG) ( + (UnpauseTime.QuadPart - m_StartTime.QuadPart) / + m_TimePerFrame + ); + + UnpauseTime.QuadPart = m_StartTime.QuadPart + + (m_InterruptTime + 1) * m_TimePerFrame; + + m_HardwareState = HardwareRunning; + KeSetTimer (&m_IsrTimer, UnpauseTime, &m_IsrFakeDpc); + + } + + return STATUS_SUCCESS; + +} + +/************************************************************************** + + LOCKED CODE + +**************************************************************************/ + +#ifdef ALLOC_PRAGMA +#pragma code_seg() +#endif // ALLOC_PRAGMA + +NTSTATUS +CHardwareSimulation:: +Stop ( + ) + +/*++ + +Routine Description: + + Stop the hardware simulation.... Wait until the hardware simulation + has successfully stopped and then return. + +Arguments: + + None + +Return Value: + + Success / Failure + +--*/ + +{ + KIRQL Irql; + // + // If the hardware is told to stop while it's running, we need to + // halt the interrupts first. If we're already paused, this has + // already been done. + // + if (m_HardwareState == HardwareRunning) { + + m_StopHardware = TRUE; + + KeWaitForSingleObject ( + &m_HardwareEvent, + Suspended, + KernelMode, + FALSE, + NULL + ); + + NT_ASSERT (m_StopHardware == FALSE); + + } + + m_HardwareState = HardwareStopped; + + // + // The image synthesizer may still be around. Just for safety's + // sake, NULL out the image synthesis buffer and toast it. + // + m_ImageSynth -> SetBuffer (NULL); + + if (m_SynthesisBuffer) { + ExFreePool (m_SynthesisBuffer); + m_SynthesisBuffer = NULL; + } + + // + // Protect the S/G list + // + KeAcquireSpinLock (&m_ListLock, &Irql); + // + // Free S/G buffer + // + // + while (m_ScatterGatherMappingsQueued > 0) { + LIST_ENTRY *listEntry = RemoveHeadList (&m_ScatterGatherMappings); + m_ScatterGatherMappingsQueued--; + PSCATTER_GATHER_ENTRY SGEntry = + reinterpret_cast <PSCATTER_GATHER_ENTRY> ( + CONTAINING_RECORD ( + listEntry, + SCATTER_GATHER_ENTRY, + ListEntry + ) + ); + // + // Release the scatter / gather entry back to our lookaside. + // + ExFreeToNPagedLookasideList ( + &m_ScatterGatherLookaside, + reinterpret_cast <PVOID> (SGEntry) + ); + } + + m_NumMappingsCompleted = 0; + m_ScatterGatherBytesQueued = 0; + // + // Delete the scatter / gather lookaside for this run. + // + ExDeleteNPagedLookasideList (&m_ScatterGatherLookaside); + + KeReleaseSpinLock (&m_ListLock, Irql); + + return STATUS_SUCCESS; + +} + + +ULONG +CHardwareSimulation:: +ReadNumberOfMappingsCompleted ( + ) + +/*++ + +Routine Description: + + Read the number of scatter / gather mappings which have been + completed (TOTAL NUMBER) since the last reset of the simulated + hardware + +Arguments: + + None + +Return Value: + + Total number of completed mappings. + +--*/ + +{ + + // + // Don't care if this is being updated this moment in the DPC... I only + // need a number to return which isn't too great (too small is ok). + // In real hardware, this wouldn't be done this way anyway. + // + return m_NumMappingsCompleted; + +} + +/*************************************************/ + + +ULONG +CHardwareSimulation:: +ProgramScatterGatherMappings ( + IN PKSSTREAM_POINTER Clone, + IN PUCHAR *Buffer, + IN PKSMAPPING Mappings, + IN ULONG MappingsCount, + IN ULONG MappingStride + ) + +/*++ + +Routine Description: + + Program the scatter gather mapping list. This shoves a bunch of + entries on a list for access during the fake interrupt. Note that + we have physical addresses here only for simulation. We really + access via the virtual address.... although we chunk it into multiple + buffers to more realistically simulate S/G + +Arguments: + + Buffer - + The virtual address of the buffer mapped by the mapping list + + 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. + +--*/ + +{ + + KIRQL Irql; + + ULONG MappingsInserted = 0; + + // + // Protect our S/G list with a spinlock. + // + KeAcquireSpinLock (&m_ListLock, &Irql); + + // + // 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. + // +#if !defined(_X86_) + do + { + PSCATTER_GATHER_ENTRY Entry = + reinterpret_cast <PSCATTER_GATHER_ENTRY> ( + ExAllocateFromNPagedLookasideList ( + &m_ScatterGatherLookaside + ) + ); + + if (!Entry) { + break; + } + Entry -> Virtual = *Buffer; + Entry -> ByteCount = MappingsCount; + Entry -> CloneEntry = Clone; + + // + // 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)); + MappingsInserted = MappingsCount; + m_ScatterGatherMappingsQueued++; + m_ScatterGatherBytesQueued += MappingsCount; + + } + while(FALSE); + +#else + for (ULONG MappingNum = 0; + MappingNum < MappingsCount && + m_ScatterGatherMappingsQueued < m_ScatterGatherMappingsMax; + MappingNum++) { + + PSCATTER_GATHER_ENTRY Entry = + reinterpret_cast <PSCATTER_GATHER_ENTRY> ( + ExAllocateFromNPagedLookasideList ( + &m_ScatterGatherLookaside + ) + ); + + if (!Entry) { + break; + } + + Entry -> Virtual = *Buffer; + Entry -> ByteCount = Mappings -> ByteCount; + + // + // Move forward a specific number of bytes in chunking this into + // mapping sized va buffers. + // + *Buffer += Entry -> ByteCount; + Mappings = reinterpret_cast <PKSMAPPING> ( + (reinterpret_cast <PUCHAR> (Mappings) + MappingStride) + ); + + InsertTailList (&m_ScatterGatherMappings, &(Entry -> ListEntry)); + MappingsInserted++; + m_ScatterGatherMappingsQueued++; + m_ScatterGatherBytesQueued += Entry -> ByteCount; + + } +#endif + + KeReleaseSpinLock (&m_ListLock, Irql); + + return MappingsInserted; + +} + +/*************************************************/ + + +NTSTATUS +CHardwareSimulation:: +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 + +--*/ + +{ + + // + // We're using this list lock to protect our scatter / gather lists instead + // of some hardware mechanism / KeSynchronizeExecution / whatever. + // + KeAcquireSpinLockAtDpcLevel (&m_ListLock); + + PUCHAR Buffer = reinterpret_cast <PUCHAR> (m_SynthesisBuffer); + ULONG BufferRemaining = m_ImageSize; + + // + // For simplification, if there aren't enough scatter / gather buffers + // queued, we don't partially fill the ones that are available. We just + // skip the frame and consider it starvation. + // + // This could be enforced by only programming scatter / gather mappings + // for a buffer if all of them fit in the table also... + // + while (BufferRemaining && + m_ScatterGatherMappingsQueued > 0 && + 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 + ) + ); + + // + // Since we're software, we'll be accessing this by virtual address... + // + ULONG BytesToCopy = + (BufferRemaining < SGEntry -> ByteCount) ? + BufferRemaining : + SGEntry -> ByteCount; + + LONG Width = m_Width*(m_ImageSynth->GetBytesPerPixel()); + + LONG Stride = Width; + 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); + if(FrameInfo->lSurfacePitch != 0) + { + Stride = FrameInfo->lSurfacePitch; + if(FrameInfo->lSurfacePitch < 0) + { + Stride = -Stride; + } + } + } + + for(ULONG y = 0; y < m_Height; y++) + { + RtlCopyMemory((SGEntry->Virtual+(ULONG)Stride*y), Buffer, Width); + Buffer += Width; + BytesToCopy -= Width; + BufferRemaining -= Width; + } + + m_NumMappingsCompleted++; + m_ScatterGatherBytesQueued -= SGEntry -> ByteCount; + + // + // Release the scatter / gather entry back to our lookaside. + // + ExFreeToNPagedLookasideList ( + &m_ScatterGatherLookaside, + reinterpret_cast <PVOID> (SGEntry) + ); + + } + + KeReleaseSpinLockFromDpcLevel (&m_ListLock); + + if (BufferRemaining) return STATUS_INSUFFICIENT_RESOURCES; + else return STATUS_SUCCESS; + +} + +/*************************************************/ + + +void +CHardwareSimulation:: +FakeHardware ( + ) + +/*++ + +Routine Description: + + Simulate an interrupt and what the hardware would have done in the + time since the previous interrupt. + +Arguments: + + None + +Return Value: + + None + +--*/ + +{ + + m_InterruptTime++; + + // + // The hardware can be in a pause state in which case, it issues interrupts + // but does not complete mappings. In this case, don't bother synthesizing + // a frame and doing the work of looking through the mappings table. + // + if (m_HardwareState == HardwareRunning) { + + // + // Generate a "time stamp" just to overlay it onto the capture image. + // It makes it more exciting than bars that do nothing. + // + LONGLONG PtsRel = ((m_InterruptTime + 1) * m_TimePerFrame); + + ULONG Min = (ULONG)(PtsRel / 600000000); + ULONG RemMin = (ULONG)(PtsRel % 600000000); + ULONG Sec = (ULONG)(RemMin / 10000000); + ULONG RemSec = (ULONG)(RemMin % 10000000); + ULONG Hund = (ULONG)(RemSec / 100000); + + // + // Synthesize a buffer in scratch space. + // + m_ImageSynth -> SynthesizeBars (); + + CHAR Text [256]; + Text[0] = '\0'; + (void) RtlStringCbPrintfA(Text, sizeof(Text), "%ld:%02ld.%02ld", Min, Sec, Hund); + + // + // Overlay a clock onto the scratch space image. + // + m_ImageSynth -> OverlayText ( + POSITION_CENTER, + (m_Height - 28), + 1, + Text, + BLACK, + WHITE + ); + + // + // Overlay a counter of skipped frames onto the scratch image. + // + (void) RtlStringCbPrintfA(Text, sizeof(Text), "Skipped: %ld", m_NumFramesSkipped); + m_ImageSynth -> OverlayText ( + 10, + 10, + 1, + Text, + TRANSPARENT, + BLUE + ); + + // + // Fill scatter gather buffers + // + if (!NT_SUCCESS (FillScatterGatherBuffers ())) { + InterlockedIncrement (PLONG (&m_NumFramesSkipped)); + } + + } + + // + // Issue an interrupt to our hardware sink. This is a "fake" interrupt. + // It will occur at DISPATCH_LEVEL. + // + m_HardwareSink -> Interrupt (); + + // + // Reschedule the timer if the hardware isn't being stopped. + // + if (!m_StopHardware) { + + // + // Reschedule the timer for the next interrupt time. + // + LARGE_INTEGER NextTime; + NextTime.QuadPart = m_StartTime.QuadPart + + (m_TimePerFrame * (m_InterruptTime + 1)); + + KeSetTimer (&m_IsrTimer, NextTime, &m_IsrFakeDpc); + + } else { + // + // If someone is waiting on the hardware to stop, raise the stop + // event and clear the flag. + // + m_StopHardware = FALSE; + KeSetEvent (&m_HardwareEvent, IO_NO_INCREMENT, FALSE); + } + +} |
