diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index c47d9b4..d353e55 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -30,6 +30,7 @@
 #include <linux/mm.h>
 #include <linux/bitops.h>
 #include <linux/pm_qos.h>
+#include <linux/dma-buf.h>
 
 #define snd_pcm_substream_chip(substream) ((substream)->private_data)
 #define snd_pcm_chip(pcm) ((pcm)->private_data)
@@ -455,6 +456,7 @@ struct snd_pcm_substream {
 	size_t buffer_bytes_max;	/* limit ring buffer size */
 	struct snd_dma_buffer dma_buffer;
 	size_t dma_max;
+	struct dma_buf_attachment *attachment;
 	/* -- hardware operations -- */
 	const struct snd_pcm_ops *ops;
 	/* -- runtime information -- */
diff --git a/include/sound/pcm_dmabuf.h b/include/sound/pcm_dmabuf.h
new file mode 100644
index 0000000..4e88c5f6
--- /dev/null
+++ b/include/sound/pcm_dmabuf.h
@@ -0,0 +1,29 @@
+#ifndef __SOUND_PCM_DMABUF_H
+#define __SOUND_PCM_DMABUF_H
+
+#include <sound/pcm.h>
+
+#ifdef CONFIG_SND_PCM_DMABUF
+int snd_pcm_dmabuf_export(struct snd_pcm_substream *substream);
+int snd_pcm_dmabuf_attach(struct snd_pcm_substream *substream, int fd);
+void snd_pcm_dmabuf_detach(struct snd_pcm_substream *substream);
+#else
+static inline int snd_pcm_dmabuf_export(struct snd_pcm_substream *substream)
+{
+	return -EBADF;
+}
+
+static inline int snd_pcm_dmabuf_attach(struct snd_pcm_substream *substream,
+					int fd)
+{
+	return -ENXIO;
+}
+
+static inline void snd_pcm_dmabuf_detach(struct snd_pcm_substream *substream)
+{
+
+}
+
+#endif
+
+#endif /* __SOUND_PCM_DMABUF_H */
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 404d4b9..4770b41 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -602,6 +602,9 @@ enum {
 #define SNDRV_PCM_IOCTL_READN_FRAMES	_IOR('A', 0x53, struct snd_xfern)
 #define SNDRV_PCM_IOCTL_LINK		_IOW('A', 0x60, int)
 #define SNDRV_PCM_IOCTL_UNLINK		_IO('A', 0x61)
+#define SNDRV_PCM_IOCTL_DMABUF_EXPORT	_IOR('A', 0x70, int)
+#define SNDRV_PCM_IOCTL_DMABUF_ATTACH	_IOW('A', 0x71, int)
+#define SNDRV_PCM_IOCTL_DMABUF_DETACH	_IO('A', 0x72)
 
 /*****************************************************************************
  *                                                                           *
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 63b3ef9..5ee02f2 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -184,4 +184,8 @@ config SND_DMA_SGBUF
 	def_bool y
 	depends on X86
 
+config SND_PCM_DMABUF
+	def_bool y
+	select DMA_SHARED_BUFFER
+
 source "sound/core/seq/Kconfig"
diff --git a/sound/core/Makefile b/sound/core/Makefile
index ee4a4a6..beea463 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -49,3 +49,4 @@ obj-$(CONFIG_SND_OSSEMUL)	+= oss/
 obj-$(CONFIG_SND_SEQUENCER)	+= seq/
 
 obj-$(CONFIG_SND_COMPRESS_OFFLOAD)	+= snd-compress.o
+obj-$(CONFIG_SND_PCM_DMABUF)	+= pcm_dmabuf.o
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 01b9d62..7781db2 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -32,6 +32,7 @@
 #include <sound/timer.h>
 #include <sound/control.h>
 #include <sound/info.h>
+#include <sound/pcm_dmabuf.h>
 
 #include "pcm_local.h"
 
@@ -890,6 +891,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
 		substream_next = substream->next;
 		snd_pcm_timer_done(substream);
 		snd_pcm_substream_proc_done(substream);
+		snd_pcm_dmabuf_detach(substream);
 		kfree(substream);
 		substream = substream_next;
 	}
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 946ab08..af24489 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -687,6 +687,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
 	case SNDRV_PCM_IOCTL_XRUN:
 	case SNDRV_PCM_IOCTL_LINK:
 	case SNDRV_PCM_IOCTL_UNLINK:
+	case SNDRV_PCM_IOCTL_DMABUF_EXPORT:
+	case SNDRV_PCM_IOCTL_DMABUF_ATTACH:
+	case SNDRV_PCM_IOCTL_DMABUF_DETACH:
 		return snd_pcm_common_ioctl(file, substream, cmd, argp);
 	case SNDRV_PCM_IOCTL_HW_REFINE32:
 		return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
diff --git a/sound/core/pcm_dmabuf.c b/sound/core/pcm_dmabuf.c
new file mode 100644
index 0000000..76211ea
--- /dev/null
+++ b/sound/core/pcm_dmabuf.c
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright(C) 2018 Linaro Limited. All rights reserved.
+// Author: Baolin Wang <baolin.wang@linaro.org>
+
+#include <linux/export.h>
+#include <linux/dma-buf.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <linux/slab.h>
+
+struct pcm_dmabuf_attachment {
+	struct device *dev;
+	struct sg_table *sgt;
+	enum dma_data_direction dir;
+	struct list_head list;
+};
+
+struct pcm_dmabuf_object {
+	struct snd_dma_buffer *dmab;
+	struct dma_buf *dmabuf;
+	struct page **pages;
+	int pages_num;
+	struct mutex lock;
+	struct list_head attachments;
+};
+
+static int snd_pcm_map_attach(struct dma_buf *dma_buf,
+			      struct dma_buf_attachment *attach)
+{
+	struct pcm_dmabuf_attachment *pcm_attach;
+
+	pcm_attach = kzalloc(sizeof(*pcm_attach), GFP_KERNEL);
+	if (!pcm_attach)
+		return -ENOMEM;
+
+	pcm_attach->dir = DMA_NONE;
+	attach->priv = pcm_attach;
+
+	return 0;
+}
+
+static void snd_pcm_map_detach(struct dma_buf *dma_buf,
+			       struct dma_buf_attachment *attach)
+{
+	struct pcm_dmabuf_attachment *pcm_attach = attach->priv;
+	struct sg_table *sgt;
+
+	if (!pcm_attach)
+		return;
+
+	sgt = pcm_attach->sgt;
+	if (sgt) {
+		if (pcm_attach->dir != DMA_NONE)
+			dma_unmap_sg_attrs(attach->dev, sgt->sgl,
+					   sgt->nents,
+					   pcm_attach->dir,
+					   DMA_ATTR_SKIP_CPU_SYNC);
+
+		sg_free_table(sgt);
+	}
+
+	kfree(sgt);
+	kfree(pcm_attach);
+	attach->priv = NULL;
+}
+
+static struct sg_table *snd_pcm_dmabuf_to_sgt(struct pcm_dmabuf_object *obj)
+{
+	struct snd_dma_buffer *dmab = obj->dmab;
+	int type = dmab->dev.type, ret, i;
+	struct sg_table *sgt;
+	unsigned long offset;
+
+	sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
+	if (!sgt)
+		return ERR_PTR(-ENOMEM);
+
+	switch (type) {
+	case SNDRV_DMA_TYPE_CONTINUOUS:
+		offset = offset_in_page(dmab->area);
+
+		for (i = 0; i < obj->pages_num; i++) {
+			struct page *page =
+				virt_to_page(dmab->area + i * PAGE_SIZE);
+
+			obj->pages[i] = page;
+		}
+
+		ret = sg_alloc_table_from_pages(sgt, obj->pages, obj->pages_num,
+						offset, dmab->bytes, GFP_KERNEL);
+		if (ret)
+			goto error;
+
+		break;
+
+#ifdef CONFIG_GENERIC_ALLOCATOR
+	case SNDRV_DMA_TYPE_DEV_IRAM:
+#endif
+	case SNDRV_DMA_TYPE_DEV:
+	case SNDRV_DMA_TYPE_DEV_UC:
+		ret = dma_get_sgtable(dmab->dev.dev, sgt, dmab->area,
+				      dmab->addr, dmab->bytes);
+		if (ret)
+			goto error;
+
+		break;
+
+#ifdef CONFIG_SND_DMA_SGBUF
+	case SNDRV_DMA_TYPE_DEV_SG:
+	case SNDRV_DMA_TYPE_DEV_UC_SG:
+		struct snd_sg_buf *sgbuf = dmab->private_data;
+
+		obj->pages = sgbuf->page_table;
+		ret = sg_alloc_table_from_pages(sgt, obj->pages, obj->pages_num,
+						0, dmab->bytes, GFP_KERNEL);
+		if (ret)
+			goto error;
+
+		break;
+#endif
+
+	default:
+		ret = -ENXIO;
+		goto error;
+	}
+
+	return sgt;
+
+error:
+	kfree(sgt);
+	return ERR_PTR(ret);
+}
+
+static struct sg_table *snd_pcm_map_dmabuf(struct dma_buf_attachment *attach,
+					   enum dma_data_direction dir)
+{
+	struct pcm_dmabuf_attachment *pcm_attach = attach->priv;
+	struct pcm_dmabuf_object *obj = attach->dmabuf->priv;
+	struct sg_table *sgt;
+	int ret;
+
+	if (WARN_ON(dir == DMA_NONE || !pcm_attach))
+		return ERR_PTR(-EINVAL);
+
+	if (pcm_attach->dir == dir)
+		return pcm_attach->sgt;
+
+	if (WARN_ON(pcm_attach->dir != DMA_NONE))
+		return ERR_PTR(-EBUSY);
+
+	sgt = snd_pcm_dmabuf_to_sgt(obj);
+	if (IS_ERR(sgt))
+		return sgt;
+
+	ret = dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
+			       DMA_ATTR_SKIP_CPU_SYNC);
+	if (!ret) {
+		sg_free_table(sgt);
+		kfree(sgt);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pcm_attach->sgt = sgt;
+	pcm_attach->dir = dir;
+
+	return sgt;
+}
+
+static void snd_pcm_unmap_dmabuf(struct dma_buf_attachment *attach,
+				 struct sg_table *sgt,
+				 enum dma_data_direction dir)
+{
+	/* Nothing need to do */
+}
+
+static int snd_pcm_dmabuf_mmap(struct dma_buf *dma_buf,
+			       struct vm_area_struct *vma)
+{
+	struct pcm_dmabuf_object *obj = dma_buf->priv;
+	struct snd_dma_buffer *dmab = obj->dmab;
+	unsigned long addr = vma->vm_start;
+	unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
+	int type = dmab->dev.type, ret, i;
+	struct sg_table *sgt;
+	struct scatterlist *sg;
+
+	switch (type) {
+#ifdef CONFIG_GENERIC_ALLOCATOR
+	case SNDRV_DMA_TYPE_DEV_IRAM:
+#endif
+	case SNDRV_DMA_TYPE_DEV:
+	case SNDRV_DMA_TYPE_DEV_UC:
+		return dma_mmap_coherent(dmab->dev.dev, vma,
+					 dmab->area, dmab->addr,
+					 vma->vm_end - vma->vm_start);
+
+#ifdef CONFIG_SND_DMA_SGBUF
+	case SNDRV_DMA_TYPE_DEV_SG:
+	case SNDRV_DMA_TYPE_DEV_UC_SG:
+#endif
+	case SNDRV_DMA_TYPE_CONTINUOUS:
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+		sgt = snd_pcm_dmabuf_to_sgt(obj);
+		if (IS_ERR(sgt))
+			return PTR_ERR(sgt);
+
+		for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+			struct page *page = sg_page(sg);
+			unsigned long remainder = vma->vm_end - addr;
+			unsigned long len = sg->length;
+
+			if (offset >= sg->length) {
+				offset -= sg->length;
+				continue;
+			} else if (offset) {
+				page += offset / PAGE_SIZE;
+				len = sg->length - offset;
+				offset = 0;
+			}
+
+			len = min(len, remainder);
+			ret = remap_pfn_range(vma, addr, page_to_pfn(page), len,
+					      vma->vm_page_prot);
+			if (ret)
+				return ret;
+
+			addr += len;
+			if (addr >= vma->vm_end)
+				return 0;
+		}
+
+	default:
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void snd_pcm_dmabuf_release(struct dma_buf *dmabuf)
+{
+	struct pcm_dmabuf_object *obj = dmabuf->priv;
+
+	kfree(obj->pages);
+	kfree(obj);
+}
+
+static int snd_pcm_dmabuf_begin_cpu_access(struct dma_buf *dmabuf,
+					   enum dma_data_direction direction)
+{
+	struct pcm_dmabuf_object *obj = dmabuf->priv;
+	struct snd_dma_buffer *dmab = obj->dmab;
+	int type = dmab->dev.type;
+	struct pcm_dmabuf_attachment *pcm_attach;
+
+	switch (type) {
+#ifdef CONFIG_GENERIC_ALLOCATOR
+	case SNDRV_DMA_TYPE_DEV_IRAM:
+#endif
+	case SNDRV_DMA_TYPE_DEV:
+	case SNDRV_DMA_TYPE_DEV_UC:
+		/* Memory types are uncacheable, nothing need to do. */
+		return 0;
+
+#ifdef CONFIG_SND_DMA_SGBUF
+	case SNDRV_DMA_TYPE_DEV_SG:
+	case SNDRV_DMA_TYPE_DEV_UC_SG:
+#endif
+	case SNDRV_DMA_TYPE_CONTINUOUS:
+		mutex_lock(&obj->lock);
+
+		/*
+		 * Sync the whole DMA buffer properly in order for the CPU
+		 * to see the most up-to-date and correct copy of the DMA
+		 * buffer.
+		 */
+		list_for_each_entry(pcm_attach, &obj->attachments, list) {
+			dma_sync_sg_for_cpu(pcm_attach->dev,
+					    pcm_attach->sgt->sgl,
+					    pcm_attach->sgt->nents,
+					    direction);
+		}
+
+		mutex_unlock(&obj->lock);
+
+		break;
+
+	default:
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int snd_pcm_dmabuf_end_cpu_access(struct dma_buf *dmabuf,
+					 enum dma_data_direction direction)
+{
+	struct pcm_dmabuf_object *obj = dmabuf->priv;
+	struct snd_dma_buffer *dmab = obj->dmab;
+	struct pcm_dmabuf_attachment *pcm_attach;
+	int type = dmab->dev.type;
+
+	switch (type) {
+#ifdef CONFIG_GENERIC_ALLOCATOR
+	case SNDRV_DMA_TYPE_DEV_IRAM:
+#endif
+	case SNDRV_DMA_TYPE_DEV:
+	case SNDRV_DMA_TYPE_DEV_UC:
+		/* Memory types are uncacheable, nothing need to do. */
+		return 0;
+
+#ifdef CONFIG_SND_DMA_SGBUF
+	case SNDRV_DMA_TYPE_DEV_SG:
+	case SNDRV_DMA_TYPE_DEV_UC_SG:
+#endif
+	case SNDRV_DMA_TYPE_CONTINUOUS:
+		mutex_lock(&obj->lock);
+
+		/*
+		 * Sync the whole DMA buffer properly in order for the devices
+		 * to see the most up-to-date and correct copy of the DMA
+		 * buffer.
+		 */
+		list_for_each_entry(pcm_attach, &obj->attachments, list) {
+			dma_sync_sg_for_device(pcm_attach->dev,
+					       pcm_attach->sgt->sgl,
+					       pcm_attach->sgt->nents,
+					       direction);
+		}
+
+		mutex_unlock(&obj->lock);
+
+		break;
+
+	default:
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static const struct dma_buf_ops snd_pcm_dmabuf_ops =  {
+	.attach = snd_pcm_map_attach,
+	.detach = snd_pcm_map_detach,
+	.map_dma_buf = snd_pcm_map_dmabuf,
+	.unmap_dma_buf = snd_pcm_unmap_dmabuf,
+	.release = snd_pcm_dmabuf_release,
+	.mmap = snd_pcm_dmabuf_mmap,
+	.begin_cpu_access = snd_pcm_dmabuf_begin_cpu_access,
+	.end_cpu_access = snd_pcm_dmabuf_end_cpu_access,
+};
+
+/**
+ * snd_pcm_dmabuf_export - export one dma buffer associated with a PCM substream
+ * @substream: PCM substream
+ *
+ * Return: a file descriptor for the given dma buffer, otherwise a negative
+ * value on error.
+ */
+int snd_pcm_dmabuf_export(struct snd_pcm_substream *substream)
+{
+	struct snd_dma_buffer *dmab = &substream->dma_buffer;
+	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+	struct pcm_dmabuf_object *obj;
+	int ret;
+
+	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+	if (!obj)
+		return -ENOMEM;
+
+	mutex_init(&obj->lock);
+	INIT_LIST_HEAD(&obj->attachments);
+	obj->dmab = dmab;
+	obj->pages_num = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	obj->pages = kcalloc(obj->pages_num, sizeof(obj->pages[0]), GFP_KERNEL);
+	if (!obj->pages) {
+		ret = -ENOMEM;
+		goto alloc_err;
+	}
+
+	exp_info.ops = &snd_pcm_dmabuf_ops;
+	exp_info.size = dmab->bytes;
+	exp_info.flags = O_RDWR;
+	exp_info.priv = obj;
+
+	obj->dmabuf = dma_buf_export(&exp_info);
+	if (IS_ERR(obj->dmabuf)) {
+		ret = PTR_ERR(obj->dmabuf);
+		goto export_err;
+	}
+
+	ret = dma_buf_fd(obj->dmabuf, O_CLOEXEC);
+	if (ret < 0)
+		goto fd_err;
+
+	return ret;
+
+fd_err:
+	dma_buf_put(obj->dmabuf);
+export_err:
+	kfree(obj->pages);
+alloc_err:
+	kfree(obj);
+	return ret;
+}
+EXPORT_SYMBOL(snd_pcm_dmabuf_export);
+
+/**
+ * snd_pcm_dmabuf_attach - attach one device to the dma buffer
+ * @substream: PCM substream
+ * @fd: file descriptor for the dma buffer
+ *
+ * Add one attachment to the dma buffer and map the scatterlist table of
+ * the attachment into device address space.
+ *
+ * Return: zero if attaching successfully, otherwise a negative value on error.
+ */
+int snd_pcm_dmabuf_attach(struct snd_pcm_substream *substream, int fd)
+{
+	enum dma_data_direction dir =
+		substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		DMA_TO_DEVICE : DMA_FROM_DEVICE;
+	struct snd_card *card = substream->pcm->card;
+	struct device *dev = card->dev;
+	struct dma_buf_attachment *attachment;
+	struct pcm_dmabuf_object *obj;
+	struct pcm_dmabuf_attachment *pcm_attach;
+	struct snd_dma_buffer *dmab;
+	struct dma_buf *dmabuf;
+	struct sg_table *sgt;
+	int ret;
+
+	dmabuf = dma_buf_get(fd);
+	if (IS_ERR(dmabuf))
+		return PTR_ERR(dmabuf);
+
+	attachment = dma_buf_attach(dmabuf, dev);
+	if (IS_ERR(attachment)) {
+		ret = PTR_ERR(attachment);
+		goto err_put;
+	}
+
+	sgt = dma_buf_map_attachment(attachment, dir);
+	if (IS_ERR(sgt)) {
+		ret = PTR_ERR(sgt);
+		goto err_detach;
+	}
+
+	pcm_attach = attachment->priv;
+	pcm_attach->dev = dev;
+	INIT_LIST_HEAD(&pcm_attach->list);
+	obj = dmabuf->priv;
+	dmab = obj->dmab;
+
+	switch (dmab->dev.type) {
+	case SNDRV_DMA_TYPE_CONTINUOUS:
+		substream->runtime->dma_area = dmab->area;
+		substream->runtime->dma_addr = sg_dma_address(sgt->sgl);
+		substream->runtime->dma_bytes = dmab->bytes;
+		break;
+
+#ifdef CONFIG_GENERIC_ALLOCATOR
+	case SNDRV_DMA_TYPE_DEV_IRAM:
+#endif
+	case SNDRV_DMA_TYPE_DEV:
+	case SNDRV_DMA_TYPE_DEV_UC:
+		substream->runtime->dma_area = dmab->area;
+		substream->runtime->dma_addr = dmab->addr;
+		substream->runtime->dma_bytes = dmab->bytes;
+		break;
+
+#ifdef CONFIG_SND_DMA_SGBUF
+	case SNDRV_DMA_TYPE_DEV_SG:
+	case SNDRV_DMA_TYPE_DEV_UC_SG:
+		/* TODO: Do not support now */
+		/* fall-through */
+#endif
+
+	default:
+		ret = -ENXIO;
+		goto err_runtime_buf;
+	}
+
+	substream->attachment = attachment;
+
+	mutex_lock(&obj->lock);
+	list_add(&pcm_attach->list, &obj->attachments);
+	mutex_unlock(&obj->lock);
+
+	return 0;
+
+err_runtime_buf:
+	dma_buf_unmap_attachment(attachment, sgt, dir);
+err_detach:
+	dma_buf_detach(dmabuf, attachment);
+err_put:
+	dma_buf_put(dmabuf);
+
+	return ret;
+}
+EXPORT_SYMBOL(snd_pcm_dmabuf_attach);
+
+/**
+ * snd_pcm_dmabuf_detach - detach the given attachment from dma buffer
+ * @substream: PCM substream
+ */
+void snd_pcm_dmabuf_detach(struct snd_pcm_substream *substream)
+{
+	struct dma_buf_attachment *attachment = substream->attachment;
+	struct pcm_dmabuf_attachment *pcm_attach;
+	struct pcm_dmabuf_object *obj;
+	struct dma_buf *dmabuf;
+
+	if (!attachment)
+		return;
+
+	pcm_attach = attachment->priv;
+	dmabuf = attachment->dmabuf;
+	obj = dmabuf->priv;
+
+	mutex_lock(&obj->lock);
+	list_del(&pcm_attach->list);
+	mutex_unlock(&obj->lock);
+
+	dma_buf_unmap_attachment(attachment, pcm_attach->sgt, pcm_attach->dir);
+	dma_buf_detach(dmabuf, attachment);
+	dma_buf_put(dmabuf);
+	substream->attachment = NULL;
+}
+EXPORT_SYMBOL(snd_pcm_dmabuf_detach);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index ac37a71..5fad8dc 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -33,6 +33,7 @@
 #include <sound/info.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
+#include <sound/pcm_dmabuf.h>
 #include <sound/timer.h>
 #include <sound/minors.h>
 #include <linux/uio.h>
@@ -2863,6 +2864,37 @@ static int snd_pcm_forward_ioctl(struct snd_pcm_substream *substream,
 	return result < 0 ? result : 0;
 }
 
+static int snd_pcm_dmabuf_export_ioctl(struct snd_pcm_substream *substream,
+				       int __user *_fd)
+{
+	int fd;
+
+	fd = snd_pcm_dmabuf_export(substream);
+	if (fd < 0)
+		return fd;
+
+	__put_user(fd, _fd);
+	return 0;
+}
+
+static int snd_pcm_dmabuf_attach_ioctl(struct snd_pcm_substream *substream,
+				       int __user *_fd)
+{
+	int fd;
+
+	if (get_user(fd, _fd))
+		return -EFAULT;
+
+	return snd_pcm_dmabuf_attach(substream, fd);
+}
+
+static int snd_pcm_dmabuf_detach_ioctl(struct snd_pcm_substream *substream)
+{
+	snd_pcm_dmabuf_detach(substream);
+
+	return 0;
+}
+
 static int snd_pcm_common_ioctl(struct file *file,
 				 struct snd_pcm_substream *substream,
 				 unsigned int cmd, void __user *arg)
@@ -2960,6 +2992,12 @@ static int snd_pcm_common_ioctl(struct file *file,
 		return snd_pcm_rewind_ioctl(substream, arg);
 	case SNDRV_PCM_IOCTL_FORWARD:
 		return snd_pcm_forward_ioctl(substream, arg);
+	case SNDRV_PCM_IOCTL_DMABUF_EXPORT:
+		return snd_pcm_dmabuf_export_ioctl(substream, arg);
+	case SNDRV_PCM_IOCTL_DMABUF_ATTACH:
+		return snd_pcm_dmabuf_attach_ioctl(substream, arg);
+	case SNDRV_PCM_IOCTL_DMABUF_DETACH:
+		return snd_pcm_dmabuf_detach_ioctl(substream);
 	}
 	pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
 	return -ENOTTY;
