[alsa-devel] [PATCH v2 5/5] ALSA: xen-front: Implement ALSA virtual sound driver
Oleksandr Andrushchenko
Oleksandr_Andrushchenko at epam.com
Tue Apr 17 14:34:32 CEST 2018
On 04/17/2018 03:32 PM, Juergen Gross wrote:
> On 17/04/18 14:26, Oleksandr Andrushchenko wrote:
>> On 04/17/2018 02:32 PM, Oleksandr Andrushchenko wrote:
>>> On 04/16/2018 05:09 PM, Juergen Gross wrote:
>>>> On 16/04/18 08:24, Oleksandr Andrushchenko wrote:
>>>>> From: Oleksandr Andrushchenko <oleksandr_andrushchenko at epam.com>
>>>>>
>>>>> Implement essential initialization of the sound driver:
>>>>> - introduce required data structures
>>>>> - handle driver registration
>>>>> - handle sound card registration
>>>>> - register sound driver on backend connection
>>>>> - remove sound driver on backend disconnect
>>>>>
>>>>> Initialize virtual sound card with streams according to the
>>>>> Xen store configuration.
>>>>>
>>>>> Implement ALSA driver operations including:
>>>>> - manage frontend/backend shared buffers
>>>>> - manage Xen bus event channel states
>>>>>
>>>>> Implement requests from front to back for ALSA
>>>>> PCM operations.
>>>>> - report ALSA period elapsed event: handle XENSND_EVT_CUR_POS
>>>>> notifications from the backend when stream position advances
>>>>> during playback/capture. The event carries a value of how
>>>>> many octets were played/captured at the time of the event.
>>>>> - implement explicit stream parameter negotiation between
>>>>> backend and frontend: handle XENSND_OP_HW_PARAM_QUERY request
>>>>> to read/update configuration space for the parameter given:
>>>>> request passes desired parameter interval and the response to
>>>>> this request returns min/max interval for the parameter to be used.
>>>>>
>>>>> Signed-off-by: Oleksandr Andrushchenko
>>>>> <oleksandr_andrushchenko at epam.com>
>>>>> ---
>>>>> sound/xen/Makefile | 3 +-
>>>>> sound/xen/xen_snd_front.c | 193 ++++++++-
>>>>> sound/xen/xen_snd_front.h | 28 ++
>>>>> sound/xen/xen_snd_front_alsa.c | 830
>>>>> ++++++++++++++++++++++++++++++++++++++
>>>>> sound/xen/xen_snd_front_alsa.h | 23 ++
>>>>> sound/xen/xen_snd_front_evtchnl.c | 6 +-
>>>>> 6 files changed, 1080 insertions(+), 3 deletions(-)
>>>>> create mode 100644 sound/xen/xen_snd_front_alsa.c
>>>>> create mode 100644 sound/xen/xen_snd_front_alsa.h
>>>>>
>>>>> diff --git a/sound/xen/Makefile b/sound/xen/Makefile
>>>>> index f028bc30af5d..1e6470ecc2f2 100644
>>>>> --- a/sound/xen/Makefile
>>>>> +++ b/sound/xen/Makefile
>>>>> @@ -3,6 +3,7 @@
>>>>> snd_xen_front-objs := xen_snd_front.o \
>>>>> xen_snd_front_cfg.o \
>>>>> xen_snd_front_evtchnl.o \
>>>>> - xen_snd_front_shbuf.o
>>>>> + xen_snd_front_shbuf.o \
>>>>> + xen_snd_front_alsa.o
>>>>> obj-$(CONFIG_SND_XEN_FRONTEND) += snd_xen_front.o
>>>>> diff --git a/sound/xen/xen_snd_front.c b/sound/xen/xen_snd_front.c
>>>>> index 0569c6c596a3..1fef253ea21a 100644
>>>>> --- a/sound/xen/xen_snd_front.c
>>>>> +++ b/sound/xen/xen_snd_front.c
>>>>> @@ -19,10 +19,201 @@
>>>>> #include <xen/interface/io/sndif.h>
>>>>> #include "xen_snd_front.h"
>>>>> +#include "xen_snd_front_alsa.h"
>>>>> #include "xen_snd_front_evtchnl.h"
>>>>> +#include "xen_snd_front_shbuf.h"
>>>>> +
>>>>> +static struct xensnd_req *
>>>>> +be_stream_prepare_req(struct xen_snd_front_evtchnl *evtchnl, u8
>>>>> operation)
>>>>> +{
>>>>> + struct xensnd_req *req;
>>>>> +
>>>>> + req = RING_GET_REQUEST(&evtchnl->u.req.ring,
>>>>> + evtchnl->u.req.ring.req_prod_pvt);
>>>>> + req->operation = operation;
>>>>> + req->id = evtchnl->evt_next_id++;
>>>>> + evtchnl->evt_id = req->id;
>>>>> + return req;
>>>>> +}
>>>>> +
>>>>> +static int be_stream_do_io(struct xen_snd_front_evtchnl *evtchnl)
>>>>> +{
>>>>> + if (unlikely(evtchnl->state != EVTCHNL_STATE_CONNECTED))
>>>>> + return -EIO;
>>>>> +
>>>>> + reinit_completion(&evtchnl->u.req.completion);
>>>>> + xen_snd_front_evtchnl_flush(evtchnl);
>>>>> + return 0;
>>>>> +}
>>>>> +
>>>>> +static int be_stream_wait_io(struct xen_snd_front_evtchnl *evtchnl)
>>>>> +{
>>>>> + if (wait_for_completion_timeout(&evtchnl->u.req.completion,
>>>>> + msecs_to_jiffies(VSND_WAIT_BACK_MS)) <= 0)
>>>>> + return -ETIMEDOUT;
>>>>> +
>>>>> + return evtchnl->u.req.resp_status;
>>>>> +}
>>>>> +
>>>>> +int xen_snd_front_stream_query_hw_param(struct
>>>>> xen_snd_front_evtchnl *evtchnl,
>>>>> + struct xensnd_query_hw_param *hw_param_req,
>>>>> + struct xensnd_query_hw_param *hw_param_resp)
>>>>> +{
>>>>> + struct xen_snd_front_info *front_info = evtchnl->front_info;
>>>>> + struct xensnd_req *req;
>>>>> + unsigned long flags;
>>>>> + int ret;
>>>>> +
>>>>> + mutex_lock(&evtchnl->u.req.req_io_lock);
>>>>> +
>>>>> + spin_lock_irqsave(&front_info->io_lock, flags);
>>>>> + req = be_stream_prepare_req(evtchnl, XENSND_OP_HW_PARAM_QUERY);
>>>>> + req->op.hw_param = *hw_param_req;
>>>>> +
>>>>> + ret = be_stream_do_io(evtchnl);
>>>>> + spin_unlock_irqrestore(&front_info->io_lock, flags);
>>>>> +
>>>>> + if (ret == 0)
>>>>> + ret = be_stream_wait_io(evtchnl);
>>>>> +
>>>>> + if (ret == 0)
>>>>> + *hw_param_resp = evtchnl->u.req.resp.hw_param;
>>>>> +
>>>>> + mutex_unlock(&evtchnl->u.req.req_io_lock);
>>>>> + return ret;
>>>>> +}
>>>>> +
>>>>> +int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl
>>>>> *evtchnl,
>>>>> + struct xen_snd_front_shbuf *sh_buf,
>>>>> + u8 format, unsigned int channels,
>>>>> + unsigned int rate, u32 buffer_sz,
>>>>> + u32 period_sz)
>>>>> +{
>>>>> + struct xen_snd_front_info *front_info = evtchnl->front_info;
>>>>> + struct xensnd_req *req;
>>>>> + unsigned long flags;
>>>>> + int ret;
>>>>> +
>>>>> + mutex_lock(&evtchnl->u.req.req_io_lock);
>>>>> +
>>>>> + spin_lock_irqsave(&front_info->io_lock, flags);
>>>>> + req = be_stream_prepare_req(evtchnl, XENSND_OP_OPEN);
>>>>> + req->op.open.pcm_format = format;
>>>>> + req->op.open.pcm_channels = channels;
>>>>> + req->op.open.pcm_rate = rate;
>>>>> + req->op.open.buffer_sz = buffer_sz;
>>>>> + req->op.open.period_sz = period_sz;
>>>>> + req->op.open.gref_directory =
>>>>> xen_snd_front_shbuf_get_dir_start(sh_buf);
>>>>> +
>>>>> + ret = be_stream_do_io(evtchnl);
>>>>> + spin_unlock_irqrestore(&front_info->io_lock, flags);
>>>>> +
>>>>> + if (ret == 0)
>>>>> + ret = be_stream_wait_io(evtchnl);
>>>>> +
>>>>> + mutex_unlock(&evtchnl->u.req.req_io_lock);
>>>>> + return ret;
>>>>> +}
>>>>> +
>>>>> +int xen_snd_front_stream_close(struct xen_snd_front_evtchnl *evtchnl)
>>>>> +{
>>>>> + struct xen_snd_front_info *front_info = evtchnl->front_info;
>>>>> + struct xensnd_req *req;
>>>>> + unsigned long flags;
>>>>> + int ret;
>>>>> +
>>>>> + mutex_lock(&evtchnl->u.req.req_io_lock);
>>>>> +
>>>>> + spin_lock_irqsave(&front_info->io_lock, flags);
>>>>> + req = be_stream_prepare_req(evtchnl, XENSND_OP_CLOSE);
>>>>> +
>>>>> + ret = be_stream_do_io(evtchnl);
>>>>> + spin_unlock_irqrestore(&front_info->io_lock, flags);
>>>>> +
>>>>> + if (ret == 0)
>>>>> + ret = be_stream_wait_io(evtchnl);
>>>>> +
>>>>> + mutex_unlock(&evtchnl->u.req.req_io_lock);
>>>>> + return ret;
>>>>> +}
>>>>> +
>>>>> +int xen_snd_front_stream_write(struct xen_snd_front_evtchnl *evtchnl,
>>>>> + unsigned long pos, unsigned long count)
>>>>> +{
>>>>> + struct xen_snd_front_info *front_info = evtchnl->front_info;
>>>>> + struct xensnd_req *req;
>>>>> + unsigned long flags;
>>>>> + int ret;
>>>>> +
>>>>> + mutex_lock(&evtchnl->u.req.req_io_lock);
>>>>> +
>>>>> + spin_lock_irqsave(&front_info->io_lock, flags);
>>>>> + req = be_stream_prepare_req(evtchnl, XENSND_OP_WRITE);
>>>>> + req->op.rw.length = count;
>>>>> + req->op.rw.offset = pos;
>>>>> +
>>>>> + ret = be_stream_do_io(evtchnl);
>>>>> + spin_unlock_irqrestore(&front_info->io_lock, flags);
>>>>> +
>>>>> + if (ret == 0)
>>>>> + ret = be_stream_wait_io(evtchnl);
>>>>> +
>>>>> + mutex_unlock(&evtchnl->u.req.req_io_lock);
>>>>> + return ret;
>>>>> +}
>>>>> +
>>>>> +int xen_snd_front_stream_read(struct xen_snd_front_evtchnl *evtchnl,
>>>>> + unsigned long pos, unsigned long count)
>>>>> +{
>>>>> + struct xen_snd_front_info *front_info = evtchnl->front_info;
>>>>> + struct xensnd_req *req;
>>>>> + unsigned long flags;
>>>>> + int ret;
>>>>> +
>>>>> + mutex_lock(&evtchnl->u.req.req_io_lock);
>>>>> +
>>>>> + spin_lock_irqsave(&front_info->io_lock, flags);
>>>>> + req = be_stream_prepare_req(evtchnl, XENSND_OP_READ);
>>>>> + req->op.rw.length = count;
>>>>> + req->op.rw.offset = pos;
>>>>> +
>>>>> + ret = be_stream_do_io(evtchnl);
>>>>> + spin_unlock_irqrestore(&front_info->io_lock, flags);
>>>>> +
>>>>> + if (ret == 0)
>>>>> + ret = be_stream_wait_io(evtchnl);
>>>>> +
>>>>> + mutex_unlock(&evtchnl->u.req.req_io_lock);
>>>>> + return ret;
>>>>> +}
>>>>> +
>>>>> +int xen_snd_front_stream_trigger(struct xen_snd_front_evtchnl
>>>>> *evtchnl,
>>>>> + int type)
>>>>> +{
>>>>> + struct xen_snd_front_info *front_info = evtchnl->front_info;
>>>>> + struct xensnd_req *req;
>>>>> + unsigned long flags;
>>>>> + int ret;
>>>>> +
>>>>> + mutex_lock(&evtchnl->u.req.req_io_lock);
>>>>> +
>>>>> + spin_lock_irqsave(&front_info->io_lock, flags);
>>>>> + req = be_stream_prepare_req(evtchnl, XENSND_OP_TRIGGER);
>>>>> + req->op.trigger.type = type;
>>>>> +
>>>>> + ret = be_stream_do_io(evtchnl);
>>>>> + spin_unlock_irqrestore(&front_info->io_lock, flags);
>>>>> +
>>>>> + if (ret == 0)
>>>>> + ret = be_stream_wait_io(evtchnl);
>>>>> +
>>>>> + mutex_unlock(&evtchnl->u.req.req_io_lock);
>>>>> + return ret;
>>>>> +}
>>>>> static void xen_snd_drv_fini(struct xen_snd_front_info *front_info)
>>>>> {
>>>>> + xen_snd_front_alsa_fini(front_info);
>>>>> xen_snd_front_evtchnl_free_all(front_info);
>>>>> }
>>>>> @@ -45,7 +236,7 @@ static int sndback_initwait(struct
>>>>> xen_snd_front_info *front_info)
>>>>> static int sndback_connect(struct xen_snd_front_info *front_info)
>>>>> {
>>>>> - return 0;
>>>>> + return xen_snd_front_alsa_init(front_info);
>>>>> }
>>>>> static void sndback_disconnect(struct xen_snd_front_info
>>>>> *front_info)
>>>>> diff --git a/sound/xen/xen_snd_front.h b/sound/xen/xen_snd_front.h
>>>>> index 9c2ffbb4e4b8..7adbdb4d2019 100644
>>>>> --- a/sound/xen/xen_snd_front.h
>>>>> +++ b/sound/xen/xen_snd_front.h
>>>>> @@ -13,17 +13,45 @@
>>>>> #include "xen_snd_front_cfg.h"
>>>>> +struct card_info;
>>>>> +struct xen_snd_front_evtchnl;
>>>>> struct xen_snd_front_evtchnl_pair;
>>>>> +struct xen_snd_front_shbuf;
>>>>> +struct xensnd_query_hw_param;
>>>>> struct xen_snd_front_info {
>>>>> struct xenbus_device *xb_dev;
>>>>> + struct card_info *card_info;
>>>>> +
>>>>> /* serializer for backend IO: request/response */
>>>>> spinlock_t io_lock;
>>>>> +
>>>>> int num_evt_pairs;
>>>>> struct xen_snd_front_evtchnl_pair *evt_pairs;
>>>>> struct xen_front_cfg_card cfg;
>>>>> };
>>>>> +int xen_snd_front_stream_query_hw_param(struct
>>>>> xen_snd_front_evtchnl *evtchnl,
>>>>> + struct xensnd_query_hw_param *hw_param_req,
>>>>> + struct xensnd_query_hw_param *hw_param_resp);
>>>>> +
>>>>> +int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl
>>>>> *evtchnl,
>>>>> + struct xen_snd_front_shbuf *sh_buf,
>>>>> + u8 format, unsigned int channels,
>>>>> + unsigned int rate, u32 buffer_sz,
>>>>> + u32 period_sz);
>>>>> +
>>>>> +int xen_snd_front_stream_close(struct xen_snd_front_evtchnl *evtchnl);
>>>>> +
>>>>> +int xen_snd_front_stream_write(struct xen_snd_front_evtchnl *evtchnl,
>>>>> + unsigned long pos, unsigned long count);
>>>>> +
>>>>> +int xen_snd_front_stream_read(struct xen_snd_front_evtchnl *evtchnl,
>>>>> + unsigned long pos, unsigned long count);
>>>>> +
>>>>> +int xen_snd_front_stream_trigger(struct xen_snd_front_evtchnl
>>>>> *evtchnl,
>>>>> + int type);
>>>>> +
>>>>> #endif /* __XEN_SND_FRONT_H */
>>>>> diff --git a/sound/xen/xen_snd_front_alsa.c
>>>>> b/sound/xen/xen_snd_front_alsa.c
>>>>> new file mode 100644
>>>>> index 000000000000..f524b172750e
>>>>> --- /dev/null
>>>>> +++ b/sound/xen/xen_snd_front_alsa.c
>>>>> @@ -0,0 +1,830 @@
>>>>> +// SPDX-License-Identifier: GPL-2.0 OR MIT
>>>>> +
>>>>> +/*
>>>>> + * Xen para-virtual sound device
>>>>> + *
>>>>> + * Copyright (C) 2016-2018 EPAM Systems Inc.
>>>>> + *
>>>>> + * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko at epam.com>
>>>>> + */
>>>>> +
>>>>> +#include <linux/platform_device.h>
>>>>> +
>>>>> +#include <sound/core.h>
>>>>> +#include <sound/pcm.h>
>>>>> +#include <sound/pcm_params.h>
>>>>> +
>>>>> +#include <xen/xenbus.h>
>>>>> +
>>>>> +#include "xen_snd_front.h"
>>>>> +#include "xen_snd_front_alsa.h"
>>>>> +#include "xen_snd_front_cfg.h"
>>>>> +#include "xen_snd_front_evtchnl.h"
>>>>> +#include "xen_snd_front_shbuf.h"
>>>>> +
>>>>> +struct pcm_stream_info {
>>>> Not sure how this is generally handled in the sound drivers, but when
>>>> reviewing the code using those structures I repeatedly tried to find
>>>> their definitions in the sound headers instead of here. Same applies to
>>>> the alsa_* names.
>>>>
>>>> I'd prefer names which don't poison the name space.
>>> I'll try to do something about naming
>> One question still remains wrt alsa_* names: if this is for structures
>> I have (alsa_sndif_sample_format/alsa_sndif_hw_param), then
>> those already have sndif in their name which clearly says these are
>> Xen related ones (sndif is a Xen protocol).
>> If you also don't like the alsa_* function names then those are all
>> static and defined in this same file, so see no confusion here.
>>
>> I have changed other non-obvious struct names:
>>
>> -struct pcm_stream_info {
>> +struct xen_snd_front_pcm_stream_info {
>>
>> -struct pcm_instance_info {
>> +struct xen_snd_front_pcm_instance_info {
>>
>> -struct card_info {
>> +struct xen_snd_front_card_info {
>>
>> Does the above work for you?
> Yes, this seems to be okay.
Good, thank you
> Thanks,
>
> Juergen
More information about the Alsa-devel
mailing list