| /* |
| * Copyright 2019 The ChromiumOS Authors |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "audio_codec.h" |
| #include "console.h" |
| #include "host_command.h" |
| #include "util.h" |
| |
| #define CPRINTS(format, args...) cprints(CC_AUDIO_CODEC, format, ##args) |
| |
| static const uint32_t capabilities = 0 |
| #ifdef CONFIG_AUDIO_CODEC_CAP_WOV_AUDIO_SHM |
| | BIT(EC_CODEC_CAP_WOV_AUDIO_SHM) |
| #endif |
| #ifdef CONFIG_AUDIO_CODEC_CAP_WOV_LANG_SHM |
| | BIT(EC_CODEC_CAP_WOV_LANG_SHM) |
| #endif |
| ; |
| |
| static struct { |
| uint8_t cap; |
| uint8_t type; |
| uintptr_t *addr; |
| uint32_t len; |
| } shms[EC_CODEC_SHM_ID_LAST]; |
| |
| static enum ec_status get_capabilities(struct host_cmd_handler_args *args) |
| { |
| struct ec_response_ec_codec_get_capabilities *r = args->response; |
| |
| r->capabilities = capabilities; |
| |
| args->response_size = sizeof(*r); |
| return EC_RES_SUCCESS; |
| } |
| |
| static enum ec_status get_shm_addr(struct host_cmd_handler_args *args) |
| { |
| const struct ec_param_ec_codec *p = args->params; |
| struct ec_response_ec_codec_get_shm_addr *r = args->response; |
| const uint8_t shm_id = p->get_shm_addr_param.shm_id; |
| |
| if (shm_id >= EC_CODEC_SHM_ID_LAST) |
| return EC_RES_INVALID_PARAM; |
| if (!shms[shm_id].addr || !audio_codec_capable(shms[shm_id].cap)) |
| return EC_RES_INVALID_PARAM; |
| if (!*shms[shm_id].addr && |
| shms[shm_id].type == EC_CODEC_SHM_TYPE_EC_RAM) |
| return EC_RES_ERROR; |
| |
| r->len = shms[shm_id].len; |
| r->type = shms[shm_id].type; |
| r->phys_addr = *shms[shm_id].addr; |
| |
| args->response_size = sizeof(*r); |
| return EC_RES_SUCCESS; |
| } |
| |
| static enum ec_status set_shm_addr(struct host_cmd_handler_args *args) |
| { |
| const struct ec_param_ec_codec *p = args->params; |
| const uint8_t shm_id = p->set_shm_addr_param.shm_id; |
| uintptr_t ap_addr, ec_addr; |
| |
| if (shm_id >= EC_CODEC_SHM_ID_LAST) |
| return EC_RES_INVALID_PARAM; |
| if (!shms[shm_id].addr || !audio_codec_capable(shms[shm_id].cap)) |
| return EC_RES_INVALID_PARAM; |
| if (p->set_shm_addr_param.len < shms[shm_id].len) |
| return EC_RES_INVALID_PARAM; |
| if (*shms[shm_id].addr) |
| return EC_RES_BUSY; |
| |
| ap_addr = (uintptr_t)p->set_shm_addr_param.phys_addr; |
| if (audio_codec_memmap_ap_to_ec(ap_addr, &ec_addr) != EC_SUCCESS) |
| return EC_RES_ERROR; |
| *shms[shm_id].addr = ec_addr; |
| |
| args->response_size = 0; |
| return EC_RES_SUCCESS; |
| } |
| |
| static enum ec_status (*sub_cmds[])(struct host_cmd_handler_args *) = { |
| [EC_CODEC_GET_CAPABILITIES] = get_capabilities, |
| [EC_CODEC_GET_SHM_ADDR] = get_shm_addr, |
| [EC_CODEC_SET_SHM_ADDR] = set_shm_addr, |
| }; |
| |
| #ifdef DEBUG_AUDIO_CODEC |
| static char *strcmd[] = { |
| [EC_CODEC_GET_CAPABILITIES] = "EC_CODEC_GET_CAPABILITIES", |
| [EC_CODEC_GET_SHM_ADDR] = "EC_CODEC_GET_SHM_ADDR", |
| [EC_CODEC_SET_SHM_ADDR] = "EC_CODEC_SET_SHM_ADDR", |
| }; |
| BUILD_ASSERT(ARRAY_SIZE(sub_cmds) == ARRAY_SIZE(strcmd)); |
| #endif |
| |
| static enum ec_status host_command(struct host_cmd_handler_args *args) |
| { |
| const struct ec_param_ec_codec *p = args->params; |
| |
| #ifdef DEBUG_AUDIO_CODEC |
| CPRINTS("subcommand: %s", strcmd[p->cmd]); |
| #endif |
| |
| if (p->cmd < EC_CODEC_SUBCMD_COUNT) |
| return sub_cmds[p->cmd](args); |
| |
| return EC_RES_INVALID_PARAM; |
| } |
| DECLARE_HOST_COMMAND(EC_CMD_EC_CODEC, host_command, EC_VER_MASK(0)); |
| |
| /* |
| * Exported interfaces. |
| */ |
| int audio_codec_capable(uint8_t cap) |
| { |
| return capabilities & BIT(cap); |
| } |
| |
| int audio_codec_register_shm(uint8_t shm_id, uint8_t cap, uintptr_t *addr, |
| uint32_t len, uint8_t type) |
| { |
| if (shm_id >= EC_CODEC_SHM_ID_LAST) |
| return EC_ERROR_INVAL; |
| if (cap >= EC_CODEC_CAP_LAST) |
| return EC_ERROR_INVAL; |
| if (shms[shm_id].addr || shms[shm_id].len) |
| return EC_ERROR_BUSY; |
| |
| shms[shm_id].cap = cap; |
| shms[shm_id].addr = addr; |
| shms[shm_id].len = len; |
| shms[shm_id].type = type; |
| |
| return EC_SUCCESS; |
| } |
| |
| __attribute__((weak)) int audio_codec_memmap_ap_to_ec(uintptr_t ap_addr, |
| uintptr_t *ec_addr) |
| { |
| return EC_ERROR_UNIMPLEMENTED; |
| } |
| |
| int16_t audio_codec_s16_scale_and_clip(int16_t orig, uint8_t scalar) |
| { |
| int32_t val; |
| |
| val = (int32_t)orig * (int32_t)scalar; |
| val = MIN(val, (int32_t)INT16_MAX); |
| val = MAX(val, (int32_t)INT16_MIN); |
| return val; |
| } |