ReactOS  0.4.15-dev-4916-gd519b11
miniport_dmus.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * miniport_dmus.cpp - UART miniport implementation
3  *****************************************************************************
4  * Copyright (c) 1997-2000 Microsoft Corporation. All Rights Reserved.
5  *
6  * Feb 98 MartinP -- based on UART, began deltas for DirectMusic.
7  *
8  */
9 
10 #include "private.hpp"
11 
12 #ifndef YDEBUG
13 #define NDEBUG
14 #endif
15 
16 #include <debug.h>
17 
18 // + for absolute / - for relative
19 
20 #define kOneMillisec (10 * 1000)
21 
22 //
23 // MPU401 ports
24 //
25 #define MPU401_REG_STATUS 0x01 // Status register
26 #define MPU401_DRR 0x40 // Output ready (for command or data)
27  // if this bit is set, the output FIFO is FULL
28 #define MPU401_DSR 0x80 // Input ready (for data)
29  // if this bit is set, the input FIFO is empty
30 
31 #define MPU401_REG_DATA 0x00 // Data in
32 #define MPU401_REG_COMMAND 0x01 // Commands
33 #define MPU401_CMD_RESET 0xFF // Reset command
34 #define MPU401_CMD_UART 0x3F // Switch to UART mod
35 
36 
37 /*****************************************************************************
38  * Prototypes
39  */
40 
42 NTSTATUS ResetHardware(PUCHAR portBase);
47 NTSTATUS NTAPI SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync,PVOID syncWriteContext);
48 /*****************************************************************************
49  * Constants
50  */
51 
53 const BOOLEAN DATA = FALSE;
55 
56 
57 /*****************************************************************************
58  * Classes
59  */
60 
61 /*****************************************************************************
62  * CMiniportDMusUART
63  *****************************************************************************
64  * MPU-401 miniport. This object is associated with the device and is
65  * created when the device is started. The class inherits IMiniportDMus
66  * so it can expose this interface and CUnknown so it automatically gets
67  * reference counting and aggregation support.
68  */
69 class CMiniportDMusUART : public CUnknownImpl<IMiniportDMus, IMusicTechnology, IPowerNotify>
70 {
71 private:
72  KSSTATE m_KSStateInput; // Miniport state (RUN/PAUSE/ACQUIRE/STOP)
73  PPORTDMUS m_pPort; // Callback interface.
74  PUCHAR m_pPortBase; // Base port address.
75  PINTERRUPTSYNC m_pInterruptSync; // Interrupt synchronization object.
76  PSERVICEGROUP m_pServiceGroup; // Service group for capture.
77  PMASTERCLOCK m_MasterClock; // for input data
78  REFERENCE_TIME m_InputTimeStamp; // capture data timestamp
79  USHORT m_NumRenderStreams; // Num active render streams.
80  USHORT m_NumCaptureStreams; // Num active capture streams.
81  ULONG m_MPUInputBufferHead; // Index of the newest byte in the FIFO.
82  ULONG m_MPUInputBufferTail; // Index of the oldest empty space in the FIFO.
84  POWER_STATE m_PowerState; // Saved power state (D0 = full power, D3 = off)
85  BOOLEAN m_fMPUInitialized; // Is the MPU HW initialized.
86  BOOLEAN m_UseIRQ; // FALSE if no IRQ is used for MIDI.
88 
89  /*************************************************************************
90  * CMiniportDMusUART methods
91  *
92  * These are private member functions used internally by the object.
93  * See MINIPORT.CPP for specific descriptions.
94  */
96  (
98  );
99  NTSTATUS InitializeHardware(PINTERRUPTSYNC interruptSync,PUCHAR portBase);
100 
101 public:
103 
105  virtual ~CMiniportDMusUART();
106 
107  /*************************************************************************
108  * IMiniport methods
109  */
112  ( OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
113  );
116  ( IN ULONG PinId
117  , IN PKSDATARANGE DataRange
118  , IN PKSDATARANGE MatchingDataRange
120  , OUT PVOID ResultantFormat
121  , OUT PULONG ResultantFormatLength
122  )
123  {
124  return STATUS_NOT_IMPLEMENTED;
125  }
126 
127  /*************************************************************************
128  * IMiniportDMus methods
129  */
131  (
132  IN PUNKNOWN UnknownAdapter,
134  IN PPORTDMUS Port,
136  );
137  STDMETHODIMP_(NTSTATUS) NewStream
138  (
139  OUT PMXF * Stream,
140  IN PUNKNOWN OuterUnknown OPTIONAL,
142  IN ULONG PinID,
149  );
150  STDMETHODIMP_(void) Service
151  ( void
152  );
153 
154  /*************************************************************************
155  * IMusicTechnology methods
156  */
158 
159  /*************************************************************************
160  * IPowerNotify methods
161  */
163 
164  /*************************************************************************
165  * Friends
166  */
168  friend NTSTATUS NTAPI
170  friend NTSTATUS NTAPI
171  SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync,PVOID syncWriteContext);
172  friend VOID NTAPI
176 };
177 
178 /*****************************************************************************
179  * CMiniportDMusUARTStream
180  *****************************************************************************
181  * MPU-401 miniport stream. This object is associated with the pin and is
182  * created when the pin is instantiated. It inherits IMXF
183  * so it can expose this interface and CUnknown so it automatically gets
184  * reference counting and aggregation support.
185  */
187 {
188 private:
190  REFERENCE_TIME m_SnapshotTimeStamp; // Current snapshot of miniport's input timestamp.
191  PUCHAR m_pPortBase; // Base port address.
192  BOOLEAN m_fCapture; // Whether this is capture.
193  long m_NumFailedMPUTries; // Deadman timeout for MPU hardware.
194  PAllocatorMXF m_AllocatorMXF; // source/sink for DMus structs
195  PMXF m_sinkMXF; // sink for DMus capture
196  PDMUS_KERNEL_EVENT m_DMKEvtQueue; // queue of waiting events
197  ULONG m_NumberOfRetries; // Number of consecutive times the h/w was busy/full
198  ULONG m_DMKEvtOffset; // offset into the event
199  KDPC m_Dpc; // DPC for timer
201  BOOL m_TimerQueued; // whether a timer has been set
202  KSPIN_LOCK m_DpcSpinLock; // protects the ConsumeEvents DPC
203 
204  STDMETHODIMP_(NTSTATUS) SourceEvtsToPort();
205  STDMETHODIMP_(NTSTATUS) ConsumeEvents();
206  STDMETHODIMP_(NTSTATUS) PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt);
207 
208 public:
210 
211  virtual ~CMiniportDMusUARTStream();
212 
214  (
215  IN CMiniportDMusUART * pMiniport,
220  );
221 
223  (
225  );
226 
227  /*************************************************************************
228  * IMiniportStreamDMusUART methods
229  */
231 
233  (
237  );
238 
239  friend VOID NTAPI
241  (
242  IN PKDPC Dpc,
246  );
249 };
250 
251 
252 
253 #define STR_MODULENAME "DMusUART:Miniport: "
254 
255 #ifdef _MSC_VER
256 #pragma code_seg("PAGE")
257 #endif
258 
259 #define UartFifoOkForWrite(status) ((status & MPU401_DRR) == 0)
260 #define UartFifoOkForRead(status) ((status & MPU401_DSR) == 0)
261 
262 typedef struct
263 {
269 }
271 
272 /*****************************************************************************
273  * PinDataRangesStreamLegacy
274  * PinDataRangesStreamDMusic
275  *****************************************************************************
276  * Structures indicating range of valid format values for live pins.
277  */
278 static
280 {
281  {
282  {
283  sizeof(KSDATARANGE_MUSIC),
284  0,
285  0,
286  0,
290  }
291  },
293  0,
294  0,
295  0xFFFF
296 };
297 static
299 {
300  {
301  {
302  sizeof(KSDATARANGE_MUSIC),
303  0,
304  0,
305  0,
309  }
310  },
312  0,
313  0,
314  0xFFFF
315 };
316 
317 /*****************************************************************************
318  * PinDataRangePointersStreamLegacy
319  * PinDataRangePointersStreamDMusic
320  * PinDataRangePointersStreamCombined
321  *****************************************************************************
322  * List of pointers to structures indicating range of valid format values
323  * for live pins.
324  */
325 static
327 {
329 };
330 static
332 {
334 };
335 static
337 {
340 };
341 
342 /*****************************************************************************
343  * PinDataRangesBridge
344  *****************************************************************************
345  * Structures indicating range of valid format values for bridge pins.
346  */
347 static
349 {
350  {
351  {
352  sizeof(KSDATARANGE),
353  0,
354  0,
355  0,
359  }
360  }
361 };
362 
363 /*****************************************************************************
364  * PinDataRangePointersBridge
365  *****************************************************************************
366  * List of pointers to structures indicating range of valid format values
367  * for bridge pins.
368  */
369 static
371 {
373 };
374 
375 /*****************************************************************************
376  * SynthProperties
377  *****************************************************************************
378  * List of properties in the Synth set.
379  */
380 static
383 {
384  // Global: S/Get synthesizer caps
385  {
390  },
391  // Global: S/Get port parameters
392  {
397  },
398  // Per stream: S/Get channel groups
399  {
404  },
405  // Per stream: Get current latency time
406  {
411  }
412 };
415 
416 #define kMaxNumCaptureStreams 1
417 #define kMaxNumLegacyRenderStreams 1
418 #define kMaxNumDMusicRenderStreams 1
419 
420 /*****************************************************************************
421  * MiniportPins
422  *****************************************************************************
423  * List of pins.
424  */
425 static
427 {
428  {
430  NULL, // AutomationTable
431  { // KsPinDescriptor
432  0, // InterfacesCount
433  NULL, // Interfaces
434  0, // MediumsCount
435  NULL, // Mediums
437  PinDataRangePointersStreamLegacy, // DataRanges
438  KSPIN_DATAFLOW_IN, // DataFlow
439  KSPIN_COMMUNICATION_SINK, // Communication
440  (GUID *) &KSCATEGORY_AUDIO, // Category
441  &KSAUDFNAME_MIDI, // Name
442  {0} // Reserved
443  }
444  },
445  {
447  NULL, // AutomationTable
448  { // KsPinDescriptor
449  0, // InterfacesCount
450  NULL, // Interfaces
451  0, // MediumsCount
452  NULL, // Mediums
454  PinDataRangePointersStreamDMusic, // DataRanges
455  KSPIN_DATAFLOW_IN, // DataFlow
456  KSPIN_COMMUNICATION_SINK, // Communication
457  (GUID *) &KSCATEGORY_AUDIO, // Category
458  &KSAUDFNAME_DMUSIC_MPU_OUT, // Name
459  {0} // Reserved
460  }
461  },
462  {
463  0,0,0, // InstanceCount
464  NULL, // AutomationTable
465  { // KsPinDescriptor
466  0, // InterfacesCount
467  NULL, // Interfaces
468  0, // MediumsCount
469  NULL, // Mediums
470  SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount
471  PinDataRangePointersBridge, // DataRanges
472  KSPIN_DATAFLOW_OUT, // DataFlow
473  KSPIN_COMMUNICATION_NONE, // Communication
474  (GUID *) &KSCATEGORY_AUDIO, // Category
475  NULL, // Name
476  {0} // Reserved
477  }
478  },
479  {
480  0,0,0, // InstanceCount
481  NULL, // AutomationTable
482  { // KsPinDescriptor
483  0, // InterfacesCount
484  NULL, // Interfaces
485  0, // MediumsCount
486  NULL, // Mediums
487  SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount
488  PinDataRangePointersBridge, // DataRanges
489  KSPIN_DATAFLOW_IN, // DataFlow
490  KSPIN_COMMUNICATION_NONE, // Communication
491  (GUID *) &KSCATEGORY_AUDIO, // Category
492  NULL, // Name
493  {0} // Reserved
494  }
495  },
496  {
497  kMaxNumCaptureStreams,kMaxNumCaptureStreams,0, // InstanceCount
498  NULL, // AutomationTable
499  { // KsPinDescriptor
500  0, // InterfacesCount
501  NULL, // Interfaces
502  0, // MediumsCount
503  NULL, // Mediums
506  KSPIN_DATAFLOW_OUT, // DataFlow
507  KSPIN_COMMUNICATION_SINK, // Communication
508  (GUID *) &KSCATEGORY_AUDIO, // Category
509  &KSAUDFNAME_DMUSIC_MPU_IN, // Name
510  {0} // Reserved
511  }
512  }
513 };
514 
515 /*****************************************************************************
516  * MiniportNodes
517  *****************************************************************************
518  * List of nodes.
519  */
520 #define CONST_PCNODE_DESCRIPTOR(n) { 0, NULL, &n, NULL }
521 #define CONST_PCNODE_DESCRIPTOR_AUTO(n,a) { 0, &a, &n, NULL }
522 static
524 {
527 };
528 
529 /*****************************************************************************
530  * MiniportConnections
531  *****************************************************************************
532  * List of connections.
533  */
534 enum {
537 };
538 
539 enum {
545 };
546 
547 static
549 { // From To
550  // Node pin Node pin
551  { PCFILTER_NODE, eFilterInputPinLeg, PCFILTER_NODE, eBridgeOutputPin } // Legacy Stream in to synth.
552  , { PCFILTER_NODE, eFilterInputPinDM, eSynthNode, KSNODEPIN_STANDARD_IN } // DM Stream in to synth.
553  , { eSynthNode, KSNODEPIN_STANDARD_OUT, PCFILTER_NODE, eBridgeOutputPin } // Synth to bridge out.
554  , { PCFILTER_NODE, eBridgeInputPin, eInputNode, KSNODEPIN_STANDARD_IN } // Bridge in to input.
555  , { eInputNode, KSNODEPIN_STANDARD_OUT, PCFILTER_NODE, eFilterOutputPin } // Input to DM/Legacy Stream out.
556 };
557 
558 /*****************************************************************************
559  * MiniportCategories
560  *****************************************************************************
561  * List of categories.
562  */
563 static
565 {
569 };
570 
571 /*****************************************************************************
572  * MiniportFilterDescriptor
573  *****************************************************************************
574  * Complete miniport filter description.
575  */
576 static
578 {
579  0, // Version
580  NULL, // AutomationTable
581  sizeof(PCPIN_DESCRIPTOR), // PinSize
582  SIZEOF_ARRAY(MiniportPins), // PinCount
583  MiniportPins, // Pins
584  sizeof(PCNODE_DESCRIPTOR), // NodeSize
585  SIZEOF_ARRAY(MiniportNodes), // NodeCount
586  MiniportNodes, // Nodes
587  SIZEOF_ARRAY(MiniportConnections), // ConnectionCount
588  MiniportConnections, // Connections
589  SIZEOF_ARRAY(MiniportCategories), // CategoryCount
590  MiniportCategories // Categories
591 };
592 
593 #ifdef _MSC_VER
594 #pragma code_seg("PAGE")
595 #endif
596 
597 BOOLEAN TryMPU(IN PUCHAR PortBase);
598 NTSTATUS WriteMPU(IN PUCHAR PortBase,IN BOOLEAN IsCommand,IN UCHAR Value);
599 
600 #ifdef _MSC_VER
601 #pragma code_seg("PAGE")
602 #endif
603 
604 // make sure we're in UART mode
606 {
607  PAGED_CODE();
608 
609  return WriteMPU(portBase,COMMAND,MPU401_CMD_UART);
610 }
611 
612 #ifdef _MSC_VER
613 #pragma code_seg("PAGE")
614 #endif
615 
616 //
617 // We initialize the UART with interrupts suppressed so we don't
618 // try to service the chip prematurely.
619 //
621 {
622  PAGED_CODE();
623 
624  NTSTATUS ntStatus;
625  if (m_UseIRQ)
626  {
627  ntStatus = interruptSync->CallSynchronizedRoutine(InitMPU,PVOID(portBase));
628  }
629  else
630  {
631  ntStatus = InitMPU(NULL,PVOID(portBase));
632  }
633 
634  if (NT_SUCCESS(ntStatus))
635  {
636  //
637  // Start the UART (this should trigger an interrupt).
638  //
639  ntStatus = ResetHardware(portBase);
640  }
641  else
642  {
643  DPRINT("*** InitMPU returned with ntStatus 0x%08x ***", ntStatus);
644  }
645 
646  m_fMPUInitialized = NT_SUCCESS(ntStatus);
647 
648  return ntStatus;
649 }
650 
651 #ifdef _MSC_VER
652 #pragma code_seg()
653 #endif
654 
655 /*****************************************************************************
656  * InitMPU()
657  *****************************************************************************
658  * Synchronized routine to initialize the MPU401.
659  */
660 NTSTATUS
661 NTAPI
662 InitMPU
663 (
664  IN PINTERRUPTSYNC InterruptSync,
666 )
667 {
668  DPRINT("InitMPU");
669  if (!DynamicContext)
670  {
672  }
673 
674  PUCHAR portBase = PUCHAR(DynamicContext);
675  UCHAR status;
678  NTSTATUS ntStatus = STATUS_SUCCESS;
679 
680  //
681  // Reset the card (puts it into "smart mode")
682  //
683  ntStatus = WriteMPU(portBase,COMMAND,MPU401_CMD_RESET);
684 
685  // wait for the acknowledgement
686  // NOTE: When the Ack arrives, it will trigger an interrupt.
687  // Normally the DPC routine would read in the ack byte and we
688  // would never see it, however since we have the hardware locked (HwEnter),
689  // we can read the port before the DPC can and thus we receive the Ack.
691  success = FALSE;
693  {
695 
696  if (UartFifoOkForRead(status)) // Is data waiting?
697  {
698  READ_PORT_UCHAR(portBase + MPU401_REG_DATA); // yep.. read ACK
699  success = TRUE; // don't need to do more
700  break;
701  }
702  KeStallExecutionProcessor(25); // microseconds
703  }
704 #if (DBG)
705  if (!success)
706  {
707  DPRINT("First attempt to reset the MPU didn't get ACKed.\n");
708  }
709 #endif // (DBG)
710 
711  // NOTE: We cannot check the ACK byte because if the card was already in
712  // UART mode it will not send an ACK but it will reset.
713 
714  // reset the card again
716 
717  // wait for ack (again)
718  startTime = PcGetTimeInterval(0); // This might take a while
719  BYTE dataByte = 0;
720  success = FALSE;
722  {
724  if (UartFifoOkForRead(status)) // Is data waiting?
725  {
726  dataByte = READ_PORT_UCHAR(portBase + MPU401_REG_DATA); // yep.. read ACK
727  success = TRUE; // don't need to do more
728  break;
729  }
731  }
732 
733  if ((0xFE != dataByte) || !success) // Did we succeed? If no second ACK, something is hosed
734  {
735  DPRINT("Second attempt to reset the MPU didn't get ACKed.\n");
736  DPRINT("Init Reset failure error. Ack = %X", ULONG(dataByte));
737 
738  ntStatus = STATUS_IO_DEVICE_ERROR;
739  }
740 
741  return ntStatus;
742 }
743 
744 #ifdef _MSC_VER
745 #pragma code_seg()
746 #endif
747 
748 /*****************************************************************************
749  * CMiniportDMusUARTStream::Write()
750  *****************************************************************************
751  * Writes outgoing MIDI data.
752  */
755 Write
756 (
758  IN ULONG Length,
760 )
761 {
762  DPRINT("Write\n");
764  if (!BufferAddress)
765  {
766  Length = 0;
767  }
768 
769  NTSTATUS ntStatus = STATUS_SUCCESS;
770 
771  if (!m_fCapture)
772  {
773  PUCHAR pMidiData;
774  ULONG count;
775 
776  count = 0;
777  pMidiData = PUCHAR(BufferAddress);
778 
779  if (Length)
780  {
782  context.Miniport = (m_pMiniport);
783  context.PortBase = m_pPortBase;
784  context.BufferAddress = pMidiData;
785  context.Length = Length;
786  context.BytesRead = &count;
787 
788  if (m_pMiniport->m_UseIRQ)
789  {
790  ntStatus = m_pMiniport->m_pInterruptSync->
791  CallSynchronizedRoutine(SynchronizedDMusMPUWrite,PVOID(&context));
792  }
793  else // !m_UseIRQ
794  {
796  } // !m_UseIRQ
797 
798  if (count == 0)
799  {
801  if (m_NumFailedMPUTries >= 100)
802  {
803  ntStatus = STATUS_IO_DEVICE_ERROR;
805  }
806  }
807  else
808  {
810  }
811  } // if we have data at all
812  *BytesWritten = count;
813  }
814  else // called write on the read stream
815  {
817  }
818  return ntStatus;
819 }
820 
821 #ifdef _MSC_VER
822 #pragma code_seg()
823 #endif
824 
825 /*****************************************************************************
826  * SynchronizedDMusMPUWrite()
827  *****************************************************************************
828  * Writes outgoing MIDI data.
829  */
830 NTSTATUS
831 NTAPI
833 (
834  IN PINTERRUPTSYNC InterruptSync,
835  IN PVOID syncWriteContext
836 )
837 {
839  context = (PSYNCWRITECONTEXT)syncWriteContext;
840  ASSERT(context->Miniport);
841  ASSERT(context->PortBase);
842  ASSERT(context->BufferAddress);
843  ASSERT(context->Length);
844  ASSERT(context->BytesRead);
845 
846  PUCHAR pChar = PUCHAR(context->BufferAddress);
847  NTSTATUS ntStatus; // , readStatus
848  ntStatus = STATUS_SUCCESS;
849  //
850  // while we're not there yet, and
851  // while we don't have to wait on an aligned byte (including 0)
852  // (we never wait on a byte. Better to come back later)
853  /*readStatus = */ DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport));
854  while ( (*(context->BytesRead) < context->Length)
855  && ( TryMPU(context->PortBase)
856  || (*(context->BytesRead)%3)
857  ) )
858  {
859  ntStatus = WriteMPU(context->PortBase,DATA,*pChar);
860  if (NT_SUCCESS(ntStatus))
861  {
862  pChar++;
863  *(context->BytesRead) = *(context->BytesRead) + 1;
864 // readStatus = DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport));
865  }
866  else
867  {
868  DPRINT("SynchronizedDMusMPUWrite failed (0x%08x)",ntStatus);
869  break;
870  }
871  }
872  /*readStatus = */ DMusMPUInterruptServiceRoutine(InterruptSync,PVOID(context->Miniport));
873  return ntStatus;
874 }
875 
876 #define kMPUPollTimeout 2
877 
878 #ifdef _MSC_VER
879 #pragma code_seg()
880 #endif
881 
882 /*****************************************************************************
883  * TryMPU()
884  *****************************************************************************
885  * See if the MPU401 is free.
886  */
887 BOOLEAN
888 TryMPU
889 (
890  IN PUCHAR PortBase
891 )
892 {
894  USHORT numPolls;
895  UCHAR status;
896 
897  DPRINT("TryMPU");
898  numPolls = 0;
899 
900  while (numPolls < kMPUPollTimeout)
901  {
903 
904  if (UartFifoOkForWrite(status)) // Is this a good time to write data?
905  {
906  break;
907  }
908  numPolls++;
909  }
910  if (numPolls >= kMPUPollTimeout)
911  {
912  success = FALSE;
913  DPRINT("TryMPU failed");
914  }
915  else
916  {
917  success = TRUE;
918  }
919 
920  return success;
921 }
922 
923 #ifdef _MSC_VER
924 #pragma code_seg()
925 #endif
926 
927 /*****************************************************************************
928  * WriteMPU()
929  *****************************************************************************
930  * Write a byte out to the MPU401.
931  */
932 NTSTATUS
933 WriteMPU
934 (
935  IN PUCHAR PortBase,
936  IN BOOLEAN IsCommand,
937  IN UCHAR Value
938 )
939 {
940  DPRINT("WriteMPU");
941  NTSTATUS ntStatus = STATUS_IO_DEVICE_ERROR;
942 
943  if (!PortBase)
944  {
945  DPRINT("O: PortBase is zero\n");
946  return ntStatus;
947  }
948  PUCHAR deviceAddr = PortBase + MPU401_REG_DATA;
949 
950  if (IsCommand)
951  {
952  deviceAddr = PortBase + MPU401_REG_COMMAND;
953  }
954 
956 
958  {
959  UCHAR status
960  = READ_PORT_UCHAR(PortBase + MPU401_REG_STATUS);
961 
962  if (UartFifoOkForWrite(status)) // Is this a good time to write data?
963  { // yep (Jon comment)
964  WRITE_PORT_UCHAR(deviceAddr,Value);
965  DPRINT("WriteMPU emitted 0x%02x",Value);
966  ntStatus = STATUS_SUCCESS;
967  break;
968  }
969  }
970  return ntStatus;
971 }
972 
973 #ifdef _MSC_VER
974 #pragma code_seg()
975 #endif
976 
977 /*****************************************************************************
978  * SnapTimeStamp()
979  *****************************************************************************
980  *
981  * At synchronized execution to ISR, copy miniport's volatile m_InputTimeStamp
982  * to stream's m_SnapshotTimeStamp and zero m_InputTimeStamp.
983  *
984  */
986 SnapTimeStamp(PINTERRUPTSYNC InterruptSync,PVOID pStream)
987 {
988  CMiniportDMusUARTStream *pMPStream = (CMiniportDMusUARTStream *)pStream;
989 
990  // cache the timestamp
991  pMPStream->m_SnapshotTimeStamp = pMPStream->m_pMiniport->m_InputTimeStamp;
992 
993  // if the window is closed, zero the timestamp
994  if (pMPStream->m_pMiniport->m_MPUInputBufferHead ==
995  pMPStream->m_pMiniport->m_MPUInputBufferTail)
996  {
997  pMPStream->m_pMiniport->m_InputTimeStamp = 0;
998  }
999 
1000  return STATUS_SUCCESS;
1001 }
1002 
1003 /*****************************************************************************
1004  * CMiniportDMusUARTStream::SourceEvtsToPort()
1005  *****************************************************************************
1006  *
1007  * Reads incoming MIDI data, feeds into DMus events.
1008  * No need to touch the hardware, just read from our SW FIFO.
1009  *
1010  */
1012 CMiniportDMusUARTStream::SourceEvtsToPort()
1013 {
1014  NTSTATUS ntStatus;
1015 
1017  DPRINT("SourceEvtsToPort");
1018 
1019  if (m_fCapture)
1020  {
1021  ntStatus = STATUS_SUCCESS;
1023  {
1024  PDMUS_KERNEL_EVENT aDMKEvt,eventTail,eventHead = NULL;
1025 
1027  {
1028  (void) m_AllocatorMXF->GetMessage(&aDMKEvt);
1029  if (!aDMKEvt)
1030  {
1031  DPRINT("SourceEvtsToPort can't allocate DMKEvt");
1033  }
1034 
1035  // put this event at the end of the list
1036  if (!eventHead)
1037  {
1038  eventHead = aDMKEvt;
1039  }
1040  else
1041  {
1042  eventTail = eventHead;
1043  while (eventTail->pNextEvt)
1044  {
1045  eventTail = eventTail->pNextEvt;
1046  }
1047  eventTail->pNextEvt = aDMKEvt;
1048  }
1049  // read all the bytes out of the buffer, into event(s)
1050  for (aDMKEvt->cbEvent = 0; aDMKEvt->cbEvent < sizeof(PBYTE); aDMKEvt->cbEvent++)
1051  {
1053  {
1054 // _DbgPrintF(DEBUGLVL_TERSE, ("SourceEvtsToPort m_MPUInputBufferHead met m_MPUInputBufferTail, overrun"));
1055  break;
1056  }
1060  {
1062  }
1063  }
1064  }
1065 
1066  if (m_pMiniport->m_UseIRQ)
1067  {
1068  ntStatus = m_pMiniport->m_pInterruptSync->CallSynchronizedRoutine(SnapTimeStamp,PVOID(this));
1069  }
1070  else // !m_UseIRQ
1071  {
1072  ntStatus = SnapTimeStamp(NULL,PVOID(this));
1073  } // !m_UseIRQ
1074  aDMKEvt = eventHead;
1075  while (aDMKEvt)
1076  {
1078  aDMKEvt->usChannelGroup = 1;
1080  aDMKEvt = aDMKEvt->pNextEvt;
1081  }
1082  (void)m_sinkMXF->PutMessage(eventHead);
1083  }
1084  }
1085  else // render stream
1086  {
1087  DPRINT("SourceEvtsToPort called on render stream");
1088  ntStatus = STATUS_INVALID_DEVICE_REQUEST;
1089  }
1090  return ntStatus;
1091 }
1092 
1093 #ifdef _MSC_VER
1094 #pragma code_seg()
1095 #endif
1096 
1097 /*****************************************************************************
1098  * DMusMPUInterruptServiceRoutine()
1099  *****************************************************************************
1100  * ISR.
1101  */
1102 NTSTATUS
1103 NTAPI
1106  IN PINTERRUPTSYNC InterruptSync,
1108 )
1109 {
1110  DPRINT("DMusMPUInterruptServiceRoutine");
1112 
1114 
1115  NTSTATUS ntStatus;
1116  BOOL newBytesAvailable;
1117  CMiniportDMusUART *that;
1118  NTSTATUS clockStatus;
1119 
1120  that = (CMiniportDMusUART *) DynamicContext;
1121  newBytesAvailable = FALSE;
1122  ntStatus = STATUS_UNSUCCESSFUL;
1123 
1124  UCHAR portStatus = 0xff;
1125 
1126  //
1127  // Read the MPU status byte.
1128  //
1129  if (that->m_pPortBase)
1130  {
1131  portStatus =
1133 
1134  //
1135  // If there is outstanding work to do and there is a port-driver for
1136  // the MPU miniport...
1137  //
1138  if (UartFifoOkForRead(portStatus) && that->m_pPort)
1139  {
1142  && (UartFifoOkForRead(portStatus)) )
1143  {
1145  if ( (that->m_KSStateInput == KSSTATE_RUN)
1146  && (that->m_NumCaptureStreams)
1147  )
1148  {
1149  ULONG buffHead = that->m_MPUInputBufferHead;
1150  if ( (that->m_MPUInputBufferTail + 1 == buffHead)
1151  || (that->m_MPUInputBufferTail + 1 - kMPUInputBufferSize == buffHead))
1152  {
1153  DPRINT("*****MPU Input Buffer Overflow*****");
1154  }
1155  else
1156  {
1157  if (!that->m_InputTimeStamp)
1158  {
1159  clockStatus = that->m_MasterClock->GetTime(&that->m_InputTimeStamp);
1160  if (STATUS_SUCCESS != clockStatus)
1161  {
1162  DPRINT("GetTime failed for clock 0x%08x",that->m_MasterClock);
1163  }
1164  }
1165  newBytesAvailable = TRUE;
1166  // ...place the data in our FIFO...
1167  that->m_MPUInputBuffer[that->m_MPUInputBufferTail] = uDest;
1169 
1170  that->m_MPUInputBufferTail++;
1172  {
1173  that->m_MPUInputBufferTail = 0;
1174  }
1175  }
1176  }
1177  //
1178  // Look for more MIDI data.
1179  //
1180  portStatus =
1182  } // either there's no data or we ran too long
1183  if (newBytesAvailable)
1184  {
1185  //
1186  // ...notify the MPU port driver that we have bytes.
1187  //
1188  that->m_pPort->Notify(that->m_pServiceGroup);
1189  }
1190  ntStatus = STATUS_SUCCESS;
1191  }
1192  }
1193 
1194  return ntStatus;
1195 }
1196 
1197 /*****************************************************************************
1198  * CMiniportDMusUART::GetDescription()
1199  *****************************************************************************
1200  * Gets the topology.
1201  */
1206  OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
1207 )
1208 {
1209  PAGED_CODE();
1210 
1211  ASSERT(OutFilterDescriptor);
1212 
1213  DPRINT("GetDescription");
1214 
1215  *OutFilterDescriptor = &MiniportFilterDescriptor;
1216 
1217  return STATUS_SUCCESS;
1218 }
1219 
1220 #ifdef _MSC_VER
1221 #pragma code_seg("PAGE")
1222 #endif
1223 
1224 NTSTATUS
1226  OUT PMINIPORT* OutMiniport,
1227  IN REFCLSID ClassId)
1228 {
1230  NTSTATUS Status;
1231 
1233  if (!This)
1235 
1236  Status = This->QueryInterface(IID_IMiniport, (PVOID*)OutMiniport);
1237 
1238  if (!NT_SUCCESS(Status))
1239  {
1240  delete This;
1241  }
1242 
1243  DPRINT("NewMiniportDMusUART %p Status %x\n", *OutMiniport, Status);
1244  return Status;
1245 }
1246 
1247 
1248 #ifdef _MSC_VER
1249 #pragma code_seg("PAGE")
1250 #endif
1251 
1252 /*****************************************************************************
1253  * CMiniportDMusUART::ProcessResources()
1254  *****************************************************************************
1255  * Processes the resource list, setting up helper objects accordingly.
1256  */
1257 NTSTATUS
1262 )
1263 {
1264  PAGED_CODE();
1265 
1266  DPRINT("ProcessResources");
1267 
1269  if (!ResourceList)
1270  {
1272  }
1273  //
1274  // Get counts for the types of resources.
1275  //
1276  ULONG countIO = ResourceList->NumberOfPorts();
1277  ULONG countIRQ = ResourceList->NumberOfInterrupts();
1278  ULONG countDMA = ResourceList->NumberOfDmas();
1279  ULONG lengthIO = ResourceList->FindTranslatedPort(0)->u.Port.Length;
1280 
1281 #if DBG
1282  DPRINT("Starting MPU401 Port 0x%lx", ResourceList->FindTranslatedPort(0)->u.Port.Start.LowPart);
1283 #endif
1284 
1285  NTSTATUS ntStatus = STATUS_SUCCESS;
1286 
1287  //
1288  // Make sure we have the expected number of resources.
1289  //
1290  if ( (countIO != 1)
1291  || (countIRQ > 1)
1292  || (countDMA != 0)
1293  || (lengthIO == 0)
1294  )
1295  {
1296  DPRINT("Unknown ResourceList configuration");
1298  }
1299 
1300  if (NT_SUCCESS(ntStatus))
1301  {
1302  //
1303  // Get the port address.
1304  //
1305  m_pPortBase =
1306  PUCHAR(ResourceList->FindTranslatedPort(0)->u.Port.Start.QuadPart);
1307 
1308  ntStatus = InitializeHardware(m_pInterruptSync,m_pPortBase);
1309  }
1310 
1311  return ntStatus;
1312 }
1313 
1314 #ifdef _MSC_VER
1315 #pragma code_seg("PAGE")
1316 #endif
1317 /*****************************************************************************
1318  * CMiniportDMusUART::NonDelegatingQueryInterface()
1319  *****************************************************************************
1320  * Obtains an interface. This function works just like a COM QueryInterface
1321  * call and is used if the object is not being aggregated.
1322  */
1326  REFIID Interface,
1327  PVOID * Object
1328 )
1329 {
1330  PAGED_CODE();
1331 
1332  DPRINT("Miniport::NonDelegatingQueryInterface");
1333  ASSERT(Object);
1334 
1336  {
1337  *Object = PVOID(PUNKNOWN(PMINIPORTDMUS(this)));
1338  }
1339  else
1340  if (IsEqualGUIDAligned(Interface,IID_IMiniport))
1341  {
1342  *Object = PVOID(PMINIPORT(this));
1343  }
1344  else
1345  if (IsEqualGUIDAligned(Interface,IID_IMiniportDMus))
1346  {
1347  *Object = PVOID(PMINIPORTDMUS(this));
1348  }
1349  else
1350  if (IsEqualGUIDAligned(Interface,IID_IMusicTechnology))
1351  {
1352  *Object = PVOID(PMUSICTECHNOLOGY(this));
1353  }
1354  else
1355  if (IsEqualGUIDAligned(Interface,IID_IPowerNotify))
1356  {
1357  *Object = PVOID(PPOWERNOTIFY(this));
1358  }
1359  else
1360  {
1361  *Object = NULL;
1362  }
1363 
1364  if (*Object)
1365  {
1366  //
1367  // We reference the interface for the caller.
1368  //
1369  PUNKNOWN(*Object)->AddRef();
1370  return STATUS_SUCCESS;
1371  }
1372 
1373  return STATUS_INVALID_PARAMETER;
1374 }
1375 
1376 #ifdef _MSC_VER
1377 #pragma code_seg("PAGE")
1378 #endif
1379 /*****************************************************************************
1380  * CMiniportDMusUART::~CMiniportDMusUART()
1381  *****************************************************************************
1382  * Destructor.
1383  */
1385 {
1386  PAGED_CODE();
1387 
1388  DPRINT("~CMiniportDMusUART");
1389 
1391  ASSERT(0 == m_NumRenderStreams);
1392 
1393  // reset the HW so we don't get anymore interrupts
1394  if (m_UseIRQ && m_pInterruptSync)
1395  {
1396  (void) m_pInterruptSync->CallSynchronizedRoutine((PINTERRUPTSYNCROUTINE)InitMPU,PVOID(m_pPortBase));
1397  }
1398  else
1399  {
1401  }
1402 
1403  if (m_pInterruptSync)
1404  {
1405  m_pInterruptSync->Release();
1407  }
1408  if (m_pServiceGroup)
1409  {
1410  m_pServiceGroup->Release();
1412  }
1413  if (m_pPort)
1414  {
1415  m_pPort->Release();
1416  m_pPort = NULL;
1417  }
1418 }
1419 
1420 #ifdef _MSC_VER
1421 #pragma code_seg("PAGE")
1422 #endif
1423 /*****************************************************************************
1424  * CMiniportDMusUART::Init()
1425  *****************************************************************************
1426  * Initializes a the miniport.
1427  */
1430 Init
1431 (
1432  IN PUNKNOWN UnknownInterruptSync OPTIONAL,
1434  IN PPORTDMUS Port_,
1435  OUT PSERVICEGROUP * ServiceGroup
1436 )
1437 {
1438  PAGED_CODE();
1439 
1441  if (!ResourceList)
1442  {
1444  }
1445 
1446  ASSERT(Port_);
1448 
1449  DPRINT("Init");
1450 
1451  *ServiceGroup = NULL;
1452  m_pPortBase = 0;
1454 
1455  // This will remain unspecified if the miniport does not get any power
1456  // messages.
1457  //
1459 
1460  //
1461  // AddRef() is required because we are keeping this pointer.
1462  //
1463  m_pPort = Port_;
1464  m_pPort->AddRef();
1465 
1466  // Set dataformat.
1467  //
1469  {
1472  sizeof(GUID));
1473  }
1476  sizeof(GUID));
1479  sizeof(GUID));
1480 
1481  for (ULONG bufferCount = 0;bufferCount < kMPUInputBufferSize;bufferCount++)
1482  {
1483  m_MPUInputBuffer[bufferCount] = 0;
1484  }
1487  m_InputTimeStamp = 0;
1489 
1490  NTSTATUS ntStatus = STATUS_SUCCESS;
1491 
1492  m_NumRenderStreams = 0;
1493  m_NumCaptureStreams = 0;
1494 
1495  m_UseIRQ = TRUE;
1496  if (ResourceList->NumberOfInterrupts() == 0)
1497  {
1498  m_UseIRQ = FALSE;
1499  }
1500 
1501  ntStatus = PcNewServiceGroup(&m_pServiceGroup,NULL);
1502  if (NT_SUCCESS(ntStatus) && !m_pServiceGroup) // keep any error
1503  {
1504  ntStatus = STATUS_INSUFFICIENT_RESOURCES;
1505  }
1506 
1507  if (NT_SUCCESS(ntStatus))
1508  {
1510  m_pServiceGroup->AddRef();
1511 
1512  //
1513  // Register the service group with the port early so the port is
1514  // prepared to handle interrupts.
1515  //
1516  m_pPort->RegisterServiceGroup(m_pServiceGroup);
1517  }
1518 
1519  if (NT_SUCCESS(ntStatus) && m_UseIRQ)
1520  {
1521  //
1522  // Due to a bug in the InterruptSync design, we shouldn't share
1523  // the interrupt sync object. Whoever goes away first
1524  // will disconnect it, and the other points off into nowhere.
1525  //
1526  // Instead we generate our own interrupt sync object.
1527  //
1528  UnknownInterruptSync = NULL;
1529 
1530  if (UnknownInterruptSync)
1531  {
1532  ntStatus =
1533  UnknownInterruptSync->QueryInterface
1534  (
1535  IID_IInterruptSync,
1536  (PVOID *) &m_pInterruptSync
1537  );
1538 
1539  if (!m_pInterruptSync && NT_SUCCESS(ntStatus)) // keep any error
1540  {
1541  ntStatus = STATUS_INSUFFICIENT_RESOURCES;
1542  }
1543  if (NT_SUCCESS(ntStatus))
1544  { // run this ISR first
1545  ntStatus = m_pInterruptSync->
1546  RegisterServiceRoutine(DMusMPUInterruptServiceRoutine,PVOID(this),TRUE);
1547  }
1548 
1549  }
1550  else
1551  { // create our own interruptsync mechanism.
1552  ntStatus =
1554  (
1556  NULL,
1557  ResourceList,
1558  0, // Resource Index
1559  InterruptSyncModeNormal // Run ISRs once until we get SUCCESS
1560  );
1561 
1562  if (!m_pInterruptSync && NT_SUCCESS(ntStatus)) // keep any error
1563  {
1564  ntStatus = STATUS_INSUFFICIENT_RESOURCES;
1565  }
1566 
1567  if (NT_SUCCESS(ntStatus))
1568  {
1569  ntStatus = m_pInterruptSync->RegisterServiceRoutine(
1571  PVOID(this),
1572  TRUE); // run this ISR first
1573  }
1574  if (NT_SUCCESS(ntStatus))
1575  {
1576  ntStatus = m_pInterruptSync->Connect();
1577  }
1578  }
1579  }
1580 
1581  if (NT_SUCCESS(ntStatus))
1582  {
1583  ntStatus = ProcessResources(ResourceList);
1584  }
1585 
1586  if (!NT_SUCCESS(ntStatus))
1587  {
1588  //
1589  // clean up our mess
1590  //
1591 
1592  // clean up the interrupt sync
1593  if( m_pInterruptSync )
1594  {
1595  m_pInterruptSync->Release();
1597  }
1598 
1599  // clean up the service group
1600  if( m_pServiceGroup )
1601  {
1602  m_pServiceGroup->Release();
1604  }
1605 
1606  // clean up the out param service group.
1607  if (*ServiceGroup)
1608  {
1609  (*ServiceGroup)->Release();
1610  (*ServiceGroup) = NULL;
1611  }
1612 
1613  // release the port
1614  m_pPort->Release();
1615  m_pPort = NULL;
1616  }
1617 
1618  return ntStatus;
1619 }
1620 
1621 #ifdef _MSC_VER
1622 #pragma code_seg("PAGE")
1623 #endif
1624 /*****************************************************************************
1625  * CMiniportDMusUART::NewStream()
1626  *****************************************************************************
1627  * Gets the topology.
1628  */
1630 CMiniportDMusUART::
1631 NewStream
1632 (
1633  OUT PMXF * MXF,
1634  IN PUNKNOWN OuterUnknown OPTIONAL,
1636  IN ULONG PinID,
1637  IN DMUS_STREAM_TYPE StreamType,
1639  OUT PSERVICEGROUP * ServiceGroup,
1640  IN PAllocatorMXF AllocatorMXF,
1642  OUT PULONGLONG SchedulePreFetch
1643 )
1644 {
1645  PAGED_CODE();
1646 
1647  DPRINT("NewStream");
1648  NTSTATUS ntStatus = STATUS_SUCCESS;
1649 
1650  // In 100 ns, we want stuff as soon as it comes in
1651  //
1652  *SchedulePreFetch = 0;
1653 
1654  // if we don't have any streams already open, get the hardware ready.
1656  {
1657  ntStatus = ResetHardware(m_pPortBase);
1658  if (!NT_SUCCESS(ntStatus))
1659  {
1660  DPRINT("CMiniportDMusUART::NewStream ResetHardware failed");
1661  return ntStatus;
1662  }
1663  }
1664 
1669  )
1670  {
1672  new(PoolType, 'wNcP') CMiniportDMusUARTStream();
1673 
1674  if (pStream)
1675  {
1676  pStream->AddRef();
1677 
1678  ntStatus =
1680 
1681  if (NT_SUCCESS(ntStatus))
1682  {
1683  *MXF = PMXF(pStream);
1684  (*MXF)->AddRef();
1685 
1687  {
1690  (*ServiceGroup)->AddRef();
1691  }
1692  else
1693  {
1695  *ServiceGroup = NULL;
1696  }
1697  }
1698 
1699  pStream->Release();
1700  }
1701  else
1702  {
1703  ntStatus = STATUS_INSUFFICIENT_RESOURCES;
1704  }
1705  }
1706  else
1707  {
1708  ntStatus = STATUS_INVALID_DEVICE_REQUEST;
1710  {
1711  DPRINT("NewStream failed, too many capture streams");
1712  }
1713  else if (StreamType == DMUS_STREAM_MIDI_RENDER)
1714  {
1715  DPRINT("NewStream failed, too many render streams");
1716  }
1717  else
1718  {
1719  DPRINT("NewStream invalid stream type");
1720  }
1721  }
1722 
1723  return ntStatus;
1724 }
1725 
1726 #ifdef _MSC_VER
1727 #pragma code_seg("PAGE")
1728 #endif
1729 /*****************************************************************************
1730  * CMiniportDMusUART::SetTechnology()
1731  *****************************************************************************
1732  * Sets pindatarange technology.
1733  */
1735 CMiniportDMusUART::
1736 SetTechnology
1737 (
1738  IN const GUID * Technology
1739 )
1740 {
1741  PAGED_CODE();
1742 
1743  NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
1744 
1745  // Fail if miniport has already been initialized.
1746  //
1747  if (NULL == m_pPort)
1748  {
1749  RtlCopyMemory(&m_MusicFormatTechnology, Technology, sizeof(GUID));
1750  ntStatus = STATUS_SUCCESS;
1751  }
1752 
1753  return ntStatus;
1754 } // SetTechnology
1755 
1756 /*****************************************************************************
1757  * CMiniportDMusUART::PowerChangeNotify()
1758  *****************************************************************************
1759  * Handle power state change for the miniport.
1760  */
1761 #ifdef _MSC_VER
1762 #pragma code_seg("PAGE")
1763 #endif
1764 
1765 STDMETHODIMP_(void)
1766 CMiniportDMusUART::
1767 PowerChangeNotify
1768 (
1770 )
1771 {
1772  PAGED_CODE();
1773 
1774  DPRINT("CMiniportDMusUART::PoweChangeNotify D%d", PowerState.DeviceState);
1775 
1776  switch (PowerState.DeviceState)
1777  {
1778  case PowerDeviceD0:
1780  {
1782  {
1783  DPRINT("InitializeHardware failed when resuming");
1784  }
1785  }
1786  break;
1787 
1788  case PowerDeviceD1:
1789  case PowerDeviceD2:
1790  case PowerDeviceD3:
1791  default:
1792  break;
1793  }
1794  m_PowerState.DeviceState = PowerState.DeviceState;
1795 } // PowerChangeNotify
1796 
1797 #ifdef _MSC_VER
1798 #pragma code_seg("PAGE")
1799 #endif
1800 /*****************************************************************************
1801  * CMiniportDMusUARTStream::NonDelegatingQueryInterface()
1802  *****************************************************************************
1803  * Obtains an interface. This function works just like a COM QueryInterface
1804  * call and is used if the object is not being aggregated.
1805  */
1809  REFIID Interface,
1810  PVOID * Object
1811 )
1812 {
1813  PAGED_CODE();
1814 
1815  DPRINT("Stream::NonDelegatingQueryInterface");
1816  ASSERT(Object);
1817 
1819  {
1820  *Object = PVOID(PUNKNOWN(this));
1821  }
1822  else
1824  {
1825  *Object = PVOID(PMXF(this));
1826  }
1827  else
1828  {
1829  *Object = NULL;
1830  }
1831 
1832  if (*Object)
1833  {
1834  //
1835  // We reference the interface for the caller.
1836  //
1837  PUNKNOWN(*Object)->AddRef();
1838  return STATUS_SUCCESS;
1839  }
1840 
1841  return STATUS_INVALID_PARAMETER;
1842 }
1843 
1844 #ifdef _MSC_VER
1845 #pragma code_seg("PAGE")
1846 #endif
1847 /*****************************************************************************
1848  * CMiniportDMusUARTStream::~CMiniportDMusUARTStream()
1849  *****************************************************************************
1850  * Destructs a stream.
1851  */
1853 {
1854  PAGED_CODE();
1855 
1856  DPRINT("~CMiniportDMusUARTStream");
1857 
1859 
1860  if (m_DMKEvtQueue)
1861  {
1862  if (m_AllocatorMXF)
1863  {
1864  m_AllocatorMXF->PutMessage(m_DMKEvtQueue);
1865  }
1866  else
1867  {
1868  DPRINT("~CMiniportDMusUARTStream, no allocator, can't flush DMKEvts");
1869  }
1870  m_DMKEvtQueue = NULL;
1871  }
1872  if (m_AllocatorMXF)
1873  {
1874  m_AllocatorMXF->Release();
1875  m_AllocatorMXF = NULL;
1876  }
1877 
1878  if (m_pMiniport)
1879  {
1880  if (m_fCapture)
1881  {
1883  }
1884  else
1885  {
1887  }
1888 
1889  m_pMiniport->Release();
1890  }
1891 }
1892 
1893 #ifdef _MSC_VER
1894 #pragma code_seg("PAGE")
1895 #endif
1896 /*****************************************************************************
1897  * CMiniportDMusUARTStream::Init()
1898  *****************************************************************************
1899  * Initializes a stream.
1900  */
1903 Init
1904 (
1905  IN CMiniportDMusUART * pMiniport,
1906  IN PUCHAR pPortBase,
1907  IN BOOLEAN fCapture,
1908  IN PAllocatorMXF allocatorMXF,
1909  IN PMASTERCLOCK masterClock
1910 )
1911 {
1912  PAGED_CODE();
1913 
1914  ASSERT(pMiniport);
1915  ASSERT(pPortBase);
1916 
1917  DPRINT("Init");
1918 
1919  m_NumFailedMPUTries = 0;
1920  m_TimerQueued = FALSE;
1922  m_pMiniport = pMiniport;
1923  m_pMiniport->AddRef();
1924 
1925  pMiniport->m_MasterClock = masterClock;
1926 
1928  m_fCapture = fCapture;
1929 
1930  m_SnapshotTimeStamp = 0;
1931  m_DMKEvtQueue = NULL;
1932  m_DMKEvtOffset = 0;
1933 
1934  m_NumberOfRetries = 0;
1935 
1936  if (allocatorMXF)
1937  {
1938  allocatorMXF->AddRef();
1941  }
1942  else
1943  {
1944  return STATUS_INVALID_PARAMETER;
1945  }
1946 
1948  (
1949  &m_Dpc,
1950  &::DMusUARTTimerDPC,
1951  PVOID(this)
1952  );
1954 
1955  return STATUS_SUCCESS;
1956 }
1957 
1958 #ifdef _MSC_VER
1959 #pragma code_seg("PAGE")
1960 #endif
1961 /*****************************************************************************
1962  * CMiniportDMusUARTStream::SetState()
1963  *****************************************************************************
1964  * Sets the state of the channel.
1965  */
1967 CMiniportDMusUARTStream::
1968 SetState
1969 (
1970  IN KSSTATE NewState
1971 )
1972 {
1973  PAGED_CODE();
1974 
1975  DPRINT("SetState %d",NewState);
1976 
1977  if (NewState == KSSTATE_RUN)
1978  {
1980  {
1981  LARGE_INTEGER timeDue100ns;
1982  timeDue100ns.QuadPart = 0;
1983  KeSetTimer(&m_TimerEvent,timeDue100ns,&m_Dpc);
1984  }
1985  else
1986  {
1987  DPRINT("CMiniportDMusUARTStream::SetState KSSTATE_RUN failed due to uninitialized MPU");
1989  }
1990  }
1991 
1992  if (m_fCapture)
1993  {
1994  m_pMiniport->m_KSStateInput = NewState;
1995  if (NewState == KSSTATE_STOP) // STOPping
1996  {
1997  m_pMiniport->m_MPUInputBufferHead = 0; // Previously read bytes are discarded.
1998  m_pMiniport->m_MPUInputBufferTail = 0; // The entire FIFO is available.
1999  }
2000  }
2001  return STATUS_SUCCESS;
2002 }
2003 
2004 #ifdef _MSC_VER
2005 #pragma code_seg()
2006 #endif
2007 
2008 
2009 /*****************************************************************************
2010  * CMiniportDMusUART::Service()
2011  *****************************************************************************
2012  * DPC-mode service call from the port.
2013  */
2014 STDMETHODIMP_(void)
2016 Service
2017 ( void
2018 )
2019 {
2020  DPRINT("Service");
2021  if (!m_NumCaptureStreams)
2022  {
2023  // we should never get here....
2024  // if we do, we must have read some trash,
2025  // so just reset the input FIFO
2027  }
2028 }
2029 
2030 #ifdef _MSC_VER
2031 #pragma code_seg("PAGE")
2032 #endif
2033 
2034 /*****************************************************************************
2035  * CMiniportDMusUARTStream::ConnectOutput()
2036  *****************************************************************************
2037  * Writes outgoing MIDI data.
2038  */
2039 NTSTATUS
2040 CMiniportDMusUARTStream::
2041 ConnectOutput(PMXF sinkMXF)
2042 {
2043  PAGED_CODE();
2044 
2045  if (m_fCapture)
2046  {
2047  if ((sinkMXF) && (m_sinkMXF == m_AllocatorMXF))
2048  {
2049  DPRINT("ConnectOutput");
2050  m_sinkMXF = sinkMXF;
2051  return STATUS_SUCCESS;
2052  }
2053  else
2054  {
2055  DPRINT("ConnectOutput failed");
2056  }
2057  }
2058  else
2059  {
2060  DPRINT("ConnectOutput called on renderer; failed");
2061  }
2062  return STATUS_UNSUCCESSFUL;
2063 }
2064 
2065 #ifdef _MSC_VER
2066 #pragma code_seg("PAGE")
2067 #endif
2068 
2069 /*****************************************************************************
2070  * CMiniportDMusUARTStream::DisconnectOutput()
2071  *****************************************************************************
2072  * Writes outgoing MIDI data.
2073  */
2074 NTSTATUS
2075 CMiniportDMusUARTStream::
2076 DisconnectOutput(PMXF sinkMXF)
2077 {
2078  PAGED_CODE();
2079 
2080  if (m_fCapture)
2081  {
2082  if ((m_sinkMXF == sinkMXF) || (!sinkMXF))
2083  {
2084  DPRINT("DisconnectOutput");
2086  return STATUS_SUCCESS;
2087  }
2088  else
2089  {
2090  DPRINT("DisconnectOutput failed");
2091  }
2092  }
2093  else
2094  {
2095  DPRINT("DisconnectOutput called on renderer; failed");
2096  }
2097  return STATUS_UNSUCCESSFUL;
2098 }
2099 
2100 #ifdef _MSC_VER
2101 #pragma code_seg()
2102 #endif
2103 
2104 
2105 /*****************************************************************************
2106  * CMiniportDMusUARTStream::PutMessageLocked()
2107  *****************************************************************************
2108  * Now that the spinlock is held, add this message to the queue.
2109  *
2110  * Writes an outgoing MIDI message.
2111  * We don't sort a new message into the queue -- we append it.
2112  * This is fine, since the sequencer feeds us sequenced data.
2113  * Timestamps will ascend by design.
2114  */
2115 NTSTATUS CMiniportDMusUARTStream::PutMessageLocked(PDMUS_KERNEL_EVENT pDMKEvt)
2116 {
2117  NTSTATUS ntStatus = STATUS_SUCCESS;
2118  PDMUS_KERNEL_EVENT aDMKEvt;
2119 
2121 
2122  if (!m_fCapture)
2123  {
2124  DPRINT("PutMessage to render stream");
2125  if (pDMKEvt)
2126  {
2127  // m_DpcSpinLock already held
2128 
2129  if (m_DMKEvtQueue)
2130  {
2131  aDMKEvt = m_DMKEvtQueue; // put pDMKEvt in event queue
2132 
2133  while (aDMKEvt->pNextEvt)
2134  {
2135  aDMKEvt = aDMKEvt->pNextEvt;
2136  }
2137  aDMKEvt->pNextEvt = pDMKEvt; // here is end of queue
2138  }
2139  else // currently nothing in queue
2140  {
2141  m_DMKEvtQueue = pDMKEvt;
2142  if (m_DMKEvtOffset)
2143  {
2144  DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d",m_DMKEvtOffset);
2145  m_DMKEvtOffset = 0;
2146  }
2147  }
2148 
2149  // m_DpcSpinLock already held
2150  }
2151  if (!m_TimerQueued)
2152  {
2153  (void) ConsumeEvents();
2154  }
2155  }
2156  else // capture
2157  {
2158  DPRINT("PutMessage to capture stream");
2159  ASSERT(NULL == pDMKEvt);
2160 
2161  SourceEvtsToPort();
2162  }
2163  return ntStatus;
2164 }
2165 
2166 #ifdef _MSC_VER
2167 #pragma code_seg()
2168 #endif
2169 
2170 /*****************************************************************************
2171  * CMiniportDMusUARTStream::PutMessage()
2172  *****************************************************************************
2173  * Writes an outgoing MIDI message.
2174  * We don't sort a new message into the queue -- we append it.
2175  * This is fine, since the sequencer feeds us sequenced data.
2176  * Timestamps will ascend by design.
2177  */
2178 NTSTATUS CMiniportDMusUARTStream::PutMessage(PDMUS_KERNEL_EVENT pDMKEvt)
2179 {
2180  NTSTATUS ntStatus = STATUS_SUCCESS;
2181  PDMUS_KERNEL_EVENT aDMKEvt;
2182 
2184 
2185  if (!m_fCapture)
2186  {
2187  DPRINT("PutMessage to render stream");
2188  if (pDMKEvt)
2189  {
2191 
2192  if (m_DMKEvtQueue)
2193  {
2194  aDMKEvt = m_DMKEvtQueue; // put pDMKEvt in event queue
2195 
2196  while (aDMKEvt->pNextEvt)
2197  {
2198  aDMKEvt = aDMKEvt->pNextEvt;
2199  }
2200  aDMKEvt->pNextEvt = pDMKEvt; // here is end of queue
2201  }
2202  else // currently nothing in queue
2203  {
2204  m_DMKEvtQueue = pDMKEvt;
2205  if (m_DMKEvtOffset)
2206  {
2207  DPRINT("PutMessage Nothing in the queue, but m_DMKEvtOffset == %d", m_DMKEvtOffset);
2208  m_DMKEvtOffset = 0;
2209  }
2210  }
2211 
2213  }
2214  if (!m_TimerQueued)
2215  {
2216  (void) ConsumeEvents();
2217  }
2218  }
2219  else // capture
2220  {
2221  DPRINT("PutMessage to capture stream");
2222  ASSERT(NULL == pDMKEvt);
2223 
2224  SourceEvtsToPort();
2225  }
2226  return ntStatus;
2227 }
2228 
2229 #ifdef _MSC_VER
2230 #pragma code_seg()
2231 #endif
2232 
2233 /*****************************************************************************
2234  * CMiniportDMusUARTStream::ConsumeEvents()
2235  *****************************************************************************
2236  * Attempts to empty the render message queue.
2237  * Called either from DPC timer or upon IRP submittal.
2238 // TODO: support packages right
2239 // process the package (actually, should do this above.
2240 // treat the package as a list fragment that shouldn't be sorted.
2241 // better yet, go through each event in the package, and when
2242 // an event is exhausted, delete it and decrement m_offset.
2243  */
2244 NTSTATUS CMiniportDMusUARTStream::ConsumeEvents(void)
2245 {
2246  PDMUS_KERNEL_EVENT aDMKEvt;
2247 
2248  NTSTATUS ntStatus = STATUS_SUCCESS;
2249  ULONG bytesRemaining = 0,bytesWritten = 0;
2250  LARGE_INTEGER aMillisecIn100ns;
2251 
2254 
2255  m_TimerQueued = FALSE;
2256  while (m_DMKEvtQueue) // do we have anything to play at all?
2257  {
2258  aDMKEvt = m_DMKEvtQueue; // event we try to play
2259  if (aDMKEvt->cbEvent)
2260  {
2261  bytesRemaining = aDMKEvt->cbEvent - m_DMKEvtOffset; // number of bytes left in this evt
2262 
2263  ASSERT(bytesRemaining > 0);
2264  if (bytesRemaining <= 0)
2265  {
2266  bytesRemaining = aDMKEvt->cbEvent;
2267  }
2268 
2269  if (aDMKEvt->cbEvent <= sizeof(PBYTE)) // short message
2270  {
2271  DPRINT("ConsumeEvents(%02x%02x%02x%02x)", aDMKEvt->uData.abData[0], aDMKEvt->uData.abData[1], aDMKEvt->uData.abData[2], aDMKEvt->uData.abData[3]);
2272  ntStatus = Write(aDMKEvt->uData.abData + m_DMKEvtOffset,bytesRemaining,&bytesWritten);
2273  }
2274  else if (PACKAGE_EVT(aDMKEvt))
2275  {
2276  ASSERT(m_DMKEvtOffset == 0);
2277  m_DMKEvtOffset = 0;
2278  DPRINT("ConsumeEvents(Package)");
2279 
2280  ntStatus = PutMessageLocked(aDMKEvt->uData.pPackageEvt); // we already own the spinlock
2281 
2282  // null this because we are about to throw it in the allocator
2283  aDMKEvt->uData.pPackageEvt = NULL;
2284  aDMKEvt->cbEvent = 0;
2285  bytesWritten = bytesRemaining;
2286  }
2287  else // SysEx message
2288  {
2289  DPRINT("ConsumeEvents(%02x%02x%02x%02x)", aDMKEvt->uData.pbData[0], aDMKEvt->uData.pbData[1], aDMKEvt->uData.pbData[2], aDMKEvt->uData.pbData[3]);
2290 
2291  ntStatus = Write(aDMKEvt->uData.pbData + m_DMKEvtOffset,bytesRemaining,&bytesWritten);
2292  }
2293  } // if (aDMKEvt->cbEvent)
2294  if (STATUS_SUCCESS != ntStatus)
2295  {
2296  DPRINT("ConsumeEvents: Write returned 0x%08x", ntStatus);
2297  bytesWritten = bytesRemaining; // just bail on this event and try next time
2298  }
2299 
2300  ASSERT(bytesWritten <= bytesRemaining);
2301  if (bytesWritten == bytesRemaining)
2302  {
2304  aDMKEvt->pNextEvt = NULL;
2305 
2306  m_AllocatorMXF->PutMessage(aDMKEvt); // throw back in free pool
2307  m_DMKEvtOffset = 0; // start fresh on next evt
2308  m_NumberOfRetries = 0;
2309  } // but wait ... there's more!
2310  else // our FIFO is full for now.
2311  {
2312  // update our offset by that amount we did write
2314  ASSERT(m_DMKEvtOffset < aDMKEvt->cbEvent);
2315 
2316  DPRINT("ConsumeEvents tried %d, wrote %d, at offset %d", bytesRemaining,bytesWritten,m_DMKEvtOffset);
2317  aMillisecIn100ns.QuadPart = -(kOneMillisec); // set timer, come back later
2318  m_TimerQueued = TRUE;
2320  ntStatus = KeSetTimer( &m_TimerEvent, aMillisecIn100ns, &m_Dpc );
2321  break;
2322  } // we didn't write it all
2323  } // go back, Jack, do it again (while m_DMKEvtQueue)
2325  return ntStatus;
2326 }
2327 
2328 #ifdef _MSC_VER
2329 #pragma code_seg()
2330 #endif
2331 
2332 /*****************************************************************************
2333  * CMiniportDMusUARTStream::HandlePortParams()
2334  *****************************************************************************
2335  * Writes an outgoing MIDI message.
2336  */
2337 NTSTATUS
2342 )
2343 {
2344  PAGED_CODE();
2345 
2346  NTSTATUS ntStatus;
2347 
2348  if (pRequest->Verb & KSPROPERTY_TYPE_SET)
2349  {
2351  }
2352 
2353  ntStatus = ValidatePropertyRequest(pRequest, sizeof(SYNTH_PORTPARAMS), TRUE);
2354  if (NT_SUCCESS(ntStatus))
2355  {
2356  RtlCopyMemory(pRequest->Value, pRequest->Instance, sizeof(SYNTH_PORTPARAMS));
2357 
2359 
2360  if (Params->ValidParams & ~SYNTH_PORTPARAMS_CHANNELGROUPS)
2361  {
2362  Params->ValidParams &= SYNTH_PORTPARAMS_CHANNELGROUPS;
2363  }
2364 
2365  if (!(Params->ValidParams & SYNTH_PORTPARAMS_CHANNELGROUPS))
2366  {
2367  Params->ChannelGroups = 1;
2368  }
2369  else if (Params->ChannelGroups != 1)
2370  {
2371  Params->ChannelGroups = 1;
2372  }
2373 
2374  pRequest->ValueSize = sizeof(SYNTH_PORTPARAMS);
2375  }
2376 
2377  return ntStatus;
2378 }
2379 
2380 #ifdef _MSC_VER
2381 #pragma code_seg()
2382 #endif
2383 
2384 /*****************************************************************************
2385  * DMusTimerDPC()
2386  *****************************************************************************
2387  * The timer DPC callback. Thunks to a C++ member function.
2388  * This is called by the OS in response to the DirectMusic pin
2389  * wanting to wakeup later to process more DirectMusic stuff.
2390  */
2391 VOID
2392 NTAPI
2395  IN PKDPC Dpc,
2399 )
2400 {
2402 
2403  CMiniportDMusUARTStream *aStream;
2405  if (aStream)
2406  {
2407  DPRINT("DMusUARTTimerDPC");
2408  if (false == aStream->m_fCapture)
2409  {
2410  (void) aStream->ConsumeEvents();
2411  }
2412  // ignores return value!
2413  }
2414 }
2415 
2416 /*****************************************************************************
2417  * DirectMusic properties
2418  ****************************************************************************/
2419 
2420 #ifdef _MSC_VER
2421 #pragma code_seg()
2422 #endif
2423 
2424 /*
2425  * Properties concerning synthesizer functions.
2426  */
2427 const WCHAR wszDescOut[] = L"DMusic MPU-401 Out ";
2428 const WCHAR wszDescIn[] = L"DMusic MPU-401 In ";
2429 
2430 NTSTATUS
2431 NTAPI
2435 )
2436 {
2437  NTSTATUS ntStatus;
2438 
2439  PAGED_CODE();
2440 
2442  {
2443  ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONG), TRUE);
2444  if (NT_SUCCESS(ntStatus))
2445  {
2446  // if return buffer can hold a ULONG, return the access flags
2447  PULONG AccessFlags = PULONG(pRequest->Value);
2448 
2449  *AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT;
2450  switch (pRequest->PropertyItem->Id)
2451  {
2452  case KSPROPERTY_SYNTH_CAPS:
2454  *AccessFlags |= KSPROPERTY_TYPE_GET;
2455  }
2456  switch (pRequest->PropertyItem->Id)
2457  {
2459  *AccessFlags |= KSPROPERTY_TYPE_SET;
2460  }
2461  ntStatus = STATUS_SUCCESS;
2462  pRequest->ValueSize = sizeof(ULONG);
2463 
2464  switch (pRequest->PropertyItem->Id)
2465  {
2467  if (pRequest->MinorTarget)
2468  {
2469  *AccessFlags |= KSPROPERTY_TYPE_GET;
2470  }
2471  else
2472  {
2473  pRequest->ValueSize = 0;
2474  ntStatus = STATUS_INVALID_DEVICE_REQUEST;
2475  }
2476  }
2477  }
2478  }
2479  else
2480  {
2481  ntStatus = STATUS_SUCCESS;
2482  switch(pRequest->PropertyItem->Id)
2483  {
2484  case KSPROPERTY_SYNTH_CAPS:
2485  DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CAPS");
2486 
2487  if (pRequest->Verb & KSPROPERTY_TYPE_SET)
2488  {
2489  ntStatus = STATUS_INVALID_DEVICE_REQUEST;
2490  }
2491 
2492  if (NT_SUCCESS(ntStatus))
2493  {
2494  ntStatus = ValidatePropertyRequest(pRequest, sizeof(SYNTHCAPS), TRUE);
2495 
2496  if (NT_SUCCESS(ntStatus))
2497  {
2498  SYNTHCAPS *caps = (SYNTHCAPS*)pRequest->Value;
2499  int increment;
2500  RtlZeroMemory(caps, sizeof(SYNTHCAPS));
2501  // XXX Different guids for different instances!
2502  //
2503  if (pRequest->Node == eSynthNode)
2504  {
2505  increment = sizeof(wszDescOut) - 2;
2506  RtlCopyMemory( caps->Description,wszDescOut,increment);
2507  caps->Guid = CLSID_MiniportDriverDMusUART;
2508  }
2509  else
2510  {
2511  increment = sizeof(wszDescIn) - 2;
2512  RtlCopyMemory( caps->Description,wszDescIn,increment);
2513  caps->Guid = CLSID_MiniportDriverDMusUARTCapture;
2514  }
2515 
2516  caps->Flags = SYNTH_PC_EXTERNAL;
2517  caps->MemorySize = 0;
2518  caps->MaxChannelGroups = 1;
2519  caps->MaxVoices = 0xFFFFFFFF;
2520  caps->MaxAudioChannels = 0xFFFFFFFF;
2521 
2522  caps->EffectFlags = 0;
2523 
2524  CMiniportDMusUART *aMiniport;
2525  ASSERT(pRequest->MajorTarget);
2526  aMiniport = (CMiniportDMusUART *)(PMINIPORTDMUS)(pRequest->MajorTarget);
2527  WCHAR wszDesc2[16];
2528  int cLen;
2529  cLen = swprintf(wszDesc2,L"[%03x]\0",PtrToUlong(aMiniport->m_pPortBase));
2530 
2531  cLen *= sizeof(WCHAR);
2532  RtlCopyMemory((WCHAR *)((DWORD_PTR)(caps->Description) + increment),
2533  wszDesc2,
2534  cLen);
2535 
2536 
2537  pRequest->ValueSize = sizeof(SYNTHCAPS);
2538  }
2539  }
2540 
2541  break;
2542 
2544  DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_PORTPARAMETERS");
2545  {
2546  CMiniportDMusUARTStream *aStream;
2547 
2548  aStream = (CMiniportDMusUARTStream*)(pRequest->MinorTarget);
2549  if (aStream)
2550  {
2551  ntStatus = aStream->HandlePortParams(pRequest);
2552  }
2553  else
2554  {
2555  ntStatus = STATUS_INVALID_DEVICE_REQUEST;
2556  }
2557  }
2558  break;
2559 
2561  DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_CHANNELGROUPS");
2562 
2563  ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONG), TRUE);
2564  if (NT_SUCCESS(ntStatus))
2565  {
2566  *(PULONG)(pRequest->Value) = 1;
2567  pRequest->ValueSize = sizeof(ULONG);
2568  }
2569  break;
2570 
2572  DPRINT("PropertyHandler_Synth:KSPROPERTY_SYNTH_LATENCYCLOCK");
2573 
2574  if(pRequest->Verb & KSPROPERTY_TYPE_SET)
2575  {
2576  ntStatus = STATUS_INVALID_DEVICE_REQUEST;
2577  }
2578  else
2579  {
2580  ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONGLONG), TRUE);
2581  if(NT_SUCCESS(ntStatus))
2582  {
2583  REFERENCE_TIME rtLatency;
2584  CMiniportDMusUARTStream *aStream;
2585 
2586  aStream = (CMiniportDMusUARTStream*)(pRequest->MinorTarget);
2587  if(aStream == NULL)
2588  {
2589  ntStatus = STATUS_INVALID_DEVICE_REQUEST;
2590  }
2591  else
2592  {
2593  aStream->m_pMiniport->m_MasterClock->GetTime(&rtLatency);
2594  *((PULONGLONG)pRequest->Value) = rtLatency;
2595  pRequest->ValueSize = sizeof(ULONGLONG);
2596  }
2597  }
2598  }
2599  break;
2600 
2601  default:
2602  DPRINT("Unhandled property in PropertyHandler_Synth");
2603  break;
2604  }
2605  }
2606  return ntStatus;
2607 }
2608 
2609 /*****************************************************************************
2610  * ValidatePropertyRequest()
2611  *****************************************************************************
2612  * Validates pRequest.
2613  * Checks if the ValueSize is valid
2614  * Checks if the Value is valid
2615  *
2616  * This does not update pRequest->ValueSize if it returns NT_SUCCESS.
2617  * Caller must set pRequest->ValueSize in case of NT_SUCCESS.
2618  */
2622  IN ULONG ulValueSize,
2623  IN BOOLEAN fValueRequired
2624 )
2625 {
2626  NTSTATUS ntStatus;
2627 
2628  if (pRequest->ValueSize >= ulValueSize)
2629  {
2630  if (fValueRequired && NULL == pRequest->Value)
2631  {
2632  ntStatus = STATUS_INVALID_PARAMETER;
2633  }
2634  else
2635  {
2636  ntStatus = STATUS_SUCCESS;
2637  }
2638  }
2639  else if (0 == pRequest->ValueSize)
2640  {
2641  ntStatus = STATUS_BUFFER_OVERFLOW;
2642  }
2643  else
2644  {
2645  ntStatus = STATUS_BUFFER_TOO_SMALL;
2646  }
2647 
2648  if (STATUS_BUFFER_OVERFLOW == ntStatus)
2649  {
2650  pRequest->ValueSize = ulValueSize;
2651  }
2652  else
2653  {
2654  pRequest->ValueSize = 0;
2655  }
2656 
2657  return ntStatus;
2658 } // ValidatePropertyRequest
2659 
2660 #ifdef _MSC_VER
2661 #pragma code_seg()
2662 #endif
2663 
2664 
IN PUCHAR IN BOOLEAN fCapture
NTSTATUS NTAPI SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync, PVOID syncWriteContext)
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define MPU401_REG_COMMAND
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesWritten
Definition: wdfiotarget.h:949
struct SYNCWRITECONTEXT * PSYNCWRITECONTEXT
IServiceGroup * PSERVICEGROUP
Definition: portcls.h:614
#define KSAUDFNAME_DMUSIC_MPU_OUT
Definition: dmusicks.h:240
IN PUNKNOWN OuterUnknown IN POOL_TYPE IN ULONG IN DMUS_STREAM_TYPE StreamType
#define MPU401_REG_DATA
#define IN
Definition: typedefs.h:39
const GUID KSDATAFORMAT_TYPE_MUSIC
Definition: sup.c:35
#define UartFifoOkForWrite(status)
#define STDMETHODIMP_(t)
Definition: basetyps.h:44
#define REFIID
Definition: guiddef.h:118
CMiniportDMusUART(IUnknown *Unknown)
friend class CMiniportDMusUARTStream
DWORD MaxVoices
Definition: dmusprop.h:86
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:107
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
DWORD MemorySize
Definition: dmusprop.h:84
union KSDATAFORMAT KSDATARANGE
_In_ WDFIOTARGET _In_ PWDF_REQUEST_COMPLETION_PARAMS Params
Definition: wdfrequest.h:306
POWER_STATE m_PowerState
#define CONST_PCNODE_DESCRIPTOR_AUTO(n, a)
friend NTSTATUS NTAPI PropertyHandler_Synth(IN PPCPROPERTY_REQUEST)
Definition: http.c:7251
IN PUNKNOWN OuterUnknown IN POOL_TYPE IN ULONG PinID
#define READ_PORT_UCHAR(p)
Definition: pc98vid.h:22
const ULONG kMPUInputBufferSize
#define TRUE
Definition: types.h:120
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
IUnknown * PUNKNOWN
Definition: com_apitest.h:45
#define REFCLSID
Definition: guiddef.h:117
#define TAG_PORTCLASS
Definition: private.hpp:24
IMusicTechnology * PMUSICTECHNOLOGY
Definition: portcls.h:1028
static ULONGLONG startTime
Definition: main.c:113
GLuint GLuint GLsizei count
Definition: gl.h:1545
unsigned char * PUCHAR
Definition: retypes.h:3
CMiniportDMusUART * Miniport
#define KSCATEGORY_RENDER
Definition: ks.h:165
static PKSDATARANGE PinDataRangePointersBridge[]
VOID NTAPI KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:198
LONG NTSTATUS
Definition: precomp.h:26
STDMETHODIMP QueryInterface(REFIID InterfaceId, PVOID *Interface)
SnapTimeStamp(PINTERRUPTSYNC InterruptSync, PVOID pStream)
ULONGLONG NTAPI PcGetTimeInterval(IN ULONGLONG Since)
Definition: api.cpp:37
FxRequest * pRequest
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define KSCATEGORY_CAPTURE
Definition: ks.h:160
#define kMaxNumCaptureStreams
_In_ WDFREQUEST Request
Definition: wdfdevice.h:547
IPortDMus * PPORTDMUS
Definition: dmusicks.h:167
struct _SYNTH_PORTPARAMS SYNTH_PORTPARAMS
GUID Guid
Definition: dmusprop.h:82
NTSTATUS NTAPI DMusMPUInterruptServiceRoutine(PINTERRUPTSYNC InterruptSync, PVOID DynamicContext)
REFERENCE_TIME m_InputTimeStamp
#define IID_IMXF
Definition: dmusicks.h:250
BOOL Init(PUSERCONNECT UserCon)
Definition: dllmain.c:385
NTSTATUS WriteMPU(IN PUCHAR PortBase, IN BOOLEAN IsCommand, IN UCHAR Value)
if(dx==0 &&dy==0)
Definition: linetemp.h:174
static BOOL Write(PBYTE Address, PBYTE Data, SIZE_T Size)
Definition: vmhorizon.c:15
_Must_inspect_result_ _In_ WDFIORESREQLIST _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFIORESLIST * ResourceList
Definition: wdfresource.h:304
#define KSPROPERTY_TYPE_GET
Definition: dmksctrl.h:42
#define kOneMillisec
static KSDATARANGE PinDataRangesBridge[]
struct _DMUS_KERNEL_EVENT * pNextEvt
Definition: dmusicks.h:20
IMasterClock * PMASTERCLOCK
Definition: dmusicks.h:51
#define KSNODEPIN_STANDARD_OUT
Definition: ksmedia.h:1270
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define IsEqualGUIDAligned(guid1, guid2)
Definition: wdm.template.h:235
#define STATUS_INVALID_DEVICE_STATE
Definition: udferr_usr.h:178
#define STATUS_IO_DEVICE_ERROR
Definition: udferr_usr.h:179
_In_ WDFREQUEST _In_ size_t OutputBufferLength
Definition: wdfio.h:318
IN PUCHAR IN BOOLEAN IN PAllocatorMXF allocatorMXF
WCHAR Description[128]
Definition: dmusprop.h:89
PSERVICEGROUP m_pServiceGroup
STDMETHODIMP QueryInterface(REFIID InterfaceId, PVOID *Interface)
return STATUS_NOT_IMPLEMENTED
IN PUNKNOWN OuterUnknown IN POOL_TYPE IN ULONG IN DMUS_STREAM_TYPE IN PKSDATAFORMAT OUT PSERVICEGROUP IN PAllocatorMXF IN PMASTERCLOCK OUT PULONGLONG SchedulePreFetch
struct IAllocatorMXF * PAllocatorMXF
Definition: dmusicks.h:107
#define L(x)
Definition: ntvdm.h:50
#define KSAUDFNAME_MIDI
Definition: ksmedia.h:1301
NTSTATUS NTAPI InitMPU(IN PINTERRUPTSYNC InterruptSync, IN PVOID DynamicContext)
GetDescription(OUT PPCFILTER_DESCRIPTOR *OutFilterDescriptor)
static PCCONNECTION_DESCRIPTOR MiniportConnections[]
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
const GUID KSCATEGORY_AUDIO
Definition: controls.c:25
#define FALSE
Definition: types.h:117
CMiniportDMusUART * m_pMiniport
unsigned int BOOL
Definition: ntddk_ex.h:94
PAllocatorMXF m_AllocatorMXF
friend NTSTATUS NTAPI PropertyHandler_Synth(IN PPCPROPERTY_REQUEST PropertyRequest)
UCHAR m_MPUInputBuffer[kMPUInputBufferSize]
BYTE abData[sizeof(PBYTE)]
Definition: dmusicks.h:22
#define STDMETHODIMP
Definition: basetyps.h:43
const WCHAR wszDescIn[]
#define GTI_MILLISECONDS(t)
Definition: portcls.h:2502
friend PVOID pStream
const GUID KSDATAFORMAT_SPECIFIER_NONE
Definition: sup.c:37
FORCEINLINE VOID KeInitializeSpinLock(_Out_ PKSPIN_LOCK SpinLock)
Definition: kefuncs.h:240
unsigned char BOOLEAN
STDMETHODIMP_(NTSTATUS) SourceEvtsToPort()
#define STATUS_INVALID_PARAMETER_2
Definition: ntstatus.h:476
#define kMaxNumDMusicRenderStreams
#define DMUS_KEF_EVENT_INCOMPLETE
Definition: dmusicks.h:253
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
void * PVOID
Definition: retypes.h:9
IN PUCHAR IN BOOLEAN IN PAllocatorMXF IN PMASTERCLOCK masterClock
#define KSMUSIC_TECHNOLOGY_PORT
Definition: ksmedia.h:1291
#define PtrToUlong(u)
Definition: config.h:107
STDMETHODIMP_(void) Service(void)
static PCNODE_DESCRIPTOR MiniportNodes[]
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:406
#define KSDATAFORMAT_SUBTYPE_DIRECTMUSIC
Definition: dmusprop.h:9
REFERENCE_TIME ullPresTime100ns
Definition: dmusicks.h:18
PDMUS_KERNEL_EVENT m_DMKEvtQueue
Status
Definition: gdiplustypes.h:24
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:675
union _DMUS_KERNEL_EVENT::@1881 uData
#define KSPROPERTY_TYPE_BASICSUPPORT
Definition: dmksctrl.h:45
IN PUNKNOWN OuterUnknown IN POOL_TYPE PoolType
NTSTATUS NewMiniportDMusUART(OUT PMINIPORT *OutMiniport, IN REFCLSID ClassId)
IN PUNKNOWN OuterUnknown IN POOL_TYPE IN ULONG IN DMUS_STREAM_TYPE IN PKSDATAFORMAT OUT PSERVICEGROUP IN PAllocatorMXF AllocatorMXF
#define kMaxNumLegacyRenderStreams
#define SIZEOF_ARRAY(ar)
Definition: cdrom.h:1482
static GUID MiniportCategories[]
BOOLEAN NTAPI KeCancelTimer(IN OUT PKTIMER Timer)
Definition: timerobj.c:206
#define ASSERT(a)
Definition: mode.c:44
struct _SYNTH_PORTPARAMS * PSYNTH_PORTPARAMS
LONGLONG REFERENCE_TIME
Definition: dmusicks.h:9
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
INT POOL_TYPE
Definition: typedefs.h:78
uint64_t ULONGLONG
Definition: typedefs.h:67
const GUID IID_IUnknown
VOID NTAPI KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:221
const GUID KSDATAFORMAT_SUBTYPE_MIDI
Definition: sup.c:36
nsrefcnt Release()
DEVICE_POWER_STATE DeviceState
Definition: ntpoapi.h:58
NTSTATUS NTAPI PcNewInterruptSync(OUT PINTERRUPTSYNC *OutInterruptSync, IN PUNKNOWN OuterUnknown OPTIONAL, IN PRESOURCELIST ResourceList, IN ULONG ResourceIndex, IN INTERRUPTSYNCMODE Mode)
Definition: interrupt.cpp:305
#define success(from, fromstr, to, tostr)
struct _MINIPORT * PMINIPORT
#define STATICGUIDOF(guid)
Definition: dmksctrl.h:25
_In_opt_ PVOID _In_ ULONG _In_ PVOID context
Definition: wdfdriver.h:113
ULONG AddRef()
DWORD Flags
Definition: dmusprop.h:83
#define KSDATAFORMAT_SUBTYPE_MIDI_BUS
Definition: ksmedia.h:1296
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
NTSTATUS InitializeHardware(PINTERRUPTSYNC interruptSync, PUCHAR portBase)
unsigned char UCHAR
Definition: xmlstorage.h:181
#define PCFILTER_NODE
Definition: portcls.h:154
static KSDATARANGE_MUSIC PinDataRangesStreamDMusic
#define SYNTH_PORTPARAMS_CHANNELGROUPS
Definition: dmusprop.h:105
Definition: ketypes.h:687
#define WRITE_PORT_UCHAR(p, d)
Definition: pc98vid.h:21
friend NTSTATUS NTAPI DMusMPUInterruptServiceRoutine(PINTERRUPTSYNC InterruptSync, PVOID DynamicContext)
friend NTSTATUS NTAPI SynchronizedDMusMPUWrite(PINTERRUPTSYNC InterruptSync, PVOID syncWriteContext)
#define GUID_NULL
Definition: ks.h:106
int _cdecl swprintf(const WCHAR *,...)
uint32_t DWORD_PTR
Definition: typedefs.h:65
USHORT usChannelGroup
Definition: dmusicks.h:16
unsigned char BYTE
Definition: xxhash.c:193
DWORD EffectFlags
Definition: dmusprop.h:88
_Must_inspect_result_ _In_ WDFCOLLECTION _In_ WDFOBJECT Object
GLenum GLsizei GLuint GLint * bytesWritten
Definition: glext.h:11123
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:675
static PKSDATARANGE PinDataRangePointersStreamCombined[]
IResourceList * PRESOURCELIST
Definition: portcls.h:442
union KSDATAFORMAT * PKSDATARANGE
IN PUNKNOWN OuterUnknown IN POOL_TYPE IN ULONG IN DMUS_STREAM_TYPE IN PKSDATAFORMAT OUT PSERVICEGROUP IN PAllocatorMXF IN PMASTERCLOCK MasterClock
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define MPU401_CMD_RESET
static PKSDATARANGE PinDataRangePointersStreamLegacy[]
BOOLEAN TryMPU(IN PUCHAR PortBase)
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
KSSTATE
Definition: ks.h:1214
static PCPIN_DESCRIPTOR MiniportPins[]
IN PVOID IN PVOID IN USHORT IN USHORT IN PINTERFACE Interface
Definition: pci.h:361
VOID NTAPI DMusUARTTimerDPC(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
unsigned short USHORT
Definition: pedump.c:61
NTSTATUS ResetHardware(PUCHAR portBase)
IMiniportDMus * PMINIPORTDMUS
Definition: dmusicks.h:209
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_ WDF_DEVICE_POWER_STATE PowerState
Definition: wdfdevice.h:3032
IN PRESOURCELIST IN PPORTDMUS Port
NTSTATUS ProcessResources(IN PRESOURCELIST ResourceList)
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
virtual ~CMiniportDMusUART()
unsigned int * PULONG
Definition: retypes.h:1
#define NULL
Definition: types.h:112
const WCHAR wszDescOut[]
DWORD MaxChannelGroups
Definition: dmusprop.h:85
IInterruptSync * PINTERRUPTSYNC
Definition: portcls.h:888
IN PRESOURCELIST IN PPORTDMUS OUT PSERVICEGROUP * ServiceGroup
static PKSDATARANGE PinDataRangePointersStreamDMusic[]
NTSTATUS NTAPI PropertyHandler_Synth(IN PPCPROPERTY_REQUEST PropertyRequest)
#define SYNTH_PC_EXTERNAL
Definition: dmusprop.h:65
IPowerNotify * PPOWERNOTIFY
Definition: portcls.h:2057
#define KSNODEPIN_STANDARD_IN
Definition: ksmedia.h:1269
DWORD MaxAudioChannels
Definition: dmusprop.h:87
#define KSAUDFNAME_DMUSIC_MPU_IN
Definition: dmusicks.h:245
#define OUT
Definition: typedefs.h:40
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:383
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ _Strict_type_match_ POOL_TYPE PoolType
Definition: wdfdevice.h:3810
PMASTERCLOCK m_MasterClock
unsigned int ULONG
Definition: retypes.h:1
NTSTATUS NTAPI PcNewServiceGroup(OUT PSERVICEGROUP *OutServiceGroup, IN PUNKNOWN OuterUnknown OPTIONAL)
static PCPROPERTY_ITEM SynthProperties[]
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define PACKAGE_EVT(evt)
Definition: dmusicks.h:258
#define KSPROPSETID_Synth
Definition: dmusprop.h:50
friend VOID NTAPI DMusUARTTimerDPC(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
REFERENCE_TIME m_SnapshotTimeStamp
DataRangeIntersection(IN ULONG PinId, IN PKSDATARANGE DataRange, IN PKSDATARANGE MatchingDataRange, IN ULONG OutputBufferLength, OUT PVOID ResultantFormat, OUT PULONG ResultantFormatLength)
static KSDATARANGE_MUSIC PinDataRangesStreamLegacy
#define STATUS_SUCCESS
Definition: shellext.h:65
#define kMPUPollTimeout
DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth, SynthProperties)
#define DPRINT
Definition: sndvol32.h:71
PINTERRUPTSYNC m_pInterruptSync
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:712
#define STATUS_DEVICE_CONFIGURATION_ERROR
Definition: ntstatus.h:619
NTSTATUS ValidatePropertyRequest(IN PPCPROPERTY_REQUEST pRequest, IN ULONG ulValueSize, IN BOOLEAN fValueRequired)
struct IMXF * PMXF
Definition: dmusicks.h:68
Definition: main.c:14
static PHARDWARE_TIMER MasterClock
Definition: pit.c:28
#define KSPROPERTY_TYPE_SET
Definition: dmksctrl.h:43
#define MPU401_CMD_UART
struct _SYNTHCAPS SYNTHCAPS
static SERVICE_STATUS status
Definition: service.c:31
struct _DMUS_KERNEL_EVENT * pPackageEvt
Definition: dmusicks.h:24
friend VOID NTAPI DMusUARTTimerDPC(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
BYTE * PBYTE
Definition: pedump.c:66
nsrefcnt AddRef()
_Inout_opt_ PUNICODE_STRING _Inout_opt_ PUNICODE_STRING Stream
Definition: fltkernel.h:1092
VOID NTAPI KeStallExecutionProcessor(IN ULONG MicroSeconds)
Definition: ntoskrnl.c:81
#define UartFifoOkForRead(status)
IN PVOID DynamicContext
Definition: portcls.h:849
static PCFILTER_DESCRIPTOR MiniportFilterDescriptor
DMUS_STREAM_TYPE
Definition: dmusicks.h:28
NTSTATUS HandlePortParams(IN PPCPROPERTY_REQUEST Request)
const GUID KSNODETYPE_SYNTHESIZER
Definition: controls.c:30
LONGLONG QuadPart
Definition: typedefs.h:114
#define MPU401_REG_STATUS
_In_ PSCSI_REQUEST_BLOCK _In_opt_ PVOID BufferAddress
Definition: cdrom.h:989
#define PAGED_CODE()
Definition: ps.c:97
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:675