You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1219 lines
39 KiB
1219 lines
39 KiB
/*
|
|
* 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 <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/ioctl.h>
|
|
#include <string.h>
|
|
#include <pthread.h>
|
|
|
|
#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;
|
|
}
|