mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-27 12:15:19 +01:00
7c0aa811ec
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
613 lines
21 KiB
C
613 lines
21 KiB
C
/*
|
|
* File: HdaCodecAudioIo.c
|
|
*
|
|
* Copyright (c) 2018 John Davis
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
#ifdef _WIN32
|
|
#pragma warning (disable: 4054)
|
|
#endif
|
|
//#include "HdaCodec.h"
|
|
#include "../AudioDxe.h"
|
|
//#include <IndustryStandard/HdaCodec.h>
|
|
#include <Protocol/AudioIo.h>
|
|
/*
|
|
// HDA I/O Stream callback.
|
|
VOID
|
|
HdaCodecHdaIoStreamCallback(
|
|
IN EFI_HDA_IO_PROTOCOL_TYPE Type,
|
|
IN VOID *Context1,
|
|
IN VOID *Context2,
|
|
IN VOID *Context3)
|
|
{
|
|
// DEBUG((DEBUG_INFO, "HdaCodecHdaIoStreamCallback(): start\n"));
|
|
|
|
// Create variables.
|
|
EFI_AUDIO_IO_PROTOCOL *AudioIo = (EFI_AUDIO_IO_PROTOCOL*)Context1;
|
|
EFI_AUDIO_IO_CALLBACK AudioIoCallback = (EFI_AUDIO_IO_CALLBACK)Context2;
|
|
|
|
// Ensure required parameters are valid.
|
|
if ((AudioIo == NULL) || (AudioIoCallback == NULL))
|
|
return;
|
|
|
|
// Invoke callback.
|
|
AudioIoCallback(AudioIo, Context3);
|
|
}
|
|
*/
|
|
/**
|
|
Gets the collection of output ports.
|
|
|
|
@param[in] This A pointer to the EFI_AUDIO_IO_PROTOCOL instance.
|
|
@param[out] OutputPorts A pointer to a buffer where the output ports will be placed.
|
|
@param[out] OutputPortsCount The number of ports in OutputPorts.
|
|
|
|
@retval EFI_SUCCESS The audio data was played successfully.
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HdaCodecAudioIoGetOutputs(
|
|
IN EFI_AUDIO_IO_PROTOCOL *This,
|
|
OUT EFI_AUDIO_IO_PROTOCOL_PORT **OutputPorts,
|
|
OUT UINTN *OutputPortsCount)
|
|
{
|
|
// DEBUG((DEBUG_INFO, "HdaCodecAudioIoGetOutputs(): start\n"));
|
|
|
|
// Create variables.
|
|
EFI_STATUS Status;
|
|
AUDIO_IO_PRIVATE_DATA *AudioIoPrivateData;
|
|
HDA_CODEC_DEV *HdaCodecDev;
|
|
EFI_AUDIO_IO_PROTOCOL_PORT *HdaOutputPorts;
|
|
UINT32 SupportedRates;
|
|
UINTN i;
|
|
|
|
// If a parameter is invalid, return error.
|
|
if ((This == NULL) || (OutputPorts == NULL) ||
|
|
(OutputPortsCount == NULL))
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
// Get private data.
|
|
AudioIoPrivateData = AUDIO_IO_PRIVATE_DATA_FROM_THIS(This);
|
|
if (!AudioIoPrivateData) {
|
|
return EFI_NOT_STARTED;
|
|
}
|
|
|
|
HdaCodecDev = AudioIoPrivateData->HdaCodecDev;
|
|
|
|
// Allocate buffer.
|
|
HdaOutputPorts = AllocateZeroPool(sizeof(EFI_AUDIO_IO_PROTOCOL_PORT) * HdaCodecDev->OutputPortsCount);
|
|
if (HdaOutputPorts == NULL)
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
// Get output ports.
|
|
for (i = 0; i < HdaCodecDev->OutputPortsCount; i++) {
|
|
// Port is an output.
|
|
HdaOutputPorts[i].Type = EfiAudioIoTypeOutput;
|
|
|
|
// Get device type.
|
|
switch (HDA_VERB_GET_CONFIGURATION_DEFAULT_DEVICE(HdaCodecDev->OutputPorts[i]->DefaultConfiguration))
|
|
{
|
|
case HDA_CONFIG_DEFAULT_DEVICE_LINE_OUT:
|
|
case HDA_CONFIG_DEFAULT_DEVICE_LINE_IN:
|
|
HdaOutputPorts[i].Device = EfiAudioIoDeviceLine;
|
|
break;
|
|
|
|
case HDA_CONFIG_DEFAULT_DEVICE_SPEAKER:
|
|
HdaOutputPorts[i].Device = EfiAudioIoDeviceSpeaker;
|
|
break;
|
|
|
|
case HDA_CONFIG_DEFAULT_DEVICE_HEADPHONE_OUT:
|
|
HdaOutputPorts[i].Device = EfiAudioIoDeviceHeadphones;
|
|
break;
|
|
|
|
case HDA_CONFIG_DEFAULT_DEVICE_SPDIF_OUT:
|
|
case HDA_CONFIG_DEFAULT_DEVICE_SPDIF_IN:
|
|
HdaOutputPorts[i].Device = EfiAudioIoDeviceSpdif;
|
|
break;
|
|
|
|
case HDA_CONFIG_DEFAULT_DEVICE_MIC_IN:
|
|
HdaOutputPorts[i].Device = EfiAudioIoDeviceMic;
|
|
break;
|
|
|
|
default:
|
|
if (HdaCodecDev->OutputPorts[i]->PinCapabilities & HDA_PARAMETER_PIN_CAPS_HDMI)
|
|
HdaOutputPorts[i].Device = EfiAudioIoDeviceHdmi;
|
|
else
|
|
HdaOutputPorts[i].Device = EfiAudioIoDeviceOther;
|
|
}
|
|
|
|
// Get location.
|
|
switch (HDA_VERB_GET_CONFIGURATION_DEFAULT_LOC(HdaCodecDev->OutputPorts[i]->DefaultConfiguration)) {
|
|
case HDA_CONFIG_DEFAULT_LOC_SPEC_NA:
|
|
HdaOutputPorts[i].Location = EfiAudioIoLocationNone;
|
|
break;
|
|
|
|
case HDA_CONFIG_DEFAULT_LOC_SPEC_REAR:
|
|
HdaOutputPorts[i].Location = EfiAudioIoLocationRear;
|
|
break;
|
|
|
|
case HDA_CONFIG_DEFAULT_LOC_SPEC_FRONT:
|
|
HdaOutputPorts[i].Location = EfiAudioIoLocationFront;
|
|
break;
|
|
|
|
case HDA_CONFIG_DEFAULT_LOC_SPEC_LEFT:
|
|
HdaOutputPorts[i].Location = EfiAudioIoLocationLeft;
|
|
break;
|
|
|
|
case HDA_CONFIG_DEFAULT_LOC_SPEC_RIGHT:
|
|
HdaOutputPorts[i].Location = EfiAudioIoLocationRight;
|
|
break;
|
|
|
|
case HDA_CONFIG_DEFAULT_LOC_SPEC_TOP:
|
|
HdaOutputPorts[i].Location = EfiAudioIoLocationTop;
|
|
break;
|
|
|
|
case HDA_CONFIG_DEFAULT_LOC_SPEC_BOTTOM:
|
|
HdaOutputPorts[i].Location = EfiAudioIoLocationBottom;
|
|
break;
|
|
|
|
default:
|
|
HdaOutputPorts[i].Location = EfiAudioIoLocationOther;
|
|
}
|
|
|
|
// Get surface.
|
|
switch (HDA_VERB_GET_CONFIGURATION_DEFAULT_SURF(HdaCodecDev->OutputPorts[i]->DefaultConfiguration)) {
|
|
case HDA_CONFIG_DEFAULT_LOC_SURF_EXTERNAL:
|
|
HdaOutputPorts[i].Surface = EfiAudioIoSurfaceExternal;
|
|
break;
|
|
|
|
case HDA_CONFIG_DEFAULT_LOC_SURF_INTERNAL:
|
|
HdaOutputPorts[i].Surface = EfiAudioIoSurfaceInternal;
|
|
break;
|
|
|
|
default:
|
|
HdaOutputPorts[i].Surface = EfiAudioIoSurfaceOther;
|
|
}
|
|
|
|
// Get supported stream formats.
|
|
Status = HdaCodecGetSupportedPcmRates(HdaCodecDev->OutputPorts[i], &SupportedRates);
|
|
if (EFI_ERROR(Status))
|
|
return Status;
|
|
|
|
// Get supported bit depths.
|
|
HdaOutputPorts[i].SupportedBits = 0;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_8BIT)
|
|
HdaOutputPorts[i].SupportedBits |= EfiAudioIoBits8;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_16BIT)
|
|
HdaOutputPorts[i].SupportedBits |= EfiAudioIoBits16;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_20BIT)
|
|
HdaOutputPorts[i].SupportedBits |= EfiAudioIoBits20;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_24BIT)
|
|
HdaOutputPorts[i].SupportedBits |= EfiAudioIoBits24;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_32BIT)
|
|
HdaOutputPorts[i].SupportedBits |= EfiAudioIoBits32;
|
|
|
|
// Get supported sample rates.
|
|
HdaOutputPorts[i].SupportedFreqs = 0;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_8KHZ)
|
|
HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq8kHz;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_11KHZ)
|
|
HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq11kHz;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_16KHZ)
|
|
HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq16kHz;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_22KHZ)
|
|
HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq22kHz;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_32KHZ)
|
|
HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq32kHz;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_44KHZ)
|
|
HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq44kHz;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_48KHZ)
|
|
HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq48kHz;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_88KHZ)
|
|
HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq88kHz;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_96KHZ)
|
|
HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq96kHz;
|
|
if (SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_192KHZ)
|
|
HdaOutputPorts[i].SupportedFreqs |= EfiAudioIoFreq192kHz;
|
|
}
|
|
|
|
// Ports gotten successfully.
|
|
*OutputPorts = HdaOutputPorts;
|
|
*OutputPortsCount = HdaCodecDev->OutputPortsCount;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Sets up the device to play audio data.
|
|
|
|
@param[in] This A pointer to the EFI_AUDIO_IO_PROTOCOL instance.
|
|
@param[in] OutputIndex The zero-based index of the desired output.
|
|
@param[in] Volume The volume (0-100) to use.
|
|
@param[in] Bits The width in bits of the source data.
|
|
@param[in] Freq The frequency of the source data.
|
|
@param[in] Channels The number of channels the source data contains.
|
|
|
|
@retval EFI_SUCCESS The audio data was played successfully.
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HdaCodecAudioIoSetupPlayback(
|
|
IN EFI_AUDIO_IO_PROTOCOL *This,
|
|
IN UINT8 OutputIndex,
|
|
IN UINT8 Volume,
|
|
IN EFI_AUDIO_IO_PROTOCOL_FREQ Freq,
|
|
IN EFI_AUDIO_IO_PROTOCOL_BITS Bits,
|
|
IN UINT8 Channels)
|
|
{
|
|
// DEBUG((DEBUG_INFO, "HdaCodecAudioIoSetupPlayback(): start\n"));
|
|
|
|
// Create variables.
|
|
EFI_STATUS Status;
|
|
AUDIO_IO_PRIVATE_DATA *AudioIoPrivateData;
|
|
HDA_CODEC_DEV *HdaCodecDev;
|
|
EFI_HDA_IO_PROTOCOL *HdaIo;
|
|
|
|
// Widgets.
|
|
HDA_WIDGET_DEV *PinWidget;
|
|
HDA_WIDGET_DEV *OutputWidget;
|
|
UINT32 SupportedRates;
|
|
UINT8 HdaStreamId;
|
|
|
|
// Stream.
|
|
UINT8 StreamBits, StreamDiv, StreamMult = 0;
|
|
BOOLEAN StreamBase44kHz = FALSE;
|
|
UINT16 StreamFmt;
|
|
|
|
// If a parameter is invalid, return error.
|
|
if ((This == NULL) || (Volume > EFI_AUDIO_IO_PROTOCOL_MAX_VOLUME))
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
// Get private data.
|
|
AudioIoPrivateData = AUDIO_IO_PRIVATE_DATA_FROM_THIS(This);
|
|
HdaCodecDev = AudioIoPrivateData->HdaCodecDev;
|
|
HdaIo = HdaCodecDev->HdaIo;
|
|
|
|
// Check that output index is within bounds and get our desired output.
|
|
if (OutputIndex >= HdaCodecDev->OutputPortsCount)
|
|
return EFI_INVALID_PARAMETER;
|
|
PinWidget = HdaCodecDev->OutputPorts[OutputIndex];
|
|
|
|
// Get the output DAC for the path.
|
|
Status = HdaCodecGetOutputDac(PinWidget, &OutputWidget);
|
|
if (EFI_ERROR(Status))
|
|
return Status;
|
|
|
|
// Get supported stream formats.
|
|
Status = HdaCodecGetSupportedPcmRates(OutputWidget, &SupportedRates);
|
|
if (EFI_ERROR(Status))
|
|
return Status;
|
|
|
|
// Determine bitness of samples, ensuring desired bitness is supported.
|
|
switch (Bits) {
|
|
// 8-bit.
|
|
case EfiAudioIoBits8:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_8BIT))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBits = HDA_CONVERTER_FORMAT_BITS_8;
|
|
break;
|
|
|
|
// 16-bit.
|
|
case EfiAudioIoBits16:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_16BIT))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBits = HDA_CONVERTER_FORMAT_BITS_16;
|
|
break;
|
|
|
|
// 20-bit.
|
|
case EfiAudioIoBits20:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_20BIT))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBits = HDA_CONVERTER_FORMAT_BITS_20;
|
|
break;
|
|
|
|
// 24-bit.
|
|
case EfiAudioIoBits24:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_24BIT))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBits = HDA_CONVERTER_FORMAT_BITS_24;
|
|
break;
|
|
|
|
// 32-bit.
|
|
case EfiAudioIoBits32:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_32BIT))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBits = HDA_CONVERTER_FORMAT_BITS_32;
|
|
break;
|
|
|
|
// Others.
|
|
default:
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Determine base, divisor, and multipler.
|
|
switch (Freq) {
|
|
// 8 kHz.
|
|
case EfiAudioIoFreq8kHz:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_8KHZ))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBase44kHz = FALSE;
|
|
StreamDiv = 6;
|
|
StreamMult = 1;
|
|
break;
|
|
|
|
// 11.025 kHz.
|
|
case EfiAudioIoFreq11kHz:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_11KHZ))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBase44kHz = TRUE;
|
|
StreamDiv = 4;
|
|
StreamMult = 1;
|
|
break;
|
|
|
|
// 16 kHz.
|
|
case EfiAudioIoFreq16kHz:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_16KHZ))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBase44kHz = FALSE;
|
|
StreamDiv = 3;
|
|
StreamMult = 1;
|
|
break;
|
|
|
|
// 22.05 kHz.
|
|
case EfiAudioIoFreq22kHz:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_22KHZ))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBase44kHz = TRUE;
|
|
StreamDiv = 2;
|
|
StreamMult = 1;
|
|
break;
|
|
|
|
// 32 kHz.
|
|
case EfiAudioIoFreq32kHz:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_32KHZ))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBase44kHz = FALSE;
|
|
StreamDiv = 3;
|
|
StreamMult = 2;
|
|
break;
|
|
|
|
// 44.1 kHz.
|
|
case EfiAudioIoFreq44kHz:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_44KHZ))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBase44kHz = TRUE;
|
|
StreamDiv = 1;
|
|
StreamMult = 1;
|
|
break;
|
|
|
|
// 48 kHz.
|
|
case EfiAudioIoFreq48kHz:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_48KHZ))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBase44kHz = FALSE;
|
|
StreamDiv = 1;
|
|
StreamMult = 1;
|
|
break;
|
|
|
|
// 88 kHz.
|
|
case EfiAudioIoFreq88kHz:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_88KHZ))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBase44kHz = TRUE;
|
|
StreamDiv = 1;
|
|
StreamMult = 2;
|
|
break;
|
|
|
|
// 96 kHz.
|
|
case EfiAudioIoFreq96kHz:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_96KHZ))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBase44kHz = FALSE;
|
|
StreamDiv = 1;
|
|
StreamMult = 2;
|
|
break;
|
|
|
|
// 192 kHz.
|
|
case EfiAudioIoFreq192kHz:
|
|
if (!(SupportedRates & HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES_192KHZ))
|
|
return EFI_UNSUPPORTED;
|
|
StreamBase44kHz = FALSE;
|
|
StreamDiv = 1;
|
|
StreamMult = 4;
|
|
break;
|
|
|
|
// Others.
|
|
default:
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Disable all widget paths.
|
|
for (UINTN w = 0; w < HdaCodecDev->OutputPortsCount; w++) {
|
|
if (w == OutputIndex)
|
|
continue;
|
|
Status = HdaCodecDisableWidgetPath(HdaCodecDev->OutputPorts[w]);
|
|
if (EFI_ERROR(Status))
|
|
return Status;
|
|
}
|
|
|
|
// Close stream first.
|
|
Status = HdaIo->CloseStream(HdaIo, EfiHdaIoTypeOutput);
|
|
if (EFI_ERROR(Status))
|
|
return Status;
|
|
|
|
// Calculate stream format and setup stream.
|
|
StreamFmt = HDA_CONVERTER_FORMAT_SET(Channels - 1, StreamBits,
|
|
StreamDiv - 1, StreamMult - 1, StreamBase44kHz);
|
|
DEBUG((DEBUG_INFO, "HdaCodecAudioIoPlay(): Stream format 0x%X\n", StreamFmt));
|
|
Status = HdaIo->SetupStream(HdaIo, EfiHdaIoTypeOutput, StreamFmt, &HdaStreamId);
|
|
if (EFI_ERROR(Status))
|
|
return Status;
|
|
|
|
// Setup widget path for desired output.
|
|
AudioIoPrivateData->SelectedOutputIndex = OutputIndex;
|
|
Status = HdaCodecEnableWidgetPath(PinWidget, Volume, HdaStreamId, StreamFmt);
|
|
if (EFI_ERROR(Status))
|
|
goto CLOSE_STREAM;
|
|
return EFI_SUCCESS;
|
|
|
|
CLOSE_STREAM:
|
|
// Close stream.
|
|
HdaIo->CloseStream(HdaIo, EfiHdaIoTypeOutput);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Begins playback on the device and waits for playback to complete.
|
|
|
|
@param[in] This A pointer to the EFI_AUDIO_IO_PROTOCOL instance.
|
|
@param[in] Data A pointer to the buffer containing the audio data to play.
|
|
@param[in] DataLength The size, in bytes, of the data buffer specified by Data.
|
|
@param[in] Position The position in the buffer to start at.
|
|
|
|
@retval EFI_SUCCESS The audio data was played successfully.
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HdaCodecAudioIoStartPlayback(
|
|
IN EFI_AUDIO_IO_PROTOCOL *This,
|
|
IN VOID *Data,
|
|
IN UINTN DataLength,
|
|
IN UINTN Position OPTIONAL)
|
|
{
|
|
// DEBUG((DEBUG_INFO, "HdaCodecAudioIoStartPlayback(): start\n"));
|
|
|
|
// Create variables.
|
|
EFI_STATUS Status;
|
|
AUDIO_IO_PRIVATE_DATA *AudioIoPrivateData;
|
|
EFI_HDA_IO_PROTOCOL *HdaIo;
|
|
BOOLEAN StreamRunning = FALSE;
|
|
|
|
// If a parameter is invalid, return error.
|
|
if ((This == NULL) || (Data == NULL) || (DataLength == 0))
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
// Get private data.
|
|
AudioIoPrivateData = AUDIO_IO_PRIVATE_DATA_FROM_THIS(This);
|
|
if (!AudioIoPrivateData || !AudioIoPrivateData->HdaCodecDev || !AudioIoPrivateData->HdaCodecDev->HdaIo) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
HdaIo = AudioIoPrivateData->HdaCodecDev->HdaIo;
|
|
|
|
// Start stream.
|
|
Status = HdaIo->StartStream(HdaIo, EfiHdaIoTypeOutput, Data, DataLength, Position,
|
|
NULL, NULL, NULL, NULL);
|
|
if (EFI_ERROR(Status))
|
|
return Status;
|
|
|
|
// Wait for stream to stop.
|
|
StreamRunning = TRUE;
|
|
while (StreamRunning) {
|
|
Status = HdaIo->GetStream(HdaIo, EfiHdaIoTypeOutput, &StreamRunning);
|
|
if (EFI_ERROR(Status)) {
|
|
HdaIo->StopStream(HdaIo, EfiHdaIoTypeOutput);
|
|
return Status;
|
|
}
|
|
|
|
// Wait 100ms.
|
|
gBS->Stall(MS_TO_MICROSECOND(100));
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Begins playback on the device asynchronously.
|
|
|
|
@param[in] This A pointer to the EFI_AUDIO_IO_PROTOCOL instance.
|
|
@param[in] Data A pointer to the buffer containing the audio data to play.
|
|
@param[in] DataLength The size, in bytes, of the data buffer specified by Data.
|
|
@param[in] Position The position in the buffer to start at.
|
|
@param[in] Callback A pointer to an optional callback to be invoked when playback is complete.
|
|
@param[in] Context A pointer to data to be passed to the callback function.
|
|
|
|
@retval EFI_SUCCESS The audio data was played successfully.
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HdaCodecAudioIoStartPlaybackAsync(
|
|
IN EFI_AUDIO_IO_PROTOCOL *This,
|
|
IN VOID *Data,
|
|
IN UINTN DataLength,
|
|
IN UINTN Position OPTIONAL,
|
|
IN EFI_AUDIO_IO_CALLBACK Callback OPTIONAL,
|
|
IN VOID *Context OPTIONAL)
|
|
{
|
|
// DEBUG((DEBUG_INFO, "HdaCodecAudioIoStartPlaybackAsync(): start\n"));
|
|
|
|
// Create variables.
|
|
EFI_STATUS Status;
|
|
AUDIO_IO_PRIVATE_DATA *AudioIoPrivateData;
|
|
EFI_HDA_IO_PROTOCOL *HdaIo;
|
|
|
|
// If a parameter is invalid, return error.
|
|
if ((This == NULL) || (Data == NULL) || (DataLength == 0))
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
// Get private data.
|
|
AudioIoPrivateData = AUDIO_IO_PRIVATE_DATA_FROM_THIS(This);
|
|
if (!AudioIoPrivateData || !AudioIoPrivateData->HdaCodecDev || !AudioIoPrivateData->HdaCodecDev->HdaIo) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
HdaIo = AudioIoPrivateData->HdaCodecDev->HdaIo;
|
|
|
|
// Start stream.
|
|
// Status = HdaIo->StartStream(HdaIo, EfiHdaIoTypeOutput, Data, DataLength, Position,
|
|
// (VOID*)HdaCodecHdaIoStreamCallback, (VOID*)This, (VOID*)Callback, Context);
|
|
Status = HdaIo->StartStream(HdaIo, EfiHdaIoTypeOutput, Data, DataLength, Position,
|
|
NULL, (VOID*)This, NULL, Context);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Stops playback on the device.
|
|
|
|
@param[in] This A pointer to the EFI_AUDIO_IO_PROTOCOL instance.
|
|
|
|
@retval EFI_SUCCESS The audio data was played successfully.
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HdaCodecAudioIoStopPlayback(
|
|
IN EFI_AUDIO_IO_PROTOCOL *This) {
|
|
DEBUG((DEBUG_INFO, "HdaCodecAudioIoStopPlayback(): start\n"));
|
|
|
|
// Create variables.
|
|
AUDIO_IO_PRIVATE_DATA *AudioIoPrivateData;
|
|
EFI_HDA_IO_PROTOCOL *HdaIo;
|
|
|
|
// If a parameter is invalid, return error.
|
|
if (This == NULL)
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
// Get private data.
|
|
AudioIoPrivateData = AUDIO_IO_PRIVATE_DATA_FROM_THIS(This);
|
|
if (!AudioIoPrivateData || !AudioIoPrivateData->HdaCodecDev || !AudioIoPrivateData->HdaCodecDev->HdaIo) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
HdaIo = AudioIoPrivateData->HdaCodecDev->HdaIo;
|
|
|
|
// Stop stream.
|
|
return HdaIo->StopStream(HdaIo, EfiHdaIoTypeOutput);
|
|
}
|