blob: f8c8133fb6fbdf4a06ae894c9449480d063a2571 [file] [log] [blame]
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_TAG "audio_adsp_hdlr_event"
/*#define LOG_NDEBUG 0*/
/*#define VERY_VERY_VERBOSE_LOGGING*/
#ifdef VERY_VERY_VERBOSE_LOGGING
#define ALOGVV ALOGV
#else
#define ALOGVV(a...) do { } while(0)
#endif
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#include <log/log.h>
#include <cutils/sched_policy.h>
#include <system/thread_defs.h>
#include <sound/asound.h>
#include <linux/msm_audio.h>
#include "audio_hw.h"
#include "audio_defs.h"
#include "platform.h"
#include "platform_api.h"
#include "adsp_hdlr.h"
#define MAX_EVENT_PAYLOAD 512
#define WAIT_EVENT_POLL_TIMEOUT 50
#define MIXER_MAX_BYTE_LENGTH 512
struct adsp_hdlr_stream_data {
struct adsp_hdlr_stream_cfg config;
stream_callback_t client_callback;
void *client_cookie;
};
struct adsp_hdlr_event_info {
struct listnode list;
void *stream_handle;
char mixer_ctl_name[MIXER_PATH_MAX_LENGTH];
char cb_mixer_ctl_name[MIXER_PATH_MAX_LENGTH];
adsp_event_callback_t cb;
void *cookie;
int event_type;
};
struct adsp_hdlr_inst {
struct listnode event_list;
bool binit;
struct mixer *mixer;
pthread_mutex_t event_list_lock;
struct listnode list;
pthread_cond_t event_wait_cond;
pthread_t event_wait_thread;
struct listnode event_wait_cmd_list;
pthread_mutex_t event_wait_lock;
bool event_wait_thread_active;
pthread_cond_t event_callback_cond;
pthread_t event_callback_thread;
struct listnode event_callback_cmd_list;
pthread_mutex_t event_callback_lock;
bool event_callback_thread_active;
};
enum {
EVENT_CMD_EXIT, /* event thread exit command loop*/
EVENT_CMD_WAIT, /* event thread wait on mixer control */
EVENT_CMD_GET /* event thread get param data from mixer */
};
struct event_cmd {
struct listnode list;
int opcode;
char cb_mixer_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
};
static struct adsp_hdlr_inst *adsp_hdlr_inst = NULL;
static void *event_wait_thread_loop(void *context);
static void *event_callback_thread_loop(void *context);
static int send_cmd_event_wait_thread(struct adsp_hdlr_inst *adsp_hdlr_inst, int opcode)
{
struct event_cmd *cmd = calloc(1, sizeof(*cmd));
if (!cmd) {
ALOGE("Failed to allocate mem for command 0x%x", opcode);
return -ENOMEM;
}
ALOGVV("%s %d", __func__, opcode);
cmd->opcode = opcode;
pthread_mutex_lock(&adsp_hdlr_inst->event_wait_lock);
list_add_tail(&adsp_hdlr_inst->event_wait_cmd_list, &cmd->list);
pthread_cond_signal(&adsp_hdlr_inst->event_wait_cond);
pthread_mutex_unlock(&adsp_hdlr_inst->event_wait_lock);
return 0;
}
static int send_cmd_event_callback_thread(struct adsp_hdlr_inst *adsp_hdlr_inst,
int opcode, char *mixer_ctl_name)
{
struct event_cmd *cmd = calloc(1, sizeof(*cmd));
if (!cmd) {
ALOGE("Failed to allocate mem for command 0x%x", opcode);
return -ENOMEM;
}
ALOGVV("%s opcode %d, name = %s", __func__, opcode, mixer_ctl_name);
cmd->opcode = opcode;
if (mixer_ctl_name)
strlcpy(cmd->cb_mixer_ctl_name, mixer_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
pthread_mutex_lock(&adsp_hdlr_inst->event_callback_lock);
list_add_tail(&adsp_hdlr_inst->event_callback_cmd_list, &cmd->list);
pthread_cond_signal(&adsp_hdlr_inst->event_callback_cond);
pthread_mutex_unlock(&adsp_hdlr_inst->event_callback_lock);
return 0;
}
static void create_event_wait_thread(struct adsp_hdlr_inst *adsp_hdlr_inst)
{
pthread_cond_init(&adsp_hdlr_inst->event_wait_cond,
(const pthread_condattr_t *) NULL);
list_init(&adsp_hdlr_inst->event_wait_cmd_list);
pthread_create(&adsp_hdlr_inst->event_wait_thread, (const pthread_attr_t *) NULL,
event_wait_thread_loop, adsp_hdlr_inst);
adsp_hdlr_inst->event_wait_thread_active = true;
}
static void create_event_callback_thread(struct adsp_hdlr_inst *adsp_hdlr_inst)
{
pthread_cond_init(&adsp_hdlr_inst->event_callback_cond,
(const pthread_condattr_t *) NULL);
list_init(&adsp_hdlr_inst->event_callback_cmd_list);
pthread_create(&adsp_hdlr_inst->event_callback_thread, (const pthread_attr_t *) NULL,
event_callback_thread_loop, adsp_hdlr_inst);
adsp_hdlr_inst->event_callback_thread_active = true;
}
static void destroy_event_wait_thread(struct adsp_hdlr_inst *adsp_hdlr_inst)
{
send_cmd_event_wait_thread(adsp_hdlr_inst, EVENT_CMD_EXIT);
pthread_join(adsp_hdlr_inst->event_wait_thread, (void **) NULL);
pthread_mutex_lock(&adsp_hdlr_inst->event_wait_lock);
pthread_cond_destroy(&adsp_hdlr_inst->event_wait_cond);
adsp_hdlr_inst->event_wait_thread_active = false;
pthread_mutex_unlock(&adsp_hdlr_inst->event_wait_lock);
}
static void destroy_event_callback_thread(struct adsp_hdlr_inst *adsp_hdlr_inst)
{
send_cmd_event_callback_thread(adsp_hdlr_inst, EVENT_CMD_EXIT, NULL);
pthread_join(adsp_hdlr_inst->event_callback_thread, (void **) NULL);
pthread_mutex_lock(&adsp_hdlr_inst->event_callback_lock);
pthread_cond_destroy(&adsp_hdlr_inst->event_callback_cond);
adsp_hdlr_inst->event_callback_thread_active = false;
pthread_mutex_unlock(&adsp_hdlr_inst->event_callback_lock);
}
static void destroy_event_threads(struct adsp_hdlr_inst *adsp_hdlr_inst)
{
if (adsp_hdlr_inst->event_wait_thread_active)
destroy_event_wait_thread(adsp_hdlr_inst);
if (adsp_hdlr_inst->event_callback_thread_active)
destroy_event_callback_thread(adsp_hdlr_inst);
}
static void *event_wait_thread_loop(void *context)
{
int ret = 0;
int opcode = 0;
bool wait = false;
struct adsp_hdlr_inst *adsp_hdlr_inst =
(struct adsp_hdlr_inst *) context;
struct event_cmd *cmd;
struct listnode *node, *tempnode;
struct snd_ctl_event mixer_event = {0};
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
set_sched_policy(0, SP_BACKGROUND);
prctl(PR_SET_NAME, (unsigned long)"Event Wait", 0, 0, 0);
ret = mixer_subscribe_events(adsp_hdlr_inst->mixer, 1);
if (ret < 0) {
ALOGE("%s: Could not subscribe for mixer events, ret %d",
__func__, ret);
goto done;
}
pthread_mutex_lock(&adsp_hdlr_inst->event_wait_lock);
while (1) {
if (list_empty(&adsp_hdlr_inst->event_wait_cmd_list) && !wait) {
ALOGVV("%s SLEEPING", __func__);
pthread_cond_wait(&adsp_hdlr_inst->event_wait_cond, &adsp_hdlr_inst->event_wait_lock);
ALOGVV("%s RUNNING", __func__);
}
/* execute command if available */
if (!list_empty(&adsp_hdlr_inst->event_wait_cmd_list)) {
node = list_head(&adsp_hdlr_inst->event_wait_cmd_list);
list_remove(node);
pthread_mutex_unlock(&adsp_hdlr_inst->event_wait_lock);
cmd = node_to_item(node, struct event_cmd, list);
opcode = cmd->opcode;
/* wait if no command avialable */
} else if (wait)
opcode = EVENT_CMD_WAIT;
/* check que again and sleep if needed */
else
continue;
ALOGVV("%s command received: %d", __func__, opcode);
switch(opcode) {
case EVENT_CMD_EXIT:
free(cmd);
goto thread_exit;
case EVENT_CMD_WAIT:
ret = mixer_wait_event(adsp_hdlr_inst->mixer, WAIT_EVENT_POLL_TIMEOUT);
ALOGVV("%s: mixer_wait_event unblocked!, ret = %d", __func__, ret);
if (ret < 0) {
ALOGE("%s: mixer_wait_event err!, ret = %d", __func__, ret);
} else if (ret > 0) {
ret = mixer_read(adsp_hdlr_inst->mixer, &mixer_event);
if (ret >= 0)
send_cmd_event_callback_thread(adsp_hdlr_inst, EVENT_CMD_GET, mixer_event.data.elem.id.name);
else
ALOGE("%s: mixer_read failed, ret = %d", __func__, ret);
}
/* Once wait command has been sent continue to wait for
events unless something else is in the command que */
wait = true;
break;
default:
ALOGE("%s unknown command received: %d", __func__, opcode);
break;
}
if (cmd != NULL) {
free(cmd);
cmd = NULL;
}
}
thread_exit:
ret = mixer_subscribe_events(adsp_hdlr_inst->mixer, 0);
if (ret < 0) {
ALOGE("%s: Could not un-subscribe for mixer events, ret %d",
__func__, ret);
goto done;
}
pthread_mutex_lock(&adsp_hdlr_inst->event_wait_lock);
list_for_each_safe(node, tempnode, &adsp_hdlr_inst->event_wait_cmd_list) {
list_remove(node);
free(node);
}
pthread_mutex_unlock(&adsp_hdlr_inst->event_wait_lock);
done:
return NULL;
}
static void *event_callback_thread_loop(void *context)
{
int ret = 0;
size_t count = 0;
struct adsp_hdlr_inst *adsp_hdlr_inst =
(struct adsp_hdlr_inst *)context;
struct mixer_ctl *ctl = NULL;
uint8_t param[MAX_EVENT_PAYLOAD] = {0};
struct event_cmd *cmd;
struct listnode *node, *tempnode;
struct adsp_hdlr_event_info *event_info;
bool param_avail = false;
struct msm_adsp_event_data *received_evt;
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
set_sched_policy(0, SP_BACKGROUND);
prctl(PR_SET_NAME, (unsigned long)"Event Callback", 0, 0, 0);
pthread_mutex_lock(&adsp_hdlr_inst->event_callback_lock);
while (1) {
if (list_empty(&adsp_hdlr_inst->event_callback_cmd_list)) {
ALOGVV("%s SLEEPING", __func__);
pthread_cond_wait(&adsp_hdlr_inst->event_callback_cond,
&adsp_hdlr_inst->event_callback_lock);
ALOGVV("%s RUNNING", __func__);
continue;
}
node = list_head(&adsp_hdlr_inst->event_callback_cmd_list);
list_remove(node);
pthread_mutex_unlock(&adsp_hdlr_inst->event_callback_lock);
cmd = node_to_item(node, struct event_cmd, list);
ALOGVV("%s command received: %d", __func__, cmd->opcode);
switch(cmd->opcode) {
case EVENT_CMD_EXIT:
free(cmd);
goto thread_exit;
case EVENT_CMD_GET:
param_avail = false;
pthread_mutex_lock(&adsp_hdlr_inst->event_list_lock);
/* Find the mixer control for which event is triggered */
list_for_each(node, &adsp_hdlr_inst->event_list) {
event_info = node_to_item(node, struct adsp_hdlr_event_info, list);
ALOGVV("%s: cmd mixer name: %s, event list mixer name: %s", __func__,
cmd->cb_mixer_ctl_name, event_info->cb_mixer_ctl_name);
if (!strcmp(cmd->cb_mixer_ctl_name, event_info->cb_mixer_ctl_name)) {
if (!param_avail) {
ctl = mixer_get_ctl_by_name(adsp_hdlr_inst->mixer, cmd->cb_mixer_ctl_name);
if (!ctl) {
ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
cmd->cb_mixer_ctl_name);
break;
}
mixer_ctl_update(ctl);
count = mixer_ctl_get_num_values(ctl);
if ((count > MAX_EVENT_PAYLOAD) || (count <= 0)) {
ALOGE("%s: count is %d greater than allowed for %s mixer cmd",
__func__, count, cmd->cb_mixer_ctl_name);
break;
}
ret = mixer_ctl_get_array(ctl, param, count);
if (ret < 0) {
ALOGE("%s: mixer_ctl_get_array failed! mixer - %s, ret = %d",
__func__, cmd->cb_mixer_ctl_name, ret);
break;
}
param_avail = true;
received_evt = (struct msm_adsp_event_data *)param;
ALOGD("%s: event type = %d", __func__, received_evt->event_type);
}
/* Call appropriate event type client callback */
if (param_avail && event_info->event_type == received_evt->event_type) {
struct adsp_hdlr_stream_data *stream_data = event_info->stream_handle;
if (event_info->cb != NULL) {
ALOGVV("%s: calling event callback function", __func__);
event_info->cb(event_info->stream_handle,
received_evt->payload,
event_info->cookie);
} else if (stream_data->client_callback != NULL) {
ALOGVV("%s: sending client callback event %d", __func__,
AUDIO_EXTN_STREAM_CBK_EVENT_ADSP);
stream_data->client_callback((stream_callback_event_t)
AUDIO_EXTN_STREAM_CBK_EVENT_ADSP,
received_evt,
stream_data->client_cookie);
}
break;
}
}
}
pthread_mutex_unlock(&adsp_hdlr_inst->event_list_lock);
break;
default:
ALOGE("%s unknown command received: %d", __func__, cmd->opcode);
break;
}
free(cmd);
}
thread_exit:
pthread_mutex_lock(&adsp_hdlr_inst->event_callback_lock);
list_for_each_safe(node, tempnode, &adsp_hdlr_inst->event_callback_cmd_list) {
list_remove(node);
free(node);
}
pthread_mutex_unlock(&adsp_hdlr_inst->event_callback_lock);
done:
return NULL;
}
int audio_extn_adsp_hdlr_stream_deregister_event(void *handle, void *data)
{
struct listnode *node, *tempnode;
struct adsp_hdlr_stream_data *stream_data = (struct adsp_hdlr_stream_data *)handle;
struct adsp_hdlr_event_info *event_info;
struct audio_adsp_event *param = (struct audio_adsp_event *)data;
if (!handle) {
ALOGE("%s: Invalid handle", __func__);
return -EINVAL;
}
pthread_mutex_lock(&adsp_hdlr_inst->event_list_lock);
if (list_empty(&adsp_hdlr_inst->event_list)) {
ALOGD("%s: event list is empty", __func__);
pthread_mutex_unlock(&adsp_hdlr_inst->event_list_lock);
return 0;
}
list_for_each_safe(node, tempnode, &adsp_hdlr_inst->event_list) {
event_info = node_to_item(node, struct adsp_hdlr_event_info, list);
if (param && event_info->stream_handle == stream_data) {
/* if the type of event is avaliable to dereg then dereg only that event */
if (event_info->event_type == param->event_type) {
ALOGD("%s: Deregister event type = %d", __func__, event_info->event_type);
list_remove(node);
free(event_info);
}
} else if (event_info->stream_handle == stream_data) {
/* Dereg all the events related to that stream */
ALOGD("%s: Deregister all stream events", __func__);
list_remove(node);
free(event_info);
}
}
pthread_mutex_unlock(&adsp_hdlr_inst->event_list_lock);
if (list_empty(&adsp_hdlr_inst->event_list)) {
ALOGD("%s: Closing event threads", __func__);
destroy_event_threads(adsp_hdlr_inst);
pthread_mutex_destroy(&adsp_hdlr_inst->event_wait_lock);
pthread_mutex_destroy(&adsp_hdlr_inst->event_callback_lock);
pthread_mutex_destroy(&adsp_hdlr_inst->event_list_lock);
}
return 0;
}
int audio_extn_adsp_hdlr_stream_register_event(void *handle, void *data,
adsp_event_callback_t cb,
void *cookie, bool is_adm_event)
{
int ret = 0;
char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
char cb_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
struct mixer_ctl *ctl = NULL;
uint8_t payload[AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN] = {0};
struct adsp_hdlr_stream_data *stream_data = (struct adsp_hdlr_stream_data *)handle;
struct adsp_hdlr_stream_cfg *config = &stream_data->config;
struct adsp_hdlr_event_info *event_info;
struct audio_adsp_event *param = (struct audio_adsp_event *)data;
if (!param || !handle) {
ret = -EINVAL;
ALOGE("%s: Invalid input arguments", __func__);
goto done;
}
/* check if param size exceeds max size supported by mixer */
if (param->payload_length > AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN) {
ALOGE("%s: Invalid payload_length %d",__func__, param->payload_length);
return -EINVAL;
}
if (is_adm_event)
ret = snprintf(cb_mixer_ctl_name, sizeof(cb_mixer_ctl_name),
"ADSP COPP Callback Event");
else
ret = snprintf(cb_mixer_ctl_name, sizeof(cb_mixer_ctl_name),
"ADSP Stream Callback Event %d", config->pcm_device_id);
if (ret < 0) {
ALOGE("%s: snprintf failed",__func__);
ret = -EINVAL;
goto done;
}
ctl = mixer_get_ctl_by_name(adsp_hdlr_inst->mixer, cb_mixer_ctl_name);
if (!ctl) {
ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
cb_mixer_ctl_name);
ret = -EINVAL;
goto done;
}
if (is_adm_event)
ret = snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
"COPP Event Cmd");
else
ret = snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
"ADSP Stream Cmd %d", config->pcm_device_id);
if (ret < 0) {
ALOGE("%s: snprintf failed",__func__);
ret = -EINVAL;
goto done;
}
ctl = mixer_get_ctl_by_name(adsp_hdlr_inst->mixer, mixer_ctl_name);
if (!ctl) {
ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
mixer_ctl_name);
ret = -EINVAL;
goto done;
}
ALOGD("%s: event = %d, payload_length %d", __func__, param->event_type, param->payload_length);
/* copy event_type, payload size and payload */
memcpy(payload, &param->event_type,
sizeof(param->event_type));
memcpy(payload + sizeof(param->event_type), &param->payload_length,
sizeof(param->payload_length));
memcpy(payload + sizeof(param->event_type) + sizeof(param->payload_length),
param->payload, param->payload_length);
ret = mixer_ctl_set_array(ctl, payload, (sizeof(param->event_type) +
sizeof(param->payload_length) + param->payload_length));
if (ret < 0) {
ALOGE("%s: Could not set ctl for mixer cmd - %s, ret %d", __func__,
mixer_ctl_name, ret);
goto done;
}
if (list_empty(&adsp_hdlr_inst->event_list)) {
pthread_mutex_init(&adsp_hdlr_inst->event_wait_lock,
(const pthread_mutexattr_t *) NULL);
pthread_mutex_init(&adsp_hdlr_inst->event_callback_lock,
(const pthread_mutexattr_t *) NULL);
pthread_mutex_init(&adsp_hdlr_inst->event_list_lock,
(const pthread_mutexattr_t *) NULL);
/* create event threads during first event registration */
pthread_mutex_lock(&adsp_hdlr_inst->event_wait_lock);
if (!adsp_hdlr_inst->event_wait_thread_active)
create_event_wait_thread(adsp_hdlr_inst);
pthread_mutex_unlock(&adsp_hdlr_inst->event_wait_lock);
pthread_mutex_lock(&adsp_hdlr_inst->event_callback_lock);
if (!adsp_hdlr_inst->event_callback_thread_active)
create_event_callback_thread(adsp_hdlr_inst);
pthread_mutex_unlock(&adsp_hdlr_inst->event_callback_lock);
send_cmd_event_wait_thread(adsp_hdlr_inst, EVENT_CMD_WAIT);
}
event_info = (struct adsp_hdlr_event_info *) calloc(1,
sizeof(struct adsp_hdlr_event_info));
if (event_info == NULL) {
ret = -ENOMEM;
goto done;
}
event_info->event_type = param->event_type;
event_info->cb = cb;
event_info->cookie = cookie;
event_info->stream_handle = stream_data;
strlcpy(event_info->mixer_ctl_name, mixer_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
strlcpy(event_info->cb_mixer_ctl_name, cb_mixer_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
pthread_mutex_lock(&adsp_hdlr_inst->event_list_lock);
list_add_tail(&adsp_hdlr_inst->event_list, &event_info->list);
ALOGD("%s: event_info type %d added from the list", __func__, event_info->event_type);
pthread_mutex_unlock(&adsp_hdlr_inst->event_list_lock);
done:
return ret;
}
int audio_extn_adsp_hdlr_stream_set_param(void *handle,
adsp_hdlr_cmd_t cmd,
void *param)
{
int ret = 0;
if (handle == NULL) {
ALOGE("%s: Invalid handle",__func__);
return -EINVAL;
}
switch (cmd) {
case ADSP_HDLR_STREAM_CMD_REGISTER_EVENT :
ret = audio_extn_adsp_hdlr_stream_register_event(handle, param, NULL, NULL, false);
if (ret)
ALOGE("%s:adsp_hdlr_stream_register_event failed error %d",
__func__, ret);
break;
case ADSP_HDLR_STREAM_CMD_DEREGISTER_EVENT:
ret = audio_extn_adsp_hdlr_stream_deregister_event(handle, param);
if (ret)
ALOGE("%s:adsp_hdlr_stream_deregister_event failed error %d",
__func__, ret);
break;
default:
ret = -EINVAL;
ALOGE("%s: Unsupported command %d",__func__, cmd);
}
return ret;
}
int audio_extn_adsp_hdlr_stream_set_callback(void *handle,
stream_callback_t callback,
void *cookie)
{
int ret = 0;
struct adsp_hdlr_stream_data *stream_data;
ALOGV("%s:: handle %p", __func__, handle);
if (!handle) {
ALOGE("%s:Invalid handle", __func__);
ret = -EINVAL;
} else {
stream_data = (struct adsp_hdlr_stream_data *)handle;
stream_data->client_callback = callback;
stream_data->client_cookie = cookie;
}
return ret;
}
int audio_extn_adsp_hdlr_stream_close(void *handle)
{
int ret = 0;
struct adsp_hdlr_stream_data *stream_data;
ALOGV("%s:: handle %p", __func__, handle);
if (!handle) {
ALOGE("%s:Invalid handle", __func__);
ret = -EINVAL;
} else {
stream_data = (struct adsp_hdlr_stream_data *)handle;
ret = audio_extn_adsp_hdlr_stream_deregister_event(stream_data, NULL);
if (ret)
ALOGE("%s:adsp_hdlr_stream_deregister_event failed error %d",
__func__, ret);
free(stream_data);
stream_data = NULL;
}
return ret;
}
int audio_extn_adsp_hdlr_stream_open(void **handle,
struct adsp_hdlr_stream_cfg *config)
{
int ret = 0;
struct adsp_hdlr_stream_data *stream_data;
if (!adsp_hdlr_inst) {
ALOGE("%s: Not Inited", __func__);
return -ENODEV;;
}
if ((!config) || (config->type != PCM_PLAYBACK)) {
ALOGE("%s: Invalid config param", __func__);
return -EINVAL;
}
ALOGV("%s::pcm_device_id %d, flags %x type %d ", __func__,
config->pcm_device_id, config->flags, config->type);
*handle = NULL;
stream_data = (struct adsp_hdlr_stream_data *) calloc(1,
sizeof(struct adsp_hdlr_stream_data));
if (stream_data == NULL) {
ret = -ENOMEM;
}
stream_data->config = *config;
*handle = (void **)stream_data;
return ret;
}
int audio_extn_adsp_hdlr_init(struct mixer *mixer)
{
ALOGV("%s", __func__);
if (!mixer) {
ALOGE("%s: invalid mixer", __func__);
return -EINVAL;
}
if (adsp_hdlr_inst) {
ALOGD("%s: Already initialized", __func__);
return 0;
}
adsp_hdlr_inst = (struct adsp_hdlr_inst *)calloc(1,
sizeof(struct adsp_hdlr_inst));
if (!adsp_hdlr_inst) {
ALOGE("%s: calloc failed for adsp_hdlr_inst", __func__);
return -EINVAL;
}
adsp_hdlr_inst->mixer = mixer;
list_init(&adsp_hdlr_inst->event_list);
return 0;
}
int audio_extn_adsp_hdlr_deinit(void)
{
if (adsp_hdlr_inst) {
free(adsp_hdlr_inst);
adsp_hdlr_inst = NULL;
} else {
ALOGD("%s: Already Deinitialized", __func__);
}
return 0;
}