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