sdk-hwV1.3/lichee/linux-4.9/sound/sunxi-rpaf/component/component-core.c

1672 lines
51 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* sound\sunxi-rpaf\component\component-core.c
* (C) Copyright 2019-2025
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* yumingfeng <yumingfeng@allwinnertech.com>
*
* some simple description for this code
*
* 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; either version 2 of
* the License, or (at your option) any later version.
*
*/
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/etherdevice.h>
#include <linux/crypto.h>
#include <linux/miscdevice.h>
#include <linux/capability.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <asm/cacheflush.h>
#include <sound/aw_rpaf/component-core.h>
#include <sound/aw_rpaf/rpmsg_hifi.h>
//#define RPAF_MEM_DEBUG_LOG
static unsigned int component_id[RPAF_COMPONENT_MAX_NUM] = {0};
static DEFINE_MUTEX(comp_id_mutex);
static DEFINE_SPINLOCK(comp_stream_lock);
static LIST_HEAD(snd_soc_rpaf_info_list);
static LIST_HEAD(snd_soc_dsp_component_list);
static DEFINE_MUTEX(rpaf_sub_list_mutex);
static DEFINE_MUTEX(rpaf_info_list_mutex);
void snd_soc_rpaf_pcm_stream_component_lock(void)
{
spin_lock(&comp_stream_lock);
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_pcm_stream_component_lock);
void snd_soc_rpaf_pcm_stream_component_unlock(void)
{
spin_unlock(&comp_stream_lock);
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_pcm_stream_component_unlock);
void snd_soc_rpaf_pcm_stream_lock(struct snd_dsp_component *dsp_component)
{
spin_lock(&dsp_component->lock);
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_pcm_stream_lock);
void snd_soc_rpaf_pcm_stream_lock_irq(struct snd_dsp_component *dsp_component)
{
local_irq_disable();
snd_soc_rpaf_pcm_stream_lock(dsp_component);
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_pcm_stream_lock_irq);
unsigned long snd_soc_rpaf_pcm_stream_lock_irqsave(struct snd_dsp_component *dsp_component)
{
unsigned long flags = 0;
local_irq_save(flags);
snd_soc_rpaf_pcm_stream_lock(dsp_component);
return flags;
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_pcm_stream_lock_irqsave);
void snd_soc_rpaf_pcm_stream_unlock(struct snd_dsp_component *dsp_component)
{
spin_unlock(&dsp_component->lock);
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_pcm_stream_unlock);
void snd_soc_rpaf_pcm_stream_unlock_irq(struct snd_dsp_component *dsp_component)
{
snd_soc_rpaf_pcm_stream_unlock(dsp_component);
local_irq_enable();
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_pcm_stream_unlock_irq);
void snd_soc_rpaf_pcm_stream_unlock_irqrestore(struct snd_dsp_component *dsp_component,
unsigned long flags)
{
snd_soc_rpaf_pcm_stream_unlock(dsp_component);
local_irq_restore(flags);
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_pcm_stream_unlock_irqrestore);
/* for snd_soc_dsp_component list operation api */
void snd_soc_dsp_component_list_add_tail(struct snd_soc_dsp_component *component)
{
mutex_lock(&rpaf_sub_list_mutex);
list_add_tail(&component->list, &snd_soc_dsp_component_list);
mutex_unlock(&rpaf_sub_list_mutex);
}
EXPORT_SYMBOL_GPL(snd_soc_dsp_component_list_add_tail);
void snd_soc_dsp_component_list_del(struct snd_soc_dsp_component *component)
{
mutex_lock(&rpaf_sub_list_mutex);
list_del(&component->list);
mutex_unlock(&rpaf_sub_list_mutex);
}
EXPORT_SYMBOL_GPL(snd_soc_dsp_component_list_del);
struct snd_soc_dsp_component *snd_soc_dsp_component_get_from_list_by_pcmdev(
int card, int device, int stream)
{
struct snd_soc_dsp_component *component = NULL;
struct snd_soc_dsp_pcm_params *pcm_params = NULL;
mutex_lock(&rpaf_sub_list_mutex);
list_for_each_entry(component, &snd_soc_dsp_component_list, list) {
pcm_params = &(component->params);
if (pcm_params->card == card &&
pcm_params->device == device &&
pcm_params->stream == stream) {
mutex_unlock(&rpaf_sub_list_mutex);
return component;
}
}
mutex_unlock(&rpaf_sub_list_mutex);
return NULL;
}
EXPORT_SYMBOL_GPL(snd_soc_dsp_component_get_from_list_by_pcmdev);
/* for snd_soc_rpaf_info list operation api */
void snd_soc_rpaf_info_list_add_tail(struct snd_soc_rpaf_info *rpaf_info)
{
mutex_lock(&rpaf_info_list_mutex);
list_add_tail(&rpaf_info->list, &snd_soc_rpaf_info_list);
mutex_unlock(&rpaf_info_list_mutex);
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_info_list_add_tail);
void snd_soc_rpaf_info_list_del(struct snd_soc_rpaf_info *rpaf_info)
{
mutex_lock(&rpaf_info_list_mutex);
list_del(&rpaf_info->list);
mutex_unlock(&rpaf_info_list_mutex);
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_info_list_del);
struct snd_soc_rpaf_info *snd_soc_rpaf_info_get_from_list_by_minor(int minor)
{
struct snd_soc_rpaf_info *rpaf_info;
mutex_lock(&rpaf_info_list_mutex);
list_for_each_entry(rpaf_info, &snd_soc_rpaf_info_list, list) {
if (rpaf_info->misc_dev.minor == minor) {
mutex_unlock(&rpaf_info_list_mutex);
return rpaf_info;
}
}
mutex_unlock(&rpaf_info_list_mutex);
return NULL;
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_info_get_from_list_by_minor);
struct snd_soc_rpaf_info *snd_soc_rpaf_info_get_from_list_by_dspid(unsigned int id)
{
struct snd_soc_rpaf_info *rpaf_info;
mutex_lock(&rpaf_info_list_mutex);
list_for_each_entry(rpaf_info, &snd_soc_rpaf_info_list, list) {
if (rpaf_info->dsp_id == id) {
mutex_unlock(&rpaf_info_list_mutex);
return rpaf_info;
}
}
mutex_unlock(&rpaf_info_list_mutex);
return NULL;
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_info_get_from_list_by_dspid);
struct snd_soc_rpaf_info *snd_soc_rpaf_info_get_from_list_by_miscdevice(
struct miscdevice *device)
{
struct snd_soc_rpaf_info *rpaf_info;
mutex_lock(&rpaf_info_list_mutex);
list_for_each_entry(rpaf_info, &snd_soc_rpaf_info_list, list) {
if (&rpaf_info->misc_dev == device) {
mutex_unlock(&rpaf_info_list_mutex);
return rpaf_info;
}
}
mutex_unlock(&rpaf_info_list_mutex);
return NULL;
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_info_get_from_list_by_miscdevice);
static int snd_soc_rpaf_misc_open(struct inode *inode, struct file *file)
{
struct snd_soc_rpaf_info *rpaf_info = NULL;
struct snd_dsp_component *dsp_component = NULL;
struct msg_component_package *msg_component = NULL;
int minor = iminor(inode);
int err = -ENODEV;
err = nonseekable_open(inode, file);
if (err < 0)
return err;
rpaf_info = snd_soc_rpaf_info_get_from_list_by_minor(minor);
if (IS_ERR_OR_NULL(rpaf_info))
return -EBADF;
dsp_component = kzalloc(sizeof(struct snd_dsp_component), GFP_KERNEL);
if (IS_ERR_OR_NULL(dsp_component)) {
dev_err(rpaf_info->dev, "%s cannot malloc for dsp_component.\n", __func__);
return -ENOMEM;
}
msg_component = &dsp_component->msg_component;
init_waitqueue_head(&msg_component->tsleep);
spin_lock_init(&msg_component->lock);
snd_soc_dsp_component_list_add_tail(&msg_component->soc_component);
dsp_component->rpaf_info = rpaf_info;
file->private_data = dsp_component;
dsp_component->state = SND_DSP_COMPONENT_STATE_OPEN;
mutex_init(&dsp_component->comp_rw_lock);
spin_lock_init(&dsp_component->lock);
#ifdef RPAF_MEM_DEBUG_LOG
dev_info(rpaf_info->dev, "%s line:%d dsp_component:%p, pa:0x%llx, __pa.component:0x%llx\n",
__func__, __LINE__, dsp_component, __pa(dsp_component),
__pa(&msg_component->soc_component));
#endif
return err;
}
static int snd_soc_rpaf_misc_common_stop(struct snd_dsp_component *dsp_component);
static int snd_soc_rpaf_misc_common_remove(struct snd_dsp_component *dsp_component);
static int snd_soc_rpaf_misc_release(struct inode *inode, struct file *file)
{
struct snd_dsp_component *dsp_component = file->private_data;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *component = &msg_component->soc_component;
struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
int i = 0;
int result;
/* 判断当前状态 */
switch (dsp_component->state) {
case SND_DSP_COMPONENT_STATE_START:
case SND_DSP_COMPONENT_STATE_RUNNING:
result = snd_soc_rpaf_misc_common_stop(dsp_component);
if (result < 0)
return result;
case SND_DSP_COMPONENT_STATE_STOP:
result = snd_soc_rpaf_misc_common_remove(dsp_component);
if (result < 0)
return result;
break;
case SND_DSP_COMPONENT_STATE_CLOSE:
default:
return -EINVAL;
case SND_DSP_COMPONENT_STATE_OPEN:
case SND_DSP_COMPONENT_STATE_CREATE:
case SND_DSP_COMPONENT_STATE_REMOVE:
break;
}
dsp_component->state = SND_DSP_COMPONENT_STATE_CLOSE;
/* 其它stream持有需要互斥 */
if (component->read_addr) {
dma_free_coherent(rpaf_info->dev, component->read_size,
dsp_component->read_area, component->read_addr);
#ifdef RPAF_MEM_DEBUG_LOG
dev_err(rpaf_info->dev, "read_area:%p, read_addr:0x%x\n",
dsp_component->read_area, component->read_addr);
#endif
component->read_addr = 0;
dsp_component->read_area = NULL;
}
for (i = 0; i < ARRAY_SIZE(component->dump_addr); i++) {
if (!component->dump_addr[i])
continue;
dma_free_coherent(rpaf_info->dev, component->dump_size,
dsp_component->dump_area[i], component->dump_addr[i]);
#ifdef RPAF_MEM_DEBUG_LOG
dev_err(rpaf_info->dev, "dump_area[%d]:%p, dump_addr:0x%x\n",
i, dsp_component->dump_area[i], component->dump_addr[i]);
#endif
component->dump_addr[i] = 0;
dsp_component->dump_area[i] = NULL;
}
if (component->write_addr) {
dma_free_coherent(rpaf_info->dev, component->write_size,
dsp_component->write_area, component->write_addr);
#ifdef RPAF_MEM_DEBUG_LOG
dev_err(rpaf_info->dev, "write_area:%p, write_addr:0x%x\n",
dsp_component->write_area, component->write_addr);
#endif
component->write_addr = 0;
dsp_component->write_area = NULL;
}
snd_soc_dsp_component_list_del(component);
mutex_destroy(&dsp_component->comp_rw_lock);
kfree(dsp_component);
return 0;
}
#if 0
/* 需要在lib_write接口返回后才可以调用操作,目前只支持一个dump地址 */
static ssize_t snd_soc_rpaf_misc_read(struct file *file, char __user *buf,
size_t count, loff_t *offset)
{
struct snd_dsp_component *dsp_component = file->private_data;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *component = &msg_component->soc_component;
unsigned int read_size = count;
if (count > component->read_size)
read_size = component->read_size;
/* 加个互斥锁 */
mutex_lock(&dsp_component->comp_rw_lock);
__dma_flush_range(dsp_component->read_area, read_size);
/* 无需和dsp通信只要等待lib_write接口返回后即可操作获取对应的dump数据 */
if (copy_to_user(buf, dsp_component->read_area, read_size)) {
mutex_unlock(&dsp_component->comp_rw_lock);
return -EFAULT;
}
mutex_unlock(&dsp_component->comp_rw_lock);
return read_size;
}
#endif
/* 需要在lib_write接口返回后才可以调用操作,目前只支持一个dump地址 */
ssize_t snd_soc_rpaf_misc_component_lib_read(struct snd_dsp_component *dsp_component,
struct snd_rpaf_xferi *xferi)
{
ssize_t size = xferi->dump_length;
ssize_t read_size = size;
char __user *buf = (char __user *)(xferi->dump_buf);
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *component = &msg_component->soc_component;
// struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
// struct snd_soc_dsp_pcm_params *pcm_params = &(component->params);
if (xferi->dump_type >= RPAF_COMPONENT_MAX_NUM)
return -EINVAL;
if (IS_ERR_OR_NULL(dsp_component->dump_area[xferi->dump_type]))
return -EFAULT;
/* 加个互斥锁 */
mutex_lock(&dsp_component->comp_rw_lock);
if (size > component->dump_size)
read_size = component->dump_size;
if (size > component->dump_length[xferi->dump_type])
read_size = component->dump_length[xferi->dump_type];
__dma_flush_range(dsp_component->dump_area[xferi->dump_type],
component->dump_size);
/* 无需和dsp通信只要等待lib_write接口返回后即可操作获取对应的dump数据 */
if (copy_to_user(buf, dsp_component->dump_area[xferi->dump_type], read_size)) {
mutex_unlock(&dsp_component->comp_rw_lock);
return -EFAULT;
}
xferi->dump_length = read_size;
mutex_unlock(&dsp_component->comp_rw_lock);
return read_size;
}
static int snd_soc_rpaf_pcm_wait_for_avail(struct snd_dsp_component *dsp_component,
snd_pcm_uframes_t *availp)
{
struct snd_soc_rpaf_pcm_runtime *runtime = &dsp_component->runtime;
wait_queue_t wait;
int err = 0;
snd_pcm_uframes_t avail = 0;
long wait_time, tout;
init_waitqueue_entry(&wait, current);
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&runtime->tsleep, &wait);
wait_time = msecs_to_jiffies(5 * 1000);
for (;;) {
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
}
/*
* We need to check if space became available already
* (and thus the wakeup happened already) first to close
* the race of space already having become available.
* This check must happen after been added to the waitqueue
* and having current state be INTERRUPTIBLE.
*/
avail = snd_soc_rpaf_pcm_capture_avail(runtime);
if (avail >= runtime->twake)
break;
snd_soc_rpaf_pcm_stream_unlock_irq(dsp_component);
tout = schedule_timeout(wait_time);
snd_soc_rpaf_pcm_stream_lock_irq(dsp_component);
set_current_state(TASK_INTERRUPTIBLE);
if (!tout) {
pr_alert("[%s] line:%d cannot get avail data.\n",
__func__, __LINE__);
err = -EIO;
break;
}
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&runtime->tsleep, &wait);
*availp = avail;
return err;
}
static int32_t snd_soc_rpaf_pcm_stream_lib_read_transfer(struct snd_dsp_component *dsp_component,
unsigned int hwoff,
unsigned long data, unsigned int off,
snd_pcm_uframes_t frames)
{
struct snd_soc_rpaf_pcm_runtime *runtime = &dsp_component->runtime;
char __user *buf = (char __user *) data +
snd_soc_rpaf_pcm_frames_to_bytes(runtime, off);
char *hwbuf = dsp_component->read_area +
snd_soc_rpaf_pcm_frames_to_bytes(runtime, hwoff);
ssize_t sizes = snd_soc_rpaf_pcm_frames_to_bytes(runtime, frames);
snd_soc_rpaf_pcm_stream_component_lock();
if (!dsp_component->private_data) {
awrpaf_err("pcm stream had been closed.\n");
snd_soc_rpaf_pcm_stream_component_unlock();
return -EFAULT;
}
if (copy_to_user(buf, hwbuf, sizes)) {
snd_soc_rpaf_pcm_stream_component_unlock();
return -EFAULT;
}
snd_soc_rpaf_pcm_stream_component_unlock();
return 0;
}
static int snd_soc_rpaf_pcm_update_hw_ptr(struct snd_dsp_component *dsp_component,
unsigned int in_interrupt)
{
struct snd_soc_rpaf_pcm_runtime *runtime = &dsp_component->runtime;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *soc_component = &msg_component->soc_component;
struct snd_soc_dsp_pcm_params *pcm_params = &(soc_component->params);
snd_pcm_uframes_t avail;
snd_pcm_uframes_t pos;
snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
snd_pcm_sframes_t delta;
old_hw_ptr = runtime->hw_ptr;
pos = snd_soc_rpaf_pcm_pointer(runtime);
if (pos >= runtime->buffer_size)
pos = 0;
hw_base = runtime->hw_ptr_base;
new_hw_ptr = hw_base + pos;
/*
* new_hw_ptr might be lower than old_hw_ptr in case
* when pointer cross the end of the ring buffer
*/
if (new_hw_ptr < old_hw_ptr) {
hw_base += runtime->buffer_size;
if (hw_base >= runtime->boundary) {
hw_base = 0;
}
new_hw_ptr = hw_base + pos;
}
delta = new_hw_ptr - old_hw_ptr;
/* it means cross the end of boundary */
if (delta < 0)
delta += runtime->boundary;
/* something must be really wrong */
if (delta >= runtime->buffer_size + runtime->period_size) {
pr_err("[%s] Unexpected hw_ptr, stream:%d, pos:%lu, new_hw_ptr:%lu, old_hw_ptr:%lu\n",
(in_interrupt) ? "Q" : "P",
pcm_params->stream, pos, new_hw_ptr, old_hw_ptr);
return 0;
}
if (delta > runtime->period_size + runtime->period_size / 2) {
pr_debug("[%s] Lost interrupts? stream:%d, pos:%lu, new_hw_ptr:%lu, old_hw_ptr:%lu\n",
(in_interrupt) ? "Q" : "P",
pcm_params->stream, pos, new_hw_ptr, old_hw_ptr);
}
if (runtime->hw_ptr == new_hw_ptr)
return 0;
runtime->hw_ptr_base = hw_base;
runtime->hw_ptr = new_hw_ptr;
/* update avail */
avail = snd_soc_rpaf_pcm_capture_avail(runtime);
if (avail > runtime->avail_max)
runtime->avail_max = avail;
if (avail >= runtime->buffer_size) {
return -EPIPE;
}
if (runtime->twake) {
if (avail >= runtime->twake)
wake_up(&runtime->tsleep);
}
return 0;
}
void snd_soc_rpaf_pcm_stream_update_complete(void *arg)
{
struct snd_dsp_component *dsp_component = arg;
struct snd_soc_rpaf_pcm_runtime *runtime = &dsp_component->runtime;
unsigned long flags;
flags = snd_soc_rpaf_pcm_stream_lock_irqsave(dsp_component);
runtime->pos += snd_soc_rpaf_pcm_frames_to_bytes(runtime,
runtime->period_size);
if (runtime->pos >= snd_soc_rpaf_pcm_frames_to_bytes(runtime,
runtime->buffer_size))
runtime->pos = 0;
if (snd_soc_rpaf_pcm_update_hw_ptr(dsp_component, 1) < 0) {
goto _end;
}
_end:
snd_soc_rpaf_pcm_stream_unlock_irqrestore(dsp_component, flags);
}
EXPORT_SYMBOL(snd_soc_rpaf_pcm_stream_update_complete);
static int snd_soc_rpaf_misc_common_start(struct snd_dsp_component *dsp_component);
ssize_t snd_soc_rpaf_misc_stream_lib_read(struct snd_dsp_component *dsp_component,
struct snd_rpaf_xferi *xferi, transfer_f transfer)
{
char __user *buf = (char __user *)(xferi->dump_buf);
struct snd_soc_rpaf_pcm_runtime *runtime = &dsp_component->runtime;
ssize_t size = xferi->dump_length;
snd_pcm_sframes_t xfer = 0;
snd_pcm_uframes_t offset = 0;
snd_pcm_uframes_t avail = 0;
ssize_t err = 0;
if (xferi->dump_type >= RPAF_COMPONENT_MAX_NUM)
return -EINVAL;
if (IS_ERR_OR_NULL(dsp_component->read_area))
return -EFAULT;
if (dsp_component->state != SND_DSP_COMPONENT_STATE_RUNNING) {
err = snd_soc_rpaf_misc_common_start(dsp_component);
if (err < 0) {
awrpaf_err("start failed.\n");
return err;
}
}
snd_soc_rpaf_pcm_stream_lock_irq(dsp_component);
if (!dsp_component->private_data) {
err = -EFAULT;
goto _end_unlock;
}
runtime->dump_type = xferi->dump_type;
runtime->dump_start = 1;
snd_soc_rpaf_pcm_update_hw_ptr(dsp_component, 0);
avail = snd_soc_rpaf_pcm_capture_avail(runtime);
while (size > 0) {
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
snd_pcm_uframes_t cont;
if (!avail) {
runtime->twake = 1;
err = snd_soc_rpaf_pcm_wait_for_avail(dsp_component, &avail);
if (err < 0)
goto _end_unlock;
if (!avail)
continue;
}
frames = size > avail ? avail : size;
cont = runtime->buffer_size - runtime->appl_ptr % runtime->buffer_size;
if (frames > cont)
frames = cont;
if (WARN_ON(!frames)) {
runtime->twake = 0;
snd_soc_rpaf_pcm_stream_unlock_irq(dsp_component);
return -EINVAL;
}
appl_ptr = runtime->appl_ptr;
appl_ofs = appl_ptr % runtime->buffer_size;
snd_soc_rpaf_pcm_stream_unlock_irq(dsp_component);
err = transfer(dsp_component, appl_ofs, (unsigned long)buf, offset, frames);
snd_soc_rpaf_pcm_stream_lock_irq(dsp_component);
if (err < 0)
goto _end_unlock;
appl_ptr += frames;
if (appl_ptr >= runtime->boundary)
appl_ptr -= runtime->boundary;
runtime->appl_ptr = appl_ptr;
offset += frames;
size -= frames;
xfer += frames;
avail -= frames;
}
_end_unlock:
runtime->twake = 0;
snd_soc_rpaf_pcm_stream_unlock_irq(dsp_component);
return xfer > 0 ? xfer : err;
}
ssize_t snd_soc_rpaf_misc_lib_read(struct snd_dsp_component *dsp_component,
struct snd_rpaf_xferi *xferi)
{
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *component = &msg_component->soc_component;
ssize_t read_size;
switch (component->comp_mode) {
case SND_DSP_COMPONENT_MODE_INDEPENDENCE:
read_size = snd_soc_rpaf_misc_component_lib_read(dsp_component, xferi);
dsp_component->state = SND_DSP_COMPONENT_STATE_RUNNING;
break;
case SND_DSP_COMPONENT_MODE_STREAM:
read_size = snd_soc_rpaf_misc_stream_lib_read(dsp_component,
xferi, snd_soc_rpaf_pcm_stream_lib_read_transfer);
dsp_component->state = SND_DSP_COMPONENT_STATE_RUNNING;
break;
default:
read_size = -EINVAL;
break;
}
return read_size;
}
static ssize_t snd_soc_rpaf_write_to_user(struct snd_dsp_component *dsp_component,
void __user * const data, ssize_t *size)
{
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *component = &msg_component->soc_component;
// struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
ssize_t write_size = *size;
char __user * const buf = (char __user * const)data;
// __dma_flush_range(component, sizeof(struct snd_soc_dsp_component));
if (*size > component->read_size)
write_size = component->read_size;
if (*size > component->read_length)
write_size = component->read_length;
__dma_flush_range(dsp_component->read_area, component->read_size);
if (copy_to_user(buf, dsp_component->read_area, write_size)) {
*size = 0;
return -EFAULT;
}
*size = write_size;
return write_size;
}
static ssize_t snd_soc_rpaf_misc_write(struct file *file, const char __user *buf,
size_t count, loff_t *offset)
{
struct snd_dsp_component *dsp_component = file->private_data;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *component = &msg_component->soc_component;
struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
ssize_t read_size = count;
int ret;
if (count > component->read_size)
read_size = component->read_size;
mutex_lock(&dsp_component->comp_rw_lock);
if (copy_from_user(dsp_component->write_area, buf, read_size)) {
mutex_unlock(&dsp_component->comp_rw_lock);
return 0;
}
__dma_flush_range(dsp_component->write_area, read_size);
component->cmd_val = SND_SOC_DSP_COMPONENT_WRITE;
/* 发送给msgbox to dsp */
ret = sunxi_hifi_component_block_send(rpaf_info->dsp_id, msg_component);
mutex_unlock(&dsp_component->comp_rw_lock);
if (ret < 0) {
pr_err("%s line:%d error:%d\n", __func__, __LINE__, ret);
return ret;
}
return read_size;
}
ssize_t snd_soc_rpaf_misc_lib_write(struct snd_dsp_component *dsp_component,
const void __user *data, ssize_t size)
{
struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *component = &msg_component->soc_component;
ssize_t read_size = size;
const char __user *buf = (const char __user *)data;
int ret;
if (IS_ERR_OR_NULL(dsp_component->write_area) ||
IS_ERR_OR_NULL(dsp_component->read_area))
return -EFAULT;
mutex_lock(&dsp_component->comp_rw_lock);
if (size > component->write_size)
read_size = component->write_size;
component->write_length = read_size;
if (copy_from_user(dsp_component->write_area, buf, read_size)) {
mutex_unlock(&dsp_component->comp_rw_lock);
return 0;
}
__dma_flush_range(dsp_component->write_area, read_size);
component->cmd_val = SND_SOC_DSP_COMPONENT_WRITE;
/* 发送给msgbox to dsp */
ret = sunxi_hifi_component_block_send(rpaf_info->dsp_id, msg_component);
mutex_unlock(&dsp_component->comp_rw_lock);
if (ret < 0) {
pr_err("%s line:%d error:%d\n", __func__, __LINE__, ret);
return ret;
}
return read_size;
}
static int snd_soc_rpaf_misc_lib_pcm_params(struct snd_soc_dsp_component *component,
struct snd_soc_dsp_pcm_params *params)
{
struct snd_soc_dsp_pcm_params *pcm_params = &(component->params);
pcm_params->channels = params->channels;
pcm_params->rate = params->rate;
pcm_params->card = params->card;
pcm_params->device = params->device;
pcm_params->format = params->format;
pcm_params->stream = params->stream;
pcm_params->resample_rate = params->resample_rate;
pcm_params->period_size = params->period_size;
pcm_params->periods = params->periods;
pcm_params->buffer_size = params->buffer_size;
pcm_params->pcm_frames = params->pcm_frames;
pcm_params->data_type = params->data_type;
/* mp3 - aac */
pcm_params->codec_type = params->codec_type;
pcm_params->hw_stream = params->hw_stream;
pcm_params->data_mode = params->data_mode;
strncpy(pcm_params->driver, params->driver, 31);
pcm_params->input_size = params->input_size;
pcm_params->output_size = params->output_size;
pcm_params->dump_size = params->dump_size;
memcpy(pcm_params->algo_params, params->algo_params, sizeof(params->algo_params));
#if 1//def RPAF_MEM_DEBUG_LOG
awrpaf_info("==================================\n");
awrpaf_info("channels = %d\n", pcm_params->channels);
awrpaf_info("rate = %d\n", pcm_params->rate);
awrpaf_info("card = %d\n", pcm_params->card);
awrpaf_info("device = %d\n", pcm_params->device);
awrpaf_info("format = %d\n", pcm_params->format);
awrpaf_info("stream = %d\n", pcm_params->stream);
awrpaf_info("resample_rate = %d\n", pcm_params->resample_rate);
awrpaf_info("period_size = %u\n", pcm_params->period_size);
awrpaf_info("buffer_size = %u\n", pcm_params->buffer_size);
awrpaf_info("data_type = %d\n", pcm_params->periods);
awrpaf_info("codec_type = %d\n", pcm_params->codec_type);
awrpaf_info("hw_stream = %d\n", pcm_params->hw_stream);
awrpaf_info("driver = %s\n", pcm_params->driver);
awrpaf_info("==================================\n");
#endif
return 0;
}
static void snd_soc_rpaf_runtime_pcm_params(struct snd_soc_rpaf_pcm_runtime *runtime,
struct snd_soc_dsp_pcm_params *pcm_params)
{
int bits = 0;
/* -- HW params -- */
switch (pcm_params->format) {
case SNDRV_PCM_FORMAT_S16:
case SNDRV_PCM_FORMAT_U16:
bits = 16;
break;
case SNDRV_PCM_FORMAT_S24:
case SNDRV_PCM_FORMAT_U24:
case SNDRV_PCM_FORMAT_S32:
case SNDRV_PCM_FORMAT_U32:
bits = 32;
break;
}
runtime->frame_bits = pcm_params->channels * bits;
/* period size */
runtime->period_size = pcm_params->period_size;
/* buffer size */
runtime->buffer_size = pcm_params->buffer_size;
runtime->avail_max = runtime->buffer_size;
/* -- SW params -- */
/* Silence filling size */
runtime->silence_size = runtime->buffer_size;
/* pointers wrap point */
runtime->boundary = runtime->buffer_size;
while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
runtime->boundary *= 2;
/* transfer sleep */
init_waitqueue_head(&runtime->tsleep);
}
static int snd_soc_rpaf_misc_set_component_config_from_user(
struct snd_dsp_component *dsp_component,
struct snd_soc_dsp_component_config __user *_component_config)
{
struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
struct snd_soc_rpaf_pcm_runtime *runtime = &dsp_component->runtime;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *component = &msg_component->soc_component;
struct snd_soc_dsp_pcm_params *params;
struct snd_soc_dsp_component_config *component_config;
struct msg_component_package *stream_msg_component = NULL;
struct snd_dsp_component *stream_dsp_component = NULL;
int i = 0;
int ret = 0;
component_config = memdup_user(_component_config, sizeof(*component_config));
if (IS_ERR(component_config))
return PTR_ERR(component_config);
params = &component_config->pcm_params;
component->comp_mode = component_config->comp_mode;
component->component_type = component_config->component_type;
component->transfer_type = component_config->transfer_type;
memcpy(component->component_sort, component_config->component_sort,
sizeof(component->component_sort));
if (params->pcm_frames == 0) {
kfree(component_config);
return -EFAULT;
}
ret = snd_soc_rpaf_misc_lib_pcm_params(component, params);
if (ret < 0)
goto err_set_misc_lib_pcm_params;
snd_soc_rpaf_runtime_pcm_params(&dsp_component->runtime, params);
switch (component_config->comp_mode) {
case SND_DSP_COMPONENT_MODE_INDEPENDENCE:
component->write_size = params->input_size;
component->read_size = params->output_size;
component->dump_size = params->dump_size;
break;
case SND_DSP_COMPONENT_MODE_STREAM:
component->write_size = 0;
component->dump_size = 0;
component->read_size = snd_soc_rpaf_pcm_frames_to_bytes(runtime,
runtime->buffer_size);
break;
default:
goto err_set_misc_lib_pcm_params;
return -EINVAL;
}
if ((component->write_size) && (!component->write_addr)) {
dma_addr_t write_addr;
dsp_component->write_area = dma_alloc_coherent(rpaf_info->dev,
component->write_size,
&write_addr, GFP_KERNEL);
if (IS_ERR_OR_NULL(dsp_component->write_area)) {
ret = -ENOMEM;
goto err_malloc_write_addr;
}
component->write_addr = write_addr;
}
if ((component->read_size) && (!component->read_addr)) {
dma_addr_t read_addr;
dsp_component->read_area = dma_alloc_coherent(rpaf_info->dev,
component->read_size,
&read_addr, GFP_KERNEL);
if (IS_ERR_OR_NULL(dsp_component->read_area)) {
ret = -ENOMEM;
goto err_malloc_read_addr;
}
component->read_addr = read_addr;
}
dsp_component->state = SND_DSP_COMPONENT_STATE_SETUP;
if (component_config->comp_mode == SND_DSP_COMPONENT_MODE_STREAM)
goto _wait_msg_component_stream;
if (!component->dump_size)
goto _ignore_dump_area;
for (i = 0; i < ARRAY_SIZE(component->dump_addr); i++) {
dma_addr_t dump_addr;
if (component->dump_addr[i])
continue;
if ((component->component_type >> i) & 0x1) {
dsp_component->dump_area[i] = dma_alloc_coherent(rpaf_info->dev,
component->dump_size,
&dump_addr, GFP_KERNEL);
if (IS_ERR_OR_NULL(dsp_component->dump_area[i])) {
ret = -ENOMEM;
goto err_malloc_dump_addr;
}
component->dump_addr[i] = dump_addr;
}
}
_ignore_dump_area:
kfree(component_config);
return ret;
_wait_msg_component_stream:
/* 找到对应的音频流寻找不超过10秒? */
do {
static int i = 1;
stream_msg_component = sunxi_hifi_list_msg_component_find_item(msg_component);
if (i++ >= 100) {
i = 0;
awrpaf_err("cannot find running msg_component.\n");
ret = -EFAULT;
goto err_find_msg_component;
}
msleep(100);
} while (!stream_msg_component);
stream_dsp_component = container_of(stream_msg_component, struct snd_dsp_component,
msg_component);
/* 把参数给到pcm stream处理那一端 */
snd_soc_rpaf_pcm_stream_component_lock();
stream_dsp_component->private_data = dsp_component;
dsp_component->private_data = stream_dsp_component;
snd_soc_rpaf_pcm_stream_component_unlock();
kfree(component_config);
return ret;
err_find_msg_component:
err_malloc_dump_addr:
dma_free_coherent(rpaf_info->dev, component->read_size,
dsp_component->read_area, component->read_addr);
component->read_addr = 0;
dsp_component->read_area = NULL;
for (i = 0; i < ARRAY_SIZE(component->dump_addr); i++) {
if (!component->dump_addr[i])
continue;
dma_free_coherent(rpaf_info->dev, component->dump_size,
dsp_component->dump_area[i], component->dump_addr[i]);
component->dump_addr[i] = 0;
dsp_component->dump_area[i] = NULL;
}
err_malloc_read_addr:
dma_free_coherent(rpaf_info->dev, component->write_size,
dsp_component->write_area, component->write_addr);
component->write_addr = 0;
dsp_component->write_area = NULL;
err_malloc_write_addr:
err_set_misc_lib_pcm_params:
kfree(component_config);
return ret;
}
static int snd_soc_rpaf_misc_set_pcm_params_to_user(struct snd_dsp_component *dsp_component,
struct snd_soc_dsp_pcm_params __user *_params)
{
struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
dev_err(rpaf_info->dev, "%s line:%d\n", __func__, __LINE__);
return 0;
}
static int snd_soc_rpaf_misc_common_set_algo(struct snd_dsp_component *dsp_component,
void __user *arg)
{
struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *soc_component = &msg_component->soc_component;
struct snd_soc_dsp_component_config __user *_component_config = arg;
struct snd_soc_dsp_component_config component_config;
int ret;
if (copy_from_user(&component_config, _component_config,
sizeof(struct snd_soc_dsp_component_config))) {
dev_err(rpaf_info->dev, "cannot copy component_config.\n");
return -EFAULT;
}
soc_component->comp_mode = component_config.comp_mode;
soc_component->component_type = component_config.component_type;
strcpy(soc_component->params.driver, component_config.pcm_params.driver);
soc_component->transfer_type = component_config.transfer_type;
soc_component->sort_index = component_config.sort_index;
soc_component->used = component_config.component_used;
soc_component->params.stream = component_config.pcm_params.stream;
dev_dbg(rpaf_info->dev, "%s:Line:%d, driver:%s\n"
"component_config.comp_mode:%d, soc_component->comp_mode:%d\n"
"component_config.component_type:%d, soc_component->component_type:%d\n"
"component_config.sort_index:%d, soc_componen->sort_index:%d\n"
"component_config.pcm_params.stream:%d, soc_component->params.stream:%d\n"
"component_config.component_used:%d, soc_component->used:%d.\n",
__func__, __LINE__, soc_component->params.driver,
component_config.comp_mode, soc_component->comp_mode,
component_config.component_type, soc_component->component_type,
component_config.sort_index, soc_component->sort_index,
component_config.pcm_params.stream, soc_component->params.stream,
component_config.component_used, soc_component->used);
soc_component->cmd_val = SND_SOC_DSP_COMPONENT_ALGO_SET;
/* 发送给msgbox to dsp */
ret = sunxi_hifi_component_block_send(rpaf_info->dsp_id, msg_component);
if (ret < 0) {
pr_err("%s line:%d error:%d\n", __func__, __LINE__, ret);
return ret;
}
return 0;
}
static int snd_soc_rpaf_misc_common_get_algo(struct snd_dsp_component *dsp_component,
void __user *arg)
{
struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *soc_component = &msg_component->soc_component;
struct snd_soc_dsp_component_config __user *_component_config = arg;
struct snd_soc_dsp_component_config component_config;
int ret;
if (copy_from_user(&component_config, _component_config,
sizeof(struct snd_soc_dsp_component_config))) {
dev_err(rpaf_info->dev, "cannot copy component_config.\n");
return -EFAULT;
}
soc_component->cmd_val = SND_SOC_DSP_COMPONENT_ALGO_GET;
soc_component->comp_mode = SND_DSP_COMPONENT_MODE_ALGO;
soc_component->component_type = component_config.component_type;
strcpy(soc_component->params.driver, component_config.pcm_params.driver);
soc_component->transfer_type = component_config.transfer_type;
soc_component->sort_index = component_config.sort_index;
soc_component->used = component_config.component_used;
soc_component->params.stream = component_config.pcm_params.stream;
/* 发送给msgbox to dsp */
ret = sunxi_hifi_component_block_send(rpaf_info->dsp_id, msg_component);
if (ret < 0) {
pr_err("%s line:%d error:%d\n", __func__, __LINE__, ret);
return ret;
}
dev_dbg(rpaf_info->dev, "%s:Line:%d, driver:%s\n"
"component_config.comp_mode:%d, soc_component->comp_mode:%d\n"
"component_config.component_type:%d, soc_component->component_type:%d\n"
"component_config.sort_index:%d, soc_componen->sort_index:%d\n"
"component_config.pcm_params.stream:%d, soc_component->params.stream:%d\n"
"component_config.component_used:%d, soc_component->used:%d.\n",
__func__, __LINE__, soc_component->params.driver,
component_config.comp_mode, soc_component->comp_mode,
component_config.component_type, soc_component->component_type,
component_config.sort_index, soc_component->sort_index,
component_config.pcm_params.stream, soc_component->params.stream,
component_config.component_used, soc_component->used);
component_config.pcm_params.stream = soc_component->params.stream;
component_config.comp_mode = soc_component->comp_mode;
component_config.component_type = soc_component->component_type;
component_config.sort_index = soc_component->sort_index;
strcpy(component_config.pcm_params.driver, soc_component->params.driver);
if (copy_to_user(_component_config, &component_config,
sizeof(struct snd_soc_dsp_component_config))) {
dev_err(rpaf_info->dev, "cannot copy component_config.\n");
return -EFAULT;
}
return 0;
}
static int snd_soc_rpaf_misc_common_create(struct snd_dsp_component *dsp_component,
void __user *arg)
{
struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *soc_component = &msg_component->soc_component;
int i = 0;
int result = 0;
/* 判断当前状态 */
switch (dsp_component->state) {
case SND_DSP_COMPONENT_STATE_CREATE:
case SND_DSP_COMPONENT_STATE_SETUP:
case SND_DSP_COMPONENT_STATE_START:
case SND_DSP_COMPONENT_STATE_RUNNING:
case SND_DSP_COMPONENT_STATE_STOP:
case SND_DSP_COMPONENT_STATE_REMOVE:
case SND_DSP_COMPONENT_STATE_CLOSE:
default:
return -EINVAL;
case SND_DSP_COMPONENT_STATE_OPEN:
break;
}
/* 检查下是否有设置ID */
mutex_lock(&comp_id_mutex);
for (i = 0; i < RPAF_COMPONENT_MAX_NUM; i++) {
if (!component_id[i]) {
soc_component->id = i;
component_id[i] = 1;
break;
}
}
mutex_unlock(&comp_id_mutex);
if (soc_component->id != i) {
awrpaf_err("component id num [%d] set id:%u failed, should be less than %lu!\n",
i, soc_component->id, RPAF_COMPONENT_MAX_NUM);
return -EINVAL;
}
/* 状态跳转 */
dsp_component->state = SND_DSP_COMPONENT_STATE_CREATE;
/* 状态跳转SETUP */
result = snd_soc_rpaf_misc_set_component_config_from_user(dsp_component, arg);
if (result < 0) {
awrpaf_err("component[%u] setting pcm_params failed!\n", soc_component->id);
return result;
}
mutex_lock(&comp_id_mutex);
component_id[soc_component->id] = 1;
mutex_unlock(&comp_id_mutex);
if (soc_component->comp_mode == SND_DSP_COMPONENT_MODE_STREAM) {
return result;
}
soc_component->cmd_val = SND_SOC_DSP_COMPONENT_CREATE;
/* 发送给msgbox to dsp */
result = sunxi_hifi_component_block_send(rpaf_info->dsp_id, msg_component);
if (result < 0) {
pr_err("%s line:%d error:%d\n", __func__, __LINE__, result);
return result;
}
return result;
}
static int snd_soc_rpaf_misc_common_remove(struct snd_dsp_component *dsp_component)
{
struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *soc_component = &msg_component->soc_component;
struct snd_dsp_component *stream_dsp_component = NULL;
int ret;
/* 判断当前状态 */
switch (dsp_component->state) {
case SND_DSP_COMPONENT_STATE_CREATE:
case SND_DSP_COMPONENT_STATE_START:
case SND_DSP_COMPONENT_STATE_RUNNING:
case SND_DSP_COMPONENT_STATE_REMOVE:
case SND_DSP_COMPONENT_STATE_CLOSE:
default:
return -EINVAL;
case SND_DSP_COMPONENT_STATE_OPEN:
case SND_DSP_COMPONENT_STATE_SETUP:
case SND_DSP_COMPONENT_STATE_STOP:
break;
}
mutex_lock(&comp_id_mutex);
component_id[soc_component->id] = 0;
mutex_unlock(&comp_id_mutex);
if (soc_component->comp_mode == SND_DSP_COMPONENT_MODE_STREAM) {
snd_soc_rpaf_pcm_stream_component_lock();
stream_dsp_component = dsp_component->private_data;
if (stream_dsp_component && stream_dsp_component->private_data) {
stream_dsp_component->private_data = NULL;
dsp_component->private_data = NULL;
}
snd_soc_rpaf_pcm_stream_component_unlock();
dsp_component->state = SND_DSP_COMPONENT_STATE_REMOVE;
return 0;
}
soc_component->cmd_val = SND_SOC_DSP_COMPONENT_REMOVE;
/* 发送给msgbox to dsp */
ret = sunxi_hifi_component_block_send(rpaf_info->dsp_id, msg_component);
if (ret < 0) {
pr_err("%s line:%d error:%d\n", __func__, __LINE__, ret);
return ret;
}
/* 状态跳转 */
dsp_component->state = SND_DSP_COMPONENT_STATE_REMOVE;
return 0;
}
static int snd_soc_rpaf_misc_common_status(struct snd_dsp_component *dsp_component)
{
struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
dev_err(rpaf_info->dev, "%s line:%d\n", __func__, __LINE__);
/* 发送/不发送给msgbox to dsp */
return 0;
}
static void snd_soc_rpaf_runtime_prepare(struct snd_soc_rpaf_pcm_runtime *runtime)
{
runtime->pos = 0;
runtime->hw_ptr = 0;
runtime->appl_ptr = 0;
/* Position at buffer restart */
runtime->hw_ptr_base = 0;
/* Position at interrupt time */
runtime->hw_ptr_interrupt = 0;
/* offset for hw_ptr due to boundary wrap-around */
runtime->hw_ptr_wrap = 0;
}
static int snd_soc_rpaf_misc_common_start(struct snd_dsp_component *dsp_component)
{
struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *soc_component = &msg_component->soc_component;
struct snd_soc_rpaf_pcm_runtime *runtime = &dsp_component->runtime;
int ret;
/* 判断当前状态 */
switch (dsp_component->state) {
case SND_DSP_COMPONENT_STATE_OPEN:
case SND_DSP_COMPONENT_STATE_CREATE:
case SND_DSP_COMPONENT_STATE_START:
case SND_DSP_COMPONENT_STATE_RUNNING:
case SND_DSP_COMPONENT_STATE_REMOVE:
case SND_DSP_COMPONENT_STATE_CLOSE:
default:
return -EINVAL;
case SND_DSP_COMPONENT_STATE_SETUP:
case SND_DSP_COMPONENT_STATE_STOP:
break;
}
if (soc_component->comp_mode == SND_DSP_COMPONENT_MODE_STREAM) {
snd_soc_rpaf_pcm_stream_lock_irq(dsp_component);
/* 复位指针位置 */
snd_soc_rpaf_runtime_prepare(runtime);
snd_soc_rpaf_pcm_stream_unlock_irq(dsp_component);
}
soc_component->cmd_val = SND_SOC_DSP_COMPONENT_START;
/* 发送给msgbox to dsp */
ret = sunxi_hifi_component_block_send(rpaf_info->dsp_id, msg_component);
if (ret < 0) {
pr_err("%s line:%d error:%d\n", __func__, __LINE__, ret);
return ret;
}
/* 状态跳转 */
dsp_component->state = SND_DSP_COMPONENT_STATE_START;
return 0;
}
static int snd_soc_rpaf_misc_common_stop(struct snd_dsp_component *dsp_component)
{
struct snd_soc_rpaf_info *rpaf_info = dsp_component->rpaf_info;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *soc_component = &msg_component->soc_component;
struct snd_soc_rpaf_pcm_runtime *runtime = &dsp_component->runtime;
int ret;
/* 判断当前状态 */
switch (dsp_component->state) {
case SND_DSP_COMPONENT_STATE_OPEN:
case SND_DSP_COMPONENT_STATE_CREATE:
case SND_DSP_COMPONENT_STATE_SETUP:
case SND_DSP_COMPONENT_STATE_STOP:
case SND_DSP_COMPONENT_STATE_REMOVE:
case SND_DSP_COMPONENT_STATE_CLOSE:
default:
return -EINVAL;
case SND_DSP_COMPONENT_STATE_START:
case SND_DSP_COMPONENT_STATE_RUNNING:
break;
}
runtime->dump_start = 0;
soc_component->cmd_val = SND_SOC_DSP_COMPONENT_STOP;
/* 发送给msgbox to dsp */
ret = sunxi_hifi_component_block_send(rpaf_info->dsp_id, msg_component);
if (ret < 0) {
pr_err("%s line:%d error:%d\n", __func__, __LINE__, ret);
return ret;
}
/* 状态跳转 */
dsp_component->state = SND_DSP_COMPONENT_STATE_STOP;
return 0;
}
static long snd_soc_rpaf_misc_common_ioctl(struct file *file,
struct snd_dsp_component *dsp_component,
unsigned int cmd,
void __user *arg)
{
int result;
struct snd_soc_rpaf_info *rpaf_info;
if (IS_ERR_OR_NULL(dsp_component))
return -ENXIO;
rpaf_info = dsp_component->rpaf_info;
switch (cmd) {
case SND_SOC_DSP_COMPONENT_IOCTL_ALGO_SET:
result = snd_soc_rpaf_misc_common_set_algo(dsp_component, arg);
break;
case SND_SOC_DSP_COMPONENT_IOCTL_ALGO_GET:
result = snd_soc_rpaf_misc_common_get_algo(dsp_component, arg);
break;
case SND_SOC_DSP_COMPONENT_IOCTL_CREATE:
result = snd_soc_rpaf_misc_common_create(dsp_component, arg);
break;
case SND_SOC_DSP_COMPONENT_IOCTL_REMOVE:
result = snd_soc_rpaf_misc_common_remove(dsp_component);
put_user(result, (int __user *)arg);
break;
case SND_SOC_DSP_COMPONENT_IOCTL_STATUS:
result = snd_soc_rpaf_misc_common_status(dsp_component);
put_user(result, (int __user *)arg);
break;
case SND_SOC_DSP_COMPONENT_IOCTL_SW_PARAMS:
result = snd_soc_rpaf_misc_set_pcm_params_to_user(dsp_component, arg);
break;
case SND_SOC_DSP_COMPONENT_IOCTL_START:
result = snd_soc_rpaf_misc_common_start(dsp_component);
put_user(result, (int __user *)arg);
break;
case SND_SOC_DSP_COMPONENT_IOCTL_STOP:
result = snd_soc_rpaf_misc_common_stop(dsp_component);
put_user(result, (int __user *)arg);
break;
case SND_SOC_DSP_COMPONENT_IOCTL_READ32:
{
struct snd_rpaf_xferi xferi;
struct snd_rpaf_xferi32 __user *_xferi32 = arg;
int result;
compat_caddr_t buf;
get_user(xferi.result, &_xferi32->result);
get_user(buf, &_xferi32->input_buf);
xferi.input_buf = compat_ptr(buf);
get_user(xferi.input_length, &_xferi32->input_length);
get_user(buf, &_xferi32->output_buf);
xferi.output_buf = compat_ptr(buf);
get_user(xferi.output_length, &_xferi32->output_length);
get_user(buf, &_xferi32->dump_buf);
xferi.dump_buf = compat_ptr(buf);
get_user(xferi.dump_length, &_xferi32->dump_length);
get_user(xferi.dump_type, &_xferi32->dump_type);
result = snd_soc_rpaf_misc_lib_read(dsp_component, &xferi);
__put_user(result, &_xferi32->result);
return result < 0 ? result : 0;
}
case SND_SOC_DSP_COMPONENT_IOCTL_READ:
{
struct snd_rpaf_xferi xferi;
struct snd_rpaf_xferi __user *_xferi = arg;
if (put_user(0, &_xferi->result))
return -EFAULT;
if (copy_from_user(&xferi, _xferi, sizeof(struct snd_rpaf_xferi)))
return -EFAULT;
result = snd_soc_rpaf_misc_lib_read(dsp_component, &xferi);
if (copy_to_user(_xferi, &xferi, sizeof(*_xferi)))
return -EFAULT;
__put_user(result, &_xferi->result);
return result < 0 ? result : 0;
}
case SND_SOC_DSP_COMPONENT_IOCTL_WRITE:
{
struct snd_rpaf_xferi xferi;
struct snd_rpaf_xferi __user *_xferi = arg;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *component = &msg_component->soc_component;
int result;
if (put_user(0, &_xferi->result))
return -EFAULT;
if (copy_from_user(&xferi, _xferi, sizeof(*_xferi)))
return -EFAULT;
dsp_component->state = SND_DSP_COMPONENT_STATE_RUNNING;
component->write_length = xferi.input_length;
component->read_length = xferi.output_length;
result = snd_soc_rpaf_misc_lib_write(dsp_component, xferi.input_buf,
xferi.input_length);
if (result < 0) {
__put_user(result, &_xferi->result);
return result < 0 ? result : 0;
}
/* 回写回来 */
result = snd_soc_rpaf_write_to_user(dsp_component, xferi.output_buf,
&xferi.output_length);
if (copy_to_user(_xferi, &xferi, sizeof(*_xferi)))
return -EFAULT;
__put_user(result, &_xferi->result);
return result < 0 ? result : 0;
}
case SND_SOC_DSP_COMPONENT_IOCTL_WRITE32:
{
struct snd_rpaf_xferi xferi;
struct snd_rpaf_xferi32 __user *_xferi32 = arg;
struct msg_component_package *msg_component = &dsp_component->msg_component;
struct snd_soc_dsp_component *component = &msg_component->soc_component;
int result;
compat_caddr_t buf;
get_user(xferi.result, &_xferi32->result);
get_user(buf, &_xferi32->input_buf);
xferi.input_buf = compat_ptr(buf);
get_user(xferi.input_length, &_xferi32->input_length);
get_user(buf, &_xferi32->output_buf);
xferi.output_buf = compat_ptr(buf);
get_user(xferi.output_length, &_xferi32->output_length);
get_user(buf, &_xferi32->dump_buf);
xferi.dump_buf = compat_ptr(buf);
get_user(xferi.dump_length, &_xferi32->dump_length);
get_user(xferi.dump_type, &_xferi32->dump_type);
dsp_component->state = SND_DSP_COMPONENT_STATE_RUNNING;
component->write_length = xferi.input_length;
component->read_length = xferi.output_length;
result = snd_soc_rpaf_misc_lib_write(dsp_component, xferi.input_buf,
xferi.input_length);
if (result < 0) {
__put_user(result, &_xferi32->result);
return result < 0 ? result : 0;
}
/* 回写回来 */
result = snd_soc_rpaf_write_to_user(dsp_component, xferi.output_buf,
&xferi.output_length);
__put_user(result, &_xferi32->result);
__put_user(xferi.output_length, &_xferi32->output_length);
return result < 0 ? result : 0;
}
default:
dev_err(rpaf_info->dev, "%s cmd:%d not exist.\n", __func__, cmd);
return -EINVAL;
}
return result;
}
static long snd_soc_rpaf_misc_compat_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg)
{
struct snd_dsp_component *dsp_component = file->private_data;
void __user *argp = compat_ptr(arg);
if (((cmd >> 8) & 0xFF) != 'C')
return -ENOTTY;
return snd_soc_rpaf_misc_common_ioctl(file, dsp_component, cmd, argp);
}
static long snd_soc_rpaf_misc_unlocked_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg)
{
struct snd_dsp_component *dsp_component = file->private_data;
if (((cmd >> 8) & 0xFF) != 'C')
return -ENOTTY;
return snd_soc_rpaf_misc_common_ioctl(file, dsp_component, cmd,
(void __user *)arg);
}
static const struct file_operations snd_soc_rpaf_misc_f_ops = {
.owner = THIS_MODULE,
.open = snd_soc_rpaf_misc_open,
.unlocked_ioctl = snd_soc_rpaf_misc_unlocked_ioctl,
.compat_ioctl = snd_soc_rpaf_misc_compat_ioctl,
// .read = snd_soc_rpaf_misc_read,
.write = snd_soc_rpaf_misc_write,
.llseek = no_llseek,
.release = snd_soc_rpaf_misc_release,
};
static struct miscdevice snd_soc_rpaf_misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "sunxi-rpaf-dsp",
.fops = &snd_soc_rpaf_misc_f_ops,
};
int snd_soc_rpaf_misc_register_device(struct device *dev, unsigned int dsp_id)
{
char *str_name = NULL;
struct snd_soc_rpaf_info *rpaf_info = NULL;
int ret = 0;
if (IS_ERR_OR_NULL(dev)) {
pr_alert("[%s] dev id:%u is null.\n", __func__, dsp_id);
return -EFAULT;
}
if (snd_soc_rpaf_info_get_from_list_by_dspid(dsp_id) != NULL) {
dev_err(dev, "the dsp_id had been register!\n");
return -EINVAL;
}
rpaf_info = devm_kzalloc(dev, sizeof(struct snd_soc_rpaf_info),
GFP_KERNEL);
if (IS_ERR_OR_NULL(rpaf_info)) {
dev_err(dev, "kzalloc for snd_soc_rpaf_info failed.\n");
return -ENOMEM;
}
rpaf_info->dev = dev;
rpaf_info->dsp_id = dsp_id;
memset(rpaf_info->name, 0, sizeof(rpaf_info->name));
snprintf(rpaf_info->name, sizeof(rpaf_info->name),
"rpaf_misc%d", rpaf_info->dsp_id);
snd_soc_rpaf_info_set_drvdata(rpaf_info, dev_get_drvdata(rpaf_info->dev));
memcpy(&rpaf_info->misc_dev, &snd_soc_rpaf_misc_dev,
sizeof(struct miscdevice));
str_name = devm_kzalloc(dev, SUNXI_RPAF_INFO_NAME_LEN, GFP_KERNEL);
if (IS_ERR_OR_NULL(str_name)) {
dev_err(dev, "failed to kzalloc attr group name!\n");
ret = -ENOMEM;
goto err_kzalloc_misc_dev_name;
}
memset(str_name, 0, SUNXI_RPAF_INFO_NAME_LEN);
snprintf(str_name, SUNXI_RPAF_INFO_NAME_LEN,
"rpaf-dsp%d", rpaf_info->dsp_id);
rpaf_info->misc_dev.name = str_name;
ret = misc_register(&rpaf_info->misc_dev);
if (ret < 0) {
dev_err(dev, "sunxi-rpaf register driver as misc device error!\n");
goto err_misc_register;
}
snd_soc_rpaf_info_list_add_tail(rpaf_info);
dev_info(dev, "register device finished!\n");
return 0;
err_misc_register:
if (!IS_ERR_OR_NULL(rpaf_info->misc_dev.name)) {
str_name = (char *)rpaf_info->misc_dev.name;
devm_kfree(dev, str_name);
}
err_kzalloc_misc_dev_name:
devm_kfree(dev, rpaf_info);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_misc_register_device);
int snd_soc_rpaf_misc_deregister_device(struct device *dev, unsigned int dsp_id)
{
struct snd_soc_rpaf_info *rpaf_info = NULL;
int ret = 0;
if (IS_ERR_OR_NULL(dev)) {
pr_alert("[%s] dev id:%u is null.\n", __func__, dsp_id);
return -EFAULT;
}
rpaf_info = snd_soc_rpaf_info_get_from_list_by_dspid(dsp_id);
if (IS_ERR_OR_NULL(rpaf_info)) {
dev_err(dev, "the dsp_id had been del from rpaf_info list.!\n");
return -EINVAL;
}
misc_deregister(&rpaf_info->misc_dev);
if (!IS_ERR_OR_NULL(rpaf_info->misc_dev.name))
devm_kfree(dev, (char *)rpaf_info->misc_dev.name);
snd_soc_rpaf_info_list_del(rpaf_info);
dev_info(dev, "deregister device finished!\n");
devm_kfree(dev, rpaf_info);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_rpaf_misc_deregister_device);
MODULE_DESCRIPTION("sunxi dsp remote processor audio framework core");
MODULE_AUTHOR("yumingfeng@allwinnertech.com");
MODULE_LICENSE("GPL");