[PATCH 06/11] ALSA: vsnd: Introduce ALSA virtual sound driver

Oleksandr Andrushchenko
2017-08-07T07:43:49Z

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

Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
---
sound/drivers/xen-front.c | 161 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 159 insertions(+), 2 deletions(-)

diff --git a/sound/drivers/xen-front.c b/sound/drivers/xen-front.c
index 04ebc15757f4..f3e3f64f0aa6 100644
--- a/sound/drivers/xen-front.c
+++ b/sound/drivers/xen-front.c
@@ -19,13 +19,14 @@
*/

#include <linux/module.h>
+#include <linux/platform_device.h>

#include <sound/core.h>
#include <sound/pcm.h>

-#include <xen/platform_pci.h>
#include <xen/events.h>
#include <xen/grant_table.h>
+#include <xen/platform_pci.h>
#include <xen/xen.h>
#include <xen/xenbus.h>

@@ -66,6 +67,33 @@ struct sh_buf_info {
size_t vbuffer_sz;
};

+struct sdev_pcm_stream_info {
+ int unique_id;
+ struct snd_pcm_hardware pcm_hw;
+ struct xdrv_evtchnl_info *evt_chnl;
+ bool is_open;
+ uint8_t req_next_id;
+ struct sh_buf_info sh_buf;
+};
+
+struct sdev_pcm_instance_info {
+ struct sdev_card_info *card_info;
+ struct snd_pcm *pcm;
+ struct snd_pcm_hardware pcm_hw;
+ int num_pcm_streams_pb;
+ struct sdev_pcm_stream_info *streams_pb;
+ int num_pcm_streams_cap;
+ struct sdev_pcm_stream_info *streams_cap;
+};
+
+struct sdev_card_info {
+ struct xdrv_info *xdrv_info;
+ struct snd_card *card;
+ struct snd_pcm_hardware pcm_hw;
+ int num_pcm_instances;
+ struct sdev_pcm_instance_info *pcm_instances;
+};
+
struct cfg_stream {
int unique_id;
char *xenstore_path;
@@ -99,6 +127,8 @@ struct xdrv_info {
struct xenbus_device *xb_dev;
spinlock_t io_lock;
struct mutex mutex;
+ bool sdrv_registered;
+ struct platform_device *sdrv_pdev;
int num_evt_channels;
struct xdrv_evtchnl_info *evt_chnls;
struct sdev_card_plat_data cfg_plat_data;
@@ -138,6 +168,132 @@ static struct snd_pcm_hardware sdrv_pcm_hw_default = {
.fifo_size = 0,
};

+static int sdrv_new_pcm(struct sdev_card_info *card_info,
+ struct cfg_pcm_instance *instance_config,
+ struct sdev_pcm_instance_info *pcm_instance_info)
+{
+ return 0;
+}
+
+static int sdrv_probe(struct platform_device *pdev)
+{
+ struct sdev_card_info *card_info;
+ struct sdev_card_plat_data *platdata;
+ struct snd_card *card;
+ int ret, i;
+
+ platdata = dev_get_platdata(&pdev->dev);
+
+ dev_dbg(&pdev->dev, "Creating virtual sound card\n");
+
+ ret = snd_card_new(&pdev->dev, 0, XENSND_DRIVER_NAME, THIS_MODULE,
+ sizeof(struct sdev_card_info), &card);
+ if (ret < 0)
+ return ret;
+
+ card_info = card->private_data;
+ card_info->xdrv_info = platdata->xdrv_info;
+ card_info->card = card;
+ card_info->pcm_instances = devm_kcalloc(&pdev->dev,
+ platdata->cfg_card.num_pcm_instances,
+ sizeof(struct sdev_pcm_instance_info), GFP_KERNEL);
+ if (!card_info->pcm_instances) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ card_info->num_pcm_instances = platdata->cfg_card.num_pcm_instances;
+ card_info->pcm_hw = platdata->cfg_card.pcm_hw;
+
+ for (i = 0; i < platdata->cfg_card.num_pcm_instances; i++) {
+ ret = sdrv_new_pcm(card_info,
+ &platdata->cfg_card.pcm_instances[i],
+ &card_info->pcm_instances[i]);
+ if (ret < 0)
+ goto fail;
+ }
+
+ strncpy(card->driver, XENSND_DRIVER_NAME, sizeof(card->driver));
+ strncpy(card->shortname, platdata->cfg_card.name_short,
+ sizeof(card->shortname));
+ strncpy(card->longname, platdata->cfg_card.name_long,
+ sizeof(card->longname));
+
+ ret = snd_card_register(card);
+ if (ret < 0)
+ goto fail;
+
+ platform_set_drvdata(pdev, card);
+ return 0;
+
+fail:
+ snd_card_free(card);
+ return ret;
+}
+
+static int sdrv_remove(struct platform_device *pdev)
+{
+ struct sdev_card_info *info;
+ struct snd_card *card = platform_get_drvdata(pdev);
+
+ info = card->private_data;
+ dev_dbg(&pdev->dev, "Removing virtual sound card %d\n",
+ info->card->number);
+ snd_card_free(card);
+ return 0;
+}
+
+static struct platform_driver sdrv_info = {
+ .probe = sdrv_probe,
+ .remove = sdrv_remove,
+ .driver = {
+ .name = XENSND_DRIVER_NAME,
+ },
+};
+
+static void sdrv_cleanup(struct xdrv_info *drv_info)
+{
+ if (!drv_info->sdrv_registered)
+ return;
+
+ if (drv_info->sdrv_pdev) {
+ struct platform_device *sdrv_pdev;
+
+ sdrv_pdev = drv_info->sdrv_pdev;
+ if (sdrv_pdev)
+ platform_device_unregister(sdrv_pdev);
+ }
+ platform_driver_unregister(&sdrv_info);
+ drv_info->sdrv_registered = false;
+}
+
+static int sdrv_init(struct xdrv_info *drv_info)
+{
+ struct platform_device *sdrv_pdev;
+ int ret;
+
+ ret = platform_driver_register(&sdrv_info);
+ if (ret < 0)
+ return ret;
+
+ drv_info->sdrv_registered = true;
+ /* pass card configuration via platform data */
+ sdrv_pdev = platform_device_register_data(NULL,
+ XENSND_DRIVER_NAME, 0, &drv_info->cfg_plat_data,
+ sizeof(drv_info->cfg_plat_data));
+ if (IS_ERR(sdrv_pdev))
+ goto fail;
+
+ drv_info->sdrv_pdev = sdrv_pdev;
+ return 0;
+
+fail:
+ dev_err(&drv_info->xb_dev->dev,
+ "failed to register virtual sound driver\n");
+ sdrv_cleanup(drv_info);
+ return -ENODEV;
+}
+
static irqreturn_t xdrv_evtchnl_interrupt(int irq, void *dev_id)
{
struct xdrv_evtchnl_info *channel = dev_id;
@@ -830,6 +986,7 @@ static int cfg_card(struct xdrv_info *drv_info,

static void xdrv_remove_internal(struct xdrv_info *drv_info)
{
+ sdrv_cleanup(drv_info);
xdrv_evtchnl_free_all(drv_info);
}

@@ -1018,7 +1175,7 @@ static int xdrv_be_on_initwait(struct xdrv_info *drv_info)

static inline int xdrv_be_on_connected(struct xdrv_info *drv_info)
{
- return 0;
+ return sdrv_init(drv_info);
}

static inline void xdrv_be_on_disconnected(struct xdrv_info *drv_info)
--
2.7.4