Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenminiport_dmus.cpp
Go to the documentation of this file.
00001 /***************************************************************************** 00002 * miniport_dmus.cpp - UART miniport implementation 00003 ***************************************************************************** 00004 * Copyright (c) 1997-2000 Microsoft Corporation. All Rights Reserved. 00005 * 00006 * Feb 98 MartinP -- based on UART, began deltas for DirectMusic. 00007 * 00008 */ 00009 00010 00011 #include "private.hpp" 00012 00013 // + for absolute / - for relative 00014 00015 #define kOneMillisec (10 * 1000) 00016 00017 // 00018 // MPU401 ports 00019 // 00020 #define MPU401_REG_STATUS 0x01 // Status register 00021 #define MPU401_DRR 0x40 // Output ready (for command or data) 00022 // if this bit is set, the output FIFO is FULL 00023 #define MPU401_DSR 0x80 // Input ready (for data) 00024 // if this bit is set, the input FIFO is empty 00025 00026 #define MPU401_REG_DATA 0x00 // Data in 00027 #define MPU401_REG_COMMAND 0x01 // Commands 00028 #define MPU401_CMD_RESET 0xFF // Reset command 00029 #define MPU401_CMD_UART 0x3F // Switch to UART mod 00030 00031 00032 /***************************************************************************** 00033 * Prototypes 00034 */ 00035 00036 NTSTATUS NTAPI InitMPU(IN PINTERRUPTSYNC InterruptSync,IN PVOID DynamicContext); 00037 NTSTATUS ResetHardware(PUCHAR portBase); 00038 NTSTATUS ValidatePropertyRequest(IN PPCPROPERTY_REQUEST pRequest, IN ULONG ulValueSize, IN BOOLEAN fValueRequired); 00039 NTSTATUS NTAPI PropertyHandler_Synth(IN PPCPROPERTY_REQUEST PropertyRequest); 00040 NTSTATUS NTAPI DMusMPUInterruptServiceRoutine(PINTERRUPTSYNC InterruptSync,PVOID DynamicContext); 00041 VOID NTAPI DMusUARTTimerDPC(PKDPC Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID SystemArgument2); 00042 NTSTATUS NTAPI SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync,PVOID syncWriteContext); 00043 /***************************************************************************** 00044 * Constants 00045 */ 00046 00047 const BOOLEAN COMMAND = TRUE; 00048 const BOOLEAN DATA = FALSE; 00049 const ULONG kMPUInputBufferSize = 128; 00050 00051 00052 /***************************************************************************** 00053 * Classes 00054 */ 00055 00056 /***************************************************************************** 00057 * CMiniportDMusUART 00058 ***************************************************************************** 00059 * MPU-401 miniport. This object is associated with the device and is 00060 * created when the device is started. The class inherits IMiniportDMus 00061 * so it can expose this interface and CUnknown so it automatically gets 00062 * reference counting and aggregation support. 00063 */ 00064 class CMiniportDMusUART 00065 : public IMiniportDMus, 00066 public IMusicTechnology, 00067 public IPowerNotify 00068 { 00069 private: 00070 LONG m_Ref; // Reference count 00071 KSSTATE m_KSStateInput; // Miniport state (RUN/PAUSE/ACQUIRE/STOP) 00072 PPORTDMUS m_pPort; // Callback interface. 00073 PUCHAR m_pPortBase; // Base port address. 00074 PINTERRUPTSYNC m_pInterruptSync; // Interrupt synchronization object. 00075 PSERVICEGROUP m_pServiceGroup; // Service group for capture. 00076 PMASTERCLOCK m_MasterClock; // for input data 00077 REFERENCE_TIME m_InputTimeStamp; // capture data timestamp 00078 USHORT m_NumRenderStreams; // Num active render streams. 00079 USHORT m_NumCaptureStreams; // Num active capture streams. 00080 ULONG m_MPUInputBufferHead; // Index of the newest byte in the FIFO. 00081 ULONG m_MPUInputBufferTail; // Index of the oldest empty space in the FIFO. 00082 GUID m_MusicFormatTechnology; 00083 POWER_STATE m_PowerState; // Saved power state (D0 = full power, D3 = off) 00084 BOOLEAN m_fMPUInitialized; // Is the MPU HW initialized. 00085 BOOLEAN m_UseIRQ; // FALSE if no IRQ is used for MIDI. 00086 UCHAR m_MPUInputBuffer[kMPUInputBufferSize]; // Internal SW FIFO. 00087 00088 /************************************************************************* 00089 * CMiniportDMusUART methods 00090 * 00091 * These are private member functions used internally by the object. 00092 * See MINIPORT.CPP for specific descriptions. 00093 */ 00094 NTSTATUS ProcessResources 00095 ( 00096 IN PRESOURCELIST ResourceList 00097 ); 00098 NTSTATUS InitializeHardware(PINTERRUPTSYNC interruptSync,PUCHAR portBase); 00099 00100 public: 00101 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); 00102 00103 STDMETHODIMP_(ULONG) AddRef() 00104 { 00105 InterlockedIncrement(&m_Ref); 00106 return m_Ref; 00107 } 00108 STDMETHODIMP_(ULONG) Release() 00109 { 00110 InterlockedDecrement(&m_Ref); 00111 00112 if (!m_Ref) 00113 { 00114 delete this; 00115 return 0; 00116 } 00117 return m_Ref; 00118 } 00119 00120 CMiniportDMusUART(IUnknown * Unknown){} 00121 ~CMiniportDMusUART(); 00122 00123 /************************************************************************* 00124 * IMiniport methods 00125 */ 00126 STDMETHODIMP_(NTSTATUS) 00127 GetDescription 00128 ( OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor 00129 ); 00130 STDMETHODIMP_(NTSTATUS) 00131 DataRangeIntersection 00132 ( IN ULONG PinId 00133 , IN PKSDATARANGE DataRange 00134 , IN PKSDATARANGE MatchingDataRange 00135 , IN ULONG OutputBufferLength 00136 , OUT PVOID ResultantFormat 00137 , OUT PULONG ResultantFormatLength 00138 ) 00139 { 00140 return STATUS_NOT_IMPLEMENTED; 00141 } 00142 00143 /************************************************************************* 00144 * IMiniportDMus methods 00145 */ 00146 STDMETHODIMP_(NTSTATUS) Init 00147 ( 00148 IN PUNKNOWN UnknownAdapter, 00149 IN PRESOURCELIST ResourceList, 00150 IN PPORTDMUS Port, 00151 OUT PSERVICEGROUP * ServiceGroup 00152 ); 00153 STDMETHODIMP_(NTSTATUS) NewStream 00154 ( 00155 OUT PMXF * Stream, 00156 IN PUNKNOWN OuterUnknown OPTIONAL, 00157 IN POOL_TYPE PoolType, 00158 IN ULONG PinID, 00159 IN DMUS_STREAM_TYPE StreamType, 00160 IN PKSDATAFORMAT DataFormat, 00161 OUT PSERVICEGROUP * ServiceGroup, 00162 IN PAllocatorMXF AllocatorMXF, 00163 IN PMASTERCLOCK MasterClock, 00164 OUT PULONGLONG SchedulePreFetch 00165 ); 00166 STDMETHODIMP_(void) Service 00167 ( void 00168 ); 00169 00170 /************************************************************************* 00171 * IMusicTechnology methods 00172 */ 00173 IMP_IMusicTechnology; 00174 00175 /************************************************************************* 00176 * IPowerNotify methods 00177 */ 00178 IMP_IPowerNotify; 00179 00180 /************************************************************************* 00181 * Friends 00182 */ 00183 friend class CMiniportDMusUARTStream; 00184 friend NTSTATUS NTAPI 00185 DMusMPUInterruptServiceRoutine(PINTERRUPTSYNC InterruptSync,PVOID DynamicContext); 00186 friend NTSTATUS NTAPI 00187 SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync,PVOID syncWriteContext); 00188 friend VOID NTAPI 00189 DMusUARTTimerDPC(PKDPC Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID SystemArgument2); 00190 friend NTSTATUS NTAPI PropertyHandler_Synth(IN PPCPROPERTY_REQUEST PropertyRequest); 00191 friend STDMETHODIMP_(NTSTATUS) SnapTimeStamp(PINTERRUPTSYNC InterruptSync,PVOID pStream); 00192 }; 00193 00194 /***************************************************************************** 00195 * CMiniportDMusUARTStream 00196 ***************************************************************************** 00197 * MPU-401 miniport stream. This object is associated with the pin and is 00198 * created when the pin is instantiated. It inherits IMXF 00199 * so it can expose this interface and CUnknown so it automatically gets 00200 * reference counting and aggregation support. 00201 */ 00202 class CMiniportDMusUARTStream : public IMXF 00203 { 00204 private: 00205 LONG m_Ref; // Reference Count 00206 CMiniportDMusUART * m_pMiniport; // Parent. 00207 REFERENCE_TIME m_SnapshotTimeStamp; // Current snapshot of miniport's input timestamp. 00208 PUCHAR m_pPortBase; // Base port address. 00209 BOOLEAN m_fCapture; // Whether this is capture. 00210 long m_NumFailedMPUTries; // Deadman timeout for MPU hardware. 00211 PAllocatorMXF m_AllocatorMXF; // source/sink for DMus structs 00212 PMXF m_sinkMXF; // sink for DMus capture 00213 PDMUS_KERNEL_EVENT m_DMKEvtQueue; // queue of waiting events 00214 ULONG m_NumberOfRetries; // Number of consecutive times the h/w was busy/full 00215 ULONG m_DMKEvtOffset; // offset into the event 00216 KDPC m_Dpc; // DPC for timer 00217 KTIMER m_TimerEvent; // timer 00218 BOOL m_TimerQueued; // whether a timer has been set 00219 KSPIN_LOCK m_DpcSpinLock; // protects the ConsumeEvents DPC 00220 00221 STDMETHODIMP_(NTSTATUS) SourceEvtsToPort(); 00222 STDMETHODIMP_(NTSTATUS) ConsumeEvents(); 00223 STDMETHODIMP_(NTSTATUS) PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt); 00224 00225 public: 00226 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); 00227 00228 STDMETHODIMP_(ULONG) AddRef() 00229 { 00230 InterlockedIncrement(&m_Ref); 00231 return m_Ref; 00232 } 00233 STDMETHODIMP_(ULONG) Release() 00234 { 00235 InterlockedDecrement(&m_Ref); 00236 00237 if (!m_Ref) 00238 { 00239 delete this; 00240 return 0; 00241 } 00242 return m_Ref; 00243 } 00244 00245 ~CMiniportDMusUARTStream(); 00246 00247 STDMETHODIMP_(NTSTATUS) Init 00248 ( 00249 IN CMiniportDMusUART * pMiniport, 00250 IN PUCHAR pPortBase, 00251 IN BOOLEAN fCapture, 00252 IN PAllocatorMXF allocatorMXF, 00253 IN PMASTERCLOCK masterClock 00254 ); 00255 00256 NTSTATUS HandlePortParams 00257 ( 00258 IN PPCPROPERTY_REQUEST Request 00259 ); 00260 00261 /************************************************************************* 00262 * IMiniportStreamDMusUART methods 00263 */ 00264 IMP_IMXF; 00265 00266 STDMETHODIMP_(NTSTATUS) Write 00267 ( 00268 IN PVOID BufferAddress, 00269 IN ULONG BytesToWrite, 00270 OUT PULONG BytesWritten 00271 ); 00272 00273 friend VOID NTAPI 00274 DMusUARTTimerDPC 00275 ( 00276 IN PKDPC Dpc, 00277 IN PVOID DeferredContext, 00278 IN PVOID SystemArgument1, 00279 IN PVOID SystemArgument2 00280 ); 00281 friend NTSTATUS NTAPI PropertyHandler_Synth(IN PPCPROPERTY_REQUEST); 00282 friend STDMETHODIMP_(NTSTATUS) SnapTimeStamp(PINTERRUPTSYNC InterruptSync,PVOID pStream); 00283 }; 00284 00285 00286 00287 #define STR_MODULENAME "DMusUART:Miniport: " 00288 00289 #ifdef _MSC_VER 00290 #pragma code_seg("PAGE") 00291 #endif 00292 00293 #define UartFifoOkForWrite(status) ((status & MPU401_DRR) == 0) 00294 #define UartFifoOkForRead(status) ((status & MPU401_DSR) == 0) 00295 00296 typedef struct 00297 { 00298 CMiniportDMusUART *Miniport; 00299 PUCHAR PortBase; 00300 PVOID BufferAddress; 00301 ULONG Length; 00302 PULONG BytesRead; 00303 } 00304 SYNCWRITECONTEXT, *PSYNCWRITECONTEXT; 00305 00306 /***************************************************************************** 00307 * PinDataRangesStreamLegacy 00308 * PinDataRangesStreamDMusic 00309 ***************************************************************************** 00310 * Structures indicating range of valid format values for live pins. 00311 */ 00312 static 00313 KSDATARANGE_MUSIC PinDataRangesStreamLegacy = 00314 { 00315 { 00316 { 00317 sizeof(KSDATARANGE_MUSIC), 00318 0, 00319 0, 00320 0, 00321 {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC)}, 00322 {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI)}, 00323 {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)} 00324 } 00325 }, 00326 {STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT)}, 00327 0, 00328 0, 00329 0xFFFF 00330 }; 00331 static 00332 KSDATARANGE_MUSIC PinDataRangesStreamDMusic = 00333 { 00334 { 00335 { 00336 sizeof(KSDATARANGE_MUSIC), 00337 0, 00338 0, 00339 0, 00340 {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC)}, 00341 {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_DIRECTMUSIC)}, 00342 {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)} 00343 } 00344 }, 00345 {STATICGUIDOF(KSMUSIC_TECHNOLOGY_PORT)}, 00346 0, 00347 0, 00348 0xFFFF 00349 }; 00350 00351 /***************************************************************************** 00352 * PinDataRangePointersStreamLegacy 00353 * PinDataRangePointersStreamDMusic 00354 * PinDataRangePointersStreamCombined 00355 ***************************************************************************** 00356 * List of pointers to structures indicating range of valid format values 00357 * for live pins. 00358 */ 00359 static 00360 PKSDATARANGE PinDataRangePointersStreamLegacy[] = 00361 { 00362 PKSDATARANGE(&PinDataRangesStreamLegacy) 00363 }; 00364 static 00365 PKSDATARANGE PinDataRangePointersStreamDMusic[] = 00366 { 00367 PKSDATARANGE(&PinDataRangesStreamDMusic) 00368 }; 00369 static 00370 PKSDATARANGE PinDataRangePointersStreamCombined[] = 00371 { 00372 PKSDATARANGE(&PinDataRangesStreamLegacy) 00373 ,PKSDATARANGE(&PinDataRangesStreamDMusic) 00374 }; 00375 00376 /***************************************************************************** 00377 * PinDataRangesBridge 00378 ***************************************************************************** 00379 * Structures indicating range of valid format values for bridge pins. 00380 */ 00381 static 00382 KSDATARANGE PinDataRangesBridge[] = 00383 { 00384 { 00385 { 00386 sizeof(KSDATARANGE), 00387 0, 00388 0, 00389 0, 00390 {STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC)}, 00391 {STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI_BUS)}, 00392 {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)} 00393 } 00394 } 00395 }; 00396 00397 /***************************************************************************** 00398 * PinDataRangePointersBridge 00399 ***************************************************************************** 00400 * List of pointers to structures indicating range of valid format values 00401 * for bridge pins. 00402 */ 00403 static 00404 PKSDATARANGE PinDataRangePointersBridge[] = 00405 { 00406 &PinDataRangesBridge[0] 00407 }; 00408 00409 /***************************************************************************** 00410 * SynthProperties 00411 ***************************************************************************** 00412 * List of properties in the Synth set. 00413 */ 00414 static 00415 PCPROPERTY_ITEM 00416 SynthProperties[] = 00417 { 00418 // Global: S/Get synthesizer caps 00419 { 00420 &KSPROPSETID_Synth, 00421 KSPROPERTY_SYNTH_CAPS, 00422 KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, 00423 PropertyHandler_Synth 00424 }, 00425 // Global: S/Get port parameters 00426 { 00427 &KSPROPSETID_Synth, 00428 KSPROPERTY_SYNTH_PORTPARAMETERS, 00429 KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, 00430 PropertyHandler_Synth 00431 }, 00432 // Per stream: S/Get channel groups 00433 { 00434 &KSPROPSETID_Synth, 00435 KSPROPERTY_SYNTH_CHANNELGROUPS, 00436 KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, 00437 PropertyHandler_Synth 00438 }, 00439 // Per stream: Get current latency time 00440 { 00441 &KSPROPSETID_Synth, 00442 KSPROPERTY_SYNTH_LATENCYCLOCK, 00443 KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT, 00444 PropertyHandler_Synth 00445 } 00446 }; 00447 DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth, SynthProperties); 00448 DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth2, SynthProperties); 00449 00450 #define kMaxNumCaptureStreams 1 00451 #define kMaxNumLegacyRenderStreams 1 00452 #define kMaxNumDMusicRenderStreams 1 00453 00454 /***************************************************************************** 00455 * MiniportPins 00456 ***************************************************************************** 00457 * List of pins. 00458 */ 00459 static 00460 PCPIN_DESCRIPTOR MiniportPins[] = 00461 { 00462 { 00463 kMaxNumLegacyRenderStreams,kMaxNumLegacyRenderStreams,0, // InstanceCount 00464 NULL, // AutomationTable 00465 { // KsPinDescriptor 00466 0, // InterfacesCount 00467 NULL, // Interfaces 00468 0, // MediumsCount 00469 NULL, // Mediums 00470 SIZEOF_ARRAY(PinDataRangePointersStreamLegacy), // DataRangesCount 00471 PinDataRangePointersStreamLegacy, // DataRanges 00472 KSPIN_DATAFLOW_IN, // DataFlow 00473 KSPIN_COMMUNICATION_SINK, // Communication 00474 (GUID *) &KSCATEGORY_AUDIO, // Category 00475 &KSAUDFNAME_MIDI, // Name 00476 {0} // Reserved 00477 } 00478 }, 00479 { 00480 kMaxNumDMusicRenderStreams,kMaxNumDMusicRenderStreams,0, // InstanceCount 00481 NULL, // AutomationTable 00482 { // KsPinDescriptor 00483 0, // InterfacesCount 00484 NULL, // Interfaces 00485 0, // MediumsCount 00486 NULL, // Mediums 00487 SIZEOF_ARRAY(PinDataRangePointersStreamDMusic), // DataRangesCount 00488 PinDataRangePointersStreamDMusic, // DataRanges 00489 KSPIN_DATAFLOW_IN, // DataFlow 00490 KSPIN_COMMUNICATION_SINK, // Communication 00491 (GUID *) &KSCATEGORY_AUDIO, // Category 00492 &KSAUDFNAME_DMUSIC_MPU_OUT, // Name 00493 {0} // Reserved 00494 } 00495 }, 00496 { 00497 0,0,0, // InstanceCount 00498 NULL, // AutomationTable 00499 { // KsPinDescriptor 00500 0, // InterfacesCount 00501 NULL, // Interfaces 00502 0, // MediumsCount 00503 NULL, // Mediums 00504 SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount 00505 PinDataRangePointersBridge, // DataRanges 00506 KSPIN_DATAFLOW_OUT, // DataFlow 00507 KSPIN_COMMUNICATION_NONE, // Communication 00508 (GUID *) &KSCATEGORY_AUDIO, // Category 00509 NULL, // Name 00510 {0} // Reserved 00511 } 00512 }, 00513 { 00514 0,0,0, // InstanceCount 00515 NULL, // AutomationTable 00516 { // KsPinDescriptor 00517 0, // InterfacesCount 00518 NULL, // Interfaces 00519 0, // MediumsCount 00520 NULL, // Mediums 00521 SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount 00522 PinDataRangePointersBridge, // DataRanges 00523 KSPIN_DATAFLOW_IN, // DataFlow 00524 KSPIN_COMMUNICATION_NONE, // Communication 00525 (GUID *) &KSCATEGORY_AUDIO, // Category 00526 NULL, // Name 00527 {0} // Reserved 00528 } 00529 }, 00530 { 00531 kMaxNumCaptureStreams,kMaxNumCaptureStreams,0, // InstanceCount 00532 NULL, // AutomationTable 00533 { // KsPinDescriptor 00534 0, // InterfacesCount 00535 NULL, // Interfaces 00536 0, // MediumsCount 00537 NULL, // Mediums 00538 SIZEOF_ARRAY(PinDataRangePointersStreamCombined), // DataRangesCount 00539 PinDataRangePointersStreamCombined, // DataRanges 00540 KSPIN_DATAFLOW_OUT, // DataFlow 00541 KSPIN_COMMUNICATION_SINK, // Communication 00542 (GUID *) &KSCATEGORY_AUDIO, // Category 00543 &KSAUDFNAME_DMUSIC_MPU_IN, // Name 00544 {0} // Reserved 00545 } 00546 } 00547 }; 00548 00549 /***************************************************************************** 00550 * MiniportNodes 00551 ***************************************************************************** 00552 * List of nodes. 00553 */ 00554 #define CONST_PCNODE_DESCRIPTOR(n) { 0, NULL, &n, NULL } 00555 #define CONST_PCNODE_DESCRIPTOR_AUTO(n,a) { 0, &a, &n, NULL } 00556 static 00557 PCNODE_DESCRIPTOR MiniportNodes[] = 00558 { 00559 CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER, AutomationSynth) 00560 , CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER, AutomationSynth2) 00561 }; 00562 00563 /***************************************************************************** 00564 * MiniportConnections 00565 ***************************************************************************** 00566 * List of connections. 00567 */ 00568 enum { 00569 eSynthNode = 0 00570 , eInputNode 00571 }; 00572 00573 enum { 00574 eFilterInputPinLeg = 0, 00575 eFilterInputPinDM, 00576 eBridgeOutputPin, 00577 eBridgeInputPin, 00578 eFilterOutputPin 00579 }; 00580 00581 static 00582 PCCONNECTION_DESCRIPTOR MiniportConnections[] = 00583 { // From To 00584 // Node pin Node pin 00585 { PCFILTER_NODE, eFilterInputPinLeg, PCFILTER_NODE, eBridgeOutputPin } // Legacy Stream in to synth. 00586 , { PCFILTER_NODE, eFilterInputPinDM, eSynthNode, KSNODEPIN_STANDARD_IN } // DM Stream in to synth. 00587 , { eSynthNode, KSNODEPIN_STANDARD_OUT, PCFILTER_NODE, eBridgeOutputPin } // Synth to bridge out. 00588 , { PCFILTER_NODE, eBridgeInputPin, eInputNode, KSNODEPIN_STANDARD_IN } // Bridge in to input. 00589 , { eInputNode, KSNODEPIN_STANDARD_OUT, PCFILTER_NODE, eFilterOutputPin } // Input to DM/Legacy Stream out. 00590 }; 00591 00592 /***************************************************************************** 00593 * MiniportCategories 00594 ***************************************************************************** 00595 * List of categories. 00596 */ 00597 static 00598 GUID MiniportCategories[] = 00599 { 00600 {STATICGUIDOF(KSCATEGORY_AUDIO)}, 00601 {STATICGUIDOF(KSCATEGORY_RENDER)}, 00602 {STATICGUIDOF(KSCATEGORY_CAPTURE)} 00603 }; 00604 00605 /***************************************************************************** 00606 * MiniportFilterDescriptor 00607 ***************************************************************************** 00608 * Complete miniport filter description. 00609 */ 00610 static 00611 PCFILTER_DESCRIPTOR MiniportFilterDescriptor = 00612 { 00613 0, // Version 00614 NULL, // AutomationTable 00615 sizeof(PCPIN_DESCRIPTOR), // PinSize 00616 SIZEOF_ARRAY(MiniportPins), // PinCount 00617 MiniportPins, // Pins 00618 sizeof(PCNODE_DESCRIPTOR), // NodeSize 00619 SIZEOF_ARRAY(MiniportNodes), // NodeCount 00620 MiniportNodes, // Nodes 00621 SIZEOF_ARRAY(MiniportConnections), // ConnectionCount 00622 MiniportConnections, // Connections 00623 SIZEOF_ARRAY(MiniportCategories), // CategoryCount 00624 MiniportCategories // Categories 00625 }; 00626 00627 #ifdef _MSC_VER 00628 #pragma code_seg("PAGE") 00629 #endif 00630 00631 BOOLEAN TryMPU(IN PUCHAR PortBase); 00632 NTSTATUS WriteMPU(IN PUCHAR PortBase,IN BOOLEAN IsCommand,IN UCHAR Value); 00633 00634 #ifdef _MSC_VER 00635 #pragma code_seg("PAGE") 00636 #endif 00637 00638 // make sure we're in UART mode 00639 NTSTATUS ResetHardware(PUCHAR portBase) 00640 { 00641 PAGED_CODE(); 00642 00643 return WriteMPU(portBase,COMMAND,MPU401_CMD_UART); 00644 } 00645 00646 #ifdef _MSC_VER 00647 #pragma code_seg("PAGE") 00648 #endif 00649 00650 // 00651 // We initialize the UART with interrupts suppressed so we don't 00652 // try to service the chip prematurely. 00653 // 00654 NTSTATUS CMiniportDMusUART::InitializeHardware(PINTERRUPTSYNC interruptSync,PUCHAR portBase) 00655 { 00656 PAGED_CODE(); 00657 00658 NTSTATUS ntStatus; 00659 if (m_UseIRQ) 00660 { 00661 ntStatus = interruptSync->CallSynchronizedRoutine(InitMPU,PVOID(portBase)); 00662 } 00663 else 00664 { 00665 ntStatus = InitMPU(NULL,PVOID(portBase)); 00666 } 00667 00668 if (NT_SUCCESS(ntStatus)) 00669 { 00670 // 00671 // Start the UART (this should trigger an interrupt). 00672 // 00673 ntStatus = ResetHardware(portBase); 00674 } 00675 else 00676 { 00677 DPRINT("*** InitMPU returned with ntStatus 0x%08x ***", ntStatus); 00678 } 00679 00680 m_fMPUInitialized = NT_SUCCESS(ntStatus); 00681 00682 return ntStatus; 00683 } 00684 00685 #ifdef _MSC_VER 00686 #pragma code_seg() 00687 #endif 00688 00689 /***************************************************************************** 00690 * InitMPU() 00691 ***************************************************************************** 00692 * Synchronized routine to initialize the MPU401. 00693 */ 00694 NTSTATUS 00695 NTAPI 00696 InitMPU 00697 ( 00698 IN PINTERRUPTSYNC InterruptSync, 00699 IN PVOID DynamicContext 00700 ) 00701 { 00702 DPRINT("InitMPU"); 00703 if (!DynamicContext) 00704 { 00705 return STATUS_INVALID_PARAMETER_2; 00706 } 00707 00708 PUCHAR portBase = PUCHAR(DynamicContext); 00709 UCHAR status; 00710 ULONGLONG startTime; 00711 BOOLEAN success; 00712 NTSTATUS ntStatus = STATUS_SUCCESS; 00713 00714 // 00715 // Reset the card (puts it into "smart mode") 00716 // 00717 ntStatus = WriteMPU(portBase,COMMAND,MPU401_CMD_RESET); 00718 00719 // wait for the acknowledgement 00720 // NOTE: When the Ack arrives, it will trigger an interrupt. 00721 // Normally the DPC routine would read in the ack byte and we 00722 // would never see it, however since we have the hardware locked (HwEnter), 00723 // we can read the port before the DPC can and thus we receive the Ack. 00724 startTime = PcGetTimeInterval(0); 00725 success = FALSE; 00726 while(PcGetTimeInterval(startTime) < GTI_MILLISECONDS(50)) 00727 { 00728 status = READ_PORT_UCHAR(portBase + MPU401_REG_STATUS); 00729 00730 if (UartFifoOkForRead(status)) // Is data waiting? 00731 { 00732 READ_PORT_UCHAR(portBase + MPU401_REG_DATA); // yep.. read ACK 00733 success = TRUE; // don't need to do more 00734 break; 00735 } 00736 KeStallExecutionProcessor(25); // microseconds 00737 } 00738 #if (DBG) 00739 if (!success) 00740 { 00741 DPRINT("First attempt to reset the MPU didn't get ACKed.\n"); 00742 } 00743 #endif // (DBG) 00744 00745 // NOTE: We cannot check the ACK byte because if the card was already in 00746 // UART mode it will not send an ACK but it will reset. 00747 00748 // reset the card again 00749 (void) WriteMPU(portBase,COMMAND,MPU401_CMD_RESET); 00750 00751 // wait for ack (again) 00752 startTime = PcGetTimeInterval(0); // This might take a while 00753 BYTE dataByte = 0; 00754 success = FALSE; 00755 while (PcGetTimeInterval(startTime) < GTI_MILLISECONDS(50)) 00756 { 00757 status = READ_PORT_UCHAR(portBase + MPU401_REG_STATUS); 00758 if (UartFifoOkForRead(status)) // Is data waiting? 00759 { 00760 dataByte = READ_PORT_UCHAR(portBase + MPU401_REG_DATA); // yep.. read ACK 00761 success = TRUE; // don't need to do more 00762 break; 00763 } 00764 KeStallExecutionProcessor(25); 00765 } 00766 00767 if ((0xFE != dataByte) || !success) // Did we succeed? If no second ACK, something is hosed 00768 { 00769 DPRINT("Second attempt to reset the MPU didn't get ACKed.\n"); 00770 DPRINT("Init Reset failure error. Ack = %X", ULONG(dataByte)); 00771 00772 ntStatus = STATUS_IO_DEVICE_ERROR; 00773 } 00774 00775 return ntStatus; 00776 } 00777 00778 #ifdef _MSC_VER 00779 #pragma code_seg() 00780 #endif 00781 00782 /***************************************************************************** 00783 * CMiniportDMusUARTStream::Write() 00784 ***************************************************************************** 00785 * Writes outgoing MIDI data. 00786 */ 00787 STDMETHODIMP_(NTSTATUS) 00788 CMiniportDMusUARTStream:: 00789 Write 00790 ( 00791 IN PVOID BufferAddress, 00792 IN ULONG Length, 00793 OUT PULONG BytesWritten 00794 ) 00795 { 00796 DPRINT("Write\n"); 00797 ASSERT(BytesWritten); 00798 if (!BufferAddress) 00799 { 00800 Length = 0; 00801 } 00802 00803 NTSTATUS ntStatus = STATUS_SUCCESS; 00804 00805 if (!m_fCapture) 00806 { 00807 PUCHAR pMidiData; 00808 ULONG count; 00809 00810 count = 0; 00811 pMidiData = PUCHAR(BufferAddress); 00812 00813 if (Length) 00814 { 00815 SYNCWRITECONTEXT context; 00816 context.Miniport = (m_pMiniport); 00817 context.PortBase = m_pPortBase; 00818 context.BufferAddress = pMidiData; 00819 context.Length = Length; 00820 context.BytesRead = &count; 00821 00822 if (m_pMiniport->m_UseIRQ) 00823 { 00824 ntStatus = m_pMiniport->m_pInterruptSync-> 00825 CallSynchronizedRoutine(SynchronizedDMusMPUWrite,PVOID(&context)); 00826 } 00827 else // !m_UseIRQ 00828 { 00829 ntStatus = SynchronizedDMusMPUWrite(NULL,PVOID(&context)); 00830 } // !m_UseIRQ 00831 00832 if (count == 0) 00833 { 00834 m_NumFailedMPUTries++; 00835 if (m_NumFailedMPUTries >= 100) 00836 { 00837 ntStatus = STATUS_IO_DEVICE_ERROR; 00838 m_NumFailedMPUTries = 0; 00839 } 00840 } 00841 else 00842 { 00843 m_NumFailedMPUTries = 0; 00844 } 00845 } // if we have data at all 00846 *BytesWritten = count; 00847 } 00848 else // called write on the read stream 00849 { 00850 ntStatus = STATUS_INVALID_DEVICE_REQUEST; 00851 } 00852 return ntStatus; 00853 } 00854 00855 #ifdef _MSC_VER 00856 #pragma code_seg() 00857 #endif 00858 00859 /***************************************************************************** 00860 * SynchronizedDMusMPUWrite() 00861 ***************************************************************************** 00862 * Writes outgoing MIDI data. 00863 */ 00864 NTSTATUS 00865 NTAPI 00866 SynchronizedDMusMPUWrite 00867 ( 00868 IN PINTERRUPTSYNC InterruptSync, 00869 IN PVOID syncWriteContext 00870 ) 00871 { 00872 PSYNCWRITECONTEXT context; 00873 context = (PSYNCWRITECONTEXT)syncWriteContext; 00874 ASSERT(context->Miniport); 00875 ASSERT(context->PortBase); 00876 ASSERT(context->BufferAddress); 00877 ASSERT(context->Length); 00878 ASSERT(context->BytesRead); 00879 00880 PUCHAR pChar = PUCHAR(context->BufferAddress); 00881 NTSTATUS ntStatus; // , readStatus 00882 ntStatus = STATUS_SUCCESS; 00883 // 00884 // while we're not there yet, and 00885 // while we don't have to wait on an aligned byte (including 0) 00886 // (we never wait on a byte. Better to come back later) 00887 /*readStatus = */ DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport)); 00888 while ( (*(context->BytesRead) < context->Length) 00889 && ( TryMPU(context->PortBase) 00890 || (*(context->BytesRead)%3) 00891 ) ) 00892 { 00893 ntStatus = WriteMPU(context->PortBase,DATA,*pChar); 00894 if (NT_SUCCESS(ntStatus)) 00895 { 00896 pChar++; 00897 *(context->BytesRead) = *(context->BytesRead) + 1; 00898 // readStatus = DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport)); 00899 } 00900 else 00901 { 00902 DPRINT("SynchronizedDMusMPUWrite failed (0x%08x)",ntStatus); 00903 break; 00904 } 00905 } 00906 /*readStatus = */ DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport)); 00907 return ntStatus; 00908 } 00909 00910 #define kMPUPollTimeout 2 00911 00912 #ifdef _MSC_VER 00913 #pragma code_seg() 00914 #endif 00915 00916 /***************************************************************************** 00917 * TryMPU() 00918 ***************************************************************************** 00919 * See if the MPU401 is free. 00920 */ 00921 BOOLEAN 00922 TryMPU 00923 ( 00924 IN PUCHAR PortBase 00925 ) 00926 { 00927 BOOLEAN success; 00928 USHORT numPolls; 00929 UCHAR status; 00930 00931 DPRINT("TryMPU"); 00932 numPolls = 0; 00933 00934 while (numPolls < kMPUPollTimeout) 00935 { 00936 status = READ_PORT_UCHAR(PortBase + MPU401_REG_STATUS); 00937 00938 if (UartFifoOkForWrite(status)) // Is this a good time to write data? 00939 { 00940 break; 00941 } 00942 numPolls++; 00943 } 00944 if (numPolls >= kMPUPollTimeout) 00945 { 00946 success = FALSE; 00947 DPRINT("TryMPU failed"); 00948 } 00949 else 00950 { 00951 success = TRUE; 00952 } 00953 00954 return success; 00955 } 00956 00957 #ifdef _MSC_VER 00958 #pragma code_seg() 00959 #endif 00960 00961 /***************************************************************************** 00962 * WriteMPU() 00963 ***************************************************************************** 00964 * Write a byte out to the MPU401. 00965 */ 00966 NTSTATUS 00967 WriteMPU 00968 ( 00969 IN PUCHAR PortBase, 00970 IN BOOLEAN IsCommand, 00971 IN UCHAR Value 00972 ) 00973 { 00974 DPRINT("WriteMPU"); 00975 NTSTATUS ntStatus = STATUS_IO_DEVICE_ERROR; 00976 00977 if (!PortBase) 00978 { 00979 DPRINT("O: PortBase is zero\n"); 00980 return ntStatus; 00981 } 00982 PUCHAR deviceAddr = PortBase + MPU401_REG_DATA; 00983 00984 if (IsCommand) 00985 { 00986 deviceAddr = PortBase + MPU401_REG_COMMAND; 00987 } 00988 00989 ULONGLONG startTime = PcGetTimeInterval(0); 00990 00991 while (PcGetTimeInterval(startTime) < GTI_MILLISECONDS(50)) 00992 { 00993 UCHAR status 00994 = READ_PORT_UCHAR(PortBase + MPU401_REG_STATUS); 00995 00996 if (UartFifoOkForWrite(status)) // Is this a good time to write data? 00997 { // yep (Jon comment) 00998 WRITE_PORT_UCHAR(deviceAddr,Value); 00999 DPRINT("WriteMPU emitted 0x%02x",Value); 01000 ntStatus = STATUS_SUCCESS; 01001 break; 01002 } 01003 } 01004 return ntStatus; 01005 } 01006 01007 #ifdef _MSC_VER 01008 #pragma code_seg() 01009 #endif 01010 01011 /***************************************************************************** 01012 * SnapTimeStamp() 01013 ***************************************************************************** 01014 * 01015 * At synchronized execution to ISR, copy miniport's volatile m_InputTimeStamp 01016 * to stream's m_SnapshotTimeStamp and zero m_InputTimeStamp. 01017 * 01018 */ 01019 STDMETHODIMP_(NTSTATUS) 01020 SnapTimeStamp(PINTERRUPTSYNC InterruptSync,PVOID pStream) 01021 { 01022 CMiniportDMusUARTStream *pMPStream = (CMiniportDMusUARTStream *)pStream; 01023 01024 // cache the timestamp 01025 pMPStream->m_SnapshotTimeStamp = pMPStream->m_pMiniport->m_InputTimeStamp; 01026 01027 // if the window is closed, zero the timestamp 01028 if (pMPStream->m_pMiniport->m_MPUInputBufferHead == 01029 pMPStream->m_pMiniport->m_MPUInputBufferTail) 01030 { 01031 pMPStream->m_pMiniport->m_InputTimeStamp = 0; 01032 } 01033 01034 return STATUS_SUCCESS; 01035 } 01036 01037 /***************************************************************************** 01038 * CMiniportDMusUARTStream::SourceEvtsToPort() 01039 ***************************************************************************** 01040 * 01041 * Reads incoming MIDI data, feeds into DMus events. 01042 * No need to touch the hardware, just read from our SW FIFO. 01043 * 01044 */ 01045 STDMETHODIMP_(NTSTATUS) 01046 CMiniportDMusUARTStream::SourceEvtsToPort() 01047 { 01048 NTSTATUS ntStatus; 01049 01050 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 01051 DPRINT("SourceEvtsToPort"); 01052 01053 if (m_fCapture) 01054 { 01055 ntStatus = STATUS_SUCCESS; 01056 if (m_pMiniport->m_MPUInputBufferHead != m_pMiniport->m_MPUInputBufferTail) 01057 { 01058 PDMUS_KERNEL_EVENT aDMKEvt,eventTail,eventHead = NULL; 01059 01060 while (m_pMiniport->m_MPUInputBufferHead != m_pMiniport->m_MPUInputBufferTail) 01061 { 01062 (void) m_AllocatorMXF->GetMessage(&aDMKEvt); 01063 if (!aDMKEvt) 01064 { 01065 DPRINT("SourceEvtsToPort can't allocate DMKEvt"); 01066 return STATUS_INSUFFICIENT_RESOURCES; 01067 } 01068 01069 // put this event at the end of the list 01070 if (!eventHead) 01071 { 01072 eventHead = aDMKEvt; 01073 } 01074 else 01075 { 01076 eventTail = eventHead; 01077 while (eventTail->pNextEvt) 01078 { 01079 eventTail = eventTail->pNextEvt; 01080 } 01081 eventTail->pNextEvt = aDMKEvt; 01082 } 01083 // read all the bytes out of the buffer, into event(s) 01084 for (aDMKEvt->cbEvent = 0; aDMKEvt->cbEvent < sizeof(PBYTE); aDMKEvt->cbEvent++) 01085 { 01086 if (m_pMiniport->m_MPUInputBufferHead == m_pMiniport->m_MPUInputBufferTail) 01087 { 01088 // _DbgPrintF(DEBUGLVL_TERSE, ("SourceEvtsToPort m_MPUInputBufferHead met m_MPUInputBufferTail, overrun")); 01089 break; 01090 } 01091 aDMKEvt->uData.abData[aDMKEvt->cbEvent] = m_pMiniport->m_MPUInputBuffer[m_pMiniport->m_MPUInputBufferHead]; 01092 m_pMiniport->m_MPUInputBufferHead++; 01093 if (m_pMiniport->m_MPUInputBufferHead >= kMPUInputBufferSize) 01094 { 01095 m_pMiniport->m_MPUInputBufferHead = 0; 01096 } 01097 } 01098 } 01099 01100 if (m_pMiniport->m_UseIRQ) 01101 { 01102 ntStatus = m_pMiniport->m_pInterruptSync->CallSynchronizedRoutine(SnapTimeStamp,PVOID(this)); 01103 } 01104 else // !m_UseIRQ 01105 { 01106 ntStatus = SnapTimeStamp(NULL,PVOID(this)); 01107 } // !m_UseIRQ 01108 aDMKEvt = eventHead; 01109 while (aDMKEvt) 01110 { 01111 aDMKEvt->ullPresTime100ns = m_SnapshotTimeStamp; 01112 aDMKEvt->usChannelGroup = 1; 01113 aDMKEvt->usFlags = DMUS_KEF_EVENT_INCOMPLETE; 01114 aDMKEvt = aDMKEvt->pNextEvt; 01115 } 01116 (void)m_sinkMXF->PutMessage(eventHead); 01117 } 01118 } 01119 else // render stream 01120 { 01121 DPRINT("SourceEvtsToPort called on render stream"); 01122 ntStatus = STATUS_INVALID_DEVICE_REQUEST; 01123 } 01124 return ntStatus; 01125 } 01126 01127 #ifdef _MSC_VER 01128 #pragma code_seg() 01129 #endif 01130 01131 /***************************************************************************** 01132 * DMusMPUInterruptServiceRoutine() 01133 ***************************************************************************** 01134 * ISR. 01135 */ 01136 NTSTATUS 01137 NTAPI 01138 DMusMPUInterruptServiceRoutine 01139 ( 01140 IN PINTERRUPTSYNC InterruptSync, 01141 IN PVOID DynamicContext 01142 ) 01143 { 01144 DPRINT("DMusMPUInterruptServiceRoutine"); 01145 ULONGLONG startTime; 01146 01147 ASSERT(DynamicContext); 01148 01149 NTSTATUS ntStatus; 01150 BOOL newBytesAvailable; 01151 CMiniportDMusUART *that; 01152 NTSTATUS clockStatus; 01153 01154 that = (CMiniportDMusUART *) DynamicContext; 01155 newBytesAvailable = FALSE; 01156 ntStatus = STATUS_UNSUCCESSFUL; 01157 01158 UCHAR portStatus = 0xff; 01159 01160 // 01161 // Read the MPU status byte. 01162 // 01163 if (that->m_pPortBase) 01164 { 01165 portStatus = 01166 READ_PORT_UCHAR(that->m_pPortBase + MPU401_REG_STATUS); 01167 01168 // 01169 // If there is outstanding work to do and there is a port-driver for 01170 // the MPU miniport... 01171 // 01172 if (UartFifoOkForRead(portStatus) && that->m_pPort) 01173 { 01174 startTime = PcGetTimeInterval(0); 01175 while ( (PcGetTimeInterval(startTime) < GTI_MILLISECONDS(50)) 01176 && (UartFifoOkForRead(portStatus)) ) 01177 { 01178 UCHAR uDest = READ_PORT_UCHAR(that->m_pPortBase + MPU401_REG_DATA); 01179 if ( (that->m_KSStateInput == KSSTATE_RUN) 01180 && (that->m_NumCaptureStreams) 01181 ) 01182 { 01183 ULONG buffHead = that->m_MPUInputBufferHead; 01184 if ( (that->m_MPUInputBufferTail + 1 == buffHead) 01185 || (that->m_MPUInputBufferTail + 1 - kMPUInputBufferSize == buffHead)) 01186 { 01187 DPRINT("*****MPU Input Buffer Overflow*****"); 01188 } 01189 else 01190 { 01191 if (!that->m_InputTimeStamp) 01192 { 01193 clockStatus = that->m_MasterClock->GetTime(&that->m_InputTimeStamp); 01194 if (STATUS_SUCCESS != clockStatus) 01195 { 01196 DPRINT("GetTime failed for clock 0x%08x",that->m_MasterClock); 01197 } 01198 } 01199 newBytesAvailable = TRUE; 01200 // ...place the data in our FIFO... 01201 that->m_MPUInputBuffer[that->m_MPUInputBufferTail] = uDest; 01202 ASSERT(that->m_MPUInputBufferTail < kMPUInputBufferSize); 01203 01204 that->m_MPUInputBufferTail++; 01205 if (that->m_MPUInputBufferTail >= kMPUInputBufferSize) 01206 { 01207 that->m_MPUInputBufferTail = 0; 01208 } 01209 } 01210 } 01211 // 01212 // Look for more MIDI data. 01213 // 01214 portStatus = 01215 READ_PORT_UCHAR(that->m_pPortBase + MPU401_REG_STATUS); 01216 } // either there's no data or we ran too long 01217 if (newBytesAvailable) 01218 { 01219 // 01220 // ...notify the MPU port driver that we have bytes. 01221 // 01222 that->m_pPort->Notify(that->m_pServiceGroup); 01223 } 01224 ntStatus = STATUS_SUCCESS; 01225 } 01226 } 01227 01228 return ntStatus; 01229 } 01230 01231 /***************************************************************************** 01232 * CMiniportDMusUART::GetDescription() 01233 ***************************************************************************** 01234 * Gets the topology. 01235 */ 01236 STDMETHODIMP_(NTSTATUS) 01237 CMiniportDMusUART:: 01238 GetDescription 01239 ( 01240 OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor 01241 ) 01242 { 01243 PAGED_CODE(); 01244 01245 ASSERT(OutFilterDescriptor); 01246 01247 DPRINT("GetDescription"); 01248 01249 *OutFilterDescriptor = &MiniportFilterDescriptor; 01250 01251 return STATUS_SUCCESS; 01252 } 01253 01254 #ifdef _MSC_VER 01255 #pragma code_seg("PAGE") 01256 #endif 01257 01258 NTSTATUS 01259 NewMiniportDMusUART( 01260 OUT PMINIPORT* OutMiniport, 01261 IN REFCLSID ClassId) 01262 { 01263 CMiniportDMusUART * This; 01264 NTSTATUS Status; 01265 01266 This= new(NonPagedPool, TAG_PORTCLASS) CMiniportDMusUART(NULL); 01267 if (!This) 01268 return STATUS_INSUFFICIENT_RESOURCES; 01269 01270 Status = This->QueryInterface(IID_IMiniport, (PVOID*)OutMiniport); 01271 01272 if (!NT_SUCCESS(Status)) 01273 { 01274 delete This; 01275 } 01276 01277 DPRINT("NewMiniportDMusUART %p Status %x\n", *OutMiniport, Status); 01278 return Status; 01279 } 01280 01281 01282 #ifdef _MSC_VER 01283 #pragma code_seg("PAGE") 01284 #endif 01285 01286 /***************************************************************************** 01287 * CMiniportDMusUART::ProcessResources() 01288 ***************************************************************************** 01289 * Processes the resource list, setting up helper objects accordingly. 01290 */ 01291 NTSTATUS 01292 CMiniportDMusUART:: 01293 ProcessResources 01294 ( 01295 IN PRESOURCELIST ResourceList 01296 ) 01297 { 01298 PAGED_CODE(); 01299 01300 DPRINT("ProcessResources"); 01301 01302 ASSERT(ResourceList); 01303 if (!ResourceList) 01304 { 01305 return STATUS_DEVICE_CONFIGURATION_ERROR; 01306 } 01307 // 01308 // Get counts for the types of resources. 01309 // 01310 ULONG countIO = ResourceList->NumberOfPorts(); 01311 ULONG countIRQ = ResourceList->NumberOfInterrupts(); 01312 ULONG countDMA = ResourceList->NumberOfDmas(); 01313 ULONG lengthIO = ResourceList->FindTranslatedPort(0)->u.Port.Length; 01314 01315 #if DBG 01316 DPRINT("Starting MPU401 Port 0x%lx", ResourceList->FindTranslatedPort(0)->u.Port.Start.LowPart); 01317 #endif 01318 01319 NTSTATUS ntStatus = STATUS_SUCCESS; 01320 01321 // 01322 // Make sure we have the expected number of resources. 01323 // 01324 if ( (countIO != 1) 01325 || (countIRQ > 1) 01326 || (countDMA != 0) 01327 || (lengthIO == 0) 01328 ) 01329 { 01330 DPRINT("Unknown ResourceList configuraton"); 01331 ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR; 01332 } 01333 01334 if (NT_SUCCESS(ntStatus)) 01335 { 01336 // 01337 // Get the port address. 01338 // 01339 m_pPortBase = 01340 PUCHAR(ResourceList->FindTranslatedPort(0)->u.Port.Start.QuadPart); 01341 01342 ntStatus = InitializeHardware(m_pInterruptSync,m_pPortBase); 01343 } 01344 01345 return ntStatus; 01346 } 01347 01348 #ifdef _MSC_VER 01349 #pragma code_seg("PAGE") 01350 #endif 01351 /***************************************************************************** 01352 * CMiniportDMusUART::NonDelegatingQueryInterface() 01353 ***************************************************************************** 01354 * Obtains an interface. This function works just like a COM QueryInterface 01355 * call and is used if the object is not being aggregated. 01356 */ 01357 STDMETHODIMP_(NTSTATUS) 01358 CMiniportDMusUART::QueryInterface 01359 ( 01360 REFIID Interface, 01361 PVOID * Object 01362 ) 01363 { 01364 PAGED_CODE(); 01365 01366 DPRINT("Miniport::NonDelegatingQueryInterface"); 01367 ASSERT(Object); 01368 01369 if (IsEqualGUIDAligned(Interface,IID_IUnknown)) 01370 { 01371 *Object = PVOID(PUNKNOWN(PMINIPORTDMUS(this))); 01372 } 01373 else 01374 if (IsEqualGUIDAligned(Interface,IID_IMiniport)) 01375 { 01376 *Object = PVOID(PMINIPORT(this)); 01377 } 01378 else 01379 if (IsEqualGUIDAligned(Interface,IID_IMiniportDMus)) 01380 { 01381 *Object = PVOID(PMINIPORTDMUS(this)); 01382 } 01383 else 01384 if (IsEqualGUIDAligned(Interface,IID_IMusicTechnology)) 01385 { 01386 *Object = PVOID(PMUSICTECHNOLOGY(this)); 01387 } 01388 else 01389 if (IsEqualGUIDAligned(Interface,IID_IPowerNotify)) 01390 { 01391 *Object = PVOID(PPOWERNOTIFY(this)); 01392 } 01393 else 01394 { 01395 *Object = NULL; 01396 } 01397 01398 if (*Object) 01399 { 01400 // 01401 // We reference the interface for the caller. 01402 // 01403 PUNKNOWN(*Object)->AddRef(); 01404 return STATUS_SUCCESS; 01405 } 01406 01407 return STATUS_INVALID_PARAMETER; 01408 } 01409 01410 #ifdef _MSC_VER 01411 #pragma code_seg("PAGE") 01412 #endif 01413 /***************************************************************************** 01414 * CMiniportDMusUART::~CMiniportDMusUART() 01415 ***************************************************************************** 01416 * Destructor. 01417 */ 01418 CMiniportDMusUART::~CMiniportDMusUART(void) 01419 { 01420 PAGED_CODE(); 01421 01422 DPRINT("~CMiniportDMusUART"); 01423 01424 ASSERT(0 == m_NumCaptureStreams); 01425 ASSERT(0 == m_NumRenderStreams); 01426 01427 // reset the HW so we don't get anymore interrupts 01428 if (m_UseIRQ && m_pInterruptSync) 01429 { 01430 (void) m_pInterruptSync->CallSynchronizedRoutine((PINTERRUPTSYNCROUTINE)InitMPU,PVOID(m_pPortBase)); 01431 } 01432 else 01433 { 01434 (void) InitMPU(NULL,PVOID(m_pPortBase)); 01435 } 01436 01437 if (m_pInterruptSync) 01438 { 01439 m_pInterruptSync->Release(); 01440 m_pInterruptSync = NULL; 01441 } 01442 if (m_pServiceGroup) 01443 { 01444 m_pServiceGroup->Release(); 01445 m_pServiceGroup = NULL; 01446 } 01447 if (m_pPort) 01448 { 01449 m_pPort->Release(); 01450 m_pPort = NULL; 01451 } 01452 } 01453 01454 #ifdef _MSC_VER 01455 #pragma code_seg("PAGE") 01456 #endif 01457 /***************************************************************************** 01458 * CMiniportDMusUART::Init() 01459 ***************************************************************************** 01460 * Initializes a the miniport. 01461 */ 01462 STDMETHODIMP_(NTSTATUS) 01463 CMiniportDMusUART:: 01464 Init 01465 ( 01466 IN PUNKNOWN UnknownInterruptSync OPTIONAL, 01467 IN PRESOURCELIST ResourceList, 01468 IN PPORTDMUS Port_, 01469 OUT PSERVICEGROUP * ServiceGroup 01470 ) 01471 { 01472 PAGED_CODE(); 01473 01474 ASSERT(ResourceList); 01475 if (!ResourceList) 01476 { 01477 return STATUS_DEVICE_CONFIGURATION_ERROR; 01478 } 01479 01480 ASSERT(Port_); 01481 ASSERT(ServiceGroup); 01482 01483 DPRINT("Init"); 01484 01485 *ServiceGroup = NULL; 01486 m_pPortBase = 0; 01487 m_fMPUInitialized = FALSE; 01488 01489 // This will remain unspecified if the miniport does not get any power 01490 // messages. 01491 // 01492 m_PowerState.DeviceState = PowerDeviceUnspecified; 01493 01494 // 01495 // AddRef() is required because we are keeping this pointer. 01496 // 01497 m_pPort = Port_; 01498 m_pPort->AddRef(); 01499 01500 // Set dataformat. 01501 // 01502 if (IsEqualGUIDAligned(m_MusicFormatTechnology, GUID_NULL)) 01503 { 01504 RtlCopyMemory( &m_MusicFormatTechnology, 01505 &KSMUSIC_TECHNOLOGY_PORT, 01506 sizeof(GUID)); 01507 } 01508 RtlCopyMemory( &PinDataRangesStreamLegacy.Technology, 01509 &m_MusicFormatTechnology, 01510 sizeof(GUID)); 01511 RtlCopyMemory( &PinDataRangesStreamDMusic.Technology, 01512 &m_MusicFormatTechnology, 01513 sizeof(GUID)); 01514 01515 for (ULONG bufferCount = 0;bufferCount < kMPUInputBufferSize;bufferCount++) 01516 { 01517 m_MPUInputBuffer[bufferCount] = 0; 01518 } 01519 m_MPUInputBufferHead = 0; 01520 m_MPUInputBufferTail = 0; 01521 m_InputTimeStamp = 0; 01522 m_KSStateInput = KSSTATE_STOP; 01523 01524 NTSTATUS ntStatus = STATUS_SUCCESS; 01525 01526 m_NumRenderStreams = 0; 01527 m_NumCaptureStreams = 0; 01528 01529 m_UseIRQ = TRUE; 01530 if (ResourceList->NumberOfInterrupts() == 0) 01531 { 01532 m_UseIRQ = FALSE; 01533 } 01534 01535 ntStatus = PcNewServiceGroup(&m_pServiceGroup,NULL); 01536 if (NT_SUCCESS(ntStatus) && !m_pServiceGroup) // keep any error 01537 { 01538 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 01539 } 01540 01541 if (NT_SUCCESS(ntStatus)) 01542 { 01543 *ServiceGroup = m_pServiceGroup; 01544 m_pServiceGroup->AddRef(); 01545 01546 // 01547 // Register the service group with the port early so the port is 01548 // prepared to handle interrupts. 01549 // 01550 m_pPort->RegisterServiceGroup(m_pServiceGroup); 01551 } 01552 01553 if (NT_SUCCESS(ntStatus) && m_UseIRQ) 01554 { 01555 // 01556 // Due to a bug in the InterruptSync design, we shouldn't share 01557 // the interrupt sync object. Whoever goes away first 01558 // will disconnect it, and the other points off into nowhere. 01559 // 01560 // Instead we generate our own interrupt sync object. 01561 // 01562 UnknownInterruptSync = NULL; 01563 01564 if (UnknownInterruptSync) 01565 { 01566 ntStatus = 01567 UnknownInterruptSync->QueryInterface 01568 ( 01569 IID_IInterruptSync, 01570 (PVOID *) &m_pInterruptSync 01571 ); 01572 01573 if (!m_pInterruptSync && NT_SUCCESS(ntStatus)) // keep any error 01574 { 01575 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 01576 } 01577 if (NT_SUCCESS(ntStatus)) 01578 { // run this ISR first 01579 ntStatus = m_pInterruptSync-> 01580 RegisterServiceRoutine(DMusMPUInterruptServiceRoutine,PVOID(this),TRUE); 01581 } 01582 01583 } 01584 else 01585 { // create our own interruptsync mechanism. 01586 ntStatus = 01587 PcNewInterruptSync 01588 ( 01589 &m_pInterruptSync, 01590 NULL, 01591 ResourceList, 01592 0, // Resource Index 01593 InterruptSyncModeNormal // Run ISRs once until we get SUCCESS 01594 ); 01595 01596 if (!m_pInterruptSync && NT_SUCCESS(ntStatus)) // keep any error 01597 { 01598 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 01599 } 01600 01601 if (NT_SUCCESS(ntStatus)) 01602 { 01603 ntStatus = m_pInterruptSync->RegisterServiceRoutine( 01604 DMusMPUInterruptServiceRoutine, 01605 PVOID(this), 01606 TRUE); // run this ISR first 01607 } 01608 if (NT_SUCCESS(ntStatus)) 01609 { 01610 ntStatus = m_pInterruptSync->Connect(); 01611 } 01612 } 01613 } 01614 01615 if (NT_SUCCESS(ntStatus)) 01616 { 01617 ntStatus = ProcessResources(ResourceList); 01618 } 01619 01620 if (!NT_SUCCESS(ntStatus)) 01621 { 01622 // 01623 // clean up our mess 01624 // 01625 01626 // clean up the interrupt sync 01627 if( m_pInterruptSync ) 01628 { 01629 m_pInterruptSync->Release(); 01630 m_pInterruptSync = NULL; 01631 } 01632 01633 // clean up the service group 01634 if( m_pServiceGroup ) 01635 { 01636 m_pServiceGroup->Release(); 01637 m_pServiceGroup = NULL; 01638 } 01639 01640 // clean up the out param service group. 01641 if (*ServiceGroup) 01642 { 01643 (*ServiceGroup)->Release(); 01644 (*ServiceGroup) = NULL; 01645 } 01646 01647 // release the port 01648 m_pPort->Release(); 01649 m_pPort = NULL; 01650 } 01651 01652 return ntStatus; 01653 } 01654 01655 #ifdef _MSC_VER 01656 #pragma code_seg("PAGE") 01657 #endif 01658 /***************************************************************************** 01659 * CMiniportDMusUART::NewStream() 01660 ***************************************************************************** 01661 * Gets the topology. 01662 */ 01663 STDMETHODIMP_(NTSTATUS) 01664 CMiniportDMusUART:: 01665 NewStream 01666 ( 01667 OUT PMXF * MXF, 01668 IN PUNKNOWN OuterUnknown OPTIONAL, 01669 IN POOL_TYPE PoolType, 01670 IN ULONG PinID, 01671 IN DMUS_STREAM_TYPE StreamType, 01672 IN PKSDATAFORMAT DataFormat, 01673 OUT PSERVICEGROUP * ServiceGroup, 01674 IN PAllocatorMXF AllocatorMXF, 01675 IN PMASTERCLOCK MasterClock, 01676 OUT PULONGLONG SchedulePreFetch 01677 ) 01678 { 01679 PAGED_CODE(); 01680 01681 DPRINT("NewStream"); 01682 NTSTATUS ntStatus = STATUS_SUCCESS; 01683 01684 // In 100 ns, we want stuff as soon as it comes in 01685 // 01686 *SchedulePreFetch = 0; 01687 01688 // if we don't have any streams already open, get the hardware ready. 01689 if ((!m_NumCaptureStreams) && (!m_NumRenderStreams)) 01690 { 01691 ntStatus = ResetHardware(m_pPortBase); 01692 if (!NT_SUCCESS(ntStatus)) 01693 { 01694 DPRINT("CMiniportDMusUART::NewStream ResetHardware failed"); 01695 return ntStatus; 01696 } 01697 } 01698 01699 if ( ((m_NumCaptureStreams < kMaxNumCaptureStreams) 01700 && (StreamType == DMUS_STREAM_MIDI_CAPTURE)) 01701 || ((m_NumRenderStreams < kMaxNumLegacyRenderStreams + kMaxNumDMusicRenderStreams) 01702 && (StreamType == DMUS_STREAM_MIDI_RENDER)) 01703 ) 01704 { 01705 CMiniportDMusUARTStream *pStream = 01706 new(PoolType) CMiniportDMusUARTStream(); 01707 01708 if (pStream) 01709 { 01710 pStream->AddRef(); 01711 01712 ntStatus = 01713 pStream->Init(this,m_pPortBase,(StreamType == DMUS_STREAM_MIDI_CAPTURE),AllocatorMXF,MasterClock); 01714 01715 if (NT_SUCCESS(ntStatus)) 01716 { 01717 *MXF = PMXF(pStream); 01718 (*MXF)->AddRef(); 01719 01720 if (StreamType == DMUS_STREAM_MIDI_CAPTURE) 01721 { 01722 m_NumCaptureStreams++; 01723 *ServiceGroup = m_pServiceGroup; 01724 (*ServiceGroup)->AddRef(); 01725 } 01726 else 01727 { 01728 m_NumRenderStreams++; 01729 *ServiceGroup = NULL; 01730 } 01731 } 01732 01733 pStream->Release(); 01734 } 01735 else 01736 { 01737 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 01738 } 01739 } 01740 else 01741 { 01742 ntStatus = STATUS_INVALID_DEVICE_REQUEST; 01743 if (StreamType == DMUS_STREAM_MIDI_CAPTURE) 01744 { 01745 DPRINT("NewStream failed, too many capture streams"); 01746 } 01747 else if (StreamType == DMUS_STREAM_MIDI_RENDER) 01748 { 01749 DPRINT("NewStream failed, too many render streams"); 01750 } 01751 else 01752 { 01753 DPRINT("NewStream invalid stream type"); 01754 } 01755 } 01756 01757 return ntStatus; 01758 } 01759 01760 #ifdef _MSC_VER 01761 #pragma code_seg("PAGE") 01762 #endif 01763 /***************************************************************************** 01764 * CMiniportDMusUART::SetTechnology() 01765 ***************************************************************************** 01766 * Sets pindatarange technology. 01767 */ 01768 STDMETHODIMP_(NTSTATUS) 01769 CMiniportDMusUART:: 01770 SetTechnology 01771 ( 01772 IN const GUID * Technology 01773 ) 01774 { 01775 PAGED_CODE(); 01776 01777 NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; 01778 01779 // Fail if miniport has already been initialized. 01780 // 01781 if (NULL == m_pPort) 01782 { 01783 RtlCopyMemory(&m_MusicFormatTechnology, Technology, sizeof(GUID)); 01784 ntStatus = STATUS_SUCCESS; 01785 } 01786 01787 return ntStatus; 01788 } // SetTechnology 01789 01790 /***************************************************************************** 01791 * CMiniportDMusUART::PowerChangeNotify() 01792 ***************************************************************************** 01793 * Handle power state change for the miniport. 01794 */ 01795 #ifdef _MSC_VER 01796 #pragma code_seg("PAGE") 01797 #endif 01798 01799 STDMETHODIMP_(void) 01800 CMiniportDMusUART:: 01801 PowerChangeNotify 01802 ( 01803 IN POWER_STATE PowerState 01804 ) 01805 { 01806 PAGED_CODE(); 01807 01808 DPRINT("CMiniportDMusUART::PoweChangeNotify D%d", PowerState.DeviceState); 01809 01810 switch (PowerState.DeviceState) 01811 { 01812 case PowerDeviceD0: 01813 if (m_PowerState.DeviceState != PowerDeviceD0) 01814 { 01815 if (!NT_SUCCESS(InitializeHardware(m_pInterruptSync,m_pPortBase))) 01816 { 01817 DPRINT("InitializeHardware failed when resuming"); 01818 } 01819 } 01820 break; 01821 01822 case PowerDeviceD1: 01823 case PowerDeviceD2: 01824 case PowerDeviceD3: 01825 default: 01826 break; 01827 } 01828 m_PowerState.DeviceState = PowerState.DeviceState; 01829 } // PowerChangeNotify 01830 01831 #ifdef _MSC_VER 01832 #pragma code_seg("PAGE") 01833 #endif 01834 /***************************************************************************** 01835 * CMiniportDMusUARTStream::NonDelegatingQueryInterface() 01836 ***************************************************************************** 01837 * Obtains an interface. This function works just like a COM QueryInterface 01838 * call and is used if the object is not being aggregated. 01839 */ 01840 STDMETHODIMP_(NTSTATUS) 01841 CMiniportDMusUARTStream::QueryInterface 01842 ( 01843 REFIID Interface, 01844 PVOID * Object 01845 ) 01846 { 01847 PAGED_CODE(); 01848 01849 DPRINT("Stream::NonDelegatingQueryInterface"); 01850 ASSERT(Object); 01851 01852 if (IsEqualGUIDAligned(Interface,IID_IUnknown)) 01853 { 01854 *Object = PVOID(PUNKNOWN(this)); 01855 } 01856 else 01857 if (IsEqualGUIDAligned(Interface,IID_IMXF)) 01858 { 01859 *Object = PVOID(PMXF(this)); 01860 } 01861 else 01862 { 01863 *Object = NULL; 01864 } 01865 01866 if (*Object) 01867 { 01868 // 01869 // We reference the interface for the caller. 01870 // 01871 PUNKNOWN(*Object)->AddRef(); 01872 return STATUS_SUCCESS; 01873 } 01874 01875 return STATUS_INVALID_PARAMETER; 01876 } 01877 01878 #ifdef _MSC_VER 01879 #pragma code_seg("PAGE") 01880 #endif 01881 /***************************************************************************** 01882 * CMiniportDMusUARTStream::~CMiniportDMusUARTStream() 01883 ***************************************************************************** 01884 * Destructs a stream. 01885 */ 01886 CMiniportDMusUARTStream::~CMiniportDMusUARTStream(void) 01887 { 01888 PAGED_CODE(); 01889 01890 DPRINT("~CMiniportDMusUARTStream"); 01891 01892 KeCancelTimer(&m_TimerEvent); 01893 01894 if (m_DMKEvtQueue) 01895 { 01896 if (m_AllocatorMXF) 01897 { 01898 m_AllocatorMXF->PutMessage(m_DMKEvtQueue); 01899 } 01900 else 01901 { 01902 DPRINT("~CMiniportDMusUARTStream, no allocator, can't flush DMKEvts"); 01903 } 01904 m_DMKEvtQueue = NULL; 01905 } 01906 if (m_AllocatorMXF) 01907 { 01908 m_AllocatorMXF->Release(); 01909 m_AllocatorMXF = NULL; 01910 } 01911 01912 if (m_pMiniport) 01913 { 01914 if (m_fCapture) 01915 { 01916 m_pMiniport->m_NumCaptureStreams--; 01917 } 01918 else 01919 { 01920 m_pMiniport->m_NumRenderStreams--; 01921 } 01922 01923 m_pMiniport->Release(); 01924 } 01925 } 01926 01927 #ifdef _MSC_VER 01928 #pragma code_seg("PAGE") 01929 #endif 01930 /***************************************************************************** 01931 * CMiniportDMusUARTStream::Init() 01932 ***************************************************************************** 01933 * Initializes a stream. 01934 */ 01935 STDMETHODIMP_(NTSTATUS) 01936 CMiniportDMusUARTStream:: 01937 Init 01938 ( 01939 IN CMiniportDMusUART * pMiniport, 01940 IN PUCHAR pPortBase, 01941 IN BOOLEAN fCapture, 01942 IN PAllocatorMXF allocatorMXF, 01943 IN PMASTERCLOCK masterClock 01944 ) 01945 { 01946 PAGED_CODE(); 01947 01948 ASSERT(pMiniport); 01949 ASSERT(pPortBase); 01950 01951 DPRINT("Init"); 01952 01953 m_NumFailedMPUTries = 0; 01954 m_TimerQueued = FALSE; 01955 KeInitializeSpinLock(&m_DpcSpinLock); 01956 m_pMiniport = pMiniport; 01957 m_pMiniport->AddRef(); 01958 01959 pMiniport->m_MasterClock = masterClock; 01960 01961 m_pPortBase = pPortBase; 01962 m_fCapture = fCapture; 01963 01964 m_SnapshotTimeStamp = 0; 01965 m_DMKEvtQueue = NULL; 01966 m_DMKEvtOffset = 0; 01967 01968 m_NumberOfRetries = 0; 01969 01970 if (allocatorMXF) 01971 { 01972 allocatorMXF->AddRef(); 01973 m_AllocatorMXF = allocatorMXF; 01974 m_sinkMXF = m_AllocatorMXF; 01975 } 01976 else 01977 { 01978 return STATUS_INVALID_PARAMETER; 01979 } 01980 01981 KeInitializeDpc 01982 ( 01983 &m_Dpc, 01984 &::DMusUARTTimerDPC, 01985 PVOID(this) 01986 ); 01987 KeInitializeTimer(&m_TimerEvent); 01988 01989 return STATUS_SUCCESS; 01990 } 01991 01992 #ifdef _MSC_VER 01993 #pragma code_seg("PAGE") 01994 #endif 01995 /***************************************************************************** 01996 * CMiniportDMusUARTStream::SetState() 01997 ***************************************************************************** 01998 * Sets the state of the channel. 01999 */ 02000 STDMETHODIMP_(NTSTATUS) 02001 CMiniportDMusUARTStream:: 02002 SetState 02003 ( 02004 IN KSSTATE NewState 02005 ) 02006 { 02007 PAGED_CODE(); 02008 02009 DPRINT("SetState %d",NewState); 02010 02011 if (NewState == KSSTATE_RUN) 02012 { 02013 if (m_pMiniport->m_fMPUInitialized) 02014 { 02015 LARGE_INTEGER timeDue100ns; 02016 timeDue100ns.QuadPart = 0; 02017 KeSetTimer(&m_TimerEvent,timeDue100ns,&m_Dpc); 02018 } 02019 else 02020 { 02021 DPRINT("CMiniportDMusUARTStream::SetState KSSTATE_RUN failed due to uninitialized MPU"); 02022 return STATUS_INVALID_DEVICE_STATE; 02023 } 02024 } 02025 02026 if (m_fCapture) 02027 { 02028 m_pMiniport->m_KSStateInput = NewState; 02029 if (NewState == KSSTATE_STOP) // STOPping 02030 { 02031 m_pMiniport->m_MPUInputBufferHead = 0; // Previously read bytes are discarded. 02032 m_pMiniport->m_MPUInputBufferTail = 0; // The entire FIFO is available. 02033 } 02034 } 02035 return STATUS_SUCCESS; 02036 } 02037 02038 #ifdef _MSC_VER 02039 #pragma code_seg() 02040 #endif 02041 02042 02043 /***************************************************************************** 02044 * CMiniportDMusUART::Service() 02045 ***************************************************************************** 02046 * DPC-mode service call from the port. 02047 */ 02048 STDMETHODIMP_(void) 02049 CMiniportDMusUART:: 02050 Service 02051 ( void 02052 ) 02053 { 02054 DPRINT("Service"); 02055 if (!m_NumCaptureStreams) 02056 { 02057 // we should never get here.... 02058 // if we do, we must have read some trash, 02059 // so just reset the input FIFO 02060 m_MPUInputBufferTail = m_MPUInputBufferHead = 0; 02061 } 02062 } 02063 02064 #ifdef _MSC_VER 02065 #pragma code_seg("PAGE") 02066 #endif 02067 02068 /***************************************************************************** 02069 * CMiniportDMusUARTStream::ConnectOutput() 02070 ***************************************************************************** 02071 * Writes outgoing MIDI data. 02072 */ 02073 NTSTATUS 02074 CMiniportDMusUARTStream:: 02075 ConnectOutput(PMXF sinkMXF) 02076 { 02077 PAGED_CODE(); 02078 02079 if (m_fCapture) 02080 { 02081 if ((sinkMXF) && (m_sinkMXF == m_AllocatorMXF)) 02082 { 02083 DPRINT("ConnectOutput"); 02084 m_sinkMXF = sinkMXF; 02085 return STATUS_SUCCESS; 02086 } 02087 else 02088 { 02089 DPRINT("ConnectOutput failed"); 02090 } 02091 } 02092 else 02093 { 02094 DPRINT("ConnectOutput called on renderer; failed"); 02095 } 02096 return STATUS_UNSUCCESSFUL; 02097 } 02098 02099 #ifdef _MSC_VER 02100 #pragma code_seg("PAGE") 02101 #endif 02102 02103 /***************************************************************************** 02104 * CMiniportDMusUARTStream::DisconnectOutput() 02105 ***************************************************************************** 02106 * Writes outgoing MIDI data. 02107 */ 02108 NTSTATUS 02109 CMiniportDMusUARTStream:: 02110 DisconnectOutput(PMXF sinkMXF) 02111 { 02112 PAGED_CODE(); 02113 02114 if (m_fCapture) 02115 { 02116 if ((m_sinkMXF == sinkMXF) || (!sinkMXF)) 02117 { 02118 DPRINT("DisconnectOutput"); 02119 m_sinkMXF = m_AllocatorMXF; 02120 return STATUS_SUCCESS; 02121 } 02122 else 02123 { 02124 DPRINT("DisconnectOutput failed"); 02125 } 02126 } 02127 else 02128 { 02129 DPRINT("DisconnectOutput called on renderer; failed"); 02130 } 02131 return STATUS_UNSUCCESSFUL; 02132 } 02133 02134 #ifdef _MSC_VER 02135 #pragma code_seg() 02136 #endif 02137 02138 02139 /***************************************************************************** 02140 * CMiniportDMusUARTStream::PutMessageLocked() 02141 ***************************************************************************** 02142 * Now that the spinlock is held, add this message to the queue. 02143 * 02144 * Writes an outgoing MIDI message. 02145 * We don't sort a new message into the queue -- we append it. 02146 * This is fine, since the sequencer feeds us sequenced data. 02147 * Timestamps will ascend by design. 02148 */ 02149 NTSTATUS CMiniportDMusUARTStream::PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt) 02150 { 02151 NTSTATUS ntStatus = STATUS_SUCCESS; 02152 PDMUS_KERNEL_EVENT aDMKEvt; 02153 02154 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 02155 02156 if (!m_fCapture) 02157 { 02158 DPRINT("PutMessage to render stream"); 02159 if (pDMKEvt) 02160 { 02161 // m_DpcSpinLock already held 02162 02163 if (m_DMKEvtQueue) 02164 { 02165 aDMKEvt = m_DMKEvtQueue; // put pDMKEvt in event queue 02166 02167 while (aDMKEvt->pNextEvt) 02168 { 02169 aDMKEvt = aDMKEvt->pNextEvt; 02170 } 02171 aDMKEvt->pNextEvt = pDMKEvt; // here is end of queue 02172 } 02173 else // currently nothing in queue 02174 { 02175 m_DMKEvtQueue = pDMKEvt; 02176 if (m_DMKEvtOffset) 02177 { 02178 DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d",m_DMKEvtOffset); 02179 m_DMKEvtOffset = 0; 02180 } 02181 } 02182 02183 // m_DpcSpinLock already held 02184 } 02185 if (!m_TimerQueued) 02186 { 02187 (void) ConsumeEvents(); 02188 } 02189 } 02190 else // capture 02191 { 02192 DPRINT("PutMessage to capture stream"); 02193 ASSERT(NULL == pDMKEvt); 02194 02195 SourceEvtsToPort(); 02196 } 02197 return ntStatus; 02198 } 02199 02200 #ifdef _MSC_VER 02201 #pragma code_seg() 02202 #endif 02203 02204 /***************************************************************************** 02205 * CMiniportDMusUARTStream::PutMessage() 02206 ***************************************************************************** 02207 * Writes an outgoing MIDI message. 02208 * We don't sort a new message into the queue -- we append it. 02209 * This is fine, since the sequencer feeds us sequenced data. 02210 * Timestamps will ascend by design. 02211 */ 02212 NTSTATUS CMiniportDMusUARTStream::PutMessage(PDMUS_KERNEL_EVENT pDMKEvt) 02213 { 02214 NTSTATUS ntStatus = STATUS_SUCCESS; 02215 PDMUS_KERNEL_EVENT aDMKEvt; 02216 02217 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 02218 02219 if (!m_fCapture) 02220 { 02221 DPRINT("PutMessage to render stream"); 02222 if (pDMKEvt) 02223 { 02224 KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock); 02225 02226 if (m_DMKEvtQueue) 02227 { 02228 aDMKEvt = m_DMKEvtQueue; // put pDMKEvt in event queue 02229 02230 while (aDMKEvt->pNextEvt) 02231 { 02232 aDMKEvt = aDMKEvt->pNextEvt; 02233 } 02234 aDMKEvt->pNextEvt = pDMKEvt; // here is end of queue 02235 } 02236 else // currently nothing in queue 02237 { 02238 m_DMKEvtQueue = pDMKEvt; 02239 if (m_DMKEvtOffset) 02240 { 02241 DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d", m_DMKEvtOffset); 02242 m_DMKEvtOffset = 0; 02243 } 02244 } 02245 02246 KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock); 02247 } 02248 if (!m_TimerQueued) 02249 { 02250 (void) ConsumeEvents(); 02251 } 02252 } 02253 else // capture 02254 { 02255 DPRINT("PutMessage to capture stream"); 02256 ASSERT(NULL == pDMKEvt); 02257 02258 SourceEvtsToPort(); 02259 } 02260 return ntStatus; 02261 } 02262 02263 #ifdef _MSC_VER 02264 #pragma code_seg() 02265 #endif 02266 02267 /***************************************************************************** 02268 * CMiniportDMusUARTStream::ConsumeEvents() 02269 ***************************************************************************** 02270 * Attempts to empty the render message queue. 02271 * Called either from DPC timer or upon IRP submittal. 02272 // TODO: support packages right 02273 // process the package (actually, should do this above. 02274 // treat the package as a list fragment that shouldn't be sorted. 02275 // better yet, go through each event in the package, and when 02276 // an event is exhausted, delete it and decrement m_offset. 02277 */ 02278 NTSTATUS CMiniportDMusUARTStream::ConsumeEvents(void) 02279 { 02280 PDMUS_KERNEL_EVENT aDMKEvt; 02281 02282 NTSTATUS ntStatus = STATUS_SUCCESS; 02283 ULONG bytesRemaining = 0,bytesWritten = 0; 02284 LARGE_INTEGER aMillisecIn100ns; 02285 02286 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 02287 KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock); 02288 02289 m_TimerQueued = FALSE; 02290 while (m_DMKEvtQueue) // do we have anything to play at all? 02291 { 02292 aDMKEvt = m_DMKEvtQueue; // event we try to play 02293 if (aDMKEvt->cbEvent) 02294 { 02295 bytesRemaining = aDMKEvt->cbEvent - m_DMKEvtOffset; // number of bytes left in this evt 02296 02297 ASSERT(bytesRemaining > 0); 02298 if (bytesRemaining <= 0) 02299 { 02300 bytesRemaining = aDMKEvt->cbEvent; 02301 } 02302 02303 if (aDMKEvt->cbEvent <= sizeof(PBYTE)) // short message 02304 { 02305 DPRINT("ConsumeEvents(%02x%02x%02x%02x)", aDMKEvt->uData.abData[0], aDMKEvt->uData.abData[1], aDMKEvt->uData.abData[2], aDMKEvt->uData.abData[3]); 02306 ntStatus = Write(aDMKEvt->uData.abData + m_DMKEvtOffset,bytesRemaining,&bytesWritten); 02307 } 02308 else if (PACKAGE_EVT(aDMKEvt)) 02309 { 02310 ASSERT(m_DMKEvtOffset == 0); 02311 m_DMKEvtOffset = 0; 02312 DPRINT("ConsumeEvents(Package)"); 02313 02314 ntStatus = PutMessageLocked(aDMKEvt->uData.pPackageEvt); // we already own the spinlock 02315 02316 // null this because we are about to throw it in the allocator 02317 aDMKEvt->uData.pPackageEvt = NULL; 02318 aDMKEvt->cbEvent = 0; 02319 bytesWritten = bytesRemaining; 02320 } 02321 else // SysEx message 02322 { 02323 DPRINT("ConsumeEvents(%02x%02x%02x%02x)", aDMKEvt->uData.pbData[0], aDMKEvt->uData.pbData[1], aDMKEvt->uData.pbData[2], aDMKEvt->uData.pbData[3]); 02324 02325 ntStatus = Write(aDMKEvt->uData.pbData + m_DMKEvtOffset,bytesRemaining,&bytesWritten); 02326 } 02327 } // if (aDMKEvt->cbEvent) 02328 if (STATUS_SUCCESS != ntStatus) 02329 { 02330 DPRINT("ConsumeEvents: Write returned 0x%08x", ntStatus); 02331 bytesWritten = bytesRemaining; // just bail on this event and try next time 02332 } 02333 02334 ASSERT(bytesWritten <= bytesRemaining); 02335 if (bytesWritten == bytesRemaining) 02336 { 02337 m_DMKEvtQueue = m_DMKEvtQueue->pNextEvt; 02338 aDMKEvt->pNextEvt = NULL; 02339 02340 m_AllocatorMXF->PutMessage(aDMKEvt); // throw back in free pool 02341 m_DMKEvtOffset = 0; // start fresh on next evt 02342 m_NumberOfRetries = 0; 02343 } // but wait ... there's more! 02344 else // our FIFO is full for now. 02345 { 02346 // update our offset by that amount we did write 02347 m_DMKEvtOffset += bytesWritten; 02348 ASSERT(m_DMKEvtOffset < aDMKEvt->cbEvent); 02349 02350 DPRINT("ConsumeEvents tried %d, wrote %d, at offset %d", bytesRemaining,bytesWritten,m_DMKEvtOffset); 02351 aMillisecIn100ns.QuadPart = -(kOneMillisec); // set timer, come back later 02352 m_TimerQueued = TRUE; 02353 m_NumberOfRetries++; 02354 ntStatus = KeSetTimer( &m_TimerEvent, aMillisecIn100ns, &m_Dpc ); 02355 break; 02356 } // we didn't write it all 02357 } // go back, Jack, do it again (while m_DMKEvtQueue) 02358 KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock); 02359 return ntStatus; 02360 } 02361 02362 #ifdef _MSC_VER 02363 #pragma code_seg() 02364 #endif 02365 02366 /***************************************************************************** 02367 * CMiniportDMusUARTStream::HandlePortParams() 02368 ***************************************************************************** 02369 * Writes an outgoing MIDI message. 02370 */ 02371 NTSTATUS 02372 CMiniportDMusUARTStream:: 02373 HandlePortParams 02374 ( 02375 IN PPCPROPERTY_REQUEST pRequest 02376 ) 02377 { 02378 PAGED_CODE(); 02379 02380 NTSTATUS ntStatus; 02381 02382 if (pRequest->Verb & KSPROPERTY_TYPE_SET) 02383 { 02384 return STATUS_INVALID_DEVICE_REQUEST; 02385 } 02386 02387 ntStatus = ValidatePropertyRequest(pRequest, sizeof(SYNTH_PORTPARAMS), TRUE); 02388 if (NT_SUCCESS(ntStatus)) 02389 { 02390 RtlCopyMemory(pRequest->Value, pRequest->Instance, sizeof(SYNTH_PORTPARAMS)); 02391 02392 PSYNTH_PORTPARAMS Params = (PSYNTH_PORTPARAMS)pRequest->Value; 02393 02394 if (Params->ValidParams & ~SYNTH_PORTPARAMS_CHANNELGROUPS) 02395 { 02396 Params->ValidParams &= SYNTH_PORTPARAMS_CHANNELGROUPS; 02397 } 02398 02399 if (!(Params->ValidParams & SYNTH_PORTPARAMS_CHANNELGROUPS)) 02400 { 02401 Params->ChannelGroups = 1; 02402 } 02403 else if (Params->ChannelGroups != 1) 02404 { 02405 Params->ChannelGroups = 1; 02406 } 02407 02408 pRequest->ValueSize = sizeof(SYNTH_PORTPARAMS); 02409 } 02410 02411 return ntStatus; 02412 } 02413 02414 #ifdef _MSC_VER 02415 #pragma code_seg() 02416 #endif 02417 02418 /***************************************************************************** 02419 * DMusTimerDPC() 02420 ***************************************************************************** 02421 * The timer DPC callback. Thunks to a C++ member function. 02422 * This is called by the OS in response to the DirectMusic pin 02423 * wanting to wakeup later to process more DirectMusic stuff. 02424 */ 02425 VOID 02426 NTAPI 02427 DMusUARTTimerDPC 02428 ( 02429 IN PKDPC Dpc, 02430 IN PVOID DeferredContext, 02431 IN PVOID SystemArgument1, 02432 IN PVOID SystemArgument2 02433 ) 02434 { 02435 ASSERT(DeferredContext); 02436 02437 CMiniportDMusUARTStream *aStream; 02438 aStream = (CMiniportDMusUARTStream *) DeferredContext; 02439 if (aStream) 02440 { 02441 DPRINT("DMusUARTTimerDPC"); 02442 if (false == aStream->m_fCapture) 02443 { 02444 (void) aStream->ConsumeEvents(); 02445 } 02446 // ignores return value! 02447 } 02448 } 02449 02450 /***************************************************************************** 02451 * DirectMusic properties 02452 ****************************************************************************/ 02453 02454 #ifdef _MSC_VER 02455 #pragma code_seg() 02456 #endif 02457 02458 /* 02459 * Properties concerning synthesizer functions. 02460 */ 02461 const WCHAR wszDescOut[] = L"DMusic MPU-401 Out "; 02462 const WCHAR wszDescIn[] = L"DMusic MPU-401 In "; 02463 02464 NTSTATUS 02465 NTAPI 02466 PropertyHandler_Synth 02467 ( 02468 IN PPCPROPERTY_REQUEST pRequest 02469 ) 02470 { 02471 NTSTATUS ntStatus; 02472 02473 PAGED_CODE(); 02474 02475 if (pRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) 02476 { 02477 ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONG), TRUE); 02478 if (NT_SUCCESS(ntStatus)) 02479 { 02480 // if return buffer can hold a ULONG, return the access flags 02481 PULONG AccessFlags = PULONG(pRequest->Value); 02482 02483 *AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT; 02484 switch (pRequest->PropertyItem->Id) 02485 { 02486 case KSPROPERTY_SYNTH_CAPS: 02487 case KSPROPERTY_SYNTH_CHANNELGROUPS: 02488 *AccessFlags |= KSPROPERTY_TYPE_GET; 02489 } 02490 switch (pRequest->PropertyItem->Id) 02491 { 02492 case KSPROPERTY_SYNTH_CHANNELGROUPS: 02493 *AccessFlags |= KSPROPERTY_TYPE_SET; 02494 } 02495 ntStatus = STATUS_SUCCESS; 02496 pRequest->ValueSize = sizeof(ULONG); 02497 02498 switch (pRequest->PropertyItem->Id) 02499 { 02500 case KSPROPERTY_SYNTH_PORTPARAMETERS: 02501 if (pRequest->MinorTarget) 02502 { 02503 *AccessFlags |= KSPROPERTY_TYPE_GET; 02504 } 02505 else 02506 { 02507 pRequest->ValueSize = 0; 02508 ntStatus = STATUS_INVALID_DEVICE_REQUEST; 02509 } 02510 } 02511 } 02512 } 02513 else 02514 { 02515 ntStatus = STATUS_SUCCESS; 02516 switch(pRequest->PropertyItem->Id) 02517 { 02518 case KSPROPERTY_SYNTH_CAPS: 02519 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CAPS"); 02520 02521 if (pRequest->Verb & KSPROPERTY_TYPE_SET) 02522 { 02523 ntStatus = STATUS_INVALID_DEVICE_REQUEST; 02524 } 02525 02526 if (NT_SUCCESS(ntStatus)) 02527 { 02528 ntStatus = ValidatePropertyRequest(pRequest, sizeof(SYNTHCAPS), TRUE); 02529 02530 if (NT_SUCCESS(ntStatus)) 02531 { 02532 SYNTHCAPS *caps = (SYNTHCAPS*)pRequest->Value; 02533 int increment; 02534 RtlZeroMemory(caps, sizeof(SYNTHCAPS)); 02535 // XXX Different guids for different instances! 02536 // 02537 if (pRequest->Node == eSynthNode) 02538 { 02539 increment = sizeof(wszDescOut) - 2; 02540 RtlCopyMemory( caps->Description,wszDescOut,increment); 02541 caps->Guid = CLSID_MiniportDriverDMusUART; 02542 } 02543 else 02544 { 02545 increment = sizeof(wszDescIn) - 2; 02546 RtlCopyMemory( caps->Description,wszDescIn,increment); 02547 caps->Guid = CLSID_MiniportDriverDMusUARTCapture; 02548 } 02549 02550 caps->Flags = SYNTH_PC_EXTERNAL; 02551 caps->MemorySize = 0; 02552 caps->MaxChannelGroups = 1; 02553 caps->MaxVoices = 0xFFFFFFFF; 02554 caps->MaxAudioChannels = 0xFFFFFFFF; 02555 02556 caps->EffectFlags = 0; 02557 02558 CMiniportDMusUART *aMiniport; 02559 ASSERT(pRequest->MajorTarget); 02560 aMiniport = (CMiniportDMusUART *)(PMINIPORTDMUS)(pRequest->MajorTarget); 02561 WCHAR wszDesc2[16]; 02562 int cLen; 02563 cLen = swprintf(wszDesc2,L"[%03x]\0",PtrToUlong(aMiniport->m_pPortBase)); 02564 02565 cLen *= sizeof(WCHAR); 02566 RtlCopyMemory((WCHAR *)((DWORD_PTR)(caps->Description) + increment), 02567 wszDesc2, 02568 cLen); 02569 02570 02571 pRequest->ValueSize = sizeof(SYNTHCAPS); 02572 } 02573 } 02574 02575 break; 02576 02577 case KSPROPERTY_SYNTH_PORTPARAMETERS: 02578 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_PORTPARAMETERS"); 02579 { 02580 CMiniportDMusUARTStream *aStream; 02581 02582 aStream = (CMiniportDMusUARTStream*)(pRequest->MinorTarget); 02583 if (aStream) 02584 { 02585 ntStatus = aStream->HandlePortParams(pRequest); 02586 } 02587 else 02588 { 02589 ntStatus = STATUS_INVALID_DEVICE_REQUEST; 02590 } 02591 } 02592 break; 02593 02594 case KSPROPERTY_SYNTH_CHANNELGROUPS: 02595 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CHANNELGROUPS"); 02596 02597 ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONG), TRUE); 02598 if (NT_SUCCESS(ntStatus)) 02599 { 02600 *(PULONG)(pRequest->Value) = 1; 02601 pRequest->ValueSize = sizeof(ULONG); 02602 } 02603 break; 02604 02605 case KSPROPERTY_SYNTH_LATENCYCLOCK: 02606 DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_LATENCYCLOCK"); 02607 02608 if(pRequest->Verb & KSPROPERTY_TYPE_SET) 02609 { 02610 ntStatus = STATUS_INVALID_DEVICE_REQUEST; 02611 } 02612 else 02613 { 02614 ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONGLONG), TRUE); 02615 if(NT_SUCCESS(ntStatus)) 02616 { 02617 REFERENCE_TIME rtLatency; 02618 CMiniportDMusUARTStream *aStream; 02619 02620 aStream = (CMiniportDMusUARTStream*)(pRequest->MinorTarget); 02621 if(aStream == NULL) 02622 { 02623 ntStatus = STATUS_INVALID_DEVICE_REQUEST; 02624 } 02625 else 02626 { 02627 aStream->m_pMiniport->m_MasterClock->GetTime(&rtLatency); 02628 *((PULONGLONG)pRequest->Value) = rtLatency; 02629 pRequest->ValueSize = sizeof(ULONGLONG); 02630 } 02631 } 02632 } 02633 break; 02634 02635 default: 02636 DPRINT("Unhandled property in PropertyHandler_Synth"); 02637 break; 02638 } 02639 } 02640 return ntStatus; 02641 } 02642 02643 /***************************************************************************** 02644 * ValidatePropertyRequest() 02645 ***************************************************************************** 02646 * Validates pRequest. 02647 * Checks if the ValueSize is valid 02648 * Checks if the Value is valid 02649 * 02650 * This does not update pRequest->ValueSize if it returns NT_SUCCESS. 02651 * Caller must set pRequest->ValueSize in case of NT_SUCCESS. 02652 */ 02653 NTSTATUS ValidatePropertyRequest 02654 ( 02655 IN PPCPROPERTY_REQUEST pRequest, 02656 IN ULONG ulValueSize, 02657 IN BOOLEAN fValueRequired 02658 ) 02659 { 02660 NTSTATUS ntStatus; 02661 02662 if (pRequest->ValueSize >= ulValueSize) 02663 { 02664 if (fValueRequired && NULL == pRequest->Value) 02665 { 02666 ntStatus = STATUS_INVALID_PARAMETER; 02667 } 02668 else 02669 { 02670 ntStatus = STATUS_SUCCESS; 02671 } 02672 } 02673 else if (0 == pRequest->ValueSize) 02674 { 02675 ntStatus = STATUS_BUFFER_OVERFLOW; 02676 } 02677 else 02678 { 02679 ntStatus = STATUS_BUFFER_TOO_SMALL; 02680 } 02681 02682 if (STATUS_BUFFER_OVERFLOW == ntStatus) 02683 { 02684 pRequest->ValueSize = ulValueSize; 02685 } 02686 else 02687 { 02688 pRequest->ValueSize = 0; 02689 } 02690 02691 return ntStatus; 02692 } // ValidatePropertyRequest 02693 02694 #ifdef _MSC_VER 02695 #pragma code_seg() 02696 #endif 02697 02698 Generated on Sun May 27 2012 04:28:34 for ReactOS by
1.7.6.1
|