[alsa-devel] [PATCH] ASoC: s3c24xx platform: Fix s3c2410_dma_started called at wrong time

Shine Liu shinel at foxmail.com
Fri Aug 21 12:00:39 CEST 2009


> 
> It's called ultimately by user space; within ASoC it's always called by
> the core trigger function in the fixed order that it has.  The open()
> callback would be a safe place to do the setup - that's called before
> anything else.
> 
> 

I've finished a draft patch in the callback manner. Waiting for any
suggestion. Thanks.


-----------------------------------------------------------------

diff -Nur a/arch/arm/plat-s3c24xx/include/plat/dma-plat.h b/arch/arm/plat-s3c24xx/include/plat/dma-plat.h
--- a/arch/arm/plat-s3c24xx/include/plat/dma-plat.h	2009-08-14 06:43:34.000000000 +0800
+++ b/arch/arm/plat-s3c24xx/include/plat/dma-plat.h	2009-08-21 14:14:12.000000000 +0800
@@ -76,6 +76,27 @@
 
 extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map);
 
+enum s3c24xx_dma_channel_event {
+	CHANNEL_EVENT_START,
+	CHANNEL_EVENT_STOP,
+	CHANNEL_EVENT_MAX,
+};
+
+struct s3c24xx_dma_channel_trigger {
+	unsigned int channel;
+	/* trigger event */
+	enum s3c24xx_dma_channel_event event;
+	/* pravate date to the callback function */
+	void *private_data;
+	/* callback funtion to generate the DMA REQ signal */
+	void (*gen_request)(void *private_data);
+	/* callback funtion to end the DMA request */
+	void (*end_request)(void *private_data);
+};
+
+/* trigger the DMA engine to start, called from the client */
+extern void s3c24xx_dma_trigger(struct s3c24xx_dma_channel_trigger *client);
+
 /* DMA init code, called from the cpu support code */
 
 extern int s3c2410_dma_init(void);
diff -Nur a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
--- a/arch/arm/plat-s3c24xx/dma.c	2009-08-14 06:43:34.000000000 +0800
+++ b/arch/arm/plat-s3c24xx/dma.c	2009-08-21 14:30:41.000000000 +0800
@@ -1008,6 +1008,34 @@
 
 EXPORT_SYMBOL(s3c2410_dma_ctrl);
 
+void s3c24xx_dma_trigger(struct s3c24xx_dma_channel_trigger *client)
+{
+	if(!client || !(client->channel < DMACH_MAX)) {
+ 		pr_debug("%s: Invalid parameter\n", __func__);
+		return;
+	}
+
+	switch(client->event) {
+	case CHANNEL_EVENT_START:
+		s3c2410_dma_ctrl(client->channel, S3C2410_DMAOP_START);
+		if(client->gen_request)
+			client->gen_request(client->private_data);
+		s3c2410_dma_ctrl(client->channel, S3C2410_DMAOP_STARTED);
+		return;
+	case CHANNEL_EVENT_STOP:
+		s3c2410_dma_ctrl(client->channel, S3C2410_DMAOP_STOP);
+		if(client->end_request)
+			client->end_request(client->private_data);
+		/* should be set to a vaild value in the next request */
+		client->channel = DMACH_MAX;
+		return;
+	default:
+		pr_debug("%s: Invalid event\n", __func__);
+	}
+}
+
+EXPORT_SYMBOL(s3c24xx_dma_trigger);
+
 /* DMA configuration for each channel
  *
  * DISRCC -> source of the DMA (AHB,APB)
diff -Nur a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c	2009-08-14 06:43:34.000000000 +0800
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c	2009-08-21 15:08:07.000000000 +0800
@@ -38,6 +38,7 @@
 
 #include <plat/regs-iis.h>
 
+#define __USE_S3C24XX_PCM_RUNTIME
 #include "s3c24xx-pcm.h"
 #include "s3c24xx-i2s.h"
 
@@ -278,6 +279,7 @@
 static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 			       struct snd_soc_dai *dai)
 {
+	struct s3c24xx_pcm_runtime_data *prtd = substream->runtime->private_data;
 	int ret = 0;
 
 	pr_debug("Entered %s\n", __func__);
@@ -292,24 +294,32 @@
 				goto exit_err;
 		}
 
+		spin_lock(&prtd->lock);
+		prtd->client.private_data= (void *)1;
 		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-			s3c24xx_snd_rxctrl(1);
+			prtd->client.gen_request = (void *)s3c24xx_snd_rxctrl;
 		else
-			s3c24xx_snd_txctrl(1);
+			prtd->client.gen_request = (void *)s3c24xx_snd_txctrl;
+		spin_unlock(&prtd->lock);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		spin_lock(&prtd->lock);
+		prtd->client.private_data= (void *)0;
 		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-			s3c24xx_snd_rxctrl(0);
+			prtd->client.end_request = (void *)s3c24xx_snd_rxctrl;
 		else
-			s3c24xx_snd_txctrl(0);
+			prtd->client.end_request = (void *)s3c24xx_snd_txctrl;
+		spin_unlock(&prtd->lock);
 		break;
 	default:
 		ret = -EINVAL;
-		break;
+		goto exit_err;
 	}
 
+	s3c24xx_dma_trigger(&prtd->client);
+
 exit_err:
 	return ret;
 }
diff -Nur a/sound/soc/s3c24xx/s3c24xx-pcm.h b/sound/soc/s3c24xx/s3c24xx-pcm.h
--- a/sound/soc/s3c24xx/s3c24xx-pcm.h	2009-08-14 06:43:34.000000000 +0800
+++ b/sound/soc/s3c24xx/s3c24xx-pcm.h	2009-08-21 14:40:05.000000000 +0800
@@ -22,6 +22,25 @@
 	int dma_size;			/* Size of the DMA transfer */
 };
 
+#ifdef __USE_S3C24XX_PCM_RUNTIME
+
+#include <plat/dma-plat.h>
+
+struct s3c24xx_pcm_runtime_data {
+	spinlock_t lock;
+	int state;
+	unsigned int dma_loaded;
+	unsigned int dma_limit;
+	unsigned int dma_period;
+	dma_addr_t dma_start;
+	dma_addr_t dma_pos;
+	dma_addr_t dma_end;
+	struct s3c24xx_pcm_dma_params *params;
+	struct s3c24xx_dma_channel_trigger client;
+};
+
+#endif
+
 #define S3C24XX_DAI_I2S			0
 
 /* platform data */
diff -Nur a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c
--- a/sound/soc/s3c24xx/s3c24xx-pcm.c	2009-08-14 06:43:34.000000000 +0800
+++ b/sound/soc/s3c24xx/s3c24xx-pcm.c	2009-08-21 14:47:29.000000000 +0800
@@ -31,6 +31,7 @@
 #include <mach/dma.h>
 #include <plat/audio.h>
 
+#define __USE_S3C24XX_PCM_RUNTIME
 #include "s3c24xx-pcm.h"
 
 static const struct snd_pcm_hardware s3c24xx_pcm_hardware = {
@@ -54,18 +55,6 @@
 	.fifo_size		= 32,
 };
 
-struct s3c24xx_runtime_data {
-	spinlock_t lock;
-	int state;
-	unsigned int dma_loaded;
-	unsigned int dma_limit;
-	unsigned int dma_period;
-	dma_addr_t dma_start;
-	dma_addr_t dma_pos;
-	dma_addr_t dma_end;
-	struct s3c24xx_pcm_dma_params *params;
-};
-
 /* s3c24xx_pcm_enqueue
  *
  * place a dma buffer onto the queue for the dma system
@@ -73,7 +62,7 @@
 */
 static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream)
 {
-	struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+	struct s3c24xx_pcm_runtime_data *prtd = substream->runtime->private_data;
 	dma_addr_t pos = prtd->dma_pos;
 	int ret;
 
@@ -110,7 +99,7 @@
 				enum s3c2410_dma_buffresult result)
 {
 	struct snd_pcm_substream *substream = dev_id;
-	struct s3c24xx_runtime_data *prtd;
+	struct s3c24xx_pcm_runtime_data *prtd;
 
 	pr_debug("Entered %s\n", __func__);
 
@@ -135,7 +124,7 @@
 	struct snd_pcm_hw_params *params)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct s3c24xx_runtime_data *prtd = runtime->private_data;
+	struct s3c24xx_pcm_runtime_data *prtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct s3c24xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
 	unsigned long totbytes = params_buffer_bytes(params);
@@ -187,7 +176,7 @@
 
 static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-	struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+	struct s3c24xx_pcm_runtime_data *prtd = substream->runtime->private_data;
 
 	pr_debug("Entered %s\n", __func__);
 
@@ -204,7 +193,7 @@
 
 static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
 {
-	struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+	struct s3c24xx_pcm_runtime_data *prtd = substream->runtime->private_data;
 	int ret = 0;
 
 	pr_debug("Entered %s\n", __func__);
@@ -242,7 +231,7 @@
 
 static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-	struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+	struct s3c24xx_pcm_runtime_data *prtd = substream->runtime->private_data;
 	int ret = 0;
 
 	pr_debug("Entered %s\n", __func__);
@@ -254,15 +243,15 @@
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		prtd->state |= ST_RUNNING;
-		s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START);
-		s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STARTED);
+		prtd->client.channel = prtd->params->channel;
+		prtd->client.event = CHANNEL_EVENT_START;
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		prtd->state &= ~ST_RUNNING;
-		s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP);
+		prtd->client.event = CHANNEL_EVENT_STOP;
 		break;
 
 	default:
@@ -279,7 +268,7 @@
 s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct s3c24xx_runtime_data *prtd = runtime->private_data;
+	struct s3c24xx_pcm_runtime_data *prtd = runtime->private_data;
 	unsigned long res;
 	dma_addr_t src, dst;
 
@@ -314,16 +303,18 @@
 static int s3c24xx_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct s3c24xx_runtime_data *prtd;
+	struct s3c24xx_pcm_runtime_data *prtd;
 
 	pr_debug("Entered %s\n", __func__);
 
 	snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware);
 
-	prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL);
+	prtd = kzalloc(sizeof(struct s3c24xx_pcm_runtime_data), GFP_KERNEL);
 	if (prtd == NULL)
 		return -ENOMEM;
 
+	prtd->client.channel = DMACH_MAX;
+
 	spin_lock_init(&prtd->lock);
 
 	runtime->private_data = prtd;
@@ -333,7 +324,7 @@
 static int s3c24xx_pcm_close(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct s3c24xx_runtime_data *prtd = runtime->private_data;
+	struct s3c24xx_pcm_runtime_data *prtd = runtime->private_data;
 
 	pr_debug("Entered %s\n", __func__);
 





More information about the Alsa-devel mailing list