winsta: fix spec file
[reactos.git] / reactos / drivers / wdm / audio / backpln / portcls / port_dmus.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/port_dmus.c
5 * PURPOSE: DirectMusic Port driver
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "private.h"
10
11 typedef struct
12 {
13 IPortDMusVtbl *lpVtbl;
14 IServiceSinkVtbl *lpVtblServiceSink;
15 ISubdeviceVtbl *lpVtblSubDevice;
16
17 LONG ref;
18 BOOL bInitialized;
19 IMiniportDMus *pMiniport;
20 IMiniportMidi *pMiniportMidi;
21 DEVICE_OBJECT *pDeviceObject;
22 PSERVICEGROUP ServiceGroup;
23 PPINCOUNT pPinCount;
24 PPOWERNOTIFY pPowerNotify;
25 PPORTFILTERDMUS Filter;
26
27 PPCFILTER_DESCRIPTOR pDescriptor;
28 PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor;
29
30 }IPortDMusImpl;
31
32 static GUID InterfaceGuids[3] =
33 {
34 {
35 /// KS_CATEGORY_AUDIO
36 0x6994AD04, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
37 },
38 {
39 /// KS_CATEGORY_RENDER
40 0x65E8773E, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
41 },
42 {
43 /// KS_CATEGORY_CAPTURE
44 0x65E8773D, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}
45 }
46 };
47
48 DEFINE_KSPROPERTY_TOPOLOGYSET(PortFilterDMusTopologySet, TopologyPropertyHandler);
49 DEFINE_KSPROPERTY_PINPROPOSEDATAFORMAT(PortFilterDMusPinSet, PinPropertyHandler, PinPropertyHandler, PinPropertyHandler);
50
51 KSPROPERTY_SET PortDMusPropertySet[] =
52 {
53 {
54 &KSPROPSETID_Topology,
55 sizeof(PortFilterDMusTopologySet) / sizeof(KSPROPERTY_ITEM),
56 (const KSPROPERTY_ITEM*)&PortFilterDMusTopologySet,
57 0,
58 NULL
59 },
60 {
61 &KSPROPSETID_Pin,
62 sizeof(PortFilterDMusPinSet) / sizeof(KSPROPERTY_ITEM),
63 (const KSPROPERTY_ITEM*)&PortFilterDMusPinSet,
64 0,
65 NULL
66 }
67 };
68
69
70 //---------------------------------------------------------------
71 // IUnknown interface functions
72 //
73
74 NTSTATUS
75 NTAPI
76 IPortDMus_fnQueryInterface(
77 IPortDMus* iface,
78 IN REFIID refiid,
79 OUT PVOID* Output)
80 {
81 UNICODE_STRING GuidString;
82 IPortDMusImpl * This = (IPortDMusImpl*)iface;
83
84
85 if (IsEqualGUIDAligned(refiid, &IID_IPortDMus) ||
86 IsEqualGUIDAligned(refiid, &IID_IPortMidi) ||
87 IsEqualGUIDAligned(refiid, &IID_IUnknown))
88 {
89 *Output = &This->lpVtbl;
90 InterlockedIncrement(&This->ref);
91 return STATUS_SUCCESS;
92 }
93 else if (IsEqualGUIDAligned(refiid, &IID_ISubdevice))
94 {
95 *Output = &This->lpVtblSubDevice;
96 InterlockedIncrement(&This->ref);
97 return STATUS_SUCCESS;
98 }
99 else if (IsEqualGUIDAligned(refiid, &IID_IDrmPort) ||
100 IsEqualGUIDAligned(refiid, &IID_IDrmPort2))
101 {
102 return NewIDrmPort((PDRMPORT2*)Output);
103 }
104 else if (IsEqualGUIDAligned(refiid, &IID_IPortClsVersion))
105 {
106 return NewPortClsVersion((PPORTCLSVERSION*)Output);
107 }
108 else if (IsEqualGUIDAligned(refiid, &IID_IUnregisterSubdevice))
109 {
110 return NewIUnregisterSubdevice((PUNREGISTERSUBDEVICE*)Output);
111 }
112 else if (IsEqualGUIDAligned(refiid, &IID_IUnregisterPhysicalConnection))
113 {
114 return NewIUnregisterPhysicalConnection((PUNREGISTERPHYSICALCONNECTION*)Output);
115 }
116
117 if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS)
118 {
119 DPRINT1("IPortMidi_fnQueryInterface no interface!!! iface %S\n", GuidString.Buffer);
120 RtlFreeUnicodeString(&GuidString);
121 }
122 return STATUS_UNSUCCESSFUL;
123 }
124
125 ULONG
126 NTAPI
127 IPortDMus_fnAddRef(
128 IPortDMus* iface)
129 {
130 IPortDMusImpl * This = (IPortDMusImpl*)iface;
131
132 return _InterlockedIncrement(&This->ref);
133 }
134
135 ULONG
136 NTAPI
137 IPortDMus_fnRelease(
138 IPortDMus* iface)
139 {
140 IPortDMusImpl * This = (IPortDMusImpl*)iface;
141
142 _InterlockedDecrement(&This->ref);
143
144 if (This->ref == 0)
145 {
146 if (This->bInitialized)
147 {
148 This->pMiniport->lpVtbl->Release(This->pMiniport);
149 }
150 FreeItem(This, TAG_PORTCLASS);
151 return 0;
152 }
153 /* Return new reference count */
154 return This->ref;
155 }
156
157
158 //---------------------------------------------------------------
159 // IPort interface functions
160 //
161
162 NTSTATUS
163 NTAPI
164 IPortDMus_fnGetDeviceProperty(
165 IN IPortDMus * iface,
166 IN DEVICE_REGISTRY_PROPERTY DeviceRegistryProperty,
167 IN ULONG BufferLength,
168 OUT PVOID PropertyBuffer,
169 OUT PULONG ReturnLength)
170 {
171 IPortDMusImpl * This = (IPortDMusImpl*)iface;
172
173 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
174
175 if (!This->bInitialized)
176 {
177 DPRINT("IPortDMus_fnNewRegistryKey called w/o initiazed\n");
178 return STATUS_UNSUCCESSFUL;
179 }
180
181 return IoGetDeviceProperty(This->pDeviceObject, DeviceRegistryProperty, BufferLength, PropertyBuffer, ReturnLength);
182 }
183
184 NTSTATUS
185 NTAPI
186 IPortDMus_fnInit(
187 IN IPortDMus * iface,
188 IN PDEVICE_OBJECT DeviceObject,
189 IN PIRP Irp,
190 IN PUNKNOWN UnknownMiniport,
191 IN PUNKNOWN UnknownAdapter OPTIONAL,
192 IN PRESOURCELIST ResourceList)
193 {
194 IMiniportDMus * Miniport = NULL;
195 IMiniportMidi * MidiMiniport = NULL;
196 NTSTATUS Status;
197 PSERVICEGROUP ServiceGroup = NULL;
198 PPINCOUNT PinCount;
199 PPOWERNOTIFY PowerNotify;
200 IPortDMusImpl * This = (IPortDMusImpl*)iface;
201
202 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
203
204 if (This->bInitialized)
205 {
206 DPRINT("IPortDMus_Init called again\n");
207 return STATUS_SUCCESS;
208 }
209
210 Status = UnknownMiniport->lpVtbl->QueryInterface(UnknownMiniport, &IID_IMiniportDMus, (PVOID*)&Miniport);
211 if (!NT_SUCCESS(Status))
212 {
213 /* check for legacy interface */
214 Status = UnknownMiniport->lpVtbl->QueryInterface(UnknownMiniport, &IID_IMiniportMidi, (PVOID*)&MidiMiniport);
215 if (!NT_SUCCESS(Status))
216 {
217 DPRINT("IPortDMus_Init called with invalid IMiniport adapter\n");
218 return STATUS_INVALID_PARAMETER;
219 }
220 }
221
222 /* Initialize port object */
223 This->pMiniport = Miniport;
224 This->pMiniportMidi = MidiMiniport;
225 This->pDeviceObject = DeviceObject;
226 This->bInitialized = TRUE;
227
228 if (Miniport)
229 {
230 /* initialize IMiniportDMus */
231 Status = Miniport->lpVtbl->Init(Miniport, UnknownAdapter, ResourceList, iface, &ServiceGroup);
232 if (!NT_SUCCESS(Status))
233 {
234 DPRINT("IMiniportDMus_Init failed with %x\n", Status);
235 This->bInitialized = FALSE;
236 return Status;
237 }
238
239 /* get the miniport device descriptor */
240 Status = Miniport->lpVtbl->GetDescription(Miniport, &This->pDescriptor);
241 if (!NT_SUCCESS(Status))
242 {
243 DPRINT1("failed to get description\n");
244 Miniport->lpVtbl->Release(Miniport);
245 This->bInitialized = FALSE;
246 return Status;
247 }
248
249 /* increment reference on miniport adapter */
250 Miniport->lpVtbl->AddRef(Miniport);
251
252 }
253 else
254 {
255 /* initialize IMiniportMidi */
256 Status = MidiMiniport->lpVtbl->Init(MidiMiniport, UnknownAdapter, ResourceList, (IPortMidi*)iface, &ServiceGroup);
257 if (!NT_SUCCESS(Status))
258 {
259 DPRINT("IMiniportMidi_Init failed with %x\n", Status);
260 This->bInitialized = FALSE;
261 return Status;
262 }
263
264 /* get the miniport device descriptor */
265 Status = MidiMiniport->lpVtbl->GetDescription(MidiMiniport, &This->pDescriptor);
266 if (!NT_SUCCESS(Status))
267 {
268 DPRINT1("failed to get description\n");
269 MidiMiniport->lpVtbl->Release(MidiMiniport);
270 This->bInitialized = FALSE;
271 return Status;
272 }
273
274 /* increment reference on miniport adapter */
275 MidiMiniport->lpVtbl->AddRef(MidiMiniport);
276 }
277
278 /* create the subdevice descriptor */
279 Status = PcCreateSubdeviceDescriptor(&This->SubDeviceDescriptor,
280 3,
281 InterfaceGuids,
282 0,
283 NULL,
284 2,
285 PortDMusPropertySet,
286 0,
287 0,
288 0,
289 NULL,
290 0,
291 NULL,
292 This->pDescriptor);
293
294 if (!NT_SUCCESS(Status))
295 {
296 DPRINT1("Failed to create descriptior\n");
297
298 if (Miniport)
299 Miniport->lpVtbl->Release(Miniport);
300 else
301 MidiMiniport->lpVtbl->Release(MidiMiniport);
302
303 This->bInitialized = FALSE;
304 return Status;
305 }
306
307 if (This->ServiceGroup == NULL && ServiceGroup)
308 {
309 /* register service group */
310 This->ServiceGroup = ServiceGroup;
311 }
312
313 /* check if it supports IPinCount interface */
314 Status = UnknownMiniport->lpVtbl->QueryInterface(UnknownMiniport, &IID_IPinCount, (PVOID*)&PinCount);
315 if (NT_SUCCESS(Status))
316 {
317 /* store IPinCount interface */
318 This->pPinCount = PinCount;
319 }
320
321 /* does the Miniport adapter support IPowerNotify interface*/
322 Status = UnknownMiniport->lpVtbl->QueryInterface(UnknownMiniport, &IID_IPowerNotify, (PVOID*)&PowerNotify);
323 if (NT_SUCCESS(Status))
324 {
325 /* store reference */
326 This->pPowerNotify = PowerNotify;
327 }
328
329 return STATUS_SUCCESS;
330 }
331
332
333 NTSTATUS
334 NTAPI
335 IPortDMus_fnNewRegistryKey(
336 IN IPortDMus * iface,
337 OUT PREGISTRYKEY *OutRegistryKey,
338 IN PUNKNOWN OuterUnknown OPTIONAL,
339 IN ULONG RegistryKeyType,
340 IN ACCESS_MASK DesiredAccess,
341 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
342 IN ULONG CreateOptions OPTIONAL,
343 OUT PULONG Disposition OPTIONAL)
344 {
345 IPortDMusImpl * This = (IPortDMusImpl*)iface;
346
347 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
348
349 if (!This->bInitialized)
350 {
351 DPRINT("IPortDMus_fnNewRegistryKey called w/o initialized\n");
352 return STATUS_UNSUCCESSFUL;
353 }
354
355 return PcNewRegistryKey(OutRegistryKey,
356 OuterUnknown,
357 RegistryKeyType,
358 DesiredAccess,
359 This->pDeviceObject,
360 NULL,//FIXME
361 ObjectAttributes,
362 CreateOptions,
363 Disposition);
364 }
365
366 VOID
367 NTAPI
368 IPortDMus_fnNotify(
369 IN IPortDMus * iface,
370 IN PSERVICEGROUP ServiceGroup OPTIONAL)
371 {
372 IPortDMusImpl * This = (IPortDMusImpl*)iface;
373
374 if (ServiceGroup)
375 {
376 ServiceGroup->lpVtbl->RequestService (ServiceGroup);
377 return;
378 }
379
380 ASSERT(This->ServiceGroup);
381
382 /* notify miniport service group */
383 This->ServiceGroup->lpVtbl->RequestService(This->ServiceGroup);
384
385 /* notify stream miniport service group */
386 if (This->Filter)
387 {
388 This->Filter->lpVtbl->NotifyPins(This->Filter);
389 }
390 }
391
392 VOID
393 NTAPI
394 IPortDMus_fnRegisterServiceGroup(
395 IN IPortDMus * iface,
396 IN PSERVICEGROUP ServiceGroup)
397 {
398 IPortDMusImpl * This = (IPortDMusImpl*)iface;
399
400 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
401
402 This->ServiceGroup = ServiceGroup;
403
404 ServiceGroup->lpVtbl->AddRef(ServiceGroup);
405 ServiceGroup->lpVtbl->AddMember(ServiceGroup, (PSERVICESINK)&This->lpVtblServiceSink);
406 }
407
408 static IPortDMusVtbl vt_IPortDMus =
409 {
410 /* IUnknown methods */
411 IPortDMus_fnQueryInterface,
412 IPortDMus_fnAddRef,
413 IPortDMus_fnRelease,
414 /* IPort methods */
415 IPortDMus_fnInit,
416 IPortDMus_fnGetDeviceProperty,
417 IPortDMus_fnNewRegistryKey,
418 IPortDMus_fnNotify,
419 IPortDMus_fnRegisterServiceGroup
420 };
421
422 //---------------------------------------------------------------
423 // ISubdevice interface
424 //
425
426 static
427 NTSTATUS
428 NTAPI
429 ISubDevice_fnQueryInterface(
430 IN ISubdevice *iface,
431 IN REFIID InterfaceId,
432 IN PVOID* Interface)
433 {
434 IPortDMusImpl * This = (IPortDMusImpl*)CONTAINING_RECORD(iface, IPortDMusImpl, lpVtblSubDevice);
435
436 return IPortDMus_fnQueryInterface((IPortDMus*)This, InterfaceId, Interface);
437 }
438
439 static
440 ULONG
441 NTAPI
442 ISubDevice_fnAddRef(
443 IN ISubdevice *iface)
444 {
445 IPortDMusImpl * This = (IPortDMusImpl*)CONTAINING_RECORD(iface, IPortDMusImpl, lpVtblSubDevice);
446
447 return IPortDMus_fnAddRef((IPortDMus*)This);
448 }
449
450 static
451 ULONG
452 NTAPI
453 ISubDevice_fnRelease(
454 IN ISubdevice *iface)
455 {
456 IPortDMusImpl * This = (IPortDMusImpl*)CONTAINING_RECORD(iface, IPortDMusImpl, lpVtblSubDevice);
457
458 return IPortDMus_fnRelease((IPortDMus*)This);
459 }
460
461 static
462 NTSTATUS
463 NTAPI
464 ISubDevice_fnNewIrpTarget(
465 IN ISubdevice *iface,
466 OUT struct IIrpTarget **OutTarget,
467 IN WCHAR * Name,
468 IN PUNKNOWN Unknown,
469 IN POOL_TYPE PoolType,
470 IN PDEVICE_OBJECT DeviceObject,
471 IN PIRP Irp,
472 IN KSOBJECT_CREATE *CreateObject)
473 {
474 NTSTATUS Status;
475 PPORTFILTERDMUS Filter;
476 IPortDMusImpl * This = (IPortDMusImpl*)CONTAINING_RECORD(iface, IPortDMusImpl, lpVtblSubDevice);
477
478 DPRINT("ISubDevice_NewIrpTarget this %p\n", This);
479
480 if (This->Filter)
481 {
482 *OutTarget = (IIrpTarget*)This->Filter;
483 return STATUS_SUCCESS;
484 }
485
486
487 Status = NewPortFilterDMus(&Filter);
488 if (!NT_SUCCESS(Status))
489 {
490 return Status;
491 }
492
493 Status = Filter->lpVtbl->Init(Filter, (PPORTDMUS)This);
494 if (!NT_SUCCESS(Status))
495 {
496 Filter->lpVtbl->Release(Filter);
497 return Status;
498 }
499
500 *OutTarget = (IIrpTarget*)Filter;
501 return Status;
502 }
503
504 static
505 NTSTATUS
506 NTAPI
507 ISubDevice_fnReleaseChildren(
508 IN ISubdevice *iface)
509 {
510 //IPortDMusImpl * This = (IPortDMusImpl*)CONTAINING_RECORD(iface, IPortDMusImpl, lpVtblSubDevice);
511
512 UNIMPLEMENTED
513 return STATUS_UNSUCCESSFUL;
514 }
515
516 static
517 NTSTATUS
518 NTAPI
519 ISubDevice_fnGetDescriptor(
520 IN ISubdevice *iface,
521 IN SUBDEVICE_DESCRIPTOR ** Descriptor)
522 {
523 IPortDMusImpl * This = (IPortDMusImpl*)CONTAINING_RECORD(iface, IPortDMusImpl, lpVtblSubDevice);
524
525 DPRINT("ISubDevice_GetDescriptor this %p\n", This);
526 *Descriptor = This->SubDeviceDescriptor;
527 return STATUS_SUCCESS;
528 }
529
530 static
531 NTSTATUS
532 NTAPI
533 ISubDevice_fnDataRangeIntersection(
534 IN ISubdevice *iface,
535 IN ULONG PinId,
536 IN PKSDATARANGE DataRange,
537 IN PKSDATARANGE MatchingDataRange,
538 IN ULONG OutputBufferLength,
539 OUT PVOID ResultantFormat OPTIONAL,
540 OUT PULONG ResultantFormatLength)
541 {
542 IPortDMusImpl * This = (IPortDMusImpl*)CONTAINING_RECORD(iface, IPortDMusImpl, lpVtblSubDevice);
543
544 DPRINT("ISubDevice_DataRangeIntersection this %p\n", This);
545
546 if (This->pMiniport)
547 {
548 return This->pMiniport->lpVtbl->DataRangeIntersection (This->pMiniport, PinId, DataRange, MatchingDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength);
549 }
550
551 return STATUS_UNSUCCESSFUL;
552 }
553
554 static
555 NTSTATUS
556 NTAPI
557 ISubDevice_fnPowerChangeNotify(
558 IN ISubdevice *iface,
559 IN POWER_STATE PowerState)
560 {
561 IPortDMusImpl * This = (IPortDMusImpl*)CONTAINING_RECORD(iface, IPortDMusImpl, lpVtblSubDevice);
562
563 if (This->pPowerNotify)
564 {
565 This->pPowerNotify->lpVtbl->PowerChangeNotify(This->pPowerNotify, PowerState);
566 }
567
568 return STATUS_SUCCESS;
569 }
570
571 static
572 NTSTATUS
573 NTAPI
574 ISubDevice_fnPinCount(
575 IN ISubdevice *iface,
576 IN ULONG PinId,
577 IN OUT PULONG FilterNecessary,
578 IN OUT PULONG FilterCurrent,
579 IN OUT PULONG FilterPossible,
580 IN OUT PULONG GlobalCurrent,
581 IN OUT PULONG GlobalPossible)
582 {
583 IPortDMusImpl * This = (IPortDMusImpl*)CONTAINING_RECORD(iface, IPortDMusImpl, lpVtblSubDevice);
584
585 if (This->pPinCount)
586 {
587 This->pPinCount->lpVtbl->PinCount(This->pPinCount, PinId, FilterNecessary, FilterCurrent, FilterPossible, GlobalCurrent, GlobalPossible);
588 return STATUS_SUCCESS;
589 }
590
591 /* FIXME
592 * scan filter descriptor
593 */
594 return STATUS_UNSUCCESSFUL;
595 }
596
597 static ISubdeviceVtbl vt_ISubdevice =
598 {
599 ISubDevice_fnQueryInterface,
600 ISubDevice_fnAddRef,
601 ISubDevice_fnRelease,
602 ISubDevice_fnNewIrpTarget,
603 ISubDevice_fnReleaseChildren,
604 ISubDevice_fnGetDescriptor,
605 ISubDevice_fnDataRangeIntersection,
606 ISubDevice_fnPowerChangeNotify,
607 ISubDevice_fnPinCount
608 };
609
610
611 static
612 NTSTATUS
613 NTAPI
614 IServiceSink_fnQueryInterface(
615 IServiceSink* iface,
616 IN REFIID refiid,
617 OUT PVOID* Output)
618 {
619 IPortDMusImpl * This = (IPortDMusImpl*)CONTAINING_RECORD(iface, IPortDMusImpl, lpVtblServiceSink);
620
621 if (IsEqualGUIDAligned(refiid, &IID_IServiceSink) ||
622 IsEqualGUIDAligned(refiid, &IID_IUnknown))
623 {
624 *Output = &This->lpVtblServiceSink;
625 InterlockedIncrement(&This->ref);
626 return STATUS_SUCCESS;
627 }
628
629 DPRINT("Unknown interface requested\n");
630 return STATUS_UNSUCCESSFUL;
631 }
632
633 static
634 ULONG
635 NTAPI
636 IServiceSink_fnAddRef(
637 IServiceSink* iface)
638 {
639 IPortDMusImpl * This = (IPortDMusImpl*)CONTAINING_RECORD(iface, IPortDMusImpl, lpVtblServiceSink);
640 return IPortDMus_fnAddRef((IPortDMus*)This);
641 }
642
643 static
644 ULONG
645 NTAPI
646 IServiceSink_fnRelease(
647 IServiceSink* iface)
648 {
649 IPortDMusImpl * This = (IPortDMusImpl*)CONTAINING_RECORD(iface, IPortDMusImpl, lpVtblServiceSink);
650 return IPortDMus_fnRelease((IPortDMus*)This);
651 }
652
653 static
654 VOID
655 NTAPI
656 IServiceSink_fnRequestService(
657 IServiceSink* iface)
658 {
659 UNIMPLEMENTED
660 }
661
662 static IServiceSinkVtbl vt_IServiceSink =
663 {
664 IServiceSink_fnQueryInterface,
665 IServiceSink_fnAddRef,
666 IServiceSink_fnRelease,
667 IServiceSink_fnRequestService
668 };
669
670 NTSTATUS
671 NewPortDMus(
672 OUT PPORT* OutPort)
673 {
674 IPortDMusImpl * This = AllocateItem(NonPagedPool, sizeof(IPortDMusImpl), TAG_PORTCLASS);
675
676 if (!This)
677 {
678 return STATUS_INSUFFICIENT_RESOURCES;
679 }
680
681 This->ref = 1;
682 This->lpVtbl = &vt_IPortDMus;
683 This->lpVtblServiceSink = &vt_IServiceSink;
684 This->lpVtblSubDevice = &vt_ISubdevice;
685
686 *OutPort = (PPORT)&This->lpVtbl;
687
688 return STATUS_SUCCESS;
689 }
690
691 VOID
692 GetDMusMiniport(
693 IN IPortDMus * iface,
694 IN PMINIPORTDMUS * Miniport,
695 IN PMINIPORTMIDI * MidiMiniport)
696 {
697 IPortDMusImpl * This = (IPortDMusImpl*)iface;
698
699 *Miniport = This->pMiniport;
700 *MidiMiniport = This->pMiniportMidi;
701 }