/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2019. All rights reserved. * Description: adec event * Author: audio * Create: 2019-05-30 */ #include "adec_event.h" #include "soc_errno.h" #include "mpi_memory_ext.h" #include "mpi_adec_debug.h" #include "adec_common.h" #include "drv_ioctl_adec.h" #define ADEC_EVENT_SCH_TIME_MS 10LL #define ADEC_EVENT_FIFO_SIZE 0x1000 /* 4k */ typedef struct { ext_adec_event_type event; td_u8 *arg; td_u32 arg_size; } adec_event_prefix; static td_void adec_event_call_back(adec_event *event, adec_event_prefix *event_prefix) { td_s32 ret; td_handle user_handle; ext_mpi_adec_event_fn fun; adec_mutex_lock(&event->mutex); user_handle = event->user_handle; fun = event->fun; adec_mutex_unlock(&event->mutex); if (fun == TD_NULL) { return; } ret = fun(user_handle, event_prefix->event, event_prefix->arg, event_prefix->arg_size); if (ret != TD_SUCCESS) { soc_log_err("report event 0x%x failed\n", event_prefix->event); } } static inline td_void event_prefix_reset(adec_event_prefix *event_prefix) { event_prefix->event = EXT_ADEC_EVENT_TYPE_MAX; event_prefix->arg = TD_NULL; event_prefix->arg_size = 0; } static td_void adec_event_process(adec_event *event, td_u8 *arg) { td_u32 len; kfifo *fifo = &event->event_fifo.fifo; adec_event_prefix event_prefix; while (event->alive == TD_TRUE) { event_prefix_reset(&event_prefix); len = kfifo_peek(fifo, &event_prefix, sizeof(adec_event_prefix)); if (len != sizeof(adec_event_prefix)) { break; } if (kfifo_used(fifo) < sizeof(adec_event_prefix) + event_prefix.arg_size) { break; } kfifo_poke(fifo, sizeof(adec_event_prefix)); if (event_prefix.arg_size > 0) { event_prefix.arg = arg; len = kfifo_out(fifo, arg, event_prefix.arg_size); if (len != event_prefix.arg_size) { soc_log_err("call kfifo_out failed!\n"); break; } } adec_event_call_back(event, &event_prefix); } } static td_void *adec_event_thread(td_void *arg) { td_u8 *buf = TD_NULL; adec_event *event = (adec_event *)arg; if (event == TD_NULL) { return TD_NULL; } buf = (td_u8 *)malloc(ADEC_EVENT_FIFO_SIZE); if (buf == TD_NULL) { soc_log_err("call malloc( failed!\n"); return TD_NULL; } while (event->alive == TD_TRUE) { adec_event_process(event, buf); adec_sleep(ADEC_EVENT_SCH_TIME_MS); } free(buf); return TD_NULL; } static td_void adec_event_fifo_deinit(adec_event_fifo *event_fifo) { if (event_fifo->buffer == TD_NULL) { return; } free(event_fifo->buffer); event_fifo->buffer = TD_NULL; } static td_s32 adec_event_fifo_init(adec_event_fifo *event_fifo) { td_s32 ret; event_fifo->buffer = (td_u8 *)malloc(ADEC_EVENT_FIFO_SIZE); if (event_fifo->buffer == TD_NULL) { soc_log_err("call malloc( failed!\n"); return SOC_ERR_ADEC_ALLOC_MEM_FAILED; } event_fifo->write = 0; event_fifo->read = 0; ret = kfifo_init( &event_fifo->fifo, &event_fifo->write, &event_fifo->read, event_fifo->buffer, ADEC_EVENT_FIFO_SIZE); if (ret != TD_SUCCESS) { soc_log_err("call kfifo_init failed!\n"); adec_event_fifo_deinit(event_fifo); return ret; } return TD_SUCCESS; } td_s32 adec_event_init(adec_event *event) { td_s32 ret; check_adec_null_ptr(event); ret = adec_event_fifo_init(&event->event_fifo); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_event_fifo_init, ret); return ret; } adec_mutex_init(&event->mutex); event->alive = TD_TRUE; ret = pthread_create(&event->thread, TD_NULL, adec_event_thread, event); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(pthread_create, ret); goto out; } return TD_SUCCESS; out: adec_mutex_deinit(&event->mutex); adec_event_fifo_deinit(&event->event_fifo); return ret; } td_s32 adec_event_deinit(adec_event *event) { td_s32 ret; check_adec_null_ptr(event); event->alive = TD_FALSE; ret = pthread_join(event->thread, TD_NULL); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(pthread_join, ret); return ret; } adec_mutex_deinit(&event->mutex); adec_event_fifo_deinit(&event->event_fifo); return TD_SUCCESS; } td_s32 adec_event_register_call_back(adec_event *event, td_handle user_handle, ext_mpi_adec_event_fn fun) { check_adec_null_ptr(event); if (event->alive == TD_FALSE) { soc_log_err("event->mutex is not init!\n"); return SOC_ERR_ADEC_INSUFFICIENT_RESOURCES; } adec_mutex_lock(&event->mutex); event->user_handle = user_handle; event->fun = fun; adec_mutex_unlock(&event->mutex); return TD_SUCCESS; } td_void adec_event_report(adec_event *event, ext_adec_event_type event_type, td_u8 *param, td_u32 param_size) { td_u32 len; kfifo *fifo = TD_NULL; td_bool set_event_prefix_done = TD_FALSE; td_u32 size = param_size; adec_event_prefix event_prefix = { .event = event_type, .arg = TD_NULL, .arg_size = 0, }; if (event == TD_NULL) { return; } fifo = &event->event_fifo.fifo; if (param == TD_NULL) { size = 0; } event_prefix.arg = param; /* kfifo is not written immediately, stack variables cannot be used as param */ event_prefix.arg_size = size; while (event->alive == TD_TRUE) { if (set_event_prefix_done == TD_FALSE) { len = kfifo_in(fifo, &event_prefix, sizeof(adec_event_prefix)); if (len != sizeof(adec_event_prefix)) { adec_sleep(ADEC_EVENT_SCH_TIME_MS); continue; } set_event_prefix_done = TD_TRUE; } if (event_prefix.arg_size == 0) { break; } len = kfifo_in(fifo, event_prefix.arg, event_prefix.arg_size); if (len == event_prefix.arg_size) { break; } adec_sleep(ADEC_EVENT_SCH_TIME_MS); } }