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.
10 #include "private.hpp"
18 // + for absolute / - for relative
20 #define kOneMillisec (10 * 1000)
25 #define MPU401_REG_STATUS 0x01 // Status register
26 #define MPU401_DRR 0x40 // Output ready (for command or data)
27 // if this bit is set, the output FIFO is FULL
28 #define MPU401_DSR 0x80 // Input ready (for data)
29 // if this bit is set, the input FIFO is empty
31 #define MPU401_REG_DATA 0x00 // Data in
32 #define MPU401_REG_COMMAND 0x01 // Commands
33 #define MPU401_CMD_RESET 0xFF // Reset command
34 #define MPU401_CMD_UART 0x3F // Switch to UART mod
37 /*****************************************************************************
41 NTSTATUS NTAPI
InitMPU(IN PINTERRUPTSYNC InterruptSync
,IN PVOID DynamicContext
);
42 NTSTATUS
ResetHardware(PUCHAR portBase
);
43 NTSTATUS
ValidatePropertyRequest(IN PPCPROPERTY_REQUEST pRequest
, IN ULONG ulValueSize
, IN BOOLEAN fValueRequired
);
44 NTSTATUS NTAPI
PropertyHandler_Synth(IN PPCPROPERTY_REQUEST PropertyRequest
);
45 NTSTATUS NTAPI
DMusMPUInterruptServiceRoutine(PINTERRUPTSYNC InterruptSync
,PVOID DynamicContext
);
46 VOID NTAPI
DMusUARTTimerDPC(PKDPC Dpc
,PVOID DeferredContext
,PVOID SystemArgument1
,PVOID SystemArgument2
);
47 NTSTATUS NTAPI
SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync
,PVOID syncWriteContext
);
48 /*****************************************************************************
52 const BOOLEAN COMMAND
= TRUE
;
53 const BOOLEAN DATA
= FALSE
;
54 const ULONG kMPUInputBufferSize
= 128;
57 /*****************************************************************************
61 /*****************************************************************************
63 *****************************************************************************
64 * MPU-401 miniport. This object is associated with the device and is
65 * created when the device is started. The class inherits IMiniportDMus
66 * so it can expose this interface and CUnknown so it automatically gets
67 * reference counting and aggregation support.
69 class CMiniportDMusUART
70 : public IMiniportDMus
,
71 public IMusicTechnology
,
75 LONG m_Ref
; // Reference count
76 KSSTATE m_KSStateInput
; // Miniport state (RUN/PAUSE/ACQUIRE/STOP)
77 PPORTDMUS m_pPort
; // Callback interface.
78 PUCHAR m_pPortBase
; // Base port address.
79 PINTERRUPTSYNC m_pInterruptSync
; // Interrupt synchronization object.
80 PSERVICEGROUP m_pServiceGroup
; // Service group for capture.
81 PMASTERCLOCK m_MasterClock
; // for input data
82 REFERENCE_TIME m_InputTimeStamp
; // capture data timestamp
83 USHORT m_NumRenderStreams
; // Num active render streams.
84 USHORT m_NumCaptureStreams
; // Num active capture streams.
85 ULONG m_MPUInputBufferHead
; // Index of the newest byte in the FIFO.
86 ULONG m_MPUInputBufferTail
; // Index of the oldest empty space in the FIFO.
87 GUID m_MusicFormatTechnology
;
88 POWER_STATE m_PowerState
; // Saved power state (D0 = full power, D3 = off)
89 BOOLEAN m_fMPUInitialized
; // Is the MPU HW initialized.
90 BOOLEAN m_UseIRQ
; // FALSE if no IRQ is used for MIDI.
91 UCHAR m_MPUInputBuffer
[kMPUInputBufferSize
]; // Internal SW FIFO.
93 /*************************************************************************
94 * CMiniportDMusUART methods
96 * These are private member functions used internally by the object.
97 * See MINIPORT.CPP for specific descriptions.
99 NTSTATUS ProcessResources
101 IN PRESOURCELIST ResourceList
103 NTSTATUS
InitializeHardware(PINTERRUPTSYNC interruptSync
,PUCHAR portBase
);
106 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
108 STDMETHODIMP_(ULONG
) AddRef()
110 InterlockedIncrement(&m_Ref
);
113 STDMETHODIMP_(ULONG
) Release()
115 InterlockedDecrement(&m_Ref
);
125 CMiniportDMusUART(IUnknown
* Unknown
){}
126 virtual ~CMiniportDMusUART();
128 /*************************************************************************
131 STDMETHODIMP_(NTSTATUS
)
133 ( OUT PPCFILTER_DESCRIPTOR
* OutFilterDescriptor
135 STDMETHODIMP_(NTSTATUS
)
136 DataRangeIntersection
138 , IN PKSDATARANGE DataRange
139 , IN PKSDATARANGE MatchingDataRange
140 , IN ULONG OutputBufferLength
141 , OUT PVOID ResultantFormat
142 , OUT PULONG ResultantFormatLength
145 return STATUS_NOT_IMPLEMENTED
;
148 /*************************************************************************
149 * IMiniportDMus methods
151 STDMETHODIMP_(NTSTATUS
) Init
153 IN PUNKNOWN UnknownAdapter
,
154 IN PRESOURCELIST ResourceList
,
156 OUT PSERVICEGROUP
* ServiceGroup
158 STDMETHODIMP_(NTSTATUS
) NewStream
161 IN PUNKNOWN OuterUnknown OPTIONAL
,
162 IN POOL_TYPE PoolType
,
164 IN DMUS_STREAM_TYPE StreamType
,
165 IN PKSDATAFORMAT DataFormat
,
166 OUT PSERVICEGROUP
* ServiceGroup
,
167 IN PAllocatorMXF AllocatorMXF
,
168 IN PMASTERCLOCK MasterClock
,
169 OUT PULONGLONG SchedulePreFetch
171 STDMETHODIMP_(void) Service
175 /*************************************************************************
176 * IMusicTechnology methods
178 IMP_IMusicTechnology
;
180 /*************************************************************************
181 * IPowerNotify methods
185 /*************************************************************************
188 friend class CMiniportDMusUARTStream
;
189 friend NTSTATUS NTAPI
190 DMusMPUInterruptServiceRoutine(PINTERRUPTSYNC InterruptSync
,PVOID DynamicContext
);
191 friend NTSTATUS NTAPI
192 SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync
,PVOID syncWriteContext
);
194 DMusUARTTimerDPC(PKDPC Dpc
,PVOID DeferredContext
,PVOID SystemArgument1
,PVOID SystemArgument2
);
195 friend NTSTATUS NTAPI
PropertyHandler_Synth(IN PPCPROPERTY_REQUEST PropertyRequest
);
196 friend STDMETHODIMP_(NTSTATUS
) SnapTimeStamp(PINTERRUPTSYNC InterruptSync
,PVOID pStream
);
199 /*****************************************************************************
200 * CMiniportDMusUARTStream
201 *****************************************************************************
202 * MPU-401 miniport stream. This object is associated with the pin and is
203 * created when the pin is instantiated. It inherits IMXF
204 * so it can expose this interface and CUnknown so it automatically gets
205 * reference counting and aggregation support.
207 class CMiniportDMusUARTStream
: public IMXF
210 LONG m_Ref
; // Reference Count
211 CMiniportDMusUART
* m_pMiniport
; // Parent.
212 REFERENCE_TIME m_SnapshotTimeStamp
; // Current snapshot of miniport's input timestamp.
213 PUCHAR m_pPortBase
; // Base port address.
214 BOOLEAN m_fCapture
; // Whether this is capture.
215 long m_NumFailedMPUTries
; // Deadman timeout for MPU hardware.
216 PAllocatorMXF m_AllocatorMXF
; // source/sink for DMus structs
217 PMXF m_sinkMXF
; // sink for DMus capture
218 PDMUS_KERNEL_EVENT m_DMKEvtQueue
; // queue of waiting events
219 ULONG m_NumberOfRetries
; // Number of consecutive times the h/w was busy/full
220 ULONG m_DMKEvtOffset
; // offset into the event
221 KDPC m_Dpc
; // DPC for timer
222 KTIMER m_TimerEvent
; // timer
223 BOOL m_TimerQueued
; // whether a timer has been set
224 KSPIN_LOCK m_DpcSpinLock
; // protects the ConsumeEvents DPC
226 STDMETHODIMP_(NTSTATUS
) SourceEvtsToPort();
227 STDMETHODIMP_(NTSTATUS
) ConsumeEvents();
228 STDMETHODIMP_(NTSTATUS
) PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt
);
231 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
233 STDMETHODIMP_(ULONG
) AddRef()
235 InterlockedIncrement(&m_Ref
);
238 STDMETHODIMP_(ULONG
) Release()
240 InterlockedDecrement(&m_Ref
);
250 virtual ~CMiniportDMusUARTStream();
252 STDMETHODIMP_(NTSTATUS
) Init
254 IN CMiniportDMusUART
* pMiniport
,
257 IN PAllocatorMXF allocatorMXF
,
258 IN PMASTERCLOCK masterClock
261 NTSTATUS HandlePortParams
263 IN PPCPROPERTY_REQUEST Request
266 /*************************************************************************
267 * IMiniportStreamDMusUART methods
271 STDMETHODIMP_(NTSTATUS
) Write
273 IN PVOID BufferAddress
,
274 IN ULONG BytesToWrite
,
275 OUT PULONG BytesWritten
282 IN PVOID DeferredContext
,
283 IN PVOID SystemArgument1
,
284 IN PVOID SystemArgument2
286 friend NTSTATUS NTAPI
PropertyHandler_Synth(IN PPCPROPERTY_REQUEST
);
287 friend STDMETHODIMP_(NTSTATUS
) SnapTimeStamp(PINTERRUPTSYNC InterruptSync
,PVOID pStream
);
292 #define STR_MODULENAME "DMusUART:Miniport: "
295 #pragma code_seg("PAGE")
298 #define UartFifoOkForWrite(status) ((status & MPU401_DRR) == 0)
299 #define UartFifoOkForRead(status) ((status & MPU401_DSR) == 0)
303 CMiniportDMusUART
*Miniport
;
309 SYNCWRITECONTEXT
, *PSYNCWRITECONTEXT
;
311 /*****************************************************************************
312 * PinDataRangesStreamLegacy
313 * PinDataRangesStreamDMusic
314 *****************************************************************************
315 * Structures indicating range of valid format values for live pins.
318 KSDATARANGE_MUSIC PinDataRangesStreamLegacy
=
322 sizeof(KSDATARANGE_MUSIC
),
326 {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC
)},
327 {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI
)},
328 {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE
)}
331 {STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT
)},
337 KSDATARANGE_MUSIC PinDataRangesStreamDMusic
=
341 sizeof(KSDATARANGE_MUSIC
),
345 {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC
)},
346 {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_DIRECTMUSIC
)},
347 {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE
)}
350 {STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT
)},
356 /*****************************************************************************
357 * PinDataRangePointersStreamLegacy
358 * PinDataRangePointersStreamDMusic
359 * PinDataRangePointersStreamCombined
360 *****************************************************************************
361 * List of pointers to structures indicating range of valid format values
365 PKSDATARANGE PinDataRangePointersStreamLegacy
[] =
367 PKSDATARANGE(&PinDataRangesStreamLegacy
)
370 PKSDATARANGE PinDataRangePointersStreamDMusic
[] =
372 PKSDATARANGE(&PinDataRangesStreamDMusic
)
375 PKSDATARANGE PinDataRangePointersStreamCombined
[] =
377 PKSDATARANGE(&PinDataRangesStreamLegacy
)
378 ,PKSDATARANGE(&PinDataRangesStreamDMusic
)
381 /*****************************************************************************
382 * PinDataRangesBridge
383 *****************************************************************************
384 * Structures indicating range of valid format values for bridge pins.
387 KSDATARANGE PinDataRangesBridge
[] =
395 {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC
)},
396 {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI_BUS
)},
397 {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE
)}
402 /*****************************************************************************
403 * PinDataRangePointersBridge
404 *****************************************************************************
405 * List of pointers to structures indicating range of valid format values
409 PKSDATARANGE PinDataRangePointersBridge
[] =
411 &PinDataRangesBridge
[0]
414 /*****************************************************************************
416 *****************************************************************************
417 * List of properties in the Synth set.
423 // Global: S/Get synthesizer caps
426 KSPROPERTY_SYNTH_CAPS
,
427 KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_BASICSUPPORT
,
428 PropertyHandler_Synth
430 // Global: S/Get port parameters
433 KSPROPERTY_SYNTH_PORTPARAMETERS
,
434 KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_BASICSUPPORT
,
435 PropertyHandler_Synth
437 // Per stream: S/Get channel groups
440 KSPROPERTY_SYNTH_CHANNELGROUPS
,
441 KSPROPERTY_TYPE_SET
| KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_BASICSUPPORT
,
442 PropertyHandler_Synth
444 // Per stream: Get current latency time
447 KSPROPERTY_SYNTH_LATENCYCLOCK
,
448 KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_BASICSUPPORT
,
449 PropertyHandler_Synth
452 DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth
, SynthProperties
);
453 DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth2
, SynthProperties
);
455 #define kMaxNumCaptureStreams 1
456 #define kMaxNumLegacyRenderStreams 1
457 #define kMaxNumDMusicRenderStreams 1
459 /*****************************************************************************
461 *****************************************************************************
465 PCPIN_DESCRIPTOR MiniportPins
[] =
468 kMaxNumLegacyRenderStreams
,kMaxNumLegacyRenderStreams
,0, // InstanceCount
469 NULL
, // AutomationTable
471 0, // InterfacesCount
475 SIZEOF_ARRAY(PinDataRangePointersStreamLegacy
), // DataRangesCount
476 PinDataRangePointersStreamLegacy
, // DataRanges
477 KSPIN_DATAFLOW_IN
, // DataFlow
478 KSPIN_COMMUNICATION_SINK
, // Communication
479 (GUID
*) &KSCATEGORY_AUDIO
, // Category
480 &KSAUDFNAME_MIDI
, // Name
485 kMaxNumDMusicRenderStreams
,kMaxNumDMusicRenderStreams
,0, // InstanceCount
486 NULL
, // AutomationTable
488 0, // InterfacesCount
492 SIZEOF_ARRAY(PinDataRangePointersStreamDMusic
), // DataRangesCount
493 PinDataRangePointersStreamDMusic
, // DataRanges
494 KSPIN_DATAFLOW_IN
, // DataFlow
495 KSPIN_COMMUNICATION_SINK
, // Communication
496 (GUID
*) &KSCATEGORY_AUDIO
, // Category
497 &KSAUDFNAME_DMUSIC_MPU_OUT
, // Name
502 0,0,0, // InstanceCount
503 NULL
, // AutomationTable
505 0, // InterfacesCount
509 SIZEOF_ARRAY(PinDataRangePointersBridge
), // DataRangesCount
510 PinDataRangePointersBridge
, // DataRanges
511 KSPIN_DATAFLOW_OUT
, // DataFlow
512 KSPIN_COMMUNICATION_NONE
, // Communication
513 (GUID
*) &KSCATEGORY_AUDIO
, // Category
519 0,0,0, // InstanceCount
520 NULL
, // AutomationTable
522 0, // InterfacesCount
526 SIZEOF_ARRAY(PinDataRangePointersBridge
), // DataRangesCount
527 PinDataRangePointersBridge
, // DataRanges
528 KSPIN_DATAFLOW_IN
, // DataFlow
529 KSPIN_COMMUNICATION_NONE
, // Communication
530 (GUID
*) &KSCATEGORY_AUDIO
, // Category
536 kMaxNumCaptureStreams
,kMaxNumCaptureStreams
,0, // InstanceCount
537 NULL
, // AutomationTable
539 0, // InterfacesCount
543 SIZEOF_ARRAY(PinDataRangePointersStreamCombined
), // DataRangesCount
544 PinDataRangePointersStreamCombined
, // DataRanges
545 KSPIN_DATAFLOW_OUT
, // DataFlow
546 KSPIN_COMMUNICATION_SINK
, // Communication
547 (GUID
*) &KSCATEGORY_AUDIO
, // Category
548 &KSAUDFNAME_DMUSIC_MPU_IN
, // Name
554 /*****************************************************************************
556 *****************************************************************************
559 #define CONST_PCNODE_DESCRIPTOR(n) { 0, NULL, &n, NULL }
560 #define CONST_PCNODE_DESCRIPTOR_AUTO(n,a) { 0, &a, &n, NULL }
562 PCNODE_DESCRIPTOR MiniportNodes
[] =
564 CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER
, AutomationSynth
)
565 , CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER
, AutomationSynth2
)
568 /*****************************************************************************
569 * MiniportConnections
570 *****************************************************************************
571 * List of connections.
579 eFilterInputPinLeg
= 0,
587 PCCONNECTION_DESCRIPTOR MiniportConnections
[] =
590 { PCFILTER_NODE
, eFilterInputPinLeg
, PCFILTER_NODE
, eBridgeOutputPin
} // Legacy Stream in to synth.
591 , { PCFILTER_NODE
, eFilterInputPinDM
, eSynthNode
, KSNODEPIN_STANDARD_IN
} // DM Stream in to synth.
592 , { eSynthNode
, KSNODEPIN_STANDARD_OUT
, PCFILTER_NODE
, eBridgeOutputPin
} // Synth to bridge out.
593 , { PCFILTER_NODE
, eBridgeInputPin
, eInputNode
, KSNODEPIN_STANDARD_IN
} // Bridge in to input.
594 , { eInputNode
, KSNODEPIN_STANDARD_OUT
, PCFILTER_NODE
, eFilterOutputPin
} // Input to DM/Legacy Stream out.
597 /*****************************************************************************
599 *****************************************************************************
600 * List of categories.
603 GUID MiniportCategories
[] =
605 {STATICGUIDOF(KSCATEGORY_AUDIO
)},
606 {STATICGUIDOF(KSCATEGORY_RENDER
)},
607 {STATICGUIDOF(KSCATEGORY_CAPTURE
)}
610 /*****************************************************************************
611 * MiniportFilterDescriptor
612 *****************************************************************************
613 * Complete miniport filter description.
616 PCFILTER_DESCRIPTOR MiniportFilterDescriptor
=
619 NULL
, // AutomationTable
620 sizeof(PCPIN_DESCRIPTOR
), // PinSize
621 SIZEOF_ARRAY(MiniportPins
), // PinCount
622 MiniportPins
, // Pins
623 sizeof(PCNODE_DESCRIPTOR
), // NodeSize
624 SIZEOF_ARRAY(MiniportNodes
), // NodeCount
625 MiniportNodes
, // Nodes
626 SIZEOF_ARRAY(MiniportConnections
), // ConnectionCount
627 MiniportConnections
, // Connections
628 SIZEOF_ARRAY(MiniportCategories
), // CategoryCount
629 MiniportCategories
// Categories
633 #pragma code_seg("PAGE")
636 BOOLEAN
TryMPU(IN PUCHAR PortBase
);
637 NTSTATUS
WriteMPU(IN PUCHAR PortBase
,IN BOOLEAN IsCommand
,IN UCHAR Value
);
640 #pragma code_seg("PAGE")
643 // make sure we're in UART mode
644 NTSTATUS
ResetHardware(PUCHAR portBase
)
648 return WriteMPU(portBase
,COMMAND
,MPU401_CMD_UART
);
652 #pragma code_seg("PAGE")
656 // We initialize the UART with interrupts suppressed so we don't
657 // try to service the chip prematurely.
659 NTSTATUS
CMiniportDMusUART::InitializeHardware(PINTERRUPTSYNC interruptSync
,PUCHAR portBase
)
666 ntStatus
= interruptSync
->CallSynchronizedRoutine(InitMPU
,PVOID(portBase
));
670 ntStatus
= InitMPU(NULL
,PVOID(portBase
));
673 if (NT_SUCCESS(ntStatus
))
676 // Start the UART (this should trigger an interrupt).
678 ntStatus
= ResetHardware(portBase
);
682 DPRINT("*** InitMPU returned with ntStatus 0x%08x ***", ntStatus
);
685 m_fMPUInitialized
= NT_SUCCESS(ntStatus
);
694 /*****************************************************************************
696 *****************************************************************************
697 * Synchronized routine to initialize the MPU401.
703 IN PINTERRUPTSYNC InterruptSync
,
704 IN PVOID DynamicContext
710 return STATUS_INVALID_PARAMETER_2
;
713 PUCHAR portBase
= PUCHAR(DynamicContext
);
717 NTSTATUS ntStatus
= STATUS_SUCCESS
;
720 // Reset the card (puts it into "smart mode")
722 ntStatus
= WriteMPU(portBase
,COMMAND
,MPU401_CMD_RESET
);
724 // wait for the acknowledgement
725 // NOTE: When the Ack arrives, it will trigger an interrupt.
726 // Normally the DPC routine would read in the ack byte and we
727 // would never see it, however since we have the hardware locked (HwEnter),
728 // we can read the port before the DPC can and thus we receive the Ack.
729 startTime
= PcGetTimeInterval(0);
731 while(PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
733 status
= READ_PORT_UCHAR(portBase
+ MPU401_REG_STATUS
);
735 if (UartFifoOkForRead(status
)) // Is data waiting?
737 READ_PORT_UCHAR(portBase
+ MPU401_REG_DATA
); // yep.. read ACK
738 success
= TRUE
; // don't need to do more
741 KeStallExecutionProcessor(25); // microseconds
746 DPRINT("First attempt to reset the MPU didn't get ACKed.\n");
750 // NOTE: We cannot check the ACK byte because if the card was already in
751 // UART mode it will not send an ACK but it will reset.
753 // reset the card again
754 (void) WriteMPU(portBase
,COMMAND
,MPU401_CMD_RESET
);
756 // wait for ack (again)
757 startTime
= PcGetTimeInterval(0); // This might take a while
760 while (PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
762 status
= READ_PORT_UCHAR(portBase
+ MPU401_REG_STATUS
);
763 if (UartFifoOkForRead(status
)) // Is data waiting?
765 dataByte
= READ_PORT_UCHAR(portBase
+ MPU401_REG_DATA
); // yep.. read ACK
766 success
= TRUE
; // don't need to do more
769 KeStallExecutionProcessor(25);
772 if ((0xFE != dataByte
) || !success
) // Did we succeed? If no second ACK, something is hosed
774 DPRINT("Second attempt to reset the MPU didn't get ACKed.\n");
775 DPRINT("Init Reset failure error. Ack = %X", ULONG(dataByte
));
777 ntStatus
= STATUS_IO_DEVICE_ERROR
;
787 /*****************************************************************************
788 * CMiniportDMusUARTStream::Write()
789 *****************************************************************************
790 * Writes outgoing MIDI data.
792 STDMETHODIMP_(NTSTATUS
)
793 CMiniportDMusUARTStream::
796 IN PVOID BufferAddress
,
798 OUT PULONG BytesWritten
802 ASSERT(BytesWritten
);
808 NTSTATUS ntStatus
= STATUS_SUCCESS
;
816 pMidiData
= PUCHAR(BufferAddress
);
820 SYNCWRITECONTEXT context
;
821 context
.Miniport
= (m_pMiniport
);
822 context
.PortBase
= m_pPortBase
;
823 context
.BufferAddress
= pMidiData
;
824 context
.Length
= Length
;
825 context
.BytesRead
= &count
;
827 if (m_pMiniport
->m_UseIRQ
)
829 ntStatus
= m_pMiniport
->m_pInterruptSync
->
830 CallSynchronizedRoutine(SynchronizedDMusMPUWrite
,PVOID(&context
));
834 ntStatus
= SynchronizedDMusMPUWrite(NULL
,PVOID(&context
));
839 m_NumFailedMPUTries
++;
840 if (m_NumFailedMPUTries
>= 100)
842 ntStatus
= STATUS_IO_DEVICE_ERROR
;
843 m_NumFailedMPUTries
= 0;
848 m_NumFailedMPUTries
= 0;
850 } // if we have data at all
851 *BytesWritten
= count
;
853 else // called write on the read stream
855 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
864 /*****************************************************************************
865 * SynchronizedDMusMPUWrite()
866 *****************************************************************************
867 * Writes outgoing MIDI data.
871 SynchronizedDMusMPUWrite
873 IN PINTERRUPTSYNC InterruptSync
,
874 IN PVOID syncWriteContext
877 PSYNCWRITECONTEXT context
;
878 context
= (PSYNCWRITECONTEXT
)syncWriteContext
;
879 ASSERT(context
->Miniport
);
880 ASSERT(context
->PortBase
);
881 ASSERT(context
->BufferAddress
);
882 ASSERT(context
->Length
);
883 ASSERT(context
->BytesRead
);
885 PUCHAR pChar
= PUCHAR(context
->BufferAddress
);
886 NTSTATUS ntStatus
; // , readStatus
887 ntStatus
= STATUS_SUCCESS
;
889 // while we're not there yet, and
890 // while we don't have to wait on an aligned byte (including 0)
891 // (we never wait on a byte. Better to come back later)
892 /*readStatus = */ DMusMPUInterruptServiceRoutine(InterruptSync
,PVOID(context
->Miniport
));
893 while ( (*(context
->BytesRead
) < context
->Length
)
894 && ( TryMPU(context
->PortBase
)
895 || (*(context
->BytesRead
)%3)
898 ntStatus
= WriteMPU(context
->PortBase
,DATA
,*pChar
);
899 if (NT_SUCCESS(ntStatus
))
902 *(context
->BytesRead
) = *(context
->BytesRead
) + 1;
903 // readStatus = DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport));
907 DPRINT("SynchronizedDMusMPUWrite failed (0x%08x)",ntStatus
);
911 /*readStatus = */ DMusMPUInterruptServiceRoutine(InterruptSync
,PVOID(context
->Miniport
));
915 #define kMPUPollTimeout 2
921 /*****************************************************************************
923 *****************************************************************************
924 * See if the MPU401 is free.
939 while (numPolls
< kMPUPollTimeout
)
941 status
= READ_PORT_UCHAR(PortBase
+ MPU401_REG_STATUS
);
943 if (UartFifoOkForWrite(status
)) // Is this a good time to write data?
949 if (numPolls
>= kMPUPollTimeout
)
952 DPRINT("TryMPU failed");
966 /*****************************************************************************
968 *****************************************************************************
969 * Write a byte out to the MPU401.
975 IN BOOLEAN IsCommand
,
980 NTSTATUS ntStatus
= STATUS_IO_DEVICE_ERROR
;
984 DPRINT("O: PortBase is zero\n");
987 PUCHAR deviceAddr
= PortBase
+ MPU401_REG_DATA
;
991 deviceAddr
= PortBase
+ MPU401_REG_COMMAND
;
994 ULONGLONG startTime
= PcGetTimeInterval(0);
996 while (PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
999 = READ_PORT_UCHAR(PortBase
+ MPU401_REG_STATUS
);
1001 if (UartFifoOkForWrite(status
)) // Is this a good time to write data?
1002 { // yep (Jon comment)
1003 WRITE_PORT_UCHAR(deviceAddr
,Value
);
1004 DPRINT("WriteMPU emitted 0x%02x",Value
);
1005 ntStatus
= STATUS_SUCCESS
;
1016 /*****************************************************************************
1018 *****************************************************************************
1020 * At synchronized execution to ISR, copy miniport's volatile m_InputTimeStamp
1021 * to stream's m_SnapshotTimeStamp and zero m_InputTimeStamp.
1024 STDMETHODIMP_(NTSTATUS
)
1025 SnapTimeStamp(PINTERRUPTSYNC InterruptSync
,PVOID pStream
)
1027 CMiniportDMusUARTStream
*pMPStream
= (CMiniportDMusUARTStream
*)pStream
;
1029 // cache the timestamp
1030 pMPStream
->m_SnapshotTimeStamp
= pMPStream
->m_pMiniport
->m_InputTimeStamp
;
1032 // if the window is closed, zero the timestamp
1033 if (pMPStream
->m_pMiniport
->m_MPUInputBufferHead
==
1034 pMPStream
->m_pMiniport
->m_MPUInputBufferTail
)
1036 pMPStream
->m_pMiniport
->m_InputTimeStamp
= 0;
1039 return STATUS_SUCCESS
;
1042 /*****************************************************************************
1043 * CMiniportDMusUARTStream::SourceEvtsToPort()
1044 *****************************************************************************
1046 * Reads incoming MIDI data, feeds into DMus events.
1047 * No need to touch the hardware, just read from our SW FIFO.
1050 STDMETHODIMP_(NTSTATUS
)
1051 CMiniportDMusUARTStream::SourceEvtsToPort()
1055 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1056 DPRINT("SourceEvtsToPort");
1060 ntStatus
= STATUS_SUCCESS
;
1061 if (m_pMiniport
->m_MPUInputBufferHead
!= m_pMiniport
->m_MPUInputBufferTail
)
1063 PDMUS_KERNEL_EVENT aDMKEvt
,eventTail
,eventHead
= NULL
;
1065 while (m_pMiniport
->m_MPUInputBufferHead
!= m_pMiniport
->m_MPUInputBufferTail
)
1067 (void) m_AllocatorMXF
->GetMessage(&aDMKEvt
);
1070 DPRINT("SourceEvtsToPort can't allocate DMKEvt");
1071 return STATUS_INSUFFICIENT_RESOURCES
;
1074 // put this event at the end of the list
1077 eventHead
= aDMKEvt
;
1081 eventTail
= eventHead
;
1082 while (eventTail
->pNextEvt
)
1084 eventTail
= eventTail
->pNextEvt
;
1086 eventTail
->pNextEvt
= aDMKEvt
;
1088 // read all the bytes out of the buffer, into event(s)
1089 for (aDMKEvt
->cbEvent
= 0; aDMKEvt
->cbEvent
< sizeof(PBYTE
); aDMKEvt
->cbEvent
++)
1091 if (m_pMiniport
->m_MPUInputBufferHead
== m_pMiniport
->m_MPUInputBufferTail
)
1093 // _DbgPrintF(DEBUGLVL_TERSE, ("SourceEvtsToPort m_MPUInputBufferHead met m_MPUInputBufferTail, overrun"));
1096 aDMKEvt
->uData
.abData
[aDMKEvt
->cbEvent
] = m_pMiniport
->m_MPUInputBuffer
[m_pMiniport
->m_MPUInputBufferHead
];
1097 m_pMiniport
->m_MPUInputBufferHead
++;
1098 if (m_pMiniport
->m_MPUInputBufferHead
>= kMPUInputBufferSize
)
1100 m_pMiniport
->m_MPUInputBufferHead
= 0;
1105 if (m_pMiniport
->m_UseIRQ
)
1107 ntStatus
= m_pMiniport
->m_pInterruptSync
->CallSynchronizedRoutine(SnapTimeStamp
,PVOID(this));
1111 ntStatus
= SnapTimeStamp(NULL
,PVOID(this));
1113 aDMKEvt
= eventHead
;
1116 aDMKEvt
->ullPresTime100ns
= m_SnapshotTimeStamp
;
1117 aDMKEvt
->usChannelGroup
= 1;
1118 aDMKEvt
->usFlags
= DMUS_KEF_EVENT_INCOMPLETE
;
1119 aDMKEvt
= aDMKEvt
->pNextEvt
;
1121 (void)m_sinkMXF
->PutMessage(eventHead
);
1124 else // render stream
1126 DPRINT("SourceEvtsToPort called on render stream");
1127 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
1136 /*****************************************************************************
1137 * DMusMPUInterruptServiceRoutine()
1138 *****************************************************************************
1143 DMusMPUInterruptServiceRoutine
1145 IN PINTERRUPTSYNC InterruptSync
,
1146 IN PVOID DynamicContext
1149 DPRINT("DMusMPUInterruptServiceRoutine");
1150 ULONGLONG startTime
;
1152 ASSERT(DynamicContext
);
1155 BOOL newBytesAvailable
;
1156 CMiniportDMusUART
*that
;
1157 NTSTATUS clockStatus
;
1159 that
= (CMiniportDMusUART
*) DynamicContext
;
1160 newBytesAvailable
= FALSE
;
1161 ntStatus
= STATUS_UNSUCCESSFUL
;
1163 UCHAR portStatus
= 0xff;
1166 // Read the MPU status byte.
1168 if (that
->m_pPortBase
)
1171 READ_PORT_UCHAR(that
->m_pPortBase
+ MPU401_REG_STATUS
);
1174 // If there is outstanding work to do and there is a port-driver for
1175 // the MPU miniport...
1177 if (UartFifoOkForRead(portStatus
) && that
->m_pPort
)
1179 startTime
= PcGetTimeInterval(0);
1180 while ( (PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
1181 && (UartFifoOkForRead(portStatus
)) )
1183 UCHAR uDest
= READ_PORT_UCHAR(that
->m_pPortBase
+ MPU401_REG_DATA
);
1184 if ( (that
->m_KSStateInput
== KSSTATE_RUN
)
1185 && (that
->m_NumCaptureStreams
)
1188 ULONG buffHead
= that
->m_MPUInputBufferHead
;
1189 if ( (that
->m_MPUInputBufferTail
+ 1 == buffHead
)
1190 || (that
->m_MPUInputBufferTail
+ 1 - kMPUInputBufferSize
== buffHead
))
1192 DPRINT("*****MPU Input Buffer Overflow*****");
1196 if (!that
->m_InputTimeStamp
)
1198 clockStatus
= that
->m_MasterClock
->GetTime(&that
->m_InputTimeStamp
);
1199 if (STATUS_SUCCESS
!= clockStatus
)
1201 DPRINT("GetTime failed for clock 0x%08x",that
->m_MasterClock
);
1204 newBytesAvailable
= TRUE
;
1205 // ...place the data in our FIFO...
1206 that
->m_MPUInputBuffer
[that
->m_MPUInputBufferTail
] = uDest
;
1207 ASSERT(that
->m_MPUInputBufferTail
< kMPUInputBufferSize
);
1209 that
->m_MPUInputBufferTail
++;
1210 if (that
->m_MPUInputBufferTail
>= kMPUInputBufferSize
)
1212 that
->m_MPUInputBufferTail
= 0;
1217 // Look for more MIDI data.
1220 READ_PORT_UCHAR(that
->m_pPortBase
+ MPU401_REG_STATUS
);
1221 } // either there's no data or we ran too long
1222 if (newBytesAvailable
)
1225 // ...notify the MPU port driver that we have bytes.
1227 that
->m_pPort
->Notify(that
->m_pServiceGroup
);
1229 ntStatus
= STATUS_SUCCESS
;
1236 /*****************************************************************************
1237 * CMiniportDMusUART::GetDescription()
1238 *****************************************************************************
1239 * Gets the topology.
1241 STDMETHODIMP_(NTSTATUS
)
1245 OUT PPCFILTER_DESCRIPTOR
* OutFilterDescriptor
1250 ASSERT(OutFilterDescriptor
);
1252 DPRINT("GetDescription");
1254 *OutFilterDescriptor
= &MiniportFilterDescriptor
;
1256 return STATUS_SUCCESS
;
1260 #pragma code_seg("PAGE")
1264 NewMiniportDMusUART(
1265 OUT PMINIPORT
* OutMiniport
,
1266 IN REFCLSID ClassId
)
1268 CMiniportDMusUART
* This
;
1271 This
= new(NonPagedPool
, TAG_PORTCLASS
) CMiniportDMusUART(NULL
);
1273 return STATUS_INSUFFICIENT_RESOURCES
;
1275 Status
= This
->QueryInterface(IID_IMiniport
, (PVOID
*)OutMiniport
);
1277 if (!NT_SUCCESS(Status
))
1282 DPRINT("NewMiniportDMusUART %p Status %x\n", *OutMiniport
, Status
);
1288 #pragma code_seg("PAGE")
1291 /*****************************************************************************
1292 * CMiniportDMusUART::ProcessResources()
1293 *****************************************************************************
1294 * Processes the resource list, setting up helper objects accordingly.
1300 IN PRESOURCELIST ResourceList
1305 DPRINT("ProcessResources");
1307 ASSERT(ResourceList
);
1310 return STATUS_DEVICE_CONFIGURATION_ERROR
;
1313 // Get counts for the types of resources.
1315 ULONG countIO
= ResourceList
->NumberOfPorts();
1316 ULONG countIRQ
= ResourceList
->NumberOfInterrupts();
1317 ULONG countDMA
= ResourceList
->NumberOfDmas();
1318 ULONG lengthIO
= ResourceList
->FindTranslatedPort(0)->u
.Port
.Length
;
1321 DPRINT("Starting MPU401 Port 0x%lx", ResourceList
->FindTranslatedPort(0)->u
.Port
.Start
.LowPart
);
1324 NTSTATUS ntStatus
= STATUS_SUCCESS
;
1327 // Make sure we have the expected number of resources.
1335 DPRINT("Unknown ResourceList configuration");
1336 ntStatus
= STATUS_DEVICE_CONFIGURATION_ERROR
;
1339 if (NT_SUCCESS(ntStatus
))
1342 // Get the port address.
1345 PUCHAR(ResourceList
->FindTranslatedPort(0)->u
.Port
.Start
.QuadPart
);
1347 ntStatus
= InitializeHardware(m_pInterruptSync
,m_pPortBase
);
1354 #pragma code_seg("PAGE")
1356 /*****************************************************************************
1357 * CMiniportDMusUART::NonDelegatingQueryInterface()
1358 *****************************************************************************
1359 * Obtains an interface. This function works just like a COM QueryInterface
1360 * call and is used if the object is not being aggregated.
1362 STDMETHODIMP_(NTSTATUS
)
1363 CMiniportDMusUART::QueryInterface
1371 DPRINT("Miniport::NonDelegatingQueryInterface");
1374 if (IsEqualGUIDAligned(Interface
,IID_IUnknown
))
1376 *Object
= PVOID(PUNKNOWN(PMINIPORTDMUS(this)));
1379 if (IsEqualGUIDAligned(Interface
,IID_IMiniport
))
1381 *Object
= PVOID(PMINIPORT(this));
1384 if (IsEqualGUIDAligned(Interface
,IID_IMiniportDMus
))
1386 *Object
= PVOID(PMINIPORTDMUS(this));
1389 if (IsEqualGUIDAligned(Interface
,IID_IMusicTechnology
))
1391 *Object
= PVOID(PMUSICTECHNOLOGY(this));
1394 if (IsEqualGUIDAligned(Interface
,IID_IPowerNotify
))
1396 *Object
= PVOID(PPOWERNOTIFY(this));
1406 // We reference the interface for the caller.
1408 PUNKNOWN(*Object
)->AddRef();
1409 return STATUS_SUCCESS
;
1412 return STATUS_INVALID_PARAMETER
;
1416 #pragma code_seg("PAGE")
1418 /*****************************************************************************
1419 * CMiniportDMusUART::~CMiniportDMusUART()
1420 *****************************************************************************
1423 CMiniportDMusUART::~CMiniportDMusUART(void)
1427 DPRINT("~CMiniportDMusUART");
1429 ASSERT(0 == m_NumCaptureStreams
);
1430 ASSERT(0 == m_NumRenderStreams
);
1432 // reset the HW so we don't get anymore interrupts
1433 if (m_UseIRQ
&& m_pInterruptSync
)
1435 (void) m_pInterruptSync
->CallSynchronizedRoutine((PINTERRUPTSYNCROUTINE
)InitMPU
,PVOID(m_pPortBase
));
1439 (void) InitMPU(NULL
,PVOID(m_pPortBase
));
1442 if (m_pInterruptSync
)
1444 m_pInterruptSync
->Release();
1445 m_pInterruptSync
= NULL
;
1447 if (m_pServiceGroup
)
1449 m_pServiceGroup
->Release();
1450 m_pServiceGroup
= NULL
;
1460 #pragma code_seg("PAGE")
1462 /*****************************************************************************
1463 * CMiniportDMusUART::Init()
1464 *****************************************************************************
1465 * Initializes a the miniport.
1467 STDMETHODIMP_(NTSTATUS
)
1471 IN PUNKNOWN UnknownInterruptSync OPTIONAL
,
1472 IN PRESOURCELIST ResourceList
,
1474 OUT PSERVICEGROUP
* ServiceGroup
1479 ASSERT(ResourceList
);
1482 return STATUS_DEVICE_CONFIGURATION_ERROR
;
1486 ASSERT(ServiceGroup
);
1490 *ServiceGroup
= NULL
;
1492 m_fMPUInitialized
= FALSE
;
1494 // This will remain unspecified if the miniport does not get any power
1497 m_PowerState
.DeviceState
= PowerDeviceUnspecified
;
1500 // AddRef() is required because we are keeping this pointer.
1507 if (IsEqualGUIDAligned(m_MusicFormatTechnology
, GUID_NULL
))
1509 RtlCopyMemory( &m_MusicFormatTechnology
,
1510 &KSMUSIC_TECHNOLOGY_PORT
,
1513 RtlCopyMemory( &PinDataRangesStreamLegacy
.Technology
,
1514 &m_MusicFormatTechnology
,
1516 RtlCopyMemory( &PinDataRangesStreamDMusic
.Technology
,
1517 &m_MusicFormatTechnology
,
1520 for (ULONG bufferCount
= 0;bufferCount
< kMPUInputBufferSize
;bufferCount
++)
1522 m_MPUInputBuffer
[bufferCount
] = 0;
1524 m_MPUInputBufferHead
= 0;
1525 m_MPUInputBufferTail
= 0;
1526 m_InputTimeStamp
= 0;
1527 m_KSStateInput
= KSSTATE_STOP
;
1529 NTSTATUS ntStatus
= STATUS_SUCCESS
;
1531 m_NumRenderStreams
= 0;
1532 m_NumCaptureStreams
= 0;
1535 if (ResourceList
->NumberOfInterrupts() == 0)
1540 ntStatus
= PcNewServiceGroup(&m_pServiceGroup
,NULL
);
1541 if (NT_SUCCESS(ntStatus
) && !m_pServiceGroup
) // keep any error
1543 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1546 if (NT_SUCCESS(ntStatus
))
1548 *ServiceGroup
= m_pServiceGroup
;
1549 m_pServiceGroup
->AddRef();
1552 // Register the service group with the port early so the port is
1553 // prepared to handle interrupts.
1555 m_pPort
->RegisterServiceGroup(m_pServiceGroup
);
1558 if (NT_SUCCESS(ntStatus
) && m_UseIRQ
)
1561 // Due to a bug in the InterruptSync design, we shouldn't share
1562 // the interrupt sync object. Whoever goes away first
1563 // will disconnect it, and the other points off into nowhere.
1565 // Instead we generate our own interrupt sync object.
1567 UnknownInterruptSync
= NULL
;
1569 if (UnknownInterruptSync
)
1572 UnknownInterruptSync
->QueryInterface
1575 (PVOID
*) &m_pInterruptSync
1578 if (!m_pInterruptSync
&& NT_SUCCESS(ntStatus
)) // keep any error
1580 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1582 if (NT_SUCCESS(ntStatus
))
1583 { // run this ISR first
1584 ntStatus
= m_pInterruptSync
->
1585 RegisterServiceRoutine(DMusMPUInterruptServiceRoutine
,PVOID(this),TRUE
);
1590 { // create our own interruptsync mechanism.
1597 0, // Resource Index
1598 InterruptSyncModeNormal
// Run ISRs once until we get SUCCESS
1601 if (!m_pInterruptSync
&& NT_SUCCESS(ntStatus
)) // keep any error
1603 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1606 if (NT_SUCCESS(ntStatus
))
1608 ntStatus
= m_pInterruptSync
->RegisterServiceRoutine(
1609 DMusMPUInterruptServiceRoutine
,
1611 TRUE
); // run this ISR first
1613 if (NT_SUCCESS(ntStatus
))
1615 ntStatus
= m_pInterruptSync
->Connect();
1620 if (NT_SUCCESS(ntStatus
))
1622 ntStatus
= ProcessResources(ResourceList
);
1625 if (!NT_SUCCESS(ntStatus
))
1628 // clean up our mess
1631 // clean up the interrupt sync
1632 if( m_pInterruptSync
)
1634 m_pInterruptSync
->Release();
1635 m_pInterruptSync
= NULL
;
1638 // clean up the service group
1639 if( m_pServiceGroup
)
1641 m_pServiceGroup
->Release();
1642 m_pServiceGroup
= NULL
;
1645 // clean up the out param service group.
1648 (*ServiceGroup
)->Release();
1649 (*ServiceGroup
) = NULL
;
1661 #pragma code_seg("PAGE")
1663 /*****************************************************************************
1664 * CMiniportDMusUART::NewStream()
1665 *****************************************************************************
1666 * Gets the topology.
1668 STDMETHODIMP_(NTSTATUS
)
1673 IN PUNKNOWN OuterUnknown OPTIONAL
,
1674 IN POOL_TYPE PoolType
,
1676 IN DMUS_STREAM_TYPE StreamType
,
1677 IN PKSDATAFORMAT DataFormat
,
1678 OUT PSERVICEGROUP
* ServiceGroup
,
1679 IN PAllocatorMXF AllocatorMXF
,
1680 IN PMASTERCLOCK MasterClock
,
1681 OUT PULONGLONG SchedulePreFetch
1686 DPRINT("NewStream");
1687 NTSTATUS ntStatus
= STATUS_SUCCESS
;
1689 // In 100 ns, we want stuff as soon as it comes in
1691 *SchedulePreFetch
= 0;
1693 // if we don't have any streams already open, get the hardware ready.
1694 if ((!m_NumCaptureStreams
) && (!m_NumRenderStreams
))
1696 ntStatus
= ResetHardware(m_pPortBase
);
1697 if (!NT_SUCCESS(ntStatus
))
1699 DPRINT("CMiniportDMusUART::NewStream ResetHardware failed");
1704 if ( ((m_NumCaptureStreams
< kMaxNumCaptureStreams
)
1705 && (StreamType
== DMUS_STREAM_MIDI_CAPTURE
))
1706 || ((m_NumRenderStreams
< kMaxNumLegacyRenderStreams
+ kMaxNumDMusicRenderStreams
)
1707 && (StreamType
== DMUS_STREAM_MIDI_RENDER
))
1710 CMiniportDMusUARTStream
*pStream
=
1711 new(PoolType
) CMiniportDMusUARTStream();
1718 pStream
->Init(this,m_pPortBase
,(StreamType
== DMUS_STREAM_MIDI_CAPTURE
),AllocatorMXF
,MasterClock
);
1720 if (NT_SUCCESS(ntStatus
))
1722 *MXF
= PMXF(pStream
);
1725 if (StreamType
== DMUS_STREAM_MIDI_CAPTURE
)
1727 m_NumCaptureStreams
++;
1728 *ServiceGroup
= m_pServiceGroup
;
1729 (*ServiceGroup
)->AddRef();
1733 m_NumRenderStreams
++;
1734 *ServiceGroup
= NULL
;
1742 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1747 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
1748 if (StreamType
== DMUS_STREAM_MIDI_CAPTURE
)
1750 DPRINT("NewStream failed, too many capture streams");
1752 else if (StreamType
== DMUS_STREAM_MIDI_RENDER
)
1754 DPRINT("NewStream failed, too many render streams");
1758 DPRINT("NewStream invalid stream type");
1766 #pragma code_seg("PAGE")
1768 /*****************************************************************************
1769 * CMiniportDMusUART::SetTechnology()
1770 *****************************************************************************
1771 * Sets pindatarange technology.
1773 STDMETHODIMP_(NTSTATUS
)
1777 IN
const GUID
* Technology
1782 NTSTATUS ntStatus
= STATUS_UNSUCCESSFUL
;
1784 // Fail if miniport has already been initialized.
1786 if (NULL
== m_pPort
)
1788 RtlCopyMemory(&m_MusicFormatTechnology
, Technology
, sizeof(GUID
));
1789 ntStatus
= STATUS_SUCCESS
;
1795 /*****************************************************************************
1796 * CMiniportDMusUART::PowerChangeNotify()
1797 *****************************************************************************
1798 * Handle power state change for the miniport.
1801 #pragma code_seg("PAGE")
1808 IN POWER_STATE PowerState
1813 DPRINT("CMiniportDMusUART::PoweChangeNotify D%d", PowerState
.DeviceState
);
1815 switch (PowerState
.DeviceState
)
1818 if (m_PowerState
.DeviceState
!= PowerDeviceD0
)
1820 if (!NT_SUCCESS(InitializeHardware(m_pInterruptSync
,m_pPortBase
)))
1822 DPRINT("InitializeHardware failed when resuming");
1833 m_PowerState
.DeviceState
= PowerState
.DeviceState
;
1834 } // PowerChangeNotify
1837 #pragma code_seg("PAGE")
1839 /*****************************************************************************
1840 * CMiniportDMusUARTStream::NonDelegatingQueryInterface()
1841 *****************************************************************************
1842 * Obtains an interface. This function works just like a COM QueryInterface
1843 * call and is used if the object is not being aggregated.
1845 STDMETHODIMP_(NTSTATUS
)
1846 CMiniportDMusUARTStream::QueryInterface
1854 DPRINT("Stream::NonDelegatingQueryInterface");
1857 if (IsEqualGUIDAligned(Interface
,IID_IUnknown
))
1859 *Object
= PVOID(PUNKNOWN(this));
1862 if (IsEqualGUIDAligned(Interface
,IID_IMXF
))
1864 *Object
= PVOID(PMXF(this));
1874 // We reference the interface for the caller.
1876 PUNKNOWN(*Object
)->AddRef();
1877 return STATUS_SUCCESS
;
1880 return STATUS_INVALID_PARAMETER
;
1884 #pragma code_seg("PAGE")
1886 /*****************************************************************************
1887 * CMiniportDMusUARTStream::~CMiniportDMusUARTStream()
1888 *****************************************************************************
1889 * Destructs a stream.
1891 CMiniportDMusUARTStream::~CMiniportDMusUARTStream(void)
1895 DPRINT("~CMiniportDMusUARTStream");
1897 KeCancelTimer(&m_TimerEvent
);
1903 m_AllocatorMXF
->PutMessage(m_DMKEvtQueue
);
1907 DPRINT("~CMiniportDMusUARTStream, no allocator, can't flush DMKEvts");
1909 m_DMKEvtQueue
= NULL
;
1913 m_AllocatorMXF
->Release();
1914 m_AllocatorMXF
= NULL
;
1921 m_pMiniport
->m_NumCaptureStreams
--;
1925 m_pMiniport
->m_NumRenderStreams
--;
1928 m_pMiniport
->Release();
1933 #pragma code_seg("PAGE")
1935 /*****************************************************************************
1936 * CMiniportDMusUARTStream::Init()
1937 *****************************************************************************
1938 * Initializes a stream.
1940 STDMETHODIMP_(NTSTATUS
)
1941 CMiniportDMusUARTStream::
1944 IN CMiniportDMusUART
* pMiniport
,
1945 IN PUCHAR pPortBase
,
1946 IN BOOLEAN fCapture
,
1947 IN PAllocatorMXF allocatorMXF
,
1948 IN PMASTERCLOCK masterClock
1958 m_NumFailedMPUTries
= 0;
1959 m_TimerQueued
= FALSE
;
1960 KeInitializeSpinLock(&m_DpcSpinLock
);
1961 m_pMiniport
= pMiniport
;
1962 m_pMiniport
->AddRef();
1964 pMiniport
->m_MasterClock
= masterClock
;
1966 m_pPortBase
= pPortBase
;
1967 m_fCapture
= fCapture
;
1969 m_SnapshotTimeStamp
= 0;
1970 m_DMKEvtQueue
= NULL
;
1973 m_NumberOfRetries
= 0;
1977 allocatorMXF
->AddRef();
1978 m_AllocatorMXF
= allocatorMXF
;
1979 m_sinkMXF
= m_AllocatorMXF
;
1983 return STATUS_INVALID_PARAMETER
;
1989 &::DMusUARTTimerDPC
,
1992 KeInitializeTimer(&m_TimerEvent
);
1994 return STATUS_SUCCESS
;
1998 #pragma code_seg("PAGE")
2000 /*****************************************************************************
2001 * CMiniportDMusUARTStream::SetState()
2002 *****************************************************************************
2003 * Sets the state of the channel.
2005 STDMETHODIMP_(NTSTATUS
)
2006 CMiniportDMusUARTStream::
2014 DPRINT("SetState %d",NewState
);
2016 if (NewState
== KSSTATE_RUN
)
2018 if (m_pMiniport
->m_fMPUInitialized
)
2020 LARGE_INTEGER timeDue100ns
;
2021 timeDue100ns
.QuadPart
= 0;
2022 KeSetTimer(&m_TimerEvent
,timeDue100ns
,&m_Dpc
);
2026 DPRINT("CMiniportDMusUARTStream::SetState KSSTATE_RUN failed due to uninitialized MPU");
2027 return STATUS_INVALID_DEVICE_STATE
;
2033 m_pMiniport
->m_KSStateInput
= NewState
;
2034 if (NewState
== KSSTATE_STOP
) // STOPping
2036 m_pMiniport
->m_MPUInputBufferHead
= 0; // Previously read bytes are discarded.
2037 m_pMiniport
->m_MPUInputBufferTail
= 0; // The entire FIFO is available.
2040 return STATUS_SUCCESS
;
2048 /*****************************************************************************
2049 * CMiniportDMusUART::Service()
2050 *****************************************************************************
2051 * DPC-mode service call from the port.
2060 if (!m_NumCaptureStreams
)
2062 // we should never get here....
2063 // if we do, we must have read some trash,
2064 // so just reset the input FIFO
2065 m_MPUInputBufferTail
= m_MPUInputBufferHead
= 0;
2070 #pragma code_seg("PAGE")
2073 /*****************************************************************************
2074 * CMiniportDMusUARTStream::ConnectOutput()
2075 *****************************************************************************
2076 * Writes outgoing MIDI data.
2079 CMiniportDMusUARTStream::
2080 ConnectOutput(PMXF sinkMXF
)
2086 if ((sinkMXF
) && (m_sinkMXF
== m_AllocatorMXF
))
2088 DPRINT("ConnectOutput");
2089 m_sinkMXF
= sinkMXF
;
2090 return STATUS_SUCCESS
;
2094 DPRINT("ConnectOutput failed");
2099 DPRINT("ConnectOutput called on renderer; failed");
2101 return STATUS_UNSUCCESSFUL
;
2105 #pragma code_seg("PAGE")
2108 /*****************************************************************************
2109 * CMiniportDMusUARTStream::DisconnectOutput()
2110 *****************************************************************************
2111 * Writes outgoing MIDI data.
2114 CMiniportDMusUARTStream::
2115 DisconnectOutput(PMXF sinkMXF
)
2121 if ((m_sinkMXF
== sinkMXF
) || (!sinkMXF
))
2123 DPRINT("DisconnectOutput");
2124 m_sinkMXF
= m_AllocatorMXF
;
2125 return STATUS_SUCCESS
;
2129 DPRINT("DisconnectOutput failed");
2134 DPRINT("DisconnectOutput called on renderer; failed");
2136 return STATUS_UNSUCCESSFUL
;
2144 /*****************************************************************************
2145 * CMiniportDMusUARTStream::PutMessageLocked()
2146 *****************************************************************************
2147 * Now that the spinlock is held, add this message to the queue.
2149 * Writes an outgoing MIDI message.
2150 * We don't sort a new message into the queue -- we append it.
2151 * This is fine, since the sequencer feeds us sequenced data.
2152 * Timestamps will ascend by design.
2154 NTSTATUS
CMiniportDMusUARTStream::PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt
)
2156 NTSTATUS ntStatus
= STATUS_SUCCESS
;
2157 PDMUS_KERNEL_EVENT aDMKEvt
;
2159 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
2163 DPRINT("PutMessage to render stream");
2166 // m_DpcSpinLock already held
2170 aDMKEvt
= m_DMKEvtQueue
; // put pDMKEvt in event queue
2172 while (aDMKEvt
->pNextEvt
)
2174 aDMKEvt
= aDMKEvt
->pNextEvt
;
2176 aDMKEvt
->pNextEvt
= pDMKEvt
; // here is end of queue
2178 else // currently nothing in queue
2180 m_DMKEvtQueue
= pDMKEvt
;
2183 DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d",m_DMKEvtOffset
);
2188 // m_DpcSpinLock already held
2192 (void) ConsumeEvents();
2197 DPRINT("PutMessage to capture stream");
2198 ASSERT(NULL
== pDMKEvt
);
2209 /*****************************************************************************
2210 * CMiniportDMusUARTStream::PutMessage()
2211 *****************************************************************************
2212 * Writes an outgoing MIDI message.
2213 * We don't sort a new message into the queue -- we append it.
2214 * This is fine, since the sequencer feeds us sequenced data.
2215 * Timestamps will ascend by design.
2217 NTSTATUS
CMiniportDMusUARTStream::PutMessage(PDMUS_KERNEL_EVENT pDMKEvt
)
2219 NTSTATUS ntStatus
= STATUS_SUCCESS
;
2220 PDMUS_KERNEL_EVENT aDMKEvt
;
2222 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
2226 DPRINT("PutMessage to render stream");
2229 KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock
);
2233 aDMKEvt
= m_DMKEvtQueue
; // put pDMKEvt in event queue
2235 while (aDMKEvt
->pNextEvt
)
2237 aDMKEvt
= aDMKEvt
->pNextEvt
;
2239 aDMKEvt
->pNextEvt
= pDMKEvt
; // here is end of queue
2241 else // currently nothing in queue
2243 m_DMKEvtQueue
= pDMKEvt
;
2246 DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d", m_DMKEvtOffset
);
2251 KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock
);
2255 (void) ConsumeEvents();
2260 DPRINT("PutMessage to capture stream");
2261 ASSERT(NULL
== pDMKEvt
);
2272 /*****************************************************************************
2273 * CMiniportDMusUARTStream::ConsumeEvents()
2274 *****************************************************************************
2275 * Attempts to empty the render message queue.
2276 * Called either from DPC timer or upon IRP submittal.
2277 // TODO: support packages right
2278 // process the package (actually, should do this above.
2279 // treat the package as a list fragment that shouldn't be sorted.
2280 // better yet, go through each event in the package, and when
2281 // an event is exhausted, delete it and decrement m_offset.
2283 NTSTATUS
CMiniportDMusUARTStream::ConsumeEvents(void)
2285 PDMUS_KERNEL_EVENT aDMKEvt
;
2287 NTSTATUS ntStatus
= STATUS_SUCCESS
;
2288 ULONG bytesRemaining
= 0,bytesWritten
= 0;
2289 LARGE_INTEGER aMillisecIn100ns
;
2291 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
2292 KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock
);
2294 m_TimerQueued
= FALSE
;
2295 while (m_DMKEvtQueue
) // do we have anything to play at all?
2297 aDMKEvt
= m_DMKEvtQueue
; // event we try to play
2298 if (aDMKEvt
->cbEvent
)
2300 bytesRemaining
= aDMKEvt
->cbEvent
- m_DMKEvtOffset
; // number of bytes left in this evt
2302 ASSERT(bytesRemaining
> 0);
2303 if (bytesRemaining
<= 0)
2305 bytesRemaining
= aDMKEvt
->cbEvent
;
2308 if (aDMKEvt
->cbEvent
<= sizeof(PBYTE
)) // short message
2310 DPRINT("ConsumeEvents(%02x%02x%02x%02x)", aDMKEvt
->uData
.abData
[0], aDMKEvt
->uData
.abData
[1], aDMKEvt
->uData
.abData
[2], aDMKEvt
->uData
.abData
[3]);
2311 ntStatus
= Write(aDMKEvt
->uData
.abData
+ m_DMKEvtOffset
,bytesRemaining
,&bytesWritten
);
2313 else if (PACKAGE_EVT(aDMKEvt
))
2315 ASSERT(m_DMKEvtOffset
== 0);
2317 DPRINT("ConsumeEvents(Package)");
2319 ntStatus
= PutMessageLocked(aDMKEvt
->uData
.pPackageEvt
); // we already own the spinlock
2321 // null this because we are about to throw it in the allocator
2322 aDMKEvt
->uData
.pPackageEvt
= NULL
;
2323 aDMKEvt
->cbEvent
= 0;
2324 bytesWritten
= bytesRemaining
;
2326 else // SysEx message
2328 DPRINT("ConsumeEvents(%02x%02x%02x%02x)", aDMKEvt
->uData
.pbData
[0], aDMKEvt
->uData
.pbData
[1], aDMKEvt
->uData
.pbData
[2], aDMKEvt
->uData
.pbData
[3]);
2330 ntStatus
= Write(aDMKEvt
->uData
.pbData
+ m_DMKEvtOffset
,bytesRemaining
,&bytesWritten
);
2332 } // if (aDMKEvt->cbEvent)
2333 if (STATUS_SUCCESS
!= ntStatus
)
2335 DPRINT("ConsumeEvents: Write returned 0x%08x", ntStatus
);
2336 bytesWritten
= bytesRemaining
; // just bail on this event and try next time
2339 ASSERT(bytesWritten
<= bytesRemaining
);
2340 if (bytesWritten
== bytesRemaining
)
2342 m_DMKEvtQueue
= m_DMKEvtQueue
->pNextEvt
;
2343 aDMKEvt
->pNextEvt
= NULL
;
2345 m_AllocatorMXF
->PutMessage(aDMKEvt
); // throw back in free pool
2346 m_DMKEvtOffset
= 0; // start fresh on next evt
2347 m_NumberOfRetries
= 0;
2348 } // but wait ... there's more!
2349 else // our FIFO is full for now.
2351 // update our offset by that amount we did write
2352 m_DMKEvtOffset
+= bytesWritten
;
2353 ASSERT(m_DMKEvtOffset
< aDMKEvt
->cbEvent
);
2355 DPRINT("ConsumeEvents tried %d, wrote %d, at offset %d", bytesRemaining
,bytesWritten
,m_DMKEvtOffset
);
2356 aMillisecIn100ns
.QuadPart
= -(kOneMillisec
); // set timer, come back later
2357 m_TimerQueued
= TRUE
;
2358 m_NumberOfRetries
++;
2359 ntStatus
= KeSetTimer( &m_TimerEvent
, aMillisecIn100ns
, &m_Dpc
);
2361 } // we didn't write it all
2362 } // go back, Jack, do it again (while m_DMKEvtQueue)
2363 KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock
);
2371 /*****************************************************************************
2372 * CMiniportDMusUARTStream::HandlePortParams()
2373 *****************************************************************************
2374 * Writes an outgoing MIDI message.
2377 CMiniportDMusUARTStream::
2380 IN PPCPROPERTY_REQUEST pRequest
2387 if (pRequest
->Verb
& KSPROPERTY_TYPE_SET
)
2389 return STATUS_INVALID_DEVICE_REQUEST
;
2392 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(SYNTH_PORTPARAMS
), TRUE
);
2393 if (NT_SUCCESS(ntStatus
))
2395 RtlCopyMemory(pRequest
->Value
, pRequest
->Instance
, sizeof(SYNTH_PORTPARAMS
));
2397 PSYNTH_PORTPARAMS Params
= (PSYNTH_PORTPARAMS
)pRequest
->Value
;
2399 if (Params
->ValidParams
& ~SYNTH_PORTPARAMS_CHANNELGROUPS
)
2401 Params
->ValidParams
&= SYNTH_PORTPARAMS_CHANNELGROUPS
;
2404 if (!(Params
->ValidParams
& SYNTH_PORTPARAMS_CHANNELGROUPS
))
2406 Params
->ChannelGroups
= 1;
2408 else if (Params
->ChannelGroups
!= 1)
2410 Params
->ChannelGroups
= 1;
2413 pRequest
->ValueSize
= sizeof(SYNTH_PORTPARAMS
);
2423 /*****************************************************************************
2425 *****************************************************************************
2426 * The timer DPC callback. Thunks to a C++ member function.
2427 * This is called by the OS in response to the DirectMusic pin
2428 * wanting to wakeup later to process more DirectMusic stuff.
2435 IN PVOID DeferredContext
,
2436 IN PVOID SystemArgument1
,
2437 IN PVOID SystemArgument2
2440 ASSERT(DeferredContext
);
2442 CMiniportDMusUARTStream
*aStream
;
2443 aStream
= (CMiniportDMusUARTStream
*) DeferredContext
;
2446 DPRINT("DMusUARTTimerDPC");
2447 if (false == aStream
->m_fCapture
)
2449 (void) aStream
->ConsumeEvents();
2451 // ignores return value!
2455 /*****************************************************************************
2456 * DirectMusic properties
2457 ****************************************************************************/
2464 * Properties concerning synthesizer functions.
2466 const WCHAR wszDescOut
[] = L
"DMusic MPU-401 Out ";
2467 const WCHAR wszDescIn
[] = L
"DMusic MPU-401 In ";
2471 PropertyHandler_Synth
2473 IN PPCPROPERTY_REQUEST pRequest
2480 if (pRequest
->Verb
& KSPROPERTY_TYPE_BASICSUPPORT
)
2482 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(ULONG
), TRUE
);
2483 if (NT_SUCCESS(ntStatus
))
2485 // if return buffer can hold a ULONG, return the access flags
2486 PULONG AccessFlags
= PULONG(pRequest
->Value
);
2488 *AccessFlags
= KSPROPERTY_TYPE_BASICSUPPORT
;
2489 switch (pRequest
->PropertyItem
->Id
)
2491 case KSPROPERTY_SYNTH_CAPS
:
2492 case KSPROPERTY_SYNTH_CHANNELGROUPS
:
2493 *AccessFlags
|= KSPROPERTY_TYPE_GET
;
2495 switch (pRequest
->PropertyItem
->Id
)
2497 case KSPROPERTY_SYNTH_CHANNELGROUPS
:
2498 *AccessFlags
|= KSPROPERTY_TYPE_SET
;
2500 ntStatus
= STATUS_SUCCESS
;
2501 pRequest
->ValueSize
= sizeof(ULONG
);
2503 switch (pRequest
->PropertyItem
->Id
)
2505 case KSPROPERTY_SYNTH_PORTPARAMETERS
:
2506 if (pRequest
->MinorTarget
)
2508 *AccessFlags
|= KSPROPERTY_TYPE_GET
;
2512 pRequest
->ValueSize
= 0;
2513 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2520 ntStatus
= STATUS_SUCCESS
;
2521 switch(pRequest
->PropertyItem
->Id
)
2523 case KSPROPERTY_SYNTH_CAPS
:
2524 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CAPS");
2526 if (pRequest
->Verb
& KSPROPERTY_TYPE_SET
)
2528 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2531 if (NT_SUCCESS(ntStatus
))
2533 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(SYNTHCAPS
), TRUE
);
2535 if (NT_SUCCESS(ntStatus
))
2537 SYNTHCAPS
*caps
= (SYNTHCAPS
*)pRequest
->Value
;
2539 RtlZeroMemory(caps
, sizeof(SYNTHCAPS
));
2540 // XXX Different guids for different instances!
2542 if (pRequest
->Node
== eSynthNode
)
2544 increment
= sizeof(wszDescOut
) - 2;
2545 RtlCopyMemory( caps
->Description
,wszDescOut
,increment
);
2546 caps
->Guid
= CLSID_MiniportDriverDMusUART
;
2550 increment
= sizeof(wszDescIn
) - 2;
2551 RtlCopyMemory( caps
->Description
,wszDescIn
,increment
);
2552 caps
->Guid
= CLSID_MiniportDriverDMusUARTCapture
;
2555 caps
->Flags
= SYNTH_PC_EXTERNAL
;
2556 caps
->MemorySize
= 0;
2557 caps
->MaxChannelGroups
= 1;
2558 caps
->MaxVoices
= 0xFFFFFFFF;
2559 caps
->MaxAudioChannels
= 0xFFFFFFFF;
2561 caps
->EffectFlags
= 0;
2563 CMiniportDMusUART
*aMiniport
;
2564 ASSERT(pRequest
->MajorTarget
);
2565 aMiniport
= (CMiniportDMusUART
*)(PMINIPORTDMUS
)(pRequest
->MajorTarget
);
2568 cLen
= swprintf(wszDesc2
,L
"[%03x]\0",PtrToUlong(aMiniport
->m_pPortBase
));
2570 cLen
*= sizeof(WCHAR
);
2571 RtlCopyMemory((WCHAR
*)((DWORD_PTR
)(caps
->Description
) + increment
),
2576 pRequest
->ValueSize
= sizeof(SYNTHCAPS
);
2582 case KSPROPERTY_SYNTH_PORTPARAMETERS
:
2583 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_PORTPARAMETERS");
2585 CMiniportDMusUARTStream
*aStream
;
2587 aStream
= (CMiniportDMusUARTStream
*)(pRequest
->MinorTarget
);
2590 ntStatus
= aStream
->HandlePortParams(pRequest
);
2594 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2599 case KSPROPERTY_SYNTH_CHANNELGROUPS
:
2600 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CHANNELGROUPS");
2602 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(ULONG
), TRUE
);
2603 if (NT_SUCCESS(ntStatus
))
2605 *(PULONG
)(pRequest
->Value
) = 1;
2606 pRequest
->ValueSize
= sizeof(ULONG
);
2610 case KSPROPERTY_SYNTH_LATENCYCLOCK
:
2611 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_LATENCYCLOCK");
2613 if(pRequest
->Verb
& KSPROPERTY_TYPE_SET
)
2615 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2619 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(ULONGLONG
), TRUE
);
2620 if(NT_SUCCESS(ntStatus
))
2622 REFERENCE_TIME rtLatency
;
2623 CMiniportDMusUARTStream
*aStream
;
2625 aStream
= (CMiniportDMusUARTStream
*)(pRequest
->MinorTarget
);
2628 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2632 aStream
->m_pMiniport
->m_MasterClock
->GetTime(&rtLatency
);
2633 *((PULONGLONG
)pRequest
->Value
) = rtLatency
;
2634 pRequest
->ValueSize
= sizeof(ULONGLONG
);
2641 DPRINT("Unhandled property in PropertyHandler_Synth");
2648 /*****************************************************************************
2649 * ValidatePropertyRequest()
2650 *****************************************************************************
2651 * Validates pRequest.
2652 * Checks if the ValueSize is valid
2653 * Checks if the Value is valid
2655 * This does not update pRequest->ValueSize if it returns NT_SUCCESS.
2656 * Caller must set pRequest->ValueSize in case of NT_SUCCESS.
2658 NTSTATUS ValidatePropertyRequest
2660 IN PPCPROPERTY_REQUEST pRequest
,
2661 IN ULONG ulValueSize
,
2662 IN BOOLEAN fValueRequired
2667 if (pRequest
->ValueSize
>= ulValueSize
)
2669 if (fValueRequired
&& NULL
== pRequest
->Value
)
2671 ntStatus
= STATUS_INVALID_PARAMETER
;
2675 ntStatus
= STATUS_SUCCESS
;
2678 else if (0 == pRequest
->ValueSize
)
2680 ntStatus
= STATUS_BUFFER_OVERFLOW
;
2684 ntStatus
= STATUS_BUFFER_TOO_SMALL
;
2687 if (STATUS_BUFFER_OVERFLOW
== ntStatus
)
2689 pRequest
->ValueSize
= ulValueSize
;
2693 pRequest
->ValueSize
= 0;
2697 } // ValidatePropertyRequest