Merge "ASoC: msm: Add hwdep node for NOIRQ FE"
This commit is contained in:
commit
0ea2b1fc15
2 changed files with 160 additions and 2 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue