USB: gadget: f_audio_source: Switch to DMA memory to support MMAP
- Music takes more time to resume on speaker after USB unplug.
- USB driver does not support the Non-blocking mode i.e.
MMAP mode. When the USB is unplugged, write is blocked for
10 sec, and after a 10 sec timeout, the USB accessory device
is closed and the device switch to speaker occurs.
- Changes were made to implement the MMAP interface in the
driver that is Non-blocking. Hence, the write thread gets
unblocked immediately and the switch to speaker is
instantaneous.
CRs-Fixed: 453134
Change-Id: I3020f56db31e78aed114e6a4021f519b1ed234c3
Signed-off-by: Deepa Madiregama <dmadireg@codeaurora.org>
diff --git a/drivers/usb/gadget/f_audio_source.c b/drivers/usb/gadget/f_audio_source.c
index f0d5c52..37f229b 100644
--- a/drivers/usb/gadget/f_audio_source.c
+++ b/drivers/usb/gadget/f_audio_source.c
@@ -14,6 +14,8 @@
*
*/
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/usb/audio.h>
#include <linux/wait.h>
@@ -694,6 +696,7 @@
static int audio_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
unsigned int channels = params_channels(params);
unsigned int rate = params_rate(params);
@@ -702,13 +705,31 @@
if (channels != 2)
return -EINVAL;
- return snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(params));
+ if (!substream->pcm->card->dev->coherent_dma_mask)
+ substream->pcm->card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = substream->pcm->card->dev;
+ buf->private_data = NULL;
+ buf->area = dma_alloc_coherent(substream->pcm->card->dev,
+ params_buffer_bytes(params),
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+ buf->bytes = params_buffer_bytes(params);
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ return 0;
}
static int audio_pcm_hw_free(struct snd_pcm_substream *substream)
{
- return snd_pcm_lib_free_vmalloc_buffer(substream);
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+ if (buf->area != NULL)
+ dma_free_coherent(substream->pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ return 0;
}
static int audio_pcm_prepare(struct snd_pcm_substream *substream)
@@ -760,6 +781,22 @@
return ret;
}
+static int audio_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ if (runtime->dma_addr && runtime->dma_bytes) {
+ return dma_mmap_coherent(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+ } else {
+ pr_err("Physical address or size of buf is NULL");
+ return -EINVAL;
+ }
+}
+
static struct audio_dev _audio_dev = {
.func = {
.name = "audio_source",
@@ -784,6 +821,7 @@
.prepare = audio_pcm_prepare,
.trigger = audio_pcm_playback_trigger,
.pointer = audio_pcm_pointer,
+ .mmap = audio_pcm_mmap,
};
int audio_source_bind_config(struct usb_configuration *c,