[PATCH v2 1/6] staging: most: sound: create one sound card w/ multiple PCM devices per MOST device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch avoids that a sound card is created and registered with ALSA
every time a channel is being linked. Instead the channels are hooked on
the same card, which is registered not until the final link has been added
to the component. The string provided by user space that used to be the
card name becomes the PCM device name. The user space API to add a link is
being expanded by a "create" flag to trigger the registration.

Signed-off-by: Christian Gromm <christian.gromm@xxxxxxxxxxxxx>
---
v2:
	- push audio apdaper to list right afer its initialization

Reported-by: Dan Carpenter <dan.carpenter@xxxxxxxxxx>
	- mention user space API change in description
	- assign value to variable ret before jumping to error handling
	- remove unnecessary variable initializations
	- fix if statements when iterating audio adapter list  
	- use correct variable in sizeof operator
	- store PCM device name

 drivers/staging/most/sound/sound.c | 129 +++++++++++++++++++++++++------------
 1 file changed, 88 insertions(+), 41 deletions(-)

diff --git a/drivers/staging/most/sound/sound.c b/drivers/staging/most/sound/sound.c
index 89b02fc..8ed37d6 100644
--- a/drivers/staging/most/sound/sound.c
+++ b/drivers/staging/most/sound/sound.c
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/printk.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -20,7 +21,6 @@
 
 #define DRIVER_NAME "sound"
 
-static struct list_head dev_list;
 static struct core_component comp;
 
 /**
@@ -56,6 +56,17 @@ struct channel {
 	void (*copy_fn)(void *alsa, void *most, unsigned int bytes);
 };
 
+struct sound_adapter {
+	struct list_head dev_list;
+	struct most_interface *iface;
+	struct snd_card *card;
+	struct list_head list;
+	bool registered;
+	int pcm_dev_idx;
+};
+
+static struct list_head adpt_list;
+
 #define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \
 		       SNDRV_PCM_INFO_MMAP_VALID | \
 		       SNDRV_PCM_INFO_BATCH | \
@@ -157,9 +168,10 @@ static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes)
 static struct channel *get_channel(struct most_interface *iface,
 				   int channel_id)
 {
+	struct sound_adapter *adpt = iface->priv;
 	struct channel *channel, *tmp;
 
-	list_for_each_entry_safe(channel, tmp, &dev_list, list) {
+	list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) {
 		if ((channel->iface == iface) && (channel->id == channel_id))
 			return channel;
 	}
@@ -460,7 +472,7 @@ static const struct snd_pcm_ops pcm_ops = {
 };
 
 static int split_arg_list(char *buf, char **card_name, u16 *ch_num,
-			  char **sample_res)
+			  char **sample_res, u8 *create)
 {
 	char *num;
 	int ret;
@@ -479,6 +491,9 @@ static int split_arg_list(char *buf, char **card_name, u16 *ch_num,
 	*sample_res = strsep(&buf, ".\n");
 	if (!*sample_res)
 		goto err;
+
+	if (buf && !strcmp(buf, "create"))
+		*create = 1;
 	return 0;
 
 err:
@@ -536,6 +551,19 @@ static int audio_set_hw_params(struct snd_pcm_hardware *pcm_hw,
 	return 0;
 }
 
+static void release_adapter(struct sound_adapter *adpt)
+{
+	struct channel *channel, *tmp;
+
+	list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) {
+		list_del(&channel->list);
+		kfree(channel);
+	}
+	snd_card_free(adpt->card);
+	list_del(&adpt->list);
+	kfree(adpt);
+}
+
 /**
  * audio_probe_channel - probe function of the driver module
  * @iface: pointer to interface instance
@@ -553,7 +581,7 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id,
 			       char *arg_list)
 {
 	struct channel *channel;
-	struct snd_card *card;
+	struct sound_adapter *adpt;
 	struct snd_pcm *pcm;
 	int playback_count = 0;
 	int capture_count = 0;
@@ -561,6 +589,7 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id,
 	int direction;
 	char *card_name;
 	u16 ch_num;
+	u8 create = 0;
 	char *sample_res;
 
 	if (!iface)
@@ -571,6 +600,39 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id,
 		return -EINVAL;
 	}
 
+	ret = split_arg_list(arg_list, &card_name, &ch_num, &sample_res,
+			     &create);
+	if (ret < 0)
+		return ret;
+
+	list_for_each_entry(adpt, &adpt_list, list) {
+		if (adpt->iface != iface)
+			continue;
+		if (adpt->registered)
+			return -ENOSPC;
+		adpt->pcm_dev_idx++;
+		goto skip_adpt_alloc;
+	}
+	adpt = kzalloc(sizeof(*adpt), GFP_KERNEL);
+	if (!adpt)
+		return -ENOMEM;
+
+	adpt->iface = iface;
+	INIT_LIST_HEAD(&adpt->dev_list);
+	iface->priv = adpt;
+	list_add_tail(&adpt->list, &adpt_list);
+	ret = snd_card_new(&iface->dev, -1, card_name, THIS_MODULE,
+			   sizeof(*channel), &adpt->card);
+	if (ret < 0)
+		return ret;
+	snprintf(adpt->card->driver, sizeof(adpt->card->driver),
+		 "%s", DRIVER_NAME);
+	snprintf(adpt->card->shortname, sizeof(adpt->card->shortname),
+		 "Microchip MOST:%d", adpt->card->number);
+	snprintf(adpt->card->longname, sizeof(adpt->card->longname),
+		 "%s at %s, ch %d", adpt->card->shortname, iface->description,
+		 channel_id);
+skip_adpt_alloc:
 	if (get_channel(iface, channel_id)) {
 		pr_err("channel (%s:%d) is already linked\n",
 		       iface->description, channel_id);
@@ -584,53 +646,43 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id,
 		capture_count = 1;
 		direction = SNDRV_PCM_STREAM_CAPTURE;
 	}
-
-	ret = split_arg_list(arg_list, &card_name, &ch_num, &sample_res);
-	if (ret < 0)
-		return ret;
-
-	ret = snd_card_new(&iface->dev, -1, card_name, THIS_MODULE,
-			   sizeof(*channel), &card);
-	if (ret < 0)
-		return ret;
-
-	channel = card->private_data;
-	channel->card = card;
+	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+	if (!channel) {
+		ret = -ENOMEM;
+		goto err_free_card;
+	}
+	channel->card = adpt->card;
 	channel->cfg = cfg;
 	channel->iface = iface;
 	channel->id = channel_id;
 	init_waitqueue_head(&channel->playback_waitq);
+	list_add_tail(&channel->list, &adpt->dev_list);
 
 	ret = audio_set_hw_params(&channel->pcm_hardware, ch_num, sample_res,
 				  cfg);
 	if (ret)
 		goto err_free_card;
 
-	snprintf(card->driver, sizeof(card->driver), "%s", DRIVER_NAME);
-	snprintf(card->shortname, sizeof(card->shortname), "Microchip MOST:%d",
-		 card->number);
-	snprintf(card->longname, sizeof(card->longname), "%s at %s, ch %d",
-		 card->shortname, iface->description, channel_id);
+	ret = snd_pcm_new(adpt->card, card_name, adpt->pcm_dev_idx,
+			  playback_count, capture_count, &pcm);
 
-	ret = snd_pcm_new(card, card_name, 0, playback_count,
-			  capture_count, &pcm);
 	if (ret < 0)
 		goto err_free_card;
 
 	pcm->private_data = channel;
-
+	snprintf(pcm->name, sizeof(pcm->name), card_name);
 	snd_pcm_set_ops(pcm, direction, &pcm_ops);
 
-	ret = snd_card_register(card);
-	if (ret < 0)
-		goto err_free_card;
-
-	list_add_tail(&channel->list, &dev_list);
-
+	if (create) {
+		ret = snd_card_register(adpt->card);
+		if (ret < 0)
+			goto err_free_card;
+		adpt->registered = true;
+	}
 	return 0;
 
 err_free_card:
-	snd_card_free(card);
+	release_adapter(adpt);
 	return ret;
 }
 
@@ -647,6 +699,7 @@ static int audio_disconnect_channel(struct most_interface *iface,
 				    int channel_id)
 {
 	struct channel *channel;
+	struct sound_adapter *adpt = iface->priv;
 
 	channel = get_channel(iface, channel_id);
 	if (!channel) {
@@ -656,8 +709,10 @@ static int audio_disconnect_channel(struct most_interface *iface,
 	}
 
 	list_del(&channel->list);
-	snd_card_free(channel->card);
 
+	kfree(channel);
+	if (list_empty(&adpt->dev_list))
+		release_adapter(adpt);
 	return 0;
 }
 
@@ -733,22 +788,14 @@ static int __init audio_init(void)
 {
 	pr_info("init()\n");
 
-	INIT_LIST_HEAD(&dev_list);
+	INIT_LIST_HEAD(&adpt_list);
 
 	return most_register_component(&comp);
 }
 
 static void __exit audio_exit(void)
 {
-	struct channel *channel, *tmp;
-
 	pr_info("exit()\n");
-
-	list_for_each_entry_safe(channel, tmp, &dev_list, list) {
-		list_del(&channel->list);
-		snd_card_free(channel->card);
-	}
-
 	most_deregister_component(&comp);
 }
 
-- 
2.7.4

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel



[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux