⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 minwave.cpp

📁 C-Media8738/8768声卡驱动开发源码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
	Port->AddRef();
#else
	DBGPRINT(("CMiniportWaveStreamCMI[%p]::Init(%p, %d, %d, %p, %p, %p)", this, Miniport_, streamIndex_, isCaptureStream_, DataFormat, DMAChannel_, OutServiceGroup));
	DMAChannel = DMAChannel_;
	DMAChannel->AddRef();
#endif

	Miniport = Miniport_;
	Miniport->AddRef();

	streamIndex     = streamIndex_;
	isCaptureStream = isCaptureStream_;
	state           = KSSTATE_STOP;

	if ( (streamIndex == PCM_OUT_STREAM) || (streamIndex == AC3_OUT_STREAM) ) {
		channelNumber = OUT_CHANNEL;
	} else {
		channelNumber = IN_CHANNEL;
	}

#ifndef WAVERT
	ntStatus = PcNewServiceGroup(&ServiceGroup,NULL);
	if (!NT_SUCCESS(ntStatus)) {
		DBGPRINT(("PcNewServiceGroup() or NewMasterDmaChannel() failed"));
		return ntStatus;
	}
	*OutServiceGroup = ServiceGroup;
	ServiceGroup->AddRef();
#endif

	ntStatus = SetFormat(DataFormat);
	if (!NT_SUCCESS(ntStatus)) {
		DBGPRINT(("SetFormat() failed"));
		return ntStatus;
	}

	Miniport->isStreamRunning[streamIndex] = true;

	return ntStatus;
}

NTSTATUS CMiniportWaveStreamCMI::SetFormat(PKSDATAFORMAT Format)
{
	PAGED_CODE();
	DBGPRINT(("CMiniportWaveStreamCMI[%p]::SetFormat(%p)", this, Format));
	PWAVEFORMATEX waveFormat = PWAVEFORMATEX(Format + 1);
	NTSTATUS ntStatus = Miniport->validateFormat(Format, -1, isCaptureStream);
	if (!NT_SUCCESS(ntStatus)) {
		return ntStatus;
	}
	// the DAC and ADC can only run at the same sample rate simultaneously
	if ((streamIndex == PCM_IN_STREAM) && Miniport->isStreamRunning[PCM_OUT_STREAM]) {
   		if (waveFormat->nSamplesPerSec != Miniport->stream[PCM_OUT_STREAM]->currentSampleRate) {
   			return STATUS_UNSUCCESSFUL;
		}
	}
	if ((streamIndex == PCM_IN_STREAM) && Miniport->isStreamRunning[AC3_OUT_STREAM]) {
   		if (waveFormat->nSamplesPerSec != Miniport->stream[AC3_OUT_STREAM]->currentSampleRate) {
   			return STATUS_UNSUCCESSFUL;
		}
	}
	if ((streamIndex == PCM_OUT_STREAM) && Miniport->isStreamRunning[PCM_IN_STREAM]) {
   		if (waveFormat->nSamplesPerSec != Miniport->stream[PCM_IN_STREAM]->currentSampleRate) {
   			return STATUS_UNSUCCESSFUL;
		}
	}
	if ((streamIndex == PCM_OUT_STREAM) && Miniport->isStreamRunning[AC3_OUT_STREAM]) {
		return STATUS_UNSUCCESSFUL;
	}

	KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, false, NULL);
	currentSampleRate   = waveFormat->nSamplesPerSec;
	currentChannelCount = waveFormat->nChannels;
	currentResolution   = waveFormat->wBitsPerSample;
	enableAC3Passthru   = (WAVE_FORMAT_DOLBY_AC3_SPDIF == EXTRACT_WAVEFORMATEX_ID(&Format->SubFormat));
	KeReleaseMutex(&Miniport->mutex, false);
	ntStatus = prepareStream();

	return ntStatus;
}

// DRM crap - we're supposed to disable every digital interface here
STDMETHODIMP_(NTSTATUS) CMiniportWaveStreamCMI::SetContentId(ULONG contentId, PCDRMRIGHTS drmRights)
{
	PAGED_CODE();
	DBGPRINT(("CMiniportWaveStreamCMI[%p]::SetContentId(%d, %p)", this, contentId, drmRights));

	return STATUS_SUCCESS;
}

#ifdef WAVERT

STDMETHODIMP_(NTSTATUS) CMiniportWaveStreamCMI::AllocateAudioBuffer(ULONG size, PMDL *userModeBuffer, ULONG *bufferSize, ULONG *bufferOffset, MEMORY_CACHING_TYPE *cacheType)
{
    PAGED_CODE();

    PHYSICAL_ADDRESS    low;
    PHYSICAL_ADDRESS    high;
    DBGPRINT(("CMiniportWaveStreamCMI[%p]::AllocateAudioBuffer(%x, %p, %p, %p, %p)", this, size, userModeBuffer, bufferSize, bufferOffset, cacheType));

    if (size <= size % (currentChannelCount * 2)) {
        return STATUS_UNSUCCESSFUL;
    }
    size -= size % (currentChannelCount * 2);

    if (size == 0) {
        return STATUS_UNSUCCESSFUL;
    }

    low.QuadPart = 0;
    high.HighPart = 0, high.LowPart = MAXULONG;

    audioBufferMDL = Port->AllocateContiguousPagesForMdl(low, high, size);

    if (!audioBufferMDL) {
		DBGPRINT(("AllocateContiguousPagesForMdl() failed"));
		return STATUS_UNSUCCESSFUL;
	}

	dmaAddress = Port->GetPhysicalPageAddress(audioBufferMDL, 0).LowPart;
	dmaMemorySize = size;

	*userModeBuffer = audioBufferMDL;
	*bufferSize = size;
	*bufferOffset = 0;
	*cacheType = MmCached;

	return STATUS_SUCCESS;
}


STDMETHODIMP_(VOID) CMiniportWaveStreamCMI::FreeAudioBuffer(PMDL Mdl, ULONG Size)
{
	PAGED_CODE();
    DBGPRINT(("CMiniportWaveStreamCMI[%p]::FreeAudioBuffer(%p, %x)", this, Mdl, Size));

	Port->FreePagesFromMdl(Mdl);
	audioBufferMDL = NULL;
	dmaAddress     = 0;
	dmaMemorySize  = 0;
}

STDMETHODIMP_(void) CMiniportWaveStreamCMI::GetHWLatency(PKSRTAUDIO_HWLATENCY hwLatency) {
    PAGED_CODE();
    DBGPRINT(("CMiniportWaveStreamCMI[%p]::GetHWLatency(%p)", this, hwLatency));
	hwLatency->FifoSize     = 32;
	hwLatency->ChipsetDelay = 0;
	hwLatency->CodecDelay   = 4;
}

STDMETHODIMP_(NTSTATUS) CMiniportWaveStreamCMI::GetPositionRegister(PKSRTAUDIO_HWREGISTER hwRegister)
{
    PAGED_CODE();
    DBGPRINT(("CMiniportWaveStreamCMI[%p]::GetPositionRegister(%p)", this, hwRegister));

    return STATUS_UNSUCCESSFUL;
}

STDMETHODIMP_(NTSTATUS) CMiniportWaveStreamCMI::GetClockRegister(PKSRTAUDIO_HWREGISTER hwRegister)
{
    PAGED_CODE();
    DBGPRINT(("CMiniportWaveStreamCMI[%p]::GetClockRegister(%p)", this, hwRegister));

    return STATUS_UNSUCCESSFUL;
}

#endif // WAVERT

#pragma code_seg()

STDMETHODIMP CMiniportWaveStreamCMI::SetState(KSSTATE NewState)
{
	DBGPRINT(("CMiniportWaveStreamCMI[%p]::SetState(%d)", this, NewState));

	UInt32 inthld, chen, reset, pause;
	UInt8  reg;

	inthld = EN_CH0_INT << channelNumber;
	chen   = EN_CH0     << channelNumber;
	reset  = RST_CH0    << channelNumber;
	pause  = PAUSE_CH0  << channelNumber;

	NTSTATUS ntStatus = STATUS_SUCCESS;

	if ((streamIndex == PCM_OUT_STREAM) && Miniport->isStreamRunning[AC3_OUT_STREAM]) {
		return STATUS_INVALID_PARAMETER;
	}

	if (NewState == KSSTATE_RUN_AC3) {
		NewState = state;
		state = KSSTATE_STOP;
	}

	// STOP -> ACQUIRE -> PAUSE -> PLAY -> PAUSE -> ACQUIRE -> STOP
	if (state != NewState) {
		switch (NewState) {
			case KSSTATE_ACQUIRE:
				DBGPRINT(("---KSSTATE_ACQUIRE: previous state: %d", state));
				if (state == KSSTATE_PAUSE) {
					break;
				}

#ifdef WAVERT
				if ((dmaMemorySize == 0) || (dmaAddress == 0)) {
					return STATUS_UNSUCCESSFUL;
				}
				dmaSize = (dmaMemorySize / (2 * (currentResolution >> 3)) );
				periodSize = dmaSize;
				DBGPRINT(("---dmaAddress: %x, dmaMemorySize: %x, dmaSize: %x", dmaAddress, dmaMemorySize, dmaSize));
#else
				if (currentResolution == 24) {
					dmaSize = (DMAChannel->BufferSize() / (2 * (24 >> 3)) );
				} else {
					dmaSize = (DMAChannel->BufferSize() / (2 * (currentResolution >> 3)) );
				}
#endif
				DBGPRINT(("---streamIndex: %d, channelNumber: %d", streamIndex, channelNumber));
				DBGPRINT(("---SampleRate: %d, Resolution: %d, Channels: %d", currentSampleRate, currentResolution, currentChannelCount));

				if (periodSize > dmaSize) {
					periodSize = dmaSize;
				}

				// set address of the DMA buffer
				KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, FALSE, NULL);
				reg = channelNumber ? REG_CH1_FRAME1 : REG_CH0_FRAME1;
#ifdef WAVERT
				Miniport->CMIAdapter->writeUInt32(reg, dmaAddress);
#else
				Miniport->CMIAdapter->writeUInt32(reg, DMAChannel->PhysicalAddress().u.LowPart);
#endif
				// count of samples
				reg = channelNumber ? REG_CH1_FRAME2 : REG_CH0_FRAME2;
				Miniport->CMIAdapter->writeUInt16(reg, dmaSize-1);
				Miniport->CMIAdapter->writeUInt16(reg + 2, periodSize-1);
				DBGPRINT(("---DMA Size:   0x%04X, Period Size: 0x%04X, enableSPDIFIn: %d", dmaSize, periodSize, Miniport->cm->enableSPDIFIn));
				if (isCaptureStream && (Miniport->cm->enableSPDIFIn)) {
#if OUT_CHANNEL==0
					Miniport->CMIAdapter->setUInt32Bit(REG_FUNCTRL1, SPDF_1);
#else
					Miniport->CMIAdapter->setUInt32Bit(REG_FUNCTRL1, SPDF_0);
#endif
				}
				KeReleaseMutex(&Miniport->mutex, false);
				break;

			case KSSTATE_PAUSE:
				DBGPRINT(("---KSSTATE_PAUSE: previous state: %d", state));
				if (state == KSSTATE_RUN) {
					KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, false, NULL);
					Miniport->cm->regFUNCTRL0 |= pause;
					Miniport->CMIAdapter->writeUInt32(REG_FUNCTRL0, Miniport->cm->regFUNCTRL0);
					KeReleaseMutex(&Miniport->mutex, FALSE);
				}
				if (state == KSSTATE_STOP) {
					KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, false, NULL);
					Miniport->cm->regFUNCTRL0 &= ~pause;
					Miniport->CMIAdapter->writeUInt32(REG_FUNCTRL0, Miniport->cm->regFUNCTRL0);
					KeReleaseMutex(&Miniport->mutex, false);
				}
				break;

			case KSSTATE_RUN:
				DBGPRINT(("---KSSTATE_RUN: previous state: %d", state));

				KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, FALSE, NULL);
				// set interrupt
				Miniport->CMIAdapter->setUInt32Bit(REG_INTHLDCLR, inthld);
				Miniport->cm->regFUNCTRL0 &= ~pause;
				Miniport->cm->regFUNCTRL0 |= chen;
				// and enable the channel
				Miniport->CMIAdapter->writeUInt32(REG_FUNCTRL0, Miniport->cm->regFUNCTRL0);

				DBGPRINT(("---FUNCTRL0:   0x%08X", Miniport->cm->regFUNCTRL0));
				DBGPRINT(("---FUNCTRL1:   0x%08X", Miniport->CMIAdapter->readUInt32(REG_FUNCTRL1)));
				DBGPRINT(("---CHFORMAT:   0x%08X", Miniport->CMIAdapter->readUInt32(REG_CHFORMAT)));
				DBGPRINT(("---LEGACYCTRL: 0x%08X", Miniport->CMIAdapter->readUInt32(REG_LEGACY)));
				DBGPRINT(("---MISCCTRL:   0x%08X", Miniport->CMIAdapter->readUInt32(REG_MISCCTRL)));
				DBGPRINT(("---MIX1:       0x%02X", Miniport->CMIAdapter->readUInt8(REG_MIXER1)));
				DBGPRINT(("---MIX2:       0x%02X", Miniport->CMIAdapter->readUInt8(REG_MIXER2)));
				DBGPRINT(("---MIX3:       0x%02X", Miniport->CMIAdapter->readUInt8(REG_MIXER3)));

				KeReleaseMutex(&Miniport->mutex, false);
				break;

			case KSSTATE_STOP_AC3:
			case KSSTATE_STOP:
				DBGPRINT(("---KSSTATE_STOP: previous state: %d", state));
				KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, FALSE, NULL);
				// clear interrupt
				Miniport->CMIAdapter->clearUInt32Bit(REG_INTHLDCLR, inthld);
				Miniport->cm->regFUNCTRL0 &= ~chen;
				// reset
				Miniport->CMIAdapter->writeUInt32(REG_FUNCTRL0, Miniport->cm->regFUNCTRL0 | reset);
				Miniport->CMIAdapter->writeUInt32(REG_FUNCTRL0, Miniport->cm->regFUNCTRL0 & ~reset);
				if (isCaptureStream && (Miniport->cm->enableSPDIFIn)) {
#if OUT_CHANNEL==0
					Miniport->CMIAdapter->clearUInt32Bit(REG_FUNCTRL1, SPDF_1);
#else
					Miniport->CMIAdapter->clearUInt32Bit(REG_FUNCTRL1, SPDF_0);
#endif
				}
				KeReleaseMutex(&Miniport->mutex, FALSE);
				break;
		}
		if (NewState != KSSTATE_STOP_AC3) {
			state = NewState;
		}
	}
	return ntStatus;
}

#ifdef WAVERT
STDMETHODIMP CMiniportWaveStreamCMI::GetPosition(PKSAUDIO_POSITION Position)
{
	ASSERT(Position);

	UInt32 reg;

	if ((state == KSSTATE_RUN) && (dmaAddress)) {
		reg = (channelNumber) ? REG_CH1_FRAME1 : REG_CH0_FRAME1;
		Position->PlayOffset = Miniport->CMIAdapter->readUInt32(reg) - dmaAddress;
        Position->WriteOffset = Position->PlayOffset + currentChannelCount * 2 * 8;
	} else {
        Position->PlayOffset = 0;
        Position->WriteOffset = 0;
	}

	return STATUS_SUCCESS;
}

#else //WaveCyclic
STDMETHODIMP CMiniportWaveStreamCMI::GetPosition(PULONG Position)
{
	ASSERT(Position);

	UInt32 reg;

	if ((DMAChannel) && (state == KSSTATE_RUN)) {
#if 0
// this implementation messes with SPDIF-in recording
        reg = (channelNumber) ? REG_CH1_FRAME2 : REG_CH0_FRAME2;
        *Position = dmaSize - (Miniport->CMIAdapter->readUInt16(reg)-1);
        *Position *= 2 * (currentResolution >> 3);
#else
		reg = (channelNumber) ? REG_CH1_FRAME1 : REG_CH0_FRAME1;
		*Position = Miniport->CMIAdapter->readUInt32(reg);
		if (*Position > DMAChannel->PhysicalAddress().u.LowPart) {
			*Position -= DMAChannel->PhysicalAddress().u.LowPart;
		} else {
			*Position = 0;
		}
#endif
	} else {
		*Position = 0;
	}

	return STATUS_SUCCESS;
}

STDMETHODIMP_(ULONG) CMiniportWaveStreamCMI::SetNotificationFreq(ULONG Interval, PULONG FramingSize)
{
	Miniport->notificationInterval = Interval;

	if (state == KSSTATE_RUN) {
		return 0;
	}
	periodSize   = Interval * currentSampleRate/1000;
	*FramingSize = periodSize*currentChannelCount*(currentResolution >> 3);

	KeWaitForSingleObject(&Miniport->mutex, Executive, KernelMode, FALSE, NULL);
	Miniport->CMIAdapter->writeUInt16((channelNumber ? REG_CH1_FRAME2 : REG_CH0_FRAME2) + 2, periodSize-1);
	KeReleaseMutex(&Miniport->mutex, FALSE);

	DBGPRINT(("periodSize: %x, FramingSize: %x", periodSize, *FramingSize));
	return Interval;
}

STDMETHODIMP CMiniportWaveStreamCMI::NormalizePhysicalPosition(OUT PLONGLONG PhysicalPosition)
{
	*PhysicalPosition = (_100NS_UNITS_PER_SECOND / currentChannelCount * (currentResolution >> 3) * *PhysicalPosition) / currentSampleRate;
	return STATUS_SUCCESS;
}


STDMETHODIMP_(void) CMiniportWaveStreamCMI::Silence(PVOID Buffer, ULONG ByteCount)
{
	RtlFillMemory(Buffer, ByteCount, 0x00);
}

#endif //WAVERT

STDMETHODIMP_(void) CMiniportWaveCMI::ServiceWaveISR(UInt32 streamIndex)
{
#ifndef WAVERT
	if ((streamIndex == PCM_OUT_STREAM) && isStreamRunning[AC3_OUT_STREAM]) {
		streamIndex = AC3_OUT_STREAM;
	}
	if (Port && stream[streamIndex]->ServiceGroup) {
		Port->Notify(stream[streamIndex]->ServiceGroup);
	}
#endif
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -