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
;
50 const ULONG kMPUInputBufferSize
= 128;
53 /*****************************************************************************
57 /*****************************************************************************
59 *****************************************************************************
60 * MPU-401 miniport. This object is associated with the device and is
61 * created when the device is started. The class inherits IMiniportDMus
62 * so it can expose this interface and CUnknown so it automatically gets
63 * reference counting and aggregation support.
65 class CMiniportDMusUART
66 : public IMiniportDMus
,
67 public IMusicTechnology
,
71 LONG m_Ref
; // Reference count
72 KSSTATE m_KSStateInput
; // Miniport state (RUN/PAUSE/ACQUIRE/STOP)
73 PPORTDMUS m_pPort
; // Callback interface.
74 PUCHAR m_pPortBase
; // Base port address.
75 PINTERRUPTSYNC m_pInterruptSync
; // Interrupt synchronization object.
76 PSERVICEGROUP m_pServiceGroup
; // Service group for capture.
77 PMASTERCLOCK m_MasterClock
; // for input data
78 REFERENCE_TIME m_InputTimeStamp
; // capture data timestamp
79 USHORT m_NumRenderStreams
; // Num active render streams.
80 USHORT m_NumCaptureStreams
; // Num active capture streams.
81 ULONG m_MPUInputBufferHead
; // Index of the newest byte in the FIFO.
82 ULONG m_MPUInputBufferTail
; // Index of the oldest empty space in the FIFO.
83 GUID m_MusicFormatTechnology
;
84 POWER_STATE m_PowerState
; // Saved power state (D0 = full power, D3 = off)
85 BOOLEAN m_fMPUInitialized
; // Is the MPU HW initialized.
86 BOOLEAN m_UseIRQ
; // FALSE if no IRQ is used for MIDI.
87 UCHAR m_MPUInputBuffer
[kMPUInputBufferSize
]; // Internal SW FIFO.
89 /*************************************************************************
90 * CMiniportDMusUART methods
92 * These are private member functions used internally by the object.
93 * See MINIPORT.CPP for specific descriptions.
95 NTSTATUS ProcessResources
97 IN PRESOURCELIST ResourceList
99 NTSTATUS
InitializeHardware(PINTERRUPTSYNC interruptSync
,PUCHAR portBase
);
102 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
104 STDMETHODIMP_(ULONG
) AddRef()
106 InterlockedIncrement(&m_Ref
);
109 STDMETHODIMP_(ULONG
) Release()
111 InterlockedDecrement(&m_Ref
);
121 CMiniportDMusUART(IUnknown
* Unknown
){}
122 ~CMiniportDMusUART();
124 /*************************************************************************
127 STDMETHODIMP_(NTSTATUS
)
129 ( OUT PPCFILTER_DESCRIPTOR
* OutFilterDescriptor
131 STDMETHODIMP_(NTSTATUS
)
132 DataRangeIntersection
134 , IN PKSDATARANGE DataRange
135 , IN PKSDATARANGE MatchingDataRange
136 , IN ULONG OutputBufferLength
137 , OUT PVOID ResultantFormat
138 , OUT PULONG ResultantFormatLength
141 return STATUS_NOT_IMPLEMENTED
;
144 /*************************************************************************
145 * IMiniportDMus methods
147 STDMETHODIMP_(NTSTATUS
) Init
149 IN PUNKNOWN UnknownAdapter
,
150 IN PRESOURCELIST ResourceList
,
152 OUT PSERVICEGROUP
* ServiceGroup
154 STDMETHODIMP_(NTSTATUS
) NewStream
157 IN PUNKNOWN OuterUnknown OPTIONAL
,
158 IN POOL_TYPE PoolType
,
160 IN DMUS_STREAM_TYPE StreamType
,
161 IN PKSDATAFORMAT DataFormat
,
162 OUT PSERVICEGROUP
* ServiceGroup
,
163 IN PAllocatorMXF AllocatorMXF
,
164 IN PMASTERCLOCK MasterClock
,
165 OUT PULONGLONG SchedulePreFetch
167 STDMETHODIMP_(void) Service
171 /*************************************************************************
172 * IMusicTechnology methods
174 IMP_IMusicTechnology
;
176 /*************************************************************************
177 * IPowerNotify methods
181 /*************************************************************************
184 friend class CMiniportDMusUARTStream
;
186 DMusMPUInterruptServiceRoutine(PINTERRUPTSYNC InterruptSync
,PVOID DynamicContext
);
188 SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync
,PVOID syncWriteContext
);
190 DMusUARTTimerDPC(PKDPC Dpc
,PVOID DeferredContext
,PVOID SystemArgument1
,PVOID SystemArgument2
);
191 friend NTSTATUS NTAPI
PropertyHandler_Synth(IN PPCPROPERTY_REQUEST PropertyRequest
);
192 friend STDMETHODIMP_(NTSTATUS
) SnapTimeStamp(PINTERRUPTSYNC InterruptSync
,PVOID pStream
);
195 /*****************************************************************************
196 * CMiniportDMusUARTStream
197 *****************************************************************************
198 * MPU-401 miniport stream. This object is associated with the pin and is
199 * created when the pin is instantiated. It inherits IMXF
200 * so it can expose this interface and CUnknown so it automatically gets
201 * reference counting and aggregation support.
203 class CMiniportDMusUARTStream
: public IMXF
206 LONG m_Ref
; // Reference Count
207 CMiniportDMusUART
* m_pMiniport
; // Parent.
208 REFERENCE_TIME m_SnapshotTimeStamp
; // Current snapshot of miniport's input timestamp.
209 PUCHAR m_pPortBase
; // Base port address.
210 BOOLEAN m_fCapture
; // Whether this is capture.
211 long m_NumFailedMPUTries
; // Deadman timeout for MPU hardware.
212 PAllocatorMXF m_AllocatorMXF
; // source/sink for DMus structs
213 PMXF m_sinkMXF
; // sink for DMus capture
214 PDMUS_KERNEL_EVENT m_DMKEvtQueue
; // queue of waiting events
215 ULONG m_NumberOfRetries
; // Number of consecutive times the h/w was busy/full
216 ULONG m_DMKEvtOffset
; // offset into the event
217 KDPC m_Dpc
; // DPC for timer
218 KTIMER m_TimerEvent
; // timer
219 BOOL m_TimerQueued
; // whether a timer has been set
220 KSPIN_LOCK m_DpcSpinLock
; // protects the ConsumeEvents DPC
222 STDMETHODIMP_(NTSTATUS
) SourceEvtsToPort();
223 STDMETHODIMP_(NTSTATUS
) ConsumeEvents();
224 STDMETHODIMP_(NTSTATUS
) PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt
);
227 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
229 STDMETHODIMP_(ULONG
) AddRef()
231 InterlockedIncrement(&m_Ref
);
234 STDMETHODIMP_(ULONG
) Release()
236 InterlockedDecrement(&m_Ref
);
246 ~CMiniportDMusUARTStream();
248 STDMETHODIMP_(NTSTATUS
) Init
250 IN CMiniportDMusUART
* pMiniport
,
253 IN PAllocatorMXF allocatorMXF
,
254 IN PMASTERCLOCK masterClock
257 NTSTATUS HandlePortParams
259 IN PPCPROPERTY_REQUEST Request
262 /*************************************************************************
263 * IMiniportStreamDMusUART methods
267 STDMETHODIMP_(NTSTATUS
) Write
269 IN PVOID BufferAddress
,
270 IN ULONG BytesToWrite
,
271 OUT PULONG BytesWritten
278 IN PVOID DeferredContext
,
279 IN PVOID SystemArgument1
,
280 IN PVOID SystemArgument2
282 friend NTSTATUS
PropertyHandler_Synth(IN PPCPROPERTY_REQUEST
);
283 friend STDMETHODIMP_(NTSTATUS
) SnapTimeStamp(PINTERRUPTSYNC InterruptSync
,PVOID pStream
);
288 #define STR_MODULENAME "DMusUART:Miniport: "
291 #pragma code_seg("PAGE")
294 #define UartFifoOkForWrite(status) ((status & MPU401_DRR) == 0)
295 #define UartFifoOkForRead(status) ((status & MPU401_DSR) == 0)
299 CMiniportDMusUART
*Miniport
;
305 SYNCWRITECONTEXT
, *PSYNCWRITECONTEXT
;
307 /*****************************************************************************
308 * PinDataRangesStreamLegacy
309 * PinDataRangesStreamDMusic
310 *****************************************************************************
311 * Structures indicating range of valid format values for live pins.
314 KSDATARANGE_MUSIC PinDataRangesStreamLegacy
=
318 sizeof(KSDATARANGE_MUSIC
),
322 {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC
)},
323 {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI
)},
324 {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE
)}
327 {STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT
)},
333 KSDATARANGE_MUSIC PinDataRangesStreamDMusic
=
337 sizeof(KSDATARANGE_MUSIC
),
341 {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC
)},
342 {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_DIRECTMUSIC
)},
343 {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE
)}
346 {STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT
)},
352 /*****************************************************************************
353 * PinDataRangePointersStreamLegacy
354 * PinDataRangePointersStreamDMusic
355 * PinDataRangePointersStreamCombined
356 *****************************************************************************
357 * List of pointers to structures indicating range of valid format values
361 PKSDATARANGE PinDataRangePointersStreamLegacy
[] =
363 PKSDATARANGE(&PinDataRangesStreamLegacy
)
366 PKSDATARANGE PinDataRangePointersStreamDMusic
[] =
368 PKSDATARANGE(&PinDataRangesStreamDMusic
)
371 PKSDATARANGE PinDataRangePointersStreamCombined
[] =
373 PKSDATARANGE(&PinDataRangesStreamLegacy
)
374 ,PKSDATARANGE(&PinDataRangesStreamDMusic
)
377 /*****************************************************************************
378 * PinDataRangesBridge
379 *****************************************************************************
380 * Structures indicating range of valid format values for bridge pins.
383 KSDATARANGE PinDataRangesBridge
[] =
391 {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC
)},
392 {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI_BUS
)},
393 {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE
)}
398 /*****************************************************************************
399 * PinDataRangePointersBridge
400 *****************************************************************************
401 * List of pointers to structures indicating range of valid format values
405 PKSDATARANGE PinDataRangePointersBridge
[] =
407 &PinDataRangesBridge
[0]
410 /*****************************************************************************
412 *****************************************************************************
413 * List of properties in the Synth set.
419 // Global: S/Get synthesizer caps
422 KSPROPERTY_SYNTH_CAPS
,
423 KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_BASICSUPPORT
,
424 PropertyHandler_Synth
426 // Global: S/Get port parameters
429 KSPROPERTY_SYNTH_PORTPARAMETERS
,
430 KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_BASICSUPPORT
,
431 PropertyHandler_Synth
433 // Per stream: S/Get channel groups
436 KSPROPERTY_SYNTH_CHANNELGROUPS
,
437 KSPROPERTY_TYPE_SET
| KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_BASICSUPPORT
,
438 PropertyHandler_Synth
440 // Per stream: Get current latency time
443 KSPROPERTY_SYNTH_LATENCYCLOCK
,
444 KSPROPERTY_TYPE_GET
| KSPROPERTY_TYPE_BASICSUPPORT
,
445 PropertyHandler_Synth
448 DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth
, SynthProperties
);
449 DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth2
, SynthProperties
);
451 #define kMaxNumCaptureStreams 1
452 #define kMaxNumLegacyRenderStreams 1
453 #define kMaxNumDMusicRenderStreams 1
455 /*****************************************************************************
457 *****************************************************************************
461 PCPIN_DESCRIPTOR MiniportPins
[] =
464 kMaxNumLegacyRenderStreams
,kMaxNumLegacyRenderStreams
,0, // InstanceCount
465 NULL
, // AutomationTable
467 0, // InterfacesCount
471 SIZEOF_ARRAY(PinDataRangePointersStreamLegacy
), // DataRangesCount
472 PinDataRangePointersStreamLegacy
, // DataRanges
473 KSPIN_DATAFLOW_IN
, // DataFlow
474 KSPIN_COMMUNICATION_SINK
, // Communication
475 (GUID
*) &KSCATEGORY_AUDIO
, // Category
476 &KSAUDFNAME_MIDI
, // Name
481 kMaxNumDMusicRenderStreams
,kMaxNumDMusicRenderStreams
,0, // InstanceCount
482 NULL
, // AutomationTable
484 0, // InterfacesCount
488 SIZEOF_ARRAY(PinDataRangePointersStreamDMusic
), // DataRangesCount
489 PinDataRangePointersStreamDMusic
, // DataRanges
490 KSPIN_DATAFLOW_IN
, // DataFlow
491 KSPIN_COMMUNICATION_SINK
, // Communication
492 (GUID
*) &KSCATEGORY_AUDIO
, // Category
493 &KSAUDFNAME_DMUSIC_MPU_OUT
, // Name
498 0,0,0, // InstanceCount
499 NULL
, // AutomationTable
501 0, // InterfacesCount
505 SIZEOF_ARRAY(PinDataRangePointersBridge
), // DataRangesCount
506 PinDataRangePointersBridge
, // DataRanges
507 KSPIN_DATAFLOW_OUT
, // DataFlow
508 KSPIN_COMMUNICATION_NONE
, // Communication
509 (GUID
*) &KSCATEGORY_AUDIO
, // Category
515 0,0,0, // InstanceCount
516 NULL
, // AutomationTable
518 0, // InterfacesCount
522 SIZEOF_ARRAY(PinDataRangePointersBridge
), // DataRangesCount
523 PinDataRangePointersBridge
, // DataRanges
524 KSPIN_DATAFLOW_IN
, // DataFlow
525 KSPIN_COMMUNICATION_NONE
, // Communication
526 (GUID
*) &KSCATEGORY_AUDIO
, // Category
532 kMaxNumCaptureStreams
,kMaxNumCaptureStreams
,0, // InstanceCount
533 NULL
, // AutomationTable
535 0, // InterfacesCount
539 SIZEOF_ARRAY(PinDataRangePointersStreamCombined
), // DataRangesCount
540 PinDataRangePointersStreamCombined
, // DataRanges
541 KSPIN_DATAFLOW_OUT
, // DataFlow
542 KSPIN_COMMUNICATION_SINK
, // Communication
543 (GUID
*) &KSCATEGORY_AUDIO
, // Category
544 &KSAUDFNAME_DMUSIC_MPU_IN
, // Name
550 /*****************************************************************************
552 *****************************************************************************
555 #define CONST_PCNODE_DESCRIPTOR(n) { 0, NULL, &n, NULL }
556 #define CONST_PCNODE_DESCRIPTOR_AUTO(n,a) { 0, &a, &n, NULL }
558 PCNODE_DESCRIPTOR MiniportNodes
[] =
560 CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER
, AutomationSynth
)
561 , CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER
, AutomationSynth2
)
564 /*****************************************************************************
565 * MiniportConnections
566 *****************************************************************************
567 * List of connections.
575 eFilterInputPinLeg
= 0,
583 PCCONNECTION_DESCRIPTOR MiniportConnections
[] =
586 { PCFILTER_NODE
, eFilterInputPinLeg
, PCFILTER_NODE
, eBridgeOutputPin
} // Legacy Stream in to synth.
587 , { PCFILTER_NODE
, eFilterInputPinDM
, eSynthNode
, KSNODEPIN_STANDARD_IN
} // DM Stream in to synth.
588 , { eSynthNode
, KSNODEPIN_STANDARD_OUT
, PCFILTER_NODE
, eBridgeOutputPin
} // Synth to bridge out.
589 , { PCFILTER_NODE
, eBridgeInputPin
, eInputNode
, KSNODEPIN_STANDARD_IN
} // Bridge in to input.
590 , { eInputNode
, KSNODEPIN_STANDARD_OUT
, PCFILTER_NODE
, eFilterOutputPin
} // Input to DM/Legacy Stream out.
593 /*****************************************************************************
595 *****************************************************************************
596 * List of categories.
599 GUID MiniportCategories
[] =
601 {STATICGUIDOF(KSCATEGORY_AUDIO
)},
602 {STATICGUIDOF(KSCATEGORY_RENDER
)},
603 {STATICGUIDOF(KSCATEGORY_CAPTURE
)}
606 /*****************************************************************************
607 * MiniportFilterDescriptor
608 *****************************************************************************
609 * Complete miniport filter description.
612 PCFILTER_DESCRIPTOR MiniportFilterDescriptor
=
615 NULL
, // AutomationTable
616 sizeof(PCPIN_DESCRIPTOR
), // PinSize
617 SIZEOF_ARRAY(MiniportPins
), // PinCount
618 MiniportPins
, // Pins
619 sizeof(PCNODE_DESCRIPTOR
), // NodeSize
620 SIZEOF_ARRAY(MiniportNodes
), // NodeCount
621 MiniportNodes
, // Nodes
622 SIZEOF_ARRAY(MiniportConnections
), // ConnectionCount
623 MiniportConnections
, // Connections
624 SIZEOF_ARRAY(MiniportCategories
), // CategoryCount
625 MiniportCategories
// Categories
629 #pragma code_seg("PAGE")
632 BOOLEAN
TryMPU(IN PUCHAR PortBase
);
633 NTSTATUS
WriteMPU(IN PUCHAR PortBase
,IN BOOLEAN IsCommand
,IN UCHAR Value
);
636 #pragma code_seg("PAGE")
639 // make sure we're in UART mode
640 NTSTATUS
ResetHardware(PUCHAR portBase
)
644 return WriteMPU(portBase
,COMMAND
,MPU401_CMD_UART
);
648 #pragma code_seg("PAGE")
652 // We initialize the UART with interrupts suppressed so we don't
653 // try to service the chip prematurely.
655 NTSTATUS
CMiniportDMusUART::InitializeHardware(PINTERRUPTSYNC interruptSync
,PUCHAR portBase
)
662 ntStatus
= interruptSync
->CallSynchronizedRoutine(InitMPU
,PVOID(portBase
));
666 ntStatus
= InitMPU(NULL
,PVOID(portBase
));
669 if (NT_SUCCESS(ntStatus
))
672 // Start the UART (this should trigger an interrupt).
674 ntStatus
= ResetHardware(portBase
);
678 DPRINT("*** InitMPU returned with ntStatus 0x%08x ***", ntStatus
);
681 m_fMPUInitialized
= NT_SUCCESS(ntStatus
);
690 /*****************************************************************************
692 *****************************************************************************
693 * Synchronized routine to initialize the MPU401.
698 IN PINTERRUPTSYNC InterruptSync
,
699 IN PVOID DynamicContext
705 return STATUS_INVALID_PARAMETER_2
;
708 PUCHAR portBase
= PUCHAR(DynamicContext
);
712 NTSTATUS ntStatus
= STATUS_SUCCESS
;
715 // Reset the card (puts it into "smart mode")
717 ntStatus
= WriteMPU(portBase
,COMMAND
,MPU401_CMD_RESET
);
719 // wait for the acknowledgement
720 // NOTE: When the Ack arrives, it will trigger an interrupt.
721 // Normally the DPC routine would read in the ack byte and we
722 // would never see it, however since we have the hardware locked (HwEnter),
723 // we can read the port before the DPC can and thus we receive the Ack.
724 startTime
= PcGetTimeInterval(0);
726 while(PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
728 status
= READ_PORT_UCHAR(portBase
+ MPU401_REG_STATUS
);
730 if (UartFifoOkForRead(status
)) // Is data waiting?
732 READ_PORT_UCHAR(portBase
+ MPU401_REG_DATA
); // yep.. read ACK
733 success
= TRUE
; // don't need to do more
736 KeStallExecutionProcessor(25); // microseconds
741 DPRINT("First attempt to reset the MPU didn't get ACKed.\n");
745 // NOTE: We cannot check the ACK byte because if the card was already in
746 // UART mode it will not send an ACK but it will reset.
748 // reset the card again
749 (void) WriteMPU(portBase
,COMMAND
,MPU401_CMD_RESET
);
751 // wait for ack (again)
752 startTime
= PcGetTimeInterval(0); // This might take a while
755 while (PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
757 status
= READ_PORT_UCHAR(portBase
+ MPU401_REG_STATUS
);
758 if (UartFifoOkForRead(status
)) // Is data waiting?
760 dataByte
= READ_PORT_UCHAR(portBase
+ MPU401_REG_DATA
); // yep.. read ACK
761 success
= TRUE
; // don't need to do more
764 KeStallExecutionProcessor(25);
767 if ((0xFE != dataByte
) || !success
) // Did we succeed? If no second ACK, something is hosed
769 DPRINT("Second attempt to reset the MPU didn't get ACKed.\n");
770 DPRINT("Init Reset failure error. Ack = %X", ULONG(dataByte
));
772 ntStatus
= STATUS_IO_DEVICE_ERROR
;
782 /*****************************************************************************
783 * CMiniportDMusUARTStream::Write()
784 *****************************************************************************
785 * Writes outgoing MIDI data.
787 STDMETHODIMP_(NTSTATUS
)
788 CMiniportDMusUARTStream::
791 IN PVOID BufferAddress
,
793 OUT PULONG BytesWritten
797 ASSERT(BytesWritten
);
803 NTSTATUS ntStatus
= STATUS_SUCCESS
;
811 pMidiData
= PUCHAR(BufferAddress
);
815 SYNCWRITECONTEXT context
;
816 context
.Miniport
= (m_pMiniport
);
817 context
.PortBase
= m_pPortBase
;
818 context
.BufferAddress
= pMidiData
;
819 context
.Length
= Length
;
820 context
.BytesRead
= &count
;
822 if (m_pMiniport
->m_UseIRQ
)
824 ntStatus
= m_pMiniport
->m_pInterruptSync
->
825 CallSynchronizedRoutine(SynchronizedDMusMPUWrite
,PVOID(&context
));
829 ntStatus
= SynchronizedDMusMPUWrite(NULL
,PVOID(&context
));
834 m_NumFailedMPUTries
++;
835 if (m_NumFailedMPUTries
>= 100)
837 ntStatus
= STATUS_IO_DEVICE_ERROR
;
838 m_NumFailedMPUTries
= 0;
843 m_NumFailedMPUTries
= 0;
845 } // if we have data at all
846 *BytesWritten
= count
;
848 else // called write on the read stream
850 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
859 /*****************************************************************************
860 * SynchronizedDMusMPUWrite()
861 *****************************************************************************
862 * Writes outgoing MIDI data.
865 SynchronizedDMusMPUWrite
867 IN PINTERRUPTSYNC InterruptSync
,
868 IN PVOID syncWriteContext
871 PSYNCWRITECONTEXT context
;
872 context
= (PSYNCWRITECONTEXT
)syncWriteContext
;
873 ASSERT(context
->Miniport
);
874 ASSERT(context
->PortBase
);
875 ASSERT(context
->BufferAddress
);
876 ASSERT(context
->Length
);
877 ASSERT(context
->BytesRead
);
879 PUCHAR pChar
= PUCHAR(context
->BufferAddress
);
880 NTSTATUS ntStatus
,readStatus
;
881 ntStatus
= STATUS_SUCCESS
;
883 // while we're not there yet, and
884 // while we don't have to wait on an aligned byte (including 0)
885 // (we never wait on a byte. Better to come back later)
886 readStatus
= DMusMPUInterruptServiceRoutine(InterruptSync
,PVOID(context
->Miniport
));
887 while ( (*(context
->BytesRead
) < context
->Length
)
888 && ( TryMPU(context
->PortBase
)
889 || (*(context
->BytesRead
)%3)
892 ntStatus
= WriteMPU(context
->PortBase
,DATA
,*pChar
);
893 if (NT_SUCCESS(ntStatus
))
896 *(context
->BytesRead
) = *(context
->BytesRead
) + 1;
897 // readStatus = DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport));
901 DPRINT("SynchronizedDMusMPUWrite failed (0x%08x)",ntStatus
);
905 readStatus
= DMusMPUInterruptServiceRoutine(InterruptSync
,PVOID(context
->Miniport
));
909 #define kMPUPollTimeout 2
915 /*****************************************************************************
917 *****************************************************************************
918 * See if the MPU401 is free.
933 while (numPolls
< kMPUPollTimeout
)
935 status
= READ_PORT_UCHAR(PortBase
+ MPU401_REG_STATUS
);
937 if (UartFifoOkForWrite(status
)) // Is this a good time to write data?
943 if (numPolls
>= kMPUPollTimeout
)
946 DPRINT("TryMPU failed");
960 /*****************************************************************************
962 *****************************************************************************
963 * Write a byte out to the MPU401.
969 IN BOOLEAN IsCommand
,
974 NTSTATUS ntStatus
= STATUS_IO_DEVICE_ERROR
;
978 DPRINT("O: PortBase is zero\n");
981 PUCHAR deviceAddr
= PortBase
+ MPU401_REG_DATA
;
985 deviceAddr
= PortBase
+ MPU401_REG_COMMAND
;
988 ULONGLONG startTime
= PcGetTimeInterval(0);
990 while (PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
993 = READ_PORT_UCHAR(PortBase
+ MPU401_REG_STATUS
);
995 if (UartFifoOkForWrite(status
)) // Is this a good time to write data?
996 { // yep (Jon comment)
997 WRITE_PORT_UCHAR(deviceAddr
,Value
);
998 DPRINT("WriteMPU emitted 0x%02x",Value
);
999 ntStatus
= STATUS_SUCCESS
;
1010 /*****************************************************************************
1012 *****************************************************************************
1014 * At synchronized execution to ISR, copy miniport's volatile m_InputTimeStamp
1015 * to stream's m_SnapshotTimeStamp and zero m_InputTimeStamp.
1018 STDMETHODIMP_(NTSTATUS
)
1019 SnapTimeStamp(PINTERRUPTSYNC InterruptSync
,PVOID pStream
)
1021 CMiniportDMusUARTStream
*pMPStream
= (CMiniportDMusUARTStream
*)pStream
;
1023 // cache the timestamp
1024 pMPStream
->m_SnapshotTimeStamp
= pMPStream
->m_pMiniport
->m_InputTimeStamp
;
1026 // if the window is closed, zero the timestamp
1027 if (pMPStream
->m_pMiniport
->m_MPUInputBufferHead
==
1028 pMPStream
->m_pMiniport
->m_MPUInputBufferTail
)
1030 pMPStream
->m_pMiniport
->m_InputTimeStamp
= 0;
1033 return STATUS_SUCCESS
;
1036 /*****************************************************************************
1037 * CMiniportDMusUARTStream::SourceEvtsToPort()
1038 *****************************************************************************
1040 * Reads incoming MIDI data, feeds into DMus events.
1041 * No need to touch the hardware, just read from our SW FIFO.
1044 STDMETHODIMP_(NTSTATUS
)
1045 CMiniportDMusUARTStream::SourceEvtsToPort()
1049 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1050 DPRINT("SourceEvtsToPort");
1054 ntStatus
= STATUS_SUCCESS
;
1055 if (m_pMiniport
->m_MPUInputBufferHead
!= m_pMiniport
->m_MPUInputBufferTail
)
1057 PDMUS_KERNEL_EVENT aDMKEvt
,eventTail
,eventHead
= NULL
;
1059 while (m_pMiniport
->m_MPUInputBufferHead
!= m_pMiniport
->m_MPUInputBufferTail
)
1061 (void) m_AllocatorMXF
->GetMessage(&aDMKEvt
);
1064 DPRINT("SourceEvtsToPort can't allocate DMKEvt");
1065 return STATUS_INSUFFICIENT_RESOURCES
;
1068 // put this event at the end of the list
1071 eventHead
= aDMKEvt
;
1075 eventTail
= eventHead
;
1076 while (eventTail
->pNextEvt
)
1078 eventTail
= eventTail
->pNextEvt
;
1080 eventTail
->pNextEvt
= aDMKEvt
;
1082 // read all the bytes out of the buffer, into event(s)
1083 for (aDMKEvt
->cbEvent
= 0; aDMKEvt
->cbEvent
< sizeof(PBYTE
); aDMKEvt
->cbEvent
++)
1085 if (m_pMiniport
->m_MPUInputBufferHead
== m_pMiniport
->m_MPUInputBufferTail
)
1087 // _DbgPrintF(DEBUGLVL_TERSE, ("SourceEvtsToPort m_MPUInputBufferHead met m_MPUInputBufferTail, overrun"));
1090 aDMKEvt
->uData
.abData
[aDMKEvt
->cbEvent
] = m_pMiniport
->m_MPUInputBuffer
[m_pMiniport
->m_MPUInputBufferHead
];
1091 m_pMiniport
->m_MPUInputBufferHead
++;
1092 if (m_pMiniport
->m_MPUInputBufferHead
>= kMPUInputBufferSize
)
1094 m_pMiniport
->m_MPUInputBufferHead
= 0;
1099 if (m_pMiniport
->m_UseIRQ
)
1101 ntStatus
= m_pMiniport
->m_pInterruptSync
->CallSynchronizedRoutine(SnapTimeStamp
,PVOID(this));
1105 ntStatus
= SnapTimeStamp(NULL
,PVOID(this));
1107 aDMKEvt
= eventHead
;
1110 aDMKEvt
->ullPresTime100ns
= m_SnapshotTimeStamp
;
1111 aDMKEvt
->usChannelGroup
= 1;
1112 aDMKEvt
->usFlags
= DMUS_KEF_EVENT_INCOMPLETE
;
1113 aDMKEvt
= aDMKEvt
->pNextEvt
;
1115 (void)m_sinkMXF
->PutMessage(eventHead
);
1118 else // render stream
1120 DPRINT("SourceEvtsToPort called on render stream");
1121 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
1130 /*****************************************************************************
1131 * DMusMPUInterruptServiceRoutine()
1132 *****************************************************************************
1136 DMusMPUInterruptServiceRoutine
1138 IN PINTERRUPTSYNC InterruptSync
,
1139 IN PVOID DynamicContext
1142 DPRINT("DMusMPUInterruptServiceRoutine");
1143 ULONGLONG startTime
;
1145 ASSERT(DynamicContext
);
1148 BOOL newBytesAvailable
;
1149 CMiniportDMusUART
*that
;
1150 NTSTATUS clockStatus
;
1152 that
= (CMiniportDMusUART
*) DynamicContext
;
1153 newBytesAvailable
= FALSE
;
1154 ntStatus
= STATUS_UNSUCCESSFUL
;
1156 UCHAR portStatus
= 0xff;
1159 // Read the MPU status byte.
1161 if (that
->m_pPortBase
)
1164 READ_PORT_UCHAR(that
->m_pPortBase
+ MPU401_REG_STATUS
);
1167 // If there is outstanding work to do and there is a port-driver for
1168 // the MPU miniport...
1170 if (UartFifoOkForRead(portStatus
) && that
->m_pPort
)
1172 startTime
= PcGetTimeInterval(0);
1173 while ( (PcGetTimeInterval(startTime
) < GTI_MILLISECONDS(50))
1174 && (UartFifoOkForRead(portStatus
)) )
1176 UCHAR uDest
= READ_PORT_UCHAR(that
->m_pPortBase
+ MPU401_REG_DATA
);
1177 if ( (that
->m_KSStateInput
== KSSTATE_RUN
)
1178 && (that
->m_NumCaptureStreams
)
1181 ULONG buffHead
= that
->m_MPUInputBufferHead
;
1182 if ( (that
->m_MPUInputBufferTail
+ 1 == buffHead
)
1183 || (that
->m_MPUInputBufferTail
+ 1 - kMPUInputBufferSize
== buffHead
))
1185 DPRINT("*****MPU Input Buffer Overflow*****");
1189 if (!that
->m_InputTimeStamp
)
1191 clockStatus
= that
->m_MasterClock
->GetTime(&that
->m_InputTimeStamp
);
1192 if (STATUS_SUCCESS
!= clockStatus
)
1194 DPRINT("GetTime failed for clock 0x%08x",that
->m_MasterClock
);
1197 newBytesAvailable
= TRUE
;
1198 // ...place the data in our FIFO...
1199 that
->m_MPUInputBuffer
[that
->m_MPUInputBufferTail
] = uDest
;
1200 ASSERT(that
->m_MPUInputBufferTail
< kMPUInputBufferSize
);
1202 that
->m_MPUInputBufferTail
++;
1203 if (that
->m_MPUInputBufferTail
>= kMPUInputBufferSize
)
1205 that
->m_MPUInputBufferTail
= 0;
1210 // Look for more MIDI data.
1213 READ_PORT_UCHAR(that
->m_pPortBase
+ MPU401_REG_STATUS
);
1214 } // either there's no data or we ran too long
1215 if (newBytesAvailable
)
1218 // ...notify the MPU port driver that we have bytes.
1220 that
->m_pPort
->Notify(that
->m_pServiceGroup
);
1222 ntStatus
= STATUS_SUCCESS
;
1229 /*****************************************************************************
1230 * CMiniportDMusUART::GetDescription()
1231 *****************************************************************************
1232 * Gets the topology.
1234 STDMETHODIMP_(NTSTATUS
)
1238 OUT PPCFILTER_DESCRIPTOR
* OutFilterDescriptor
1243 ASSERT(OutFilterDescriptor
);
1245 DPRINT("GetDescription");
1247 *OutFilterDescriptor
= &MiniportFilterDescriptor
;
1249 return STATUS_SUCCESS
;
1253 #pragma code_seg("PAGE")
1257 NewMiniportDMusUART(
1258 OUT PMINIPORT
* OutMiniport
,
1259 IN REFCLSID ClassId
)
1261 CMiniportDMusUART
* This
;
1264 This
= new(NonPagedPool
, TAG_PORTCLASS
) CMiniportDMusUART(NULL
);
1266 return STATUS_INSUFFICIENT_RESOURCES
;
1268 Status
= This
->QueryInterface(IID_IMiniport
, (PVOID
*)OutMiniport
);
1270 if (!NT_SUCCESS(Status
))
1275 DPRINT("NewMiniportDMusUART %p Status %x\n", *OutMiniport
, Status
);
1281 #pragma code_seg("PAGE")
1284 /*****************************************************************************
1285 * CMiniportDMusUART::ProcessResources()
1286 *****************************************************************************
1287 * Processes the resource list, setting up helper objects accordingly.
1293 IN PRESOURCELIST ResourceList
1298 DPRINT("ProcessResources");
1300 ASSERT(ResourceList
);
1303 return STATUS_DEVICE_CONFIGURATION_ERROR
;
1306 // Get counts for the types of resources.
1308 ULONG countIO
= ResourceList
->NumberOfPorts();
1309 ULONG countIRQ
= ResourceList
->NumberOfInterrupts();
1310 ULONG countDMA
= ResourceList
->NumberOfDmas();
1311 ULONG lengthIO
= ResourceList
->FindTranslatedPort(0)->u
.Port
.Length
;
1314 DPRINT("Starting MPU401 Port 0x%lx", ResourceList
->FindTranslatedPort(0)->u
.Port
.Start
.LowPart
);
1317 NTSTATUS ntStatus
= STATUS_SUCCESS
;
1320 // Make sure we have the expected number of resources.
1328 DPRINT("Unknown ResourceList configuraton");
1329 ntStatus
= STATUS_DEVICE_CONFIGURATION_ERROR
;
1332 if (NT_SUCCESS(ntStatus
))
1335 // Get the port address.
1338 PUCHAR(ResourceList
->FindTranslatedPort(0)->u
.Port
.Start
.QuadPart
);
1340 ntStatus
= InitializeHardware(m_pInterruptSync
,m_pPortBase
);
1347 #pragma code_seg("PAGE")
1349 /*****************************************************************************
1350 * CMiniportDMusUART::NonDelegatingQueryInterface()
1351 *****************************************************************************
1352 * Obtains an interface. This function works just like a COM QueryInterface
1353 * call and is used if the object is not being aggregated.
1355 STDMETHODIMP_(NTSTATUS
)
1356 CMiniportDMusUART::QueryInterface
1364 DPRINT("Miniport::NonDelegatingQueryInterface");
1367 if (IsEqualGUIDAligned(Interface
,IID_IUnknown
))
1369 *Object
= PVOID(PUNKNOWN(PMINIPORTDMUS(this)));
1372 if (IsEqualGUIDAligned(Interface
,IID_IMiniport
))
1374 *Object
= PVOID(PMINIPORT(this));
1377 if (IsEqualGUIDAligned(Interface
,IID_IMiniportDMus
))
1379 *Object
= PVOID(PMINIPORTDMUS(this));
1382 if (IsEqualGUIDAligned(Interface
,IID_IMusicTechnology
))
1384 *Object
= PVOID(PMUSICTECHNOLOGY(this));
1387 if (IsEqualGUIDAligned(Interface
,IID_IPowerNotify
))
1389 *Object
= PVOID(PPOWERNOTIFY(this));
1399 // We reference the interface for the caller.
1401 PUNKNOWN(*Object
)->AddRef();
1402 return STATUS_SUCCESS
;
1405 return STATUS_INVALID_PARAMETER
;
1409 #pragma code_seg("PAGE")
1411 /*****************************************************************************
1412 * CMiniportDMusUART::~CMiniportDMusUART()
1413 *****************************************************************************
1416 CMiniportDMusUART::~CMiniportDMusUART(void)
1420 DPRINT("~CMiniportDMusUART");
1422 ASSERT(0 == m_NumCaptureStreams
);
1423 ASSERT(0 == m_NumRenderStreams
);
1425 // reset the HW so we don't get anymore interrupts
1426 if (m_UseIRQ
&& m_pInterruptSync
)
1428 (void) m_pInterruptSync
->CallSynchronizedRoutine((PINTERRUPTSYNCROUTINE
)InitMPU
,PVOID(m_pPortBase
));
1432 (void) InitMPU(NULL
,PVOID(m_pPortBase
));
1435 if (m_pInterruptSync
)
1437 m_pInterruptSync
->Release();
1438 m_pInterruptSync
= NULL
;
1440 if (m_pServiceGroup
)
1442 m_pServiceGroup
->Release();
1443 m_pServiceGroup
= NULL
;
1453 #pragma code_seg("PAGE")
1455 /*****************************************************************************
1456 * CMiniportDMusUART::Init()
1457 *****************************************************************************
1458 * Initializes a the miniport.
1460 STDMETHODIMP_(NTSTATUS
)
1464 IN PUNKNOWN UnknownInterruptSync OPTIONAL
,
1465 IN PRESOURCELIST ResourceList
,
1467 OUT PSERVICEGROUP
* ServiceGroup
1472 ASSERT(ResourceList
);
1475 return STATUS_DEVICE_CONFIGURATION_ERROR
;
1479 ASSERT(ServiceGroup
);
1483 *ServiceGroup
= NULL
;
1485 m_fMPUInitialized
= FALSE
;
1487 // This will remain unspecified if the miniport does not get any power
1490 m_PowerState
.DeviceState
= PowerDeviceUnspecified
;
1493 // AddRef() is required because we are keeping this pointer.
1500 if (IsEqualGUIDAligned(m_MusicFormatTechnology
, GUID_NULL
))
1502 RtlCopyMemory( &m_MusicFormatTechnology
,
1503 &KSMUSIC_TECHNOLOGY_PORT
,
1506 RtlCopyMemory( &PinDataRangesStreamLegacy
.Technology
,
1507 &m_MusicFormatTechnology
,
1509 RtlCopyMemory( &PinDataRangesStreamDMusic
.Technology
,
1510 &m_MusicFormatTechnology
,
1513 for (ULONG bufferCount
= 0;bufferCount
< kMPUInputBufferSize
;bufferCount
++)
1515 m_MPUInputBuffer
[bufferCount
] = 0;
1517 m_MPUInputBufferHead
= 0;
1518 m_MPUInputBufferTail
= 0;
1519 m_InputTimeStamp
= 0;
1520 m_KSStateInput
= KSSTATE_STOP
;
1522 NTSTATUS ntStatus
= STATUS_SUCCESS
;
1524 m_NumRenderStreams
= 0;
1525 m_NumCaptureStreams
= 0;
1528 if (ResourceList
->NumberOfInterrupts() == 0)
1533 ntStatus
= PcNewServiceGroup(&m_pServiceGroup
,NULL
);
1534 if (NT_SUCCESS(ntStatus
) && !m_pServiceGroup
) // keep any error
1536 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1539 if (NT_SUCCESS(ntStatus
))
1541 *ServiceGroup
= m_pServiceGroup
;
1542 m_pServiceGroup
->AddRef();
1545 // Register the service group with the port early so the port is
1546 // prepared to handle interrupts.
1548 m_pPort
->RegisterServiceGroup(m_pServiceGroup
);
1551 if (NT_SUCCESS(ntStatus
) && m_UseIRQ
)
1554 // Due to a bug in the InterruptSync design, we shouldn't share
1555 // the interrupt sync object. Whoever goes away first
1556 // will disconnect it, and the other points off into nowhere.
1558 // Instead we generate our own interrupt sync object.
1560 UnknownInterruptSync
= NULL
;
1562 if (UnknownInterruptSync
)
1565 UnknownInterruptSync
->QueryInterface
1568 (PVOID
*) &m_pInterruptSync
1571 if (!m_pInterruptSync
&& NT_SUCCESS(ntStatus
)) // keep any error
1573 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1575 if (NT_SUCCESS(ntStatus
))
1576 { // run this ISR first
1577 ntStatus
= m_pInterruptSync
->
1578 RegisterServiceRoutine(DMusMPUInterruptServiceRoutine
,PVOID(this),TRUE
);
1583 { // create our own interruptsync mechanism.
1590 0, // Resource Index
1591 InterruptSyncModeNormal
// Run ISRs once until we get SUCCESS
1594 if (!m_pInterruptSync
&& NT_SUCCESS(ntStatus
)) // keep any error
1596 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1599 if (NT_SUCCESS(ntStatus
))
1601 ntStatus
= m_pInterruptSync
->RegisterServiceRoutine(
1602 DMusMPUInterruptServiceRoutine
,
1604 TRUE
); // run this ISR first
1606 if (NT_SUCCESS(ntStatus
))
1608 ntStatus
= m_pInterruptSync
->Connect();
1613 if (NT_SUCCESS(ntStatus
))
1615 ntStatus
= ProcessResources(ResourceList
);
1618 if (!NT_SUCCESS(ntStatus
))
1621 // clean up our mess
1624 // clean up the interrupt sync
1625 if( m_pInterruptSync
)
1627 m_pInterruptSync
->Release();
1628 m_pInterruptSync
= NULL
;
1631 // clean up the service group
1632 if( m_pServiceGroup
)
1634 m_pServiceGroup
->Release();
1635 m_pServiceGroup
= NULL
;
1638 // clean up the out param service group.
1641 (*ServiceGroup
)->Release();
1642 (*ServiceGroup
) = NULL
;
1654 #pragma code_seg("PAGE")
1656 /*****************************************************************************
1657 * CMiniportDMusUART::NewStream()
1658 *****************************************************************************
1659 * Gets the topology.
1661 STDMETHODIMP_(NTSTATUS
)
1666 IN PUNKNOWN OuterUnknown OPTIONAL
,
1667 IN POOL_TYPE PoolType
,
1669 IN DMUS_STREAM_TYPE StreamType
,
1670 IN PKSDATAFORMAT DataFormat
,
1671 OUT PSERVICEGROUP
* ServiceGroup
,
1672 IN PAllocatorMXF AllocatorMXF
,
1673 IN PMASTERCLOCK MasterClock
,
1674 OUT PULONGLONG SchedulePreFetch
1679 DPRINT("NewStream");
1680 NTSTATUS ntStatus
= STATUS_SUCCESS
;
1682 // In 100 ns, we want stuff as soon as it comes in
1684 *SchedulePreFetch
= 0;
1686 // if we don't have any streams already open, get the hardware ready.
1687 if ((!m_NumCaptureStreams
) && (!m_NumRenderStreams
))
1689 ntStatus
= ResetHardware(m_pPortBase
);
1690 if (!NT_SUCCESS(ntStatus
))
1692 DPRINT("CMiniportDMusUART::NewStream ResetHardware failed");
1697 if ( ((m_NumCaptureStreams
< kMaxNumCaptureStreams
)
1698 && (StreamType
== DMUS_STREAM_MIDI_CAPTURE
))
1699 || ((m_NumRenderStreams
< kMaxNumLegacyRenderStreams
+ kMaxNumDMusicRenderStreams
)
1700 && (StreamType
== DMUS_STREAM_MIDI_RENDER
))
1703 CMiniportDMusUARTStream
*pStream
=
1704 new(PoolType
) CMiniportDMusUARTStream();
1711 pStream
->Init(this,m_pPortBase
,(StreamType
== DMUS_STREAM_MIDI_CAPTURE
),AllocatorMXF
,MasterClock
);
1713 if (NT_SUCCESS(ntStatus
))
1715 *MXF
= PMXF(pStream
);
1718 if (StreamType
== DMUS_STREAM_MIDI_CAPTURE
)
1720 m_NumCaptureStreams
++;
1721 *ServiceGroup
= m_pServiceGroup
;
1722 (*ServiceGroup
)->AddRef();
1726 m_NumRenderStreams
++;
1727 *ServiceGroup
= NULL
;
1735 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1740 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
1741 if (StreamType
== DMUS_STREAM_MIDI_CAPTURE
)
1743 DPRINT("NewStream failed, too many capture streams");
1745 else if (StreamType
== DMUS_STREAM_MIDI_RENDER
)
1747 DPRINT("NewStream failed, too many render streams");
1751 DPRINT("NewStream invalid stream type");
1759 #pragma code_seg("PAGE")
1761 /*****************************************************************************
1762 * CMiniportDMusUART::SetTechnology()
1763 *****************************************************************************
1764 * Sets pindatarange technology.
1766 STDMETHODIMP_(NTSTATUS
)
1770 IN
const GUID
* Technology
1775 NTSTATUS ntStatus
= STATUS_UNSUCCESSFUL
;
1777 // Fail if miniport has already been initialized.
1779 if (NULL
== m_pPort
)
1781 RtlCopyMemory(&m_MusicFormatTechnology
, Technology
, sizeof(GUID
));
1782 ntStatus
= STATUS_SUCCESS
;
1788 /*****************************************************************************
1789 * CMiniportDMusUART::PowerChangeNotify()
1790 *****************************************************************************
1791 * Handle power state change for the miniport.
1794 #pragma code_seg("PAGE")
1801 IN POWER_STATE PowerState
1806 DPRINT("CMiniportDMusUART::PoweChangeNotify D%d", PowerState
.DeviceState
);
1808 switch (PowerState
.DeviceState
)
1811 if (m_PowerState
.DeviceState
!= PowerDeviceD0
)
1813 if (!NT_SUCCESS(InitializeHardware(m_pInterruptSync
,m_pPortBase
)))
1815 DPRINT("InitializeHardware failed when resuming");
1826 m_PowerState
.DeviceState
= PowerState
.DeviceState
;
1827 } // PowerChangeNotify
1830 #pragma code_seg("PAGE")
1832 /*****************************************************************************
1833 * CMiniportDMusUARTStream::NonDelegatingQueryInterface()
1834 *****************************************************************************
1835 * Obtains an interface. This function works just like a COM QueryInterface
1836 * call and is used if the object is not being aggregated.
1838 STDMETHODIMP_(NTSTATUS
)
1839 CMiniportDMusUARTStream::QueryInterface
1847 DPRINT("Stream::NonDelegatingQueryInterface");
1850 if (IsEqualGUIDAligned(Interface
,IID_IUnknown
))
1852 *Object
= PVOID(PUNKNOWN(this));
1855 if (IsEqualGUIDAligned(Interface
,IID_IMXF
))
1857 *Object
= PVOID(PMXF(this));
1867 // We reference the interface for the caller.
1869 PUNKNOWN(*Object
)->AddRef();
1870 return STATUS_SUCCESS
;
1873 return STATUS_INVALID_PARAMETER
;
1877 #pragma code_seg("PAGE")
1879 /*****************************************************************************
1880 * CMiniportDMusUARTStream::~CMiniportDMusUARTStream()
1881 *****************************************************************************
1882 * Destructs a stream.
1884 CMiniportDMusUARTStream::~CMiniportDMusUARTStream(void)
1888 DPRINT("~CMiniportDMusUARTStream");
1890 KeCancelTimer(&m_TimerEvent
);
1896 m_AllocatorMXF
->PutMessage(m_DMKEvtQueue
);
1900 DPRINT("~CMiniportDMusUARTStream, no allocator, can't flush DMKEvts");
1902 m_DMKEvtQueue
= NULL
;
1906 m_AllocatorMXF
->Release();
1907 m_AllocatorMXF
= NULL
;
1914 m_pMiniport
->m_NumCaptureStreams
--;
1918 m_pMiniport
->m_NumRenderStreams
--;
1921 m_pMiniport
->Release();
1926 #pragma code_seg("PAGE")
1928 /*****************************************************************************
1929 * CMiniportDMusUARTStream::Init()
1930 *****************************************************************************
1931 * Initializes a stream.
1933 STDMETHODIMP_(NTSTATUS
)
1934 CMiniportDMusUARTStream::
1937 IN CMiniportDMusUART
* pMiniport
,
1938 IN PUCHAR pPortBase
,
1939 IN BOOLEAN fCapture
,
1940 IN PAllocatorMXF allocatorMXF
,
1941 IN PMASTERCLOCK masterClock
1951 m_NumFailedMPUTries
= 0;
1952 m_TimerQueued
= FALSE
;
1953 KeInitializeSpinLock(&m_DpcSpinLock
);
1954 m_pMiniport
= pMiniport
;
1955 m_pMiniport
->AddRef();
1957 pMiniport
->m_MasterClock
= masterClock
;
1959 m_pPortBase
= pPortBase
;
1960 m_fCapture
= fCapture
;
1962 m_SnapshotTimeStamp
= 0;
1963 m_DMKEvtQueue
= NULL
;
1966 m_NumberOfRetries
= 0;
1970 allocatorMXF
->AddRef();
1971 m_AllocatorMXF
= allocatorMXF
;
1972 m_sinkMXF
= m_AllocatorMXF
;
1976 return STATUS_INVALID_PARAMETER
;
1982 &::DMusUARTTimerDPC
,
1985 KeInitializeTimer(&m_TimerEvent
);
1987 return STATUS_SUCCESS
;
1991 #pragma code_seg("PAGE")
1993 /*****************************************************************************
1994 * CMiniportDMusUARTStream::SetState()
1995 *****************************************************************************
1996 * Sets the state of the channel.
1998 STDMETHODIMP_(NTSTATUS
)
1999 CMiniportDMusUARTStream::
2007 DPRINT("SetState %d",NewState
);
2009 if (NewState
== KSSTATE_RUN
)
2011 if (m_pMiniport
->m_fMPUInitialized
)
2013 LARGE_INTEGER timeDue100ns
;
2014 timeDue100ns
.QuadPart
= 0;
2015 KeSetTimer(&m_TimerEvent
,timeDue100ns
,&m_Dpc
);
2019 DPRINT("CMiniportDMusUARTStream::SetState KSSTATE_RUN failed due to uninitialized MPU");
2020 return STATUS_INVALID_DEVICE_STATE
;
2026 m_pMiniport
->m_KSStateInput
= NewState
;
2027 if (NewState
== KSSTATE_STOP
) // STOPping
2029 m_pMiniport
->m_MPUInputBufferHead
= 0; // Previously read bytes are discarded.
2030 m_pMiniport
->m_MPUInputBufferTail
= 0; // The entire FIFO is available.
2033 return STATUS_SUCCESS
;
2041 /*****************************************************************************
2042 * CMiniportDMusUART::Service()
2043 *****************************************************************************
2044 * DPC-mode service call from the port.
2053 if (!m_NumCaptureStreams
)
2055 // we should never get here....
2056 // if we do, we must have read some trash,
2057 // so just reset the input FIFO
2058 m_MPUInputBufferTail
= m_MPUInputBufferHead
= 0;
2063 #pragma code_seg("PAGE")
2066 /*****************************************************************************
2067 * CMiniportDMusUARTStream::ConnectOutput()
2068 *****************************************************************************
2069 * Writes outgoing MIDI data.
2072 CMiniportDMusUARTStream::
2073 ConnectOutput(PMXF sinkMXF
)
2079 if ((sinkMXF
) && (m_sinkMXF
== m_AllocatorMXF
))
2081 DPRINT("ConnectOutput");
2082 m_sinkMXF
= sinkMXF
;
2083 return STATUS_SUCCESS
;
2087 DPRINT("ConnectOutput failed");
2092 DPRINT("ConnectOutput called on renderer; failed");
2094 return STATUS_UNSUCCESSFUL
;
2098 #pragma code_seg("PAGE")
2101 /*****************************************************************************
2102 * CMiniportDMusUARTStream::DisconnectOutput()
2103 *****************************************************************************
2104 * Writes outgoing MIDI data.
2107 CMiniportDMusUARTStream::
2108 DisconnectOutput(PMXF sinkMXF
)
2114 if ((m_sinkMXF
== sinkMXF
) || (!sinkMXF
))
2116 DPRINT("DisconnectOutput");
2117 m_sinkMXF
= m_AllocatorMXF
;
2118 return STATUS_SUCCESS
;
2122 DPRINT("DisconnectOutput failed");
2127 DPRINT("DisconnectOutput called on renderer; failed");
2129 return STATUS_UNSUCCESSFUL
;
2137 /*****************************************************************************
2138 * CMiniportDMusUARTStream::PutMessageLocked()
2139 *****************************************************************************
2140 * Now that the spinlock is held, add this message to the queue.
2142 * Writes an outgoing MIDI message.
2143 * We don't sort a new message into the queue -- we append it.
2144 * This is fine, since the sequencer feeds us sequenced data.
2145 * Timestamps will ascend by design.
2147 NTSTATUS
CMiniportDMusUARTStream::PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt
)
2149 NTSTATUS ntStatus
= STATUS_SUCCESS
;
2150 PDMUS_KERNEL_EVENT aDMKEvt
;
2152 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
2156 DPRINT("PutMessage to render stream");
2159 // m_DpcSpinLock already held
2163 aDMKEvt
= m_DMKEvtQueue
; // put pDMKEvt in event queue
2165 while (aDMKEvt
->pNextEvt
)
2167 aDMKEvt
= aDMKEvt
->pNextEvt
;
2169 aDMKEvt
->pNextEvt
= pDMKEvt
; // here is end of queue
2171 else // currently nothing in queue
2173 m_DMKEvtQueue
= pDMKEvt
;
2176 DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d",m_DMKEvtOffset
);
2181 // m_DpcSpinLock already held
2185 (void) ConsumeEvents();
2190 DPRINT("PutMessage to capture stream");
2191 ASSERT(NULL
== pDMKEvt
);
2202 /*****************************************************************************
2203 * CMiniportDMusUARTStream::PutMessage()
2204 *****************************************************************************
2205 * Writes an outgoing MIDI message.
2206 * We don't sort a new message into the queue -- we append it.
2207 * This is fine, since the sequencer feeds us sequenced data.
2208 * Timestamps will ascend by design.
2210 NTSTATUS
CMiniportDMusUARTStream::PutMessage(PDMUS_KERNEL_EVENT pDMKEvt
)
2212 NTSTATUS ntStatus
= STATUS_SUCCESS
;
2213 PDMUS_KERNEL_EVENT aDMKEvt
;
2215 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
2219 DPRINT("PutMessage to render stream");
2222 KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock
);
2226 aDMKEvt
= m_DMKEvtQueue
; // put pDMKEvt in event queue
2228 while (aDMKEvt
->pNextEvt
)
2230 aDMKEvt
= aDMKEvt
->pNextEvt
;
2232 aDMKEvt
->pNextEvt
= pDMKEvt
; // here is end of queue
2234 else // currently nothing in queue
2236 m_DMKEvtQueue
= pDMKEvt
;
2239 DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d", m_DMKEvtOffset
);
2244 KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock
);
2248 (void) ConsumeEvents();
2253 DPRINT("PutMessage to capture stream");
2254 ASSERT(NULL
== pDMKEvt
);
2265 /*****************************************************************************
2266 * CMiniportDMusUARTStream::ConsumeEvents()
2267 *****************************************************************************
2268 * Attempts to empty the render message queue.
2269 * Called either from DPC timer or upon IRP submittal.
2270 // TODO: support packages right
2271 // process the package (actually, should do this above.
2272 // treat the package as a list fragment that shouldn't be sorted.
2273 // better yet, go through each event in the package, and when
2274 // an event is exhausted, delete it and decrement m_offset.
2276 NTSTATUS
CMiniportDMusUARTStream::ConsumeEvents(void)
2278 PDMUS_KERNEL_EVENT aDMKEvt
;
2280 NTSTATUS ntStatus
= STATUS_SUCCESS
;
2281 ULONG bytesRemaining
= 0,bytesWritten
= 0;
2282 LARGE_INTEGER aMillisecIn100ns
;
2284 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
2285 KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock
);
2287 m_TimerQueued
= FALSE
;
2288 while (m_DMKEvtQueue
) // do we have anything to play at all?
2290 aDMKEvt
= m_DMKEvtQueue
; // event we try to play
2291 if (aDMKEvt
->cbEvent
)
2293 bytesRemaining
= aDMKEvt
->cbEvent
- m_DMKEvtOffset
; // number of bytes left in this evt
2295 ASSERT(bytesRemaining
> 0);
2296 if (bytesRemaining
<= 0)
2298 bytesRemaining
= aDMKEvt
->cbEvent
;
2301 if (aDMKEvt
->cbEvent
<= sizeof(PBYTE
)) // short message
2303 DPRINT("ConsumeEvents(%02x%02x%02x%02x)", aDMKEvt
->uData
.abData
[0], aDMKEvt
->uData
.abData
[1], aDMKEvt
->uData
.abData
[2], aDMKEvt
->uData
.abData
[3]);
2304 ntStatus
= Write(aDMKEvt
->uData
.abData
+ m_DMKEvtOffset
,bytesRemaining
,&bytesWritten
);
2306 else if (PACKAGE_EVT(aDMKEvt
))
2308 ASSERT(m_DMKEvtOffset
== 0);
2310 DPRINT("ConsumeEvents(Package)");
2312 ntStatus
= PutMessageLocked(aDMKEvt
->uData
.pPackageEvt
); // we already own the spinlock
2314 // null this because we are about to throw it in the allocator
2315 aDMKEvt
->uData
.pPackageEvt
= NULL
;
2316 aDMKEvt
->cbEvent
= 0;
2317 bytesWritten
= bytesRemaining
;
2319 else // SysEx message
2321 DPRINT("ConsumeEvents(%02x%02x%02x%02x)", aDMKEvt
->uData
.pbData
[0], aDMKEvt
->uData
.pbData
[1], aDMKEvt
->uData
.pbData
[2], aDMKEvt
->uData
.pbData
[3]);
2323 ntStatus
= Write(aDMKEvt
->uData
.pbData
+ m_DMKEvtOffset
,bytesRemaining
,&bytesWritten
);
2325 } // if (aDMKEvt->cbEvent)
2326 if (STATUS_SUCCESS
!= ntStatus
)
2328 DPRINT("ConsumeEvents: Write returned 0x%08x", ntStatus
);
2329 bytesWritten
= bytesRemaining
; // just bail on this event and try next time
2332 ASSERT(bytesWritten
<= bytesRemaining
);
2333 if (bytesWritten
== bytesRemaining
)
2335 m_DMKEvtQueue
= m_DMKEvtQueue
->pNextEvt
;
2336 aDMKEvt
->pNextEvt
= NULL
;
2338 m_AllocatorMXF
->PutMessage(aDMKEvt
); // throw back in free pool
2339 m_DMKEvtOffset
= 0; // start fresh on next evt
2340 m_NumberOfRetries
= 0;
2341 } // but wait ... there's more!
2342 else // our FIFO is full for now.
2344 // update our offset by that amount we did write
2345 m_DMKEvtOffset
+= bytesWritten
;
2346 ASSERT(m_DMKEvtOffset
< aDMKEvt
->cbEvent
);
2348 DPRINT("ConsumeEvents tried %d, wrote %d, at offset %d", bytesRemaining
,bytesWritten
,m_DMKEvtOffset
);
2349 aMillisecIn100ns
.QuadPart
= -(kOneMillisec
); // set timer, come back later
2350 m_TimerQueued
= TRUE
;
2351 m_NumberOfRetries
++;
2352 ntStatus
= KeSetTimer( &m_TimerEvent
, aMillisecIn100ns
, &m_Dpc
);
2354 } // we didn't write it all
2355 } // go back, Jack, do it again (while m_DMKEvtQueue)
2356 KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock
);
2364 /*****************************************************************************
2365 * CMiniportDMusUARTStream::HandlePortParams()
2366 *****************************************************************************
2367 * Writes an outgoing MIDI message.
2370 CMiniportDMusUARTStream::
2373 IN PPCPROPERTY_REQUEST pRequest
2380 if (pRequest
->Verb
& KSPROPERTY_TYPE_SET
)
2382 return STATUS_INVALID_DEVICE_REQUEST
;
2385 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(SYNTH_PORTPARAMS
), TRUE
);
2386 if (NT_SUCCESS(ntStatus
))
2388 RtlCopyMemory(pRequest
->Value
, pRequest
->Instance
, sizeof(SYNTH_PORTPARAMS
));
2390 PSYNTH_PORTPARAMS Params
= (PSYNTH_PORTPARAMS
)pRequest
->Value
;
2392 if (Params
->ValidParams
& ~SYNTH_PORTPARAMS_CHANNELGROUPS
)
2394 Params
->ValidParams
&= SYNTH_PORTPARAMS_CHANNELGROUPS
;
2397 if (!(Params
->ValidParams
& SYNTH_PORTPARAMS_CHANNELGROUPS
))
2399 Params
->ChannelGroups
= 1;
2401 else if (Params
->ChannelGroups
!= 1)
2403 Params
->ChannelGroups
= 1;
2406 pRequest
->ValueSize
= sizeof(SYNTH_PORTPARAMS
);
2416 /*****************************************************************************
2418 *****************************************************************************
2419 * The timer DPC callback. Thunks to a C++ member function.
2420 * This is called by the OS in response to the DirectMusic pin
2421 * wanting to wakeup later to process more DirectMusic stuff.
2428 IN PVOID DeferredContext
,
2429 IN PVOID SystemArgument1
,
2430 IN PVOID SystemArgument2
2433 ASSERT(DeferredContext
);
2435 CMiniportDMusUARTStream
*aStream
;
2436 aStream
= (CMiniportDMusUARTStream
*) DeferredContext
;
2439 DPRINT("DMusUARTTimerDPC");
2440 if (false == aStream
->m_fCapture
)
2442 (void) aStream
->ConsumeEvents();
2444 // ignores return value!
2448 /*****************************************************************************
2449 * DirectMusic properties
2450 ****************************************************************************/
2457 * Properties concerning synthesizer functions.
2459 const WCHAR wszDescOut
[] = L
"DMusic MPU-401 Out ";
2460 const WCHAR wszDescIn
[] = L
"DMusic MPU-401 In ";
2462 NTSTATUS PropertyHandler_Synth
2464 IN PPCPROPERTY_REQUEST pRequest
2471 if (pRequest
->Verb
& KSPROPERTY_TYPE_BASICSUPPORT
)
2473 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(ULONG
), TRUE
);
2474 if (NT_SUCCESS(ntStatus
))
2476 // if return buffer can hold a ULONG, return the access flags
2477 PULONG AccessFlags
= PULONG(pRequest
->Value
);
2479 *AccessFlags
= KSPROPERTY_TYPE_BASICSUPPORT
;
2480 switch (pRequest
->PropertyItem
->Id
)
2482 case KSPROPERTY_SYNTH_CAPS
:
2483 case KSPROPERTY_SYNTH_CHANNELGROUPS
:
2484 *AccessFlags
|= KSPROPERTY_TYPE_GET
;
2486 switch (pRequest
->PropertyItem
->Id
)
2488 case KSPROPERTY_SYNTH_CHANNELGROUPS
:
2489 *AccessFlags
|= KSPROPERTY_TYPE_SET
;
2491 ntStatus
= STATUS_SUCCESS
;
2492 pRequest
->ValueSize
= sizeof(ULONG
);
2494 switch (pRequest
->PropertyItem
->Id
)
2496 case KSPROPERTY_SYNTH_PORTPARAMETERS
:
2497 if (pRequest
->MinorTarget
)
2499 *AccessFlags
|= KSPROPERTY_TYPE_GET
;
2503 pRequest
->ValueSize
= 0;
2504 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2511 ntStatus
= STATUS_SUCCESS
;
2512 switch(pRequest
->PropertyItem
->Id
)
2514 case KSPROPERTY_SYNTH_CAPS
:
2515 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CAPS");
2517 if (pRequest
->Verb
& KSPROPERTY_TYPE_SET
)
2519 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2522 if (NT_SUCCESS(ntStatus
))
2524 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(SYNTHCAPS
), TRUE
);
2526 if (NT_SUCCESS(ntStatus
))
2528 SYNTHCAPS
*caps
= (SYNTHCAPS
*)pRequest
->Value
;
2530 RtlZeroMemory(caps
, sizeof(SYNTHCAPS
));
2531 // XXX Different guids for different instances!
2533 if (pRequest
->Node
== eSynthNode
)
2535 increment
= sizeof(wszDescOut
) - 2;
2536 RtlCopyMemory( caps
->Description
,wszDescOut
,increment
);
2537 caps
->Guid
= CLSID_MiniportDriverDMusUART
;
2541 increment
= sizeof(wszDescIn
) - 2;
2542 RtlCopyMemory( caps
->Description
,wszDescIn
,increment
);
2543 caps
->Guid
= CLSID_MiniportDriverDMusUARTCapture
;
2546 caps
->Flags
= SYNTH_PC_EXTERNAL
;
2547 caps
->MemorySize
= 0;
2548 caps
->MaxChannelGroups
= 1;
2549 caps
->MaxVoices
= 0xFFFFFFFF;
2550 caps
->MaxAudioChannels
= 0xFFFFFFFF;
2552 caps
->EffectFlags
= 0;
2554 CMiniportDMusUART
*aMiniport
;
2555 ASSERT(pRequest
->MajorTarget
);
2556 aMiniport
= (CMiniportDMusUART
*)(PMINIPORTDMUS
)(pRequest
->MajorTarget
);
2559 cLen
= swprintf(wszDesc2
,L
"[%03x]\0",PtrToUlong(aMiniport
->m_pPortBase
));
2561 cLen
*= sizeof(WCHAR
);
2562 RtlCopyMemory((WCHAR
*)((DWORD_PTR
)(caps
->Description
) + increment
),
2567 pRequest
->ValueSize
= sizeof(SYNTHCAPS
);
2573 case KSPROPERTY_SYNTH_PORTPARAMETERS
:
2574 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_PORTPARAMETERS");
2576 CMiniportDMusUARTStream
*aStream
;
2578 aStream
= (CMiniportDMusUARTStream
*)(pRequest
->MinorTarget
);
2581 ntStatus
= aStream
->HandlePortParams(pRequest
);
2585 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2590 case KSPROPERTY_SYNTH_CHANNELGROUPS
:
2591 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CHANNELGROUPS");
2593 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(ULONG
), TRUE
);
2594 if (NT_SUCCESS(ntStatus
))
2596 *(PULONG
)(pRequest
->Value
) = 1;
2597 pRequest
->ValueSize
= sizeof(ULONG
);
2601 case KSPROPERTY_SYNTH_LATENCYCLOCK
:
2602 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_LATENCYCLOCK");
2604 if(pRequest
->Verb
& KSPROPERTY_TYPE_SET
)
2606 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2610 ntStatus
= ValidatePropertyRequest(pRequest
, sizeof(ULONGLONG
), TRUE
);
2611 if(NT_SUCCESS(ntStatus
))
2613 REFERENCE_TIME rtLatency
;
2614 CMiniportDMusUARTStream
*aStream
;
2616 aStream
= (CMiniportDMusUARTStream
*)(pRequest
->MinorTarget
);
2619 ntStatus
= STATUS_INVALID_DEVICE_REQUEST
;
2623 aStream
->m_pMiniport
->m_MasterClock
->GetTime(&rtLatency
);
2624 *((PULONGLONG
)pRequest
->Value
) = rtLatency
;
2625 pRequest
->ValueSize
= sizeof(ULONGLONG
);
2632 DPRINT("Unhandled property in PropertyHandler_Synth");
2639 /*****************************************************************************
2640 * ValidatePropertyRequest()
2641 *****************************************************************************
2642 * Validates pRequest.
2643 * Checks if the ValueSize is valid
2644 * Checks if the Value is valid
2646 * This does not update pRequest->ValueSize if it returns NT_SUCCESS.
2647 * Caller must set pRequest->ValueSize in case of NT_SUCCESS.
2649 NTSTATUS ValidatePropertyRequest
2651 IN PPCPROPERTY_REQUEST pRequest
,
2652 IN ULONG ulValueSize
,
2653 IN BOOLEAN fValueRequired
2658 if (pRequest
->ValueSize
>= ulValueSize
)
2660 if (fValueRequired
&& NULL
== pRequest
->Value
)
2662 ntStatus
= STATUS_INVALID_PARAMETER
;
2666 ntStatus
= STATUS_SUCCESS
;
2669 else if (0 == pRequest
->ValueSize
)
2671 ntStatus
= STATUS_BUFFER_OVERFLOW
;
2675 ntStatus
= STATUS_BUFFER_TOO_SMALL
;
2678 if (STATUS_BUFFER_OVERFLOW
== ntStatus
)
2680 pRequest
->ValueSize
= ulValueSize
;
2684 pRequest
->ValueSize
= 0;
2688 } // ValidatePropertyRequest