On Apr 14, 2021, at 9:01 PM, Ethin Probst <harlydavidsen@gmail.com> wrote:

Hi Mike and Andrew,

Thanks for your responses. I'm looking at the VirtIO block device now
but will certainly have a look at the others as well. We'll also need
to define a completely new protocol for audio, as well, as no existing
protocol will fit the bill. The generic protocol proposed by Andrew
might work, though I was thinking of a couple modifications: primarily
that the audio interface will most likely be asynchronous in nature.
Every audio library I've looked at out there that's open-source is
fully asynchronous, as are operating-system level APIs. For example,
the Microsoft Windows WASAPI audio API requires the application that
uses the audio engine to poll a particular variable that's updated as
the audio stream progresses, as demonstrated here
(https://docs.microsoft.com/en-us/windows/win32/coreaudio/rendering-a-stream).
Obviously, I'm not going to make the code as complicated as the code
shown in the aforementioned example, since this is UEFI and not an
operating system, and making it too complicated would make it
difficult to use and understand, something that I'd like to avoid.
Therefore, for protocol design, would this be satisfactory? Not all of
it needs to be finished for GSoC; I can implement stubs for those that
I don't have time to implement, but I'd like to discuss the protocol
before I start working on a driver for it. I have a (incomplete)
outline of a (hopefully) good protocol at
https://gist.github.com/ethindp/56066e0561b901c1e276e82ff469436d. I'd
appreciate your thoughts on it.


I’d drop the Audio Input part of it. I don’t see a lot of use recording audio when you boot the system, and it is going to be a mess dealing with built in microphones etc. vs. input jacks etc. If we wanted to do input we could define a 2nd protocol that lives on the same handle for that. 

The EFI APIs don’t generally have enumeration members so I’d drop that part too. The driver is going to get started on a PCI device and that is how the device is going to be selection. So we should have a VirtIO Audio driver, a USB Audio driver, and an HDA Audio driver, not one driver that does everything. If there are common operations then 

I really think we need the volume and mute members. I did a prototype for the emulator a few years back and it looked like [1] as a simple abstract for HDA Audo to the system. I assume we could make this generic. 

The firmware really just wants to play the sound for the canned resource. The calling code is not some GUI app the user can configure. So I’m not sure of the value of having to pass in sampleRate, sampleCout, and sampleFormat. I think my proposal basically assumed PCM 16 via a WAVE file or some such. So basically the calling code just has to grab a source and pass it to the Audio protocol. That is how our GUIs work the artwork is in some encoding we can decode and that gets converted to something we can draw to the raw frame buffer. 


 [1] My prototype from a while while back. 

/** @file
  Abstraction for audio modeled on the High Definition Audio Specification. 

  This API is targeted at "Code First" with the UEFI Forum. Thus the plan is 
  to potential make this a standard in the future and definition will then move
  to the MdePkg, and EFI_GUID will likely change. 

  Copyright (c) 2018-2019 Rafael Machado <rafaelrodrigues.machado@gmail.com>
  Copyright (c) 2019, Apple Inc. All rights reserved.<BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#ifndef __HDA_AUDIO_H__
#define __HDA_AUDIO_H__

///
/// Global ID for the HDA Audio Protocol
///

// 61EE0891-E13E-11E9-A1C7-823F7D860801
#define CODE_FIRST_HDA_AUDIO_PROTOCOL_GUID \
  { \
    0x61EE0891, 0xE13E, 0x11E9, { 0xA1, 0xC7, 0x82, 0x3F, 0x7D, 0x86, 0x08, 0x01 } \
  }

typedef struct _CODE_FIRST_HDA_AUDIO_PROTOCOL  CODE_FIRST_HDA_AUDIO_PROTOCOL;


typedef INT32   HDA_GAIN;


/**
  The struct of Audio Token.
**/
typedef struct {

  ///
  /// Event will be signaled when the read audo has been played.
  /// If only synchronous playback is supported the Event must still get signaled. 
  ///
  EFI_EVENT               Event;

  ///
  /// Defines whether or not the signaled event encountered an error.
  ///
  EFI_STATUS              TransactionStatus;
} CODE_FIRST_HDA_AUDIO_TOKEN;



/**
  Play synchronous or asynchronous audio. If Token is passed in the audio is played
  asynchronously, if Token is NULL then this call blocks until the Audio is complete. 

  @param[in]      This         A pointer to the CODE_FIRST_HDA_AUDIO_PROTOCOL instance.
  @param[in, out] Token        A pointer to the token associated with the transaction.
                               If NULL this functions blocks until audio play back is complete.
  @param[in]      Buffer       PCM encoded buffer of the audio to play. 
  @param[in ]     BufferSize   The size of Buffer in bytes.

  @retval EFI_SUCCESS           The audio started playing. 
  @retval EFI_UNSUPPORTED       Buffer is not a supported format.
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.

**/
typedef
EFI_STATUS
(EFIAPI *CODE_FIRST_HDA_AUDIO_PROTOCOL_PLAY_STREAM)(
  IN     CODE_FIRST_HDA_AUDIO_PROTOCOL   *This,
  IN OUT CODE_FIRST_HDA_AUDIO_TOKEN      *Token,     OPTIONAL
  IN     UINT8                           *Buffer,
  IN     UINT64                          BufferSize
  );


/**
  Stop playing asynchronous audio. 

  @param[in]      This         A pointer to the CODE_FIRST_HDA_AUDIO_PROTOCOL instance.
  @param[in, out] Token        A pointer to the token associated with the transaction.

  @retval EFI_SUCCESS           Audio stopped playing. 
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.

**/
typedef
EFI_STATUS
(EFIAPI *CODE_FIRST_HDA_AUDIO_PROTOCOL_STOP_STREAM)(
  IN     CODE_FIRST_HDA_AUDIO_PROTOCOL   *This,
  IN     CODE_FIRST_HDA_AUDIO_TOKEN      *Token
  );


/**
  Return the current volume for audio played by this protocol. 

  @param[in]      This         A pointer to the CODE_FIRST_HDA_AUDIO_PROTOCOL instance.
  @param[out]     Gain         A pointer to the value returned between 0 and 100. 

  @retval EFI_SUCCESS           Gain was returned. 
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.

**/
typedef
EFI_STATUS
(EFIAPI *CODE_FIRST_HDA_AUDIO_PROTOCOL_GET_VOLUME)(
  IN     CODE_FIRST_HDA_AUDIO_PROTOCOL  *This,
  IN OUT HDA_GAIN                       *Gain
  );


/**
  Set the current volume for audio played by this protocol.
  
  The result of calling this function while audio is playing asynchronously is undefined. 

  @param[in]      This         A pointer to the CODE_FIRST_HDA_AUDIO_PROTOCOL instance.
  @param[in]      Gain         A value between 0 and 100 to set the volume. 

  @retval EFI_SUCCESS           Gain was updated. 
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.

**/
typedef
EFI_STATUS
(EFIAPI *CODE_FIRST_HDA_AUDIO_PROTOCOL_SET_VOLUME)(
  IN     CODE_FIRST_HDA_AUDIO_PROTOCOL    *This,
  IN OUT HDA_GAIN                         Gain
  );


/**
  Increment the volume in an implementation defined quanta. The value of the Gain can never
  be over 100. The final successful call will round the volume increase to 100. If this
  function is called an the Gain is already set to 100 EFI_NO_MAPPING must be returned. 
  
  The result of calling this function while audio is playing asynchronously is undefined. 

  @param[in]      This         A pointer to the CODE_FIRST_HDA_AUDIO_PROTOCOL instance.

  @retval EFI_SUCCESS           Gain was incremented. 
  @retval EFI_NO_MAPPING        Gasin was not updated since it was already set to 100.
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.

**/
typedef
EFI_STATUS
(EFIAPI *CODE_FIRST_HDA_AUDIO_PROTOCOL_VOLUME_UP)(
  IN     CODE_FIRST_HDA_AUDIO_PROTOCOL   *This
  );


/**
  Decrement the volume in an implementation defined quanta. The value of the Gain can never
  be under 0. The final successful call will round the volume decrease to 0. If this
  function is called an the Gain is already set to 0 EFI_NO_MAPPING must be returned. 
  
  The result of calling this function while audio is playing asynchronously is undefined. 

  @param[in]      This         A pointer to the CODE_FIRST_HDA_AUDIO_PROTOCOL instance.

  @retval EFI_SUCCESS           Gain was decremented. 
  @retval EFI_NO_MAPPING        Gain was not updated since it was already set to 0.
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.

**/
typedef
EFI_STATUS
(EFIAPI *CODE_FIRST_HDA_AUDIO_PROTOCOL_VOLUME_DOWN)(
  IN     CODE_FIRST_HDA_AUDIO_PROTOCOL   *This
  );


/**
  Mute audio output, but retain the current Gain (volume Level).
    
  The result of calling this function while audio is playing asynchronously is undefined. 

  @param[in]      This         A pointer to the CODE_FIRST_HDA_AUDIO_PROTOCOL instance.

  @retval EFI_SUCCESS           Audio was muted. 
  @retval EFI_ALREADY_STARTED   Audio is already muted. 
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.

**/
typedef
EFI_STATUS
(EFIAPI *CODE_FIRST_HDA_AUDIO_PROTOCOL_MUTE)(
  IN     CODE_FIRST_HDA_AUDIO_PROTOCOL   *This
  );

/**
  Unmute audio output, but retain the current Gain (volume Level).
    
  The result of calling this function while audio is playing asynchronously is undefined. 

  @param[in]      This         A pointer to the CODE_FIRST_HDA_AUDIO_PROTOCOL instance.

  @retval EFI_SUCCESS           Audio was muted. 
  @retval EFI_ALREADY_STARTED   Audio is already unmuted. 
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.

**/
typedef
EFI_STATUS
(EFIAPI *CODE_FIRST_HDA_AUDIO_PROTOCOL_UNMUTE)(
  IN     CODE_FIRST_HDA_AUDIO_PROTOCOL   *This
  );


/**
  Reset the audio hardware. 
    
  The result of calling this function while audio is playing asynchronously is undefined. 

  @param[in]      This         A pointer to the CODE_FIRST_HDA_AUDIO_PROTOCOL instance.

  @retval EFI_SUCCESS           Audio was muted. 
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.

**/
typedef
EFI_STATUS
(EFIAPI *CODE_FIRST_HDA_AUDIO_PROTOCOL_RESET)(
  IN     CODE_FIRST_HDA_AUDIO_PROTOCOL   *This
  );


#define HDA_AUDIO_VERSION 0x00010000

///
/// The CODE_FIRST_HDA_AUDIO_PROTOCOL provides an abstraction for an Audio device that
/// can play PCM files. 
/// There is one CODE_FIRST_HDA_AUDIO_PROTOCOL instance for each Audio Hardware device.
///
struct _CODE_FIRST_HDA_AUDIO_PROTOCOL {
  UINT64                                      Version;
  CODE_FIRST_HDA_AUDIO_PROTOCOL_PLAY_STREAM   PlayStream;
  CODE_FIRST_HDA_AUDIO_PROTOCOL_STOP_STREAM   StopStream;
  CODE_FIRST_HDA_AUDIO_PROTOCOL_GET_VOLUME    GetVolume;  
  CODE_FIRST_HDA_AUDIO_PROTOCOL_SET_VOLUME    SetVolume;
  CODE_FIRST_HDA_AUDIO_PROTOCOL_VOLUME_UP     VolumeUp;
  CODE_FIRST_HDA_AUDIO_PROTOCOL_VOLUME_DOWN   VolumeDown; 
  CODE_FIRST_HDA_AUDIO_PROTOCOL_MUTE          Mute;
  CODE_FIRST_HDA_AUDIO_PROTOCOL_UNMUTE        UnMute;
  CODE_FIRST_HDA_AUDIO_PROTOCOL_RESET         Reset;
};

extern EFI_GUID gBz2387HdaAudioProtocolGuid;

#endif


Thanks,

Andrew Fish

On 4/14/21, Andrew Fish <afish@apple.com> wrote:


On Apr 14, 2021, at 3:30 PM, Kinney, Michael D
<michael.d.kinney@intel.com> wrote:

Hi Ethin,

Most UEFI Drivers do use polling.

If it is a blocking I/O operation the UEFI Driver waits for completion.
Typically by polling a status register until the I/O is complete and then
return status.

If it is a non-blocking I/O Operation, then the UEFI Driver can create a
timer event to periodically check the completion status.

Non-blocking APIs may also use an event to know when the I/O operation is
completed and this can be used with the CheckEvent() service to poll for
event completion.

These concepts are discussed in the UEFI Driver Writer's Guide.

https://tianocore-docs.github.io/edk2-UefiDriverWritersGuide/draft/edk2-UefiDriverWritersGuide-draft.pdf
<https://tianocore-docs.github.io/edk2-UefiDriverWritersGuide/draft/edk2-UefiDriverWritersGuide-draft.pdf>

Specifically for audio.  If there is an audio playback buffer that will
take some time to send,
the Audio Protocol would likely define a non-blocking interface to start
playback.  You may need
an event that is signaled when more audio data is needed or when the
playback is complete.  You
will need to think about the consumer of the Audio Protocol and how it
will interact with the
Audio Protocol and if the consumer also needs to do other activities while
audio is playing or
if it is ok for the consumer to wait until the audio playback is
completed.


Mike,

It is likely we want async and synchronous playback. If you are playing a
boot bong you don’t want to block on its completion. If you are doing a GUI
UI you don’t want to block on playback and then do a bunch of GUI math etc.


Ethin,

I’d take a look at some example drivers like VirtioBlkDxe[1]. It also looks
like there is already a VirtioLib[2] to help with house keeping. I did a
quick skim and I don’t see a VirtIo device with an Event driven API.  It
looks like VirtioNetDxe[3] does have the concept of a callback to poll [4],
so you might be able to leverage that concept into a timer event to check
for completion.

I’d not get hung up on the asynchronous part of the API. It might make sense
to implement the synchronous version of the API in the driver 1st and fake
the async for your 1st pass.

If you look at other UEFI Async APIs they generally pass around a Token
(usually an Event to signal on completion, and an EFI_STATUS)[5]. Thus
faking the Async means making it look like the event fired before your API
returned. Assuming that *Token is an argument to the protocol you do this to
fake the Async transaction….

If (Token != NULL) {
 Token->TransactionStatus = Status;
 gBS->SignalEvent (Token->Event);
}

This just make it look to the caller like the transaction completed by the
time you returned to the caller. So from a caller perspective that is a
valid way the API could work. The other upside to this is you can make a
UEFI Shell App to test the protocol and also add a path to test the async
API, even if for the 1st pass implementation that is faked out.

[1] https://github.com/tianocore/edk2/tree/master/OvmfPkg/VirtioBlkDxe
[2]
https://github.com/tianocore/edk2/blob/master/OvmfPkg/Library/VirtioLib/VirtioLib.c
[3] https://github.com/tianocore/edk2/tree/master/OvmfPkg/VirtioNetDxe
[4]
https://github.com/tianocore/edk2/blob/master/OvmfPkg/VirtioNetDxe/Events.c#L32
[5]
https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/BlockIo2.h#L41

Thanks,

Andrew Fish

Mike

-----Original Message-----
From: devel@edk2.groups.io <mailto:devel@edk2.groups.io>
<devel@edk2.groups.io <mailto:devel@edk2.groups.io>> On Behalf Of Ethin
Probst
Sent: Wednesday, April 14, 2021 1:48 PM
To: Andrew Fish <afish@apple.com <mailto:afish@apple.com>>
Cc: edk2-devel-groups-io <devel@edk2.groups.io
<mailto:devel@edk2.groups.io>>; Leif Lindholm <leif@nuviainc.com
<mailto:leif@nuviainc.com>>; Laszlo Ersek <lersek@redhat.com
<mailto:lersek@redhat.com>>;
Desimone, Nathaniel L <nathaniel.l.desimone@intel.com
<mailto:nathaniel.l.desimone@intel.com>>; Rafael Rodrigues Machado
<rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>>; Gerd
Hoffmann <kraxel@redhat.com <mailto:kraxel@redhat.com>>
Subject: Re: [edk2-devel] VirtIO Sound Driver (GSoC 2021)

These are some pretty good suggestions; however, while reading through
the VirtIO specification again yesterday, I (re)-discovered that
VirtIO devices are usually interrupt based. In particular, a VirtIO
PCI/PCIe device defines the common, notifications, ISR status,
device-specific configuration, PCI configuration access, shared memory
region, and vendor-specific data capability structures in PCI
configuration space. It doesn't look like the EFI_CREATE_EVENT or
EFI_CREATE_EVENT_EX function works via interrupts, from what I can
tell. I'm not sure but it doesn't seem like there's a way I can poll
the device, though I might be missing something.
The idea for the generic protocol is good. The interrupt issue might
be a problem though and I'm not sure how to actually solve that.

On 4/13/21, Andrew Fish <afish@apple.com> wrote:
Ethin,

In terms of defining the protocol stack it is good to start with the
producers and consumers and think about the problem from both
perspectives.
It is easy enough to think about the producer part of it as you are
thinking
about writing the driver. The driver is going to consume things like the
PCI
I/O Protocol.

The consumer of the sound Protocol is going to most likely be generic
EFI
platform code, and possibly an OS loader. In the boot process Audio has
traditionally be used for error codes, sign of life (for example the
famous
Mac startup sound). We are also would like to have the option of
enabling
better accessibility features, especially for people how are visually
impaired. These days a lot of software engineers think of disk space as
free
and really don’t consider the size of software, but this is not true
for
firmware. Firmware generally lives in NOR FLASH that is considered
expensive
(it is more expensive than NAND, but at the same time more reliable) so
firmware implementations are constrained by the size of the code that
can be
carried, and the size of assets/resources that can be used for user
interfaces. The OS loader is some what less constrained, but it still
has to
share the EFI System Partition on the disk with potentially other OS
loaders.

So the consumer wants a protocol that is unleveled and focused on the
task
at hand. I’m not too caught up on the names but in general I think
things
you want are (How many knobs we need is probably better answered by an
audiophile, and that is not me):
1) CompatibleBuffer() - Does driver support this buffer format.
2) PlayBuffer() - Play the sound
a) We probably want a synchronous and asynchronous version of this API.
For
example you don’t want to slow down the boot to wait for a boot beep to
complete, and you may chose to implement an API that waits for the sound
to
complete (and do some GUI work in parallel) vs. blocking on the sound.
b) async in EFI usually means you return a pointer to an EFI_EVENT
that
gets signaled on completion.
3) StopBuffer() - In case the asynchronous PlayBuffer() needs to be
stopped.
Think error exit.
3) SetVolume()/GetVolume() - Set/Get Volume in units of 0 - 100 (trying
to
avoid db as that gets into capability and math that is likely best
abstracted by the driver)?
4) Mute()/UnMute() - Mute and volume are often independent features in a
UI
keeping them separate in API makes it easier to implement things.
5) PlayTone() - Maybe for error sounds that don’t require canned sound
files. Maybe TimeOn, TimeOff, Frequency, and how many times to repeat.
6) Do we need tuning values or Tone settings?

At some point we might consider defining nvram variable for the default
state of some of the tunable, especially mute and volume. For example
the
user may want to turn off all volume on the system so it would be nice
if
the OS can set the EFI volume and mute. In the short run we can probably
use
PCD values to set the default values.

So I think we have a generic AUDIO API on top and likely a PCI I/O on
the
bottom. If we need more protocols to manage hardware devices then those
protocols can be defined in the context of that hardware. So for example
we
would probably end up with an HDA_CODEC protocol. I think the best way
to
think about this is a disk. A lot of disk adapters just produce a raw
Block
I/O  protocol, but for a more common bus like ATA or SCSI you might have
an
extra driver in place to make the common bits common code. I think some
of
the same layers may be in place here. So likely VirtIo is simple and
just
produces the generic AUDIO API, while an HDA audio driver also has to
abstract some of the complexity of its hardware implementation and
standard.


In terms of picking the set of APIs and tunables it is probably good to
start with VirtIo and USB and see what set make sense and what you could
and
could not implement. HDA Audio is so complex you might want to look at
it in
terms of the minute you have to implement to make it function. Think
what
assumptions are you forced to make to implement.

This is a vey 10,000 foot view to start with. I think you will need to
mix
this in the the reality of how it works in the real world to figure out
the
right abstraction, but then again that is the beauty of having an
implementation. Likely also get some feedback from audiophiles.

Oh and make sure you don’t go off an implement a lot of code just
because we
chose the wrong complexity or abstraction point. This is the one time we
get
to change the public APIs so lets feel free to adjust them to make the
most
sense for the job at hand.

Thanks,

Andrew Fish

On Apr 13, 2021, at 6:20 PM, Ethin Probst <harlydavidsen@gmail.com>
wrote:

Okay, so looking at the EDK2 driver developers guide, here are my
thoughts:

- Each audio driver will be a bus driver, even if it doesn't control
buses in the traditional sense.
- I think the initialization sequence should be different: there
should be an AudioDxe, but it should contain three separate bus
drivers for each kind of audio device supported.
- For the VirtIO audio device driver, it'll most likely consume the
PCI I/O protocol and produce the EFI_VIRTIO_AUDIO_OUTPUT_PROTOCOL and
EFI_VIRTIO_AUDIO_INPUT_PROTOCOL protocols. This will just be an
ordinary UEFI device driver.
- The HDA audio device driver will consume the PCI I/O protocol and
will produce different device handles per HDA controller found. I'd
produce a handle per codec, but that seems overkill. Each handle will
be attached to both an audio stream protocol and a controller
management protocol. The audio stream protocol will manage the
creation, control, and deletion of audio streams as well as the
processing of audio data. The controller management protocol is
responsible for allowing applications or other drivers to manage the
HDA controller itself.

I haven't planned for the USB audio device driver yet, but these are
my thoughts so far. What do you guys think? Am I over-complicating
this setup? How can it be improved upon?

On 4/13/21, Ethin Probst via groups.io <http://groups.io/>
<harlydavidsen=gmail.com@groups.io
<mailto:harlydavidsen=gmail.com@groups.io>> wrote:
Hi Andrew,

The developer guide for EDK2 drivers is a godsend. Thank you very
much, and thank you, Mike, for your excellent work on the guide! I
may
just ahve to do my building on Linux and not Windows -- unless the
Bug
-- bug 3302 -- has been fixed. I'll have to do testing on Linux, at
any rate, since Windows hosts do not support VirtIO emulation and I
can't seem to find any way of emulating them in a guest machine with
Windows as a host.

On 4/13/21, Andrew Fish <afish@apple.com <mailto:afish@apple.com>>
wrote:


On Apr 13, 2021, at 9:53 AM, Ethin Probst <harlydavidsen@gmail.com>
wrote:

Would it be possible for us to conduct discussion on the UEFI
talkbox?
I don't mind using email, but things could definitely get moving
quicker over there (though its not a requirement obviously).


Sure, don’t think I’ve really used that but as long as I get pointed
int
he
right direction I can make it work.

For a device driver the general UEFI model is for the Entry point of
the
driver to publish a EFI_DRIVER_BINDING_PROTOCOL[1]. The Supported()
function
matches on the PCI devices. The Start() function installs the
Protocols
to
do work, and the Stop() undoes the Start().

Mike Kinney started this back in the day and it describes how to
write
UEFI
drivers:
https://github.com/tianocore/tianocore.github.io/wiki/UEFI-Driver-Writer%27s-Guide

[1]https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/DriverBinding.h#L157

Thanks,

Andrew Fish

Here's how I generally envision the driver functioning:

1. Firmware/platform code calls InitaudioOutput() or something like
it. This function scans the PCIe bus and scans for one of the
following:
- Vendor ID 0x1AF4, device ID 0x1059: VirtIO sound device
- PCI class 0x0C, subclass 0x03, program interface 0x30 or 0x40:
for
USB audio interface (I'm only thinking of targeting XHCI and USB 4,
and not UHCI, OHCI or EHCI). But maybe EDK2 will take that out of
my
hands. If so, it will make things easier.
- For USB audio devices I'm not quite sure what to look for; I'm
definitely unused to USB.
2. If any of the above cases are found, appropriate driver
initialization occurs. Since for the time being I am solely
focusing
on VirtIO sound devices, the VirtIO general initialization sequence
will occur as outlined in sec. 3 of the VirtIO specification
available
at https://www.kraxel.org/virtio/virtio-v1.1-cs01-sound-v7.html
<https://www.kraxel.org/virtio/virtio-v1.1-cs01-sound-v7.html
<https://www.kraxel.org/virtio/virtio-v1.1-cs01-sound-v7.html>>.
As for actual protocol exposure that would be spec-worthy, for
EFI_AUDIO_OUTPUT_PROTOCOL, I'm not quite sure what to expose.
VirtIO
is rather simple: there's a buffer for sending and receiving audio
data in PCM streams. So for that we could expose a Reset(),
RemapJack(), GetJackConfig(), GetPcmConfig(), SetPcmParams(),
Prepare(), Release(), Start(), and Stop() function for the
corresponding request types VIRTIO_SND_R_JACK_GET_CONFIG,
VIRTIO_SND_R_JACK_REMAP, VIRTIO_SND_R_PCM_GET_CONFIG,
VIRTIO_SND_R_PCM_SET_PARAMS, VIRTIO_SND_R_PCM_PREPARE,
VIRTIO_SND_R_PCM_RELEASE, VIRTIO_SND_R_PCM_START, and
VIRTIO_SND_R_PCM_STOP control requests. However, for HDA things are
a
lot more complex, so I'm not sure how that should work.
For VirtIO -- which is what I'll focus on for now -- everything is
described, in excellent detail, in sec. 5.14 of the above-linked
document. What are your guys's thoughts thus far and how should
everything be mapped to UEFI interfaces?

On 4/13/21, Andrew Fish <afish@apple.com <mailto:afish@apple.com>
<mailto:afish@apple.com <mailto:afish@apple.com>>>
wrote:
Leif,

Since I have put some brain cells around this area in the past I
can
be
the
backup and help out too.

I’d also point out if you are having issues building or have
general
questions on how things work it is fine to use the mailing list.
I’ve
got
a
lot of feedback that folks read or search the mailing list looking
for
answer to their questions so one person asking can help out a lot
of
other
people.

Thanks,

Andrew Fish

On Apr 13, 2021, at 5:28 AM, Leif Lindholm <leif@nuviainc.com
<mailto:leif@nuviainc.com>> wrote:

Hi all, especially Ethin.

Apologies for radio silence - last week I was off on holiday, and
before
that ... let's just say corporate acquisitions generate some
distractions.
Anyway, I'm back, and since I'm down as the mentor for this task,
feel
free to spam me with any remaining/new questions.

/
Leif

On Tue, Apr 6, 2021 at 4:17 PM Ethin Probst
<harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>
<mailto:harlydavidsen@gmail.com <mailto:harlydavidsen@gmail.com>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>>>>
wrote:
I'll attach the bug for the build tools to the BZ shortly.
Laszlo, thanks for that. I don't know their email addresses
though.
And yes, I was going to make it device independent, as the
majority
(if not all) of UEFI protocols are.

On 4/6/21, Laszlo Ersek <lersek@redhat.com
<mailto:lersek@redhat.com>
<mailto:lersek@redhat.com <mailto:lersek@redhat.com>>
<mailto:lersek@redhat.com <mailto:lersek@redhat.com>
<mailto:lersek@redhat.com <mailto:lersek@redhat.com>>>>
wrote:
On 03/31/21 08:41, Nate DeSimone wrote:
Another option is to put the protocol definition in
MdeModulePkg
and
mark it with the EDKII_ prefix. For my last “code first” UEFI
spec
contribution I did this with the PPI that added up getting
added.

The new audio protocol should be generic, only its
implementation
in
question should be virtio specific.

Please include Gerd Hoffmann (CC'd) in the protocol design, as
well
as
the developers of the virtio-sound device model in QEMU.

Thanks
Laszlo





Thanks,

Nate



*From: *<devel@edk2.groups.io <mailto:devel@edk2.groups.io>
<mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>>
<mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>
<mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>>>>
on
behalf
of "Andrew Fish via groups.io <http://groups.io/>
<http://groups.io/ <http://groups.io/>> <http://groups.io/
<http://groups.io/>
<http://groups.io/ <http://groups.io/>>>"
<afish=apple.com@groups.io <mailto:afish=apple.com@groups.io>
<mailto:afish=apple.com@groups.io
<mailto:afish=apple.com@groups.io>>
<mailto:apple.com@groups.io <mailto:apple.com@groups.io>
<mailto:apple.com@groups.io <mailto:apple.com@groups.io>>>>
*Reply-To: *"devel@edk2.groups.io <mailto:devel@edk2.groups.io>
<mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>>
<mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>
<mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>>>"
<devel@edk2.groups.io <mailto:devel@edk2.groups.io>
<mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>>
<mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>
<mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>>>>,
"afish@apple.com <mailto:afish@apple.com>
<mailto:afish@apple.com
<mailto:afish@apple.com>> <mailto:afish@apple.com
<mailto:afish@apple.com>
<mailto:afish@apple.com <mailto:afish@apple.com>>>"
<afish@apple.com <mailto:afish@apple.com>
<mailto:afish@apple.com
<mailto:afish@apple.com>>
<mailto:afish@apple.com <mailto:afish@apple.com>
<mailto:afish@apple.com <mailto:afish@apple.com>>>>
*Date: *Tuesday, March 30, 2021 at 10:54 PM
*To: *edk2-devel-groups-io <devel@edk2.groups.io
<mailto:devel@edk2.groups.io>
<mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>>
<mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>
<mailto:devel@edk2.groups.io <mailto:devel@edk2.groups.io>>>>,
"harlydavidsen@gmail.com <mailto:harlydavidsen@gmail.com>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>>>"
<harlydavidsen@gmail.com <mailto:harlydavidsen@gmail.com>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>>>>
*Cc: *Rafael Rodrigues Machado
<rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>
<mailto:rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>>
<mailto:rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>
<mailto:rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>>>>
*Subject: *Re: [edk2-devel] VirtIO Sound Driver (GSoC 2021)





On Mar 30, 2021, at 5:01 PM, Ethin Probst
<harlydavidsen@gmail.com <mailto:harlydavidsen@gmail.com>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>>>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>>>>>
wrote:



I'm wondering where exactly I should add the VirtIO sound
protocol.
I
just familiarized myself with the build system and am about to
test
it
by building OVMF if possible, but I'm wondering where I should
actually put the protocol and all that stuff. Maybe there's
documentation I've missed as well.



Ethin,



For the driver I’d match the patter of OVMF [1] and use
OvmfPkg/VirtioSoundDxe/. Maybe even use one of the other
drivers
as
a
template.



The protocol is more of a public thing. I think eventually we
would
like
to publish the protocol in the UEFI Spec (I can help with that
part)
and
that would mean we put the Protocol definition in
MdePkg/Include/Protocol, but we don’t want to do that before it
is
standardized as that causes compatibility issues. So this is a
“code
first project” (code prototype and then contribute to the UEFI
Forum
for
inclusion in the specification) so we need to follow some code
first
rules that I don’t remember of the top of my head? So why not
start
out
the protocol definition OvmfPkg/Include/Protocol. You can also
add
a
test application looks like you can just use the root [2] of
OVMF
for
that. That way the project is not blocked.



We can have a conversation on the mailing list about better
places
to
put stuff, and it should be easy enough to move stuff around if
everything else is working.



[1] find OvmfPkg  -iname '*Virtio*.inf'

OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf

OvmfPkg/VirtioScsiDxe/VirtioScsi.inf

OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf

OvmfPkg/Library/VirtioLib/VirtioLib.inf

OvmfPkg/VirtioGpuDxe/VirtioGpu.inf

OvmfPkg/VirtioBlkDxe/VirtioBlk.inf

OvmfPkg/Virtio10Dxe/Virtio10.inf

OvmfPkg/VirtioNetDxe/VirtioNet.inf

OvmfPkg/VirtioRngDxe/VirtioRng.inf



[2] /Volumes/Case/edk2-github/OvmfPkg>git grep APPLICATION --
*.inf
|
grep MODULE_TYPE

EnrollDefaultKeys/EnrollDefaultKeys.inf:13:  MODULE_TYPE
= UEFI_APPLICATION



Thanks,



Andrew Fish






On 3/30/21, Ethin Probst via groups.io <http://groups.io/>
<http://groups.io/ <http://groups.io/>>
<http://groups.io/ <http://groups.io/> <http://groups.io/
<http://groups.io/>>>
<http://groups.io/ <http://groups.io/> <http://groups.io/
<http://groups.io/>> <http://groups.io/ <http://groups.io/>
<http://groups.io/ <http://groups.io/>>>>
<harlydavidsen=gmail.com@groups.io
<mailto:harlydavidsen=gmail.com@groups.io>
<mailto:harlydavidsen=gmail.com@groups.io
<mailto:harlydavidsen=gmail.com@groups.io>>
<mailto:gmail.com@groups.io <mailto:gmail.com@groups.io>
<mailto:gmail.com@groups.io <mailto:gmail.com@groups.io>>>
<mailto:harlydavidsen
<mailto:harlydavidsen>=gmail.com@groups.io
<mailto:gmail.com@groups.io>
<mailto:gmail.com@groups.io <mailto:gmail.com@groups.io>>
<mailto:gmail.com@groups.io <mailto:gmail.com@groups.io>
<mailto:gmail.com@groups.io <mailto:gmail.com@groups.io>>>>>
wrote:

    I agree. Plus, it gives me a chance to finally learn the
EDK2
build
    system and how it works! I've been working on a hobby OS
as
a
side
    project and, though learning from other code examples from
OSes
is
    fun, I have to say that learning from the firmware code
like
from
    SeaBIOS has been some of the most enlightening and
interesting
times
    thus far.
    Thanks for the link to your code, Rafael; once I get
virtIO
support
    in, I can work on HDA support, though I might tackle USB
support
    second and HDA third. We'll see, but VirtIO definitely is
coming
    first.

    As I said before, I look forward to working with all of
you
    wonderful
    people!

    On 3/30/21, Rafael Rodrigues Machado
    <rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>
<mailto:rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>>
<mailto:rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>
<mailto:rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>>>
    <mailto:rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>
<mailto:rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>>
<mailto:rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>
<mailto:rafaelrodrigues.machado@gmail.com
<mailto:rafaelrodrigues.machado@gmail.com>>>>>
    wrote:

        This would be amazing so people can continue my work
related
to
        accessibility at BIOS. Something desired by the blind
people
        since the
        90's
        Just for reference, this is what I have done:


https://github.com/RafaelRMachado/Msc_UefiHda_PreOs_Accessibility
<https://github.com/RafaelRMachado/Msc_UefiHda_PreOs_Accessibility>
<https://github.com/RafaelRMachado/Msc_UefiHda_PreOs_Accessibility
<https://github.com/RafaelRMachado/Msc_UefiHda_PreOs_Accessibility>>
<https://github.com/RafaelRMachado/Msc_UefiHda_PreOs_Accessibility
<https://github.com/RafaelRMachado/Msc_UefiHda_PreOs_Accessibility>
<https://github.com/RafaelRMachado/Msc_UefiHda_PreOs_Accessibility
<https://github.com/RafaelRMachado/Msc_UefiHda_PreOs_Accessibility>>>

        Thanks
        Rafael

        Em seg, 29 de mar de 2021 20:24, Ethin Probst
        <harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>
<mailto:harlydavidsen@gmail.com
<mailto:harlydavidsen@gmail.com>>>>
        escreveu:


            Hello everyone,

            This is the first time I've ever contributed to
EDK2.
As
            part of GSoC
            2021, I have submitted a proposal to implement a
UEFI
            audio output
            protocol that will utilize the VirtIO sound
driver.
I've
            already
            submitted a draft proposal, and apologize if I've
done
            things out of
            order. This is my first time doing GSoC 2021, and
            contributing to EDK2
            felt like a really fun thing to do!

            I look forward to working with you guys on this
and
any
            future projects!
            :-)

            --
            Signed,
            Ethin D. Probst









    --
    Signed,
    Ethin D. Probst







--
Signed,
Ethin D. Probst










--
Signed,
Ethin D. Probst










--
Signed,
Ethin D. Probst







--
Signed,
Ethin D. Probst








--
Signed,
Ethin D. Probst




--
Signed,
Ethin D. Probst







-- 
Signed,
Ethin D. Probst