Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5b086fd8 authored by Tarun Gupta's avatar Tarun Gupta
Browse files

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: default avatarDeepa Madiregama <dmadireg@codeaurora.org>
Signed-off-by: default avatarTarun Gupta <tarung@codeaurora.org>
parent 51b2e8a3
Loading
Loading
Loading
Loading
+41 −3
Original line number Diff line number Diff line
@@ -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>
@@ -774,6 +776,7 @@ static int audio_pcm_close(struct snd_pcm_substream *substream)
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);

@@ -782,13 +785,31 @@ static int audio_pcm_hw_params(struct snd_pcm_substream *substream,
	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)
@@ -840,6 +861,22 @@ static int audio_pcm_playback_trigger(struct snd_pcm_substream *substream,
	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",
@@ -862,6 +899,7 @@ static struct snd_pcm_ops audio_playback_ops = {
	.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,