317 lines
7.6 KiB
C
317 lines
7.6 KiB
C
/*
|
|
* effect_offload.c - effects offload core
|
|
*
|
|
* Copyright (C) 2013 Intel Corporation
|
|
* Authors: Lakshmi N Vinnakota <lakshmi.n.vinnakota@intel.com>
|
|
* Vinod Koul <vinod.koul@intel.com>
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
*
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
*/
|
|
#define FORMAT(fmt) "%s: %d: " fmt, __func__, __LINE__
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/uio.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/slab.h>
|
|
#include <sound/core.h>
|
|
#include <sound/effect_offload.h>
|
|
#include <sound/effect_driver.h>
|
|
|
|
static DEFINE_MUTEX(effect_mutex);
|
|
|
|
int snd_ctl_effect_create(struct snd_card *card, void *arg)
|
|
{
|
|
int retval = 0;
|
|
struct snd_effect *effect;
|
|
|
|
effect = kmalloc(sizeof(*effect), GFP_KERNEL);
|
|
if (!effect)
|
|
return -ENOMEM;
|
|
if (copy_from_user(effect, (void __user *)arg, sizeof(*effect))) {
|
|
retval = -EFAULT;
|
|
goto out;
|
|
}
|
|
pr_debug("effect_offload: device %u, pos %u, mode%u\n",
|
|
effect->device, effect->pos, effect->mode);
|
|
|
|
mutex_lock(&card->effect_lock);
|
|
retval = card->effect_ops->create(card, effect);
|
|
mutex_unlock(&card->effect_lock);
|
|
out:
|
|
kfree(effect);
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL_GPL(snd_ctl_effect_create);
|
|
|
|
int snd_ctl_effect_destroy(struct snd_card *card, void *arg)
|
|
{
|
|
int retval = 0;
|
|
struct snd_effect *effect;
|
|
|
|
effect = kmalloc(sizeof(*effect), GFP_KERNEL);
|
|
if (!effect)
|
|
return -ENOMEM;
|
|
if (copy_from_user(effect, (void __user *)arg, sizeof(*effect))) {
|
|
retval = -EFAULT;
|
|
goto out;
|
|
}
|
|
mutex_lock(&card->effect_lock);
|
|
retval = card->effect_ops->destroy(card, effect);
|
|
mutex_unlock(&card->effect_lock);
|
|
out:
|
|
kfree(effect);
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL_GPL(snd_ctl_effect_destroy);
|
|
|
|
int snd_ctl_effect_set_params(struct snd_card *card, void *arg)
|
|
{
|
|
int retval = 0;
|
|
struct snd_effect_params *params;
|
|
char *params_ptr;
|
|
char __user *argp = (char __user *)arg;
|
|
|
|
params = kmalloc(sizeof(*params), GFP_KERNEL);
|
|
if (!params)
|
|
return -ENOMEM;
|
|
|
|
if (copy_from_user(params, argp, sizeof(*params))) {
|
|
retval = -EFAULT;
|
|
goto out;
|
|
}
|
|
params_ptr = kmalloc(params->size, GFP_KERNEL);
|
|
if (!params_ptr) {
|
|
retval = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
if (copy_from_user((void *)params_ptr, (void __user *)params->buffer_ptr,
|
|
params->size)) {
|
|
retval = -EFAULT;
|
|
goto free_buf;
|
|
}
|
|
|
|
params->buffer_ptr = (unsigned long)params_ptr;
|
|
|
|
mutex_lock(&card->effect_lock);
|
|
retval = card->effect_ops->set_params(card, params);
|
|
mutex_unlock(&card->effect_lock);
|
|
free_buf:
|
|
kfree(params_ptr);
|
|
out:
|
|
kfree(params);
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL_GPL(snd_ctl_effect_set_params);
|
|
|
|
int snd_ctl_effect_get_params(struct snd_card *card, void *arg)
|
|
{
|
|
int retval = 0;
|
|
struct snd_effect_params inparams;
|
|
struct snd_effect_params *outparams;
|
|
unsigned int offset;
|
|
char *params_ptr;
|
|
char __user *argp = (char __user *)arg;
|
|
|
|
if (copy_from_user((void *)&inparams, argp, sizeof(inparams)))
|
|
retval = -EFAULT;
|
|
|
|
outparams = kmalloc(sizeof(*outparams), GFP_KERNEL);
|
|
if (!outparams)
|
|
return -ENOMEM;
|
|
|
|
memcpy(outparams, &inparams, sizeof(inparams));
|
|
params_ptr = kmalloc(inparams.size, GFP_KERNEL);
|
|
if (!params_ptr) {
|
|
retval = -ENOMEM;
|
|
goto free_out;
|
|
}
|
|
|
|
if (copy_from_user((void *)params_ptr, (void *)inparams.buffer_ptr,
|
|
inparams.size)) {
|
|
retval = -EFAULT;
|
|
goto free_buf;
|
|
}
|
|
|
|
outparams->buffer_ptr = (unsigned long)params_ptr;
|
|
|
|
mutex_lock(&card->effect_lock);
|
|
retval = card->effect_ops->get_params(card, outparams);
|
|
mutex_unlock(&card->effect_lock);
|
|
|
|
if (retval)
|
|
goto free_buf;
|
|
|
|
if (!outparams->size)
|
|
goto free_buf;
|
|
|
|
if (outparams->size > inparams.size) {
|
|
pr_err("mem insufficient to copy\n");
|
|
retval = -EMSGSIZE;
|
|
goto free_buf;
|
|
} else {
|
|
offset = offsetof(struct snd_effect_params, size);
|
|
if (copy_to_user((argp + offset), (void *)&outparams->size,
|
|
sizeof(u32)))
|
|
retval = -EFAULT;
|
|
|
|
if (copy_to_user((void *)inparams.buffer_ptr,
|
|
(void *) outparams->buffer_ptr, outparams->size))
|
|
retval = -EFAULT;
|
|
}
|
|
free_buf:
|
|
kfree(params_ptr);
|
|
free_out:
|
|
kfree(outparams);
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL_GPL(snd_ctl_effect_get_params);
|
|
|
|
int snd_ctl_effect_query_num_effects(struct snd_card *card, void *arg)
|
|
{
|
|
int retval = 0;
|
|
int __user *ip = arg;
|
|
|
|
mutex_lock(&card->effect_lock);
|
|
retval = card->effect_ops->query_num_effects(card);
|
|
mutex_unlock(&card->effect_lock);
|
|
|
|
if (retval < 0)
|
|
goto out;
|
|
retval = put_user(retval, ip) ? -EFAULT : 0;
|
|
out:
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL_GPL(snd_ctl_effect_query_num_effects);
|
|
|
|
int snd_ctl_effect_query_effect_caps(struct snd_card *card, void *arg)
|
|
{
|
|
int retval = 0;
|
|
struct snd_effect_caps *caps;
|
|
unsigned int offset, insize;
|
|
char *caps_ptr;
|
|
char __user *argp = (char __user *)arg;
|
|
char __user *bufp;
|
|
|
|
caps = kzalloc(sizeof(*caps), GFP_KERNEL);
|
|
if (!caps)
|
|
return -ENOMEM;
|
|
|
|
if (copy_from_user(caps, argp, sizeof(*caps))) {
|
|
retval = -EFAULT;
|
|
goto out;
|
|
}
|
|
|
|
bufp = (void __user *)caps->buffer_ptr;
|
|
insize = caps->size;
|
|
caps_ptr = kmalloc(caps->size, GFP_KERNEL);
|
|
if (!caps_ptr) {
|
|
retval = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
caps->buffer_ptr = (unsigned long)caps_ptr;
|
|
|
|
mutex_lock(&card->effect_lock);
|
|
retval = card->effect_ops->query_effect_caps(card, caps);
|
|
mutex_unlock(&card->effect_lock);
|
|
|
|
if (retval)
|
|
goto free_buf;
|
|
|
|
if (insize < caps->size) {
|
|
pr_err("mem insufficient to copy\n");
|
|
retval = -EMSGSIZE;
|
|
goto free_buf;
|
|
}
|
|
|
|
offset = offsetof(struct snd_effect_caps, size);
|
|
if (copy_to_user((argp + offset), (void *)&caps->size, sizeof(u32))) {
|
|
retval = -EFAULT;
|
|
goto free_buf;
|
|
}
|
|
|
|
if (copy_to_user(bufp, (void *)caps->buffer_ptr, caps->size))
|
|
retval = -EFAULT;
|
|
|
|
free_buf:
|
|
kfree(caps_ptr);
|
|
out:
|
|
kfree(caps);
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL_GPL(snd_ctl_effect_query_effect_caps);
|
|
|
|
/**
|
|
* snd_effect_register - register compressed device
|
|
*
|
|
* @card : snd card to which the effect is registered
|
|
* @ops : effect_ops to register
|
|
*/
|
|
int snd_effect_register(struct snd_card *card, struct snd_effect_ops *ops)
|
|
{
|
|
|
|
if (card == NULL || ops == NULL)
|
|
return -EINVAL;
|
|
|
|
if (snd_BUG_ON(!ops->create))
|
|
return -EINVAL;
|
|
if (snd_BUG_ON(!ops->destroy))
|
|
return -EINVAL;
|
|
if (snd_BUG_ON(!ops->set_params))
|
|
return -EINVAL;
|
|
|
|
mutex_init(&card->effect_lock);
|
|
|
|
pr_debug("Registering Effects to card %s\n", card->shortname);
|
|
/* register the effect ops with the card */
|
|
mutex_lock(&effect_mutex);
|
|
card->effect_ops = ops;
|
|
mutex_unlock(&effect_mutex);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(snd_effect_register);
|
|
|
|
int snd_effect_deregister(struct snd_card *card)
|
|
{
|
|
pr_debug("Removing effects for card %s\n", card->shortname);
|
|
mutex_lock(&effect_mutex);
|
|
card->effect_ops = NULL;
|
|
mutex_unlock(&effect_mutex);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(snd_effect_deregister);
|
|
|
|
static int __init snd_effect_init(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void __exit snd_effect_exit(void)
|
|
{
|
|
}
|
|
|
|
module_init(snd_effect_init);
|
|
module_exit(snd_effect_exit);
|
|
|
|
MODULE_DESCRIPTION("ALSA Effect offload framework");
|
|
MODULE_AUTHOR("Lakshmi N Vinnakota <lakshmi.n.vinnakota@intel.com>");
|
|
MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
|
|
MODULE_LICENSE("GPL v2");
|