1 /*****************************************************************************
2 * miniport_dmus.cpp - UART miniport implementation
3 *****************************************************************************
4 * Copyright (c) 1997-2000 Microsoft Corporation. All Rights Reserved.
6 * Feb 98 MartinP -- based on UART, began deltas for DirectMusic.
11 #include "private.hpp"
13 // + for absolute / - for relative
15 #define kOneMillisec (10 * 1000)
20 #define MPU401_REG_STATUS 0x01 // Status register
21 #define MPU401_DRR 0x40 // Output ready (for command or data)
22 // if this bit is set, the output FIFO is FULL
23 #define MPU401_DSR 0x80 // Input ready (for data)
24 // if this bit is set, the input FIFO is empty
26 #define MPU401_REG_DATA 0x00 // Data in
27 #define MPU401_REG_COMMAND 0x01 // Commands
28 #define MPU401_CMD_RESET 0xFF // Reset command
29 #define MPU401_CMD_UART 0x3F // Switch to UART mod
32 /*****************************************************************************
36 NTSTATUS NTAPI
InitMPU(IN PINTERRUPTSYNC InterruptSync
,IN PVOID DynamicContext
);
37 NTSTATUS
ResetHardware(PUCHAR portBase
);
38 NTSTATUS
ValidatePropertyRequest(IN PPCPROPERTY_REQUEST pRequest
, IN ULONG ulValueSize
, IN BOOLEAN fValueRequired
);
39 NTSTATUS NTAPI
PropertyHandler_Synth(IN PPCPROPERTY_REQUEST PropertyRequest
);
40 NTSTATUS NTAPI
DMusMPUInterruptServiceRoutine(PINTERRUPTSYNC InterruptSync
,PVOID DynamicContext
);
41 VOID NTAPI
DMusUARTTimerDPC(PKDPC Dpc
,PVOID DeferredContext
,PVOID SystemArgument1
,PVOID SystemArgument2
);
42 NTSTATUS NTAPI
SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync
,PVOID syncWriteContext
);
43 /*****************************************************************************
47 const BOOLEAN COMMAND
= TRUE
;
48 const BOOLEAN DATA
= FALSE
;
49 const ULONG kMPUInputBufferSize
= 128;
52 /*****************************************************************************
56 /*****************************************************************************
58 *****************************************************************************
59 * MPU-401 miniport. This object is associated with the device and is
60 * created when the device is started. The class inherits IMiniportDMus
61 * so it can expose this interface and CUnknown so it automatically gets
62 * reference counting and aggregation support.
64 class CMiniportDMusUART
65 : public IMiniportDMus
,
66 public IMusicTechnology
,
70 LONG m_Ref
; // Reference count
71 KSSTATE m_KSStateInput
; // Miniport state (RUN/PAUSE/ACQUIRE/STOP)
72 PPORTDMUS m_pPort
; // Callback interface.
73 PUCHAR m_pPortBase
; // Base port address.
74 PINTERRUPTSYNC m_pInterruptSync
; // Interrupt synchronization object.
75 PSERVICEGROUP m_pServiceGroup
; // Service group for capture.
76 PMASTERCLOCK m_MasterClock
; // for input data
77 REFERENCE_TIME m_InputTimeStamp
; // capture data timestamp
78 USHORT m_NumRenderStreams
; // Num active render streams.
79 USHORT m_NumCaptureStreams
; // Num active capture streams.
80 ULONG m_MPUInputBufferHead
; // Index of the newest byte in the FIFO.
81 ULONG m_MPUInputBufferTail
; // Index of the oldest empty space in the FIFO.
82 GUID m_MusicFormatTechnology
;
83 POWER_STATE m_PowerState
; // Saved power state (D0 = full power, D3 = off)
84 BOOLEAN m_fMPUInitialized
; // Is the MPU HW initialized.
85 BOOLEAN m_UseIRQ
; // FALSE if no IRQ is used for MIDI.
86 UCHAR m_MPUInputBuffer
[kMPUInputBufferSize
]; // Internal SW FIFO.
88 /*************************************************************************
89 * CMiniportDMusUART methods
91 * These are private member functions used internally by the object.
92 * See MINIPORT.CPP for specific descriptions.
94 NTSTATUS ProcessResources
96 IN PRESOURCELIST ResourceList
98 NTSTATUS
InitializeHardware(PINTERRUPTSYNC interruptSync
,PUCHAR portBase
);
101 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
103 STDMETHODIMP_(ULONG
) AddRef()
105 InterlockedIncrement(&m_Ref
);
108 STDMETHODIMP_(ULONG
) Release()
110 InterlockedDecrement(&m_Ref
);
120 CMiniportDMusUART(IUnknown
* Unknown
){}
121 ~CMiniportDMusUART();
123 /*************************************************************************
126 STDMETHODIMP_(NTSTATUS
)
128 ( OUT PPCFILTER_DESCRIPTOR
* OutFilterDescriptor
130 STDMETHODIMP_(NTSTATUS
)
131 DataRangeIntersection
133 , IN PKSDATARANGE DataRange
134 , IN PKSDATARANGE MatchingDataRange
135 , IN ULONG OutputBufferLength
136 , OUT PVOID ResultantFormat
137 , OUT PULONG ResultantFormatLength
140 return STATUS_NOT_IMPLEMENTED
;
143 /*************************************************************************
144 * IMiniportDMus methods
146 STDMETHODIMP_(NTSTATUS
) Init
148 IN PUNKNOWN UnknownAdapter
,
149 IN PRESOURCELIST ResourceList
,
151 OUT PSERVICEGROUP
* ServiceGroup
153 STDMETHODIMP_(NTSTATUS
) NewStream
156 IN PUNKNOWN OuterUnknown OPTIONAL
,
157 IN POOL_TYPE PoolType
,
159 IN DMUS_STREAM_TYPE StreamType
,
160 IN PKSDATAFORMAT DataFormat
,
161 OUT PSERVICEGROUP
* ServiceGroup
,
162 IN PAllocatorMXF AllocatorMXF
,
163 IN PMASTERCLOCK MasterClock
,
164 OUT PULONGLONG SchedulePreFetch
166 STDMETHODIMP_(void) Service
170 /*************************************************************************
171 * IMusicTechnology methods
173 IMP_IMusicTechnology
;
175 /*************************************************************************
176 * IPowerNotify methods
180 /*************************************************************************
183 friend class CMiniportDMusUARTStream
;
184 friend NTSTATUS NTAPI
185 DMusMPUInterruptServiceRoutine(PINTERRUPTSYNC InterruptSync
,PVOID DynamicContext
);
186 friend NTSTATUS NTAPI
187 SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync
,PVOID syncWriteContext
);
189 DMusUARTTimerDPC(PKDPC Dpc
,PVOID DeferredContext
,PVOID SystemArgument1
,PVOID SystemArgument2
);
190 friend NTSTATUS NTAPI
PropertyHandler_Synth(IN PPCPROPERTY_REQUEST PropertyRequest
);
191 friend STDMETHODIMP_(NTSTATUS
) SnapTimeStamp(PINTERRUPTSYNC InterruptSync
,PVOID pStream
);
194 /*****************************************************************************
195 * CMiniportDMusUARTStream
196 *****************************************************************************
197 * MPU-401 miniport stream. This object is associated with the pin and is
198 * created when the pin is instantiated. It inherits IMXF
199 * so it can expose this interface and CUnknown so it automatically gets
200 * reference counting and aggregation support.
202 class CMiniportDMusUARTStream
: public IMXF
205 LONG m_Ref
; // Reference Count
206 CMiniportDMusUART
* m_pMiniport
; // Parent.
207 REFERENCE_TIME m_SnapshotTimeStamp
; // Current snapshot of miniport's input timestamp.
208 PUCHAR m_pPortBase
; // Base port address.
209 BOOLEAN m_fCapture
; // Whether this is capture.
210 long m_NumFailedMPUTries
; // Deadman timeout for MPU hardware.
211 PAllocatorMXF m_AllocatorMXF
; // source/sink for DMus structs
212 PMXF m_sinkMXF
; // sink for DMus capture
213 PDMUS_KERNEL_EVENT m_DMKEvtQueue
; // queue of waiting events
214 ULONG m_NumberOfRetries
; // Number of consecutive times the h/w was busy/full
215 ULONG m_DMKEvtOffset
; // offset into the event
216 KDPC m_Dpc
; // DPC for timer
217 KTIMER m_TimerEvent
; // timer
218 BOOL m_TimerQueued
; // whether a timer has been set
219 KSPIN_LOCK m_DpcSpinLock
; // protects the ConsumeEvents DPC
221 STDMETHODIMP_(NTSTATUS
) SourceEvtsToPort();
222 STDMETHODIMP_(NTSTATUS
) ConsumeEvents();
223 STDMETHODIMP_(NTSTATUS
) PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt
);
226 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
228 STDMETHODIMP_(ULONG
) AddRef()
230 InterlockedIncrement(&m_Ref
);
233 STDMETHODIMP_(ULONG
) Release()
235 InterlockedDecrement(&m_Ref
);
245 ~CMiniportDMusUARTStream();
247 STDMETHODIMP_(NTSTATUS
) Init
249 IN CMiniportDMusUART
* pMiniport
,
252 IN PAllocatorMXF allocatorMXF
,
253 IN PMASTERCLOCK masterClock
256 NTSTATUS HandlePortParams
258 IN PPCPROPERTY_REQUEST Request
261 /*************************************************************************
262 * IMiniportStreamDMusUART methods
266 STDMETHODIMP_(NTSTATUS
) Write
268 IN PVOID BufferAddress
,
269 IN ULONG BytesToWrite
,
270 OUT PULONG BytesWritten
277 IN PVOID DeferredContext
,
278 IN PVOID SystemArgument1
,
279 IN PVOID SystemArgument2
281 friend NTSTATUS NTAPI
PropertyHandler_Synth(IN PPCPROPERTY_REQUEST
);
282 friend STDMETHODIMP_(NTSTATUS
) SnapTimeStamp(PINTERRUPTSYNC InterruptSync
,PVOID pStream
);
287 #define STR_MODULENAME "DMusUART:Miniport: "
290 #pragma code_seg("PAGE")
293 #define UartFifoOkForWrite(status) ((status & MPU401_DRR) == 0)
294 #define UartFifoOkForRead(status) ((status & MPU401_DSR) == 0)
298 CMiniportDMusUART
*Miniport
;
304 SYNCWRITECONTEXT
, *PSYNCWRITECONTEXT
;
306 /*****************************************************************************
307 * PinDataRangesStreamLegacy
308 * PinDataRangesStreamDMusic
309 *****************************************************************************
310 * Structures indicating range of valid format values for live pins.
313 KSDATARANGE_MUSIC PinDataRangesStreamLegacy
=
317 sizeof(KSDATARANGE_MUSIC
),
321 {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC
)},
322 {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI
)},
323 {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE
)}
326 {STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT
)},
332 KSDATARANGE_MUSIC PinDataRangesStreamDMusic
=
336 sizeof(KSDATARANGE_MUSIC
),
340 {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC
)},
341 {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_DIRECTMUSIC
)},
342 {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE
)}
345 {STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT
)},
351 /*****************************************************************************
352 * PinDataRangePointersStreamLegacy
353 * PinDataRangePointersStreamDMusic
354 * PinDataRangePointersStreamCombined
355 *****************************************************************************
356 * List of pointers to structures indicating range of valid format values
360 PKSDATARANGE PinDataRangePointersStreamLegacy
[] =
362 PKSDATARANGE(&PinDataRangesStreamLegacy
)
365 PKSDATARANGE PinDataRangePointersStreamDMusic
[] =
367 PKSDATARANGE(&PinDataRangesStreamDMusic
)
370 PKSDATARANGE PinDataRangePointersStreamCombined
[] =
372 PKSDATARANGE(&PinDataRangesStreamLegacy
)
373 ,PKSDATARANGE(&PinDataRangesStreamDMusic
)
376 /*****************************************************************************
377 * PinDataRangesBridge
378 *****************************************************************************
379 * Structures indicating range of valid format values for bridge pins.
382 KSDATARANGE PinDataRangesBridge
[] =
390 {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC
)},
391 {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI_BUS
)},
392 {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE
)}
397 /*****************************************************************************
398 * PinDataRangePointersBridge
399 *****************************************************************************
400 * List of pointers to structures indicating range of valid format values
404 PKSDATARANGE PinDataRangePointersBridge
[] =
406 &PinDataRangesBridge
[0]
409 /*****************************************************************************
411 *****************************************************************************
412 * List of properties in the Synth set.
418 // Global: S/Get synthesizer caps
421 KSPROPERTY_SYNTH_CAPS
,
422 KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_BASICSUPPORT
,
423 PropertyHandler_Synth
425 // Global: S/Get port parameters
428 KSPROPERTY_SYNTH_PORTPARAMETERS
,
429 KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_BASICSUPPORT
,
430 PropertyHandler_Synth
432 // Per stream: S/Get channel groups
435 KSPROPERTY_SYNTH_CHANNELGROUPS
,
436 KSPROPERTY_TYPE_SET
| KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_BASICSUPPORT
,
437 PropertyHandler_Synth
439 // Per stream: Get current latency time
442 KSPROPERTY_SYNTH_LATENCYCLOCK
,
443 KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_BASICSUPPORT
,
444 PropertyHandler_Synth
447 DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth
, SynthProperties
);
448 DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth2
, SynthProperties
);
450 #define kMaxNumCaptureStreams 1
451 #define kMaxNumLegacyRenderStreams 1
452 #define kMaxNumDMusicRenderStreams 1
454 /*****************************************************************************
456 *****************************************************************************
460 PCPIN_DESCRIPTOR MiniportPins
[] =
463 kMaxNumLegacyRenderStreams
,kMaxNumLegacyRenderStreams
,0, // InstanceCount
464 NULL
, // AutomationTable
466 0, // InterfacesCount
470 SIZEOF_ARRAY(PinDataRangePointersStreamLegacy
), // DataRangesCount
471 PinDataRangePointersStreamLegacy
, // DataRanges
472 KSPIN_DATAFLOW_IN
, // DataFlow
473 KSPIN_COMMUNICATION_SINK
, // Communication
474 (GUID
*) &KSCATEGORY_AUDIO
, // Category
475 &KSAUDFNAME_MIDI
, // Name
480 kMaxNumDMusicRenderStreams
,kMaxNumDMusicRenderStreams
,0, // InstanceCount
481 NULL
, // AutomationTable
483 0, // InterfacesCount
487 SIZEOF_ARRAY(PinDataRangePointersStreamDMusic
), // DataRangesCount
488 PinDataRangePointersStreamDMusic
, // DataRanges
489 KSPIN_DATAFLOW_IN
, // DataFlow
490 KSPIN_COMMUNICATION_SINK
, // Communication
491 (GUID
*) &KSCATEGORY_AUDIO
, // Category
492 &KSAUDFNAME_DMUSIC_MPU_OUT
, // Name
497 0,0,0, // InstanceCount
498 NULL
, // AutomationTable
500 0, // InterfacesCount
504 SIZEOF_ARRAY(PinDataRangePointersBridge
), // DataRangesCount
505 PinDataRangePointersBridge
, // DataRanges
506 KSPIN_DATAFLOW_OUT
, // DataFlow
507 KSPIN_COMMUNICATION_NONE
, // Communication
508 (GUID
*) &KSCATEGORY_AUDIO
, // Category
514 0,0,0, // InstanceCount
515 NULL
, // AutomationTable
517 0, // InterfacesCount
521 SIZEOF_ARRAY(PinDataRangePointersBridge
), // DataRangesCount
522 PinDataRangePointersBridge
, // DataRanges
523 KSPIN_DATAFLOW_IN
, // DataFlow
524 KSPIN_COMMUNICATION_NONE
, // Communication
525 (GUID
*) &KSCATEGORY_AUDIO
, // Category
531 kMaxNumCaptureStreams
,kMaxNumCaptureStreams
,0, // InstanceCount
532 NULL
, // AutomationTable
534 0, // InterfacesCount
538 SIZEOF_ARRAY(PinDataRangePointersStreamCombined
), // DataRangesCount
539 PinDataRangePointersStreamCombined
, // DataRanges
540 KSPIN_DATAFLOW_OUT
, // DataFlow
541 KSPIN_COMMUNICATION_SINK
, // Communication
542 (GUID
*) &KSCATEGORY_AUDIO
, // Category
543 &KSAUDFNAME_DMUSIC_MPU_IN
, // Name
549 /*****************************************************************************
551 *****************************************************************************
554 #define CONST_PCNODE_DESCRIPTOR(n) { 0, NULL, &n, NULL }
555 #define CONST_PCNODE_DESCRIPTOR_AUTO(n,a) { 0, &a, &n, NULL }
557 PCNODE_DESCRIPTOR MiniportNodes
[] =
559 CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER
, AutomationSynth
)
560 , CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER
, AutomationSynth2
)
563 /*****************************************************************************
564 * MiniportConnections
565 *****************************************************************************
566 * List of connections.
574 eFilterInputPinLeg
= 0,
582 PCCONNECTION_DESCRIPTOR MiniportConnections
[] =
585 { PCFILTER_NODE
, eFilterInputPinLeg
, PCFILTER_NODE
, eBridgeOutputPin
} // Legacy Stream in to synth.
586 , { PCFILTER_NODE
, eFilterInputPinDM
, eSynthNode
, KSNODEPIN_STANDARD_IN
} // DM Stream in to synth.
587 , { eSynthNode
, KSNODEPIN_STANDARD_OUT
, PCFILTER_NODE
, eBridgeOutputPin
} // Synth to bridge out.
588 , { PCFILTER_NODE
, eBridgeInputPin
, eInputNode
, KSNODEPIN_STANDARD_IN
} // Bridge in to input.
589 , { eInputNode
, KSNODEPIN_STANDARD_OUT
, PCFILTER_NODE
, eFilterOutputPin
} // Input to DM/Legacy Stream out.
592 /*****************************************************************************
594 *****************************************************************************
595 * List of categories.
598 GUID MiniportCategories
[] =
600 {STATICGUIDOF(KSCATEGORY_AUDIO
)},
601 {STATICGUIDOF(KSCATEGORY_RENDER
)},
602 {STATICGUIDOF(KSCATEGORY_CAPTURE
)}
605 /*****************************************************************************
606 * MiniportFilterDescriptor
607 *****************************************************************************
608 * Complete miniport filter description.
611 PCFILTER_DESCRIPTOR MiniportFilterDescriptor
=
614 NULL
, // AutomationTable
615 sizeof(PCPIN_DESCRIPTOR
), // PinSize
616 SIZEOF_ARRAY(MiniportPins
), // PinCount
617 MiniportPins
, // Pins
618 sizeof(PCNODE_DESCRIPTOR
), // NodeSize
619 SIZEOF_ARRAY(MiniportNodes
), // NodeCount
620 MiniportNodes
, // Nodes
621 SIZEOF_ARRAY(MiniportConnections
), // ConnectionCount
622 MiniportConnections
, // Connections
623 SIZEOF_ARRAY(MiniportCategories
), // CategoryCount
624 MiniportCategories
// Categories
628 #pragma code_seg("PAGE")
631 BOOLEAN
TryMPU(IN PUCHAR PortBase
);
632 NTSTATUS
WriteMPU(IN PUCHAR PortBase
,IN BOOLEAN IsCommand
,IN UCHAR Value
);
635 #pragma code_seg("PAGE")
638 // make sure we're in UART mode
639 NTSTATUS
ResetHardware(PUCHAR portBase
)
643 return WriteMPU(portBase
,COMMAND
,MPU401_CMD_UART
);
647 #pragma code_seg("PAGE")
651 // We initialize the UART with interrupts suppressed so we don't
652 // try to service the chip prematurely.
654 NTSTATUS
CMiniportDMusUART::InitializeHardware(PINTERRUPTSYNC interruptSync
,PUCHAR portBase
)
661 ntStatus
= interruptSync
->CallSynchronizedRoutine(InitMPU
,PVOID(portBase
));
665 ntStatus
= InitMPU(NULL
,PVOID(portBase
));
668 if (NT_SUCCESS(ntStatus
))
671 // Start the UART (this should trigger an interrupt).
673 ntStatus
= ResetHardware(portBase
);
677 DPRINT("*** InitMPU returned with ntStatus 0x%08x ***", ntStatus
);
680 m_fMPUInitialized
= NT_SUCCESS(ntStatus
);
689 /*****************************************************************************
691 *****************************************************************************
692 * Synchronized routine to initialize the MPU401.
698 IN PINTERRUPTSYNC InterruptSync
,
699 IN PVOID DynamicContext
705 return STATUS_INVALID_PARAMETER_2
;
708 PUCHAR portBase
= PUCHAR(DynamicContext
);
712 NTSTATUS ntStatus
= STATUS_SUCCESS
;
715 // Reset the card (puts it into "smart mode")
717 ntStatus
= WriteMPU(portBase
,COMMAND
,MPU401_CMD_RESET
);
719 // wait for the acknowledgement
720 // NOTE: When the Ack arrives, it will trigger an interrupt.
721 // Normally the DPC routine would read in the ack byte and we
722 // would never see it, however since we have the hardware locked (HwEnter),
723 // we can read the port before the DPC can and thus we receive the Ack.
724 startTime
= PcGetTimeInterval(0);
726 while(PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
728 status
= READ_PORT_UCHAR(portBase
+ MPU401_REG_STATUS
);
730 if (UartFifoOkForRead(status
)) // Is data waiting?
732 READ_PORT_UCHAR(portBase
+ MPU401_REG_DATA
); // yep.. read ACK
733 success
= TRUE
; // don't need to do more
736 KeStallExecutionProcessor(25); // microseconds
741 DPRINT("First attempt to reset the MPU didn't get ACKed.\n");
745 // NOTE: We cannot check the ACK byte because if the card was already in
746 // UART mode it will not send an ACK but it will reset.
748 // reset the card again
749 (void) WriteMPU(portBase
,COMMAND
,MPU401_CMD_RESET
);
751 // wait for ack (again)
752 startTime
= PcGetTimeInterval(0); // This might take a while
755 while (PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
757 status
= READ_PORT_UCHAR(portBase
+ MPU401_REG_STATUS
);
758 if (UartFifoOkForRead(status
)) // Is data waiting?
760 dataByte
= READ_PORT_UCHAR(portBase
+ MPU401_REG_DATA
); // yep.. read ACK
761 success
= TRUE
; // don't need to do more
764 KeStallExecutionProcessor(25);
767 if ((0xFE != dataByte
) || !success
) // Did we succeed? If no second ACK, something is hosed
769 DPRINT("Second attempt to reset the MPU didn't get ACKed.\n");
770 DPRINT("Init Reset failure error. Ack = %X", ULONG(dataByte
));
772 ntStatus
= STATUS_IO_DEVICE_ERROR
;
782 /*****************************************************************************
783 * CMiniportDMusUARTStream::Write()
784 *****************************************************************************
785 * Writes outgoing MIDI data.
787 STDMETHODIMP_(NTSTATUS
)
788 CMiniportDMusUARTStream::
791 IN PVOID BufferAddress
,
793 OUT PULONG BytesWritten
797 ASSERT(BytesWritten
);
803 NTSTATUS ntStatus
= STATUS_SUCCESS
;
811 pMidiData
= PUCHAR(BufferAddress
);
815 SYNCWRITECONTEXT context
;
816 context
.Miniport
= (m_pMiniport
);
817 context
.PortBase
= m_pPortBase
;
818 context
.BufferAddress
= pMidiData
;
819 context
.Length
= Length
;
820 context
.BytesRead
= &count
;
822 if (m_pMiniport
->m_UseIRQ
)
824 ntStatus
= m_pMiniport
->m_pInterruptSync
->
825 CallSynchronizedRoutine(SynchronizedDMusMPUWrite
,PVOID(&context
));
829 ntStatus
= SynchronizedDMusMPUWrite(NULL
,PVOID(&context
));
834 m_NumFailedMPUTries
++;
835 if (m_NumFailedMPUTries
>= 100)
837 ntStatus
= STATUS_IO_DEVICE_ERROR
;
838 m_NumFailedMPUTries
= 0;
843 m_NumFailedMPUTries
= 0;
845 } // if we have data at all
846 *BytesWritten
= count
;
848 else // called write on the read stream
850 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
859 /*****************************************************************************
860 * SynchronizedDMusMPUWrite()
861 *****************************************************************************
862 * Writes outgoing MIDI data.
866 SynchronizedDMusMPUWrite
868 IN PINTERRUPTSYNC InterruptSync
,
869 IN PVOID syncWriteContext
872 PSYNCWRITECONTEXT context
;
873 context
= (PSYNCWRITECONTEXT
)syncWriteContext
;
874 ASSERT(context
->Miniport
);
875 ASSERT(context
->PortBase
);
876 ASSERT(context
->BufferAddress
);
877 ASSERT(context
->Length
);
878 ASSERT(context
->BytesRead
);
880 PUCHAR pChar
= PUCHAR(context
->BufferAddress
);
881 NTSTATUS ntStatus
; // , readStatus
882 ntStatus
= STATUS_SUCCESS
;
884 // while we're not there yet, and
885 // while we don't have to wait on an aligned byte (including 0)
886 // (we never wait on a byte. Better to come back later)
887 /*readStatus = */ DMusMPUInterruptServiceRoutine(InterruptSync
,PVOID(context
->Miniport
));
888 while ( (*(context
->BytesRead
) < context
->Length
)
889 && ( TryMPU(context
->PortBase
)
890 || (*(context
->BytesRead
)%3)
893 ntStatus
= WriteMPU(context
->PortBase
,DATA
,*pChar
);
894 if (NT_SUCCESS(ntStatus
))
897 *(context
->BytesRead
) = *(context
->BytesRead
) + 1;
898 // readStatus = DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport));
902 DPRINT("SynchronizedDMusMPUWrite failed (0x%08x)",ntStatus
);
906 /*readStatus = */ DMusMPUInterruptServiceRoutine(InterruptSync
,PVOID(context
->Miniport
));
910 #define kMPUPollTimeout 2
916 /*****************************************************************************
918 *****************************************************************************
919 * See if the MPU401 is free.
934 while (numPolls
< kMPUPollTimeout
)
936 status
= READ_PORT_UCHAR(PortBase
+ MPU401_REG_STATUS
);
938 if (UartFifoOkForWrite(status
)) // Is this a good time to write data?
944 if (numPolls
>= kMPUPollTimeout
)
947 DPRINT("TryMPU failed");
961 /*****************************************************************************
963 *****************************************************************************
964 * Write a byte out to the MPU401.
970 IN BOOLEAN IsCommand
,
975 NTSTATUS ntStatus
= STATUS_IO_DEVICE_ERROR
;
979 DPRINT("O: PortBase is zero\n");
982 PUCHAR deviceAddr
= PortBase
+ MPU401_REG_DATA
;
986 deviceAddr
= PortBase
+ MPU401_REG_COMMAND
;
989 ULONGLONG startTime
= PcGetTimeInterval(0);
991 while (PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
994 = READ_PORT_UCHAR(PortBase
+ MPU401_REG_STATUS
);
996 if (UartFifoOkForWrite(status
)) // Is this a good time to write data?
997 { // yep (Jon comment)
998 WRITE_PORT_UCHAR(deviceAddr
,Value
);
999 DPRINT("WriteMPU emitted 0x%02x",Value
);
1000 ntStatus
= STATUS_SUCCESS
;
1011 /*****************************************************************************
1013 *****************************************************************************
1015 * At synchronized execution to ISR, copy miniport's volatile m_InputTimeStamp
1016 * to stream's m_SnapshotTimeStamp and zero m_InputTimeStamp.
1019 STDMETHODIMP_(NTSTATUS
)
1020 SnapTimeStamp(PINTERRUPTSYNC InterruptSync
,PVOID pStream
)
1022 CMiniportDMusUARTStream
*pMPStream
= (CMiniportDMusUARTStream
*)pStream
;
1024 // cache the timestamp
1025 pMPStream
->m_SnapshotTimeStamp
= pMPStream
->m_pMiniport
->m_InputTimeStamp
;
1027 // if the window is closed, zero the timestamp
1028 if (pMPStream
->m_pMiniport
->m_MPUInputBufferHead
==
1029 pMPStream
->m_pMiniport
->m_MPUInputBufferTail
)
1031 pMPStream
->m_pMiniport
->m_InputTimeStamp
= 0;
1034 return STATUS_SUCCESS
;
1037 /*****************************************************************************
1038 * CMiniportDMusUARTStream::SourceEvtsToPort()
1039 *****************************************************************************
1041 * Reads incoming MIDI data, feeds into DMus events.
1042 * No need to touch the hardware, just read from our SW FIFO.
1045 STDMETHODIMP_(NTSTATUS
)
1046 CMiniportDMusUARTStream::SourceEvtsToPort()
1050 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1051 DPRINT("SourceEvtsToPort");
1055 ntStatus
= STATUS_SUCCESS
;
1056 if (m_pMiniport
->m_MPUInputBufferHead
!= m_pMiniport
->m_MPUInputBufferTail
)
1058 PDMUS_KERNEL_EVENT aDMKEvt
,eventTail
,eventHead
= NULL
;
1060 while (m_pMiniport
->m_MPUInputBufferHead
!= m_pMiniport
->m_MPUInputBufferTail
)
1062 (void) m_AllocatorMXF
->GetMessage(&aDMKEvt
);
1065 DPRINT("SourceEvtsToPort can't allocate DMKEvt");
1066 return STATUS_INSUFFICIENT_RESOURCES
;
1069 // put this event at the end of the list
1072 eventHead
= aDMKEvt
;
1076 eventTail
= eventHead
;
1077 while (eventTail
->pNextEvt
)
1079 eventTail
= eventTail
->pNextEvt
;
1081 eventTail
->pNextEvt
= aDMKEvt
;
1083 // read all the bytes out of the buffer, into event(s)
1084 for (aDMKEvt
->cbEvent
= 0; aDMKEvt
->cbEvent
< sizeof(PBYTE
); aDMKEvt
->cbEvent
++)
1086 if (m_pMiniport
->m_MPUInputBufferHead
== m_pMiniport
->m_MPUInputBufferTail
)
1088 // _DbgPrintF(DEBUGLVL_TERSE, ("SourceEvtsToPort m_MPUInputBufferHead met m_MPUInputBufferTail, overrun"));
1091 aDMKEvt
->uData
.abData
[aDMKEvt
->cbEvent
] = m_pMiniport
->m_MPUInputBuffer
[m_pMiniport
->m_MPUInputBufferHead
];
1092 m_pMiniport
->m_MPUInputBufferHead
++;
1093 if (m_pMiniport
->m_MPUInputBufferHead
>= kMPUInputBufferSize
)
1095 m_pMiniport
->m_MPUInputBufferHead
= 0;
1100 if (m_pMiniport
->m_UseIRQ
)
1102 ntStatus
= m_pMiniport
->m_pInterruptSync
->CallSynchronizedRoutine(SnapTimeStamp
,PVOID(this));
1106 ntStatus
= SnapTimeStamp(NULL
,PVOID(this));
1108 aDMKEvt
= eventHead
;
1111 aDMKEvt
->ullPresTime100ns
= m_SnapshotTimeStamp
;
1112 aDMKEvt
->usChannelGroup
= 1;
1113 aDMKEvt
->usFlags
= DMUS_KEF_EVENT_INCOMPLETE
;
1114 aDMKEvt
= aDMKEvt
->pNextEvt
;
1116 (void)m_sinkMXF
->PutMessage(eventHead
);
1119 else // render stream
1121 DPRINT("SourceEvtsToPort called on render stream");
1122 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
1131 /*****************************************************************************
1132 * DMusMPUInterruptServiceRoutine()
1133 *****************************************************************************
1138 DMusMPUInterruptServiceRoutine
1140 IN PINTERRUPTSYNC InterruptSync
,
1141 IN PVOID DynamicContext
1144 DPRINT("DMusMPUInterruptServiceRoutine");
1145 ULONGLONG startTime
;
1147 ASSERT(DynamicContext
);
1150 BOOL newBytesAvailable
;
1151 CMiniportDMusUART
*that
;
1152 NTSTATUS clockStatus
;
1154 that
= (CMiniportDMusUART
*) DynamicContext
;
1155 newBytesAvailable
= FALSE
;
1156 ntStatus
= STATUS_UNSUCCESSFUL
;
1158 UCHAR portStatus
= 0xff;
1161 // Read the MPU status byte.
1163 if (that
->m_pPortBase
)
1166 READ_PORT_UCHAR(that
->m_pPortBase
+ MPU401_REG_STATUS
);
1169 // If there is outstanding work to do and there is a port-driver for
1170 // the MPU miniport...
1172 if (UartFifoOkForRead(portStatus
) && that
->m_pPort
)
1174 startTime
= PcGetTimeInterval(0);
1175 while ( (PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
1176 && (UartFifoOkForRead(portStatus
)) )
1178 UCHAR uDest
= READ_PORT_UCHAR(that
->m_pPortBase
+ MPU401_REG_DATA
);
1179 if ( (that
->m_KSStateInput
== KSSTATE_RUN
)
1180 && (that
->m_NumCaptureStreams
)
1183 ULONG buffHead
= that
->m_MPUInputBufferHead
;
1184 if ( (that
->m_MPUInputBufferTail
+ 1 == buffHead
)
1185 || (that
->m_MPUInputBufferTail
+ 1 - kMPUInputBufferSize
== buffHead
))
1187 DPRINT("*****MPU Input Buffer Overflow*****");
1191 if (!that
->m_InputTimeStamp
)
1193 clockStatus
= that
->m_MasterClock
->GetTime(&that
->m_InputTimeStamp
);
1194 if (STATUS_SUCCESS
!= clockStatus
)
1196 DPRINT("GetTime failed for clock 0x%08x",that
->m_MasterClock
);
1199 newBytesAvailable
= TRUE
;
1200 // ...place the data in our FIFO...
1201 that
->m_MPUInputBuffer
[that
->m_MPUInputBufferTail
] = uDest
;
1202 ASSERT(that
->m_MPUInputBufferTail
< kMPUInputBufferSize
);
1204 that
->m_MPUInputBufferTail
++;
1205 if (that
->m_MPUInputBufferTail
>= kMPUInputBufferSize
)
1207 that
->m_MPUInputBufferTail
= 0;
1212 // Look for more MIDI data.
1215 READ_PORT_UCHAR(that
->m_pPortBase
+ MPU401_REG_STATUS
);
1216 } // either there's no data or we ran too long
1217 if (newBytesAvailable
)
1220 // ...notify the MPU port driver that we have bytes.
1222 that
->m_pPort
->Notify(that
->m_pServiceGroup
);
1224 ntStatus
= STATUS_SUCCESS
;
1231 /*****************************************************************************
1232 * CMiniportDMusUART::GetDescription()
1233 *****************************************************************************
1234 * Gets the topology.
1236 STDMETHODIMP_(NTSTATUS
)
1240 OUT PPCFILTER_DESCRIPTOR
* OutFilterDescriptor
1245 ASSERT(OutFilterDescriptor
);
1247 DPRINT("GetDescription");
1249 *OutFilterDescriptor
= &MiniportFilterDescriptor
;
1251 return STATUS_SUCCESS
;
1255 #pragma code_seg("PAGE")
1259 NewMiniportDMusUART(
1260 OUT PMINIPORT
* OutMiniport
,
1261 IN REFCLSID ClassId
)
1263 CMiniportDMusUART
* This
;
1266 This
= new(NonPagedPool
, TAG_PORTCLASS
) CMiniportDMusUART(NULL
);
1268 return STATUS_INSUFFICIENT_RESOURCES
;
1270 Status
= This
->QueryInterface(IID_IMiniport
, (PVOID
*)OutMiniport
);
1272 if (!NT_SUCCESS(Status
))
1277 DPRINT("NewMiniportDMusUART %p Status %x\n", *OutMiniport
, Status
);
1283 #pragma code_seg("PAGE")
1286 /*****************************************************************************
1287 * CMiniportDMusUART::ProcessResources()
1288 *****************************************************************************
1289 * Processes the resource list, setting up helper objects accordingly.
1295 IN PRESOURCELIST ResourceList
1300 DPRINT("ProcessResources");
1302 ASSERT(ResourceList
);
1305 return STATUS_DEVICE_CONFIGURATION_ERROR
;
1308 // Get counts for the types of resources.
1310 ULONG countIO
= ResourceList
->NumberOfPorts();
1311 ULONG countIRQ
= ResourceList
->NumberOfInterrupts();
1312 ULONG countDMA
= ResourceList
->NumberOfDmas();
1313 ULONG lengthIO
= ResourceList
->FindTranslatedPort(0)->u
.Port
.Length
;
1316 DPRINT("Starting MPU401 Port 0x%lx", ResourceList
->FindTranslatedPort(0)->u
.Port
.Start
.LowPart
);
1319 NTSTATUS ntStatus
= STATUS_SUCCESS
;
1322 // Make sure we have the expected number of resources.
1330 DPRINT("Unknown ResourceList configuraton");
1331 ntStatus
= STATUS_DEVICE_CONFIGURATION_ERROR
;
1334 if (NT_SUCCESS(ntStatus
))
1337 // Get the port address.
1340 PUCHAR(ResourceList
->FindTranslatedPort(0)->u
.Port
.Start
.QuadPart
);
1342 ntStatus
= InitializeHardware(m_pInterruptSync
,m_pPortBase
);
1349 #pragma code_seg("PAGE")
1351 /*****************************************************************************
1352 * CMiniportDMusUART::NonDelegatingQueryInterface()
1353 *****************************************************************************
1354 * Obtains an interface. This function works just like a COM QueryInterface
1355 * call and is used if the object is not being aggregated.
1357 STDMETHODIMP_(NTSTATUS
)
1358 CMiniportDMusUART::QueryInterface
1366 DPRINT("Miniport::NonDelegatingQueryInterface");
1369 if (IsEqualGUIDAligned(Interface
,IID_IUnknown
))
1371 *Object
= PVOID(PUNKNOWN(PMINIPORTDMUS(this)));
1374 if (IsEqualGUIDAligned(Interface
,IID_IMiniport
))
1376 *Object
= PVOID(PMINIPORT(this));
1379 if (IsEqualGUIDAligned(Interface
,IID_IMiniportDMus
))
1381 *Object
= PVOID(PMINIPORTDMUS(this));
1384 if (IsEqualGUIDAligned(Interface
,IID_IMusicTechnology
))
1386 *Object
= PVOID(PMUSICTECHNOLOGY(this));
1389 if (IsEqualGUIDAligned(Interface
,IID_IPowerNotify
))
1391 *Object
= PVOID(PPOWERNOTIFY(this));
1401 // We reference the interface for the caller.
1403 PUNKNOWN(*Object
)->AddRef();
1404 return STATUS_SUCCESS
;
1407 return STATUS_INVALID_PARAMETER
;
1411 #pragma code_seg("PAGE")
1413 /*****************************************************************************
1414 * CMiniportDMusUART::~CMiniportDMusUART()
1415 *****************************************************************************
1418 CMiniportDMusUART::~CMiniportDMusUART(void)
1422 DPRINT("~CMiniportDMusUART");
1424 ASSERT(0 == m_NumCaptureStreams
);
1425 ASSERT(0 == m_NumRenderStreams
);
1427 // reset the HW so we don't get anymore interrupts
1428 if (m_UseIRQ
&& m_pInterruptSync
)
1430 (void) m_pInterruptSync
->CallSynchronizedRoutine((PINTERRUPTSYNCROUTINE
)InitMPU
,PVOID(m_pPortBase
));
1434 (void) InitMPU(NULL
,PVOID(m_pPortBase
));
1437 if (m_pInterruptSync
)
1439 m_pInterruptSync
->Release();
1440 m_pInterruptSync
= NULL
;
1442 if (m_pServiceGroup
)
1444 m_pServiceGroup
->Release();
1445 m_pServiceGroup
= NULL
;
1455 #pragma code_seg("PAGE")
1457 /*****************************************************************************
1458 * CMiniportDMusUART::Init()
1459 *****************************************************************************
1460 * Initializes a the miniport.
1462 STDMETHODIMP_(NTSTATUS
)
1466 IN PUNKNOWN UnknownInterruptSync OPTIONAL
,
1467 IN PRESOURCELIST ResourceList
,
1469 OUT PSERVICEGROUP
* ServiceGroup
1474 ASSERT(ResourceList
);
1477 return STATUS_DEVICE_CONFIGURATION_ERROR
;
1481 ASSERT(ServiceGroup
);
1485 *ServiceGroup
= NULL
;
1487 m_fMPUInitialized
= FALSE
;
1489 // This will remain unspecified if the miniport does not get any power
1492 m_PowerState
.DeviceState
= PowerDeviceUnspecified
;
1495 // AddRef() is required because we are keeping this pointer.
1502 if (IsEqualGUIDAligned(m_MusicFormatTechnology
, GUID_NULL
))
1504 RtlCopyMemory( &m_MusicFormatTechnology
,
1505 &KSMUSIC_TECHNOLOGY_PORT
,
1508 RtlCopyMemory( &PinDataRangesStreamLegacy
.Technology
,
1509 &m_MusicFormatTechnology
,
1511 RtlCopyMemory( &PinDataRangesStreamDMusic
.Technology
,
1512 &m_MusicFormatTechnology
,
1515 for (ULONG bufferCount
= 0;bufferCount
< kMPUInputBufferSize
;bufferCount
++)
1517 m_MPUInputBuffer
[bufferCount
] = 0;
1519 m_MPUInputBufferHead
= 0;
1520 m_MPUInputBufferTail
= 0;
1521 m_InputTimeStamp
= 0;
1522 m_KSStateInput
= KSSTATE_STOP
;
1524 NTSTATUS ntStatus
= STATUS_SUCCESS
;
1526 m_NumRenderStreams
= 0;
1527 m_NumCaptureStreams
= 0;
1530 if (ResourceList
->NumberOfInterrupts() == 0)
1535 ntStatus
= PcNewServiceGroup(&m_pServiceGroup
,NULL
);
1536 if (NT_SUCCESS(ntStatus
) && !m_pServiceGroup
) // keep any error
1538 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1541 if (NT_SUCCESS(ntStatus
))
1543 *ServiceGroup
= m_pServiceGroup
;
1544 m_pServiceGroup
->AddRef();
1547 // Register the service group with the port early so the port is
1548 // prepared to handle interrupts.
1550 m_pPort
->RegisterServiceGroup(m_pServiceGroup
);
1553 if (NT_SUCCESS(ntStatus
) && m_UseIRQ
)
1556 // Due to a bug in the InterruptSync design, we shouldn't share
1557 // the interrupt sync object. Whoever goes away first
1558 // will disconnect it, and the other points off into nowhere.
1560 // Instead we generate our own interrupt sync object.
1562 UnknownInterruptSync
= NULL
;
1564 if (UnknownInterruptSync
)
1567 UnknownInterruptSync
->QueryInterface
1570 (PVOID
*) &m_pInterruptSync
1573 if (!m_pInterruptSync
&& NT_SUCCESS(ntStatus
)) // keep any error
1575 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1577 if (NT_SUCCESS(ntStatus
))
1578 { // run this ISR first
1579 ntStatus
= m_pInterruptSync
->
1580 RegisterServiceRoutine(DMusMPUInterruptServiceRoutine
,PVOID(this),TRUE
);
1585 { // create our own interruptsync mechanism.
1592 0, // Resource Index
1593 InterruptSyncModeNormal
// Run ISRs once until we get SUCCESS
1596 if (!m_pInterruptSync
&& NT_SUCCESS(ntStatus
)) // keep any error
1598 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1601 if (NT_SUCCESS(ntStatus
))
1603 ntStatus
= m_pInterruptSync
->RegisterServiceRoutine(
1604 DMusMPUInterruptServiceRoutine
,
1606 TRUE
); // run this ISR first
1608 if (NT_SUCCESS(ntStatus
))
1610 ntStatus
= m_pInterruptSync
->Connect();
1615 if (NT_SUCCESS(ntStatus
))
1617 ntStatus
= ProcessResources(ResourceList
);
1620 if (!NT_SUCCESS(ntStatus
))
1623 // clean up our mess
1626 // clean up the interrupt sync
1627 if( m_pInterruptSync
)
1629 m_pInterruptSync
->Release();
1630 m_pInterruptSync
= NULL
;
1633 // clean up the service group
1634 if( m_pServiceGroup
)
1636 m_pServiceGroup
->Release();
1637 m_pServiceGroup
= NULL
;
1640 // clean up the out param service group.
1643 (*ServiceGroup
)->Release();
1644 (*ServiceGroup
) = NULL
;
1656 #pragma code_seg("PAGE")
1658 /*****************************************************************************
1659 * CMiniportDMusUART::NewStream()
1660 *****************************************************************************
1661 * Gets the topology.
1663 STDMETHODIMP_(NTSTATUS
)
1668 IN PUNKNOWN OuterUnknown OPTIONAL
,
1669 IN POOL_TYPE PoolType
,
1671 IN DMUS_STREAM_TYPE StreamType
,
1672 IN PKSDATAFORMAT DataFormat
,
1673 OUT PSERVICEGROUP
* ServiceGroup
,
1674 IN PAllocatorMXF AllocatorMXF
,
1675 IN PMASTERCLOCK MasterClock
,
1676 OUT PULONGLONG SchedulePreFetch
1681 DPRINT("NewStream");
1682 NTSTATUS ntStatus
= STATUS_SUCCESS
;
1684 // In 100 ns, we want stuff as soon as it comes in
1686 *SchedulePreFetch
= 0;
1688 // if we don't have any streams already open, get the hardware ready.
1689 if ((!m_NumCaptureStreams
) && (!m_NumRenderStreams
))
1691 ntStatus
= ResetHardware(m_pPortBase
);
1692 if (!NT_SUCCESS(ntStatus
))
1694 DPRINT("CMiniportDMusUART::NewStream ResetHardware failed");
1699 if ( ((m_NumCaptureStreams
< kMaxNumCaptureStreams
)
1700 && (StreamType
== DMUS_STREAM_MIDI_CAPTURE
))
1701 || ((m_NumRenderStreams
< kMaxNumLegacyRenderStreams
+ kMaxNumDMusicRenderStreams
)
1702 && (StreamType
== DMUS_STREAM_MIDI_RENDER
))
1705 CMiniportDMusUARTStream
*pStream
=
1706 new(PoolType
) CMiniportDMusUARTStream();
1713 pStream
->Init(this,m_pPortBase
,(StreamType
== DMUS_STREAM_MIDI_CAPTURE
),AllocatorMXF
,MasterClock
);
1715 if (NT_SUCCESS(ntStatus
))
1717 *MXF
= PMXF(pStream
);
1720 if (StreamType
== DMUS_STREAM_MIDI_CAPTURE
)
1722 m_NumCaptureStreams
++;
1723 *ServiceGroup
= m_pServiceGroup
;
1724 (*ServiceGroup
)->AddRef();
1728 m_NumRenderStreams
++;
1729 *ServiceGroup
= NULL
;
1737 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1742 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
1743 if (StreamType
== DMUS_STREAM_MIDI_CAPTURE
)
1745 DPRINT("NewStream failed, too many capture streams");
1747 else if (StreamType
== DMUS_STREAM_MIDI_RENDER
)
1749 DPRINT("NewStream failed, too many render streams");
1753 DPRINT("NewStream invalid stream type");
1761 #pragma code_seg("PAGE")
1763 /*****************************************************************************
1764 * CMiniportDMusUART::SetTechnology()
1765 *****************************************************************************
1766 * Sets pindatarange technology.
1768 STDMETHODIMP_(NTSTATUS
)
1772 IN
const GUID
* Technology
1777 NTSTATUS ntStatus
= STATUS_UNSUCCESSFUL
;
1779 // Fail if miniport has already been initialized.
1781 if (NULL
== m_pPort
)
1783 RtlCopyMemory(&m_MusicFormatTechnology
, Technology
, sizeof(GUID
));
1784 ntStatus
= STATUS_SUCCESS
;
1790 /*****************************************************************************
1791 * CMiniportDMusUART::PowerChangeNotify()
1792 *****************************************************************************
1793 * Handle power state change for the miniport.
1796 #pragma code_seg("PAGE")
1803 IN POWER_STATE PowerState
1808 DPRINT("CMiniportDMusUART::PoweChangeNotify D%d", PowerState
.DeviceState
);
1810 switch (PowerState
.DeviceState
)
1813 if (m_PowerState
.DeviceState
!= PowerDeviceD0
)
1815 if (!NT_SUCCESS(InitializeHardware(m_pInterruptSync
,m_pPortBase
)))
1817 DPRINT("InitializeHardware failed when resuming");
1828 m_PowerState
.DeviceState
= PowerState
.DeviceState
;
1829 } // PowerChangeNotify
1832 #pragma code_seg("PAGE")
1834 /*****************************************************************************
1835 * CMiniportDMusUARTStream::NonDelegatingQueryInterface()
1836 *****************************************************************************
1837 * Obtains an interface. This function works just like a COM QueryInterface
1838 * call and is used if the object is not being aggregated.
1840 STDMETHODIMP_(NTSTATUS
)
1841 CMiniportDMusUARTStream::QueryInterface
1849 DPRINT("Stream::NonDelegatingQueryInterface");
1852 if (IsEqualGUIDAligned(Interface
,IID_IUnknown
))
1854 *Object
= PVOID(PUNKNOWN(this));
1857 if (IsEqualGUIDAligned(Interface
,IID_IMXF
))
1859 *Object
= PVOID(PMXF(this));
1869 // We reference the interface for the caller.
1871 PUNKNOWN(*Object
)->AddRef();
1872 return STATUS_SUCCESS
;
1875 return STATUS_INVALID_PARAMETER
;
1879 #pragma code_seg("PAGE")
1881 /*****************************************************************************
1882 * CMiniportDMusUARTStream::~CMiniportDMusUARTStream()
1883 *****************************************************************************
1884 * Destructs a stream.
1886 CMiniportDMusUARTStream::~CMiniportDMusUARTStream(void)
1890 DPRINT("~CMiniportDMusUARTStream");
1892 KeCancelTimer(&m_TimerEvent
);
1898 m_AllocatorMXF
->PutMessage(m_DMKEvtQueue
);
1902 DPRINT("~CMiniportDMusUARTStream, no allocator, can't flush DMKEvts");
1904 m_DMKEvtQueue
= NULL
;
1908 m_AllocatorMXF
->Release();
1909 m_AllocatorMXF
= NULL
;
1916 m_pMiniport
->m_NumCaptureStreams
--;
1920 m_pMiniport
->m_NumRenderStreams
--;
1923 m_pMiniport
->Release();
1928 #pragma code_seg("PAGE")
1930 /*****************************************************************************
1931 * CMiniportDMusUARTStream::Init()
1932 *****************************************************************************
1933 * Initializes a stream.
1935 STDMETHODIMP_(NTSTATUS
)
1936 CMiniportDMusUARTStream::
1939 IN CMiniportDMusUART
* pMiniport
,
1940 IN PUCHAR pPortBase
,
1941 IN BOOLEAN fCapture
,
1942 IN PAllocatorMXF allocatorMXF
,
1943 IN PMASTERCLOCK masterClock
1953 m_NumFailedMPUTries
= 0;
1954 m_TimerQueued
= FALSE
;
1955 KeInitializeSpinLock(&m_DpcSpinLock
);
1956 m_pMiniport
= pMiniport
;
1957 m_pMiniport
->AddRef();
1959 pMiniport
->m_MasterClock
= masterClock
;
1961 m_pPortBase
= pPortBase
;
1962 m_fCapture
= fCapture
;
1964 m_SnapshotTimeStamp
= 0;
1965 m_DMKEvtQueue
= NULL
;
1968 m_NumberOfRetries
= 0;
1972 allocatorMXF
->AddRef();
1973 m_AllocatorMXF
= allocatorMXF
;
1974 m_sinkMXF
= m_AllocatorMXF
;
1978 return STATUS_INVALID_PARAMETER
;
1984 &::DMusUARTTimerDPC
,
1987 KeInitializeTimer(&m_TimerEvent
);
1989 return STATUS_SUCCESS
;
1993 #pragma code_seg("PAGE")
1995 /*****************************************************************************
1996 * CMiniportDMusUARTStream::SetState()
1997 *****************************************************************************
1998 * Sets the state of the channel.
2000 STDMETHODIMP_(NTSTATUS
)
2001 CMiniportDMusUARTStream::
2009 DPRINT("SetState %d",NewState
);
2011 if (NewState
== KSSTATE_RUN
)
2013 if (m_pMiniport
->m_fMPUInitialized
)
2015 LARGE_INTEGER timeDue100ns
;
2016 timeDue100ns
.QuadPart
= 0;
2017 KeSetTimer(&m_TimerEvent
,timeDue100ns
,&m_Dpc
);
2021 DPRINT("CMiniportDMusUARTStream::SetState KSSTATE_RUN failed due to uninitialized MPU");
2022 return STATUS_INVALID_DEVICE_STATE
;
2028 m_pMiniport
->m_KSStateInput
= NewState
;
2029 if (NewState
== KSSTATE_STOP
) // STOPping
2031 m_pMiniport
->m_MPUInputBufferHead
= 0; // Previously read bytes are discarded.
2032 m_pMiniport
->m_MPUInputBufferTail
= 0; // The entire FIFO is available.
2035 return STATUS_SUCCESS
;
2043 /*****************************************************************************
2044 * CMiniportDMusUART::Service()
2045 *****************************************************************************
2046 * DPC-mode service call from the port.
2055 if (!m_NumCaptureStreams
)
2057 // we should never get here....
2058 // if we do, we must have read some trash,
2059 // so just reset the input FIFO
2060 m_MPUInputBufferTail
= m_MPUInputBufferHead
= 0;
2065 #pragma code_seg("PAGE")
2068 /*****************************************************************************
2069 * CMiniportDMusUARTStream::ConnectOutput()
2070 *****************************************************************************
2071 * Writes outgoing MIDI data.
2074 CMiniportDMusUARTStream::
2075 ConnectOutput(PMXF sinkMXF
)
2081 if ((sinkMXF
) && (m_sinkMXF
== m_AllocatorMXF
))
2083 DPRINT("ConnectOutput");
2084 m_sinkMXF
= sinkMXF
;
2085 return STATUS_SUCCESS
;
2089 DPRINT("ConnectOutput failed");
2094 DPRINT("ConnectOutput called on renderer; failed");
2096 return STATUS_UNSUCCESSFUL
;
2100 #pragma code_seg("PAGE")
2103 /*****************************************************************************
2104 * CMiniportDMusUARTStream::DisconnectOutput()
2105 *****************************************************************************
2106 * Writes outgoing MIDI data.
2109 CMiniportDMusUARTStream::
2110 DisconnectOutput(PMXF sinkMXF
)
2116 if ((m_sinkMXF
== sinkMXF
) || (!sinkMXF
))
2118 DPRINT("DisconnectOutput");
2119 m_sinkMXF
= m_AllocatorMXF
;
2120 return STATUS_SUCCESS
;
2124 DPRINT("DisconnectOutput failed");
2129 DPRINT("DisconnectOutput called on renderer; failed");
2131 return STATUS_UNSUCCESSFUL
;
2139 /*****************************************************************************
2140 * CMiniportDMusUARTStream::PutMessageLocked()
2141 *****************************************************************************
2142 * Now that the spinlock is held, add this message to the queue.
2144 * Writes an outgoing MIDI message.
2145 * We don't sort a new message into the queue -- we append it.
2146 * This is fine, since the sequencer feeds us sequenced data.
2147 * Timestamps will ascend by design.
2149 NTSTATUS
CMiniportDMusUARTStream::PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt
)
2151 NTSTATUS ntStatus
= STATUS_SUCCESS
;
2152 PDMUS_KERNEL_EVENT aDMKEvt
;
2154 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
2158 DPRINT("PutMessage to render stream");
2161 // m_DpcSpinLock already held
2165 aDMKEvt
= m_DMKEvtQueue
; // put pDMKEvt in event queue
2167 while (aDMKEvt
->pNextEvt
)
2169 aDMKEvt
= aDMKEvt
->pNextEvt
;
2171 aDMKEvt
->pNextEvt
= pDMKEvt
; // here is end of queue
2173 else // currently nothing in queue
2175 m_DMKEvtQueue
= pDMKEvt
;
2178 DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d",m_DMKEvtOffset
);
2183 // m_DpcSpinLock already held
2187 (void) ConsumeEvents();
2192 DPRINT("PutMessage to capture stream");
2193 ASSERT(NULL
== pDMKEvt
);
2204 /*****************************************************************************
2205 * CMiniportDMusUARTStream::PutMessage()
2206 *****************************************************************************
2207 * Writes an outgoing MIDI message.
2208 * We don't sort a new message into the queue -- we append it.
2209 * This is fine, since the sequencer feeds us sequenced data.
2210 * Timestamps will ascend by design.
2212 NTSTATUS
CMiniportDMusUARTStream::PutMessage(PDMUS_KERNEL_EVENT pDMKEvt
)
2214 NTSTATUS ntStatus
= STATUS_SUCCESS
;
2215 PDMUS_KERNEL_EVENT aDMKEvt
;
2217 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
2221 DPRINT("PutMessage to render stream");
2224 KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock
);
2228 aDMKEvt
= m_DMKEvtQueue
; // put pDMKEvt in event queue
2230 while (aDMKEvt
->pNextEvt
)
2232 aDMKEvt
= aDMKEvt
->pNextEvt
;
2234 aDMKEvt
->pNextEvt
= pDMKEvt
; // here is end of queue
2236 else // currently nothing in queue
2238 m_DMKEvtQueue
= pDMKEvt
;
2241 DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d", m_DMKEvtOffset
);
2246 KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock
);
2250 (void) ConsumeEvents();
2255 DPRINT("PutMessage to capture stream");
2256 ASSERT(NULL
== pDMKEvt
);
2267 /*****************************************************************************
2268 * CMiniportDMusUARTStream::ConsumeEvents()
2269 *****************************************************************************
2270 * Attempts to empty the render message queue.
2271 * Called either from DPC timer or upon IRP submittal.
2272 // TODO: support packages right
2273 // process the package (actually, should do this above.
2274 // treat the package as a list fragment that shouldn't be sorted.
2275 // better yet, go through each event in the package, and when
2276 // an event is exhausted, delete it and decrement m_offset.
2278 NTSTATUS
CMiniportDMusUARTStream::ConsumeEvents(void)
2280 PDMUS_KERNEL_EVENT aDMKEvt
;
2282 NTSTATUS ntStatus
= STATUS_SUCCESS
;
2283 ULONG bytesRemaining
= 0,bytesWritten
= 0;
2284 LARGE_INTEGER aMillisecIn100ns
;
2286 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
2287 KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock
);
2289 m_TimerQueued
= FALSE
;
2290 while (m_DMKEvtQueue
) // do we have anything to play at all?
2292 aDMKEvt
= m_DMKEvtQueue
; // event we try to play
2293 if (aDMKEvt
->cbEvent
)
2295 bytesRemaining
= aDMKEvt
->cbEvent
- m_DMKEvtOffset
; // number of bytes left in this evt
2297 ASSERT(bytesRemaining
> 0);
2298 if (bytesRemaining
<= 0)
2300 bytesRemaining
= aDMKEvt
->cbEvent
;
2303 if (aDMKEvt
->cbEvent
<= sizeof(PBYTE
)) // short message
2305 DPRINT("ConsumeEvents(%02x%02x%02x%02x)", aDMKEvt
->uData
.abData
[0], aDMKEvt
->uData
.abData
[1], aDMKEvt
->uData
.abData
[2], aDMKEvt
->uData
.abData
[3]);
2306 ntStatus
= Write(aDMKEvt
->uData
.abData
+ m_DMKEvtOffset
,bytesRemaining
,&bytesWritten
);
2308 else if (PACKAGE_EVT(aDMKEvt
))
2310 ASSERT(m_DMKEvtOffset
== 0);
2312 DPRINT("ConsumeEvents(Package)");
2314 ntStatus
= PutMessageLocked(aDMKEvt
->uData
.pPackageEvt
); // we already own the spinlock
2316 // null this because we are about to throw it in the allocator
2317 aDMKEvt
->uData
.pPackageEvt
= NULL
;
2318 aDMKEvt
->cbEvent
= 0;
2319 bytesWritten
= bytesRemaining
;
2321 else // SysEx message
2323 DPRINT("ConsumeEvents(%02x%02x%02x%02x)", aDMKEvt
->uData
.pbData
[0], aDMKEvt
->uData
.pbData
[1], aDMKEvt
->uData
.pbData
[2], aDMKEvt
->uData
.pbData
[3]);
2325 ntStatus
= Write(aDMKEvt
->uData
.pbData
+ m_DMKEvtOffset
,bytesRemaining
,&bytesWritten
);
2327 } // if (aDMKEvt->cbEvent)
2328 if (STATUS_SUCCESS
!= ntStatus
)
2330 DPRINT("ConsumeEvents: Write returned 0x%08x", ntStatus
);
2331 bytesWritten
= bytesRemaining
; // just bail on this event and try next time
2334 ASSERT(bytesWritten
<= bytesRemaining
);
2335 if (bytesWritten
== bytesRemaining
)
2337 m_DMKEvtQueue
= m_DMKEvtQueue
->pNextEvt
;
2338 aDMKEvt
->pNextEvt
= NULL
;
2340 m_AllocatorMXF
->PutMessage(aDMKEvt
); // throw back in free pool
2341 m_DMKEvtOffset
= 0; // start fresh on next evt
2342 m_NumberOfRetries
= 0;
2343 } // but wait ... there's more!
2344 else // our FIFO is full for now.
2346 // update our offset by that amount we did write
2347 m_DMKEvtOffset
+= bytesWritten
;
2348 ASSERT(m_DMKEvtOffset
< aDMKEvt
->cbEvent
);
2350 DPRINT("ConsumeEvents tried %d, wrote %d, at offset %d", bytesRemaining
,bytesWritten
,m_DMKEvtOffset
);
2351 aMillisecIn100ns
.QuadPart
= -(kOneMillisec
); // set timer, come back later
2352 m_TimerQueued
= TRUE
;
2353 m_NumberOfRetries
++;
2354 ntStatus
= KeSetTimer( &m_TimerEvent
, aMillisecIn100ns
, &m_Dpc
);
2356 } // we didn't write it all
2357 } // go back, Jack, do it again (while m_DMKEvtQueue)
2358 KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock
);
2366 /*****************************************************************************
2367 * CMiniportDMusUARTStream::HandlePortParams()
2368 *****************************************************************************
2369 * Writes an outgoing MIDI message.
2372 CMiniportDMusUARTStream::
2375 IN PPCPROPERTY_REQUEST pRequest
2382 if (pRequest
->Verb
& KSPROPERTY_TYPE_SET
)
2384 return STATUS_INVALID_DEVICE_REQUEST
;
2387 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(SYNTH_PORTPARAMS
), TRUE
);
2388 if (NT_SUCCESS(ntStatus
))
2390 RtlCopyMemory(pRequest
->Value
, pRequest
->Instance
, sizeof(SYNTH_PORTPARAMS
));
2392 PSYNTH_PORTPARAMS Params
= (PSYNTH_PORTPARAMS
)pRequest
->Value
;
2394 if (Params
->ValidParams
& ~SYNTH_PORTPARAMS_CHANNELGROUPS
)
2396 Params
->ValidParams
&= SYNTH_PORTPARAMS_CHANNELGROUPS
;
2399 if (!(Params
->ValidParams
& SYNTH_PORTPARAMS_CHANNELGROUPS
))
2401 Params
->ChannelGroups
= 1;
2403 else if (Params
->ChannelGroups
!= 1)
2405 Params
->ChannelGroups
= 1;
2408 pRequest
->ValueSize
= sizeof(SYNTH_PORTPARAMS
);
2418 /*****************************************************************************
2420 *****************************************************************************
2421 * The timer DPC callback. Thunks to a C++ member function.
2422 * This is called by the OS in response to the DirectMusic pin
2423 * wanting to wakeup later to process more DirectMusic stuff.
2430 IN PVOID DeferredContext
,
2431 IN PVOID SystemArgument1
,
2432 IN PVOID SystemArgument2
2435 ASSERT(DeferredContext
);
2437 CMiniportDMusUARTStream
*aStream
;
2438 aStream
= (CMiniportDMusUARTStream
*) DeferredContext
;
2441 DPRINT("DMusUARTTimerDPC");
2442 if (false == aStream
->m_fCapture
)
2444 (void) aStream
->ConsumeEvents();
2446 // ignores return value!
2450 /*****************************************************************************
2451 * DirectMusic properties
2452 ****************************************************************************/
2459 * Properties concerning synthesizer functions.
2461 const WCHAR wszDescOut
[] = L
"DMusic MPU-401 Out ";
2462 const WCHAR wszDescIn
[] = L
"DMusic MPU-401 In ";
2466 PropertyHandler_Synth
2468 IN PPCPROPERTY_REQUEST pRequest
2475 if (pRequest
->Verb
& KSPROPERTY_TYPE_BASICSUPPORT
)
2477 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(ULONG
), TRUE
);
2478 if (NT_SUCCESS(ntStatus
))
2480 // if return buffer can hold a ULONG, return the access flags
2481 PULONG AccessFlags
= PULONG(pRequest
->Value
);
2483 *AccessFlags
= KSPROPERTY_TYPE_BASICSUPPORT
;
2484 switch (pRequest
->PropertyItem
->Id
)
2486 case KSPROPERTY_SYNTH_CAPS
:
2487 case KSPROPERTY_SYNTH_CHANNELGROUPS
:
2488 *AccessFlags
|= KSPROPERTY_TYPE_GET
;
2490 switch (pRequest
->PropertyItem
->Id
)
2492 case KSPROPERTY_SYNTH_CHANNELGROUPS
:
2493 *AccessFlags
|= KSPROPERTY_TYPE_SET
;
2495 ntStatus
= STATUS_SUCCESS
;
2496 pRequest
->ValueSize
= sizeof(ULONG
);
2498 switch (pRequest
->PropertyItem
->Id
)
2500 case KSPROPERTY_SYNTH_PORTPARAMETERS
:
2501 if (pRequest
->MinorTarget
)
2503 *AccessFlags
|= KSPROPERTY_TYPE_GET
;
2507 pRequest
->ValueSize
= 0;
2508 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2515 ntStatus
= STATUS_SUCCESS
;
2516 switch(pRequest
->PropertyItem
->Id
)
2518 case KSPROPERTY_SYNTH_CAPS
:
2519 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CAPS");
2521 if (pRequest
->Verb
& KSPROPERTY_TYPE_SET
)
2523 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2526 if (NT_SUCCESS(ntStatus
))
2528 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(SYNTHCAPS
), TRUE
);
2530 if (NT_SUCCESS(ntStatus
))
2532 SYNTHCAPS
*caps
= (SYNTHCAPS
*)pRequest
->Value
;
2534 RtlZeroMemory(caps
, sizeof(SYNTHCAPS
));
2535 // XXX Different guids for different instances!
2537 if (pRequest
->Node
== eSynthNode
)
2539 increment
= sizeof(wszDescOut
) - 2;
2540 RtlCopyMemory( caps
->Description
,wszDescOut
,increment
);
2541 caps
->Guid
= CLSID_MiniportDriverDMusUART
;
2545 increment
= sizeof(wszDescIn
) - 2;
2546 RtlCopyMemory( caps
->Description
,wszDescIn
,increment
);
2547 caps
->Guid
= CLSID_MiniportDriverDMusUARTCapture
;
2550 caps
->Flags
= SYNTH_PC_EXTERNAL
;
2551 caps
->MemorySize
= 0;
2552 caps
->MaxChannelGroups
= 1;
2553 caps
->MaxVoices
= 0xFFFFFFFF;
2554 caps
->MaxAudioChannels
= 0xFFFFFFFF;
2556 caps
->EffectFlags
= 0;
2558 CMiniportDMusUART
*aMiniport
;
2559 ASSERT(pRequest
->MajorTarget
);
2560 aMiniport
= (CMiniportDMusUART
*)(PMINIPORTDMUS
)(pRequest
->MajorTarget
);
2563 cLen
= swprintf(wszDesc2
,L
"[%03x]\0",PtrToUlong(aMiniport
->m_pPortBase
));
2565 cLen
*= sizeof(WCHAR
);
2566 RtlCopyMemory((WCHAR
*)((DWORD_PTR
)(caps
->Description
) + increment
),
2571 pRequest
->ValueSize
= sizeof(SYNTHCAPS
);
2577 case KSPROPERTY_SYNTH_PORTPARAMETERS
:
2578 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_PORTPARAMETERS");
2580 CMiniportDMusUARTStream
*aStream
;
2582 aStream
= (CMiniportDMusUARTStream
*)(pRequest
->MinorTarget
);
2585 ntStatus
= aStream
->HandlePortParams(pRequest
);
2589 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2594 case KSPROPERTY_SYNTH_CHANNELGROUPS
:
2595 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CHANNELGROUPS");
2597 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(ULONG
), TRUE
);
2598 if (NT_SUCCESS(ntStatus
))
2600 *(PULONG
)(pRequest
->Value
) = 1;
2601 pRequest
->ValueSize
= sizeof(ULONG
);
2605 case KSPROPERTY_SYNTH_LATENCYCLOCK
:
2606 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_LATENCYCLOCK");
2608 if(pRequest
->Verb
& KSPROPERTY_TYPE_SET
)
2610 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2614 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(ULONGLONG
), TRUE
);
2615 if(NT_SUCCESS(ntStatus
))
2617 REFERENCE_TIME rtLatency
;
2618 CMiniportDMusUARTStream
*aStream
;
2620 aStream
= (CMiniportDMusUARTStream
*)(pRequest
->MinorTarget
);
2623 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2627 aStream
->m_pMiniport
->m_MasterClock
->GetTime(&rtLatency
);
2628 *((PULONGLONG
)pRequest
->Value
) = rtLatency
;
2629 pRequest
->ValueSize
= sizeof(ULONGLONG
);
2636 DPRINT("Unhandled property in PropertyHandler_Synth");
2643 /*****************************************************************************
2644 * ValidatePropertyRequest()
2645 *****************************************************************************
2646 * Validates pRequest.
2647 * Checks if the ValueSize is valid
2648 * Checks if the Value is valid
2650 * This does not update pRequest->ValueSize if it returns NT_SUCCESS.
2651 * Caller must set pRequest->ValueSize in case of NT_SUCCESS.
2653 NTSTATUS ValidatePropertyRequest
2655 IN PPCPROPERTY_REQUEST pRequest
,
2656 IN ULONG ulValueSize
,
2657 IN BOOLEAN fValueRequired
2662 if (pRequest
->ValueSize
>= ulValueSize
)
2664 if (fValueRequired
&& NULL
== pRequest
->Value
)
2666 ntStatus
= STATUS_INVALID_PARAMETER
;
2670 ntStatus
= STATUS_SUCCESS
;
2673 else if (0 == pRequest
->ValueSize
)
2675 ntStatus
= STATUS_BUFFER_OVERFLOW
;
2679 ntStatus
= STATUS_BUFFER_TOO_SMALL
;
2682 if (STATUS_BUFFER_OVERFLOW
== ntStatus
)
2684 pRequest
->ValueSize
= ulValueSize
;
2688 pRequest
->ValueSize
= 0;
2692 } // ValidatePropertyRequest