ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

miniport_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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.