Title: [4196] trunk/sound: bug[#3577] add dmix support for AD1981, enable mmap for the soundcard driver
Revision
4196
Author
cliff
Date
2008-01-31 03:56:08 -0600 (Thu, 31 Jan 2008)

Log Message

bug[#3577] add dmix support for AD1981,enable mmap for the soundcard driver

Diffstat

 core/pcm_native.c          |    8 +
 soc/blackfin/Kconfig       |    7 +
 soc/blackfin/bf5xx-pcm.c   |  184 +++++++++++++++++++++++++++++++++++++--------
 soc/blackfin/bf5xx-sport.h |    9 +-
 soc/codecs/ad1980.c        |    5 -
 5 files changed, 180 insertions(+), 33 deletions(-)

Modified Paths

Diff

Modified: trunk/sound/core/pcm_native.c (4195 => 4196)


--- trunk/sound/core/pcm_native.c	2008-01-31 04:27:30 UTC (rev 4195)
+++ trunk/sound/core/pcm_native.c	2008-01-31 09:56:08 UTC (rev 4196)
@@ -3413,6 +3413,12 @@
 }
 #endif /* CONFIG_SND_SUPPORT_OLD_API */
 
+unsigned long dummy_get_unmapped_area(struct file *file, unsigned long addr,
+				      unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+	return 0;
+}
+
 /*
  *  Register section
  */
@@ -3429,6 +3435,7 @@
 		.compat_ioctl = 	snd_pcm_ioctl_compat,
 		.mmap =			snd_pcm_mmap,
 		.fasync =		snd_pcm_fasync,
+		.get_unmapped_area =	dummy_get_unmapped_area,
 	},
 	{
 		.owner =		THIS_MODULE,
@@ -3441,5 +3448,6 @@
 		.compat_ioctl = 	snd_pcm_ioctl_compat,
 		.mmap =			snd_pcm_mmap,
 		.fasync =		snd_pcm_fasync,
+		.get_unmapped_area =	dummy_get_unmapped_area,
 	}
 };

Modified: trunk/sound/soc/blackfin/Kconfig (4195 => 4196)


--- trunk/sound/soc/blackfin/Kconfig	2008-01-31 04:27:30 UTC (rev 4195)
+++ trunk/sound/soc/blackfin/Kconfig	2008-01-31 09:56:08 UTC (rev 4196)
@@ -6,6 +6,13 @@
 	  the BF5xx AC97 interface.  You will also need
 	  to select the audio interfaces to support below.
 
+config SND_MMAP_SUPPORT
+	bool "Enable True MMAP Support"
+	depends on SND_BF5XX_SOC
+	default y
+	help
+	  Say y if you want driver to support mmap way.
+
 config SND_BF5XX_AC97
 	tristate
 	select SND_AC97_CODEC

Modified: trunk/sound/soc/blackfin/bf5xx-pcm.c (4195 => 4196)


--- trunk/sound/soc/blackfin/bf5xx-pcm.c	2008-01-31 04:27:30 UTC (rev 4195)
+++ trunk/sound/soc/blackfin/bf5xx-pcm.c	2008-01-31 09:56:08 UTC (rev 4196)
@@ -27,12 +27,37 @@
 #include "bf5xx-ac97.h"
 #include "bf5xx-sport.h"
 
+#ifdef CONFIG_SND_MMAP_SUPPORT
+static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
+	 snd_pcm_uframes_t count)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			bf5xx_ac97_pcm32_to_frame(
+					(struct ac97_frame *)sport->tx_dma_buf + sport->tx_pos,
+					(__u32 *)runtime->dma_area+sport->tx_pos, count);
+			sport->tx_pos += runtime->period_size;
+			if (sport->tx_pos >= runtime->buffer_size)
+				sport->tx_pos %= runtime->buffer_size;
+		} else {
+			bf5xx_ac97_frame_to_pcm32(
+					(struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos,
+					(__u32 *)runtime->dma_area+sport->rx_pos, count);
+			sport->rx_pos += runtime->period_size;
+			if (sport->rx_pos >= runtime->buffer_size)
+				sport->rx_pos %= runtime->buffer_size;
+		}
+}
+#endif
 
 static void bf5xx_dma_irq(void *data)
 {
 	struct snd_pcm_substream *pcm = data;
-
-	pr_debug("%s enter \n", __FUNCTION__);
+#ifdef CONFIG_SND_MMAP_SUPPORT
+	struct snd_pcm_runtime *runtime = pcm->runtime;
+	bf5xx_mmap_copy(pcm, runtime->period_size);
+#endif
 	snd_pcm_period_elapsed(pcm);
 }
 
@@ -40,8 +65,23 @@
  * The total rx/tx buffer is for ac97 frame to hold all pcm data
  * is  0x20000 * sizeof(struct ac97_frame) / 4.
  */
+#ifdef CONFIG_SND_MMAP_SUPPORT
 static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
 	.info			= SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_MMAP |
+				   SNDRV_PCM_INFO_MMAP_VALID |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.period_bytes_min	= 2048,
+	.period_bytes_max	= 2048,
+	.periods_min		= 16,
+	.periods_max		= 16,
+	.buffer_bytes_max	= 0x20000, /* 128 kbytes */
+	.fifo_size		= 16,
+};
+#else
+static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_INTERLEAVED |
 				  SNDRV_PCM_INFO_BLOCK_TRANSFER,
 	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
 	.period_bytes_min	= 32,
@@ -51,13 +91,13 @@
 	.buffer_bytes_max	= 0x20000, /* 128 kbytes */
 	.fifo_size		= 16,
 };
+#endif
 
 static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 {
 	size_t size = bf5xx_pcm_hardware.buffer_bytes_max * \
 			sizeof(struct ac97_frame) / 4;
-
 	snd_pcm_lib_malloc_pages(substream, size);
 
 	return 0;
@@ -73,9 +113,41 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct sport_device *sport = runtime->private_data;
-
+#ifdef CONFIG_SND_MMAP_SUPPORT
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (!sport->tx_dma_buf) {
+			sport->tx_dma_buf = dma_alloc_coherent(NULL, \
+				runtime->buffer_size * sizeof(struct ac97_frame), &sport->tx_dma_phy, GFP_KERNEL);
+			if (!sport->tx_dma_buf) {
+				printk(KERN_ERR "Failed to allocate memory for tx dma buf\n");
+				return -ENOMEM;
+			} else
+				memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+		}
+	} else {
+		if (!sport->rx_dma_buf) {
+			sport->rx_dma_buf = dma_alloc_coherent(NULL, \
+				runtime->buffer_size * sizeof(struct ac97_frame), &sport->rx_dma_phy, GFP_KERNEL);
+			if (!sport->rx_dma_buf) {
+				printk(KERN_ERR "Failed to allocate memory for rx dma buf\n");
+				return -ENOMEM;
+			} else
+				memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+		}
+	}
+	memset(runtime->dma_area, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
+		sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
+				runtime->period_size * sizeof(struct ac97_frame));
+	} else {
+		sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
+		sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods,
+				runtime->period_size * sizeof(struct ac97_frame));
+	}
+#else
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
 		sport_config_tx_dma(sport, runtime->dma_area, runtime->periods,
 				runtime->period_size * sizeof(struct ac97_frame));
 	} else {
@@ -83,38 +155,58 @@
 		sport_config_rx_dma(sport, runtime->dma_area, runtime->periods,
 				runtime->period_size * sizeof(struct ac97_frame));
 	}
+#endif
 	return 0;
 }
 
 static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-	struct sport_device *sport = substream->runtime->private_data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
 	int ret = 0;
 
 	pr_debug("%s %s\n", substream->stream?"Capture":"Playback", \
 			cmd?" start":" stop");
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
+#ifdef CONFIG_SND_MMAP_SUPPORT
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			bf5xx_mmap_copy(substream, runtime->period_size);
+			snd_pcm_period_elapsed(substream);
+			sport_tx_start(sport);
+			bf5xx_mmap_copy(substream, runtime->period_size);
+			snd_pcm_period_elapsed(substream);
+		} else {
+			sport_rx_start(sport);
+			bf5xx_mmap_copy(substream, runtime->period_size);
+			snd_pcm_period_elapsed(substream);
+		}
+#else
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 			sport_tx_start(sport);
 		else
 			sport_rx_start(sport);
+#endif
 		break;
-
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 			pr_debug("stop dma\n");
+#ifdef CONFIG_SND_MMAP_SUPPORT
+			sport->tx_pos = 0;
+#endif
 			sport_tx_stop(sport);
-		} else
+		} else {
+#ifdef CONFIG_SND_MMAP_SUPPORT
+			sport->rx_pos = 0;
+#endif
 			sport_rx_stop(sport);
+		}
 		break;
-
 	default:
 		ret = -EINVAL;
 	}
-
 	return ret;
 }
 
@@ -134,26 +226,6 @@
 	return curr;
 }
 
-static	int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
-		    snd_pcm_uframes_t pos,
-		    void __user *buf, snd_pcm_uframes_t count)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	pr_debug("%s copy pos:0x%lx count:0x%lx\n",
-			substream->stream?"Capture":"Playback", pos, count);
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		bf5xx_ac97_pcm32_to_frame(
-				(struct ac97_frame *)runtime->dma_area + pos,
-				buf, count);
-	} else
-		bf5xx_ac97_frame_to_pcm32(
-				(struct ac97_frame *)runtime->dma_area + pos,
-				buf, count);
-
-	return 0;
-}
-
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -184,6 +256,38 @@
 	return 0;
 }
 
+#ifdef CONFIG_SND_MMAP_SUPPORT
+static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
+	struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	size_t size = vma->vm_end - vma->vm_start;
+	vma->vm_start = (unsigned long)runtime->dma_area;
+	vma->vm_end = vma->vm_start + size;
+	vma->vm_flags |=  VM_SHARED;
+	return 0 ;
+}
+#else
+static	int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
+		    snd_pcm_uframes_t pos,
+		    void __user *buf, snd_pcm_uframes_t count)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	pr_debug("%s copy pos:0x%lx count:0x%lx\n",
+			substream->stream?"Capture":"Playback", pos, count);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		bf5xx_ac97_pcm32_to_frame(
+				(struct ac97_frame *)runtime->dma_area + pos,
+				buf, count);
+	else
+		bf5xx_ac97_frame_to_pcm32(
+				(struct ac97_frame *)runtime->dma_area + pos,
+				buf, count);
+	return 0;
+}
+#endif
+
 struct snd_pcm_ops bf5xx_pcm_ops = {
 	.open		= bf5xx_pcm_open,
 	.close		= bf5xx_pcm_close,
@@ -193,7 +297,11 @@
 	.prepare	= bf5xx_pcm_prepare,
 	.trigger	= bf5xx_pcm_trigger,
 	.pointer	= bf5xx_pcm_pointer,
+#ifdef CONFIG_SND_MMAP_SUPPORT
+	.mmap		= bf5xx_pcm_mmap,
+#else
 	.copy		= bf5xx_pcm_copy,
+#endif
 };
 
 static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
@@ -227,7 +335,9 @@
 	struct snd_pcm_substream *substream;
 	struct snd_dma_buffer *buf;
 	int stream;
-
+#ifdef CONFIG_SND_MMAP_SUPPORT
+	struct snd_pcm_runtime *runtime;
+#endif
 	for (stream = 0; stream < 2; stream++) {
 		substream = pcm->streams[stream].substream;
 		if (!substream)
@@ -236,7 +346,19 @@
 		buf = &substream->dma_buffer;
 		if (!buf->area)
 			continue;
-
+#ifdef CONFIG_SND_MMAP_SUPPORT
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			runtime = substream->runtime;
+			dma_free_coherent(NULL, runtime->buffer_size * sizeof(struct ac97_frame),\
+				sport_handle->tx_dma_buf, 0);
+			sport_handle->tx_dma_buf = NULL;
+		} else {
+			runtime = substream->runtime;
+			dma_free_coherent(NULL, runtime->buffer_size * sizeof(struct ac97_frame), \
+				sport_handle->rx_dma_buf, 0);
+			sport_handle->rx_dma_buf = NULL;
+		}
+#endif
 		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
 		buf->area = NULL;
 	}

Modified: trunk/sound/soc/blackfin/bf5xx-sport.h (4195 => 4196)


--- trunk/sound/soc/blackfin/bf5xx-sport.h	2008-01-31 04:27:30 UTC (rev 4195)
+++ trunk/sound/soc/blackfin/bf5xx-sport.h	2008-01-31 09:56:08 UTC (rev 4196)
@@ -114,7 +114,14 @@
 	void *tx_data;
 	void (*err_callback)(void *data);
 	void *err_data;
-
+	unsigned char *tx_dma_buf;
+	unsigned char *rx_dma_buf;
+#ifdef CONFIG_SND_MMAP_SUPPORT
+	dma_addr_t tx_dma_phy;
+	dma_addr_t rx_dma_phy;
+	int tx_pos;/*pcm sample count*/
+	int rx_pos;
+#endif
 	void *private_data;
 };
 

Modified: trunk/sound/soc/codecs/ad1980.c (4195 => 4196)


--- trunk/sound/soc/codecs/ad1980.c	2008-01-31 04:27:30 UTC (rev 4195)
+++ trunk/sound/soc/codecs/ad1980.c	2008-01-31 09:56:08 UTC (rev 4196)
@@ -222,8 +222,11 @@
 			ARRAY_SIZE(ad1980_reg));
 	codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg);
 	codec->reg_cache_step = 2;
-
+#ifdef CONFIG_SND_MMAP_SUPPORT
+	codec->name = "AD1980-MMAP";
+#else
 	codec->name = "AD1980";
+#endif
 	codec->owner = THIS_MODULE;
 	codec->dai = &ad1980_dai;
 	codec->num_dai = 1;
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
http://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to