/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2020. All rights reserved. * Description : hdmirx mpi-part * Author : Hisilicon * Create : 2019-11-20 */ #include "mpi_hdmirx.h" #include #include #include #include #include #include "mpi_hdmirx_ext.h" #include "mpi_memory_ext.h" #include "mpi_stat_ext.h" #include "securec.h" #include "mpi_system_ext.h" #include "soc_errno.h" #ifndef CONFIG_HDMIRX_EXCLUDE_HDCP #include "mpi_keyslot_ext.h" #include "mpi_klad_ext.h" #endif #define CEC_OPERAND_ARG_NUM 2 #define HDMIRX_ALGORITHM_AES_CBC 0x12 static ext_mpi_hdmirx_ctx g_hdmirx_mpi_ctx; #define ext_hdmirx_lock() (td_void)pthread_mutex_lock(&g_hdmirx_mutex) #define ext_hdmirx_unlock() (td_void)pthread_mutex_unlock(&g_hdmirx_mutex) #define hdmirx_mpi_get_ctx() (&g_hdmirx_mpi_ctx) #define hdmirx_mpi_check_inited(ret) \ do { \ if (g_hdmirx_mpi_ctx.inited != TD_TRUE) { \ ext_err_hdmirx("hdmirx drv don't init\n"); \ (ret) = SOC_ERR_HDMIRX_NOT_INIT; \ } \ } while (0) #define hdmirx_mpi_check_connected(port, ret) \ do { \ if (g_hdmirx_mpi_ctx.connected[(port)] != TD_TRUE) { \ ext_err_hdmirx("hdmirx drv don't connect port:%d\n", (port)); \ (ret) = SOC_ERR_HDMIRX_NOT_CONNECT; \ } \ } while (0) #define check_mpi_hdmirx_null_ptr(ptr, ret) \ do { \ if ((ptr) == NULL) { \ ext_err_hdmirx("NULL pointer\n"); \ (ret) = SOC_ERR_HDMIRX_NULL_PTR; \ } \ } while (0) static pthread_mutex_t g_hdmirx_mutex = PTHREAD_MUTEX_INITIALIZER; static const td_char *g_edid_mode_string[] = { "auto", "1.4", "2.0", "2.1", "max" }; td_s32 ext_mpi_hdmirx_init(td_void) { td_s32 fd = -1; errno_t err_ret; td_s32 ret; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); if (ctx->inited == TD_TRUE) { return TD_SUCCESS; } err_ret = ext_mpi_sys_init(); if (err_ret != TD_SUCCESS) { ext_err_hdmirx("sys init fail! err_ret:0x%x.\n", err_ret); return err_ret; } err_ret = memset_s(ctx, sizeof(ext_mpi_hdmirx_ctx), 0, sizeof(ext_mpi_hdmirx_ctx)); if (err_ret != EOK) { close(fd); ext_err_hdmirx("secure func call error\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } ret = ext_mpi_sys_get_version(&ctx->sys_version); if (ret != TD_SUCCESS) { soc_log_err("get chip version failed! ret: 0x%x\n", ret); return SOC_ERR_HDMIRX_GET_CHIP_VER_ERR; } ext_mpi_sys_deinit(); fd = open("/dev/soc_hdmirx", O_RDWR | O_NONBLOCK); if (fd < 0) { ext_err_hdmirx("can't open hdmirx drv\n"); return SOC_ERR_HDMIRX_DEV_NOT_OPEN; } ext_info_hdmirx("INFO! hdmirx drv init ok\n"); ctx->fd = fd; ctx->inited = TD_TRUE; ctx->en_sig_status = EXT_DRV_SIG_MAX; return TD_SUCCESS; } td_s32 ext_mpi_hdmirx_de_init(td_void) { td_s32 ret; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); if (ctx->inited == TD_FALSE) { return TD_SUCCESS; } ctx->inited = TD_FALSE; ret = close(ctx->fd); ctx->fd = TD_INVALID_HANDLE; ext_info_hdmirx("INFO! hdmirx drv deinit ok\n"); return ret; } td_s32 ext_mpi_hdmirx_connect(ext_drv_hdmirx_port port_idx) { td_s32 ret = TD_SUCCESS; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { return ret; } if (port_idx >= EXT_DRV_HDMIRX_PORT_MAX) { ext_err_hdmirx("hdmirx port:%d error!\n", port_idx); return SOC_ERR_HDMIRX_INVALID_PORT; } (td_void)ext_mpi_stat_event(EXT_STAT_EVENT_CONNECT, 2); // 2: param value ext_hdmirx_lock(); if (ctx->connected[port_idx]) { ext_hdmirx_unlock(); return TD_SUCCESS; } ext_info_hdmirx("INFO! hdmirx drv connect port %d\n", port_idx); ret = ioctl(ctx->fd, IOC_HDMIRX_CONNECT, &port_idx); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx connect port:%d fail!\n", port_idx); ext_hdmirx_unlock(); return ret; } ctx->connected[port_idx] = TD_TRUE; ext_hdmirx_unlock(); return TD_SUCCESS; } td_s32 ext_mpi_hdmirx_dis_connect(ext_drv_hdmirx_port port_idx) { td_s32 ret = TD_SUCCESS; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { return ret; } if (port_idx >= EXT_DRV_HDMIRX_PORT_MAX) { ext_err_hdmirx("hdmirx port:%d error!\n", port_idx); return SOC_ERR_HDMIRX_INVALID_PORT; } ext_hdmirx_lock(); if (ctx->connected[port_idx] != TD_TRUE) { ext_hdmirx_unlock(); return TD_SUCCESS; } ext_info_hdmirx("INFO! hdmirx drv disconnect port:%d\n", port_idx); ret = ioctl(ctx->fd, IOC_HDMIRX_DISCONNECT, &port_idx); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx disconnect port:%d fail!\n", port_idx); ext_hdmirx_unlock(); return ret; } ctx->connected[port_idx] = TD_FALSE; ext_hdmirx_unlock(); return TD_SUCCESS; } td_s32 ext_mpi_hdmirx_get_timing_info(ext_drv_hdmirx_port port, ext_drv_hdmirx_timing_info *timing_info) { td_s32 ret = TD_SUCCESS; errno_t err_ret; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); ext_drv_hdmirx_timing timing; hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { return ret; } if (port >= EXT_DRV_HDMIRX_PORT_MAX) { ext_err_hdmirx("hdmirx port:%d error!\n", port); return SOC_ERR_HDMIRX_INVALID_PORT; } hdmirx_mpi_check_connected(port, ret); if (ret != TD_SUCCESS) { return ret; } check_mpi_hdmirx_null_ptr(timing_info, ret); if (ret != TD_SUCCESS) { return ret; } timing.port = port; ret = ioctl(ctx->fd, IOC_HDMIRX_G_TIMING_INFO, &timing); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx get_timing_info of port:%d fail!\n", port); return ret; } err_ret = memcpy_s(timing_info, sizeof(ext_drv_hdmirx_timing_info), &(timing.timing_info), sizeof(timing.timing_info)); if (err_ret != EOK) { ext_err_hdmirx("secure func call error\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } return ret; } td_s32 ext_mpi_hdmirx_get_audio_info(ext_drv_hdmirx_port port, ext_drv_ai_hdmirx_attr *audio_info) { td_s32 ret = TD_SUCCESS; errno_t err_ret; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); ext_drv_hdmirx_aud_info aud_info; hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { return ret; } if (port >= EXT_DRV_HDMIRX_PORT_MAX) { ext_err_hdmirx("hdmirx port:%d error!\n", port); return SOC_ERR_HDMIRX_INVALID_PORT; } hdmirx_mpi_check_connected(port, ret); if (ret != TD_SUCCESS) { return ret; } check_mpi_hdmirx_null_ptr(audio_info, ret); if (ret != TD_SUCCESS) { return ret; } aud_info.port = port; ret = ioctl(ctx->fd, IOC_HDMIRX_G_AUDIO_INFO, &aud_info); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx get_audio of port:%d fail!\n", port); return ret; } err_ret = memcpy_s(audio_info, sizeof(ext_drv_ai_hdmirx_attr), &(aud_info.attr), sizeof(aud_info.attr)); if (err_ret != EOK) { ext_err_hdmirx("secure func call error\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } return ret; } td_s32 ext_mpi_hdmirx_get_sig_status(ext_drv_hdmirx_port port, ext_drv_sig_status *signal_status) { td_s32 ret = TD_SUCCESS; ext_drv_sig_info sig_info; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); check_mpi_hdmirx_null_ptr(signal_status, ret); if (ret != TD_SUCCESS) { return ret; } hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { *signal_status = EXT_DRV_SIG_NO_SIGNAL; return ret; } if (port >= EXT_DRV_HDMIRX_PORT_MAX) { ext_err_hdmirx("hdmirx port:%d error!\n", port); *signal_status = EXT_DRV_SIG_NO_SIGNAL; return SOC_ERR_HDMIRX_INVALID_PORT; } hdmirx_mpi_check_connected(port, ret); if (ret != TD_SUCCESS) { *signal_status = EXT_DRV_SIG_NO_SIGNAL; return ret; } sig_info.port = port; ret = ioctl(ctx->fd, IOC_HDMIRX_G_STATUS, &sig_info); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx get_sig_status of port:%d fail!\n", port); return ret; } *signal_status = sig_info.status; /* if mpi status change from not support to support, check whether send mpi event */ ctx->en_sig_status = *signal_status; return ret; } td_s32 ext_mpi_hdmirx_get_audio_status(ext_drv_hdmirx_port port, ext_drv_sig_status *status) { td_s32 ret = TD_SUCCESS; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); ext_drv_sig_info sig_info; check_mpi_hdmirx_null_ptr(status, ret); if (ret != TD_SUCCESS) { return ret; } hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { *status = EXT_DRV_SIG_NO_SIGNAL; return ret; } if (port >= EXT_DRV_HDMIRX_PORT_MAX) { ext_err_hdmirx("hdmirx port:%d error!\n", port); *status = EXT_DRV_SIG_NO_SIGNAL; return SOC_ERR_HDMIRX_INVALID_PORT; } hdmirx_mpi_check_connected(port, ret); if (ret != TD_SUCCESS) { *status = EXT_DRV_SIG_NO_SIGNAL; return ret; } sig_info.port = port; ret = ioctl(ctx->fd, IOC_HDMIRX_G_AUDIO_STATUS, &sig_info); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx get_audio_status of port:%d fail!\n", port); return ret; } *status = sig_info.status; return ret; } static td_s32 ext_mpi_hdmirx_overwrite_pa(td_u8 *edid, td_u32 cec_addr, td_u32 edid_len) { td_s32 ret = TD_FAILURE; td_u32 i; td_u32 offset = 0; td_u8 old_pa = 0; td_u32 old_sum = 0; td_u32 check_sum; td_u8 new_pa; for (i = 128; i < edid_len - 3; i++) { /* 128:edid cea block offset 3: last reserve */ if ((edid[i] == 0x3) && (edid[i + 1] == 0xc) && (edid[i + 2] == 0x0)) { /* 0x3, 0xc, 0x0: ieee code */ offset = i + 3; old_pa = edid[offset]; old_sum = edid[edid_len - 1]; ret = TD_SUCCESS; break; } } new_pa = cec_addr & 0xff; if (ret != TD_SUCCESS) { ext_err_hdmirx("no find pa offset\n"); return SOC_ERR_HDMIRX_EDID_NO_PA; } old_sum = (old_sum + old_pa) % 256; /* 256: edid length */ if (old_sum >= new_pa) { check_sum = old_sum - new_pa; } else { check_sum = old_sum + (0x100 - new_pa); } edid[offset] = new_pa; edid[edid_len - 1] = (td_u8)check_sum; return TD_SUCCESS; } static errno_t ext_mpi_hdmirx_copy_edid(ext_drv_hdmirx_edid_init_info *edid_init_info, ext_drv_hdmirx_edid *edid, td_u32 edid_count) { td_u32 temp = 0; td_s32 ret = 0; errno_t err_ret = -1; if (edid_init_info == TD_NULL) { ext_err_hdmirx("edid_init_info is NULL\n"); return SOC_ERR_HDMIRX_NULL_PTR; } if (edid == TD_NULL) { ext_err_hdmirx("edid is NULL\n"); return SOC_ERR_HDMIRX_NULL_PTR; } for (temp = 0; temp < edid_count; temp++) { edid_init_info->init_edid.edid_group[temp].cec_addr = edid[temp].cec_addr; edid_init_info->init_edid.edid_group[temp].edid_length = edid[temp].edid_length; ret = ext_mpi_hdmirx_overwrite_pa(edid[temp].edid_data, edid[temp].cec_addr, HDMIRX_EDID_LENGTH); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx overwrite pa fail!\n"); return ret; } err_ret = memset_s(edid_init_info->init_edid.edid_group[temp].edid_data, HDMIRX_EDID_LENGTH * sizeof(td_u8), 0, HDMIRX_EDID_LENGTH * sizeof(td_u8)); if (err_ret != EOK) { ext_err_hdmirx("secure func call error\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } err_ret = memcpy_s(edid_init_info->init_edid.edid_group[temp].edid_data, HDMIRX_EDID_LENGTH, edid[temp].edid_data, sizeof(edid[temp].edid_data)); if (err_ret != EOK) { ext_err_hdmirx("secure func call error\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } } return err_ret; } td_s32 ext_mpi_hdmirx_init_edid(ext_drv_hdmirx_port port, ext_drv_hdmirx_edid *edid, td_u32 edid_count) { td_u32 temp = 0; td_s32 ret = TD_SUCCESS; errno_t err_ret; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); ext_drv_hdmirx_edid_init_info edid_init_info; if (edid_count > HDMIRX_EDID_NUM) { ext_err_hdmirx("EDID count:%u is error!\n", edid_count); return SOC_ERR_HDMIRX_EDID_COUNT_ERR; } if (port >= EXT_DRV_HDMIRX_PORT_MAX) { ext_err_hdmirx("hdmirx port:%d error!\n", port); return SOC_ERR_HDMIRX_INVALID_PORT; } check_mpi_hdmirx_null_ptr(edid, ret); if (ret != TD_SUCCESS) { return SOC_ERR_HDMIRX_NULL_PTR; } for (temp = 0; temp < edid_count; temp++) { if (edid[temp].edid_length != HDMIRX_EDID_LENGTH) { ext_err_hdmirx("EDID length error!\n"); return SOC_ERR_HDMIRX_EDID_LEN_ERR; } if (port >= EXT_DRV_HDMIRX_PORT_MAX) { ext_err_hdmirx("EDID port:%d error!\n", port); return SOC_ERR_HDMIRX_INVALID_PORT; } } err_ret = memset_s(&edid_init_info, sizeof(edid_init_info), 0, sizeof(ext_drv_hdmirx_edid_init_info)); if (err_ret != EOK) { ext_err_hdmirx("secure func call error\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } edid_init_info.port = port; edid_init_info.init_edid.count = edid_count; err_ret = ext_mpi_hdmirx_copy_edid(&edid_init_info, edid, edid_count); if (err_ret != EOK) { ext_err_hdmirx("ext_mpi_hdmirx_copy_edid call error\n"); return err_ret; } ret = ioctl(ctx->fd, IOC_HDMIRX_S_INIT_EDID, &edid_init_info); return ret; } td_s32 ext_mpi_hdmirx_set_edid_mode(ext_drv_hdmirx_port port, ext_drv_hdmirx_edid_mode edid_mode) { td_s32 ret = TD_SUCCESS; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); ext_drv_hdmirx_edid_mode_info mode_info; if (port >= EXT_DRV_HDMIRX_PORT_MAX) { ext_err_hdmirx("hdmirx port:%d error!\n", port); return SOC_ERR_HDMIRX_INVALID_PORT; } hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { return ret; } if (edid_mode >= EXT_DRV_HDMIRX_EDID_MODE_MAX) { ext_err_hdmirx("hdmirx edid mode %d! error\n", edid_mode); return SOC_ERR_HDMIRX_EDID_MODE_ERR; } ext_info_hdmirx("port%d set edid mode : %s\n", port, g_edid_mode_string[edid_mode]); mode_info.port = port; mode_info.mode = edid_mode; ret = ioctl(ctx->fd, IOC_HDMIRX_S_EDID_MODE, &mode_info); return ret; } td_s32 ext_mpi_hdmirx_get_capability(ext_drv_hdmirx_capability_info *capability) { td_s32 ret = TD_SUCCESS; errno_t err_ret; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); ext_drv_hdmirx_capability_info caps_info; hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { return ret; } check_mpi_hdmirx_null_ptr(capability, ret); if (ret != TD_SUCCESS) { return ret; } err_ret = memset_s(&caps_info, sizeof(ext_drv_hdmirx_capability_info), 0, sizeof(ext_drv_hdmirx_capability_info)); if (err_ret != EOK) { ext_err_hdmirx("secure func call error\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } ret = ioctl(ctx->fd, IOC_HDMIRX_G_CAPABILITY, &caps_info); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx capability fail!\n"); return ret; } err_ret = memcpy_s(capability, sizeof(*capability), &(caps_info), sizeof(caps_info)); if (err_ret != EOK) { ext_err_hdmirx("secure func call error\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } return ret; } td_s32 ext_mpi_hdmirx_get_offline_status(ext_drv_hdmirx_port port, ext_drv_hdmirx_offline_info *offline) { td_s32 ret = TD_SUCCESS; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); ext_drv_hdmirx_offline_status status; check_mpi_hdmirx_null_ptr(offline, ret); if (ret != TD_SUCCESS) { return ret; } hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { offline->connected = TD_FALSE; offline->format = EXT_DRV_HDMIRX_FORMAT_MAX; return ret; } if (port >= EXT_DRV_HDMIRX_PORT_MAX) { ext_err_hdmirx("hdmirx port:%d error!\n", port); offline->connected = TD_FALSE; offline->format = EXT_DRV_HDMIRX_FORMAT_MAX; return SOC_ERR_HDMIRX_INVALID_PORT; } status.port = port; ret = ioctl(ctx->fd, IOC_HDMIRX_G_OFF_LINE_DET_STA, &status); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx get_offline_det_status of port:%d error!\n", port); return ret; } offline->connected = status.info.connected; offline->format = status.info.format; return TD_SUCCESS; } #ifndef CONFIG_HDMIRX_EXCLUDE_HDCP static ext_hdmirx_hdcp_key_type ext_mpi_hdmirx_get_hdcp_key_type(td_u32 otp_key_type) { ext_hdmirx_hdcp_key_type key_type; if (otp_key_type == HDMIRX_OTP_KEY_TYPE_STBM) { key_type = HDMIRX_HDCP_KEY_TYPE_OEM; } else if (otp_key_type == HDMIRX_OTP_KEY_TYPE_SOCT) { key_type = HDMIRX_HDCP_KEY_TYPE_MAX; /* not support now */ ext_err_hdmirx("not support now (otp_key_type = %u)!\n", otp_key_type); } else { key_type = HDMIRX_HDCP_KEY_TYPE_MAX; ext_err_hdmirx("invalide otp_key_type = %u!\n", otp_key_type); } return key_type; } static ext_klad_alg_type ext_mpi_hdmirx_get_klad_alg_type(td_u32 algorithm) { ext_klad_alg_type alg_type; if (algorithm == HDMIRX_ALGORITHM_AES128_GCM) { alg_type = EXT_KLAD_ALG_TYPE_AES; } else if (algorithm == HDMIRX_ALGORITHM_SM4_CTR) { alg_type = EXT_KLAD_ALG_TYPE_SM4; } else { alg_type = EXT_KLAD_ALG_TYPE_MAX; ext_err_hdmirx("invalide algorithm = 0x%x!\n", algorithm); } return alg_type; } static uapi_cipher_hdmi_ram_sel mpi_hdmirx_get_hdmi_ram_sel(td_u32 data_type) { uapi_cipher_hdmi_ram_sel ram_sel; switch (data_type) { case HDMIRX_HDCP14_TX_KEY: ram_sel = UAPI_CIPHER_HDMI_RAM_SEL_TX_14; break; case HDMIRX_HDCP14_RX_KEY: ram_sel = UAPI_CIPHER_HDMI_RAM_SEL_RX_14; break; case HDMIRX_HDCP22_RX_KEY: ram_sel = UAPI_CIPHER_HDMI_RAM_SEL_RX_22; break; case HDMIRX_HDCP22_TX_KEY: ram_sel = UAPI_CIPHER_HDMI_RAM_SEL_TX_22; break; default: ram_sel = UAPI_CIPHER_HDMI_RAM_SEL_COUNT; ext_err_hdmirx("invalide data_type = 0x%x!\n", data_type); }; return ram_sel; } static td_s32 ext_mpi_hdmirx_hdcp_package_check(const ext_hdmirx_hdcp_package *pkg, td_u32 size) { td_s32 ret = TD_SUCCESS; if (pkg->header.image_type != 0x3C78871E) { ext_err_hdmirx("invalid image_type = 0x%x!\n", pkg->header.image_type); return SOC_ERR_HDMIRX_INVALID_PARA; } if (pkg->header.key_area_offset < sizeof(pkg->header)) { ext_err_hdmirx("invalid key_area_offset = %u!\n", pkg->header.key_area_offset); return SOC_ERR_HDMIRX_INVALID_PARA; } if (pkg->header.data_area_offset < pkg->header.key_area_offset + sizeof(pkg->pk)) { ext_err_hdmirx("invalid data_area_offset = %u!\n", pkg->header.data_area_offset); return SOC_ERR_HDMIRX_INVALID_PARA; } if (size != pkg->header.data_area_offset + pkg->header.data_area_length) { ext_err_hdmirx("invalid package size = %u, data_offset = %u, data_length = %u!\n", size, pkg->header.data_area_offset, pkg->header.data_area_length); return SOC_ERR_HDMIRX_INVALID_PARA; } return ret; } static td_s32 mpi_hdmirx_get_klad_support(td_bool *klad_support) { ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); *klad_support = TD_TRUE; if (ctx->sys_version.chip_name_id == CHIP_NAME_RESERVED5 || ctx->sys_version.chip_name_id == CHIP_NAME_RESERVED2 || ctx->sys_version.chip_name_id == CHIP_NAME_RESERVED17 || ctx->sys_version.chip_name_id == CHIP_NAME_RESERVED19 || ctx->sys_version.chip_name_id == CHIP_NAME_HI3751V811) { *klad_support = TD_FALSE; } return TD_SUCCESS; } static td_s32 mpi_hdmirx_hdcp_package_parse(ext_hdmirx_hdcp_package *pkg, const td_u8 *data, td_u32 size) { td_s32 ret; ext_hdmirx_hdcp_package_header *headr = TD_NULL; ext_hdmirx_hdcp_package_pk *pk = TD_NULL; ext_hdmirx_hdcp_package_key *key = TD_NULL; headr = (ext_hdmirx_hdcp_package_header *)data; if (memcpy_s(&pkg->header, sizeof(pkg->header), headr, sizeof(*headr)) != 0) { ext_err_hdmirx("memcpy_s failed!\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } ret = ext_mpi_hdmirx_hdcp_package_check(pkg, size); if (ret != TD_SUCCESS) { return ret; } pk = (ext_hdmirx_hdcp_package_pk *)(data + pkg->header.key_area_offset); if (memcpy_s(&pkg->pk, sizeof(pkg->pk), pk, sizeof(*pk)) != 0) { ext_err_hdmirx("memcpy_s failed!\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } key = (ext_hdmirx_hdcp_package_key *)(data + pkg->header.data_area_offset); if (memcpy_s(&pkg->key, sizeof(pkg->key), key, sizeof(*key) - sizeof(key->key)) != 0) { ext_err_hdmirx("memcpy_s failed!\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } if ((pkg->header.data_area_length < pkg->key.key_len + 56) || /* 56bytes: not include key */ (pkg->key.key_len > sizeof(pkg->key.key))) { ext_err_hdmirx("invalid key_len = %u, data_area_length = %u\n", pkg->key.key_len, pkg->header.data_area_length); return SOC_ERR_HDMIRX_INVALID_PARA; } if (memcpy_s(pkg->key.key, sizeof(pkg->key.key), &data[size - 4 - pkg->key.key_len], pkg->key.key_len) != 0) { /* last 4bytes is crc */ ext_err_hdmirx("memcpy_s failed!\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } return TD_SUCCESS; } static td_s32 mpi_hdmirx_klad_init(td_handle *handle_ks) { td_s32 ret; ext_keyslot_attr ks_attr; ret = ext_mpi_klad_init(); if (ret != TD_SUCCESS) { ext_err_hdmirx("ext_mpi_klad_init failed(ret = 0x%x)!\n", ret); return SOC_ERR_HDMIRX_KLAD_FUNC_FAILED; } ret = ext_mpi_keyslot_init(); if (ret != TD_SUCCESS) { ext_err_hdmirx("ext_mpi_keyslot_init failed(ret = 0x%x)!\n", ret); ext_mpi_klad_deinit(); return SOC_ERR_HDMIRX_KEYSLOT_FUNC_FAILED; } ks_attr.type = EXT_KEYSLOT_TYPE_MCIPHER; ks_attr.secure_mode = EXT_KEYSLOT_SECURE_MODE_NONE; ret = ext_mpi_keyslot_create(&ks_attr, handle_ks); if (ret != TD_SUCCESS) { ext_err_hdmirx("ext_mpi_keyslot_create failed(ret = 0x%x)!\n", ret); ext_mpi_keyslot_deinit(); ext_mpi_klad_deinit(); return SOC_ERR_HDMIRX_KEYSLOT_FUNC_FAILED; } return ret; } static td_void mpi_hdmirx_klad_deinit(td_handle handle_ks) { td_bool klad_support = TD_FALSE; td_s32 ret; ret = mpi_hdmirx_get_klad_support(&klad_support); if (ret != TD_SUCCESS) { return; } if (klad_support == TD_TRUE) { ext_mpi_keyslot_destroy(handle_ks); ext_mpi_keyslot_deinit(); ext_mpi_klad_deinit(); } } static td_s32 ext_mpi_hdmirx_klad_destroy(const td_handle handle_klad, const td_handle handle_ks, td_bool is_detach) { td_s32 ret; if (is_detach == TD_TRUE) { ret = ext_mpi_klad_detach(handle_klad, handle_ks); if (ret != TD_SUCCESS) { ext_err_hdmirx("ext_mpi_klad_detach failed(ret = 0x%x)!\n", ret); } } ret = ext_mpi_klad_destroy(handle_klad); if (ret != TD_SUCCESS) { ext_err_hdmirx("ext_mpi_klad_destroy failed(ret = 0x%x)!\n", ret); return SOC_ERR_HDMIRX_KLAD_FUNC_FAILED; } return ret; } static td_s32 ext_mpi_hdmirx_klad_load_pk(ext_hdmirx_hdcp_key_type key_type, ext_klad_alg_type klad_alg, const ext_hdmirx_hdcp_package *hdcp_pkg, td_u32 pk_len, td_handle handle_ks) { td_s32 ret; td_handle handle_klad = TD_INVALID_HANDLE; ext_klad_content_key content_key = {0}; ext_klad_attr attr_klad = {{0}, {0}}; ret = ext_mpi_klad_create(&handle_klad); if (ret != TD_SUCCESS) { ext_err_hdmirx("ext_mpi_klad_create failed(ret = 0x%x)!\n", ret); return SOC_ERR_HDMIRX_KLAD_FUNC_FAILED; } attr_klad.klad_cfg.owner_id = hdcp_pkg->pk.vendor_id; /* vendor id */ if (key_type == HDMIRX_HDCP_KEY_TYPE_OEM) { attr_klad.klad_cfg.klad_type = EXT_KLAD_TYPE_OEM_HDCP; } attr_klad.key_cfg.decrypt_support = TD_TRUE; attr_klad.key_cfg.encrypt_support = TD_FALSE; attr_klad.key_cfg.engine = EXT_CRYPTO_ENGINE_ALG_RAW_HDCP; ret = ext_mpi_klad_set_attr(handle_klad, &attr_klad); if (ret != TD_SUCCESS) { ext_mpi_hdmirx_klad_destroy(handle_klad, handle_ks, TD_FALSE); return SOC_ERR_HDMIRX_KLAD_FUNC_FAILED; } ret = ext_mpi_klad_attach(handle_klad, handle_ks); if (ret != TD_SUCCESS) { ext_mpi_hdmirx_klad_destroy(handle_klad, handle_ks, TD_FALSE); return SOC_ERR_HDMIRX_KLAD_FUNC_FAILED; } content_key.odd = TD_FALSE; content_key.key_size = pk_len; content_key.alg = klad_alg; if (memcpy_s(content_key.key, sizeof(content_key.key), hdcp_pkg->pk.enc_pk, pk_len) != 0) { ext_err_hdmirx("memcpy_s failed!\n"); ext_mpi_hdmirx_klad_destroy(handle_klad, handle_ks, TD_TRUE); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } ret = ext_mpi_klad_set_content_key(handle_klad, &content_key); if (ret != TD_SUCCESS) { ext_mpi_hdmirx_klad_destroy(handle_klad, handle_ks, TD_TRUE); return SOC_ERR_HDMIRX_KLAD_FUNC_FAILED; } ret = ext_mpi_hdmirx_klad_destroy(handle_klad, handle_ks, TD_TRUE); return ret; } static td_s32 mpi_hdmirx_get_cipher_algorithm_mode(uapi_cipher_hdcp_attr *hdcp_attr, const ext_hdmirx_hdcp_package *pkg) { if (pkg->pk.algorithm == HDMIRX_ALGORITHM_AES128_GCM) { hdcp_attr->alg = UAPI_CIPHER_SYMC_ALG_AES; hdcp_attr->mode = UAPI_CIPHER_SYMC_WORK_MODE_GCM; } else if (pkg->pk.algorithm == HDMIRX_ALGORITHM_SM4_CTR) { hdcp_attr->alg = UAPI_CIPHER_SYMC_ALG_SM4; hdcp_attr->mode = UAPI_CIPHER_SYMC_WORK_MODE_CTR; } else if (pkg->pk.algorithm == HDMIRX_ALGORITHM_AES_CBC) { hdcp_attr->alg = UAPI_CIPHER_SYMC_ALG_AES; hdcp_attr->mode = UAPI_CIPHER_SYMC_WORK_MODE_CBC; } else { ext_err_hdmirx("invalid algorithm = 0x%x!\n", pkg->pk.algorithm); return SOC_ERR_HDMIRX_INVALID_PARA; } return TD_SUCCESS; } static td_s32 mpi_hdmirx_get_cipher_hdcp_attr(uapi_cipher_hdcp_attr *hdcp_attr, const ext_hdmirx_hdcp_package *pkg, ext_drv_hdmirx_port port, td_handle handle_ks) { td_s32 ret; hdcp_attr->ram_num = port; hdcp_attr->key_slot = handle_ks; hdcp_attr->ram_sel = mpi_hdmirx_get_hdmi_ram_sel(pkg->header.data_type); if (hdcp_attr->ram_sel == UAPI_CIPHER_HDMI_RAM_SEL_COUNT) { return SOC_ERR_HDMIRX_INVALID_PARA; } ret = mpi_hdmirx_get_cipher_algorithm_mode(hdcp_attr, pkg); if (ret != TD_SUCCESS) { return ret; } hdcp_attr->key_sel = UAPI_CIPHER_HDCP_KEY_SEL_KLAD; if (memcpy_s(hdcp_attr->tag, sizeof(hdcp_attr->tag), pkg->key.tag, sizeof(pkg->key.tag)) != 0) { ext_err_hdmirx("memcpy_s failed!\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } if (memcpy_s(hdcp_attr->aad, sizeof(hdcp_attr->aad), pkg->key.manufacture_name, sizeof(pkg->key.manufacture_name)) != 0) { ext_err_hdmirx("memcpy_s failed!\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } if (memcpy_s(hdcp_attr->iv, sizeof(hdcp_attr->iv), pkg->key.iv, sizeof(pkg->key.iv)) != 0) { ext_err_hdmirx("memcpy_s failed!\n"); return SOC_ERR_HDMIRX_SECURE_FUNC_FAILED; } return TD_SUCCESS; } static td_s32 mpi_hdmirx_hdcp_check(ext_drv_hdmirx_port port, ext_drv_hdmirx_hdcp_type type, const ext_drv_hdmirx_hdcp *hdcp_info) { if ((port >= EXT_DRV_HDMIRX_PORT_MAX) || (hdcp_info == NULL)) { return SOC_ERR_HDMIRX_INVALID_PARA; } if (hdcp_info->hdcp_data == NULL) { ext_err_hdmirx("hdcp_data = NULL!\n"); return SOC_ERR_HDMIRX_NULL_PTR; } if (type >= EXT_DRV_HDMIRX_HDCPTYPE_MAX) { ext_err_hdmirx("hdcp_type is error!\n"); return SOC_ERR_HDMIRX_HDCP_TYPE_ERR; } return TD_SUCCESS; } static td_s32 ext_mpi_hdmirx_klad_load(const ext_hdmirx_hdcp_package *hdcp_package, td_handle handle_ks) { ext_hdmirx_hdcp_key_type key_type; ext_klad_alg_type alg_type; td_s32 ret; key_type = ext_mpi_hdmirx_get_hdcp_key_type(hdcp_package->pk.otp_key_type); alg_type = ext_mpi_hdmirx_get_klad_alg_type(hdcp_package->pk.algorithm); if ((alg_type == EXT_KLAD_ALG_TYPE_MAX) || (key_type == HDMIRX_HDCP_KEY_TYPE_MAX)) { ret = SOC_ERR_HDMIRX_INVALID_PARA; return ret; } ret = ext_mpi_hdmirx_klad_load_pk(key_type, alg_type, hdcp_package, HDMIRX_HDCP_ENC_PK_SZ, handle_ks); return ret; } static td_s32 ext_mpi_hdmirx_load_hdcp(ext_drv_hdmirx_port port, ext_drv_hdmirx_hdcp_type type) { td_s32 ret; ext_drv_hdmirx_hdcp_info hdcp_update_info; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); hdcp_update_info.port = port; hdcp_update_info.hdcp_type = type; ret = ioctl(ctx->fd, IOC_HDMIRX_S_LOAD_HDCP, &hdcp_update_info); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx update_hdcp fail, 0x%x!\n", ret); } return ret; } static td_s32 mpi_hdmirx_mem_malloc(ext_hdmirx_hdcp_package **hdcp_package, td_u8 **key_out) { *hdcp_package = (ext_hdmirx_hdcp_package *)malloc(sizeof(ext_hdmirx_hdcp_package)); if (*hdcp_package == TD_NULL) { ext_err_hdmirx("mpi malloc failed!\n"); return SOC_ERR_HDMIRX_MALLOC_FAILED; } *key_out = (td_u8 *)malloc(HDMIRX_HDCP_KEY_MAX_SZ * sizeof(td_u8)); if (*key_out == TD_NULL) { ext_err_hdmirx("mpi malloc failed!\n"); free(*hdcp_package); *hdcp_package = TD_NULL; return SOC_ERR_HDMIRX_MALLOC_FAILED; } return TD_SUCCESS; } static td_s32 mpi_hdmirx_cipher_klad_init(td_handle *handle_ks, const ext_hdmirx_hdcp_package *hdcp_package) { td_s32 ret; td_bool klad_support = TD_TRUE; ret = uapi_cipher_symc_init(); if (ret != TD_SUCCESS) { ext_err_hdmirx("ext_mpi_cipher_init failed(ret = 0x%x)!\n", ret); return SOC_ERR_HDMIRX_CIPHER_FUNC_FAILED; } ret = mpi_hdmirx_get_klad_support(&klad_support); if (ret != TD_SUCCESS) { uapi_cipher_symc_deinit(); return ret; } if (klad_support == TD_TRUE) { ret = mpi_hdmirx_klad_init(handle_ks); if (ret != TD_SUCCESS) { uapi_cipher_symc_deinit(); return ret; } ret = ext_mpi_hdmirx_klad_load(hdcp_package, *handle_ks); if (ret != TD_SUCCESS) { mpi_hdmirx_klad_deinit(*handle_ks); uapi_cipher_symc_deinit(); return ret; } } return TD_SUCCESS; } static td_void ext_mpi_hdmirx_hdcp_deinit(const td_handle handle_ks, td_u8 **key_out, ext_hdmirx_hdcp_package **hdcp_package, td_bool is_deinit) { if (is_deinit == TD_TRUE) { mpi_hdmirx_klad_deinit(handle_ks); uapi_cipher_symc_deinit(); } free(*hdcp_package); free(*key_out); *hdcp_package = TD_NULL; *key_out = TD_NULL; } static td_bool mpi_hdmirx_check_hdcp_loaded(ext_drv_hdmirx_port port, ext_drv_hdmirx_hdcp_type type) { td_s32 ret; ext_drv_hdmirx_hdcp_load_state key_load_state = {0}; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); key_load_state.port = port; ret = ioctl(ctx->fd, IOC_HDMIRX_CHECK_HDCP_LOADED, &key_load_state); if (ret == TD_SUCCESS) { if (type == EXT_DRV_HDMIRX_HDCPTYPE_14) { return key_load_state.hdcp14_loaded; } else if (type == EXT_DRV_HDMIRX_HDCPTYPE_22) { return key_load_state.hdcp22_loaded; } } return TD_FALSE; } static td_bool mpi_hdmirx_need_update_hdcp(ext_drv_hdmirx_port port, ext_drv_hdmirx_hdcp_type type) { ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); if ((ctx->sys_version.chip_name_id == CHIP_NAME_HI3751V811) && (port != EXT_DRV_HDMIRX_PORT0)) { /* TELEVISION_A only need port0 update hdcp */ return TD_FALSE; } if ((ctx->sys_version.chip_name_id >= CHIP_NAME_RESERVED5 && ctx->sys_version.chip_name_id <= CHIP_NAME_RESERVED19) && (port != EXT_DRV_HDMIRX_PORT0)) { /* TELEVISION_A only need port0 update hdcp */ return TD_FALSE; } /* If the HDCP key has been loaded, not need to load hdcp key again. */ if (mpi_hdmirx_check_hdcp_loaded(port, type)) { return TD_FALSE; } return TD_TRUE; } td_s32 ext_mpi_hdmirx_update_hdcp(ext_drv_hdmirx_port port, ext_drv_hdmirx_hdcp_type type, const ext_drv_hdmirx_hdcp *hdcp_info) { td_s32 ret; td_handle handle_ks = 0; uapi_cipher_hdcp_attr hdcp_attr = {0}; ext_hdmirx_hdcp_package *hdcp_package = TD_NULL; td_u8 *key_out = TD_NULL; ret = mpi_hdmirx_hdcp_check(port, type, hdcp_info); if (ret != TD_SUCCESS) { return ret; } ext_info_hdmirx("port%d start load %s key\n", port, (type == EXT_DRV_HDMIRX_HDCPTYPE_14) ? "hdcp1x" : "hdcp2x"); if (mpi_hdmirx_need_update_hdcp(port, type) == TD_FALSE) { ext_info_hdmirx("port%d update hdcp success!\n", port); return TD_SUCCESS; } if (mpi_hdmirx_mem_malloc(&hdcp_package, &key_out) != TD_SUCCESS) { return SOC_ERR_HDMIRX_MALLOC_FAILED; } ret = mpi_hdmirx_hdcp_package_parse(hdcp_package, hdcp_info->hdcp_data, hdcp_info->hdcp_length); if (ret != TD_SUCCESS) { ext_mpi_hdmirx_hdcp_deinit(handle_ks, &key_out, &hdcp_package, TD_FALSE); return ret; } ret = mpi_hdmirx_cipher_klad_init(&handle_ks, hdcp_package); if (ret != TD_SUCCESS) { ext_mpi_hdmirx_hdcp_deinit(handle_ks, &key_out, &hdcp_package, TD_FALSE); return ret; } ret = mpi_hdmirx_get_cipher_hdcp_attr(&hdcp_attr, hdcp_package, port, handle_ks); if (ret != TD_SUCCESS) { ext_mpi_hdmirx_hdcp_deinit(handle_ks, &key_out, &hdcp_package, TD_TRUE); return ret; } ret = uapi_hdcp_operation(&hdcp_attr, hdcp_package->key.key, key_out, hdcp_package->key.key_len, TD_TRUE); /* TD_TRUE: decrypt */ if (ret != TD_SUCCESS) { ext_mpi_hdmirx_hdcp_deinit(handle_ks, &key_out, &hdcp_package, TD_TRUE); return SOC_ERR_HDMIRX_HDCP_OPERATION_FAILED; } ret = ext_mpi_hdmirx_load_hdcp(port, type); ext_mpi_hdmirx_hdcp_deinit(handle_ks, &key_out, &hdcp_package, TD_TRUE); return ret; } #endif td_s32 ext_mpi_hdmirx_cec_enable(td_bool enable) { td_s32 ret = TD_SUCCESS; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { return ret; } if (enable != TD_TRUE && enable != TD_FALSE) { ext_err_hdmirx("hdmirx hdmirx_cec_enable input value:%d error!\n", enable); return SOC_ERR_HDMIRX_INVALID_PARA; } ext_info_hdmirx("set hdmirx_cec_enable value to %d\n", enable); ret = ioctl(ctx->fd, IOC_HDMIRX_S_CEC_ENABLE, &enable); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx cec_enable:%d fail!\n", enable); return ret; } return ret; } td_s32 ext_mpi_hdmirx_set_hpd_value(ext_drv_hdmirx_port port, td_bool value) { td_s32 ret; ext_drv_hdmirx_hpd hpd; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); if (port >= EXT_DRV_HDMIRX_PORT_MAX) { ext_err_hdmirx("hdmirx set_hpd_value port:%d error!\n", port); return SOC_ERR_HDMIRX_INVALID_PORT; } if (value != TD_TRUE && value != TD_FALSE) { ext_err_hdmirx("hdmirx set_hpd_value input value of port:% error!\n", port); return SOC_ERR_HDMIRX_INVALID_PARA; } hpd.port = port; hpd.value = value; ext_info_hdmirx("INFO! hdmirx set port:%d HPD:%d\n", port, value); ret = ioctl(ctx->fd, IOC_HDMIRX_S_HPD_VALUE, &hpd); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx set_hpd_value of port:% fail!\n", port); return ret; } return ret; } td_s32 ext_mpi_hdmirx_get_video_attr(ext_drv_hdmirx_port port, ext_drv_hdmirx_video_attr *video_attr) { ext_drv_hdmirx_video_info video_info = {0}; td_s32 ret = TD_SUCCESS; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); check_mpi_hdmirx_null_ptr(video_attr, ret); if (ret != TD_SUCCESS) { return ret; } if (video_attr == TD_NULL) { ext_err_hdmirx("hdmirx video_attr is null!\n"); return SOC_ERR_HDMIRX_NULL_PTR; } hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { video_attr->allm_status = EXT_DRV_HDMIRX_ALLM_STATUS_NONE; video_attr->vrr_mode = EXT_DRV_HDMIRX_VRR_MODE_NONE; return ret; } video_info.port = port; ret = ioctl(ctx->fd, IOC_HDMIRX_G_VIDEO_ATTR, &video_info); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx get_video_attr of port:%d fail!\n", port); return ret; } video_attr->allm_status = video_info.video_attr.allm_status; video_attr->vrr_mode = video_info.video_attr.vrr_mode; video_attr->cur_frame_rate = video_info.video_attr.cur_frame_rate; return ret; } td_s32 ext_mpi_hdmirx_cec_set_command(const ext_drv_hdmirx_cec_cmd *cec_cmd) { td_s32 ret = TD_SUCCESS; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { return ret; } check_mpi_hdmirx_null_ptr(cec_cmd, ret); if (ret != TD_SUCCESS) { return ret; } ret = ioctl(ctx->fd, IOC_HDMIRX_S_CEC_CMD, cec_cmd); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx set_command fail!\n"); return ret; } return ret; } td_s32 ext_mpi_hdmirx_cec_get_command(ext_drv_hdmirx_cec_cmd *cec_cmd) { td_s32 ret = TD_SUCCESS; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { return ret; } check_mpi_hdmirx_null_ptr(cec_cmd, ret); if (ret != TD_SUCCESS) { return ret; } ret = ioctl(ctx->fd, IOC_HDMIRX_G_CEC_CMD, cec_cmd); return ret; } td_s32 ext_mpi_hdmirx_cec_get_cur_cmd_state(ext_drv_hdmirx_cec_cmd_state_data *cmd_state) { td_s32 ret = TD_SUCCESS; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { return ret; } check_mpi_hdmirx_null_ptr(cmd_state, ret); if (ret != TD_SUCCESS) { return ret; } ret = ioctl(ctx->fd, IOC_HDMIRX_G_CEC_CMDSTATE, cmd_state); return ret; } td_s32 ext_mpi_hdmirx_get_source_product_description(ext_drv_hdmirx_spd_info *spd_info) { td_s32 ret = TD_SUCCESS; ext_mpi_hdmirx_ctx *ctx = hdmirx_mpi_get_ctx(); check_mpi_hdmirx_null_ptr(spd_info, ret); if (ret != TD_SUCCESS) { return ret; } hdmirx_mpi_check_inited(ret); if (ret != TD_SUCCESS) { return ret; } ret = ioctl(ctx->fd, IOC_HDMIRX_G_SPD_INFO, spd_info); if (ret != TD_SUCCESS) { ext_err_hdmirx("hdmirx get_spd_info fail!\n"); return ret; } return ret; }