1 /*
2 Copyright (c) 2006-2008 dogbert <dogber1@gmail.com>
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14    derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 #include "minwave.hpp"
29 #include "minwavetables.hpp"
30 #include "ntddk.h"
31 
32 #ifdef _MSC_VER
33 #pragma code_seg("PAGE")
34 #endif
35 
CreateMiniportWaveCMI(PUNKNOWN * Unknown,REFCLSID,PUNKNOWN UnknownOuter,POOL_TYPE PoolType)36 NTSTATUS NTAPI CreateMiniportWaveCMI(PUNKNOWN *Unknown, REFCLSID, PUNKNOWN UnknownOuter, POOL_TYPE PoolType)
37 {
38 	PAGED_CODE();
39 	ASSERT(Unknown);
40 #ifdef WAVERT
41 	STD_CREATE_BODY_(CMiniportWaveCMI,Unknown,UnknownOuter,PoolType,PMINIPORTWAVERT);
42 #else
43 	STD_CREATE_BODY_(CMiniportWaveCMI,Unknown,UnknownOuter,PoolType,PMINIPORTWAVECYCLIC);
44 #endif
45 }
46 
processResources(PRESOURCELIST resourceList)47 NTSTATUS CMiniportWaveCMI::processResources(PRESOURCELIST resourceList)
48 {
49 	PAGED_CODE();
50 	ASSERT (resourceList);
51 	DBGPRINT(("CMiniportWaveCMI[%p]::ProcessResources(%p)", this, resourceList));
52 
53 	if (resourceList->NumberOfInterrupts() < 1) {
54 		DBGPRINT(("Unknown configuration for wave miniport"));
55 		return STATUS_DEVICE_CONFIGURATION_ERROR;
56 	}
57 	return STATUS_SUCCESS;
58 }
59 
60 #ifndef WAVERT
newDMAChannel(PDMACHANNEL * dmaChannel,UInt32 bufferLength)61 NTSTATUS CMiniportWaveCMI::newDMAChannel(PDMACHANNEL *dmaChannel, UInt32 bufferLength)
62 {
63 	PAGED_CODE();
64 	ASSERT(dmaChannel);
65 	DBGPRINT(("CMiniportWaveCMI[%p]::newDMAChannel(%p)", this, dmaChannel));
66 
67 	NTSTATUS ntStatus;
68 
69 	ntStatus = Port->NewMasterDmaChannel(dmaChannel, NULL, NULL, bufferLength, TRUE, FALSE, (DMA_WIDTH)(-1), (DMA_SPEED)(-1));
70 	if (NT_SUCCESS(ntStatus)) {
71 		ULONG  lDMABufferLength = bufferLength;
72 		do {
73 			ntStatus = (*dmaChannel)->AllocateBuffer(lDMABufferLength, NULL);
74 			lDMABufferLength >>= 1;
75 		} while (!NT_SUCCESS(ntStatus) && (lDMABufferLength > (PAGE_SIZE / 2)));
76 	}
77 	return ntStatus;
78 }
79 #endif
80 
81 //generic crap
NonDelegatingQueryInterface(REFIID Interface,PVOID * Object)82 STDMETHODIMP CMiniportWaveCMI::NonDelegatingQueryInterface(REFIID Interface, PVOID *Object)
83 {
84 	PAGED_CODE();
85 	ASSERT(Object);
86 	DBGPRINT(("CMiniportWaveCMI[%p]::NonDelegatingQueryInterface", this));
87 
88 	if (IsEqualGUIDAligned(Interface,IID_IUnknown)) {
89 #ifdef WAVERT
90 		*Object = PVOID(PUNKNOWN(PMINIPORTWAVERT(this)));
91 #else
92 		*Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLIC(this)));
93 #endif
94 	} else if (IsEqualGUIDAligned(Interface,IID_IMiniport)) {
95 		*Object = PVOID(PMINIPORT(this));
96 #ifdef WAVERT
97 	} else if (IsEqualGUIDAligned(Interface,IID_IMiniportWaveRT)) {
98 		*Object = PVOID(PMINIPORTWAVERT(this));
99 #else
100 	} else if (IsEqualGUIDAligned(Interface,IID_IMiniportWaveCyclic)) {
101 		*Object = PVOID(PMINIPORTWAVECYCLIC(this));
102 #endif
103 	} else {
104 		*Object = NULL;
105 	}
106 
107 	if (*Object) {
108 		// We reference the interface for the caller.
109 		PUNKNOWN(*Object)->AddRef();
110 		return STATUS_SUCCESS;
111 	}
112 
113 	return STATUS_INVALID_PARAMETER;
114 }
115 
~CMiniportWaveCMI(void)116 CMiniportWaveCMI::~CMiniportWaveCMI(void)
117 {
118 	PAGED_CODE();
119 	DBGPRINT(("CMiniportWaveCMI[%p]::~CMiniportWaveCMI", this));
120 
121 	storeChannelConfigToRegistry(); //or not. during system shutdown, this doesn't seem to work.
122 
123 	if (CMIAdapter) {
124 		CMIAdapter->Release();
125 		CMIAdapter = NULL;
126 	}
127 
128 	for (int i=0;i<3;i++) {
129 #ifndef WAVERT
130 		if (DMAChannel[i]) {
131 			DMAChannel[i]->Release();
132 			DMAChannel[i] = NULL;
133 		}
134 #endif
135 	if (isStreamRunning[i]) {
136 			isStreamRunning[i] = false;
137 			stream[i]->Release();
138 			stream[i] = NULL;
139 		}
140 	}
141 
142 	if (Port) {
143 		Port->Release();
144 		Port = NULL;
145 	}
146 }
147 
148 #ifdef WAVERT
Init(PUNKNOWN UnknownAdapter,PRESOURCELIST ResourceList,PPORTWAVERT Port_)149 STDMETHODIMP CMiniportWaveCMI::Init(PUNKNOWN UnknownAdapter, PRESOURCELIST ResourceList, PPORTWAVERT Port_)
150 #else
151 STDMETHODIMP CMiniportWaveCMI::Init(PUNKNOWN UnknownAdapter, PRESOURCELIST ResourceList, PPORTWAVECYCLIC Port_)
152 #endif
153 {
154 	PAGED_CODE();
155 
156 	ASSERT(UnknownAdapter);
157 	ASSERT(ResourceList);
158 	ASSERT(Port_);
159 
160 	DBGPRINT(("CMiniportWaveCMI[%p]::Init(%p, %p, %p)", this, UnknownAdapter, ResourceList, Port_));
161 
162 	Port = Port_;
163 	Port->AddRef();
164 
165 	NTSTATUS ntStatus = UnknownAdapter->QueryInterface(IID_ICMIAdapter, (PVOID *) &CMIAdapter);
166 	if (!NT_SUCCESS(ntStatus)) {
167 	    DBGPRINT(("QueryInterface(CMIAdapter) failed"));
168 		return ntStatus;
169 	}
170 
171 	//check for Vista, set the AC3 stuff accordingly
172 	if (IoIsWdmVersionAvailable(0x06,0x00)) {
173 		WavePinDataRangesAC3Stream[1].MinimumSampleFrequency = MIN_SAMPLE_RATE;
174 		WavePinDataRangesAC3Stream[1].MaximumSampleFrequency = MAX_SAMPLE_RATE;
175 		WavePinDataRangesAC3Stream[1].DataRange.SubFormat    = KSDATAFORMAT_SUBTYPE_PCM;
176 		WavePinDataRangesAC3Stream[1].DataRange.Specifier    = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
177 	}
178 
179 	cm = CMIAdapter->getCMI8738Info();
180 	cm->regFUNCTRL0  = 0;
181 	cm->WaveMiniport = this;
182 
183 	loadChannelConfigFromRegistry();
184 
185 	for (int i=0;i<3;i++)
186 	{
187 		isStreamRunning[i] = false;
188 
189 #ifndef WAVERT
190 		ntStatus = newDMAChannel(&DMAChannel[i], MAXLEN_DMA_BUFFER);
191 		if (!NT_SUCCESS(ntStatus)) {
192 			DBGPRINT(("NewDmaChannel() failed"));
193 			return ntStatus;
194 		}
195 #endif
196 	}
197 
198 	KeInitializeMutex(&mutex, 1);
199 
200 	return processResources(ResourceList);
201 }
202 
203 #ifdef WAVERT
STDMETHODIMP_(NTSTATUS)204 STDMETHODIMP_(NTSTATUS) CMiniportWaveCMI::GetDeviceDescription(PDEVICE_DESCRIPTION OutDeviceDescriptor)
205 {
206 	PAGED_CODE();
207 	ASSERT(OutDeviceDescriptor);
208 	DBGPRINT(("CMiniportWaveCMI[%p]::GetDeviceDescription(%p)", this, OutDeviceDescriptor));
209 
210 	RtlZeroMemory(OutDeviceDescriptor, sizeof(DEVICE_DESCRIPTION));
211 	OutDeviceDescriptor->ScatterGather     = false;
212 	OutDeviceDescriptor->Master            = true;
213 	OutDeviceDescriptor->Dma32BitAddresses = true;
214 	OutDeviceDescriptor->InterfaceType     = PCIBus;
215 	OutDeviceDescriptor->MaximumLength     = MAXLEN_DMA_BUFFER-2;
216 
217 	return STATUS_SUCCESS;
218 }
219 #endif
220 
GetDescription(PPCFILTER_DESCRIPTOR * OutFilterDescriptor)221 STDMETHODIMP CMiniportWaveCMI::GetDescription(PPCFILTER_DESCRIPTOR *OutFilterDescriptor)
222 {
223 	PAGED_CODE();
224 	ASSERT(OutFilterDescriptor);
225 	DBGPRINT(("CMiniportWaveCMI[%p]::GetDescription(%p)", this, OutFilterDescriptor));
226 
227 	*OutFilterDescriptor = &WaveMiniportFilterDescriptor;
228 
229 	return STATUS_SUCCESS;
230 }
231 
loadChannelConfigFromRegistry()232 NTSTATUS CMiniportWaveCMI::loadChannelConfigFromRegistry()
233 {
234 	PAGED_CODE();
235 	PREGISTRYKEY       DriverKey;
236 	PREGISTRYKEY       SettingsKey;
237 	UNICODE_STRING     KeyName;
238 	DWORD              ResultLength;
239 	PVOID              KeyInfo;
240 
241 	DBGPRINT(("CMiniportWaveCMI::loadChannelConfigFromRegistry()"));
242 
243 	if ((!CMIAdapter) || (!(CMIAdapter->getDeviceObject()))) {
244 		return STATUS_UNSUCCESSFUL;
245 	}
246 
247 	NTSTATUS ntStatus = PcNewRegistryKey(&DriverKey, NULL, DriverRegistryKey, KEY_ALL_ACCESS, CMIAdapter->getDeviceObject(), NULL, NULL, 0, NULL);
248 
249 	if(!NT_SUCCESS(ntStatus)) {
250 		DBGPRINT(("PcNewRegistryKey() failed"));
251 		return STATUS_UNSUCCESSFUL;
252 	}
253 
254 	RtlInitUnicodeString(&KeyName, L"Settings");
255 
256 	ntStatus = DriverKey->NewSubKey(&SettingsKey, NULL, KEY_ALL_ACCESS, &KeyName, REG_OPTION_NON_VOLATILE, NULL);
257 	if(!NT_SUCCESS(ntStatus)) {
258 		DBGPRINT(("DriverKey->NewSubKey() failed"));
259 		return STATUS_UNSUCCESSFUL;
260 	}
261 
262 	KeyInfo = ExAllocatePoolWithTag(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD), 'gnaa');
263 	if (KeyInfo) {
264 		RtlInitUnicodeString(&KeyName, L"ChannelCount");
265 		ntStatus = SettingsKey->QueryValueKey(&KeyName, KeyValuePartialInformation, KeyInfo, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD), &ResultLength);
266 		if (NT_SUCCESS (ntStatus)) {
267 			PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyInfo;
268 			if (PartialInfo->DataLength == sizeof(DWORD)) {
269 				requestedChannelCount = (*(PLONG)PartialInfo->Data);
270 			}
271 		} else {
272 			requestedChannelCount = 2;
273 		}
274 
275 		RtlInitUnicodeString(&KeyName, L"ChannelMask");
276 		ntStatus = SettingsKey->QueryValueKey(&KeyName, KeyValuePartialInformation, KeyInfo, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD), &ResultLength);
277 		if (NT_SUCCESS (ntStatus)) {
278 			PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyInfo;
279 			if (PartialInfo->DataLength == sizeof(DWORD)) {
280 				requestedChannelMask = (*(PLONG)PartialInfo->Data);
281 			}
282 		} else {
283 			requestedChannelMask = KSAUDIO_SPEAKER_STEREO;
284 		}
285 	}
286 	ExFreePoolWithTag(KeyInfo,'gnaa');
287 
288 	SettingsKey->Release();
289 	DriverKey->Release();
290 
291 	return STATUS_SUCCESS;
292 }
293 
storeChannelConfigToRegistry()294 NTSTATUS CMiniportWaveCMI::storeChannelConfigToRegistry()
295 {
296 	PAGED_CODE();
297 	PREGISTRYKEY       DriverKey;
298 	PREGISTRYKEY       SettingsKey;
299 	UNICODE_STRING     KeyName;
300 	DWORD              Value;
301 	DBGPRINT(("CMiniportWaveCMI::storeChannelConfigToRegistry()"));
302 
303 	if ((!CMIAdapter) || (!(CMIAdapter->getDeviceObject()))) {
304 		return STATUS_UNSUCCESSFUL;
305 	}
306 
307 	NTSTATUS ntStatus = PcNewRegistryKey(&DriverKey, NULL, DriverRegistryKey, KEY_ALL_ACCESS, CMIAdapter->getDeviceObject(), NULL, NULL, 0, NULL);
308 
309 	if(!NT_SUCCESS(ntStatus)) {
310 		DBGPRINT(("PcNewRegistryKey() failed"));
311 		return STATUS_UNSUCCESSFUL;
312 	}
313 
314 	RtlInitUnicodeString(&KeyName, L"Settings");
315 
316 	ntStatus = DriverKey->NewSubKey(&SettingsKey, NULL, KEY_ALL_ACCESS, &KeyName, REG_OPTION_NON_VOLATILE, NULL);
317 	if(!NT_SUCCESS(ntStatus)) {
318 		DBGPRINT(("DriverKey->NewSubKey() failed"));
319 		return STATUS_UNSUCCESSFUL;
320 	}
321 
322 	Value = requestedChannelCount;
323 	RtlInitUnicodeString(&KeyName, L"ChannelCount");
324 	ntStatus = SettingsKey->SetValueKey(&KeyName, REG_DWORD, PVOID(&Value), sizeof(DWORD));
325 	if (!NT_SUCCESS(ntStatus)) {
326 		DBGPRINT(("SetValueKey() failed"));
327 	}
328 	Value = requestedChannelMask;
329 	RtlInitUnicodeString(&KeyName, L"ChannelMask");
330 	ntStatus = SettingsKey->SetValueKey(&KeyName, REG_DWORD, PVOID(&Value), sizeof(DWORD));
331 	if (!NT_SUCCESS(ntStatus)) {
332 		DBGPRINT(("SetValueKey() failed"));
333 	}
334 
335 	SettingsKey->Release();
336 	DriverKey->Release();
337 
338 	return STATUS_SUCCESS;
339 }
340 
341 
STDMETHODIMP_(void)342 STDMETHODIMP_(void) CMiniportWaveCMI::powerUp(void)
343 {
344 	PAGED_CODE();
345 	DBGPRINT(("CMiniportWaveCMI[%p]::powerUp()", this));
346 	KSSTATE oldState[3];
347 
348 	for (int i=0;i<3;i++) {
349 		if (isStreamRunning[i]) {
350 			oldState[i] = stream[i]->state;
351 			stream[i]->SetState(KSSTATE_STOP);
352 		}
353 	}
354 
355 	if (cm->TopoMiniport) {
356 		cm->TopoMiniport->loadMixerSettingsFromMemory();
357 	}
358 
359 	for (int i=0;i<3;i++) {
360 		if (isStreamRunning[i]) {
361 			stream[i]->prepareStream();
362 			stream[i]->SetState(KSSTATE_ACQUIRE);
363 			stream[i]->SetState(oldState[i]);
364 		}
365 	}
366 }
367 
STDMETHODIMP_(void)368 STDMETHODIMP_(void) CMiniportWaveCMI::powerDown(void)
369 {
370 	PAGED_CODE();
371 	DBGPRINT(("CMiniportWaveCMI[%p]::powerDown()", this));
372 
373 	if (cm->TopoMiniport) {
374 		cm->TopoMiniport->storeMixerSettingsToMemory();
375 	}
376 
377 }
378 
379 
isFormatAllowed(UInt32 sampleRate,BOOLEAN multiChan,BOOLEAN AC3)380 NTSTATUS CMiniportWaveCMI::isFormatAllowed(UInt32 sampleRate, BOOLEAN multiChan, BOOLEAN AC3)
381 {
382 	PAGED_CODE();
383 	ASSERT(sampleRate);
384 	DBGPRINT(("CMiniportWaveCMI[%p]::isFormatAllowed(%d, %d, %d)", this, sampleRate, multiChan, AC3));
385 
386 	if (multiChan) {
387 		switch (sampleRate) {
388 			case 44100: if (cm->formatMask & FMT_441_MULTI_PCM) return STATUS_SUCCESS; break;
389 			case 48000: if (cm->formatMask & FMT_480_MULTI_PCM) return STATUS_SUCCESS; break;
390 			case 88200: if (cm->formatMask & FMT_882_MULTI_PCM) return STATUS_SUCCESS; break;
391 			case 96000: if (cm->formatMask & FMT_960_MULTI_PCM) return STATUS_SUCCESS; break;
392 		}
393 		return STATUS_INVALID_PARAMETER;
394 	}
395 	if (AC3) {
396 		switch (sampleRate) {
397 			case 44100: if (cm->formatMask & FMT_441_DOLBY) return STATUS_SUCCESS; break;
398 			case 48000: if (cm->formatMask & FMT_480_DOLBY) return STATUS_SUCCESS; break;
399 			case 88200: if (cm->formatMask & FMT_882_DOLBY) return STATUS_SUCCESS; break;
400 			case 96000: if (cm->formatMask & FMT_960_DOLBY) return STATUS_SUCCESS; break;
401 		}
402 		return STATUS_INVALID_PARAMETER;
403 	}
404 	switch (sampleRate) {
405 		case 44100: if (cm->formatMask & FMT_441_PCM) return STATUS_SUCCESS; break;
406 		case 48000: if (cm->formatMask & FMT_480_PCM) return STATUS_SUCCESS; break;
407 		case 88200: if (cm->formatMask & FMT_882_PCM) return STATUS_SUCCESS; break;
408 		case 96000: if (cm->formatMask & FMT_960_PCM) return STATUS_SUCCESS; break;
409 	}
410 	return STATUS_INVALID_PARAMETER;
411 }
412 
validateFormat(PKSDATAFORMAT format,ULONG PinID,BOOLEAN capture)413 NTSTATUS CMiniportWaveCMI::validateFormat(PKSDATAFORMAT format, ULONG PinID, BOOLEAN capture)
414 {
415 	PAGED_CODE();
416 	ASSERT(format);
417 	DBGPRINT(("CMiniportWaveCMI[%p]::validateFormat(%p, %d, %d)", this, format, PinID, capture));
418 
419 	PWAVEFORMATEX waveFormat = PWAVEFORMATEX(format + 1);
420 	DBGPRINT(("---channels: %d, resolution: %d, sample rate: %d, pin: %d, formatMask: %x", waveFormat->nChannels, waveFormat->wBitsPerSample, waveFormat->nSamplesPerSec, PinID, cm->formatMask));
421 
422 //WaveFormatEx
423 	if  ( ( format->FormatSize >= sizeof(KSDATAFORMAT_WAVEFORMATEX))
424 	  && IsEqualGUIDAligned(format->MajorFormat,KSDATAFORMAT_TYPE_AUDIO)
425 	  && IsEqualGUIDAligned(format->Specifier,KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) ) {
426 		switch (EXTRACT_WAVEFORMATEX_ID(&format->SubFormat)) {
427 			case WAVE_FORMAT_PCM:
428 				if ((PinID != PIN_WAVE_RENDER_SINK) && (PinID != PIN_WAVE_CAPTURE_SOURCE) && (PinID != ((ULONG)-1))) {
429 					if ((PinID == PIN_WAVE_AC3_RENDER_SINK) && !IoIsWdmVersionAvailable(6,0)) {
430 						return STATUS_INVALID_PARAMETER;
431 					}
432 				}
433 
434 				if ( ((waveFormat->wBitsPerSample == 16) || (waveFormat->wBitsPerSample == 32))
435 				  && ((waveFormat->nSamplesPerSec == 44100) || (waveFormat->nSamplesPerSec == 48000) || (waveFormat->nSamplesPerSec == 88200) ||  (waveFormat->nSamplesPerSec == 96000))
436 				  && (waveFormat->nChannels == 2) ) {
437 					if ((capture) && (waveFormat->nSamplesPerSec > 48000) ) {
438 						return STATUS_INVALID_PARAMETER;
439 					}
440 					return isFormatAllowed(waveFormat->nSamplesPerSec, FALSE, FALSE);
441 				}
442 				if ( (waveFormat->wBitsPerSample == 16)
443 				  && ((waveFormat->nChannels >= 4) && (waveFormat->nChannels <= cm->maxChannels))
444 				  && ((waveFormat->nSamplesPerSec == 44100) || (waveFormat->nSamplesPerSec == 48000)) ) {
445 #if OUT_CHANNEL == 1
446 					if ((PinID == PIN_WAVE_RENDER_SINK) || (PinID == ((ULONG)-1))) {
447 						return isFormatAllowed(waveFormat->nSamplesPerSec, TRUE, FALSE);
448 					}
449 #else
450 					return STATUS_INVALID_PARAMETER;
451 #endif
452 				}
453 				break;
454 			case WAVE_FORMAT_DOLBY_AC3_SPDIF:
455 				if ((PinID != PIN_WAVE_AC3_RENDER_SINK) && (PinID != ((ULONG)-1))) {
456 					return STATUS_INVALID_PARAMETER;
457 				}
458 				if ( ((waveFormat->wBitsPerSample >= MIN_BITS_PER_SAMPLE_AC3) && (waveFormat->wBitsPerSample <= MAX_BITS_PER_SAMPLE_AC3))
459 				  && ((waveFormat->nSamplesPerSec >= MIN_SAMPLE_RATE_AC3) && (waveFormat->nSamplesPerSec <= MAX_SAMPLE_RATE_AC3))
460 				  && (waveFormat->nChannels == MAX_CHANNELS_AC3) ) {
461 					return isFormatAllowed(waveFormat->nSamplesPerSec, FALSE, TRUE);
462 				}
463 				break;
464 			case WAVE_FORMAT_WMA_SPDIF:
465 				if ((PinID != PIN_WAVE_AC3_RENDER_SINK) && (PinID != ((ULONG)-1))) {
466 					return STATUS_INVALID_PARAMETER;
467 				}
468 				if ( ((waveFormat->wBitsPerSample >= MIN_BITS_PER_SAMPLE_WMA) && (waveFormat->wBitsPerSample <= MAX_BITS_PER_SAMPLE_WMA))
469 				  && ((waveFormat->nSamplesPerSec >= MIN_SAMPLE_RATE_WMA) && (waveFormat->nSamplesPerSec <= MAX_SAMPLE_RATE_WMA))
470 				  && (waveFormat->nChannels == MAX_CHANNELS_WMA) ) {
471 					return isFormatAllowed(waveFormat->nSamplesPerSec, FALSE, TRUE);
472 				}
473 				break;
474 		}
475 	}
476 
477 	return STATUS_INVALID_PARAMETER;
478 }
479 
480 // Tests a data range intersection
DataRangeIntersection(ULONG PinId,PKSDATARANGE ClientDataRange,PKSDATARANGE MyDataRange,ULONG OutputBufferLength,PVOID ResultantFormat,PULONG ResultantFormatLength)481 STDMETHODIMP CMiniportWaveCMI::DataRangeIntersection(ULONG PinId, PKSDATARANGE ClientDataRange, PKSDATARANGE MyDataRange, ULONG OutputBufferLength, PVOID ResultantFormat, PULONG ResultantFormatLength)
482 {
483 	PAGED_CODE();
484 	DBGPRINT(("CMiniportWaveCMI[%p]::DataRangeIntersection(%d, %p, %p, %d, %p, %p)", this, PinId, ClientDataRange, MyDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength));
485 
486 	if (PinId == PIN_WAVE_AC3_RENDER_SINK) {
487 		bool isAC3Pin = true;
488 		// Under Windows 2000 and XP, the client's DataRange should be AC3 only.
489 		// The AC3 pin is the SPDIF pin in Windows Vista, so 2ch stereo is going to be allowed.
490 
491 		if (!IsEqualGUIDAligned(ClientDataRange->MajorFormat, KSDATAFORMAT_TYPE_AUDIO)
492 		  && !IsEqualGUIDAligned(ClientDataRange->MajorFormat, KSDATAFORMAT_TYPE_WILDCARD)) {
493 			return STATUS_NO_MATCH;
494 		}
495 
496 
497 		if (!IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF)
498 		  && !IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WMA_SPDIF)
499 		  && !IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD)) {
500 			// check for Vista
501 			isAC3Pin = false;
502 			if (IoIsWdmVersionAvailable(0x06,0x00)) {
503 				if (!IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_PCM)
504 				  && !IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD)) {
505 					return STATUS_NO_MATCH;
506 				}
507 			} else {
508 				return STATUS_NO_MATCH;
509 			}
510 		}
511 
512 		if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
513 		 || IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WILDCARD)) {
514 			*ResultantFormatLength = sizeof(KSDATAFORMAT_WAVEFORMATEX);
515 		} else
516 		if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND)) {
517 			*ResultantFormatLength = sizeof(KSDATAFORMAT_DSOUND);
518 		} else {
519 			return STATUS_NO_MATCH;
520 		}
521 
522 		// Validate return buffer size, if the request is only for the
523 		// size of the resultant structure, return it now.
524 		if (!OutputBufferLength) {
525 			*ResultantFormatLength = sizeof(KSDATAFORMAT_WAVEFORMATEX);
526 			return STATUS_BUFFER_OVERFLOW;
527 		} else
528 		if (OutputBufferLength < sizeof(KSDATAFORMAT_WAVEFORMATEX)) {
529 			return STATUS_BUFFER_TOO_SMALL;
530 		}
531 
532 		PKSDATAFORMAT_WAVEFORMATEX  resultantFormatWFX = (PKSDATAFORMAT_WAVEFORMATEX) ResultantFormat;
533 		PWAVEFORMATEX               pWaveFormatEx;
534 
535 		// Return the best (only) available format.
536 		resultantFormatWFX->DataFormat.FormatSize = *ResultantFormatLength;
537 		resultantFormatWFX->DataFormat.Flags      = 0;
538 		resultantFormatWFX->DataFormat.SampleSize = 4; // must match nBlockAlign
539 		resultantFormatWFX->DataFormat.Reserved	  = 0;
540 
541 		resultantFormatWFX->DataFormat.MajorFormat  = KSDATAFORMAT_TYPE_AUDIO;
542 		INIT_WAVEFORMATEX_GUID(&resultantFormatWFX->DataFormat.SubFormat, WAVE_FORMAT_DOLBY_AC3_SPDIF);
543 
544 		// Extra space for the DSound specifier
545 		if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND)) {
546 
547 			PKSDATAFORMAT_DSOUND  resultantFormatDSound = (PKSDATAFORMAT_DSOUND)ResultantFormat;
548 
549 			resultantFormatDSound->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_DSOUND;
550 
551 			// DSound format capabilities are not expressed
552 			// this way in KS, so we express no capabilities.
553 			resultantFormatDSound->BufferDesc.Flags   = 0 ;
554 			resultantFormatDSound->BufferDesc.Control = 0 ;
555 
556 			pWaveFormatEx = &resultantFormatDSound->BufferDesc.WaveFormatEx;
557 		} else {
558 		// WAVEFORMATEX or WILDCARD (WAVEFORMATEX)
559 			resultantFormatWFX->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
560 
561 			pWaveFormatEx = (PWAVEFORMATEX)((PKSDATAFORMAT)resultantFormatWFX + 1);
562 		}
563 
564 		pWaveFormatEx->nChannels	   = 2;
565 		pWaveFormatEx->wBitsPerSample  = 16; // SPDIF
566 		pWaveFormatEx->cbSize          = 0;
567 		if (isAC3Pin) {
568 			if (IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WMA_SPDIF)) {
569 				pWaveFormatEx->wFormatTag      = WAVE_FORMAT_WMA_SPDIF;
570 				pWaveFormatEx->nSamplesPerSec  = min( ((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumSampleFrequency, MAX_SAMPLE_RATE_WMA);
571 			} else {
572 				pWaveFormatEx->wFormatTag      = WAVE_FORMAT_DOLBY_AC3_SPDIF;
573 				pWaveFormatEx->nSamplesPerSec  = 48000;
574 			}
575 		} else {
576 			pWaveFormatEx->wFormatTag      = WAVE_FORMAT_PCM;
577 			pWaveFormatEx->nSamplesPerSec  = min( ((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumSampleFrequency, MAX_SAMPLE_RATE);
578 		}
579 		pWaveFormatEx->nBlockAlign     = pWaveFormatEx->nChannels * pWaveFormatEx->wBitsPerSample / 8;
580 		pWaveFormatEx->nAvgBytesPerSec = pWaveFormatEx->nSamplesPerSec * pWaveFormatEx->nBlockAlign;
581 
582 		return STATUS_SUCCESS;
583 	}
584 	if ((PinId == PIN_WAVE_RENDER_SINK) || (PinId == PIN_WAVE_CAPTURE_SINK)) {
585 
586 		if (!IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_PCM) &&
587 		    !IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD)) {
588 			return STATUS_NO_MATCH;
589 		}
590 
591 		if (!IsEqualGUIDAligned(ClientDataRange->MajorFormat, KSDATAFORMAT_TYPE_AUDIO) &&
592 		    !IsEqualGUIDAligned(ClientDataRange->MajorFormat, KSDATAFORMAT_TYPE_WILDCARD)) {
593 			return STATUS_NO_MATCH;
594 		}
595 
596 		if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) ||
597 		  IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WILDCARD)) {
598 			*ResultantFormatLength = sizeof(KSDATAFORMAT_WAVEFORMATEX);
599 		} else
600 		if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND)) {
601 			*ResultantFormatLength = sizeof(KSDATAFORMAT_DSOUND);
602 		} else {
603 			return STATUS_NO_MATCH;
604 		}
605 
606 
607 		ULONG sampleRate   = 0;
608 		ULONG nMaxChannels = min(((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumChannels, requestedChannelCount);
609 
610 		// check for Vista
611 		if (IoIsWdmVersionAvailable(6,0) && (PinId == PIN_WAVE_RENDER_SINK)) {
612 			nMaxChannels = ((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumChannels;
613 		}
614 		if (nMaxChannels & 0x01) {
615 			nMaxChannels--;
616 		}
617 		if (!nMaxChannels) {
618 			return STATUS_NO_MATCH;
619 		}
620 
621 		if (isStreamRunning[PCM_OUT_STREAM]) {
622 			sampleRate = stream[PCM_OUT_STREAM]->currentSampleRate;
623 		} else
624 		if (isStreamRunning[PCM_IN_STREAM]) {
625 			sampleRate = stream[PCM_IN_STREAM]->currentSampleRate;
626 		}
627 		if (sampleRate == 0) {
628 			if ((nMaxChannels > 2) && (((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumSampleFrequency > MAX_SAMPLE_RATE_MULTI)) {
629 				sampleRate = MAX_SAMPLE_RATE_MULTI;
630 			} else
631 			if ((nMaxChannels == 2) && (((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumSampleFrequency > MAX_SAMPLE_RATE)) {
632 				sampleRate = MAX_SAMPLE_RATE;
633 			} else {
634 				sampleRate = ((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumSampleFrequency;
635 			}
636 		}
637 
638 		if ((((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumSampleFrequency < sampleRate)
639 		  || (((PKSDATARANGE_AUDIO)ClientDataRange)->MinimumSampleFrequency > sampleRate)) {
640 			return STATUS_NO_MATCH;
641 		}
642 
643 		if (PinId == PIN_WAVE_RENDER_SINK) {
644 			if (!OutputBufferLength) {
645 				*ResultantFormatLength = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX);
646 				return STATUS_BUFFER_OVERFLOW;
647 			} else
648 			if (OutputBufferLength < sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX)) {
649 				return STATUS_BUFFER_TOO_SMALL;
650 			}
651 
652 			if (((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumChannels < 2) {
653 				DBGPRINT(("[[DataRangeIntersection] mono format not supported"));
654 				return STATUS_NO_MATCH;
655 			}
656 
657 			PWAVEFORMATPCMEX WaveFormat = (PWAVEFORMATPCMEX)((PKSDATAFORMAT)ResultantFormat + 1);
658 			if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND)) {
659 				return STATUS_NOT_SUPPORTED;
660 			}
661 			*(PKSDATAFORMAT)ResultantFormat = *MyDataRange;
662 			((PKSDATAFORMAT)ResultantFormat)->FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX);
663 
664 
665 			WaveFormat->Format.wFormatTag      = WAVE_FORMAT_EXTENSIBLE;
666 			WaveFormat->SubFormat              = KSDATAFORMAT_SUBTYPE_PCM;
667 			WaveFormat->Format.nChannels       = (WORD)nMaxChannels;
668 			WaveFormat->Format.wBitsPerSample  = 16;
669 			WaveFormat->Format.nBlockAlign     = (WaveFormat->Format.wBitsPerSample >> 3) * WaveFormat->Format.nChannels;
670 			WaveFormat->Format.nAvgBytesPerSec = WaveFormat->Format.nSamplesPerSec * WaveFormat->Format.nBlockAlign;
671 			WaveFormat->Format.cbSize          = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
672 			WaveFormat->Format.nSamplesPerSec  = sampleRate;
673 			WaveFormat->Samples.wValidBitsPerSample = WaveFormat->Format.wBitsPerSample;
674 			switch (nMaxChannels) {
675 				case 8: WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_7POINT1; break;
676 				case 6: WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_5POINT1; break;
677 				case 4: WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_QUAD;    break;
678 				case 2: WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_STEREO;  break;
679 			}
680 			if (nMaxChannels == requestedChannelCount) {
681 				WaveFormat->dwChannelMask = requestedChannelMask;
682 			}
683 			((PKSDATAFORMAT)ResultantFormat)->SampleSize = WaveFormat->Format.nBlockAlign;
684 
685 			*ResultantFormatLength = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX);
686 			DBGPRINT(("[DataRangeIntersection] MultiChannel Renderer: SampleRate: %d, ClientDataRange->MaxChans: %d, Channels: %d, BitPerSample: %d, BlockAlign: %d, AvgBytesPerSec: %d, ChannelMask: %08X", WaveFormat->Format.nSamplesPerSec, ((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumChannels, WaveFormat->Format.nChannels, WaveFormat->Format.wBitsPerSample, WaveFormat->Format.nBlockAlign, WaveFormat->Format.nAvgBytesPerSec, WaveFormat->dwChannelMask));
687 		} else
688 		if (PinId == PIN_WAVE_CAPTURE_SINK) {
689 			PKSDATAFORMAT_WAVEFORMATEX  resultantFormatWFX;
690 			PWAVEFORMATEX               pWaveFormatEx;
691 
692 			if (!OutputBufferLength) {
693 				*ResultantFormatLength = sizeof(KSDATAFORMAT_WAVEFORMATEX);
694 				return STATUS_BUFFER_OVERFLOW;
695 			} else
696 			if (OutputBufferLength < sizeof(KSDATAFORMAT_WAVEFORMATEX)) {
697 				return STATUS_BUFFER_TOO_SMALL;
698 			}
699 
700 			if (nMaxChannels > 2) {
701 				nMaxChannels = 2;
702 			}
703 
704 			resultantFormatWFX = (PKSDATAFORMAT_WAVEFORMATEX) ResultantFormat;
705 			resultantFormatWFX->DataFormat.FormatSize   = *ResultantFormatLength;
706 			resultantFormatWFX->DataFormat.Flags        = 0;
707 			resultantFormatWFX->DataFormat.SampleSize   = 4;
708 			resultantFormatWFX->DataFormat.Reserved     = 0;
709 			resultantFormatWFX->DataFormat.MajorFormat  = KSDATAFORMAT_TYPE_AUDIO;
710 			INIT_WAVEFORMATEX_GUID(&resultantFormatWFX->DataFormat.SubFormat, WAVE_FORMAT_PCM);
711 
712 			if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND)) {
713 				PKSDATAFORMAT_DSOUND resultantFormatDSound;
714 				resultantFormatDSound = (PKSDATAFORMAT_DSOUND)ResultantFormat;
715 				resultantFormatDSound->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_DSOUND;
716 				resultantFormatDSound->BufferDesc.Flags   = 0 ;
717 				resultantFormatDSound->BufferDesc.Control = 0 ;
718 				pWaveFormatEx = &resultantFormatDSound->BufferDesc.WaveFormatEx;
719 			} else {
720 				resultantFormatWFX->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
721 				pWaveFormatEx = (PWAVEFORMATEX)((PKSDATAFORMAT)resultantFormatWFX + 1);
722 			}
723 			pWaveFormatEx->wFormatTag      = WAVE_FORMAT_PCM;
724 			pWaveFormatEx->nChannels       = nMaxChannels;
725 			pWaveFormatEx->nSamplesPerSec  = sampleRate;
726 			pWaveFormatEx->wBitsPerSample  = 16;
727 			pWaveFormatEx->cbSize          = 0;
728 			pWaveFormatEx->nBlockAlign     = 4;
729 			pWaveFormatEx->nAvgBytesPerSec = 192000;
730 		}
731 		return STATUS_SUCCESS;
732 	}
733 	return STATUS_NO_MATCH;
734 }
735 
736 //from IMiniportWaveCyclic::NewStream()
737 #ifdef WAVERT
NewStream(PMINIPORTWAVERTSTREAM * OutStream,PPORTWAVERTSTREAM OuterUnknown,ULONG PinID,BOOLEAN Capture,PKSDATAFORMAT DataFormat)738 STDMETHODIMP CMiniportWaveCMI::NewStream(PMINIPORTWAVERTSTREAM *OutStream, PPORTWAVERTSTREAM OuterUnknown, ULONG PinID, BOOLEAN Capture, PKSDATAFORMAT DataFormat)
739 #else
740 STDMETHODIMP CMiniportWaveCMI::NewStream(PMINIPORTWAVECYCLICSTREAM *OutStream, PUNKNOWN OuterUnknown, POOL_TYPE PoolType, ULONG PinID, BOOLEAN Capture, PKSDATAFORMAT DataFormat, PDMACHANNEL* OutDmaChannel, PSERVICEGROUP* OutServiceGroup)
741 #endif
742 {
743 	PAGED_CODE();
744 	ASSERT(OutStream);
745 	ASSERT(DataFormat);
746 #ifdef WAVERT
747 	DBGPRINT(("CMiniportWaveCMI[%p]::NewStream(%p, %p, %d, %d, %p)", this, OutStream, OuterUnknown, PinID, Capture, DataFormat));
748 #else
749 	ASSERT(OutDmaChannel);
750 	ASSERT(OutServiceGroup);
751 	DBGPRINT(("CMiniportWaveCMI[%p]::NewStream(%p, %p, %p, %d, %d, %p, %p, %p)", this, OutStream, OuterUnknown, PoolType, PinID, Capture, DataFormat, OutDmaChannel, OutServiceGroup));
752 #endif
753 
754 	NTSTATUS      ntStatus    = STATUS_SUCCESS;
755 	PWAVEFORMATEX waveFormat  = PWAVEFORMATEX(DataFormat + 1);
756 	UInt32        streamIndex = PCM_OUT_STREAM;
757 
758 	ntStatus = validateFormat(DataFormat, PinID, Capture);
759 	if (!NT_SUCCESS(ntStatus)) {
760 		DBGPRINT(("invalid stream format"));
761 		return STATUS_UNSUCCESSFUL;
762 	}
763 	if (cm->enableSPDIFInMonitor) {
764 		CMIAdapter->setUInt8Bit(REG_MIXER1, EN_SPDI2DAC);
765 	}
766 
767 	if (Capture) {
768 		streamIndex = PCM_IN_STREAM;
769 	} else
770 	if ( (WAVE_FORMAT_DOLBY_AC3_SPDIF == EXTRACT_WAVEFORMATEX_ID(&DataFormat->SubFormat)) || (WAVE_FORMAT_WMA_SPDIF == EXTRACT_WAVEFORMATEX_ID(&DataFormat->SubFormat))) {
771 		streamIndex = AC3_OUT_STREAM;
772 	}
773 
774 	// make sure the hardware is not already in use
775 	if (isStreamRunning[streamIndex]) {
776 		DBGPRINT(("Stream %d running, exiting...", streamIndex));
777    		return STATUS_UNSUCCESSFUL;
778 	}
779 	if ((streamIndex == AC3_OUT_STREAM) && isStreamRunning[PCM_OUT_STREAM]) {
780 #ifdef WAVERT
781    		stream[PCM_OUT_STREAM]->SetState(KSSTATE_STOP);
782 #else
783    		stream[PCM_OUT_STREAM]->SetState(KSSTATE_STOP_AC3);
784 #endif
785 	}
786 	if ((streamIndex == PCM_OUT_STREAM) && isStreamRunning[AC3_OUT_STREAM]) {
787    		return STATUS_UNSUCCESSFUL;
788 	}
789 
790 	DBGPRINT(("---StreamNo: %d, Bits: %d, Sample Rate: %d, Channels: %d, AC3: %d", streamIndex,
791 		waveFormat->wBitsPerSample, waveFormat->nSamplesPerSec, waveFormat->nChannels,
792 		(WAVE_FORMAT_DOLBY_AC3_SPDIF == EXTRACT_WAVEFORMATEX_ID(&DataFormat->SubFormat)) || (WAVE_FORMAT_WMA_SPDIF == EXTRACT_WAVEFORMATEX_ID(&DataFormat->SubFormat)) ));
793 
794 	// the DAC and ADC can only run at the same sample rate simultaneously
795 	if ((streamIndex == PCM_IN_STREAM) && isStreamRunning[PCM_OUT_STREAM]) {
796    		if (waveFormat->nSamplesPerSec != stream[PCM_OUT_STREAM]->currentSampleRate) {
797    			return STATUS_UNSUCCESSFUL;
798 		}
799 	}
800 	if ((streamIndex == PCM_OUT_STREAM) && isStreamRunning[PCM_IN_STREAM]) {
801    		if (waveFormat->nSamplesPerSec != stream[PCM_IN_STREAM]->currentSampleRate) {
802    			return STATUS_UNSUCCESSFUL;
803 		}
804 	}
805 
806 	// instantiate a stream
807 #ifdef WAVERT
808 	ntStatus = CreateMiniportWaveStreamCMI(&stream[streamIndex], OuterUnknown, NonPagedPool);
809 #else
810 	ntStatus = CreateMiniportWaveStreamCMI(&stream[streamIndex], OuterUnknown, PoolType);
811 #endif
812 	if (!NT_SUCCESS (ntStatus)) {
813 		DBGPRINT(("Failed to create stream"));
814 		return ntStatus;
815 	}
816 
817 	// initialize it
818 #ifdef WAVERT
819 	ntStatus = stream[streamIndex]->Init(this, streamIndex, Capture, DataFormat, OuterUnknown);
820 #else
821 	ntStatus = stream[streamIndex]->Init(this, streamIndex, Capture, DataFormat, DMAChannel[streamIndex], OutServiceGroup);
822 #endif
823 	if (!NT_SUCCESS(ntStatus)) {
824 		DBGPRINT(("Failed to init stream"));
825 		stream[streamIndex]->Release();
826 		stream[streamIndex] = NULL;
827 		*OutStream          = NULL;
828 #ifndef WAVERT
829 		*OutServiceGroup    = NULL;
830 		*OutDmaChannel      = NULL;
831 #endif
832 		return ntStatus;
833 	}
834 
835 #ifdef WAVERT
836 //this has been referenced in CreateMiniportWaveStreamCMI() already
837 	*OutStream = (PMINIPORTWAVERTSTREAM)stream[streamIndex];
838 #else
839 	*OutDmaChannel = DMAChannel[streamIndex];
840 	DMAChannel[streamIndex]->AddRef();
841 	*OutStream = (PMINIPORTWAVECYCLICSTREAM)stream[streamIndex];
842 #endif
843 
844 	return ntStatus;
845 }
846 
PropertyHandler_ChannelConfig(PPCPROPERTY_REQUEST PropertyRequest)847 NTSTATUS NTAPI PropertyHandler_ChannelConfig(PPCPROPERTY_REQUEST PropertyRequest)
848 {
849 	PAGED_CODE();
850 	ASSERT(PropertyRequest);
851 	DBGPRINT(("[PropertyHandler_ChannelConfig]"));
852 
853 #ifdef WAVERT
854 	CMiniportWaveCMI *that = (CMiniportWaveCMI *) ((PMINIPORTWAVERT)PropertyRequest->MajorTarget);
855 #else
856 	CMiniportWaveCMI *that = (CMiniportWaveCMI *) ((PMINIPORTWAVECYCLIC)PropertyRequest->MajorTarget);
857 #endif
858 
859 	if (PropertyRequest->Node == KSNODE_WAVE_DAC) {
860 
861 		if (PropertyRequest->ValueSize == 0) {
862 			PropertyRequest->ValueSize = sizeof(LONG);
863 			return STATUS_BUFFER_OVERFLOW;
864 		} else if (PropertyRequest->ValueSize < sizeof (LONG)) {
865 			PropertyRequest->ValueSize = 0;
866 			return STATUS_BUFFER_TOO_SMALL;
867 		}
868 
869 		if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) {
870 			*(PLONG)PropertyRequest->Value = that->requestedChannelMask;
871 			PropertyRequest->ValueSize = sizeof(ULONG);
872 			return STATUS_SUCCESS;
873 		} else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET) {
874 			if (*(PLONG)PropertyRequest->Value == KSAUDIO_SPEAKER_7POINT1) {
875 				that->requestedChannelMask =  *(PLONG)PropertyRequest->Value;
876 				that->requestedChannelCount = 8;
877 				return STATUS_SUCCESS;
878 			}
879 			if (*(PLONG)PropertyRequest->Value == KSAUDIO_SPEAKER_5POINT1) {
880 				that->requestedChannelMask =  *(PLONG)PropertyRequest->Value;
881 				that->requestedChannelCount = 6;
882 				return STATUS_SUCCESS;
883 			}
884 			if ((*(PLONG)PropertyRequest->Value == KSAUDIO_SPEAKER_QUAD) || (*(PLONG)PropertyRequest->Value == KSAUDIO_SPEAKER_SURROUND)) {
885 				that->requestedChannelMask =  *(PLONG)PropertyRequest->Value;
886 				that->requestedChannelCount = 4;
887 				return STATUS_SUCCESS;
888 			}
889 			if (*(PLONG)PropertyRequest->Value == KSAUDIO_SPEAKER_STEREO) {
890 				that->requestedChannelMask =  *(PLONG)PropertyRequest->Value;
891 				that->requestedChannelCount = 2;
892 				return STATUS_SUCCESS;
893 			}
894 		} else if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT) {
895 			PULONG AccessFlags = PULONG(PropertyRequest->Value);
896 			*AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET;
897 			PropertyRequest->ValueSize = sizeof(ULONG);
898 			return STATUS_SUCCESS;
899 		}
900 	}
901 	return STATUS_INVALID_PARAMETER;
902 }
903 
904 ///////////////////////////
905 
CreateMiniportWaveStreamCMI(CMiniportWaveStreamCMI ** MiniportWaveStreamCMI,PUNKNOWN pUnknownOuter,POOL_TYPE PoolType)906 NTSTATUS CreateMiniportWaveStreamCMI(CMiniportWaveStreamCMI  **MiniportWaveStreamCMI, PUNKNOWN pUnknownOuter, POOL_TYPE PoolType)
907 {
908 	PAGED_CODE();
909 	DBGPRINT(("CreateMiniportWaveStreamCMI"));
910 
911 #ifdef WAVERT
912 	*MiniportWaveStreamCMI = new (PoolType, 'gnaa') CMiniportWaveStreamCMI(NULL);
913 #else
914 	*MiniportWaveStreamCMI = new (PoolType, 'gnaa') CMiniportWaveStreamCMI(pUnknownOuter);
915 #endif
916 	if (*MiniportWaveStreamCMI) {
917 		(*MiniportWaveStreamCMI)->AddRef();
918 		return STATUS_SUCCESS;
919 	}
920 
921 	return STATUS_INSUFFICIENT_RESOURCES;
922 }
923 
prepareStream()924 NTSTATUS CMiniportWaveStreamCMI::prepareStream()
925 {
926 	PAGED_CODE();
927 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::prepareStream()", this));
928 	DBGPRINT(("---streamIndex: %d, channelNumber: %d", streamIndex, channelNumber));
929 
930 	NTSTATUS ntStatus;
931 	UInt32   val;
932 
933 	if (state == KSSTATE_RUN) {
934 		return STATUS_INVALID_DEVICE_REQUEST;
935 	}
936 
937 	if (!(Miniport->cm)) {
938 		DBGPRINT(("Miniport not set"));
939 		return STATUS_INVALID_DEVICE_REQUEST;
940 	}
941 
942 	enableSPDIF = ((currentSampleRate == 44100 || currentSampleRate == 48000 || currentSampleRate == 88200 || currentSampleRate == 96000) &&
943 		           ((currentResolution == 16) || (currentResolution == 32)) && (currentChannelCount == 2)) &&
944 		           (Miniport->cm->enableSPDIFOut);
945 
946 	if (!isCaptureStream) {
947 		ntStatus = setupSPDIFPlayback(enableSPDIF);
948 		if (!NT_SUCCESS(ntStatus)) {
949 			return ntStatus;
950 		}
951 		ntStatus = setDACChannels();
952 		if (!NT_SUCCESS(ntStatus)) {
953 			return ntStatus;
954 		}
955 	}
956 
957 	KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, false, NULL);
958 
959 	val = channelNumber ? ADC_CH1 : ADC_CH0;
960 	if (isCaptureStream) {
961 		Miniport->cm->regFUNCTRL0 |= val;  // 1->Recording
962 	} else {
963 		Miniport->cm->regFUNCTRL0 &= ~val; // 0->Playback
964 	}
965 	Miniport->CMIAdapter->writeUInt32(REG_FUNCTRL0, Miniport->cm->regFUNCTRL0);
966 
967 	//set sampling frequency
968 	val = Miniport->CMIAdapter->readUInt32(REG_FUNCTRL1);
969 	if ((currentSampleRate == 88200) || (currentSampleRate == 44100)) {
970 		if (channelNumber) {
971 			val &= ~SFC_CH1_MASK;
972 			val |= SFC_44K_CH1;
973 		} else {
974 			val &= ~SFC_CH0_MASK;
975 			val |= SFC_44K_CH0;
976 		}
977 	} else if ((currentSampleRate == 96000) || (currentSampleRate == 48000)) {
978 		if (channelNumber) {
979 			val &= ~SFC_CH1_MASK;
980 			val |= SFC_48K_CH1;
981 		} else {
982 			val &= ~SFC_CH0_MASK;
983 			val |= SFC_48K_CH0;
984 		}
985 	} else {
986 			KeReleaseMutex(&Miniport->mutex, FALSE);
987 			return STATUS_INVALID_DEVICE_REQUEST;
988 	}
989 	Miniport->CMIAdapter->writeUInt32(REG_FUNCTRL1, val);
990 
991 	//set resolution
992 	val = Miniport->CMIAdapter->readUInt32(REG_CHFORMAT);
993 	if (channelNumber) {
994 		val |= FORMAT_CH1;
995 	} else {
996 		val |= FORMAT_CH0;
997 	}
998 	Miniport->CMIAdapter->writeUInt32(REG_CHFORMAT, val);
999 
1000 	KeReleaseMutex(&Miniport->mutex, false);
1001 
1002 	return STATUS_SUCCESS;
1003 }
1004 
setDACChannels()1005 NTSTATUS CMiniportWaveStreamCMI::setDACChannels()
1006 {
1007 	PAGED_CODE();
1008 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::setDACChannels()", this));
1009 	NTSTATUS ntStatus = STATUS_SUCCESS;
1010 
1011 	if (currentChannelCount > 2) {
1012 		if (Miniport->cm->maxChannels < currentChannelCount) {
1013 			return STATUS_INVALID_DEVICE_REQUEST;
1014 		}
1015 		if ((currentResolution != 16) || (currentChannelCount < 2)) {
1016 			return STATUS_INVALID_DEVICE_REQUEST;
1017 		}
1018 #if OUT_CHANNEL == 0
1019 		return STATUS_INVALID_DEVICE_REQUEST;
1020 #endif
1021 		KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, FALSE, NULL);
1022 		Miniport->CMIAdapter->setUInt32Bit(REG_LEGACY, DWORD_MAPPING);
1023 		Miniport->CMIAdapter->setUInt32Bit(REG_MISCCTRL, XCHG_DAC);
1024 
1025 		switch (currentChannelCount) {
1026 			case 4:
1027 				Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, EN_4CH_CH1);
1028 				Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, EN_5CH_CH1);
1029 				Miniport->CMIAdapter->clearUInt32Bit(REG_LEGACY, EN_6CH_CH1);
1030 				Miniport->CMIAdapter->clearUInt32Bit(REG_MISCCTRL, EN_CENTER);
1031 				break;
1032 			case 6:
1033 				Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, EN_4CH_CH1);
1034 				Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, EN_5CH_CH1);
1035 				Miniport->CMIAdapter->setUInt32Bit(REG_LEGACY, EN_6CH_CH1);
1036 				Miniport->CMIAdapter->setUInt32Bit(REG_MISCCTRL, EN_CENTER);
1037 				break;
1038 			case 8:
1039 				if (Miniport->cm->chipVersion == 68) {
1040 					Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, EN_4CH_CH1);
1041 					Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, EN_5CH_CH1);
1042 					Miniport->CMIAdapter->setUInt32Bit(REG_LEGACY, EN_6CH_CH1);
1043 					Miniport->CMIAdapter->setUInt32Bit(REG_MISCCTRL, EN_CENTER);
1044 					Miniport->CMIAdapter->setUInt32Bit(REG_MISCCTRL2, EN_8CH_CH1);
1045 					break;
1046 				} else {
1047 					ntStatus = STATUS_INVALID_DEVICE_REQUEST;
1048 				}
1049 			default:
1050 				ntStatus = STATUS_INVALID_DEVICE_REQUEST;
1051 		}
1052 		KeReleaseMutex(&Miniport->mutex, FALSE);
1053 	} else {
1054 		if (Miniport->cm->canMultiChannel) {
1055 			KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, FALSE, NULL);
1056 			Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, EN_5CH_CH1 | EN_4CH_CH1);
1057 			Miniport->CMIAdapter->clearUInt32Bit(REG_LEGACY, EN_6CH_CH1 | DWORD_MAPPING);
1058 			Miniport->CMIAdapter->clearUInt32Bit(REG_MISCCTRL, EN_CENTER);
1059 			Miniport->CMIAdapter->clearUInt32Bit(REG_MISCCTRL, XCHG_DAC);
1060 			if (Miniport->cm->chipVersion == 68) {
1061 				Miniport->CMIAdapter->clearUInt32Bit(REG_MISCCTRL2, EN_8CH_CH1);
1062 			}
1063 			KeReleaseMutex(&Miniport->mutex, FALSE);
1064 		}
1065 	}
1066 	return ntStatus;
1067 }
1068 
setupSPDIFPlayback(bool enableSPDIF)1069 NTSTATUS CMiniportWaveStreamCMI::setupSPDIFPlayback(bool enableSPDIF)
1070 {
1071 	PAGED_CODE();
1072 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::setupSPDIFPlayback(%d)", this, enableSPDIF));
1073 
1074 	KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, false, NULL);
1075 
1076 	if (enableSPDIF) {
1077 		Miniport->CMIAdapter->setUInt32Bit(REG_LEGACY, EN_SPDIF_OUT);
1078 		Miniport->CMIAdapter->setUInt32Bit(REG_FUNCTRL1, SPDO2DAC);
1079 #if OUT_CHANNEL == 0
1080 		Miniport->CMIAdapter->setUInt32Bit(REG_FUNCTRL1, SPDF_0);
1081 #else
1082 		Miniport->CMIAdapter->setUInt32Bit(REG_FUNCTRL1, SPDF_1);
1083 #endif
1084 		setupAC3Passthru();
1085 
1086 		if ( (currentSampleRate == 48000) || (currentSampleRate == 96000) ) {
1087 			Miniport->CMIAdapter->setUInt32Bit(REG_MISCCTRL, EN_SPDIF_48);
1088 		} else {
1089 			Miniport->CMIAdapter->clearUInt32Bit(REG_MISCCTRL, EN_SPDIF_48);
1090 		}
1091 
1092 		if (currentSampleRate == 96000) {
1093 #if OUT_CHANNEL == 0
1094 			Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, SPD96_CH0);
1095 #else
1096 			Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, SPD96_CH1);
1097 #endif
1098 			Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, DBLSPDS);
1099 		} else if (currentSampleRate == 88200) {
1100 #if OUT_CHANNEL == 0
1101 			Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, SPD88_CH0);
1102 #else
1103 			Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, SPD88_CH1);
1104 #endif
1105 			Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, DBLSPDS);
1106 		} else {
1107 #if OUT_CHANNEL == 0
1108 			Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, SPD88_CH0 | SPD96_CH0);
1109 #else
1110 			Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, SPD88_CH1 | SPD96_CH1);
1111 #endif
1112 			Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, DBLSPDS);
1113 		}
1114 
1115 	} else {
1116 		Miniport->CMIAdapter->clearUInt32Bit(REG_LEGACY, EN_SPDIF_OUT);
1117 		Miniport->CMIAdapter->clearUInt32Bit(REG_FUNCTRL1, SPDO2DAC);
1118 #if OUT_CHANNEL == 0
1119 		Miniport->CMIAdapter->clearUInt32Bit(REG_FUNCTRL1, SPDF_0);
1120 #else
1121 		Miniport->CMIAdapter->clearUInt32Bit(REG_FUNCTRL1, SPDF_1);
1122 #endif
1123 #if OUT_CHANNEL == 0
1124 		Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, SPD88_CH0 | SPD96_CH0);
1125 #else
1126 		Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, SPD88_CH1 | SPD96_CH1);
1127 #endif
1128 		Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, DBLSPDS);
1129 		setupAC3Passthru();
1130 	}
1131 
1132 	KeReleaseMutex(&Miniport->mutex, false);
1133 	return STATUS_SUCCESS;
1134 }
1135 
setupAC3Passthru()1136 NTSTATUS CMiniportWaveStreamCMI::setupAC3Passthru()
1137 {
1138 	PAGED_CODE();
1139 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::setupAC3Passthru() [enableAC3Passthru: %d]", this, enableAC3Passthru));
1140 
1141 	if (enableAC3Passthru) {
1142 		Miniport->CMIAdapter->writeUInt8(REG_MIXER1, Miniport->CMIAdapter->readUInt8(REG_MIXER1) | MUTE_WAVE);
1143 
1144 		Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, EN_SPDO_AC3_1);
1145 		Miniport->CMIAdapter->setUInt32Bit(REG_MISCCTRL, EN_SPDO_AC3_2);
1146 
1147 		if (Miniport->cm->canAC3HW) {
1148 			Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, EN_SPDO_AC3_3);
1149 			Miniport->CMIAdapter->clearUInt32Bit(REG_MISCCTRL, SPD32SEL);
1150 			if (Miniport->cm->chipVersion >= 39) {
1151 				Miniport->CMIAdapter->clearUInt8Bit(REG_MIXER1, EN_SPDI2DAC);
1152 			}
1153 		} else {
1154 			Miniport->CMIAdapter->setUInt32Bit(REG_MISCCTRL, SPD32SEL);
1155 			if (Miniport->cm->chipVersion == 33) {
1156 				if (currentSampleRate >= 48000) {
1157 #if OUT_CHANNEL == 0
1158 					 Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, SPD96_CH0);
1159 #else
1160 					 Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, SPD96_CH1);
1161 #endif
1162 				} else {
1163 #if OUT_CHANNEL == 0
1164 					 Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, SPD96_CH0);
1165 #else
1166 					 Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, SPD96_CH1);
1167 #endif
1168 				}
1169 			}
1170 		}
1171 	} else {
1172 		if (Miniport->cm->enableSPDIFInMonitor) {
1173 			Miniport->CMIAdapter->setUInt8Bit(REG_MIXER1, EN_SPDI2DAC);
1174 		}
1175 
1176 		Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, EN_SPDO_AC3_1);
1177 		Miniport->CMIAdapter->clearUInt32Bit(REG_MISCCTRL, EN_SPDO_AC3_2);
1178 
1179 		if (Miniport->cm->canAC3HW) {
1180 			Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, EN_SPDO_AC3_3);
1181 			if (currentResolution > 16) {
1182 				Miniport->CMIAdapter->setUInt32Bit(REG_MISCCTRL, SPD32SEL);
1183 				Miniport->CMIAdapter->setUInt32Bit(REG_CHFORMAT, SPD24SEL);
1184 			} else {
1185 				Miniport->CMIAdapter->clearUInt32Bit(REG_MISCCTRL, SPD32SEL);
1186 				Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, SPD24SEL);
1187 			}
1188 		} else {
1189 			Miniport->CMIAdapter->clearUInt32Bit(REG_MISCCTRL, SPD32SEL);
1190 #if OUT_CHANNEL == 0
1191 			Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, SPD96_CH0);
1192 #else
1193 			Miniport->CMIAdapter->clearUInt32Bit(REG_CHFORMAT, SPD96_CH1);
1194 #endif
1195 		}
1196 	}
1197 	return STATUS_SUCCESS;
1198 }
1199 
~CMiniportWaveStreamCMI(void)1200 CMiniportWaveStreamCMI::~CMiniportWaveStreamCMI(void)
1201 {
1202 	PAGED_CODE();
1203 
1204 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::~CMiniportWaveStreamCMI [streamIndex: %d]", this, streamIndex));
1205 
1206 	if (state != KSSTATE_STOP) {
1207 		SetState(KSSTATE_STOP);
1208 	}
1209 
1210 #ifdef WAVERT
1211 	if (Port) {
1212 		Port->Release();
1213 		Port = NULL;
1214 	}
1215 #else
1216 	if (DMAChannel) {
1217 		DMAChannel->Release();
1218 		DMAChannel = NULL;
1219 	}
1220 
1221 	if (ServiceGroup) {
1222 		ServiceGroup->Release();
1223 		ServiceGroup = NULL;
1224 	}
1225 #endif
1226 
1227 	Miniport->isStreamRunning[streamIndex] = false;
1228 
1229 	if ((streamIndex == AC3_OUT_STREAM) && Miniport->isStreamRunning[PCM_OUT_STREAM]) {
1230 		KSSTATE temp = Miniport->stream[PCM_OUT_STREAM]->state;
1231 		Miniport->stream[PCM_OUT_STREAM]->state = KSSTATE_STOP;
1232 		Miniport->stream[PCM_OUT_STREAM]->prepareStream();
1233 		Miniport->stream[PCM_OUT_STREAM]->SetState(KSSTATE_ACQUIRE);
1234 		Miniport->stream[PCM_OUT_STREAM]->state = temp;
1235 		Miniport->stream[PCM_OUT_STREAM]->SetState(KSSTATE_RUN_AC3);
1236 	}
1237 
1238 	if (Miniport) {
1239 		Miniport->Release();
1240 		Miniport = NULL;
1241 	}
1242 }
1243 
NonDelegatingQueryInterface(REFIID Interface,PVOID * Object)1244 STDMETHODIMP CMiniportWaveStreamCMI::NonDelegatingQueryInterface(REFIID Interface, PVOID *Object)
1245 {
1246 	PAGED_CODE();
1247 	ASSERT(Object);
1248 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::NonDelegatingQueryInterface(%p, %p)", this, Interface, Object));
1249 
1250 	if (IsEqualGUIDAligned(Interface,IID_IUnknown)) {
1251 		*Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLICSTREAM(this)));
1252 #ifdef WAVERT
1253 	} else if (IsEqualGUIDAligned(Interface,IID_IMiniportWaveRTStream)) {
1254 		*Object = PVOID(PMINIPORTWAVERTSTREAM(this));
1255 #else
1256 	} else if (IsEqualGUIDAligned(Interface,IID_IMiniportWaveCyclicStream)) {
1257 		*Object = PVOID(PMINIPORTWAVECYCLICSTREAM(this));
1258 #endif
1259 	} else if (IsEqualGUIDAligned (Interface, IID_IDrmAudioStream)) {
1260 		*Object = (PVOID)(PDRMAUDIOSTREAM(this));
1261 	} else {
1262 		*Object = NULL;
1263 	}
1264 
1265 	if (*Object) {
1266 		PUNKNOWN(*Object)->AddRef();
1267 		return STATUS_SUCCESS;
1268 	}
1269 
1270 	return STATUS_INVALID_PARAMETER;
1271 }
1272 
1273 #ifdef WAVERT
Init(CMiniportWaveCMI * Miniport_,UInt32 streamIndex_,bool isCaptureStream_,PKSDATAFORMAT DataFormat,PPORTWAVERTSTREAM Port_)1274 NTSTATUS CMiniportWaveStreamCMI::Init(CMiniportWaveCMI* Miniport_, UInt32 streamIndex_, bool isCaptureStream_, PKSDATAFORMAT DataFormat, PPORTWAVERTSTREAM Port_)
1275 #else
1276 NTSTATUS CMiniportWaveStreamCMI::Init(CMiniportWaveCMI* Miniport_, UInt32 streamIndex_, bool isCaptureStream_, PKSDATAFORMAT DataFormat, PDMACHANNEL DMAChannel_, PSERVICEGROUP* OutServiceGroup)
1277 #endif
1278 {
1279 	PAGED_CODE();
1280 	ASSERT(Miniport_);
1281 	ASSERT(DataFormat);
1282 
1283 	NTSTATUS ntStatus;
1284 
1285 #ifdef WAVERT
1286 	ASSERT(Port_);
1287 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::Init(%p, %d, %d, %p, %p)", this, Miniport_, streamIndex_, isCaptureStream_, DataFormat, Port_));
1288 	Port = Port_;
1289 	Port->AddRef();
1290 #else
1291 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::Init(%p, %d, %d, %p, %p, %p)", this, Miniport_, streamIndex_, isCaptureStream_, DataFormat, DMAChannel_, OutServiceGroup));
1292 	DMAChannel = DMAChannel_;
1293 	DMAChannel->AddRef();
1294 #endif
1295 
1296 	Miniport = Miniport_;
1297 	Miniport->AddRef();
1298 
1299 	streamIndex     = streamIndex_;
1300 	isCaptureStream = isCaptureStream_;
1301 	state           = KSSTATE_STOP;
1302 
1303 	if ( (streamIndex == PCM_OUT_STREAM) || (streamIndex == AC3_OUT_STREAM) ) {
1304 		channelNumber = OUT_CHANNEL;
1305 	} else {
1306 		channelNumber = IN_CHANNEL;
1307 	}
1308 
1309 #ifndef WAVERT
1310 	ntStatus = PcNewServiceGroup(&ServiceGroup,NULL);
1311 	if (!NT_SUCCESS(ntStatus)) {
1312 		DBGPRINT(("PcNewServiceGroup() or NewMasterDmaChannel() failed"));
1313 		return ntStatus;
1314 	}
1315 	*OutServiceGroup = ServiceGroup;
1316 	ServiceGroup->AddRef();
1317 #endif
1318 
1319 	ntStatus = SetFormat(DataFormat);
1320 	if (!NT_SUCCESS(ntStatus)) {
1321 		DBGPRINT(("SetFormat() failed"));
1322 		return ntStatus;
1323 	}
1324 
1325 	Miniport->isStreamRunning[streamIndex] = true;
1326 
1327 	return ntStatus;
1328 }
1329 
SetFormat(PKSDATAFORMAT Format)1330 NTSTATUS CMiniportWaveStreamCMI::SetFormat(PKSDATAFORMAT Format)
1331 {
1332 	PAGED_CODE();
1333 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::SetFormat(%p)", this, Format));
1334 	PWAVEFORMATEX waveFormat = PWAVEFORMATEX(Format + 1);
1335 	NTSTATUS ntStatus = Miniport->validateFormat(Format, -1, isCaptureStream);
1336 	if (!NT_SUCCESS(ntStatus)) {
1337 		return ntStatus;
1338 	}
1339 	// the DAC and ADC can only run at the same sample rate simultaneously
1340 	if ((streamIndex == PCM_IN_STREAM) && Miniport->isStreamRunning[PCM_OUT_STREAM]) {
1341    		if (waveFormat->nSamplesPerSec != Miniport->stream[PCM_OUT_STREAM]->currentSampleRate) {
1342    			return STATUS_UNSUCCESSFUL;
1343 		}
1344 	}
1345 	if ((streamIndex == PCM_IN_STREAM) && Miniport->isStreamRunning[AC3_OUT_STREAM]) {
1346    		if (waveFormat->nSamplesPerSec != Miniport->stream[AC3_OUT_STREAM]->currentSampleRate) {
1347    			return STATUS_UNSUCCESSFUL;
1348 		}
1349 	}
1350 	if ((streamIndex == PCM_OUT_STREAM) && Miniport->isStreamRunning[PCM_IN_STREAM]) {
1351    		if (waveFormat->nSamplesPerSec != Miniport->stream[PCM_IN_STREAM]->currentSampleRate) {
1352    			return STATUS_UNSUCCESSFUL;
1353 		}
1354 	}
1355 	if ((streamIndex == PCM_OUT_STREAM) && Miniport->isStreamRunning[AC3_OUT_STREAM]) {
1356 		return STATUS_UNSUCCESSFUL;
1357 	}
1358 
1359 	KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, false, NULL);
1360 	currentSampleRate   = waveFormat->nSamplesPerSec;
1361 	currentChannelCount = waveFormat->nChannels;
1362 	currentResolution   = waveFormat->wBitsPerSample;
1363 	enableAC3Passthru   = (WAVE_FORMAT_DOLBY_AC3_SPDIF == EXTRACT_WAVEFORMATEX_ID(&Format->SubFormat)) || (WAVE_FORMAT_WMA_SPDIF == EXTRACT_WAVEFORMATEX_ID(&Format->SubFormat));
1364 	KeReleaseMutex(&Miniport->mutex, false);
1365 	ntStatus = prepareStream();
1366 
1367 	return ntStatus;
1368 }
1369 
1370 // DRM crap - we're supposed to disable every digital interface here
STDMETHODIMP_(NTSTATUS)1371 STDMETHODIMP_(NTSTATUS) CMiniportWaveStreamCMI::SetContentId(ULONG contentId, PCDRMRIGHTS drmRights)
1372 {
1373 	PAGED_CODE();
1374 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::SetContentId(%d, %p)", this, contentId, drmRights));
1375 
1376 	return STATUS_SUCCESS;
1377 }
1378 
1379 #ifdef WAVERT
STDMETHODIMP_(NTSTATUS)1380 STDMETHODIMP_(NTSTATUS) CMiniportWaveStreamCMI::AllocateAudioBuffer(ULONG size, PMDL *userModeBuffer, ULONG *bufferSize, ULONG *bufferOffset, MEMORY_CACHING_TYPE *cacheType)
1381 {
1382 	PAGED_CODE();
1383 
1384 	PHYSICAL_ADDRESS    low;
1385 	PHYSICAL_ADDRESS    high;
1386 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::AllocateAudioBuffer(0x%x, %p, %p, %p, %p)", this, size, userModeBuffer, bufferSize, bufferOffset, cacheType));
1387 
1388 	if (size <= size % (currentChannelCount * 2)) {
1389 		return STATUS_UNSUCCESSFUL;
1390 	}
1391 	size -= size % (currentChannelCount * 2);
1392 
1393 	if (size == 0) {
1394 		return STATUS_UNSUCCESSFUL;
1395 	}
1396 
1397 	low.HighPart = 0; low.LowPart = 0;
1398 	high.HighPart = 0; high.LowPart = MAXULONG;
1399 	if (size <= 4096) {
1400 		audioBufferMDL = Port->AllocatePagesForMdl(high, size);
1401     	} else {
1402 		audioBufferMDL = Port->AllocateContiguousPagesForMdl(low, high, size);
1403     	}
1404 	if (!audioBufferMDL) {
1405 		DBGPRINT(("AllocateContiguousPagesForMdl()/AllocatePagesForMdl() failed (size: 0x%x)", size));
1406 		return STATUS_INSUFFICIENT_RESOURCES;
1407 	}
1408 
1409 	dmaAddress = Port->GetPhysicalPageAddress(audioBufferMDL, 0).LowPart;
1410 	dmaMemorySize = size;
1411 
1412 	*userModeBuffer = audioBufferMDL;
1413 	*bufferSize = size;
1414 	*bufferOffset = 0;
1415 	*cacheType = MmCached;
1416 
1417 	return STATUS_SUCCESS;
1418 }
1419 
1420 
STDMETHODIMP_(VOID)1421 STDMETHODIMP_(VOID) CMiniportWaveStreamCMI::FreeAudioBuffer(PMDL Mdl, ULONG Size)
1422 {
1423 	PAGED_CODE();
1424 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::FreeAudioBuffer(%p, %x)", this, Mdl, Size));
1425 
1426 	Port->FreePagesFromMdl(Mdl);
1427 	audioBufferMDL = NULL;
1428 	dmaAddress     = 0;
1429 	dmaMemorySize  = 0;
1430 }
1431 
STDMETHODIMP_(void)1432 STDMETHODIMP_(void) CMiniportWaveStreamCMI::GetHWLatency(PKSRTAUDIO_HWLATENCY hwLatency)
1433 {
1434 	PAGED_CODE();
1435 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::GetHWLatency(%p)", this, hwLatency));
1436 	hwLatency->FifoSize     = 32;
1437 	hwLatency->ChipsetDelay = 0;
1438 	hwLatency->CodecDelay   = 4;
1439 }
1440 
STDMETHODIMP_(NTSTATUS)1441 STDMETHODIMP_(NTSTATUS) CMiniportWaveStreamCMI::GetPositionRegister(PKSRTAUDIO_HWREGISTER hwRegister)
1442 {
1443 	PAGED_CODE();
1444 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::GetPositionRegister(%p)", this, hwRegister));
1445 
1446 	return STATUS_UNSUCCESSFUL;
1447 }
1448 
STDMETHODIMP_(NTSTATUS)1449 STDMETHODIMP_(NTSTATUS) CMiniportWaveStreamCMI::GetClockRegister(PKSRTAUDIO_HWREGISTER hwRegister)
1450 {
1451 	PAGED_CODE();
1452 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::GetClockRegister(%p)", this, hwRegister));
1453 
1454 	return STATUS_UNSUCCESSFUL;
1455 }
1456 
1457 #endif // WAVERT
1458 
1459 /*
1460 ** non-paged code below
1461 */
1462 #ifdef _MSC_VER
1463 #pragma code_seg()
1464 #endif
1465 
SetState(KSSTATE NewState)1466 STDMETHODIMP CMiniportWaveStreamCMI::SetState(KSSTATE NewState)
1467 {
1468 	DBGPRINT(("CMiniportWaveStreamCMI[%p]::SetState(%d) [streamIndex: %d, channelNumber: %d]", this, NewState, streamIndex, channelNumber));
1469 
1470 	UInt32 inthld, chen, reset, pause;
1471 	UInt8  reg;
1472 
1473 	inthld = EN_CH0_INT << channelNumber;
1474 	chen   = EN_CH0     << channelNumber;
1475 	reset  = RST_CH0    << channelNumber;
1476 	pause  = PAUSE_CH0  << channelNumber;
1477 
1478 	NTSTATUS ntStatus = STATUS_SUCCESS;
1479 
1480 	if ((streamIndex == PCM_OUT_STREAM) && Miniport->isStreamRunning[AC3_OUT_STREAM]) {
1481 		return STATUS_INVALID_PARAMETER;
1482 	}
1483 
1484 	if (NewState == KSSTATE_RUN_AC3) {
1485 		NewState = state;
1486 		state = KSSTATE_STOP;
1487 	}
1488 
1489 	// STOP -> ACQUIRE -> PAUSE -> PLAY -> PAUSE -> ACQUIRE -> STOP
1490 	if (state != NewState) {
1491 		switch (NewState) {
1492 			case KSSTATE_ACQUIRE:
1493 				DBGPRINT(("---KSSTATE_ACQUIRE: previous state: %d", state));
1494 				if (state == KSSTATE_PAUSE) {
1495 					break;
1496 				}
1497 
1498 #ifdef WAVERT
1499 				if ((dmaMemorySize == 0) || (dmaAddress == 0)) {
1500 					return STATUS_UNSUCCESSFUL;
1501 				}
1502 				dmaSize = (dmaMemorySize / (2 * (currentResolution >> 3)) );
1503 				periodSize = dmaSize;
1504 				DBGPRINT(("---dmaAddress: %x, dmaMemorySize: %x, dmaSize: %x", dmaAddress, dmaMemorySize, dmaSize));
1505 #else
1506 				if (currentResolution == 32) {
1507 					dmaSize = (DMAChannel->BufferSize() / (2 * (32 >> 3)) );
1508 				} else {
1509 					dmaSize = (DMAChannel->BufferSize() / (2 * (currentResolution >> 3)) );
1510 				}
1511 #endif
1512 				DBGPRINT(("---SampleRate: %d, Resolution: %d, Channels: %d", currentSampleRate, currentResolution, currentChannelCount));
1513 
1514 				if (periodSize > dmaSize) {
1515 					periodSize = dmaSize;
1516 				}
1517 
1518 				// set address of the DMA buffer
1519 				KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, FALSE, NULL);
1520 				reg = channelNumber ? REG_CH1_FRAME1 : REG_CH0_FRAME1;
1521 #ifdef WAVERT
1522 				Miniport->CMIAdapter->writeUInt32(reg, dmaAddress);
1523 #else
1524 				Miniport->CMIAdapter->writeUInt32(reg, DMAChannel->PhysicalAddress().u.LowPart);
1525 				DBGPRINT(("---DMA Address: HighPart: 0x%08X LowPart: 0x%08X", DMAChannel->PhysicalAddress().u.HighPart, DMAChannel->PhysicalAddress().u.LowPart));
1526 #endif
1527 				// count of samples
1528 				reg = channelNumber ? REG_CH1_FRAME2 : REG_CH0_FRAME2;
1529 				Miniport->CMIAdapter->writeUInt16(reg, dmaSize-1);
1530 				Miniport->CMIAdapter->writeUInt16(reg + 2, periodSize-1);
1531 				DBGPRINT(("---DMA Size:   0x%04X, Period Size: 0x%04X, enableSPDIFIn: %d", dmaSize, periodSize, Miniport->cm->enableSPDIFIn));
1532 				if (isCaptureStream) {
1533 					if (Miniport->cm->enableSPDIFIn) {
1534 #if OUT_CHANNEL==0
1535 						Miniport->CMIAdapter->setUInt32Bit(REG_FUNCTRL1, SPDF_1);
1536 #else
1537 						Miniport->CMIAdapter->setUInt32Bit(REG_FUNCTRL1, SPDF_0);
1538 #endif
1539 					} else {
1540 #if OUT_CHANNEL==0
1541 						Miniport->CMIAdapter->clearUInt32Bit(REG_FUNCTRL1, SPDF_1);
1542 #else
1543 						Miniport->CMIAdapter->clearUInt32Bit(REG_FUNCTRL1, SPDF_0);
1544 #endif
1545 					}
1546 				}
1547 				KeReleaseMutex(&Miniport->mutex, false);
1548 				break;
1549 
1550 			case KSSTATE_PAUSE:
1551 				DBGPRINT(("---KSSTATE_PAUSE: previous state: %d", state));
1552 				if (state == KSSTATE_RUN) {
1553 					KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, false, NULL);
1554 					Miniport->cm->regFUNCTRL0 |= pause;
1555 					Miniport->CMIAdapter->writeUInt32(REG_FUNCTRL0, Miniport->cm->regFUNCTRL0);
1556 					KeReleaseMutex(&Miniport->mutex, FALSE);
1557 				}
1558 				if (state == KSSTATE_STOP) {
1559 					KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, false, NULL);
1560 					Miniport->cm->regFUNCTRL0 &= ~pause;
1561 					Miniport->CMIAdapter->writeUInt32(REG_FUNCTRL0, Miniport->cm->regFUNCTRL0);
1562 					KeReleaseMutex(&Miniport->mutex, false);
1563 				}
1564 				break;
1565 
1566 			case KSSTATE_RUN:
1567 				DBGPRINT(("---KSSTATE_RUN: previous state: %d", state));
1568 
1569 				KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, FALSE, NULL);
1570 				// set interrupt
1571 				Miniport->CMIAdapter->setUInt32Bit(REG_INTHLDCLR, inthld);
1572 				Miniport->cm->regFUNCTRL0 &= ~pause;
1573 				Miniport->cm->regFUNCTRL0 |= chen;
1574 				// and enable the channel
1575 				Miniport->CMIAdapter->writeUInt32(REG_FUNCTRL0, Miniport->cm->regFUNCTRL0);
1576 
1577 				DBGPRINT(("---FUNCTRL0:   0x%08X", Miniport->cm->regFUNCTRL0));
1578 				DBGPRINT(("---FUNCTRL1:   0x%08X", Miniport->CMIAdapter->readUInt32(REG_FUNCTRL1)));
1579 				DBGPRINT(("---CHFORMAT:   0x%08X", Miniport->CMIAdapter->readUInt32(REG_CHFORMAT)));
1580 				DBGPRINT(("---LEGACYCTRL: 0x%08X", Miniport->CMIAdapter->readUInt32(REG_LEGACY)));
1581 				DBGPRINT(("---MISCCTRL:   0x%08X", Miniport->CMIAdapter->readUInt32(REG_MISCCTRL)));
1582 				DBGPRINT(("---MIX1:       0x%02X", Miniport->CMIAdapter->readUInt8(REG_MIXER1)));
1583 				DBGPRINT(("---MIX2:       0x%02X", Miniport->CMIAdapter->readUInt8(REG_MIXER2)));
1584 				DBGPRINT(("---MIX3:       0x%02X", Miniport->CMIAdapter->readUInt8(REG_MIXER3)));
1585 
1586 				KeReleaseMutex(&Miniport->mutex, false);
1587 				break;
1588 
1589 			case KSSTATE_STOP_AC3:
1590 			case KSSTATE_STOP:
1591 				DBGPRINT(("---KSSTATE_STOP: previous state: %d", state));
1592 				KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, FALSE, NULL);
1593 				// clear interrupt
1594 				Miniport->CMIAdapter->clearUInt32Bit(REG_INTHLDCLR, inthld);
1595 				Miniport->cm->regFUNCTRL0 &= ~chen;
1596 				// reset
1597 				Miniport->CMIAdapter->writeUInt32(REG_FUNCTRL0, Miniport->cm->regFUNCTRL0 | reset);
1598 				Miniport->CMIAdapter->writeUInt32(REG_FUNCTRL0, Miniport->cm->regFUNCTRL0 & ~reset);
1599 				if (isCaptureStream && (Miniport->cm->enableSPDIFIn)) {
1600 #if OUT_CHANNEL==0
1601 					Miniport->CMIAdapter->clearUInt32Bit(REG_FUNCTRL1, SPDF_1);
1602 #else
1603 					Miniport->CMIAdapter->clearUInt32Bit(REG_FUNCTRL1, SPDF_0);
1604 #endif
1605 				}
1606 				KeReleaseMutex(&Miniport->mutex, FALSE);
1607 				break;
1608 		}
1609 		if (NewState != KSSTATE_STOP_AC3) {
1610 			state = NewState;
1611 		}
1612 	}
1613 	return ntStatus;
1614 }
1615 
1616 #ifdef WAVERT
1617 
GetPosition(PKSAUDIO_POSITION Position)1618 STDMETHODIMP CMiniportWaveStreamCMI::GetPosition(PKSAUDIO_POSITION Position)
1619 {
1620 	ASSERT(Position);
1621 
1622 	UInt32 reg;
1623 
1624 	if ((state == KSSTATE_RUN) && (dmaAddress)) {
1625 		reg = (channelNumber) ? REG_CH1_FRAME1 : REG_CH0_FRAME1;
1626 		Position->PlayOffset = Miniport->CMIAdapter->readUInt32(reg) - dmaAddress;
1627 		Position->WriteOffset = Position->PlayOffset + currentChannelCount * 2 * 8;
1628 	} else {
1629 		Position->PlayOffset = 0;
1630 		Position->WriteOffset = 0;
1631 	}
1632 
1633 	return STATUS_SUCCESS;
1634 }
1635 
1636 #else //WaveCyclic
1637 
GetPosition(PULONG Position)1638 STDMETHODIMP CMiniportWaveStreamCMI::GetPosition(PULONG Position)
1639 {
1640 	ASSERT(Position);
1641 
1642 	UInt32 reg;
1643 
1644 	if ((DMAChannel) && (state == KSSTATE_RUN)) {
1645 #if 0
1646 // this implementation messes with SPDIF-in recording
1647 		reg = (channelNumber) ? REG_CH1_FRAME2 : REG_CH0_FRAME2;
1648 		*Position = dmaSize - (Miniport->CMIAdapter->readUInt16(reg)-1);
1649 		*Position *= 2 * (currentResolution >> 3);
1650 #else
1651 		reg = (channelNumber) ? REG_CH1_FRAME1 : REG_CH0_FRAME1;
1652 		*Position = Miniport->CMIAdapter->readUInt32(reg);
1653 		if (*Position > DMAChannel->PhysicalAddress().u.LowPart) {
1654 			*Position -= DMAChannel->PhysicalAddress().u.LowPart;
1655 		} else {
1656 			*Position = 0;
1657 		}
1658 #endif
1659 	} else {
1660 		*Position = 0;
1661 	}
1662 
1663 	return STATUS_SUCCESS;
1664 }
1665 
STDMETHODIMP_(ULONG)1666 STDMETHODIMP_(ULONG) CMiniportWaveStreamCMI::SetNotificationFreq(ULONG Interval, PULONG FramingSize)
1667 {
1668 	Miniport->notificationInterval = Interval;
1669 
1670 	if (state == KSSTATE_RUN) {
1671 		return 0;
1672 	}
1673 	// periodSize [sample] = interval [ms] * sample rate [Hz] * 1e-3 [milli]
1674 	periodSize   = Interval * currentSampleRate / 1000;
1675 	// FramingSize [byte] = periodSize [sample] * #Channels * resolution [byte];
1676 	*FramingSize = periodSize * currentChannelCount * (currentResolution >> 3);
1677 
1678 	KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, FALSE, NULL);
1679 	Miniport->CMIAdapter->writeUInt16((channelNumber ? REG_CH1_FRAME2 : REG_CH0_FRAME2) + 2, periodSize-1);
1680 	KeReleaseMutex(&Miniport->mutex, FALSE);
1681 
1682 	DBGPRINT(("periodSize: %x, FramingSize: %x", periodSize, *FramingSize));
1683 	return Interval;
1684 }
1685 
NormalizePhysicalPosition(PLONGLONG PhysicalPosition)1686 STDMETHODIMP CMiniportWaveStreamCMI::NormalizePhysicalPosition(PLONGLONG PhysicalPosition)
1687 {
1688 	// time_pos [ns] = byte_pos [byte] / (1e-9 [nano] * #Channels * resolution [byte] * sample rate [Hz])
1689 	*PhysicalPosition = (*PhysicalPosition * 10000000L) / (currentChannelCount * (currentResolution >> 3) * currentSampleRate);
1690 	return STATUS_SUCCESS;
1691 }
1692 
1693 
STDMETHODIMP_(void)1694 STDMETHODIMP_(void) CMiniportWaveStreamCMI::Silence(PVOID Buffer, ULONG ByteCount)
1695 {
1696 	RtlFillMemory(Buffer, ByteCount, 0x00);
1697 }
1698 
1699 #endif //WAVERT
1700 
STDMETHODIMP_(void)1701 STDMETHODIMP_(void) CMiniportWaveCMI::ServiceWaveISR(UInt32 streamIndex)
1702 {
1703 #ifndef WAVERT
1704 	if ((streamIndex == PCM_OUT_STREAM) && isStreamRunning[AC3_OUT_STREAM]) {
1705 		streamIndex = AC3_OUT_STREAM;
1706 	}
1707 	if (Port && stream[streamIndex]->ServiceGroup) {
1708 		Port->Notify(stream[streamIndex]->ServiceGroup);
1709 	}
1710 #endif
1711 }
1712