/* * Copyright (c) 2021 Amlogic, Inc. All rights reserved. * * This source code is subject to the terms and conditions defined in the * file 'LICENSE' which is part of this source code package. * * Description: */ #define LOG_TAG "AmlMPDscDev" #include #include #include #include #include #include #include #include #include #include #include "AmlMPDscDev.h" #define MAX_DSC_DEV 16 #define DEV_NAME "/dev/dvb0.ca" static const char* mName = LOG_TAG; namespace aml_mp { struct _dsc_dev{ uint8_t used; int fd; }; typedef struct _dsc_dev dsc_dev; static dsc_dev dvb_dsc_dev[MAX_DSC_DEV]; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; bool dsc_inited = false; int ca_init(void) { pthread_mutex_lock(&lock); if (!dsc_inited) { MLOGI("ca dsc inited"); dsc_inited = true; } pthread_mutex_unlock(&lock); return CA_DSC_OK; } int ca_open(int devno) { int fd; char buf[32]; int32_t retry_open_times = 0; if (devno >= MAX_DSC_DEV) { MLOGE("ca_open failed! devno:%d\n", devno); return CA_DSC_ERROR; } snprintf(buf, sizeof(buf), DEV_NAME"%d", devno); pthread_mutex_lock(&lock); if (dvb_dsc_dev[devno].used) { MLOGI("ca_open dvb_dsc_dev[%d] has been used!", devno); pthread_mutex_unlock(&lock); return CA_DSC_OK; } pthread_mutex_unlock(&lock); retry_open: fd = open(buf, O_RDWR); MLOGI("ca_open [%d] fd is %d", devno, fd); if (fd == -1) { retry_open_times++; usleep(10000); if (retry_open_times < 200) { goto retry_open; } MLOGE("Cannot open %s%d (%d:%s), and will retry_open_times %d", DEV_NAME, devno, errno, strerror(errno), retry_open_times); return CA_DSC_ERROR; } pthread_mutex_lock(&lock); if (dvb_dsc_dev[devno].used) { MLOGI("ca_open dvb_dsc_dev[%d] has been used!", devno); close(fd); } else { dvb_dsc_dev[devno].fd = fd; dvb_dsc_dev[devno].used = 1; } pthread_mutex_unlock(&lock); return CA_DSC_OK; } int ca_alloc_chan(int devno, unsigned int pid, int algo, int dsc_type) { int ret, fd; struct ca_sc2_descr_ex desc; pthread_mutex_lock(&lock); MLOGI("ca_alloc_chan dev:%d, pid:0x%0x, algo:%d, dsc_type:%d\n", devno, pid, algo, dsc_type); memset(&desc, 0, sizeof(desc)); desc.cmd = CA_ALLOC; desc.params.alloc_params.pid = pid; desc.params.alloc_params.algo = (ca_sc2_algo_type)algo; desc.params.alloc_params.dsc_type = (ca_sc2_dsc_type)dsc_type; desc.params.alloc_params.ca_index = -1; desc.params.alloc_params.loop = 0; if (devno >= MAX_DSC_DEV) { MLOGE("ca_alloc_chan failed! devno:%d\n", devno); goto ERROR_EXIT; } if (!dvb_dsc_dev[devno].used) { MLOGE("ca_alloc_chan failed! devno:%d used:%d\n", devno, dvb_dsc_dev[devno].used); goto ERROR_EXIT; } fd = dvb_dsc_dev[devno].fd; ret = ioctl(fd, CA_SC2_SET_DESCR_EX, &desc); if (ret != 0) { MLOGE(" ca_alloc_chan ioctl fail, ret:0x%0x\n", ret); goto ERROR_EXIT; } pthread_mutex_unlock(&lock); MLOGI("ca_alloc_chan, index:%d\n", desc.params.alloc_params.ca_index); return desc.params.alloc_params.ca_index; ERROR_EXIT: pthread_mutex_unlock(&lock); return CA_DSC_ERROR; } int ca_set_scb(int devno, int ca_index,int ca_scb, int ca_scb_as_is) { struct ca_sc2_descr_ex desc; memset(&desc, 0, sizeof(desc)); pthread_mutex_lock(&lock); if (devno >= MAX_DSC_DEV) { MLOGE("ca_set_scb failed! devno:%d\n", devno); pthread_mutex_unlock(&lock); return CA_DSC_ERROR; } if (!dvb_dsc_dev[devno].used) { MLOGE("ca_set_scb failed! devno:%d used:%d\n", devno, dvb_dsc_dev[devno].used); pthread_mutex_unlock(&lock); return CA_DSC_ERROR; } desc.cmd = CA_SET_SCB; desc.params.scb_params.ca_index = ca_index; desc.params.scb_params.ca_scb = ca_scb; desc.params.scb_params.ca_scb_as_is = ca_scb_as_is; int fd = dvb_dsc_dev[devno].fd; int ret = ioctl(fd, CA_SC2_SET_DESCR_EX, &desc); if (ret != 0) { MLOGE("ca_set_scb ioctl fail, ret:0x%0x\n", ret); pthread_mutex_unlock(&lock); return CA_DSC_ERROR; } MLOGI("ca_set_scb ca_index:%d,ca_scb:%d,ca_scb_as_is:%d, ret:0x%0x\n", desc.params.scb_params.ca_index,desc.params.scb_params.ca_scb,desc.params.scb_params.ca_scb_as_is, ret); pthread_mutex_unlock(&lock); return CA_DSC_OK; } int ca_free_chan(int devno, int index) { int ret, fd; struct ca_sc2_descr_ex desc; pthread_mutex_lock(&lock); MLOGI("ca_free_chan:%d, index:%d\n", devno, index); desc.cmd = CA_FREE; desc.params.free_params.ca_index = index; if (devno >= MAX_DSC_DEV) { MLOGE("ca_free_chan failed! devno:%d\n", devno); goto ERROR_EXIT; } if (!dvb_dsc_dev[devno].used) { MLOGE("ca_free_chan failed! devno:%d used:%d\n", devno, dvb_dsc_dev[devno].used); goto ERROR_EXIT; } fd = dvb_dsc_dev[devno].fd; ret = ioctl(fd, CA_SC2_SET_DESCR_EX, &desc); if (ret != 0) { MLOGE(" ca_free_chan ioctl fail\n"); goto ERROR_EXIT; } pthread_mutex_unlock(&lock); MLOGI("ca_free_chan, index:%d\n", index); return CA_DSC_OK; ERROR_EXIT: pthread_mutex_unlock(&lock); return CA_DSC_ERROR; } int ca_set_key(int devno, int index, int parity, uint32_t key_index) { int ret, fd; struct ca_sc2_descr_ex desc; pthread_mutex_lock(&lock); MLOGI("ca_set_key dev:%d, index:%d, parity:%d, key_index:%#x\n", devno, index, parity, key_index); desc.cmd = CA_KEY; desc.params.key_params.ca_index = index; desc.params.key_params.parity = (ca_sc2_key_type)parity; desc.params.key_params.key_index = key_index; if (devno >= MAX_DSC_DEV) { MLOGE("ca_set_key failed! devno:%d\n", devno); goto ERROR_EXIT; } if (!dvb_dsc_dev[devno].used) { MLOGE("ca_set_key failed! devno:%d used:%d\n", devno, dvb_dsc_dev[devno].used); goto ERROR_EXIT; } fd = dvb_dsc_dev[devno].fd; ret = ioctl(fd, CA_SC2_SET_DESCR_EX, &desc); if (ret != 0) { MLOGE("ca_set_key ioctl fail, ret:0x%0x\n", ret); goto ERROR_EXIT; } pthread_mutex_unlock(&lock); MLOGI("ca_set_key ok, index:%d, parity:%d, key_index:%#x\n",index, parity, key_index); return CA_DSC_OK; ERROR_EXIT: pthread_mutex_unlock(&lock); return CA_DSC_ERROR; } int ca_close(int devno) { int fd; int ret = 0; pthread_mutex_lock(&lock); MLOGI("ca_close dev:%d\n", devno); if (devno >= MAX_DSC_DEV) { MLOGE("ca_close failed! devno:%d\n", devno); goto ERROR_EXIT; } if (!dvb_dsc_dev[devno].used) { MLOGE("ca_close failed! devno:%d used:%d\n", devno, dvb_dsc_dev[devno].used); goto ERROR_EXIT; } fd = dvb_dsc_dev[devno].fd; ret = close(fd); if (0 == ret) { dvb_dsc_dev[devno].fd = 0; dvb_dsc_dev[devno].used = 0; } MLOGI("ca_close ret:%d\n", ret); pthread_mutex_unlock(&lock); return CA_DSC_OK; ERROR_EXIT: pthread_mutex_unlock(&lock); return CA_DSC_ERROR; } int caGetFd(int devno) { int fd = -1; pthread_mutex_lock(&lock); if (devno >= MAX_DSC_DEV) { MLOGE("ca_open failed! devno:%d\n", devno); pthread_mutex_unlock(&lock); return fd; } if (dvb_dsc_dev[devno].used) { fd = dvb_dsc_dev[devno].fd; } pthread_mutex_unlock(&lock); return fd; } bool caSetDscChannelsKeyslot(Aml_MP_MediaCasDsmParams *mediacasDsmParams) { MLOG(); Aml_MP_MediaCasDsmParams *mParams = mediacasDsmParams; int mCount = mParams->mKeyslotList.count; MLOGI("mKeyslotList mCount=%d.", mCount); for (int i = 0; i < mCount; i++) { uint32_t kt_parity = mParams->mKeyslotList.keyslots[i].parity; uint32_t kt_is_iv = mParams->mKeyslotList.keyslots[i].is_iv; int kt_type = 0; uint32_t kt_id = 0; if (kt_parity == DSM_PARITY_NONE) kt_type = kt_is_iv ? CA_KEY_00_IV_TYPE : CA_KEY_00_TYPE; else if (kt_parity == DSM_PARITY_EVEN) kt_type = kt_is_iv ? CA_KEY_EVEN_IV_TYPE : CA_KEY_EVEN_TYPE; else if (kt_parity == DSM_PARITY_ODD) kt_type = kt_is_iv ? CA_KEY_ODD_IV_TYPE : CA_KEY_ODD_TYPE; else return false; kt_id = mParams->mKeyslotList.keyslots[i].id; MLOGI("kt_is_iv=%d kt_type=%d kt_id=%d .", kt_is_iv, kt_type, kt_id); if (mParams->vdsc_handle != AML_MP_INVALID_DSC_HANDLE) { if (ca_set_key(mParams->dev_no, mParams->vdsc_handle, kt_type, kt_id)) { MLOGI("ca_set_key vdsc(%d %d %d) failed!", mParams->vdsc_handle, kt_type, kt_id); return false; } } for (int i = 0; i < (int)(sizeof(mParams->adsc_handle) / sizeof(mParams->adsc_handle[0])); i++) { if (mParams->adsc_handle[i] != AML_MP_INVALID_DSC_HANDLE) { if (ca_set_key(mParams->dev_no, mParams->adsc_handle[i], kt_type, kt_id)) { MLOGI("ca_set_key adsc[%d](%d %d %d) failed!", i, mParams->adsc_handle[i], kt_type, kt_id); return false; } } } } return true; } bool caFreeDscChannels(Aml_MP_MediaCasDsmParams *mediacasDsmParams) { MLOG(); Aml_MP_MediaCasDsmParams *mParams = mediacasDsmParams; MLOGI("dev_no,vdsc_handle (%d,%d).", mParams->dev_no, mParams->vdsc_handle); if (mParams->vdsc_handle != AML_MP_INVALID_DSC_HANDLE) { ca_free_chan(mParams->dev_no, mParams->vdsc_handle); } MLOGI("ca_free_chan vdsc(0x%x 0x%x) ok.", mParams->vid, mParams->vdsc_handle); for (int i = 0; i < (int)(sizeof(mParams->adsc_handle) / sizeof(mParams->adsc_handle[0])); i++) { MLOGI("dev_no,adsc_handle[%d] (%d,%d).", i, mParams->dev_no, mParams->adsc_handle[i]); if (mParams->adsc_handle[i] != AML_MP_INVALID_DSC_HANDLE) { ca_free_chan(mParams->dev_no, mParams->adsc_handle[i]); } MLOGI("ca_free_chan adsc[%d](0x%x 0x%x) ok.", i, mParams->aid[i], mParams->adsc_handle[i]); } ca_close(mParams->dev_no); mParams->hasAllocDscChannels = false; return true; } bool caAllocDscChannels(Aml_MP_MediaCasDsmParams *mediacasDsmParams) { MLOG(); Aml_MP_MediaCasDsmParams *mParams = mediacasDsmParams; if (mParams->hasAllocDscChannels == true) { MLOGI("caAllocDscChannels hasAllocDscChannels %d", mParams->hasAllocDscChannels); return true; } if (mParams->vid != AML_MP_INVALID_PID) { mParams->vdsc_handle = ca_alloc_chan(mParams->dev_no, mParams->vid, mParams->mDscAlgo, mParams->mDscType); if (mParams->vdsc_handle == AML_MP_INVALID_DSC_HANDLE) { MLOGI("ca_alloc_chan failed! vid:0x%x", mParams->vid); ca_close(mParams->dev_no); return false; } MLOGI("ca_alloc_chan vdsc(0x%x 0x%x) ok.", mParams->vid, mParams->vdsc_handle); //if(mParams->isDvrRecord) { ca_set_scb(mParams->dev_no, mParams->vdsc_handle, 0, 1); //} } for (int i = 0; i < (int)(sizeof(mParams->aid) / sizeof(mParams->aid[0])); i++) { if (mParams->aid[i] != AML_MP_INVALID_PID) { mParams->adsc_handle[i] = ca_alloc_chan(mParams->dev_no, mParams->aid[i], mParams->mDscAlgo, mParams->mDscType); if (mParams->adsc_handle[i] == AML_MP_INVALID_DSC_HANDLE) { MLOGI("ca_alloc_chan failed! aid:0x%x", mParams->aid[i]); ca_close(mParams->dev_no); return false; } MLOGI("ca_alloc_chan adsc[%d](0x%x 0x%x) ok.hasAllocDscChannels=true", i, mParams->aid[i], mParams->adsc_handle[i]); mParams->hasAllocDscChannels = true; //if(mParams->isDvrRecord) { ca_set_scb(mParams->dev_no, mParams->adsc_handle[i], 0, 1); //} } } mParams->hasAllocDscChannels = true; return true; } bool isDsmDecSlotReady(int dsmFd) { int dsmRet = 0; uint32_t mIsKtReady = DSM_PROP_SLOT_NOT_READY; uint32_t dsmUsage = DSM_PROP_SESSION_USAGE_LIVE; if (dsmFd >= 0) { dsmRet = DSM_GetProperty(dsmFd, DSM_PROP_CAS_SESSION_USAGE, &dsmUsage); if (dsmRet != 0 || dsmUsage != DSM_PROP_SESSION_USAGE_LIVE) return false; dsmRet = DSM_GetProperty(dsmFd, DSM_PROP_DEC_SLOT_READY, &mIsKtReady); if (dsmRet == 0 && mIsKtReady == DSM_PROP_SLOT_IS_READY) { MLOGI("DSM_PROP_SLOT_IS_READY"); return true; } else { return false; } } else { return false; } } bool getKeySlots(int dsmFd, Aml_MP_MediaCasDsmParams *mediacasDsmParams) { int dsmRet = 0; if (dsmFd < 0 || mediacasDsmParams == NULL) { MLOGI("invalid parameter"); return false; } dsmRet = DSM_GetKeySlots(dsmFd, &(mediacasDsmParams->mKeyslotList)); if (dsmRet) return false; return true; } bool caDsmOpenSession(int dev_no, int sessionId, int &dsmFd) { if (sessionId == -1) { MLOGE("invalid parameter"); return false; } int dsmFd_tmp = DSM_OpenSession(0);//a non-negative integer on success MLOGI("DSM_OpenSession mDsmFd: %d", dsmFd_tmp); if (dsmFd_tmp < 0) { MLOGE("dsm_open failed! %s", strerror(errno)); return false; } MLOGI("sessionId = 0x%x", sessionId); if (DSM_BindToken(dsmFd_tmp, sessionId)) { MLOGE("DSM_BindToken failed! %s", strerror(errno)); DSM_CloseSession(dsmFd_tmp); return false; } uint32_t casSessionUsage = 0; if (DSM_GetProperty(dsmFd_tmp, DSM_PROP_CAS_SESSION_USAGE, &casSessionUsage) == 0) { MLOGI("casSessionUsage:%d", casSessionUsage); } if (ca_open(dev_no) != 0) { MLOGE("ca_open failed! %s", strerror(errno)); DSM_CloseSession(dsmFd_tmp); return false; } dsmFd = dsmFd_tmp; return true; } int caDsmCloseSession(Aml_MP_MediaCasDsmParams *mediacasDsmParams) { Aml_MP_MediaCasDsmParams *mParams = mediacasDsmParams; int ret = 0; if (mParams->mDsmFd >= 0) { DSM_CloseSession(mParams->mDsmFd); mParams->mDsmFd = -1; } MLOGI("caDsmCloseSession ret:%d", ret); return ret; } int CaClearMediacasDsmParamsState(Aml_MP_MediaCasDsmParams *mediacasDsmParams) { Aml_MP_MediaCasDsmParams *mParams = mediacasDsmParams; memset(mParams, 0, sizeof(Aml_MP_MediaCasDsmParams)); mParams->mDsmFd = -1; mParams->vdsc_handle = AML_MP_INVALID_DSC_HANDLE; mParams->vid = AML_MP_INVALID_PID; for (int i = 0; i < (int)(sizeof(mParams->adsc_handle) / sizeof(mParams->adsc_handle[0])); i++) { mParams->adsc_handle[i] = AML_MP_INVALID_DSC_HANDLE; } for (int j = 0; j < (int)(sizeof(mParams->aid) / sizeof(mParams->aid[0])); j++) { mParams->aid[j] = AML_MP_INVALID_PID; } mParams->hasAllocDscChannels = false; return 0; } }