Author: janderwald
Date: Mon Nov 1 00:26:59 2010
New Revision: 49389
URL:
http://svn.reactos.org/svn/reactos?rev=49389&view=rev
Log:
[PORTCLS]
- Add MPU-401 Uart miniport driver from DDK 2003 sample
Modified:
trunk/reactos/drivers/wdm/audio/backpln/portcls/guids.cpp
trunk/reactos/drivers/wdm/audio/backpln/portcls/miniport_dmus.cpp
trunk/reactos/drivers/wdm/audio/backpln/portcls/private.hpp
Modified: trunk/reactos/drivers/wdm/audio/backpln/portcls/guids.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/backpln/…
==============================================================================
--- trunk/reactos/drivers/wdm/audio/backpln/portcls/guids.cpp [iso-8859-1] (original)
+++ trunk/reactos/drivers/wdm/audio/backpln/portcls/guids.cpp [iso-8859-1] Mon Nov 1
00:26:59 2010
@@ -35,7 +35,6 @@
const GUID CLSID_MiniportDriverFmSynth = {0xb4c90ae0L, 0x5791, 0x11d0, {0x86, 0xf9, 0x00,
0xa0, 0xc9, 0x11, 0xb5, 0x44}};
const GUID CLSID_MiniportDriverFmSynthWithVol = {0xe5a3c139L, 0xf0f2, 0x11d1, {0x81,
0xaf, 0x00, 0x60, 0x08, 0x33, 0x16, 0xc1}};
-
const GUID IID_IPort = {0xb4c90a25L, 0x5791, 0x11d0, {0x86, 0xf9, 0x00, 0xa0, 0xc9,
0x11, 0xb5, 0x44}};
const GUID IID_IDrmPort = {0x286D3DF8L, 0xCA22, 0x4E2E, {0xB9, 0xBC, 0x20, 0xB4, 0xF0,
0xE2, 0x01, 0xCE}};
const GUID IID_IDrmPort2 = {0x1ACCE59CL, 0x7311, 0x4B6B, {0x9F, 0xBA, 0xCC, 0x3B, 0xA5,
0x9A, 0xCD, 0xCE}};
@@ -46,6 +45,7 @@
const GUID IID_IPortDMus = {0xc096df9cL, 0xfb09, 0x11d1, {0x81, 0xb0, 0x00, 0x60,
0x08, 0x33, 0x16, 0xc1}};
const GUID IID_IAdapterPowerManagement = {0x793417D0L, 0x35FE, 0x11D1, {0xAD, 0x08, 0x00,
0xA0, 0xC9, 0x0A, 0xB1, 0xB0}};
+const GUID IID_IMiniport = {0xb4c90a24, 0x5791, 0x11d0, {0x86, 0xf9, 0x00, 0xa0, 0xc9,
0x11, 0xb5, 0x44}};
const GUID IID_IMiniportWaveCyclic = {0xb4c90a27L, 0x5791, 0x11d0, {0x86, 0xf9, 0x00,
0xa0, 0xc9, 0x11, 0xb5, 0x44}};
const GUID IID_IPortWaveCyclic = {0xb4c90a26L, 0x5791, 0x11d0, {0x86, 0xf9, 0x00, 0xa0,
0xc9, 0x11, 0xb5, 0x44}};
const GUID IID_IResourceList = {0x22C6AC60L, 0x851B, 0x11D0, {0x9A, 0x7F, 0x00, 0xAA,
0x00, 0x38, 0xAC, 0xFE}};
@@ -59,6 +59,7 @@
const GUID IID_IPortClsVersion = {0x7D89A7BBL, 0x869B, 0x4567, {0x8D, 0xBE, 0x1E, 0x16,
0x8C, 0xC8, 0x53, 0xDE}};
const GUID IID_IUnknown = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0xC0, 0x00, 0x00,
0x00, 0x00, 0x46}};
const GUID IID_IPortEvents = {0xA80F29C4L, 0x5498, 0x11D2, {0x95, 0xD9, 0x00, 0xC0, 0x4F,
0xB9, 0x25, 0xD3}};
+const GUID IID_IMusicTechnology = {0x80396C3C, 0xCBCB, 0x409B, {0x9F, 0x65, 0x4F, 0x1E,
0x74, 0x67, 0xCD, 0xAF}};
const GUID KSNAME_PIN = {0x146F1A80, 0x4791, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB,
0x04, 0xC1, 0x00, 0x00}};
const GUID IID_IDrmAudioStream = {0x1915c967, 0x3299, 0x48cb, {0xa3, 0xe4, 0x69, 0xfd,
0x1d, 0x1b, 0x30, 0x6e}};
@@ -69,7 +70,13 @@
const GUID KS_CATEGORY_RENDER = {0x65E8773E, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0,
0xC9, 0x22, 0x31, 0x96}};
const GUID KS_CATEGORY_CAPTURE = {0x65E8773D, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0,
0xC9, 0x22, 0x31, 0x96}};
const GUID KS_CATEGORY_TOPOLOGY = {0xDDA54A40, 0x1E4C, 0x11D1, {0xA0, 0x50, 0x40, 0x57,
0x05, 0xC1, 0x00, 0x00}};
+const GUID KSCATEGORY_AUDIO = {0x6994AD04L, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0,
0xC9, 0x22, 0x31, 0x96}};
+
+const GUID KSNODETYPE_SYNTHESIZER = {0xDFF220F3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00,
0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSAUDFNAME_DMUSIC_MPU_IN = {0xB2EC0A7D, 0xBAC9, 0x11d2, {0xB7, 0xA8, 0x00,
0x60, 0x08, 0x33, 0x16, 0xC1}};
+const GUID KSAUDFNAME_MIDI = {0x185FEDF8L, 0x9905, 0x11D1, {0x95, 0xA9, 0x00,
0xC0, 0x4F, 0xB9, 0x25, 0xD3}};
+const GUID KSAUDFNAME_DMUSIC_MPU_OUT = {0xA4DF0EB5, 0xBAC9, 0x11d2, {0xB7, 0xA8, 0x00,
0x60, 0x08, 0x33, 0x16, 0xC1}};
const GUID KSDATAFORMAT_TYPE_AUDIO = {0x73647561L, 0x0000, 0x0010, {0x80,
0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001L, 0x0000, 0x0010, {0x80,
0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
@@ -80,13 +87,16 @@
const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5,
0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
const GUID KSPROPTYPESETID_General = {0x97E99BA0L, 0xBDEA, 0x11CF, {0xA5,
0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
const GUID KSPROPSETID_DrmAudioStream = {0x2f2c8ddd, 0x4198, 0x4fac, {0xba,
0x29, 0x61, 0xbb, 0x05, 0xb7, 0xde, 0x06}};
+const GUID KSPROPSETID_Synth = {0xfedfae25L, 0xe46e, 0x11d1, {0xaa, 0xce, 0x00, 0x00,
0xf8, 0x75, 0xac, 0x12}};
+const GUID KSPROPSETID_Audio = {0x45FFAAA0L, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45,
0x53, 0x54, 0x00, 0x00}};
const GUID KSEVENTSETID_LoopedStreaming = {0x4682B940L, 0xC6EF, 0x11D0, {0x96,
0xD8, 0x00, 0xAA, 0x00, 0x51, 0xE5, 0x1D}};
const GUID KSEVENTSETID_Connection = {0x7f4bcbe0L, 0x9ea5, 0x11cf, {0xa5,
0xd6, 0x28, 0xdb, 0x04, 0xc1, 0x00, 0x00}};
const GUID IID_IAllocatorMXF = {0xa5f0d62cL, 0xb30f, 0x11d2, {0xb7,
0xa3, 0x00, 0x60, 0x08, 0x33, 0x16, 0xc1}};
+const GUID IID_IMXF = {0xc096df9e, 0xfb09, 0x11d1, {0x81,
0xb0, 0x00, 0x60, 0x08, 0x33, 0x16, 0xc1}};
+const GUID KSMUSIC_TECHNOLOGY_PORT = {0x86C92E60, 0x62E8, 0x11CF, {0xA5,
0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
-const GUID KSPROPSETID_Audio = {0x45FFAAA0L, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45,
0x53, 0x54, 0x00, 0x00}};
///
/// undocumented guids
Modified: trunk/reactos/drivers/wdm/audio/backpln/portcls/miniport_dmus.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/backpln/…
==============================================================================
--- trunk/reactos/drivers/wdm/audio/backpln/portcls/miniport_dmus.cpp [iso-8859-1]
(original)
+++ trunk/reactos/drivers/wdm/audio/backpln/portcls/miniport_dmus.cpp [iso-8859-1] Mon Nov
1 00:26:59 2010
@@ -1,15 +1,92 @@
-/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS Kernel Streaming
- * FILE: drivers/wdm/audio/backpln/portcls/miniport_dmus.cpp
- * PURPOSE: DirectMusic miniport
- * PROGRAMMER: Johannes Anderwald
- */
-
#include "private.hpp"
-class CMiniportDMus : public IMiniportDMus
-{
+// + for absolute / - for relative
+#define kOneMillisec (10 * 1000)
+
+//
+// MPU401 ports
+//
+#define MPU401_REG_STATUS 0x01 // Status register
+#define MPU401_DRR 0x40 // Output ready (for command or data)
+ // if this bit is set, the output FIFO is FULL
+#define MPU401_DSR 0x80 // Input ready (for data)
+ // if this bit is set, the input FIFO is empty
+
+#define MPU401_REG_DATA 0x00 // Data in
+#define MPU401_REG_COMMAND 0x01 // Commands
+#define MPU401_CMD_RESET 0xFF // Reset command
+#define MPU401_CMD_UART 0x3F // Switch to UART mod
+
+
+/*****************************************************************************
+ * Prototypes
+ */
+
+NTSTATUS NTAPI InitMPU(IN PINTERRUPTSYNC InterruptSync,IN PVOID DynamicContext);
+NTSTATUS ResetHardware(PUCHAR portBase);
+NTSTATUS ValidatePropertyRequest(IN PPCPROPERTY_REQUEST pRequest, IN ULONG ulValueSize,
IN BOOLEAN fValueRequired);
+NTSTATUS NTAPI PropertyHandler_Synth(IN PPCPROPERTY_REQUEST PropertyRequest);
+NTSTATUS NTAPI DMusMPUInterruptServiceRoutine(PINTERRUPTSYNC InterruptSync,PVOID
DynamicContext);
+VOID NTAPI DMusUARTTimerDPC(PKDPC Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID
SystemArgument2);
+NTSTATUS NTAPI SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync,PVOID
syncWriteContext);
+/*****************************************************************************
+ * Constants
+ */
+
+const BOOLEAN COMMAND = TRUE;
+const BOOLEAN DATA = FALSE;
+
+const ULONG kMPUInputBufferSize = 128;
+
+
+/*****************************************************************************
+ * Classes
+ */
+
+/*****************************************************************************
+ * CMiniportDMusUART
+ *****************************************************************************
+ * MPU-401 miniport. This object is associated with the device and is
+ * created when the device is started. The class inherits IMiniportDMus
+ * so it can expose this interface and CUnknown so it automatically gets
+ * reference counting and aggregation support.
+ */
+class CMiniportDMusUART
+: public IMiniportDMus,
+ public IMusicTechnology,
+ public IPowerNotify
+{
+private:
+ LONG m_Ref; // Reference count
+ KSSTATE m_KSStateInput; // Miniport state (RUN/PAUSE/ACQUIRE/STOP)
+ PPORTDMUS m_pPort; // Callback interface.
+ PUCHAR m_pPortBase; // Base port address.
+ PINTERRUPTSYNC m_pInterruptSync; // Interrupt synchronization object.
+ PSERVICEGROUP m_pServiceGroup; // Service group for capture.
+ PMASTERCLOCK m_MasterClock; // for input data
+ REFERENCE_TIME m_InputTimeStamp; // capture data timestamp
+ USHORT m_NumRenderStreams; // Num active render streams.
+ USHORT m_NumCaptureStreams; // Num active capture streams.
+ ULONG m_MPUInputBufferHead; // Index of the newest byte in the FIFO.
+ ULONG m_MPUInputBufferTail; // Index of the oldest empty space in the
FIFO.
+ GUID m_MusicFormatTechnology;
+ POWER_STATE m_PowerState; // Saved power state (D0 = full power, D3 =
off)
+ BOOLEAN m_fMPUInitialized; // Is the MPU HW initialized.
+ BOOLEAN m_UseIRQ; // FALSE if no IRQ is used for MIDI.
+ UCHAR m_MPUInputBuffer[kMPUInputBufferSize]; // Internal SW FIFO.
+
+ /*************************************************************************
+ * CMiniportDMusUART methods
+ *
+ * These are private member functions used internally by the object.
+ * See MINIPORT.CPP for specific descriptions.
+ */
+ NTSTATUS ProcessResources
+ (
+ IN PRESOURCELIST ResourceList
+ );
+ NTSTATUS InitializeHardware(PINTERRUPTSYNC interruptSync,PUCHAR portBase);
+
public:
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
@@ -29,107 +106,2584 @@
}
return m_Ref;
}
- IMP_IMiniportDMus;
- CMiniportDMus(IUnknown *OuterUnknown){}
- virtual ~CMiniportDMus(){}
-
-protected:
- LONG m_Ref;
-
+
+ CMiniportDMusUART(IUnknown * Unknown){}
+ ~CMiniportDMusUART();
+
+ /*************************************************************************
+ * IMiniport methods
+ */
+ STDMETHODIMP_(NTSTATUS)
+ GetDescription
+ ( OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
+ );
+ STDMETHODIMP_(NTSTATUS)
+ DataRangeIntersection
+ ( IN ULONG PinId
+ , IN PKSDATARANGE DataRange
+ , IN PKSDATARANGE MatchingDataRange
+ , IN ULONG OutputBufferLength
+ , OUT PVOID ResultantFormat
+ , OUT PULONG ResultantFormatLength
+ )
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /*************************************************************************
+ * IMiniportDMus methods
+ */
+ STDMETHODIMP_(NTSTATUS) Init
+ (
+ IN PUNKNOWN UnknownAdapter,
+ IN PRESOURCELIST ResourceList,
+ IN PPORTDMUS Port,
+ OUT PSERVICEGROUP * ServiceGroup
+ );
+ STDMETHODIMP_(NTSTATUS) NewStream
+ (
+ OUT PMXF * Stream,
+ IN PUNKNOWN OuterUnknown OPTIONAL,
+ IN POOL_TYPE PoolType,
+ IN ULONG PinID,
+ IN DMUS_STREAM_TYPE StreamType,
+ IN PKSDATAFORMAT DataFormat,
+ OUT PSERVICEGROUP * ServiceGroup,
+ IN PAllocatorMXF AllocatorMXF,
+ IN PMASTERCLOCK MasterClock,
+ OUT PULONGLONG SchedulePreFetch
+ );
+ STDMETHODIMP_(void) Service
+ ( void
+ );
+
+ /*************************************************************************
+ * IMusicTechnology methods
+ */
+ IMP_IMusicTechnology;
+
+ /*************************************************************************
+ * IPowerNotify methods
+ */
+ IMP_IPowerNotify;
+
+ /*************************************************************************
+ * Friends
+ */
+ friend class CMiniportDMusUARTStream;
+ friend NTSTATUS
+ DMusMPUInterruptServiceRoutine(PINTERRUPTSYNC InterruptSync,PVOID
DynamicContext);
+ friend NTSTATUS
+ SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync,PVOID syncWriteContext);
+ friend VOID NTAPI
+ DMusUARTTimerDPC(PKDPC Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID
SystemArgument2);
+ friend NTSTATUS NTAPI PropertyHandler_Synth(IN PPCPROPERTY_REQUEST PropertyRequest);
+ friend STDMETHODIMP_(NTSTATUS) SnapTimeStamp(PINTERRUPTSYNC InterruptSync,PVOID
pStream);
};
-// IUnknown methods
-
+/*****************************************************************************
+ * CMiniportDMusUARTStream
+ *****************************************************************************
+ * MPU-401 miniport stream. This object is associated with the pin and is
+ * created when the pin is instantiated. It inherits IMXF
+ * so it can expose this interface and CUnknown so it automatically gets
+ * reference counting and aggregation support.
+ */
+class CMiniportDMusUARTStream : public IMXF
+{
+private:
+ LONG m_Ref; // Reference Count
+ CMiniportDMusUART * m_pMiniport; // Parent.
+ REFERENCE_TIME m_SnapshotTimeStamp; // Current snapshot of miniport's
input timestamp.
+ PUCHAR m_pPortBase; // Base port address.
+ BOOLEAN m_fCapture; // Whether this is capture.
+ long m_NumFailedMPUTries; // Deadman timeout for MPU hardware.
+ PAllocatorMXF m_AllocatorMXF; // source/sink for DMus structs
+ PMXF m_sinkMXF; // sink for DMus capture
+ PDMUS_KERNEL_EVENT m_DMKEvtQueue; // queue of waiting events
+ ULONG m_NumberOfRetries; // Number of consecutive times the h/w
was busy/full
+ ULONG m_DMKEvtOffset; // offset into the event
+ KDPC m_Dpc; // DPC for timer
+ KTIMER m_TimerEvent; // timer
+ BOOL m_TimerQueued; // whether a timer has been set
+ KSPIN_LOCK m_DpcSpinLock; // protects the ConsumeEvents DPC
+
+ STDMETHODIMP_(NTSTATUS) SourceEvtsToPort();
+ STDMETHODIMP_(NTSTATUS) ConsumeEvents();
+ STDMETHODIMP_(NTSTATUS) PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt);
+
+public:
+ STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
+
+ STDMETHODIMP_(ULONG) AddRef()
+ {
+ InterlockedIncrement(&m_Ref);
+ return m_Ref;
+ }
+ STDMETHODIMP_(ULONG) Release()
+ {
+ InterlockedDecrement(&m_Ref);
+
+ if (!m_Ref)
+ {
+ delete this;
+ return 0;
+ }
+ return m_Ref;
+ }
+
+ ~CMiniportDMusUARTStream();
+
+ STDMETHODIMP_(NTSTATUS) Init
+ (
+ IN CMiniportDMusUART * pMiniport,
+ IN PUCHAR pPortBase,
+ IN BOOLEAN fCapture,
+ IN PAllocatorMXF allocatorMXF,
+ IN PMASTERCLOCK masterClock
+ );
+
+ NTSTATUS HandlePortParams
+ (
+ IN PPCPROPERTY_REQUEST Request
+ );
+
+ /*************************************************************************
+ * IMiniportStreamDMusUART methods
+ */
+ IMP_IMXF;
+
+ STDMETHODIMP_(NTSTATUS) Write
+ (
+ IN PVOID BufferAddress,
+ IN ULONG BytesToWrite,
+ OUT PULONG BytesWritten
+ );
+
+ friend VOID NTAPI
+ DMusUARTTimerDPC
+ (
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+ friend NTSTATUS PropertyHandler_Synth(IN PPCPROPERTY_REQUEST);
+ friend STDMETHODIMP_(NTSTATUS) SnapTimeStamp(PINTERRUPTSYNC InterruptSync,PVOID
pStream);
+};
+
+/*****************************************************************************
+ * miniport.cpp - UART miniport implementation
+ *****************************************************************************
+ * Copyright (c) 1997-2000 Microsoft Corporation. All Rights Reserved.
+ *
+ * Feb 98 MartinP -- based on UART, began deltas for DirectMusic.
+ */
+
+#define STR_MODULENAME "DMusUART:Miniport: "
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+
+#define UartFifoOkForWrite(status) ((status & MPU401_DRR) == 0)
+#define UartFifoOkForRead(status) ((status & MPU401_DSR) == 0)
+
+typedef struct
+{
+ CMiniportDMusUART *Miniport;
+ PUCHAR PortBase;
+ PVOID BufferAddress;
+ ULONG Length;
+ PULONG BytesRead;
+}
+SYNCWRITECONTEXT, *PSYNCWRITECONTEXT;
+
+/*****************************************************************************
+ * PinDataRangesStreamLegacy
+ * PinDataRangesStreamDMusic
+ *****************************************************************************
+ * Structures indicating range of valid format values for live pins.
+ */
+static
+KSDATARANGE_MUSIC PinDataRangesStreamLegacy =
+{
+ {
+ {
+ sizeof(KSDATARANGE_MUSIC),
+ 0,
+ 0,
+ 0,
+ {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC)},
+ {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI)},
+ {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)}
+ }
+ },
+ {STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT)},
+ 0,
+ 0,
+ 0xFFFF
+};
+static
+KSDATARANGE_MUSIC PinDataRangesStreamDMusic =
+{
+ {
+ {
+ sizeof(KSDATARANGE_MUSIC),
+ 0,
+ 0,
+ 0,
+ {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC)},
+ {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_DIRECTMUSIC)},
+ {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)}
+ }
+ },
+ {STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT)},
+ 0,
+ 0,
+ 0xFFFF
+};
+
+/*****************************************************************************
+ * PinDataRangePointersStreamLegacy
+ * PinDataRangePointersStreamDMusic
+ * PinDataRangePointersStreamCombined
+ *****************************************************************************
+ * List of pointers to structures indicating range of valid format values
+ * for live pins.
+ */
+static
+PKSDATARANGE PinDataRangePointersStreamLegacy[] =
+{
+ PKSDATARANGE(&PinDataRangesStreamLegacy)
+};
+static
+PKSDATARANGE PinDataRangePointersStreamDMusic[] =
+{
+ PKSDATARANGE(&PinDataRangesStreamDMusic)
+};
+static
+PKSDATARANGE PinDataRangePointersStreamCombined[] =
+{
+ PKSDATARANGE(&PinDataRangesStreamLegacy)
+ ,PKSDATARANGE(&PinDataRangesStreamDMusic)
+};
+
+/*****************************************************************************
+ * PinDataRangesBridge
+ *****************************************************************************
+ * Structures indicating range of valid format values for bridge pins.
+ */
+static
+KSDATARANGE PinDataRangesBridge[] =
+{
+ {
+ {
+ sizeof(KSDATARANGE),
+ 0,
+ 0,
+ 0,
+ {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC)},
+ {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI_BUS)},
+ {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)}
+ }
+ }
+};
+
+/*****************************************************************************
+ * PinDataRangePointersBridge
+ *****************************************************************************
+ * List of pointers to structures indicating range of valid format values
+ * for bridge pins.
+ */
+static
+PKSDATARANGE PinDataRangePointersBridge[] =
+{
+ &PinDataRangesBridge[0]
+};
+
+/*****************************************************************************
+ * SynthProperties
+ *****************************************************************************
+ * List of properties in the Synth set.
+ */
+static
+PCPROPERTY_ITEM
+SynthProperties[] =
+{
+ // Global: S/Get synthesizer caps
+ {
+ &KSPROPSETID_Synth,
+ KSPROPERTY_SYNTH_CAPS,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_Synth
+ },
+ // Global: S/Get port parameters
+ {
+ &KSPROPSETID_Synth,
+ KSPROPERTY_SYNTH_PORTPARAMETERS,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_Synth
+ },
+ // Per stream: S/Get channel groups
+ {
+ &KSPROPSETID_Synth,
+ KSPROPERTY_SYNTH_CHANNELGROUPS,
+ KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_Synth
+ },
+ // Per stream: Get current latency time
+ {
+ &KSPROPSETID_Synth,
+ KSPROPERTY_SYNTH_LATENCYCLOCK,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_Synth
+ }
+};
+DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth, SynthProperties);
+DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth2, SynthProperties);
+
+#define kMaxNumCaptureStreams 1
+#define kMaxNumLegacyRenderStreams 1
+#define kMaxNumDMusicRenderStreams 1
+
+/*****************************************************************************
+ * MiniportPins
+ *****************************************************************************
+ * List of pins.
+ */
+static
+PCPIN_DESCRIPTOR MiniportPins[] =
+{
+ {
+ kMaxNumLegacyRenderStreams,kMaxNumLegacyRenderStreams,0, // InstanceCount
+ NULL, // AutomationTable
+ { // KsPinDescriptor
+ 0, // InterfacesCount
+ NULL, // Interfaces
+ 0, // MediumsCount
+ NULL, // Mediums
+ SIZEOF_ARRAY(PinDataRangePointersStreamLegacy), // DataRangesCount
+ PinDataRangePointersStreamLegacy, // DataRanges
+ KSPIN_DATAFLOW_IN, // DataFlow
+ KSPIN_COMMUNICATION_SINK, // Communication
+ (GUID *) &KSCATEGORY_AUDIO, // Category
+ &KSAUDFNAME_MIDI, // Name
+ {0} // Reserved
+ }
+ },
+ {
+ kMaxNumDMusicRenderStreams,kMaxNumDMusicRenderStreams,0, // InstanceCount
+ NULL, // AutomationTable
+ { // KsPinDescriptor
+ 0, // InterfacesCount
+ NULL, // Interfaces
+ 0, // MediumsCount
+ NULL, // Mediums
+ SIZEOF_ARRAY(PinDataRangePointersStreamDMusic), // DataRangesCount
+ PinDataRangePointersStreamDMusic, // DataRanges
+ KSPIN_DATAFLOW_IN, // DataFlow
+ KSPIN_COMMUNICATION_SINK, // Communication
+ (GUID *) &KSCATEGORY_AUDIO, // Category
+ &KSAUDFNAME_DMUSIC_MPU_OUT, // Name
+ {0} // Reserved
+ }
+ },
+ {
+ 0,0,0, // InstanceCount
+ NULL, // AutomationTable
+ { // KsPinDescriptor
+ 0, // InterfacesCount
+ NULL, // Interfaces
+ 0, // MediumsCount
+ NULL, // Mediums
+ SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount
+ PinDataRangePointersBridge, // DataRanges
+ KSPIN_DATAFLOW_OUT, // DataFlow
+ KSPIN_COMMUNICATION_NONE, // Communication
+ (GUID *) &KSCATEGORY_AUDIO, // Category
+ NULL, // Name
+ {0} // Reserved
+ }
+ },
+ {
+ 0,0,0, // InstanceCount
+ NULL, // AutomationTable
+ { // KsPinDescriptor
+ 0, // InterfacesCount
+ NULL, // Interfaces
+ 0, // MediumsCount
+ NULL, // Mediums
+ SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount
+ PinDataRangePointersBridge, // DataRanges
+ KSPIN_DATAFLOW_IN, // DataFlow
+ KSPIN_COMMUNICATION_NONE, // Communication
+ (GUID *) &KSCATEGORY_AUDIO, // Category
+ NULL, // Name
+ {0} // Reserved
+ }
+ },
+ {
+ kMaxNumCaptureStreams,kMaxNumCaptureStreams,0, // InstanceCount
+ NULL, // AutomationTable
+ { // KsPinDescriptor
+ 0, // InterfacesCount
+ NULL, // Interfaces
+ 0, // MediumsCount
+ NULL, // Mediums
+ SIZEOF_ARRAY(PinDataRangePointersStreamCombined), // DataRangesCount
+ PinDataRangePointersStreamCombined, // DataRanges
+ KSPIN_DATAFLOW_OUT, // DataFlow
+ KSPIN_COMMUNICATION_SINK, // Communication
+ (GUID *) &KSCATEGORY_AUDIO, // Category
+ &KSAUDFNAME_DMUSIC_MPU_IN, // Name
+ {0} // Reserved
+ }
+ }
+};
+
+/*****************************************************************************
+ * MiniportNodes
+ *****************************************************************************
+ * List of nodes.
+ */
+#define CONST_PCNODE_DESCRIPTOR(n) { 0, NULL, &n, NULL }
+#define CONST_PCNODE_DESCRIPTOR_AUTO(n,a) { 0, &a, &n, NULL }
+static
+PCNODE_DESCRIPTOR MiniportNodes[] =
+{
+ CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER, AutomationSynth)
+ , CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER, AutomationSynth2)
+};
+
+/*****************************************************************************
+ * MiniportConnections
+ *****************************************************************************
+ * List of connections.
+ */
+enum {
+ eSynthNode = 0
+ , eInputNode
+};
+
+enum {
+ eFilterInputPinLeg = 0,
+ eFilterInputPinDM,
+ eBridgeOutputPin,
+ eBridgeInputPin,
+ eFilterOutputPin
+};
+
+static
+PCCONNECTION_DESCRIPTOR MiniportConnections[] =
+{ // From To
+ // Node pin Node pin
+ { PCFILTER_NODE, eFilterInputPinLeg, PCFILTER_NODE, eBridgeOutputPin } //
Legacy Stream in to synth.
+ , { PCFILTER_NODE, eFilterInputPinDM, eSynthNode, KSNODEPIN_STANDARD_IN } // DM
Stream in to synth.
+ , { eSynthNode, KSNODEPIN_STANDARD_OUT, PCFILTER_NODE, eBridgeOutputPin } //
Synth to bridge out.
+ , { PCFILTER_NODE, eBridgeInputPin, eInputNode, KSNODEPIN_STANDARD_IN } //
Bridge in to input.
+ , { eInputNode, KSNODEPIN_STANDARD_OUT, PCFILTER_NODE, eFilterOutputPin } //
Input to DM/Legacy Stream out.
+};
+
+/*****************************************************************************
+ * MiniportCategories
+ *****************************************************************************
+ * List of categories.
+ */
+static
+GUID MiniportCategories[] =
+{
+ {STATICGUIDOF(KSCATEGORY_AUDIO)},
+ {STATICGUIDOF(KSCATEGORY_RENDER)},
+ {STATICGUIDOF(KSCATEGORY_CAPTURE)}
+};
+
+/*****************************************************************************
+ * MiniportFilterDescriptor
+ *****************************************************************************
+ * Complete miniport filter description.
+ */
+static
+PCFILTER_DESCRIPTOR MiniportFilterDescriptor =
+{
+ 0, // Version
+ NULL, // AutomationTable
+ sizeof(PCPIN_DESCRIPTOR), // PinSize
+ SIZEOF_ARRAY(MiniportPins), // PinCount
+ MiniportPins, // Pins
+ sizeof(PCNODE_DESCRIPTOR), // NodeSize
+ SIZEOF_ARRAY(MiniportNodes), // NodeCount
+ MiniportNodes, // Nodes
+ SIZEOF_ARRAY(MiniportConnections), // ConnectionCount
+ MiniportConnections, // Connections
+ SIZEOF_ARRAY(MiniportCategories), // CategoryCount
+ MiniportCategories // Categories
+};
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+
+BOOLEAN TryMPU(IN PUCHAR PortBase);
+NTSTATUS WriteMPU(IN PUCHAR PortBase,IN BOOLEAN IsCommand,IN UCHAR Value);
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+
+// make sure we're in UART mode
+NTSTATUS ResetHardware(PUCHAR portBase)
+{
+ PAGED_CODE();
+
+ return WriteMPU(portBase,COMMAND,MPU401_CMD_UART);
+}
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+
+//
+// We initialize the UART with interrupts suppressed so we don't
+// try to service the chip prematurely.
+//
+NTSTATUS CMiniportDMusUART::InitializeHardware(PINTERRUPTSYNC interruptSync,PUCHAR
portBase)
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus;
+ if (m_UseIRQ)
+ {
+ ntStatus = interruptSync->CallSynchronizedRoutine(InitMPU,PVOID(portBase));
+ }
+ else
+ {
+ ntStatus = InitMPU(NULL,PVOID(portBase));
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ //
+ // Start the UART (this should trigger an interrupt).
+ //
+ ntStatus = ResetHardware(portBase);
+ }
+ else
+ {
+ DPRINT("*** InitMPU returned with ntStatus 0x%08x ***", ntStatus);
+ }
+
+ m_fMPUInitialized = NT_SUCCESS(ntStatus);
+
+ return ntStatus;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+/*****************************************************************************
+ * InitMPU()
+ *****************************************************************************
+ * Synchronized routine to initialize the MPU401.
+ */
NTSTATUS
-NTAPI
-CMiniportDMus::QueryInterface(
- IN REFIID refiid,
- OUT PVOID* Output)
-{
- if (IsEqualGUIDAligned(refiid, IID_IMiniportDMus))
- {
- *Output = PVOID(PUNKNOWN(this));
- PUNKNOWN(*Output)->AddRef();
- return STATUS_SUCCESS;
- }
- return STATUS_UNSUCCESSFUL;
-}
-
-// IMiniport methods
-
+InitMPU
+(
+ IN PINTERRUPTSYNC InterruptSync,
+ IN PVOID DynamicContext
+)
+{
+ DPRINT("InitMPU");
+ if (!DynamicContext)
+ {
+ return STATUS_INVALID_PARAMETER_2;
+ }
+
+ PUCHAR portBase = PUCHAR(DynamicContext);
+ UCHAR status;
+ ULONGLONG startTime;
+ BOOLEAN success;
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ //
+ // Reset the card (puts it into "smart mode")
+ //
+ ntStatus = WriteMPU(portBase,COMMAND,MPU401_CMD_RESET);
+
+ // wait for the acknowledgement
+ // NOTE: When the Ack arrives, it will trigger an interrupt.
+ // Normally the DPC routine would read in the ack byte and we
+ // would never see it, however since we have the hardware locked (HwEnter),
+ // we can read the port before the DPC can and thus we receive the Ack.
+ startTime = PcGetTimeInterval(0);
+ success = FALSE;
+ while(PcGetTimeInterval(startTime) < GTI_MILLISECONDS(50))
+ {
+ status = READ_PORT_UCHAR(portBase + MPU401_REG_STATUS);
+
+ if (UartFifoOkForRead(status)) // Is data waiting?
+ {
+ READ_PORT_UCHAR(portBase + MPU401_REG_DATA); // yep.. read ACK
+ success = TRUE; // don't need to do more
+ break;
+ }
+ KeStallExecutionProcessor(25); // microseconds
+ }
+#if (DBG)
+ if (!success)
+ {
+ DPRINT("First attempt to reset the MPU didn't get ACKed.\n");
+ }
+#endif // (DBG)
+
+ // NOTE: We cannot check the ACK byte because if the card was already in
+ // UART mode it will not send an ACK but it will reset.
+
+ // reset the card again
+ (void) WriteMPU(portBase,COMMAND,MPU401_CMD_RESET);
+
+ // wait for ack (again)
+ startTime = PcGetTimeInterval(0); // This might take a while
+ BYTE dataByte = 0;
+ success = FALSE;
+ while (PcGetTimeInterval(startTime) < GTI_MILLISECONDS(50))
+ {
+ status = READ_PORT_UCHAR(portBase + MPU401_REG_STATUS);
+ if (UartFifoOkForRead(status)) // Is data waiting?
+ {
+ dataByte = READ_PORT_UCHAR(portBase + MPU401_REG_DATA); // yep.. read ACK
+ success = TRUE; // don't need to
do more
+ break;
+ }
+ KeStallExecutionProcessor(25);
+ }
+
+ if ((0xFE != dataByte) || !success) // Did we succeed? If no second ACK, something
is hosed
+ {
+ DPRINT("Second attempt to reset the MPU didn't get ACKed.\n");
+ DPRINT("Init Reset failure error. Ack = %X", ULONG(dataByte));
+
+ ntStatus = STATUS_IO_DEVICE_ERROR;
+ }
+
+ return ntStatus;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+/*****************************************************************************
+ * CMiniportDMusUARTStream::Write()
+ *****************************************************************************
+ * Writes outgoing MIDI data.
+ */
+STDMETHODIMP_(NTSTATUS)
+CMiniportDMusUARTStream::
+Write
+(
+ IN PVOID BufferAddress,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+)
+{
+ DPRINT("Write\n");
+ ASSERT(BytesWritten);
+ if (!BufferAddress)
+ {
+ Length = 0;
+ }
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (!m_fCapture)
+ {
+ PUCHAR pMidiData;
+ ULONG count;
+
+ count = 0;
+ pMidiData = PUCHAR(BufferAddress);
+
+ if (Length)
+ {
+ SYNCWRITECONTEXT context;
+ context.Miniport = (m_pMiniport);
+ context.PortBase = m_pPortBase;
+ context.BufferAddress = pMidiData;
+ context.Length = Length;
+ context.BytesRead = &count;
+
+ if (m_pMiniport->m_UseIRQ)
+ {
+ ntStatus = m_pMiniport->m_pInterruptSync->
+
CallSynchronizedRoutine(SynchronizedDMusMPUWrite,PVOID(&context));
+ }
+ else // !m_UseIRQ
+ {
+ ntStatus = SynchronizedDMusMPUWrite(NULL,PVOID(&context));
+ } // !m_UseIRQ
+
+ if (count == 0)
+ {
+ m_NumFailedMPUTries++;
+ if (m_NumFailedMPUTries >= 100)
+ {
+ ntStatus = STATUS_IO_DEVICE_ERROR;
+ m_NumFailedMPUTries = 0;
+ }
+ }
+ else
+ {
+ m_NumFailedMPUTries = 0;
+ }
+ } // if we have data at all
+ *BytesWritten = count;
+ }
+ else // called write on the read stream
+ {
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ return ntStatus;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+/*****************************************************************************
+ * SynchronizedDMusMPUWrite()
+ *****************************************************************************
+ * Writes outgoing MIDI data.
+ */
NTSTATUS
-NTAPI
-CMiniportDMus::DataRangeIntersection(
- IN ULONG PinId,
- IN PKSDATARANGE DataRange,
- IN PKSDATARANGE MatchingDataRange,
- IN ULONG OutputBufferLength,
- OUT PVOID ResultantFormat OPTIONAL,
- OUT PULONG ResultantFormatLength)
-{
- return STATUS_UNSUCCESSFUL;
-}
-
+SynchronizedDMusMPUWrite
+(
+ IN PINTERRUPTSYNC InterruptSync,
+ IN PVOID syncWriteContext
+)
+{
+ PSYNCWRITECONTEXT context;
+ context = (PSYNCWRITECONTEXT)syncWriteContext;
+ ASSERT(context->Miniport);
+ ASSERT(context->PortBase);
+ ASSERT(context->BufferAddress);
+ ASSERT(context->Length);
+ ASSERT(context->BytesRead);
+
+ PUCHAR pChar = PUCHAR(context->BufferAddress);
+ NTSTATUS ntStatus,readStatus;
+ ntStatus = STATUS_SUCCESS;
+ //
+ // while we're not there yet, and
+ // while we don't have to wait on an aligned byte (including 0)
+ // (we never wait on a byte. Better to come back later)
+ readStatus =
DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport));
+ while ( (*(context->BytesRead) < context->Length)
+ && ( TryMPU(context->PortBase)
+ || (*(context->BytesRead)%3)
+ ) )
+ {
+ ntStatus = WriteMPU(context->PortBase,DATA,*pChar);
+ if (NT_SUCCESS(ntStatus))
+ {
+ pChar++;
+ *(context->BytesRead) = *(context->BytesRead) + 1;
+// readStatus =
DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport));
+ }
+ else
+ {
+ DPRINT("SynchronizedDMusMPUWrite failed (0x%08x)",ntStatus);
+ break;
+ }
+ }
+ readStatus =
DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport));
+ return ntStatus;
+}
+
+#define kMPUPollTimeout 2
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+/*****************************************************************************
+ * TryMPU()
+ *****************************************************************************
+ * See if the MPU401 is free.
+ */
+BOOLEAN
+TryMPU
+(
+ IN PUCHAR PortBase
+)
+{
+ BOOLEAN success;
+ USHORT numPolls;
+ UCHAR status;
+
+ DPRINT("TryMPU");
+ numPolls = 0;
+
+ while (numPolls < kMPUPollTimeout)
+ {
+ status = READ_PORT_UCHAR(PortBase + MPU401_REG_STATUS);
+
+ if (UartFifoOkForWrite(status)) // Is this a good time to write data?
+ {
+ break;
+ }
+ numPolls++;
+ }
+ if (numPolls >= kMPUPollTimeout)
+ {
+ success = FALSE;
+ DPRINT("TryMPU failed");
+ }
+ else
+ {
+ success = TRUE;
+ }
+
+ return success;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+/*****************************************************************************
+ * WriteMPU()
+ *****************************************************************************
+ * Write a byte out to the MPU401.
+ */
NTSTATUS
-NTAPI
-CMiniportDMus::GetDescription(
- OUT PPCFILTER_DESCRIPTOR *Description)
-{
- return STATUS_UNSUCCESSFUL;
-}
-
-HRESULT
-NTAPI
-CMiniportDMus::Init(
- IN PUNKNOWN pUnknownAdapter,
- IN PRESOURCELIST pResourceList,
- IN PPORTDMUS pPort,
- OUT PSERVICEGROUP *ppServiceGroup
- )
-{
- return STATUS_UNSUCCESSFUL;
-}
-
-HRESULT
-NTAPI
-CMiniportDMus::NewStream(
- OUT PMXF *ppMXF,
- IN PUNKNOWN pOuterUnknown OPTIONAL,
- IN POOL_TYPE PoolType,
- IN ULONG uPinId,
- IN DMUS_STREAM_TYPE StreamType,
- IN PKSDATAFORMAT pDataFormat,
- OUT PSERVICEGROUP *ppServiceGroup,
- IN PAllocatorMXF pAllocatorMXF,
- IN PMASTERCLOCK pMasterClock,
- OUT PULONGLONG puuSchedulePreFetch
- )
-{
- return STATUS_UNSUCCESSFUL;
-}
-
-VOID
-NTAPI
-CMiniportDMus::Service()
-{
-
-}
+WriteMPU
+(
+ IN PUCHAR PortBase,
+ IN BOOLEAN IsCommand,
+ IN UCHAR Value
+)
+{
+ DPRINT("WriteMPU");
+ NTSTATUS ntStatus = STATUS_IO_DEVICE_ERROR;
+
+ if (!PortBase)
+ {
+ DPRINT("O: PortBase is zero\n");
+ return ntStatus;
+ }
+ PUCHAR deviceAddr = PortBase + MPU401_REG_DATA;
+
+ if (IsCommand)
+ {
+ deviceAddr = PortBase + MPU401_REG_COMMAND;
+ }
+
+ ULONGLONG startTime = PcGetTimeInterval(0);
+
+ while (PcGetTimeInterval(startTime) < GTI_MILLISECONDS(50))
+ {
+ UCHAR status
+ = READ_PORT_UCHAR(PortBase + MPU401_REG_STATUS);
+
+ if (UartFifoOkForWrite(status)) // Is this a good time to write data?
+ { // yep (Jon comment)
+ WRITE_PORT_UCHAR(deviceAddr,Value);
+ DPRINT("WriteMPU emitted 0x%02x",Value);
+ ntStatus = STATUS_SUCCESS;
+ break;
+ }
+ }
+ return ntStatus;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+/*****************************************************************************
+ * SnapTimeStamp()
+ *****************************************************************************
+ *
+ * At synchronized execution to ISR, copy miniport's volatile m_InputTimeStamp
+ * to stream's m_SnapshotTimeStamp and zero m_InputTimeStamp.
+ *
+ */
+STDMETHODIMP_(NTSTATUS)
+SnapTimeStamp(PINTERRUPTSYNC InterruptSync,PVOID pStream)
+{
+ CMiniportDMusUARTStream *pMPStream = (CMiniportDMusUARTStream *)pStream;
+
+ // cache the timestamp
+ pMPStream->m_SnapshotTimeStamp = pMPStream->m_pMiniport->m_InputTimeStamp;
+
+ // if the window is closed, zero the timestamp
+ if (pMPStream->m_pMiniport->m_MPUInputBufferHead ==
+ pMPStream->m_pMiniport->m_MPUInputBufferTail)
+ {
+ pMPStream->m_pMiniport->m_InputTimeStamp = 0;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/*****************************************************************************
+ * CMiniportDMusUARTStream::SourceEvtsToPort()
+ *****************************************************************************
+ *
+ * Reads incoming MIDI data, feeds into DMus events.
+ * No need to touch the hardware, just read from our SW FIFO.
+ *
+ */
+STDMETHODIMP_(NTSTATUS)
+CMiniportDMusUARTStream::SourceEvtsToPort()
+{
+ NTSTATUS ntStatus;
+
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+ DPRINT("SourceEvtsToPort");
+
+ if (m_fCapture)
+ {
+ ntStatus = STATUS_SUCCESS;
+ if (m_pMiniport->m_MPUInputBufferHead !=
m_pMiniport->m_MPUInputBufferTail)
+ {
+ PDMUS_KERNEL_EVENT aDMKEvt,eventTail,eventHead = NULL;
+
+ while (m_pMiniport->m_MPUInputBufferHead !=
m_pMiniport->m_MPUInputBufferTail)
+ {
+ (void) m_AllocatorMXF->GetMessage(&aDMKEvt);
+ if (!aDMKEvt)
+ {
+ DPRINT("SourceEvtsToPort can't allocate DMKEvt");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // put this event at the end of the list
+ if (!eventHead)
+ {
+ eventHead = aDMKEvt;
+ }
+ else
+ {
+ eventTail = eventHead;
+ while (eventTail->pNextEvt)
+ {
+ eventTail = eventTail->pNextEvt;
+ }
+ eventTail->pNextEvt = aDMKEvt;
+ }
+ // read all the bytes out of the buffer, into event(s)
+ for (aDMKEvt->cbEvent = 0; aDMKEvt->cbEvent < sizeof(PBYTE);
aDMKEvt->cbEvent++)
+ {
+ if (m_pMiniport->m_MPUInputBufferHead ==
m_pMiniport->m_MPUInputBufferTail)
+ {
+// _DbgPrintF(DEBUGLVL_TERSE, ("SourceEvtsToPort
m_MPUInputBufferHead met m_MPUInputBufferTail, overrun"));
+ break;
+ }
+ aDMKEvt->uData.abData[aDMKEvt->cbEvent] =
m_pMiniport->m_MPUInputBuffer[m_pMiniport->m_MPUInputBufferHead];
+ m_pMiniport->m_MPUInputBufferHead++;
+ if (m_pMiniport->m_MPUInputBufferHead >= kMPUInputBufferSize)
+ {
+ m_pMiniport->m_MPUInputBufferHead = 0;
+ }
+ }
+ }
+
+ if (m_pMiniport->m_UseIRQ)
+ {
+ ntStatus =
m_pMiniport->m_pInterruptSync->CallSynchronizedRoutine(SnapTimeStamp,PVOID(this));
+ }
+ else // !m_UseIRQ
+ {
+ ntStatus = SnapTimeStamp(NULL,PVOID(this));
+ } // !m_UseIRQ
+ aDMKEvt = eventHead;
+ while (aDMKEvt)
+ {
+ aDMKEvt->ullPresTime100ns = m_SnapshotTimeStamp;
+ aDMKEvt->usChannelGroup = 1;
+ aDMKEvt->usFlags = DMUS_KEF_EVENT_INCOMPLETE;
+ aDMKEvt = aDMKEvt->pNextEvt;
+ }
+ (void)m_sinkMXF->PutMessage(eventHead);
+ }
+ }
+ else // render stream
+ {
+ DPRINT("SourceEvtsToPort called on render stream");
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ return ntStatus;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+/*****************************************************************************
+ * DMusMPUInterruptServiceRoutine()
+ *****************************************************************************
+ * ISR.
+ */
+NTSTATUS
+DMusMPUInterruptServiceRoutine
+(
+ IN PINTERRUPTSYNC InterruptSync,
+ IN PVOID DynamicContext
+)
+{
+ DPRINT("DMusMPUInterruptServiceRoutine");
+ ULONGLONG startTime;
+
+ ASSERT(DynamicContext);
+
+ NTSTATUS ntStatus;
+ BOOL newBytesAvailable;
+ CMiniportDMusUART *that;
+ NTSTATUS clockStatus;
+
+ that = (CMiniportDMusUART *) DynamicContext;
+ newBytesAvailable = FALSE;
+ ntStatus = STATUS_UNSUCCESSFUL;
+
+ UCHAR portStatus = 0xff;
+
+ //
+ // Read the MPU status byte.
+ //
+ if (that->m_pPortBase)
+ {
+ portStatus =
+ READ_PORT_UCHAR(that->m_pPortBase + MPU401_REG_STATUS);
+
+ //
+ // If there is outstanding work to do and there is a port-driver for
+ // the MPU miniport...
+ //
+ if (UartFifoOkForRead(portStatus) && that->m_pPort)
+ {
+ startTime = PcGetTimeInterval(0);
+ while ( (PcGetTimeInterval(startTime) < GTI_MILLISECONDS(50))
+ && (UartFifoOkForRead(portStatus)) )
+ {
+ UCHAR uDest = READ_PORT_UCHAR(that->m_pPortBase + MPU401_REG_DATA);
+ if ( (that->m_KSStateInput == KSSTATE_RUN)
+ && (that->m_NumCaptureStreams)
+ )
+ {
+ ULONG buffHead = that->m_MPUInputBufferHead;
+ if ( (that->m_MPUInputBufferTail + 1 == buffHead)
+ || (that->m_MPUInputBufferTail + 1 - kMPUInputBufferSize ==
buffHead))
+ {
+ DPRINT("*****MPU Input Buffer Overflow*****");
+ }
+ else
+ {
+ if (!that->m_InputTimeStamp)
+ {
+ clockStatus =
that->m_MasterClock->GetTime(&that->m_InputTimeStamp);
+ if (STATUS_SUCCESS != clockStatus)
+ {
+ DPRINT("GetTime failed for clock
0x%08x",that->m_MasterClock);
+ }
+ }
+ newBytesAvailable = TRUE;
+ // ...place the data in our FIFO...
+ that->m_MPUInputBuffer[that->m_MPUInputBufferTail] =
uDest;
+ ASSERT(that->m_MPUInputBufferTail < kMPUInputBufferSize);
+
+ that->m_MPUInputBufferTail++;
+ if (that->m_MPUInputBufferTail >= kMPUInputBufferSize)
+ {
+ that->m_MPUInputBufferTail = 0;
+ }
+ }
+ }
+ //
+ // Look for more MIDI data.
+ //
+ portStatus =
+ READ_PORT_UCHAR(that->m_pPortBase + MPU401_REG_STATUS);
+ } // either there's no data or we ran too long
+ if (newBytesAvailable)
+ {
+ //
+ // ...notify the MPU port driver that we have bytes.
+ //
+ that->m_pPort->Notify(that->m_pServiceGroup);
+ }
+ ntStatus = STATUS_SUCCESS;
+ }
+ }
+
+ return ntStatus;
+}
+
+/*****************************************************************************
+ * CMiniportDMusUART::GetDescription()
+ *****************************************************************************
+ * Gets the topology.
+ */
+STDMETHODIMP_(NTSTATUS)
+CMiniportDMusUART::
+GetDescription
+(
+ OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
+)
+{
+ PAGED_CODE();
+
+ ASSERT(OutFilterDescriptor);
+
+ DPRINT("GetDescription");
+
+ *OutFilterDescriptor = &MiniportFilterDescriptor;
+
+ return STATUS_SUCCESS;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
NTSTATUS
NewMiniportDMusUART(
OUT PMINIPORT* OutMiniport,
IN REFCLSID ClassId)
{
- CMiniportDMus * This;
-
- This = new(NonPagedPool, TAG_PORTCLASS)CMiniportDMus(NULL);
+ CMiniportDMusUART * This;
+ NTSTATUS Status;
+
+ This= new(NonPagedPool, TAG_PORTCLASS) CMiniportDMusUART(NULL);
if (!This)
return STATUS_INSUFFICIENT_RESOURCES;
- *OutMiniport = (PMINIPORT)This;
- This->AddRef();
+ Status = This->QueryInterface(IID_IMiniport, (PVOID*)OutMiniport);
+
+ if (!NT_SUCCESS(Status))
+ {
+ delete This;
+ }
+
+ DPRINT("NewMiniportDMusUART %p Status %x\n", *OutMiniport, Status);
+ return Status;
+}
+
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+
+/*****************************************************************************
+ * CMiniportDMusUART::ProcessResources()
+ *****************************************************************************
+ * Processes the resource list, setting up helper objects accordingly.
+ */
+NTSTATUS
+CMiniportDMusUART::
+ProcessResources
+(
+ IN PRESOURCELIST ResourceList
+)
+{
+ PAGED_CODE();
+
+ DPRINT("ProcessResources");
+
+ ASSERT(ResourceList);
+ if (!ResourceList)
+ {
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+ //
+ // Get counts for the types of resources.
+ //
+ ULONG countIO = ResourceList->NumberOfPorts();
+ ULONG countIRQ = ResourceList->NumberOfInterrupts();
+ ULONG countDMA = ResourceList->NumberOfDmas();
+ ULONG lengthIO = ResourceList->FindTranslatedPort(0)->u.Port.Length;
+
+#ifdef DBG
+ DPRINT("Starting MPU401 Port 0x%lx",
ResourceList->FindTranslatedPort(0)->u.Port.Start.LowPart);
+#endif
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ //
+ // Make sure we have the expected number of resources.
+ //
+ if ( (countIO != 1)
+ || (countIRQ > 1)
+ || (countDMA != 0)
+ || (lengthIO == 0)
+ )
+ {
+ DPRINT("Unknown ResourceList configuraton");
+ ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ //
+ // Get the port address.
+ //
+ m_pPortBase =
+ PUCHAR(ResourceList->FindTranslatedPort(0)->u.Port.Start.QuadPart);
+
+ ntStatus = InitializeHardware(m_pInterruptSync,m_pPortBase);
+ }
+
+ return ntStatus;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+/*****************************************************************************
+ * CMiniportDMusUART::NonDelegatingQueryInterface()
+ *****************************************************************************
+ * Obtains an interface. This function works just like a COM QueryInterface
+ * call and is used if the object is not being aggregated.
+ */
+STDMETHODIMP_(NTSTATUS)
+CMiniportDMusUART::QueryInterface
+(
+ REFIID Interface,
+ PVOID * Object
+)
+{
+ PAGED_CODE();
+
+ DPRINT("Miniport::NonDelegatingQueryInterface");
+ ASSERT(Object);
+
+ if (IsEqualGUIDAligned(Interface,IID_IUnknown))
+ {
+ *Object = PVOID(PUNKNOWN(PMINIPORTDMUS(this)));
+ }
+ else
+ if (IsEqualGUIDAligned(Interface,IID_IMiniport))
+ {
+ *Object = PVOID(PMINIPORT(this));
+ }
+ else
+ if (IsEqualGUIDAligned(Interface,IID_IMiniportDMus))
+ {
+ *Object = PVOID(PMINIPORTDMUS(this));
+ }
+ else
+ if (IsEqualGUIDAligned(Interface,IID_IMusicTechnology))
+ {
+ *Object = PVOID(PMUSICTECHNOLOGY(this));
+ }
+ else
+ if (IsEqualGUIDAligned(Interface,IID_IPowerNotify))
+ {
+ *Object = PVOID(PPOWERNOTIFY(this));
+ }
+ else
+ {
+ *Object = NULL;
+ }
+
+ if (*Object)
+ {
+ //
+ // We reference the interface for the caller.
+ //
+ PUNKNOWN(*Object)->AddRef();
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_INVALID_PARAMETER;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+/*****************************************************************************
+ * CMiniportDMusUART::~CMiniportDMusUART()
+ *****************************************************************************
+ * Destructor.
+ */
+CMiniportDMusUART::~CMiniportDMusUART(void)
+{
+ PAGED_CODE();
+
+ DPRINT("~CMiniportDMusUART");
+
+ ASSERT(0 == m_NumCaptureStreams);
+ ASSERT(0 == m_NumRenderStreams);
+
+ // reset the HW so we don't get anymore interrupts
+ if (m_UseIRQ && m_pInterruptSync)
+ {
+ (void)
m_pInterruptSync->CallSynchronizedRoutine((PINTERRUPTSYNCROUTINE)InitMPU,PVOID(m_pPortBase));
+ }
+ else
+ {
+ (void) InitMPU(NULL,PVOID(m_pPortBase));
+ }
+
+ if (m_pInterruptSync)
+ {
+ m_pInterruptSync->Release();
+ m_pInterruptSync = NULL;
+ }
+ if (m_pServiceGroup)
+ {
+ m_pServiceGroup->Release();
+ m_pServiceGroup = NULL;
+ }
+ if (m_pPort)
+ {
+ m_pPort->Release();
+ m_pPort = NULL;
+ }
+}
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+/*****************************************************************************
+ * CMiniportDMusUART::Init()
+ *****************************************************************************
+ * Initializes a the miniport.
+ */
+STDMETHODIMP_(NTSTATUS)
+CMiniportDMusUART::
+Init
+(
+ IN PUNKNOWN UnknownInterruptSync OPTIONAL,
+ IN PRESOURCELIST ResourceList,
+ IN PPORTDMUS Port_,
+ OUT PSERVICEGROUP * ServiceGroup
+)
+{
+ PAGED_CODE();
+
+ ASSERT(ResourceList);
+ if (!ResourceList)
+ {
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ ASSERT(Port_);
+ ASSERT(ServiceGroup);
+
+ DPRINT("Init");
+
+ *ServiceGroup = NULL;
+ m_pPortBase = 0;
+ m_fMPUInitialized = FALSE;
+
+ // This will remain unspecified if the miniport does not get any power
+ // messages.
+ //
+ m_PowerState.DeviceState = PowerDeviceUnspecified;
+
+ //
+ // AddRef() is required because we are keeping this pointer.
+ //
+ m_pPort = Port_;
+ m_pPort->AddRef();
+
+ // Set dataformat.
+ //
+ if (IsEqualGUIDAligned(m_MusicFormatTechnology, GUID_NULL))
+ {
+ RtlCopyMemory( &m_MusicFormatTechnology,
+ &KSMUSIC_TECHNOLOGY_PORT,
+ sizeof(GUID));
+ }
+ RtlCopyMemory( &PinDataRangesStreamLegacy.Technology,
+ &m_MusicFormatTechnology,
+ sizeof(GUID));
+ RtlCopyMemory( &PinDataRangesStreamDMusic.Technology,
+ &m_MusicFormatTechnology,
+ sizeof(GUID));
+
+ for (ULONG bufferCount = 0;bufferCount < kMPUInputBufferSize;bufferCount++)
+ {
+ m_MPUInputBuffer[bufferCount] = 0;
+ }
+ m_MPUInputBufferHead = 0;
+ m_MPUInputBufferTail = 0;
+ m_InputTimeStamp = 0;
+ m_KSStateInput = KSSTATE_STOP;
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ m_NumRenderStreams = 0;
+ m_NumCaptureStreams = 0;
+
+ m_UseIRQ = TRUE;
+ if (ResourceList->NumberOfInterrupts() == 0)
+ {
+ m_UseIRQ = FALSE;
+ }
+
+ ntStatus = PcNewServiceGroup(&m_pServiceGroup,NULL);
+ if (NT_SUCCESS(ntStatus) && !m_pServiceGroup) // keep any error
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ *ServiceGroup = m_pServiceGroup;
+ m_pServiceGroup->AddRef();
+
+ //
+ // Register the service group with the port early so the port is
+ // prepared to handle interrupts.
+ //
+ m_pPort->RegisterServiceGroup(m_pServiceGroup);
+ }
+
+ if (NT_SUCCESS(ntStatus) && m_UseIRQ)
+ {
+ //
+ // Due to a bug in the InterruptSync design, we shouldn't share
+ // the interrupt sync object. Whoever goes away first
+ // will disconnect it, and the other points off into nowhere.
+ //
+ // Instead we generate our own interrupt sync object.
+ //
+ UnknownInterruptSync = NULL;
+
+ if (UnknownInterruptSync)
+ {
+ ntStatus =
+ UnknownInterruptSync->QueryInterface
+ (
+ IID_IInterruptSync,
+ (PVOID *) &m_pInterruptSync
+ );
+
+ if (!m_pInterruptSync && NT_SUCCESS(ntStatus)) // keep any error
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ if (NT_SUCCESS(ntStatus))
+ {
// run this ISR first
+ ntStatus = m_pInterruptSync->
+
RegisterServiceRoutine(DMusMPUInterruptServiceRoutine,PVOID(this),TRUE);
+ }
+
+ }
+ else
+ { // create our own interruptsync mechanism.
+ ntStatus =
+ PcNewInterruptSync
+ (
+ &m_pInterruptSync,
+ NULL,
+ ResourceList,
+ 0, // Resource Index
+ InterruptSyncModeNormal // Run ISRs once until we get SUCCESS
+ );
+
+ if (!m_pInterruptSync && NT_SUCCESS(ntStatus)) // keep any error
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = m_pInterruptSync->RegisterServiceRoutine(
+ DMusMPUInterruptServiceRoutine,
+ PVOID(this),
+ TRUE); // run this ISR first
+ }
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = m_pInterruptSync->Connect();
+ }
+ }
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = ProcessResources(ResourceList);
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ //
+ // clean up our mess
+ //
+
+ // clean up the interrupt sync
+ if( m_pInterruptSync )
+ {
+ m_pInterruptSync->Release();
+ m_pInterruptSync = NULL;
+ }
+
+ // clean up the service group
+ if( m_pServiceGroup )
+ {
+ m_pServiceGroup->Release();
+ m_pServiceGroup = NULL;
+ }
+
+ // clean up the out param service group.
+ if (*ServiceGroup)
+ {
+ (*ServiceGroup)->Release();
+ (*ServiceGroup) = NULL;
+ }
+
+ // release the port
+ m_pPort->Release();
+ m_pPort = NULL;
+ }
+
+ return ntStatus;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+/*****************************************************************************
+ * CMiniportDMusUART::NewStream()
+ *****************************************************************************
+ * Gets the topology.
+ */
+STDMETHODIMP_(NTSTATUS)
+CMiniportDMusUART::
+NewStream
+(
+ OUT PMXF * MXF,
+ IN PUNKNOWN OuterUnknown OPTIONAL,
+ IN POOL_TYPE PoolType,
+ IN ULONG PinID,
+ IN DMUS_STREAM_TYPE StreamType,
+ IN PKSDATAFORMAT DataFormat,
+ OUT PSERVICEGROUP * ServiceGroup,
+ IN PAllocatorMXF AllocatorMXF,
+ IN PMASTERCLOCK MasterClock,
+ OUT PULONGLONG SchedulePreFetch
+)
+{
+ PAGED_CODE();
+
+ DPRINT("NewStream");
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ // In 100 ns, we want stuff as soon as it comes in
+ //
+ *SchedulePreFetch = 0;
+
+ // if we don't have any streams already open, get the hardware ready.
+ if ((!m_NumCaptureStreams) && (!m_NumRenderStreams))
+ {
+ ntStatus = ResetHardware(m_pPortBase);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPRINT("CMiniportDMusUART::NewStream ResetHardware failed");
+ return ntStatus;
+ }
+ }
+
+ if ( ((m_NumCaptureStreams < kMaxNumCaptureStreams)
+ && (StreamType == DMUS_STREAM_MIDI_CAPTURE))
+ || ((m_NumRenderStreams < kMaxNumLegacyRenderStreams +
kMaxNumDMusicRenderStreams)
+ && (StreamType == DMUS_STREAM_MIDI_RENDER))
+ )
+ {
+ CMiniportDMusUARTStream *pStream =
+ new(PoolType) CMiniportDMusUARTStream();
+
+ if (pStream)
+ {
+ pStream->AddRef();
+
+ ntStatus =
+ pStream->Init(this,m_pPortBase,(StreamType ==
DMUS_STREAM_MIDI_CAPTURE),AllocatorMXF,MasterClock);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ *MXF = PMXF(pStream);
+ (*MXF)->AddRef();
+
+ if (StreamType == DMUS_STREAM_MIDI_CAPTURE)
+ {
+ m_NumCaptureStreams++;
+ *ServiceGroup = m_pServiceGroup;
+ (*ServiceGroup)->AddRef();
+ }
+ else
+ {
+ m_NumRenderStreams++;
+ *ServiceGroup = NULL;
+ }
+ }
+
+ pStream->Release();
+ }
+ else
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ if (StreamType == DMUS_STREAM_MIDI_CAPTURE)
+ {
+ DPRINT("NewStream failed, too many capture streams");
+ }
+ else if (StreamType == DMUS_STREAM_MIDI_RENDER)
+ {
+ DPRINT("NewStream failed, too many render streams");
+ }
+ else
+ {
+ DPRINT("NewStream invalid stream type");
+ }
+ }
+
+ return ntStatus;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+/*****************************************************************************
+ * CMiniportDMusUART::SetTechnology()
+ *****************************************************************************
+ * Sets pindatarange technology.
+ */
+STDMETHODIMP_(NTSTATUS)
+CMiniportDMusUART::
+SetTechnology
+(
+ IN const GUID * Technology
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
+
+ // Fail if miniport has already been initialized.
+ //
+ if (NULL == m_pPort)
+ {
+ RtlCopyMemory(&m_MusicFormatTechnology, Technology, sizeof(GUID));
+ ntStatus = STATUS_SUCCESS;
+ }
+
+ return ntStatus;
+} // SetTechnology
+
+/*****************************************************************************
+ * CMiniportDMusUART::PowerChangeNotify()
+ *****************************************************************************
+ * Handle power state change for the miniport.
+ */
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+
+STDMETHODIMP_(void)
+CMiniportDMusUART::
+PowerChangeNotify
+(
+ IN POWER_STATE PowerState
+)
+{
+ PAGED_CODE();
+
+ DPRINT("CMiniportDMusUART::PoweChangeNotify D%d", PowerState.DeviceState);
+
+ switch (PowerState.DeviceState)
+ {
+ case PowerDeviceD0:
+ if (m_PowerState.DeviceState != PowerDeviceD0)
+ {
+ if (!NT_SUCCESS(InitializeHardware(m_pInterruptSync,m_pPortBase)))
+ {
+ DPRINT("InitializeHardware failed when resuming");
+ }
+ }
+ break;
+
+ case PowerDeviceD1:
+ case PowerDeviceD2:
+ case PowerDeviceD3:
+ default:
+ break;
+ }
+ m_PowerState.DeviceState = PowerState.DeviceState;
+} // PowerChangeNotify
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+/*****************************************************************************
+ * CMiniportDMusUARTStream::NonDelegatingQueryInterface()
+ *****************************************************************************
+ * Obtains an interface. This function works just like a COM QueryInterface
+ * call and is used if the object is not being aggregated.
+ */
+STDMETHODIMP_(NTSTATUS)
+CMiniportDMusUARTStream::QueryInterface
+(
+ REFIID Interface,
+ PVOID * Object
+)
+{
+ PAGED_CODE();
+
+ DPRINT("Stream::NonDelegatingQueryInterface");
+ ASSERT(Object);
+
+ if (IsEqualGUIDAligned(Interface,IID_IUnknown))
+ {
+ *Object = PVOID(PUNKNOWN(this));
+ }
+ else
+ if (IsEqualGUIDAligned(Interface,IID_IMXF))
+ {
+ *Object = PVOID(PMXF(this));
+ }
+ else
+ {
+ *Object = NULL;
+ }
+
+ if (*Object)
+ {
+ //
+ // We reference the interface for the caller.
+ //
+ PUNKNOWN(*Object)->AddRef();
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_INVALID_PARAMETER;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+/*****************************************************************************
+ * CMiniportDMusUARTStream::~CMiniportDMusUARTStream()
+ *****************************************************************************
+ * Destructs a stream.
+ */
+CMiniportDMusUARTStream::~CMiniportDMusUARTStream(void)
+{
+ PAGED_CODE();
+
+ DPRINT("~CMiniportDMusUARTStream");
+
+ KeCancelTimer(&m_TimerEvent);
+
+ if (m_DMKEvtQueue)
+ {
+ if (m_AllocatorMXF)
+ {
+ m_AllocatorMXF->PutMessage(m_DMKEvtQueue);
+ }
+ else
+ {
+ DPRINT("~CMiniportDMusUARTStream, no allocator, can't flush
DMKEvts");
+ }
+ m_DMKEvtQueue = NULL;
+ }
+ if (m_AllocatorMXF)
+ {
+ m_AllocatorMXF->Release();
+ m_AllocatorMXF = NULL;
+ }
+
+ if (m_pMiniport)
+ {
+ if (m_fCapture)
+ {
+ m_pMiniport->m_NumCaptureStreams--;
+ }
+ else
+ {
+ m_pMiniport->m_NumRenderStreams--;
+ }
+
+ m_pMiniport->Release();
+ }
+}
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+/*****************************************************************************
+ * CMiniportDMusUARTStream::Init()
+ *****************************************************************************
+ * Initializes a stream.
+ */
+STDMETHODIMP_(NTSTATUS)
+CMiniportDMusUARTStream::
+Init
+(
+ IN CMiniportDMusUART * pMiniport,
+ IN PUCHAR pPortBase,
+ IN BOOLEAN fCapture,
+ IN PAllocatorMXF allocatorMXF,
+ IN PMASTERCLOCK masterClock
+)
+{
+ PAGED_CODE();
+
+ ASSERT(pMiniport);
+ ASSERT(pPortBase);
+
+ DPRINT("Init");
+
+ m_NumFailedMPUTries = 0;
+ m_TimerQueued = FALSE;
+ KeInitializeSpinLock(&m_DpcSpinLock);
+ m_pMiniport = pMiniport;
+ m_pMiniport->AddRef();
+
+ pMiniport->m_MasterClock = masterClock;
+
+ m_pPortBase = pPortBase;
+ m_fCapture = fCapture;
+
+ m_SnapshotTimeStamp = 0;
+ m_DMKEvtQueue = NULL;
+ m_DMKEvtOffset = 0;
+
+ m_NumberOfRetries = 0;
+
+ if (allocatorMXF)
+ {
+ allocatorMXF->AddRef();
+ m_AllocatorMXF = allocatorMXF;
+ m_sinkMXF = m_AllocatorMXF;
+ }
+ else
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ KeInitializeDpc
+ (
+ &m_Dpc,
+ &::DMusUARTTimerDPC,
+ PVOID(this)
+ );
+ KeInitializeTimer(&m_TimerEvent);
return STATUS_SUCCESS;
}
-
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+/*****************************************************************************
+ * CMiniportDMusUARTStream::SetState()
+ *****************************************************************************
+ * Sets the state of the channel.
+ */
+STDMETHODIMP_(NTSTATUS)
+CMiniportDMusUARTStream::
+SetState
+(
+ IN KSSTATE NewState
+)
+{
+ PAGED_CODE();
+
+ DPRINT("SetState %d",NewState);
+
+ if (NewState == KSSTATE_RUN)
+ {
+ if (m_pMiniport->m_fMPUInitialized)
+ {
+ LARGE_INTEGER timeDue100ns;
+ timeDue100ns.QuadPart = 0;
+ KeSetTimer(&m_TimerEvent,timeDue100ns,&m_Dpc);
+ }
+ else
+ {
+ DPRINT("CMiniportDMusUARTStream::SetState KSSTATE_RUN failed due to
uninitialized MPU");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+ }
+
+ if (m_fCapture)
+ {
+ m_pMiniport->m_KSStateInput = NewState;
+ if (NewState == KSSTATE_STOP) // STOPping
+ {
+ m_pMiniport->m_MPUInputBufferHead = 0; // Previously read bytes are
discarded.
+ m_pMiniport->m_MPUInputBufferTail = 0; // The entire FIFO is available.
+ }
+ }
+ return STATUS_SUCCESS;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+
+/*****************************************************************************
+ * CMiniportDMusUART::Service()
+ *****************************************************************************
+ * DPC-mode service call from the port.
+ */
+STDMETHODIMP_(void)
+CMiniportDMusUART::
+Service
+( void
+)
+{
+ DPRINT("Service");
+ if (!m_NumCaptureStreams)
+ {
+ // we should never get here....
+ // if we do, we must have read some trash,
+ // so just reset the input FIFO
+ m_MPUInputBufferTail = m_MPUInputBufferHead = 0;
+ }
+}
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+
+/*****************************************************************************
+ * CMiniportDMusUARTStream::ConnectOutput()
+ *****************************************************************************
+ * Writes outgoing MIDI data.
+ */
+NTSTATUS
+CMiniportDMusUARTStream::
+ConnectOutput(PMXF sinkMXF)
+{
+ PAGED_CODE();
+
+ if (m_fCapture)
+ {
+ if ((sinkMXF) && (m_sinkMXF == m_AllocatorMXF))
+ {
+ DPRINT("ConnectOutput");
+ m_sinkMXF = sinkMXF;
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ DPRINT("ConnectOutput failed");
+ }
+ }
+ else
+ {
+ DPRINT("ConnectOutput called on renderer; failed");
+ }
+ return STATUS_UNSUCCESSFUL;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+
+/*****************************************************************************
+ * CMiniportDMusUARTStream::DisconnectOutput()
+ *****************************************************************************
+ * Writes outgoing MIDI data.
+ */
+NTSTATUS
+CMiniportDMusUARTStream::
+DisconnectOutput(PMXF sinkMXF)
+{
+ PAGED_CODE();
+
+ if (m_fCapture)
+ {
+ if ((m_sinkMXF == sinkMXF) || (!sinkMXF))
+ {
+ DPRINT("DisconnectOutput");
+ m_sinkMXF = m_AllocatorMXF;
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ DPRINT("DisconnectOutput failed");
+ }
+ }
+ else
+ {
+ DPRINT("DisconnectOutput called on renderer; failed");
+ }
+ return STATUS_UNSUCCESSFUL;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+
+/*****************************************************************************
+ * CMiniportDMusUARTStream::PutMessageLocked()
+ *****************************************************************************
+ * Now that the spinlock is held, add this message to the queue.
+ *
+ * Writes an outgoing MIDI message.
+ * We don't sort a new message into the queue -- we append it.
+ * This is fine, since the sequencer feeds us sequenced data.
+ * Timestamps will ascend by design.
+ */
+NTSTATUS CMiniportDMusUARTStream::PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PDMUS_KERNEL_EVENT aDMKEvt;
+
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ if (!m_fCapture)
+ {
+ DPRINT("PutMessage to render stream");
+ if (pDMKEvt)
+ {
+ // m_DpcSpinLock already held
+
+ if (m_DMKEvtQueue)
+ {
+ aDMKEvt = m_DMKEvtQueue; // put pDMKEvt in event queue
+
+ while (aDMKEvt->pNextEvt)
+ {
+ aDMKEvt = aDMKEvt->pNextEvt;
+ }
+ aDMKEvt->pNextEvt = pDMKEvt; // here is end of queue
+ }
+ else // currently nothing in queue
+ {
+ m_DMKEvtQueue = pDMKEvt;
+ if (m_DMKEvtOffset)
+ {
+ DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset ==
%d",m_DMKEvtOffset);
+ m_DMKEvtOffset = 0;
+ }
+ }
+
+ // m_DpcSpinLock already held
+ }
+ if (!m_TimerQueued)
+ {
+ (void) ConsumeEvents();
+ }
+ }
+ else // capture
+ {
+ DPRINT("PutMessage to capture stream");
+ ASSERT(NULL == pDMKEvt);
+
+ SourceEvtsToPort();
+ }
+ return ntStatus;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+/*****************************************************************************
+ * CMiniportDMusUARTStream::PutMessage()
+ *****************************************************************************
+ * Writes an outgoing MIDI message.
+ * We don't sort a new message into the queue -- we append it.
+ * This is fine, since the sequencer feeds us sequenced data.
+ * Timestamps will ascend by design.
+ */
+NTSTATUS CMiniportDMusUARTStream::PutMessage(PDMUS_KERNEL_EVENT pDMKEvt)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PDMUS_KERNEL_EVENT aDMKEvt;
+
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ if (!m_fCapture)
+ {
+ DPRINT("PutMessage to render stream");
+ if (pDMKEvt)
+ {
+ KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock);
+
+ if (m_DMKEvtQueue)
+ {
+ aDMKEvt = m_DMKEvtQueue; // put pDMKEvt in event queue
+
+ while (aDMKEvt->pNextEvt)
+ {
+ aDMKEvt = aDMKEvt->pNextEvt;
+ }
+ aDMKEvt->pNextEvt = pDMKEvt; // here is end of queue
+ }
+ else // currently nothing in queue
+ {
+ m_DMKEvtQueue = pDMKEvt;
+ if (m_DMKEvtOffset)
+ {
+ DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset ==
%d", m_DMKEvtOffset);
+ m_DMKEvtOffset = 0;
+ }
+ }
+
+ KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock);
+ }
+ if (!m_TimerQueued)
+ {
+ (void) ConsumeEvents();
+ }
+ }
+ else // capture
+ {
+ DPRINT("PutMessage to capture stream");
+ ASSERT(NULL == pDMKEvt);
+
+ SourceEvtsToPort();
+ }
+ return ntStatus;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+/*****************************************************************************
+ * CMiniportDMusUARTStream::ConsumeEvents()
+ *****************************************************************************
+ * Attempts to empty the render message queue.
+ * Called either from DPC timer or upon IRP submittal.
+// TODO: support packages right
+// process the package (actually, should do this above.
+// treat the package as a list fragment that shouldn't be sorted.
+// better yet, go through each event in the package, and when
+// an event is exhausted, delete it and decrement m_offset.
+ */
+NTSTATUS CMiniportDMusUARTStream::ConsumeEvents(void)
+{
+ PDMUS_KERNEL_EVENT aDMKEvt;
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ ULONG bytesRemaining = 0,bytesWritten = 0;
+ LARGE_INTEGER aMillisecIn100ns;
+
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+ KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock);
+
+ m_TimerQueued = FALSE;
+ while (m_DMKEvtQueue) // do we have anything to play at all?
+ {
+ aDMKEvt = m_DMKEvtQueue; // event we try to play
+ if (aDMKEvt->cbEvent)
+ {
+ bytesRemaining = aDMKEvt->cbEvent - m_DMKEvtOffset; // number of bytes
left in this evt
+
+ ASSERT(bytesRemaining > 0);
+ if (bytesRemaining <= 0)
+ {
+ bytesRemaining = aDMKEvt->cbEvent;
+ }
+
+ if (aDMKEvt->cbEvent <= sizeof(PBYTE)) // short
message
+ {
+ DPRINT("ConsumeEvents(%02x%02x%02x%02x)",
aDMKEvt->uData.abData[0], aDMKEvt->uData.abData[1], aDMKEvt->uData.abData[2],
aDMKEvt->uData.abData[3]);
+ ntStatus = Write(aDMKEvt->uData.abData +
m_DMKEvtOffset,bytesRemaining,&bytesWritten);
+ }
+ else if (PACKAGE_EVT(aDMKEvt))
+ {
+ ASSERT(m_DMKEvtOffset == 0);
+ m_DMKEvtOffset = 0;
+ DPRINT("ConsumeEvents(Package)");
+
+ ntStatus = PutMessageLocked(aDMKEvt->uData.pPackageEvt); // we
already own the spinlock
+
+ // null this because we are about to throw it in the allocator
+ aDMKEvt->uData.pPackageEvt = NULL;
+ aDMKEvt->cbEvent = 0;
+ bytesWritten = bytesRemaining;
+ }
+ else // SysEx message
+ {
+ DPRINT("ConsumeEvents(%02x%02x%02x%02x)",
aDMKEvt->uData.pbData[0], aDMKEvt->uData.pbData[1], aDMKEvt->uData.pbData[2],
aDMKEvt->uData.pbData[3]);
+
+ ntStatus = Write(aDMKEvt->uData.pbData +
m_DMKEvtOffset,bytesRemaining,&bytesWritten);
+ }
+ } // if (aDMKEvt->cbEvent)
+ if (STATUS_SUCCESS != ntStatus)
+ {
+ DPRINT("ConsumeEvents: Write returned 0x%08x", ntStatus);
+ bytesWritten = bytesRemaining; // just bail on this event and try next
time
+ }
+
+ ASSERT(bytesWritten <= bytesRemaining);
+ if (bytesWritten == bytesRemaining)
+ {
+ m_DMKEvtQueue = m_DMKEvtQueue->pNextEvt;
+ aDMKEvt->pNextEvt = NULL;
+
+ m_AllocatorMXF->PutMessage(aDMKEvt); // throw back in free pool
+ m_DMKEvtOffset = 0; // start fresh on next evt
+ m_NumberOfRetries = 0;
+ } // but wait ... there's more!
+ else // our FIFO is full for now.
+ {
+ // update our offset by that amount we did write
+ m_DMKEvtOffset += bytesWritten;
+ ASSERT(m_DMKEvtOffset < aDMKEvt->cbEvent);
+
+ DPRINT("ConsumeEvents tried %d, wrote %d, at offset %d",
bytesRemaining,bytesWritten,m_DMKEvtOffset);
+ aMillisecIn100ns.QuadPart = -(kOneMillisec); // set timer, come back
later
+ m_TimerQueued = TRUE;
+ m_NumberOfRetries++;
+ ntStatus = KeSetTimer( &m_TimerEvent, aMillisecIn100ns, &m_Dpc );
+ break;
+ } // we didn't write it all
+ } // go back, Jack, do it again (while m_DMKEvtQueue)
+ KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock);
+ return ntStatus;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+/*****************************************************************************
+ * CMiniportDMusUARTStream::HandlePortParams()
+ *****************************************************************************
+ * Writes an outgoing MIDI message.
+ */
+NTSTATUS
+CMiniportDMusUARTStream::
+HandlePortParams
+(
+ IN PPCPROPERTY_REQUEST pRequest
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus;
+
+ if (pRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ ntStatus = ValidatePropertyRequest(pRequest, sizeof(SYNTH_PORTPARAMS), TRUE);
+ if (NT_SUCCESS(ntStatus))
+ {
+ RtlCopyMemory(pRequest->Value, pRequest->Instance,
sizeof(SYNTH_PORTPARAMS));
+
+ PSYNTH_PORTPARAMS Params = (PSYNTH_PORTPARAMS)pRequest->Value;
+
+ if (Params->ValidParams & ~SYNTH_PORTPARAMS_CHANNELGROUPS)
+ {
+ Params->ValidParams &= SYNTH_PORTPARAMS_CHANNELGROUPS;
+ }
+
+ if (!(Params->ValidParams & SYNTH_PORTPARAMS_CHANNELGROUPS))
+ {
+ Params->ChannelGroups = 1;
+ }
+ else if (Params->ChannelGroups != 1)
+ {
+ Params->ChannelGroups = 1;
+ }
+
+ pRequest->ValueSize = sizeof(SYNTH_PORTPARAMS);
+ }
+
+ return ntStatus;
+}
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+/*****************************************************************************
+ * DMusTimerDPC()
+ *****************************************************************************
+ * The timer DPC callback. Thunks to a C++ member function.
+ * This is called by the OS in response to the DirectMusic pin
+ * wanting to wakeup later to process more DirectMusic stuff.
+ */
+VOID
+NTAPI
+DMusUARTTimerDPC
+(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+)
+{
+ ASSERT(DeferredContext);
+
+ CMiniportDMusUARTStream *aStream;
+ aStream = (CMiniportDMusUARTStream *) DeferredContext;
+ if (aStream)
+ {
+ DPRINT("DMusUARTTimerDPC");
+ if (false == aStream->m_fCapture)
+ {
+ (void) aStream->ConsumeEvents();
+ }
+ // ignores return value!
+ }
+}
+
+/*****************************************************************************
+ * DirectMusic properties
+ ****************************************************************************/
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+/*
+ * Properties concerning synthesizer functions.
+ */
+const WCHAR wszDescOut[] = L"DMusic MPU-401 Out ";
+const WCHAR wszDescIn[] = L"DMusic MPU-401 In ";
+
+NTSTATUS PropertyHandler_Synth
+(
+ IN PPCPROPERTY_REQUEST pRequest
+)
+{
+ NTSTATUS ntStatus;
+
+ PAGED_CODE();
+
+ if (pRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONG), TRUE);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // if return buffer can hold a ULONG, return the access flags
+ PULONG AccessFlags = PULONG(pRequest->Value);
+
+ *AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT;
+ switch (pRequest->PropertyItem->Id)
+ {
+ case KSPROPERTY_SYNTH_CAPS:
+ case KSPROPERTY_SYNTH_CHANNELGROUPS:
+ *AccessFlags |= KSPROPERTY_TYPE_GET;
+ }
+ switch (pRequest->PropertyItem->Id)
+ {
+ case KSPROPERTY_SYNTH_CHANNELGROUPS:
+ *AccessFlags |= KSPROPERTY_TYPE_SET;
+ }
+ ntStatus = STATUS_SUCCESS;
+ pRequest->ValueSize = sizeof(ULONG);
+
+ switch (pRequest->PropertyItem->Id)
+ {
+ case KSPROPERTY_SYNTH_PORTPARAMETERS:
+ if (pRequest->MinorTarget)
+ {
+ *AccessFlags |= KSPROPERTY_TYPE_GET;
+ }
+ else
+ {
+ pRequest->ValueSize = 0;
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ }
+ }
+ }
+ else
+ {
+ ntStatus = STATUS_SUCCESS;
+ switch(pRequest->PropertyItem->Id)
+ {
+ case KSPROPERTY_SYNTH_CAPS:
+ DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CAPS");
+
+ if (pRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = ValidatePropertyRequest(pRequest, sizeof(SYNTHCAPS),
TRUE);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ SYNTHCAPS *caps = (SYNTHCAPS*)pRequest->Value;
+ int increment;
+ RtlZeroMemory(caps, sizeof(SYNTHCAPS));
+ // XXX Different guids for different instances!
+ //
+ if (pRequest->Node == eSynthNode)
+ {
+ increment = sizeof(wszDescOut) - 2;
+ RtlCopyMemory( caps->Description,wszDescOut,increment);
+ caps->Guid = CLSID_MiniportDriverDMusUART;
+ }
+ else
+ {
+ increment = sizeof(wszDescIn) - 2;
+ RtlCopyMemory( caps->Description,wszDescIn,increment);
+ caps->Guid =
CLSID_MiniportDriverDMusUARTCapture;
+ }
+
+ caps->Flags = SYNTH_PC_EXTERNAL;
+ caps->MemorySize = 0;
+ caps->MaxChannelGroups = 1;
+ caps->MaxVoices = 0xFFFFFFFF;
+ caps->MaxAudioChannels = 0xFFFFFFFF;
+
+ caps->EffectFlags = 0;
+
+ CMiniportDMusUART *aMiniport;
+ ASSERT(pRequest->MajorTarget);
+ aMiniport = (CMiniportDMusUART
*)(PMINIPORTDMUS)(pRequest->MajorTarget);
+ WCHAR wszDesc2[16];
+ int cLen;
+ cLen =
swprintf(wszDesc2,L"[%03x]\0",PtrToUlong(aMiniport->m_pPortBase));
+
+ cLen *= sizeof(WCHAR);
+ RtlCopyMemory((WCHAR *)((DWORD_PTR)(caps->Description) +
increment),
+ wszDesc2,
+ cLen);
+
+
+ pRequest->ValueSize = sizeof(SYNTHCAPS);
+ }
+ }
+
+ break;
+
+ case KSPROPERTY_SYNTH_PORTPARAMETERS:
+
DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_PORTPARAMETERS");
+ {
+ CMiniportDMusUARTStream *aStream;
+
+ aStream = (CMiniportDMusUARTStream*)(pRequest->MinorTarget);
+ if (aStream)
+ {
+ ntStatus = aStream->HandlePortParams(pRequest);
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ }
+ break;
+
+ case KSPROPERTY_SYNTH_CHANNELGROUPS:
+
DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CHANNELGROUPS");
+
+ ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONG), TRUE);
+ if (NT_SUCCESS(ntStatus))
+ {
+ *(PULONG)(pRequest->Value) = 1;
+ pRequest->ValueSize = sizeof(ULONG);
+ }
+ break;
+
+ case KSPROPERTY_SYNTH_LATENCYCLOCK:
+ DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_LATENCYCLOCK");
+
+ if(pRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ else
+ {
+ ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONGLONG),
TRUE);
+ if(NT_SUCCESS(ntStatus))
+ {
+ REFERENCE_TIME rtLatency;
+ CMiniportDMusUARTStream *aStream;
+
+ aStream = (CMiniportDMusUARTStream*)(pRequest->MinorTarget);
+ if(aStream == NULL)
+ {
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ else
+ {
+
aStream->m_pMiniport->m_MasterClock->GetTime(&rtLatency);
+ *((PULONGLONG)pRequest->Value) = rtLatency;
+ pRequest->ValueSize = sizeof(ULONGLONG);
+ }
+ }
+ }
+ break;
+
+ default:
+ DPRINT("Unhandled property in PropertyHandler_Synth");
+ break;
+ }
+ }
+ return ntStatus;
+}
+
+/*****************************************************************************
+ * ValidatePropertyRequest()
+ *****************************************************************************
+ * Validates pRequest.
+ * Checks if the ValueSize is valid
+ * Checks if the Value is valid
+ *
+ * This does not update pRequest->ValueSize if it returns NT_SUCCESS.
+ * Caller must set pRequest->ValueSize in case of NT_SUCCESS.
+ */
+NTSTATUS ValidatePropertyRequest
+(
+ IN PPCPROPERTY_REQUEST pRequest,
+ IN ULONG ulValueSize,
+ IN BOOLEAN fValueRequired
+)
+{
+ NTSTATUS ntStatus;
+
+ if (pRequest->ValueSize >= ulValueSize)
+ {
+ if (fValueRequired && NULL == pRequest->Value)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ ntStatus = STATUS_SUCCESS;
+ }
+ }
+ else if (0 == pRequest->ValueSize)
+ {
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (STATUS_BUFFER_OVERFLOW == ntStatus)
+ {
+ pRequest->ValueSize = ulValueSize;
+ }
+ else
+ {
+ pRequest->ValueSize = 0;
+ }
+
+ return ntStatus;
+} // ValidatePropertyRequest
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+
+
Modified: trunk/reactos/drivers/wdm/audio/backpln/portcls/private.hpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/backpln/…
==============================================================================
--- trunk/reactos/drivers/wdm/audio/backpln/portcls/private.hpp [iso-8859-1] (original)
+++ trunk/reactos/drivers/wdm/audio/backpln/portcls/private.hpp [iso-8859-1] Mon Nov 1
00:26:59 2010
@@ -22,6 +22,8 @@
#include "interfaces.hpp"
#include <ks.h>
#include <ksmedia.h>
+#include <stdio.h>
+
//#include <intrin.h>
#define TAG_PORTCLASS 'SLCP'