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
;
185 DMusMPUInterruptServiceRoutine(PINTERRUPTSYNC InterruptSync
,PVOID DynamicContext
);
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
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.
697 IN PINTERRUPTSYNC InterruptSync
,
698 IN PVOID DynamicContext
704 return STATUS_INVALID_PARAMETER_2
;
707 PUCHAR portBase
= PUCHAR(DynamicContext
);
711 NTSTATUS ntStatus
= STATUS_SUCCESS
;
714 // Reset the card (puts it into "smart mode")
716 ntStatus
= WriteMPU(portBase
,COMMAND
,MPU401_CMD_RESET
);
718 // wait for the acknowledgement
719 // NOTE: When the Ack arrives, it will trigger an interrupt.
720 // Normally the DPC routine would read in the ack byte and we
721 // would never see it, however since we have the hardware locked (HwEnter),
722 // we can read the port before the DPC can and thus we receive the Ack.
723 startTime
= PcGetTimeInterval(0);
725 while(PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
727 status
= READ_PORT_UCHAR(portBase
+ MPU401_REG_STATUS
);
729 if (UartFifoOkForRead(status
)) // Is data waiting?
731 READ_PORT_UCHAR(portBase
+ MPU401_REG_DATA
); // yep.. read ACK
732 success
= TRUE
; // don't need to do more
735 KeStallExecutionProcessor(25); // microseconds
740 DPRINT("First attempt to reset the MPU didn't get ACKed.\n");
744 // NOTE: We cannot check the ACK byte because if the card was already in
745 // UART mode it will not send an ACK but it will reset.
747 // reset the card again
748 (void) WriteMPU(portBase
,COMMAND
,MPU401_CMD_RESET
);
750 // wait for ack (again)
751 startTime
= PcGetTimeInterval(0); // This might take a while
754 while (PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
756 status
= READ_PORT_UCHAR(portBase
+ MPU401_REG_STATUS
);
757 if (UartFifoOkForRead(status
)) // Is data waiting?
759 dataByte
= READ_PORT_UCHAR(portBase
+ MPU401_REG_DATA
); // yep.. read ACK
760 success
= TRUE
; // don't need to do more
763 KeStallExecutionProcessor(25);
766 if ((0xFE != dataByte
) || !success
) // Did we succeed? If no second ACK, something is hosed
768 DPRINT("Second attempt to reset the MPU didn't get ACKed.\n");
769 DPRINT("Init Reset failure error. Ack = %X", ULONG(dataByte
));
771 ntStatus
= STATUS_IO_DEVICE_ERROR
;
781 /*****************************************************************************
782 * CMiniportDMusUARTStream::Write()
783 *****************************************************************************
784 * Writes outgoing MIDI data.
786 STDMETHODIMP_(NTSTATUS
)
787 CMiniportDMusUARTStream::
790 IN PVOID BufferAddress
,
792 OUT PULONG BytesWritten
796 ASSERT(BytesWritten
);
802 NTSTATUS ntStatus
= STATUS_SUCCESS
;
810 pMidiData
= PUCHAR(BufferAddress
);
814 SYNCWRITECONTEXT context
;
815 context
.Miniport
= (m_pMiniport
);
816 context
.PortBase
= m_pPortBase
;
817 context
.BufferAddress
= pMidiData
;
818 context
.Length
= Length
;
819 context
.BytesRead
= &count
;
821 if (m_pMiniport
->m_UseIRQ
)
823 ntStatus
= m_pMiniport
->m_pInterruptSync
->
824 CallSynchronizedRoutine(SynchronizedDMusMPUWrite
,PVOID(&context
));
828 ntStatus
= SynchronizedDMusMPUWrite(NULL
,PVOID(&context
));
833 m_NumFailedMPUTries
++;
834 if (m_NumFailedMPUTries
>= 100)
836 ntStatus
= STATUS_IO_DEVICE_ERROR
;
837 m_NumFailedMPUTries
= 0;
842 m_NumFailedMPUTries
= 0;
844 } // if we have data at all
845 *BytesWritten
= count
;
847 else // called write on the read stream
849 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
858 /*****************************************************************************
859 * SynchronizedDMusMPUWrite()
860 *****************************************************************************
861 * Writes outgoing MIDI data.
864 SynchronizedDMusMPUWrite
866 IN PINTERRUPTSYNC InterruptSync
,
867 IN PVOID syncWriteContext
870 PSYNCWRITECONTEXT context
;
871 context
= (PSYNCWRITECONTEXT
)syncWriteContext
;
872 ASSERT(context
->Miniport
);
873 ASSERT(context
->PortBase
);
874 ASSERT(context
->BufferAddress
);
875 ASSERT(context
->Length
);
876 ASSERT(context
->BytesRead
);
878 PUCHAR pChar
= PUCHAR(context
->BufferAddress
);
879 NTSTATUS ntStatus
,readStatus
;
880 ntStatus
= STATUS_SUCCESS
;
882 // while we're not there yet, and
883 // while we don't have to wait on an aligned byte (including 0)
884 // (we never wait on a byte. Better to come back later)
885 readStatus
= DMusMPUInterruptServiceRoutine(InterruptSync
,PVOID(context
->Miniport
));
886 while ( (*(context
->BytesRead
) < context
->Length
)
887 && ( TryMPU(context
->PortBase
)
888 || (*(context
->BytesRead
)%3)
891 ntStatus
= WriteMPU(context
->PortBase
,DATA
,*pChar
);
892 if (NT_SUCCESS(ntStatus
))
895 *(context
->BytesRead
) = *(context
->BytesRead
) + 1;
896 // readStatus = DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport));
900 DPRINT("SynchronizedDMusMPUWrite failed (0x%08x)",ntStatus
);
904 readStatus
= DMusMPUInterruptServiceRoutine(InterruptSync
,PVOID(context
->Miniport
));
908 #define kMPUPollTimeout 2
914 /*****************************************************************************
916 *****************************************************************************
917 * See if the MPU401 is free.
932 while (numPolls
< kMPUPollTimeout
)
934 status
= READ_PORT_UCHAR(PortBase
+ MPU401_REG_STATUS
);
936 if (UartFifoOkForWrite(status
)) // Is this a good time to write data?
942 if (numPolls
>= kMPUPollTimeout
)
945 DPRINT("TryMPU failed");
959 /*****************************************************************************
961 *****************************************************************************
962 * Write a byte out to the MPU401.
968 IN BOOLEAN IsCommand
,
973 NTSTATUS ntStatus
= STATUS_IO_DEVICE_ERROR
;
977 DPRINT("O: PortBase is zero\n");
980 PUCHAR deviceAddr
= PortBase
+ MPU401_REG_DATA
;
984 deviceAddr
= PortBase
+ MPU401_REG_COMMAND
;
987 ULONGLONG startTime
= PcGetTimeInterval(0);
989 while (PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
992 = READ_PORT_UCHAR(PortBase
+ MPU401_REG_STATUS
);
994 if (UartFifoOkForWrite(status
)) // Is this a good time to write data?
995 { // yep (Jon comment)
996 WRITE_PORT_UCHAR(deviceAddr
,Value
);
997 DPRINT("WriteMPU emitted 0x%02x",Value
);
998 ntStatus
= STATUS_SUCCESS
;
1009 /*****************************************************************************
1011 *****************************************************************************
1013 * At synchronized execution to ISR, copy miniport's volatile m_InputTimeStamp
1014 * to stream's m_SnapshotTimeStamp and zero m_InputTimeStamp.
1017 STDMETHODIMP_(NTSTATUS
)
1018 SnapTimeStamp(PINTERRUPTSYNC InterruptSync
,PVOID pStream
)
1020 CMiniportDMusUARTStream
*pMPStream
= (CMiniportDMusUARTStream
*)pStream
;
1022 // cache the timestamp
1023 pMPStream
->m_SnapshotTimeStamp
= pMPStream
->m_pMiniport
->m_InputTimeStamp
;
1025 // if the window is closed, zero the timestamp
1026 if (pMPStream
->m_pMiniport
->m_MPUInputBufferHead
==
1027 pMPStream
->m_pMiniport
->m_MPUInputBufferTail
)
1029 pMPStream
->m_pMiniport
->m_InputTimeStamp
= 0;
1032 return STATUS_SUCCESS
;
1035 /*****************************************************************************
1036 * CMiniportDMusUARTStream::SourceEvtsToPort()
1037 *****************************************************************************
1039 * Reads incoming MIDI data, feeds into DMus events.
1040 * No need to touch the hardware, just read from our SW FIFO.
1043 STDMETHODIMP_(NTSTATUS
)
1044 CMiniportDMusUARTStream::SourceEvtsToPort()
1048 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1049 DPRINT("SourceEvtsToPort");
1053 ntStatus
= STATUS_SUCCESS
;
1054 if (m_pMiniport
->m_MPUInputBufferHead
!= m_pMiniport
->m_MPUInputBufferTail
)
1056 PDMUS_KERNEL_EVENT aDMKEvt
,eventTail
,eventHead
= NULL
;
1058 while (m_pMiniport
->m_MPUInputBufferHead
!= m_pMiniport
->m_MPUInputBufferTail
)
1060 (void) m_AllocatorMXF
->GetMessage(&aDMKEvt
);
1063 DPRINT("SourceEvtsToPort can't allocate DMKEvt");
1064 return STATUS_INSUFFICIENT_RESOURCES
;
1067 // put this event at the end of the list
1070 eventHead
= aDMKEvt
;
1074 eventTail
= eventHead
;
1075 while (eventTail
->pNextEvt
)
1077 eventTail
= eventTail
->pNextEvt
;
1079 eventTail
->pNextEvt
= aDMKEvt
;
1081 // read all the bytes out of the buffer, into event(s)
1082 for (aDMKEvt
->cbEvent
= 0; aDMKEvt
->cbEvent
< sizeof(PBYTE
); aDMKEvt
->cbEvent
++)
1084 if (m_pMiniport
->m_MPUInputBufferHead
== m_pMiniport
->m_MPUInputBufferTail
)
1086 // _DbgPrintF(DEBUGLVL_TERSE, ("SourceEvtsToPort m_MPUInputBufferHead met m_MPUInputBufferTail, overrun"));
1089 aDMKEvt
->uData
.abData
[aDMKEvt
->cbEvent
] = m_pMiniport
->m_MPUInputBuffer
[m_pMiniport
->m_MPUInputBufferHead
];
1090 m_pMiniport
->m_MPUInputBufferHead
++;
1091 if (m_pMiniport
->m_MPUInputBufferHead
>= kMPUInputBufferSize
)
1093 m_pMiniport
->m_MPUInputBufferHead
= 0;
1098 if (m_pMiniport
->m_UseIRQ
)
1100 ntStatus
= m_pMiniport
->m_pInterruptSync
->CallSynchronizedRoutine(SnapTimeStamp
,PVOID(this));
1104 ntStatus
= SnapTimeStamp(NULL
,PVOID(this));
1106 aDMKEvt
= eventHead
;
1109 aDMKEvt
->ullPresTime100ns
= m_SnapshotTimeStamp
;
1110 aDMKEvt
->usChannelGroup
= 1;
1111 aDMKEvt
->usFlags
= DMUS_KEF_EVENT_INCOMPLETE
;
1112 aDMKEvt
= aDMKEvt
->pNextEvt
;
1114 (void)m_sinkMXF
->PutMessage(eventHead
);
1117 else // render stream
1119 DPRINT("SourceEvtsToPort called on render stream");
1120 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
1129 /*****************************************************************************
1130 * DMusMPUInterruptServiceRoutine()
1131 *****************************************************************************
1135 DMusMPUInterruptServiceRoutine
1137 IN PINTERRUPTSYNC InterruptSync
,
1138 IN PVOID DynamicContext
1141 DPRINT("DMusMPUInterruptServiceRoutine");
1142 ULONGLONG startTime
;
1144 ASSERT(DynamicContext
);
1147 BOOL newBytesAvailable
;
1148 CMiniportDMusUART
*that
;
1149 NTSTATUS clockStatus
;
1151 that
= (CMiniportDMusUART
*) DynamicContext
;
1152 newBytesAvailable
= FALSE
;
1153 ntStatus
= STATUS_UNSUCCESSFUL
;
1155 UCHAR portStatus
= 0xff;
1158 // Read the MPU status byte.
1160 if (that
->m_pPortBase
)
1163 READ_PORT_UCHAR(that
->m_pPortBase
+ MPU401_REG_STATUS
);
1166 // If there is outstanding work to do and there is a port-driver for
1167 // the MPU miniport...
1169 if (UartFifoOkForRead(portStatus
) && that
->m_pPort
)
1171 startTime
= PcGetTimeInterval(0);
1172 while ( (PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
1173 && (UartFifoOkForRead(portStatus
)) )
1175 UCHAR uDest
= READ_PORT_UCHAR(that
->m_pPortBase
+ MPU401_REG_DATA
);
1176 if ( (that
->m_KSStateInput
== KSSTATE_RUN
)
1177 && (that
->m_NumCaptureStreams
)
1180 ULONG buffHead
= that
->m_MPUInputBufferHead
;
1181 if ( (that
->m_MPUInputBufferTail
+ 1 == buffHead
)
1182 || (that
->m_MPUInputBufferTail
+ 1 - kMPUInputBufferSize
== buffHead
))
1184 DPRINT("*****MPU Input Buffer Overflow*****");
1188 if (!that
->m_InputTimeStamp
)
1190 clockStatus
= that
->m_MasterClock
->GetTime(&that
->m_InputTimeStamp
);
1191 if (STATUS_SUCCESS
!= clockStatus
)
1193 DPRINT("GetTime failed for clock 0x%08x",that
->m_MasterClock
);
1196 newBytesAvailable
= TRUE
;
1197 // ...place the data in our FIFO...
1198 that
->m_MPUInputBuffer
[that
->m_MPUInputBufferTail
] = uDest
;
1199 ASSERT(that
->m_MPUInputBufferTail
< kMPUInputBufferSize
);
1201 that
->m_MPUInputBufferTail
++;
1202 if (that
->m_MPUInputBufferTail
>= kMPUInputBufferSize
)
1204 that
->m_MPUInputBufferTail
= 0;
1209 // Look for more MIDI data.
1212 READ_PORT_UCHAR(that
->m_pPortBase
+ MPU401_REG_STATUS
);
1213 } // either there's no data or we ran too long
1214 if (newBytesAvailable
)
1217 // ...notify the MPU port driver that we have bytes.
1219 that
->m_pPort
->Notify(that
->m_pServiceGroup
);
1221 ntStatus
= STATUS_SUCCESS
;
1228 /*****************************************************************************
1229 * CMiniportDMusUART::GetDescription()
1230 *****************************************************************************
1231 * Gets the topology.
1233 STDMETHODIMP_(NTSTATUS
)
1237 OUT PPCFILTER_DESCRIPTOR
* OutFilterDescriptor
1242 ASSERT(OutFilterDescriptor
);
1244 DPRINT("GetDescription");
1246 *OutFilterDescriptor
= &MiniportFilterDescriptor
;
1248 return STATUS_SUCCESS
;
1252 #pragma code_seg("PAGE")
1256 NewMiniportDMusUART(
1257 OUT PMINIPORT
* OutMiniport
,
1258 IN REFCLSID ClassId
)
1260 CMiniportDMusUART
* This
;
1263 This
= new(NonPagedPool
, TAG_PORTCLASS
) CMiniportDMusUART(NULL
);
1265 return STATUS_INSUFFICIENT_RESOURCES
;
1267 Status
= This
->QueryInterface(IID_IMiniport
, (PVOID
*)OutMiniport
);
1269 if (!NT_SUCCESS(Status
))
1274 DPRINT("NewMiniportDMusUART %p Status %x\n", *OutMiniport
, Status
);
1280 #pragma code_seg("PAGE")
1283 /*****************************************************************************
1284 * CMiniportDMusUART::ProcessResources()
1285 *****************************************************************************
1286 * Processes the resource list, setting up helper objects accordingly.
1292 IN PRESOURCELIST ResourceList
1297 DPRINT("ProcessResources");
1299 ASSERT(ResourceList
);
1302 return STATUS_DEVICE_CONFIGURATION_ERROR
;
1305 // Get counts for the types of resources.
1307 ULONG countIO
= ResourceList
->NumberOfPorts();
1308 ULONG countIRQ
= ResourceList
->NumberOfInterrupts();
1309 ULONG countDMA
= ResourceList
->NumberOfDmas();
1310 ULONG lengthIO
= ResourceList
->FindTranslatedPort(0)->u
.Port
.Length
;
1313 DPRINT("Starting MPU401 Port 0x%lx", ResourceList
->FindTranslatedPort(0)->u
.Port
.Start
.LowPart
);
1316 NTSTATUS ntStatus
= STATUS_SUCCESS
;
1319 // Make sure we have the expected number of resources.
1327 DPRINT("Unknown ResourceList configuraton");
1328 ntStatus
= STATUS_DEVICE_CONFIGURATION_ERROR
;
1331 if (NT_SUCCESS(ntStatus
))
1334 // Get the port address.
1337 PUCHAR(ResourceList
->FindTranslatedPort(0)->u
.Port
.Start
.QuadPart
);
1339 ntStatus
= InitializeHardware(m_pInterruptSync
,m_pPortBase
);
1346 #pragma code_seg("PAGE")
1348 /*****************************************************************************
1349 * CMiniportDMusUART::NonDelegatingQueryInterface()
1350 *****************************************************************************
1351 * Obtains an interface. This function works just like a COM QueryInterface
1352 * call and is used if the object is not being aggregated.
1354 STDMETHODIMP_(NTSTATUS
)
1355 CMiniportDMusUART::QueryInterface
1363 DPRINT("Miniport::NonDelegatingQueryInterface");
1366 if (IsEqualGUIDAligned(Interface
,IID_IUnknown
))
1368 *Object
= PVOID(PUNKNOWN(PMINIPORTDMUS(this)));
1371 if (IsEqualGUIDAligned(Interface
,IID_IMiniport
))
1373 *Object
= PVOID(PMINIPORT(this));
1376 if (IsEqualGUIDAligned(Interface
,IID_IMiniportDMus
))
1378 *Object
= PVOID(PMINIPORTDMUS(this));
1381 if (IsEqualGUIDAligned(Interface
,IID_IMusicTechnology
))
1383 *Object
= PVOID(PMUSICTECHNOLOGY(this));
1386 if (IsEqualGUIDAligned(Interface
,IID_IPowerNotify
))
1388 *Object
= PVOID(PPOWERNOTIFY(this));
1398 // We reference the interface for the caller.
1400 PUNKNOWN(*Object
)->AddRef();
1401 return STATUS_SUCCESS
;
1404 return STATUS_INVALID_PARAMETER
;
1408 #pragma code_seg("PAGE")
1410 /*****************************************************************************
1411 * CMiniportDMusUART::~CMiniportDMusUART()
1412 *****************************************************************************
1415 CMiniportDMusUART::~CMiniportDMusUART(void)
1419 DPRINT("~CMiniportDMusUART");
1421 ASSERT(0 == m_NumCaptureStreams
);
1422 ASSERT(0 == m_NumRenderStreams
);
1424 // reset the HW so we don't get anymore interrupts
1425 if (m_UseIRQ
&& m_pInterruptSync
)
1427 (void) m_pInterruptSync
->CallSynchronizedRoutine((PINTERRUPTSYNCROUTINE
)InitMPU
,PVOID(m_pPortBase
));
1431 (void) InitMPU(NULL
,PVOID(m_pPortBase
));
1434 if (m_pInterruptSync
)
1436 m_pInterruptSync
->Release();
1437 m_pInterruptSync
= NULL
;
1439 if (m_pServiceGroup
)
1441 m_pServiceGroup
->Release();
1442 m_pServiceGroup
= NULL
;
1452 #pragma code_seg("PAGE")
1454 /*****************************************************************************
1455 * CMiniportDMusUART::Init()
1456 *****************************************************************************
1457 * Initializes a the miniport.
1459 STDMETHODIMP_(NTSTATUS
)
1463 IN PUNKNOWN UnknownInterruptSync OPTIONAL
,
1464 IN PRESOURCELIST ResourceList
,
1466 OUT PSERVICEGROUP
* ServiceGroup
1471 ASSERT(ResourceList
);
1474 return STATUS_DEVICE_CONFIGURATION_ERROR
;
1478 ASSERT(ServiceGroup
);
1482 *ServiceGroup
= NULL
;
1484 m_fMPUInitialized
= FALSE
;
1486 // This will remain unspecified if the miniport does not get any power
1489 m_PowerState
.DeviceState
= PowerDeviceUnspecified
;
1492 // AddRef() is required because we are keeping this pointer.
1499 if (IsEqualGUIDAligned(m_MusicFormatTechnology
, GUID_NULL
))
1501 RtlCopyMemory( &m_MusicFormatTechnology
,
1502 &KSMUSIC_TECHNOLOGY_PORT
,
1505 RtlCopyMemory( &PinDataRangesStreamLegacy
.Technology
,
1506 &m_MusicFormatTechnology
,
1508 RtlCopyMemory( &PinDataRangesStreamDMusic
.Technology
,
1509 &m_MusicFormatTechnology
,
1512 for (ULONG bufferCount
= 0;bufferCount
< kMPUInputBufferSize
;bufferCount
++)
1514 m_MPUInputBuffer
[bufferCount
] = 0;
1516 m_MPUInputBufferHead
= 0;
1517 m_MPUInputBufferTail
= 0;
1518 m_InputTimeStamp
= 0;
1519 m_KSStateInput
= KSSTATE_STOP
;
1521 NTSTATUS ntStatus
= STATUS_SUCCESS
;
1523 m_NumRenderStreams
= 0;
1524 m_NumCaptureStreams
= 0;
1527 if (ResourceList
->NumberOfInterrupts() == 0)
1532 ntStatus
= PcNewServiceGroup(&m_pServiceGroup
,NULL
);
1533 if (NT_SUCCESS(ntStatus
) && !m_pServiceGroup
) // keep any error
1535 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1538 if (NT_SUCCESS(ntStatus
))
1540 *ServiceGroup
= m_pServiceGroup
;
1541 m_pServiceGroup
->AddRef();
1544 // Register the service group with the port early so the port is
1545 // prepared to handle interrupts.
1547 m_pPort
->RegisterServiceGroup(m_pServiceGroup
);
1550 if (NT_SUCCESS(ntStatus
) && m_UseIRQ
)
1553 // Due to a bug in the InterruptSync design, we shouldn't share
1554 // the interrupt sync object. Whoever goes away first
1555 // will disconnect it, and the other points off into nowhere.
1557 // Instead we generate our own interrupt sync object.
1559 UnknownInterruptSync
= NULL
;
1561 if (UnknownInterruptSync
)
1564 UnknownInterruptSync
->QueryInterface
1567 (PVOID
*) &m_pInterruptSync
1570 if (!m_pInterruptSync
&& NT_SUCCESS(ntStatus
)) // keep any error
1572 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1574 if (NT_SUCCESS(ntStatus
))
1575 { // run this ISR first
1576 ntStatus
= m_pInterruptSync
->
1577 RegisterServiceRoutine(DMusMPUInterruptServiceRoutine
,PVOID(this),TRUE
);
1582 { // create our own interruptsync mechanism.
1589 0, // Resource Index
1590 InterruptSyncModeNormal
// Run ISRs once until we get SUCCESS
1593 if (!m_pInterruptSync
&& NT_SUCCESS(ntStatus
)) // keep any error
1595 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1598 if (NT_SUCCESS(ntStatus
))
1600 ntStatus
= m_pInterruptSync
->RegisterServiceRoutine(
1601 DMusMPUInterruptServiceRoutine
,
1603 TRUE
); // run this ISR first
1605 if (NT_SUCCESS(ntStatus
))
1607 ntStatus
= m_pInterruptSync
->Connect();
1612 if (NT_SUCCESS(ntStatus
))
1614 ntStatus
= ProcessResources(ResourceList
);
1617 if (!NT_SUCCESS(ntStatus
))
1620 // clean up our mess
1623 // clean up the interrupt sync
1624 if( m_pInterruptSync
)
1626 m_pInterruptSync
->Release();
1627 m_pInterruptSync
= NULL
;
1630 // clean up the service group
1631 if( m_pServiceGroup
)
1633 m_pServiceGroup
->Release();
1634 m_pServiceGroup
= NULL
;
1637 // clean up the out param service group.
1640 (*ServiceGroup
)->Release();
1641 (*ServiceGroup
) = NULL
;
1653 #pragma code_seg("PAGE")
1655 /*****************************************************************************
1656 * CMiniportDMusUART::NewStream()
1657 *****************************************************************************
1658 * Gets the topology.
1660 STDMETHODIMP_(NTSTATUS
)
1665 IN PUNKNOWN OuterUnknown OPTIONAL
,
1666 IN POOL_TYPE PoolType
,
1668 IN DMUS_STREAM_TYPE StreamType
,
1669 IN PKSDATAFORMAT DataFormat
,
1670 OUT PSERVICEGROUP
* ServiceGroup
,
1671 IN PAllocatorMXF AllocatorMXF
,
1672 IN PMASTERCLOCK MasterClock
,
1673 OUT PULONGLONG SchedulePreFetch
1678 DPRINT("NewStream");
1679 NTSTATUS ntStatus
= STATUS_SUCCESS
;
1681 // In 100 ns, we want stuff as soon as it comes in
1683 *SchedulePreFetch
= 0;
1685 // if we don't have any streams already open, get the hardware ready.
1686 if ((!m_NumCaptureStreams
) && (!m_NumRenderStreams
))
1688 ntStatus
= ResetHardware(m_pPortBase
);
1689 if (!NT_SUCCESS(ntStatus
))
1691 DPRINT("CMiniportDMusUART::NewStream ResetHardware failed");
1696 if ( ((m_NumCaptureStreams
< kMaxNumCaptureStreams
)
1697 && (StreamType
== DMUS_STREAM_MIDI_CAPTURE
))
1698 || ((m_NumRenderStreams
< kMaxNumLegacyRenderStreams
+ kMaxNumDMusicRenderStreams
)
1699 && (StreamType
== DMUS_STREAM_MIDI_RENDER
))
1702 CMiniportDMusUARTStream
*pStream
=
1703 new(PoolType
) CMiniportDMusUARTStream();
1710 pStream
->Init(this,m_pPortBase
,(StreamType
== DMUS_STREAM_MIDI_CAPTURE
),AllocatorMXF
,MasterClock
);
1712 if (NT_SUCCESS(ntStatus
))
1714 *MXF
= PMXF(pStream
);
1717 if (StreamType
== DMUS_STREAM_MIDI_CAPTURE
)
1719 m_NumCaptureStreams
++;
1720 *ServiceGroup
= m_pServiceGroup
;
1721 (*ServiceGroup
)->AddRef();
1725 m_NumRenderStreams
++;
1726 *ServiceGroup
= NULL
;
1734 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1739 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
1740 if (StreamType
== DMUS_STREAM_MIDI_CAPTURE
)
1742 DPRINT("NewStream failed, too many capture streams");
1744 else if (StreamType
== DMUS_STREAM_MIDI_RENDER
)
1746 DPRINT("NewStream failed, too many render streams");
1750 DPRINT("NewStream invalid stream type");
1758 #pragma code_seg("PAGE")
1760 /*****************************************************************************
1761 * CMiniportDMusUART::SetTechnology()
1762 *****************************************************************************
1763 * Sets pindatarange technology.
1765 STDMETHODIMP_(NTSTATUS
)
1769 IN
const GUID
* Technology
1774 NTSTATUS ntStatus
= STATUS_UNSUCCESSFUL
;
1776 // Fail if miniport has already been initialized.
1778 if (NULL
== m_pPort
)
1780 RtlCopyMemory(&m_MusicFormatTechnology
, Technology
, sizeof(GUID
));
1781 ntStatus
= STATUS_SUCCESS
;
1787 /*****************************************************************************
1788 * CMiniportDMusUART::PowerChangeNotify()
1789 *****************************************************************************
1790 * Handle power state change for the miniport.
1793 #pragma code_seg("PAGE")
1800 IN POWER_STATE PowerState
1805 DPRINT("CMiniportDMusUART::PoweChangeNotify D%d", PowerState
.DeviceState
);
1807 switch (PowerState
.DeviceState
)
1810 if (m_PowerState
.DeviceState
!= PowerDeviceD0
)
1812 if (!NT_SUCCESS(InitializeHardware(m_pInterruptSync
,m_pPortBase
)))
1814 DPRINT("InitializeHardware failed when resuming");
1825 m_PowerState
.DeviceState
= PowerState
.DeviceState
;
1826 } // PowerChangeNotify
1829 #pragma code_seg("PAGE")
1831 /*****************************************************************************
1832 * CMiniportDMusUARTStream::NonDelegatingQueryInterface()
1833 *****************************************************************************
1834 * Obtains an interface. This function works just like a COM QueryInterface
1835 * call and is used if the object is not being aggregated.
1837 STDMETHODIMP_(NTSTATUS
)
1838 CMiniportDMusUARTStream::QueryInterface
1846 DPRINT("Stream::NonDelegatingQueryInterface");
1849 if (IsEqualGUIDAligned(Interface
,IID_IUnknown
))
1851 *Object
= PVOID(PUNKNOWN(this));
1854 if (IsEqualGUIDAligned(Interface
,IID_IMXF
))
1856 *Object
= PVOID(PMXF(this));
1866 // We reference the interface for the caller.
1868 PUNKNOWN(*Object
)->AddRef();
1869 return STATUS_SUCCESS
;
1872 return STATUS_INVALID_PARAMETER
;
1876 #pragma code_seg("PAGE")
1878 /*****************************************************************************
1879 * CMiniportDMusUARTStream::~CMiniportDMusUARTStream()
1880 *****************************************************************************
1881 * Destructs a stream.
1883 CMiniportDMusUARTStream::~CMiniportDMusUARTStream(void)
1887 DPRINT("~CMiniportDMusUARTStream");
1889 KeCancelTimer(&m_TimerEvent
);
1895 m_AllocatorMXF
->PutMessage(m_DMKEvtQueue
);
1899 DPRINT("~CMiniportDMusUARTStream, no allocator, can't flush DMKEvts");
1901 m_DMKEvtQueue
= NULL
;
1905 m_AllocatorMXF
->Release();
1906 m_AllocatorMXF
= NULL
;
1913 m_pMiniport
->m_NumCaptureStreams
--;
1917 m_pMiniport
->m_NumRenderStreams
--;
1920 m_pMiniport
->Release();
1925 #pragma code_seg("PAGE")
1927 /*****************************************************************************
1928 * CMiniportDMusUARTStream::Init()
1929 *****************************************************************************
1930 * Initializes a stream.
1932 STDMETHODIMP_(NTSTATUS
)
1933 CMiniportDMusUARTStream::
1936 IN CMiniportDMusUART
* pMiniport
,
1937 IN PUCHAR pPortBase
,
1938 IN BOOLEAN fCapture
,
1939 IN PAllocatorMXF allocatorMXF
,
1940 IN PMASTERCLOCK masterClock
1950 m_NumFailedMPUTries
= 0;
1951 m_TimerQueued
= FALSE
;
1952 KeInitializeSpinLock(&m_DpcSpinLock
);
1953 m_pMiniport
= pMiniport
;
1954 m_pMiniport
->AddRef();
1956 pMiniport
->m_MasterClock
= masterClock
;
1958 m_pPortBase
= pPortBase
;
1959 m_fCapture
= fCapture
;
1961 m_SnapshotTimeStamp
= 0;
1962 m_DMKEvtQueue
= NULL
;
1965 m_NumberOfRetries
= 0;
1969 allocatorMXF
->AddRef();
1970 m_AllocatorMXF
= allocatorMXF
;
1971 m_sinkMXF
= m_AllocatorMXF
;
1975 return STATUS_INVALID_PARAMETER
;
1981 &::DMusUARTTimerDPC
,
1984 KeInitializeTimer(&m_TimerEvent
);
1986 return STATUS_SUCCESS
;
1990 #pragma code_seg("PAGE")
1992 /*****************************************************************************
1993 * CMiniportDMusUARTStream::SetState()
1994 *****************************************************************************
1995 * Sets the state of the channel.
1997 STDMETHODIMP_(NTSTATUS
)
1998 CMiniportDMusUARTStream::
2006 DPRINT("SetState %d",NewState
);
2008 if (NewState
== KSSTATE_RUN
)
2010 if (m_pMiniport
->m_fMPUInitialized
)
2012 LARGE_INTEGER timeDue100ns
;
2013 timeDue100ns
.QuadPart
= 0;
2014 KeSetTimer(&m_TimerEvent
,timeDue100ns
,&m_Dpc
);
2018 DPRINT("CMiniportDMusUARTStream::SetState KSSTATE_RUN failed due to uninitialized MPU");
2019 return STATUS_INVALID_DEVICE_STATE
;
2025 m_pMiniport
->m_KSStateInput
= NewState
;
2026 if (NewState
== KSSTATE_STOP
) // STOPping
2028 m_pMiniport
->m_MPUInputBufferHead
= 0; // Previously read bytes are discarded.
2029 m_pMiniport
->m_MPUInputBufferTail
= 0; // The entire FIFO is available.
2032 return STATUS_SUCCESS
;
2040 /*****************************************************************************
2041 * CMiniportDMusUART::Service()
2042 *****************************************************************************
2043 * DPC-mode service call from the port.
2052 if (!m_NumCaptureStreams
)
2054 // we should never get here....
2055 // if we do, we must have read some trash,
2056 // so just reset the input FIFO
2057 m_MPUInputBufferTail
= m_MPUInputBufferHead
= 0;
2062 #pragma code_seg("PAGE")
2065 /*****************************************************************************
2066 * CMiniportDMusUARTStream::ConnectOutput()
2067 *****************************************************************************
2068 * Writes outgoing MIDI data.
2071 CMiniportDMusUARTStream::
2072 ConnectOutput(PMXF sinkMXF
)
2078 if ((sinkMXF
) && (m_sinkMXF
== m_AllocatorMXF
))
2080 DPRINT("ConnectOutput");
2081 m_sinkMXF
= sinkMXF
;
2082 return STATUS_SUCCESS
;
2086 DPRINT("ConnectOutput failed");
2091 DPRINT("ConnectOutput called on renderer; failed");
2093 return STATUS_UNSUCCESSFUL
;
2097 #pragma code_seg("PAGE")
2100 /*****************************************************************************
2101 * CMiniportDMusUARTStream::DisconnectOutput()
2102 *****************************************************************************
2103 * Writes outgoing MIDI data.
2106 CMiniportDMusUARTStream::
2107 DisconnectOutput(PMXF sinkMXF
)
2113 if ((m_sinkMXF
== sinkMXF
) || (!sinkMXF
))
2115 DPRINT("DisconnectOutput");
2116 m_sinkMXF
= m_AllocatorMXF
;
2117 return STATUS_SUCCESS
;
2121 DPRINT("DisconnectOutput failed");
2126 DPRINT("DisconnectOutput called on renderer; failed");
2128 return STATUS_UNSUCCESSFUL
;
2136 /*****************************************************************************
2137 * CMiniportDMusUARTStream::PutMessageLocked()
2138 *****************************************************************************
2139 * Now that the spinlock is held, add this message to the queue.
2141 * Writes an outgoing MIDI message.
2142 * We don't sort a new message into the queue -- we append it.
2143 * This is fine, since the sequencer feeds us sequenced data.
2144 * Timestamps will ascend by design.
2146 NTSTATUS
CMiniportDMusUARTStream::PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt
)
2148 NTSTATUS ntStatus
= STATUS_SUCCESS
;
2149 PDMUS_KERNEL_EVENT aDMKEvt
;
2151 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
2155 DPRINT("PutMessage to render stream");
2158 // m_DpcSpinLock already held
2162 aDMKEvt
= m_DMKEvtQueue
; // put pDMKEvt in event queue
2164 while (aDMKEvt
->pNextEvt
)
2166 aDMKEvt
= aDMKEvt
->pNextEvt
;
2168 aDMKEvt
->pNextEvt
= pDMKEvt
; // here is end of queue
2170 else // currently nothing in queue
2172 m_DMKEvtQueue
= pDMKEvt
;
2175 DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d",m_DMKEvtOffset
);
2180 // m_DpcSpinLock already held
2184 (void) ConsumeEvents();
2189 DPRINT("PutMessage to capture stream");
2190 ASSERT(NULL
== pDMKEvt
);
2201 /*****************************************************************************
2202 * CMiniportDMusUARTStream::PutMessage()
2203 *****************************************************************************
2204 * Writes an outgoing MIDI message.
2205 * We don't sort a new message into the queue -- we append it.
2206 * This is fine, since the sequencer feeds us sequenced data.
2207 * Timestamps will ascend by design.
2209 NTSTATUS
CMiniportDMusUARTStream::PutMessage(PDMUS_KERNEL_EVENT pDMKEvt
)
2211 NTSTATUS ntStatus
= STATUS_SUCCESS
;
2212 PDMUS_KERNEL_EVENT aDMKEvt
;
2214 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
2218 DPRINT("PutMessage to render stream");
2221 KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock
);
2225 aDMKEvt
= m_DMKEvtQueue
; // put pDMKEvt in event queue
2227 while (aDMKEvt
->pNextEvt
)
2229 aDMKEvt
= aDMKEvt
->pNextEvt
;
2231 aDMKEvt
->pNextEvt
= pDMKEvt
; // here is end of queue
2233 else // currently nothing in queue
2235 m_DMKEvtQueue
= pDMKEvt
;
2238 DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d", m_DMKEvtOffset
);
2243 KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock
);
2247 (void) ConsumeEvents();
2252 DPRINT("PutMessage to capture stream");
2253 ASSERT(NULL
== pDMKEvt
);
2264 /*****************************************************************************
2265 * CMiniportDMusUARTStream::ConsumeEvents()
2266 *****************************************************************************
2267 * Attempts to empty the render message queue.
2268 * Called either from DPC timer or upon IRP submittal.
2269 // TODO: support packages right
2270 // process the package (actually, should do this above.
2271 // treat the package as a list fragment that shouldn't be sorted.
2272 // better yet, go through each event in the package, and when
2273 // an event is exhausted, delete it and decrement m_offset.
2275 NTSTATUS
CMiniportDMusUARTStream::ConsumeEvents(void)
2277 PDMUS_KERNEL_EVENT aDMKEvt
;
2279 NTSTATUS ntStatus
= STATUS_SUCCESS
;
2280 ULONG bytesRemaining
= 0,bytesWritten
= 0;
2281 LARGE_INTEGER aMillisecIn100ns
;
2283 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
2284 KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock
);
2286 m_TimerQueued
= FALSE
;
2287 while (m_DMKEvtQueue
) // do we have anything to play at all?
2289 aDMKEvt
= m_DMKEvtQueue
; // event we try to play
2290 if (aDMKEvt
->cbEvent
)
2292 bytesRemaining
= aDMKEvt
->cbEvent
- m_DMKEvtOffset
; // number of bytes left in this evt
2294 ASSERT(bytesRemaining
> 0);
2295 if (bytesRemaining
<= 0)
2297 bytesRemaining
= aDMKEvt
->cbEvent
;
2300 if (aDMKEvt
->cbEvent
<= sizeof(PBYTE
)) // short message
2302 DPRINT("ConsumeEvents(%02x%02x%02x%02x)", aDMKEvt
->uData
.abData
[0], aDMKEvt
->uData
.abData
[1], aDMKEvt
->uData
.abData
[2], aDMKEvt
->uData
.abData
[3]);
2303 ntStatus
= Write(aDMKEvt
->uData
.abData
+ m_DMKEvtOffset
,bytesRemaining
,&bytesWritten
);
2305 else if (PACKAGE_EVT(aDMKEvt
))
2307 ASSERT(m_DMKEvtOffset
== 0);
2309 DPRINT("ConsumeEvents(Package)");
2311 ntStatus
= PutMessageLocked(aDMKEvt
->uData
.pPackageEvt
); // we already own the spinlock
2313 // null this because we are about to throw it in the allocator
2314 aDMKEvt
->uData
.pPackageEvt
= NULL
;
2315 aDMKEvt
->cbEvent
= 0;
2316 bytesWritten
= bytesRemaining
;
2318 else // SysEx message
2320 DPRINT("ConsumeEvents(%02x%02x%02x%02x)", aDMKEvt
->uData
.pbData
[0], aDMKEvt
->uData
.pbData
[1], aDMKEvt
->uData
.pbData
[2], aDMKEvt
->uData
.pbData
[3]);
2322 ntStatus
= Write(aDMKEvt
->uData
.pbData
+ m_DMKEvtOffset
,bytesRemaining
,&bytesWritten
);
2324 } // if (aDMKEvt->cbEvent)
2325 if (STATUS_SUCCESS
!= ntStatus
)
2327 DPRINT("ConsumeEvents: Write returned 0x%08x", ntStatus
);
2328 bytesWritten
= bytesRemaining
; // just bail on this event and try next time
2331 ASSERT(bytesWritten
<= bytesRemaining
);
2332 if (bytesWritten
== bytesRemaining
)
2334 m_DMKEvtQueue
= m_DMKEvtQueue
->pNextEvt
;
2335 aDMKEvt
->pNextEvt
= NULL
;
2337 m_AllocatorMXF
->PutMessage(aDMKEvt
); // throw back in free pool
2338 m_DMKEvtOffset
= 0; // start fresh on next evt
2339 m_NumberOfRetries
= 0;
2340 } // but wait ... there's more!
2341 else // our FIFO is full for now.
2343 // update our offset by that amount we did write
2344 m_DMKEvtOffset
+= bytesWritten
;
2345 ASSERT(m_DMKEvtOffset
< aDMKEvt
->cbEvent
);
2347 DPRINT("ConsumeEvents tried %d, wrote %d, at offset %d", bytesRemaining
,bytesWritten
,m_DMKEvtOffset
);
2348 aMillisecIn100ns
.QuadPart
= -(kOneMillisec
); // set timer, come back later
2349 m_TimerQueued
= TRUE
;
2350 m_NumberOfRetries
++;
2351 ntStatus
= KeSetTimer( &m_TimerEvent
, aMillisecIn100ns
, &m_Dpc
);
2353 } // we didn't write it all
2354 } // go back, Jack, do it again (while m_DMKEvtQueue)
2355 KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock
);
2363 /*****************************************************************************
2364 * CMiniportDMusUARTStream::HandlePortParams()
2365 *****************************************************************************
2366 * Writes an outgoing MIDI message.
2369 CMiniportDMusUARTStream::
2372 IN PPCPROPERTY_REQUEST pRequest
2379 if (pRequest
->Verb
& KSPROPERTY_TYPE_SET
)
2381 return STATUS_INVALID_DEVICE_REQUEST
;
2384 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(SYNTH_PORTPARAMS
), TRUE
);
2385 if (NT_SUCCESS(ntStatus
))
2387 RtlCopyMemory(pRequest
->Value
, pRequest
->Instance
, sizeof(SYNTH_PORTPARAMS
));
2389 PSYNTH_PORTPARAMS Params
= (PSYNTH_PORTPARAMS
)pRequest
->Value
;
2391 if (Params
->ValidParams
& ~SYNTH_PORTPARAMS_CHANNELGROUPS
)
2393 Params
->ValidParams
&= SYNTH_PORTPARAMS_CHANNELGROUPS
;
2396 if (!(Params
->ValidParams
& SYNTH_PORTPARAMS_CHANNELGROUPS
))
2398 Params
->ChannelGroups
= 1;
2400 else if (Params
->ChannelGroups
!= 1)
2402 Params
->ChannelGroups
= 1;
2405 pRequest
->ValueSize
= sizeof(SYNTH_PORTPARAMS
);
2415 /*****************************************************************************
2417 *****************************************************************************
2418 * The timer DPC callback. Thunks to a C++ member function.
2419 * This is called by the OS in response to the DirectMusic pin
2420 * wanting to wakeup later to process more DirectMusic stuff.
2427 IN PVOID DeferredContext
,
2428 IN PVOID SystemArgument1
,
2429 IN PVOID SystemArgument2
2432 ASSERT(DeferredContext
);
2434 CMiniportDMusUARTStream
*aStream
;
2435 aStream
= (CMiniportDMusUARTStream
*) DeferredContext
;
2438 DPRINT("DMusUARTTimerDPC");
2439 if (false == aStream
->m_fCapture
)
2441 (void) aStream
->ConsumeEvents();
2443 // ignores return value!
2447 /*****************************************************************************
2448 * DirectMusic properties
2449 ****************************************************************************/
2456 * Properties concerning synthesizer functions.
2458 const WCHAR wszDescOut
[] = L
"DMusic MPU-401 Out ";
2459 const WCHAR wszDescIn
[] = L
"DMusic MPU-401 In ";
2461 NTSTATUS PropertyHandler_Synth
2463 IN PPCPROPERTY_REQUEST pRequest
2470 if (pRequest
->Verb
& KSPROPERTY_TYPE_BASICSUPPORT
)
2472 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(ULONG
), TRUE
);
2473 if (NT_SUCCESS(ntStatus
))
2475 // if return buffer can hold a ULONG, return the access flags
2476 PULONG AccessFlags
= PULONG(pRequest
->Value
);
2478 *AccessFlags
= KSPROPERTY_TYPE_BASICSUPPORT
;
2479 switch (pRequest
->PropertyItem
->Id
)
2481 case KSPROPERTY_SYNTH_CAPS
:
2482 case KSPROPERTY_SYNTH_CHANNELGROUPS
:
2483 *AccessFlags
|= KSPROPERTY_TYPE_GET
;
2485 switch (pRequest
->PropertyItem
->Id
)
2487 case KSPROPERTY_SYNTH_CHANNELGROUPS
:
2488 *AccessFlags
|= KSPROPERTY_TYPE_SET
;
2490 ntStatus
= STATUS_SUCCESS
;
2491 pRequest
->ValueSize
= sizeof(ULONG
);
2493 switch (pRequest
->PropertyItem
->Id
)
2495 case KSPROPERTY_SYNTH_PORTPARAMETERS
:
2496 if (pRequest
->MinorTarget
)
2498 *AccessFlags
|= KSPROPERTY_TYPE_GET
;
2502 pRequest
->ValueSize
= 0;
2503 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2510 ntStatus
= STATUS_SUCCESS
;
2511 switch(pRequest
->PropertyItem
->Id
)
2513 case KSPROPERTY_SYNTH_CAPS
:
2514 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CAPS");
2516 if (pRequest
->Verb
& KSPROPERTY_TYPE_SET
)
2518 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2521 if (NT_SUCCESS(ntStatus
))
2523 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(SYNTHCAPS
), TRUE
);
2525 if (NT_SUCCESS(ntStatus
))
2527 SYNTHCAPS
*caps
= (SYNTHCAPS
*)pRequest
->Value
;
2529 RtlZeroMemory(caps
, sizeof(SYNTHCAPS
));
2530 // XXX Different guids for different instances!
2532 if (pRequest
->Node
== eSynthNode
)
2534 increment
= sizeof(wszDescOut
) - 2;
2535 RtlCopyMemory( caps
->Description
,wszDescOut
,increment
);
2536 caps
->Guid
= CLSID_MiniportDriverDMusUART
;
2540 increment
= sizeof(wszDescIn
) - 2;
2541 RtlCopyMemory( caps
->Description
,wszDescIn
,increment
);
2542 caps
->Guid
= CLSID_MiniportDriverDMusUARTCapture
;
2545 caps
->Flags
= SYNTH_PC_EXTERNAL
;
2546 caps
->MemorySize
= 0;
2547 caps
->MaxChannelGroups
= 1;
2548 caps
->MaxVoices
= 0xFFFFFFFF;
2549 caps
->MaxAudioChannels
= 0xFFFFFFFF;
2551 caps
->EffectFlags
= 0;
2553 CMiniportDMusUART
*aMiniport
;
2554 ASSERT(pRequest
->MajorTarget
);
2555 aMiniport
= (CMiniportDMusUART
*)(PMINIPORTDMUS
)(pRequest
->MajorTarget
);
2558 cLen
= swprintf(wszDesc2
,L
"[%03x]\0",PtrToUlong(aMiniport
->m_pPortBase
));
2560 cLen
*= sizeof(WCHAR
);
2561 RtlCopyMemory((WCHAR
*)((DWORD_PTR
)(caps
->Description
) + increment
),
2566 pRequest
->ValueSize
= sizeof(SYNTHCAPS
);
2572 case KSPROPERTY_SYNTH_PORTPARAMETERS
:
2573 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_PORTPARAMETERS");
2575 CMiniportDMusUARTStream
*aStream
;
2577 aStream
= (CMiniportDMusUARTStream
*)(pRequest
->MinorTarget
);
2580 ntStatus
= aStream
->HandlePortParams(pRequest
);
2584 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2589 case KSPROPERTY_SYNTH_CHANNELGROUPS
:
2590 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CHANNELGROUPS");
2592 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(ULONG
), TRUE
);
2593 if (NT_SUCCESS(ntStatus
))
2595 *(PULONG
)(pRequest
->Value
) = 1;
2596 pRequest
->ValueSize
= sizeof(ULONG
);
2600 case KSPROPERTY_SYNTH_LATENCYCLOCK
:
2601 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_LATENCYCLOCK");
2603 if(pRequest
->Verb
& KSPROPERTY_TYPE_SET
)
2605 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2609 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(ULONGLONG
), TRUE
);
2610 if(NT_SUCCESS(ntStatus
))
2612 REFERENCE_TIME rtLatency
;
2613 CMiniportDMusUARTStream
*aStream
;
2615 aStream
= (CMiniportDMusUARTStream
*)(pRequest
->MinorTarget
);
2618 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2622 aStream
->m_pMiniport
->m_MasterClock
->GetTime(&rtLatency
);
2623 *((PULONGLONG
)pRequest
->Value
) = rtLatency
;
2624 pRequest
->ValueSize
= sizeof(ULONGLONG
);
2631 DPRINT("Unhandled property in PropertyHandler_Synth");
2638 /*****************************************************************************
2639 * ValidatePropertyRequest()
2640 *****************************************************************************
2641 * Validates pRequest.
2642 * Checks if the ValueSize is valid
2643 * Checks if the Value is valid
2645 * This does not update pRequest->ValueSize if it returns NT_SUCCESS.
2646 * Caller must set pRequest->ValueSize in case of NT_SUCCESS.
2648 NTSTATUS ValidatePropertyRequest
2650 IN PPCPROPERTY_REQUEST pRequest
,
2651 IN ULONG ulValueSize
,
2652 IN BOOLEAN fValueRequired
2657 if (pRequest
->ValueSize
>= ulValueSize
)
2659 if (fValueRequired
&& NULL
== pRequest
->Value
)
2661 ntStatus
= STATUS_INVALID_PARAMETER
;
2665 ntStatus
= STATUS_SUCCESS
;
2668 else if (0 == pRequest
->ValueSize
)
2670 ntStatus
= STATUS_BUFFER_OVERFLOW
;
2674 ntStatus
= STATUS_BUFFER_TOO_SMALL
;
2677 if (STATUS_BUFFER_OVERFLOW
== ntStatus
)
2679 pRequest
->ValueSize
= ulValueSize
;
2683 pRequest
->ValueSize
= 0;
2687 } // ValidatePropertyRequest