Skip to content

Commit

Permalink
AudioDxe: Updates
Browse files Browse the repository at this point in the history
 - DisconnectHda
 - AudioOutRange
 - Cirrus Logic (Apple) and QEMU fixes
 - Other fixes
  • Loading branch information
mikebeaton committed Dec 19, 2021
1 parent 57fc28b commit 706cb4e
Show file tree
Hide file tree
Showing 33 changed files with 997 additions and 577 deletions.
6 changes: 6 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ OpenCore Changelog
- Fixed typo in `Cpuid1Data` recommendations for Intel Rocket Lake and newer
- Updated builtin firmware versions for SMBIOS and the rest
- Updated underlying EDK II package to edk2-stable202111
- Resolved two possible crashes in QEMU in AudioDxe
- Added AudioDxe settings caching (avoids non-needed setup delays)
- Added DisconnectHda quirk to allow UEFI sound on Apple hardware (and others)
- Added autodetected Cirrus Logic GPIO enable to allow UEFI sound on Apple hardware
- Added workarounds for bugs in QEMU intel-hda driver to allow UEFI sound in QEMU
- Implemented multi-channel (e.g. bass+main speaker; speakers+headphones) UEFI sound configured with `AudioOutMask`

#### v0.7.6
- Fixed stack canary support when compiling with GCC
Expand Down
62 changes: 49 additions & 13 deletions Docs/Configuration.tex
Original file line number Diff line number Diff line change
Expand Up @@ -6481,8 +6481,12 @@ \subsection{Properties}\label{uefiprops}
\textbf{Description}: Configure audio backend support described
in the \hyperref[uefiaudioprops]{Audio Properties} section below.

Audio support provides a way for upstream protocols to interact with the
selected hardware and audio resources. All audio resources should reside
Unless documented otherwise (e.g. \texttt{ResetTrafficClass}) settings in this section
are for UEFI audio support only (e.g. OpenCore generated boot chime and audio assist) and are
unrelated to any configuration needed for OS audio support (e.g. \texttt{AppleALC}).

UEFI audio support provides a way for upstream protocols to interact with the
selected audio hardware and resources. All audio resources should reside
in \texttt{\textbackslash EFI\textbackslash OC\textbackslash Resources\textbackslash Audio}
directory. Currently the supported audio file formats are MP3 and WAVE PCM. While it is
driver-dependent which audio stream format is supported, most common audio cards
Expand Down Expand Up @@ -6889,33 +6893,65 @@ \subsection{Audio Properties}\label{uefiaudioprops}
\texttt{OCAU: 2/3 \textit{\textbf{PciRoot(0x0)/Pci(0x3,0x0)}}/VenMsg(<redacted>,00000000) (1 outputs)}\\
\texttt{OCAU: 3/3 \textit{\textbf{PciRoot(0x0)/Pci(0x1B,0x0)}}/VenMsg(<redacted>,02000000) (7 outputs)}

As an alternative, \texttt{gfxutil -f HDEF} command can be used in macOS. Specifying an empty device
path will result in the first available audio controller being used.
If using using \texttt{AudioDxe}, the required device path is also output as:

\texttt{HDA: Connecting controller \textit{\textbf{PciRoot(0x0)/Pci(0x1B,0x0)}}}

Finally, \texttt{gfxutil -f HDEF} command can be used in macOS to obtain the device path.

Specifying an empty device path will result in the first available audio controller being used, and can
be a convenient option to get UEFI audio working if only one audio controller is present.

\item
\texttt{AudioOut}\\
\texttt{AudioOutMask}\\
\textbf{Type}: \texttt{plist\ integer}\\
\textbf{Failsafe}: \texttt{0}\\
\textbf{Description}: Index of the output port of the specified codec starting from 0.
\textbf{Description}: Bit field indicating which output channels to use for UEFI sound.

This typically contains the index of the green out of the builtin analog audio controller (\texttt{HDEF}).
The number of output nodes (\texttt{N}) in the debug log (marked in bold-italic):
This should typically contain a single bit corresponding to the green out of the builtin analog audio
controller (\texttt{HDEF}).
The number of available output nodes (\texttt{N}) for each HDA codec is shown in the debug log (marked in bold-italic):

\texttt{OCAU: 1/3 PciRoot(0x0)/Pci(0x1,0x0)/Pci(0x0,0x1)/VenMsg(<redacted>,00000000) (\textit{\textbf{4 outputs}})}\\
\texttt{OCAU: 2/3 PciRoot(0x0)/Pci(0x3,0x0)/VenMsg(<redacted>,00000000) (\textit{\textbf{1 outputs}})}\\
\texttt{OCAU: 3/3 PciRoot(0x0)/Pci(0x1B,0x0)/VenMsg(<redacted>,02000000) (\textit{\textbf{7 outputs}})}

The quickest way to find the right port is to bruteforce the values from \texttt{0} to \texttt{N - 1}.
The first available output node is bit 0 (value \texttt{1}), the second node is bit 1 (value \texttt{2}), etc.

\item
When the debug version of \texttt{AudioDxe} is used, then additional information on each output channel of each codec
is logged during driver binding. Further information on the available output channels may also be found from a Linux
codec dump \texttt{cat /proc/asound/card\{n\}/codec\#\{m\}}.

Using \texttt{AudioOutMask}, it is possible to play sound to more than one channel (e.g. main speaker plus bass speaker;
headphones plus speakers). For example, if the main speaker is ouput 0 and the bass speaker
is output 2, then to play to both set \texttt{AudioOutMask} to \texttt{1 << 0 + 1 << 2} i.e. \texttt{5}. This
feature is supported when all chosen outputs support the sound file format in use; if any do not then no sound
will play and an error will be logged.

\emph{Note 1}: If all available output channels on the codec support the available sound file format, then a value
of \texttt{-1} may be used to play to all channels simultaneously.

\emph{Note 2}: Bits in \texttt{AudioOutMask} do not represent internal codec node ids as found in detailed codec
dumps, but rather the available output nodes as shown e.g. in the \texttt{OCAU} log lines above.

\item
\texttt{AudioSupport}\\
\textbf{Type}: \texttt{plist\ boolean}\\
\textbf{Failsafe}: \texttt{false}\\
\textbf{Description}: Activate audio support by connecting to a backend driver.

Enabling this setting routes audio playback from builtin protocols to a dedicated
audio port (\texttt{AudioOut}) of the specified codec (\texttt{AudioCodec}) located
on the audio controller (\texttt{AudioDevice}).
Enabling this setting routes audio playback from builtin protocols to specified
(\texttt{AudioOutMask}) dedicated audio ports of the specified codec (\texttt{AudioCodec}),
located on the specified audio controller (\texttt{AudioDevice}).

\item
\texttt{DisconnectHda}\\
\textbf{Type}: \texttt{plist\ boolean}\\
\textbf{Failsafe}: \texttt{false}\\
\textbf{Description}: Disconnect HDA controller before loading drivers.

May be required on some systems (e.g. Apple hardware, VMware Fusion guest) to allow
a UEFI sound driver (such as \texttt{AudioDxe}) to take control of the audio hardware.

\item
\texttt{MinimumVolume}\\
Expand Down
6 changes: 4 additions & 2 deletions Docs/Sample.plist
Original file line number Diff line number Diff line change
Expand Up @@ -1285,10 +1285,12 @@
<integer>0</integer>
<key>AudioDevice</key>
<string>PciRoot(0x0)/Pci(0x1b,0x0)</string>
<key>AudioOut</key>
<integer>0</integer>
<key>AudioOutMask</key>
<integer>1</integer>
<key>AudioSupport</key>
<false/>
<key>DisconnectHda</key>
<false/>
<key>MinimumVolume</key>
<integer>20</integer>
<key>PlayChime</key>
Expand Down
6 changes: 4 additions & 2 deletions Docs/SampleCustom.plist
Original file line number Diff line number Diff line change
Expand Up @@ -1623,10 +1623,12 @@
<integer>0</integer>
<key>AudioDevice</key>
<string>PciRoot(0x0)/Pci(0x1b,0x0)</string>
<key>AudioOut</key>
<integer>0</integer>
<key>AudioOutMask</key>
<integer>1</integer>
<key>AudioSupport</key>
<false/>
<key>DisconnectHda</key>
<false/>
<key>MinimumVolume</key>
<integer>20</integer>
<key>PlayChime</key>
Expand Down
6 changes: 4 additions & 2 deletions Include/Acidanthera/Library/OcAudioLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@
/**
Install audio support protocols.
@param[in] Reinstall Overwrite installed protocols.
@param[in] Reinstall Overwrite installed protocols.
@param[in] DisconnectHda Attempt to disconnect HDA controller first.
@retval installed protocol.
@retval NULL when conflicting audio implementation is present.
@retval NULL when installation failed.
**/
OC_AUDIO_PROTOCOL *
OcAudioInstallProtocols (
IN BOOLEAN Reinstall
IN BOOLEAN Reinstall,
IN BOOLEAN DisconnectHda
);

/**
Expand Down
5 changes: 3 additions & 2 deletions Include/Acidanthera/Library/OcConfigurationLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -618,9 +618,10 @@ typedef enum {
_(UINT16 , VolumeAmplifier , , 0 , ()) \
_(BOOLEAN , AudioSupport , , FALSE , ()) \
_(UINT8 , AudioCodec , , 0 , ()) \
_(UINT8 , AudioOut , , 0 , ()) \
_(UINT64 , AudioOutMask , , 0 , ()) \
_(UINT8 , MinimumVolume , , 0 , ()) \
_(BOOLEAN , ResetTrafficClass , , FALSE , ())
_(BOOLEAN , ResetTrafficClass , , FALSE , ()) \
_(BOOLEAN , DisconnectHda , , FALSE , ())
OC_DECLARE (OC_UEFI_AUDIO)

///
Expand Down
8 changes: 8 additions & 0 deletions Include/Acidanthera/Library/OcDriverConnectionLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ OcDisconnectGraphicsDrivers (
VOID
);

/**
Disconnects all HDA controllers attached to PCI I/O protcols.
**/
VOID
OcDisconnectHdaControllers (
VOID
);

/**
Disconnect effectively all drivers attached at handle.
Expand Down
11 changes: 11 additions & 0 deletions Include/Acidanthera/Library/OcHdaDevicesLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@
#define GET_CODEC_DEVICE_ID(a) (a & 0xFFFFU)
#define GET_CODEC_GENERIC_ID(a) (a | 0xFFFFU)

//
// Structure used for HDA PCI class code parsing.
//
#pragma pack(1)
typedef struct {
UINT8 ProgInterface;
UINT8 SubClass;
UINT8 Class;
} HDA_PCI_CLASSREG;
#pragma pack()

/**
Get controller name.
Expand Down
11 changes: 9 additions & 2 deletions Include/Acidanthera/Library/OcMiscLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,16 @@
#define OC_CHAR_BIT 8

/**
Convert seconds to microseconds for use in e.g. gBS->Stall.
Conversions to microseconds for use in e.g. gBS->Stall.
**/
#define SECONDS_TO_MICROSECONDS(x) ((x)*1000000)
#define SECONDS_TO_MICROSECONDS(x) ((x) * 1000000)
#define MS_TO_MICROSECONDS(x) ((x) * 1000)

/**
Conversions to nanoseconds for use in e.g. PciIo->PollMem.
**/
#define SECONDS_TO_NANOSECONDS(x) ((x) * 1000000000)
#define MS_TO_NANOSECONDS(x) ((x) * 1000000)

BOOLEAN
FindPattern (
Expand Down
19 changes: 13 additions & 6 deletions Include/Acidanthera/Protocol/AudioIo.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@

/**
Audio I/O protocol GUID.
Protocol now versioned, so GUID updated from previous when non-versioned.
**/
#define EFI_AUDIO_IO_PROTOCOL_GUID \
{ 0xF05B559C, 0x1971, 0x4AF5, \
{ 0xB2, 0xAE, 0xD6, 0x08, 0x08, 0xF7, 0x4F, 0x70 } }
{ 0x22266891, 0x2032, 0x4BAE, \
{ 0xB7, 0xB5, 0x43, 0x74, 0xE7, 0x32, 0x09, 0x49 } }

typedef struct EFI_AUDIO_IO_PROTOCOL_ EFI_AUDIO_IO_PROTOCOL;

#define EFI_AUDIO_IO_PROTOCOL_REVISION 1

/**
Port type.
**/
Expand Down Expand Up @@ -158,14 +161,16 @@ EFI_STATUS
);

/**
Sets up the device to play audio data.
Sets up the device to play audio data. Basic caching is implemented: no actions are taken
the second and subsequent times that set up is called again with exactly the same paremeters.
@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] OutputIndexMask A mask indicating the desired outputs.
@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.
@param[in] PlaybackDelay The required delay before playback after a change in setup.
@retval EFI_SUCCESS The audio data was played successfully.
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
Expand All @@ -174,11 +179,12 @@ typedef
EFI_STATUS
(EFIAPI *EFI_AUDIO_IO_SETUP_PLAYBACK) (
IN EFI_AUDIO_IO_PROTOCOL *This,
IN UINT8 OutputIndex,
IN UINT64 OutputIndexMask,
IN UINT8 Volume,
IN EFI_AUDIO_IO_PROTOCOL_FREQ Freq,
IN EFI_AUDIO_IO_PROTOCOL_BITS Bits,
IN UINT8 Channels
IN UINT8 Channels,
IN UINTN PlaybackDelay
);

/**
Expand Down Expand Up @@ -245,6 +251,7 @@ EFI_STATUS
Protocol struct.
**/
struct EFI_AUDIO_IO_PROTOCOL_ {
UINTN Revision;
EFI_AUDIO_IO_GET_OUTPUTS GetOutputs;
EFI_AUDIO_IO_SETUP_PLAYBACK SetupPlayback;
EFI_AUDIO_IO_START_PLAYBACK StartPlayback;
Expand Down
18 changes: 9 additions & 9 deletions Include/Acidanthera/Protocol/OcAudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include <Protocol/AppleVoiceOver.h>
#include <Protocol/DevicePath.h>

#define OC_AUDIO_PROTOCOL_REVISION 0x020000
#define OC_AUDIO_PROTOCOL_REVISION 0x030000

//
// OC_AUDIO_PROTOCOL_GUID
Expand Down Expand Up @@ -116,11 +116,11 @@ STATIC_ASSERT (OcVoiceOverAudioFileIndexMax - OcVoiceOverAudioFileIndexBase == 9
/**
Connect to Audio I/O.
@param[in,out] This Audio protocol instance.
@param[in] DevicePath Controller device path, optional.
@param[in] CodecAddress Codec address, optional.
@param[in] OutputIndex Output index, optional.
@param[in] Volume Raw volume level from 0 to 100.
@param[in,out] This Audio protocol instance.
@param[in] DevicePath Controller device path, optional.
@param[in] CodecAddress Codec address, optional.
@param[in] OutputIndexMask Output index mask.
@param[in] Volume Raw volume level from 0 to 100.
@retval EFI_SUCESS on success.
@retval EFI_NOT_FOUND when missing.
Expand All @@ -130,9 +130,9 @@ typedef
EFI_STATUS
(EFIAPI* OC_AUDIO_CONNECT) (
IN OUT OC_AUDIO_PROTOCOL *This,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,
IN UINT8 CodecAddress OPTIONAL,
IN UINT8 OutputIndex OPTIONAL,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,
IN UINT8 CodecAddress OPTIONAL,
IN UINT64 OutputIndexMask,
IN UINT8 Volume
);

Expand Down
2 changes: 1 addition & 1 deletion Include/Apple/Protocol/AppleDeviceControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
{ 0x8ECE08D8, 0xA6D4, 0x430B, \
{ 0xA7, 0xB0, 0x2D, 0xF3, 0x18, 0xE7, 0x88, 0x4A } }

#define APPLE_DEVOCE_CONTROL_PROTOCOL_VERSION 1
#define APPLE_DEVICE_CONTROL_PROTOCOL_VERSION 1

typedef
EFI_STATUS
Expand Down
2 changes: 1 addition & 1 deletion Legacy/BootPlatform/CpuDxe/CpuDxe.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ Routine Description:
EFI_SUCCESS - If CPU INIT occurred. This value should never be
seen.
EFI_DEVICE_ERROR - If CPU INIT failed.
EFI_NOT_SUPPORTED - Requested type of CPU INIT not supported.
EFI_UNSUPPORTED - Requested type of CPU INIT not supported.
--*/
{
Expand Down
Loading

0 comments on commit 706cb4e

Please sign in to comment.