From f70575805708cabdedea7498aaa3f710fde4d920 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 31 Jan 2024 03:29:01 +0000
Subject: [PATCH] add lvds1024*800

---
 kernel/drivers/staging/most/sound/sound.c |  275 ++++++++++++++++++++++++++----------------------------
 1 files changed, 134 insertions(+), 141 deletions(-)

diff --git a/kernel/drivers/staging/most/sound/sound.c b/kernel/drivers/staging/most/sound/sound.c
index fd9245d..b7666a7 100644
--- a/kernel/drivers/staging/most/sound/sound.c
+++ b/kernel/drivers/staging/most/sound/sound.c
@@ -10,18 +10,19 @@
 #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>
 #include <sound/pcm_params.h>
 #include <linux/sched.h>
 #include <linux/kthread.h>
-#include <most/core.h>
+#include <linux/most.h>
 
 #define DRIVER_NAME "sound"
+#define STRING_SIZE	80
 
-static struct list_head dev_list;
-static struct core_component comp;
+static struct most_component comp;
 
 /**
  * struct channel - private structure to keep channel specific data
@@ -49,12 +50,21 @@
 	unsigned int period_pos;
 	unsigned int buffer_pos;
 	bool is_stream_running;
-
 	struct task_struct *playback_task;
 	wait_queue_head_t playback_waitq;
-
 	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 | \
@@ -159,13 +169,13 @@
 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;
 	}
-
 	return NULL;
 }
 
@@ -209,7 +219,6 @@
 		channel->period_pos -= runtime->period_size;
 		return true;
 	}
-
 	return false;
 }
 
@@ -249,7 +258,6 @@
 		if (period_elapsed)
 			snd_pcm_period_elapsed(channel->substream);
 	}
-
 	return 0;
 }
 
@@ -267,6 +275,7 @@
 	struct channel *channel = substream->private_data;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct most_channel_config *cfg = channel->cfg;
+	int ret;
 
 	channel->substream = substream;
 
@@ -279,11 +288,12 @@
 		}
 	}
 
-	if (most_start_channel(channel->iface, channel->id, &comp)) {
+	ret = most_start_channel(channel->iface, channel->id, &comp);
+	if (ret) {
 		pr_err("most_start_channel() failed!\n");
 		if (cfg->direction == MOST_CH_TX)
 			kthread_stop(channel->playback_task);
-		return -EBUSY;
+		return ret;
 	}
 
 	runtime->hw = channel->pcm_hardware;
@@ -307,48 +317,7 @@
 	if (channel->cfg->direction == MOST_CH_TX)
 		kthread_stop(channel->playback_task);
 	most_stop_channel(channel->iface, channel->id, &comp);
-
 	return 0;
-}
-
-/**
- * pcm_hw_params - implements hw_params callback function for PCM middle layer
- * @substream: sub-stream pointer
- * @hw_params: contains the hardware parameters set by the application
- *
- * This is called when the hardware parameters is set by the application, that
- * is, once when the buffer size, the period size, the format, etc. are defined
- * for the PCM substream. Many hardware setups should be done is this callback,
- * including the allocation of buffers.
- *
- * Returns 0 on success or error code otherwise.
- */
-static int pcm_hw_params(struct snd_pcm_substream *substream,
-			 struct snd_pcm_hw_params *hw_params)
-{
-	struct channel *channel = substream->private_data;
-
-	if ((params_channels(hw_params) > channel->pcm_hardware.channels_max) ||
-	    (params_channels(hw_params) < channel->pcm_hardware.channels_min)) {
-		pr_err("Requested number of channels not supported.\n");
-		return -EINVAL;
-	}
-	return snd_pcm_lib_alloc_vmalloc_buffer(substream,
-						params_buffer_bytes(hw_params));
-}
-
-/**
- * pcm_hw_free - implements hw_free callback function for PCM middle layer
- * @substream: substream pointer
- *
- * This is called to release the resources allocated via hw_params.
- * This function will be always called before the close callback is called.
- *
- * Returns 0 on success or error code otherwise.
- */
-static int pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	return snd_pcm_lib_free_vmalloc_buffer(substream);
 }
 
 /**
@@ -389,14 +358,10 @@
 			channel->copy_fn = most_to_alsa_copy32;
 	}
 
-	if (!channel->copy_fn) {
-		pr_err("unsupported format\n");
+	if (!channel->copy_fn)
 		return -EINVAL;
-	}
-
 	channel->period_pos = 0;
 	channel->buffer_pos = 0;
-
 	return 0;
 }
 
@@ -425,7 +390,6 @@
 		return 0;
 
 	default:
-		pr_info("%s(), invalid\n", __func__);
 		return -EINVAL;
 	}
 	return 0;
@@ -452,26 +416,16 @@
 static const struct snd_pcm_ops pcm_ops = {
 	.open       = pcm_open,
 	.close      = pcm_close,
-	.ioctl      = snd_pcm_lib_ioctl,
-	.hw_params  = pcm_hw_params,
-	.hw_free    = pcm_hw_free,
 	.prepare    = pcm_prepare,
 	.trigger    = pcm_trigger,
 	.pointer    = pcm_pointer,
-	.page       = snd_pcm_lib_get_vmalloc_page,
 };
 
-static int split_arg_list(char *buf, char **card_name, u16 *ch_num,
-			  char **sample_res)
+static int split_arg_list(char *buf, u16 *ch_num, char **sample_res)
 {
 	char *num;
 	int ret;
 
-	*card_name = strsep(&buf, ".");
-	if (!*card_name) {
-		pr_err("Missing sound card name\n");
-		return -EIO;
-	}
 	num = strsep(&buf, "x");
 	if (!num)
 		goto err;
@@ -485,7 +439,7 @@
 
 err:
 	pr_err("Bad PCM format\n");
-	return -EIO;
+	return -EINVAL;
 }
 
 static const struct sample_resolution_info {
@@ -510,7 +464,7 @@
 			goto found;
 	}
 	pr_err("Unsupported PCM format\n");
-	return -EIO;
+	return -EINVAL;
 
 found:
 	if (!ch_num) {
@@ -538,6 +492,20 @@
 	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);
+	}
+	if (adpt->card)
+		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
@@ -552,31 +520,59 @@
  */
 static int audio_probe_channel(struct most_interface *iface, int channel_id,
 			       struct most_channel_config *cfg,
-			       char *arg_list)
+			       char *device_name, 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;
 	int ret;
 	int direction;
-	char *card_name;
 	u16 ch_num;
 	char *sample_res;
-
-	if (!iface)
-		return -EINVAL;
+	char arg_list_cpy[STRING_SIZE];
 
 	if (cfg->data_type != MOST_CH_SYNC) {
 		pr_err("Incompatible channel type\n");
 		return -EINVAL;
 	}
+	strlcpy(arg_list_cpy, arg_list, STRING_SIZE);
+	ret = split_arg_list(arg_list_cpy, &ch_num, &sample_res);
+	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->driver_dev, -1, "INIC", THIS_MODULE,
+			   sizeof(*channel), &adpt->card);
+	if (ret < 0)
+		goto err_free_adpt;
+	snprintf(adpt->card->driver, sizeof(adpt->card->driver),
+		 "%s", DRIVER_NAME);
+	snprintf(adpt->card->shortname, sizeof(adpt->card->shortname),
+		 "Microchip INIC");
+	snprintf(adpt->card->longname, sizeof(adpt->card->longname),
+		 "%s at %s", adpt->card->shortname, iface->description);
+skip_adpt_alloc:
 	if (get_channel(iface, channel_id)) {
 		pr_err("channel (%s:%d) is already linked\n",
 		       iface->description, channel_id);
-		return -EINVAL;
+		return -EEXIST;
 	}
 
 	if (cfg->direction == MOST_CH_TX) {
@@ -586,54 +582,58 @@
 		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_adpt;
+	}
+	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;
+		goto err_free_adpt;
 
-	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, device_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;
+		goto err_free_adpt;
 
 	pcm->private_data = channel;
-
+	strscpy(pcm->name, device_name, sizeof(pcm->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);
-
+	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
 	return 0;
 
-err_free_card:
-	snd_card_free(card);
+err_free_adpt:
+	release_adapter(adpt);
 	return ret;
+}
+
+static int audio_create_sound_card(void)
+{
+	int ret;
+	struct sound_adapter *adpt;
+
+	list_for_each_entry(adpt, &adpt_list, list) {
+		if (!adpt->registered)
+			goto adpt_alloc;
+	}
+	return -ENODEV;
+adpt_alloc:
+	ret = snd_card_register(adpt->card);
+	if (ret < 0) {
+		release_adapter(adpt);
+		return ret;
+	}
+	adpt->registered = true;
+	return 0;
 }
 
 /**
@@ -649,17 +649,17 @@
 				    int channel_id)
 {
 	struct channel *channel;
+	struct sound_adapter *adpt = iface->priv;
 
 	channel = get_channel(iface, channel_id);
-	if (!channel) {
-		pr_err("sound_disconnect_channel(), invalid channel %d\n",
-		       channel_id);
+	if (!channel)
 		return -EINVAL;
-	}
 
 	list_del(&channel->list);
-	snd_card_free(channel->card);
 
+	kfree(channel);
+	if (list_empty(&adpt->dev_list))
+		release_adapter(adpt);
 	return 0;
 }
 
@@ -677,20 +677,13 @@
 	struct channel *channel = get_channel(mbo->ifp, mbo->hdm_channel_id);
 	bool period_elapsed = false;
 
-	if (!channel) {
-		pr_err("sound_rx_completion(), invalid channel %d\n",
-		       mbo->hdm_channel_id);
+	if (!channel)
 		return -EINVAL;
-	}
-
 	if (channel->is_stream_running)
 		period_elapsed = copy_data(channel, mbo);
-
 	most_put_mbo(mbo);
-
 	if (period_elapsed)
 		snd_pcm_period_elapsed(channel->substream);
-
 	return 0;
 }
 
@@ -709,48 +702,48 @@
 {
 	struct channel *channel = get_channel(iface, channel_id);
 
-	if (!channel) {
-		pr_err("sound_tx_completion(), invalid channel %d\n",
-		       channel_id);
+	if (!channel)
 		return -EINVAL;
-	}
 
 	wake_up_interruptible(&channel->playback_waitq);
-
 	return 0;
 }
 
 /**
- * Initialization of the struct core_component
+ * Initialization of the struct most_component
  */
-static struct core_component comp = {
+static struct most_component comp = {
+	.mod = THIS_MODULE,
 	.name = DRIVER_NAME,
 	.probe_channel = audio_probe_channel,
 	.disconnect_channel = audio_disconnect_channel,
 	.rx_completion = audio_rx_completion,
 	.tx_completion = audio_tx_completion,
+	.cfg_complete = audio_create_sound_card,
 };
 
 static int __init audio_init(void)
 {
-	pr_info("init()\n");
+	int ret;
 
-	INIT_LIST_HEAD(&dev_list);
+	INIT_LIST_HEAD(&adpt_list);
 
-	return most_register_component(&comp);
+	ret = most_register_component(&comp);
+	if (ret) {
+		pr_err("Failed to register %s\n", comp.name);
+		return ret;
+	}
+	ret = most_register_configfs_subsys(&comp);
+	if (ret) {
+		pr_err("Failed to register %s configfs subsys\n", comp.name);
+		most_deregister_component(&comp);
+	}
+	return ret;
 }
 
 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_configfs_subsys(&comp);
 	most_deregister_component(&comp);
 }
 

--
Gitblit v1.6.2