Merge "ASoC: msm: Add hwdep node for NOIRQ FE"

This commit is contained in:
Linux Build Service Account 2017-07-16 21:04:59 -07:00 committed by Gerrit - the friendly Code Review server
commit 0ea2b1fc15
2 changed files with 160 additions and 2 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
* Copyright (c) 2013-2015,2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -66,4 +66,14 @@ struct dts_eagle_param_desc {
uint32_t device;
} __packed;
#define HWDEP_FE_BASE 3000 /*unique base for FE hw dep nodes*/
struct snd_pcm_mmap_fd {
int32_t dir;
int32_t fd;
int32_t size;
int32_t actual_size;
};
#define SNDRV_PCM_IOCTL_MMAP_DATA_FD _IOWR('U', 0xd2, struct snd_pcm_mmap_fd)
#endif

View file

@ -30,9 +30,12 @@
#include <sound/control.h>
#include <sound/q6audio-v2.h>
#include <sound/timer.h>
#include <sound/hwdep.h>
#include <asm/dma.h>
#include <sound/tlv.h>
#include <sound/pcm_params.h>
#include <sound/devdep_params.h>
#include "msm-pcm-q6-v2.h"
#include "msm-pcm-routing-v2.h"
@ -421,6 +424,42 @@ static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return ret;
}
static int msm_pcm_mmap_fd(struct snd_pcm_substream *substream,
struct snd_pcm_mmap_fd *mmap_fd)
{
struct msm_audio *prtd;
struct audio_port_data *apd;
struct audio_buffer *ab;
int dir = -1;
if (!substream->runtime) {
pr_err("%s substream runtime not found\n", __func__);
return -EFAULT;
}
prtd = substream->runtime->private_data;
if (!prtd || !prtd->audio_client || !prtd->mmap_flag) {
pr_err("%s no audio client or not an mmap session\n", __func__);
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dir = IN;
else
dir = OUT;
apd = prtd->audio_client->port;
ab = &(apd[dir].buf[0]);
mmap_fd->fd = ion_share_dma_buf_fd(ab->client, ab->handle);
if (mmap_fd->fd >= 0) {
mmap_fd->dir = dir;
mmap_fd->actual_size = ab->actual_size;
mmap_fd->size = ab->size;
}
return mmap_fd->fd < 0 ? -EFAULT : 0;
}
static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
@ -445,6 +484,15 @@ static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
return snd_pcm_lib_ioctl(substream, cmd, arg);
}
#ifdef CONFIG_COMPAT
static int msm_pcm_compat_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
/* we only handle RESET which is common for both modes */
return msm_pcm_ioctl(substream, cmd, arg);
}
#endif
static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@ -994,6 +1042,101 @@ static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
return 0;
}
static int msm_pcm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
unsigned int cmd, unsigned long arg)
{
int ret = 0;
struct snd_pcm *pcm = hw->private_data;
struct snd_pcm_mmap_fd __user *_mmap_fd = NULL;
struct snd_pcm_mmap_fd mmap_fd;
struct snd_pcm_substream *substream = NULL;
int32_t dir = -1;
switch (cmd) {
case SNDRV_PCM_IOCTL_MMAP_DATA_FD:
_mmap_fd = (struct snd_pcm_mmap_fd __user *)arg;
if (get_user(dir, (int32_t __user *)&(_mmap_fd->dir))) {
pr_err("%s: error copying mmap_fd from user\n",
__func__);
ret = -EFAULT;
break;
}
if (dir != OUT && dir != IN) {
pr_err("%s invalid stream dir\n", __func__);
ret = -EINVAL;
break;
}
substream = pcm->streams[dir].substream;
if (!substream) {
pr_err("%s substream not found\n", __func__);
ret = -ENODEV;
break;
}
pr_debug("%s : %s MMAP Data fd\n", __func__,
dir == 0 ? "P" : "C");
if (msm_pcm_mmap_fd(substream, &mmap_fd) < 0) {
pr_err("%s: error getting fd\n",
__func__);
ret = -EFAULT;
break;
}
if (put_user(mmap_fd.fd, &_mmap_fd->fd) ||
put_user(mmap_fd.size, &_mmap_fd->size) ||
put_user(mmap_fd.actual_size, &_mmap_fd->actual_size)) {
pr_err("%s: error copying fd\n", __func__);
return -EFAULT;
}
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static int msm_pcm_hwdep_compat_ioctl(struct snd_hwdep *hw,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
/* we only support mmap fd. Handling is common in both modes */
return msm_pcm_hwdep_ioctl(hw, file, cmd, arg);
}
#else
static int msm_pcm_hwdep_compat_ioctl(struct snd_hwdep *hw,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
return -EINVAL;
}
#endif
static int msm_pcm_add_hwdep_dev(struct snd_soc_pcm_runtime *runtime)
{
struct snd_hwdep *hwdep;
int rc;
char id[] = "NOIRQ_NN";
snprintf(id, sizeof(id), "NOIRQ_%d", runtime->pcm->device);
pr_debug("%s: pcm dev %d\n", __func__, runtime->pcm->device);
rc = snd_hwdep_new(runtime->card->snd_card,
&id[0],
HWDEP_FE_BASE + runtime->pcm->device,
&hwdep);
if (!hwdep || rc < 0) {
pr_err("%s: hwdep intf failed to create %s - hwdep\n", __func__,
id);
return rc;
}
hwdep->iface = SNDRV_HWDEP_IFACE_AUDIO_BE; /* for lack of a FE iface */
hwdep->private_data = runtime->pcm; /* of type struct snd_pcm */
hwdep->ops.ioctl = msm_pcm_hwdep_ioctl;
hwdep->ops.ioctl_compat = msm_pcm_hwdep_compat_ioctl;
return 0;
}
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
@ -1027,7 +1170,9 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
pr_err("%s: Could not add app type controls failed %d\n",
__func__, ret);
}
ret = msm_pcm_add_hwdep_dev(rtd);
if (ret)
pr_err("%s: Could not add hw dep node\n", __func__);
pcm->nonatomic = true;
exit:
return ret;
@ -1040,6 +1185,9 @@ static struct snd_pcm_ops msm_pcm_ops = {
.copy = msm_pcm_copy,
.hw_params = msm_pcm_hw_params,
.ioctl = msm_pcm_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = msm_pcm_compat_ioctl,
#endif
.trigger = msm_pcm_trigger,
.pointer = msm_pcm_pointer,
.mmap = msm_pcm_mmap,