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.

374 lines
14 KiB

/*
* Copyright 2023 Rockchip Electronics S.LSI Co. LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <dlfcn.h>
#include "TvPcieEp.h"
#include "common/RgaCropScale.h"
using ::android::tvinput::RgaCropScale;
namespace android {
//=======================================ep=====================================
typedef int (*rk_pcie_device_init_func)(void);
typedef int (*rk_pcie_device_deinit_func)(void);
typedef pcie_task_msg_st* (*rk_pcie_wait_task_msg_func)(int timeout_ms);
typedef void (*rk_pcie_task_msg_release_func)(struct pcie_task_msg_st *msg);
typedef int (*rk_pcie_task_create_func)(int task_id);
typedef int (*rk_pcie_task_destroy_func)(int task_id);
typedef int (*rk_pcie_set_ep_info_func)(void *status, size_t status_size);
typedef void* (*rk_pcie_get_user_cmd_func)(void);
typedef pcie_buff_node* (*rk_pcie_get_buff_func)(int task_id, enum EBuff_Type type);
typedef int (*rk_pcie_send_buff_func)(int task_id, struct pcie_buff_node *pbuff);
typedef int (*rk_pcie_release_buff_func)(int task_id, struct pcie_buff_node *pbuff);
typedef size_t (*rk_pcie_get_buff_max_size_func)(int task_id, enum EBuff_Type type);
struct PcieEp_ops {
int (*rk_pcie_device_init)(void);
int (*rk_pcie_device_deinit)(void);
pcie_task_msg_st* (*rk_pcie_wait_task_msg)(int timeout_ms);
void (*rk_pcie_task_msg_release)(struct pcie_task_msg_st *msg);
int (*rk_pcie_task_create)(int task_id);
int (*rk_pcie_task_destroy)(int task_id);
int (*rk_pcie_set_ep_info)(void *status, size_t status_size);
void* (*rk_pcie_get_user_cmd)(void);
pcie_buff_node* (*rk_pcie_get_buff)(int task_id, enum EBuff_Type type);
int (*rk_pcie_send_buff)(int task_id, struct pcie_buff_node *pbuff);
int (*rk_pcie_release_buff)(int task_id, struct pcie_buff_node *pbuff);
size_t (*rk_pcie_get_buff_max_size)(int task_id, enum EBuff_Type type);
};
#define PCIE_EP_LIB_PATH "/vendor/lib64/lib_rk_pcie_ep.so"
static struct PcieEp_ops g_ep_ops;
static void *g_ep_handle = nullptr;
//==============================================================================
static int mEpDebugLevel = 0;
TvPcieEp::TvPcieEp() {
DEBUG_PRINT(3, "");
g_ep_handle = dlopen(PCIE_EP_LIB_PATH, RTLD_NOW);
if (g_ep_handle == NULL) {
DEBUG_PRINT(3, "cat not open %s", PCIE_EP_LIB_PATH);
} else {
g_ep_ops.rk_pcie_device_init = (rk_pcie_device_init_func)dlsym(g_ep_handle, "rk_pcie_device_init");
g_ep_ops.rk_pcie_device_deinit = (rk_pcie_device_deinit_func)dlsym(g_ep_handle, "rk_pcie_device_deinit");
g_ep_ops.rk_pcie_wait_task_msg = (rk_pcie_wait_task_msg_func)dlsym(g_ep_handle, "rk_pcie_wait_task_msg");
g_ep_ops.rk_pcie_task_msg_release = (rk_pcie_task_msg_release_func)dlsym(g_ep_handle, "rk_pcie_task_msg_release");
g_ep_ops.rk_pcie_task_create = (rk_pcie_task_create_func)dlsym(g_ep_handle, "rk_pcie_task_create");
g_ep_ops.rk_pcie_task_destroy = (rk_pcie_task_destroy_func)dlsym(g_ep_handle, "rk_pcie_task_destroy");
g_ep_ops.rk_pcie_set_ep_info = (rk_pcie_set_ep_info_func)dlsym(g_ep_handle, "rk_pcie_set_ep_info");
g_ep_ops.rk_pcie_get_user_cmd = (rk_pcie_get_user_cmd_func)dlsym(g_ep_handle, "rk_pcie_get_user_cmd");
g_ep_ops.rk_pcie_get_buff = (rk_pcie_get_buff_func)dlsym(g_ep_handle, "rk_pcie_get_buff");
g_ep_ops.rk_pcie_send_buff = (rk_pcie_send_buff_func)dlsym(g_ep_handle, "rk_pcie_send_buff");
g_ep_ops.rk_pcie_release_buff = (rk_pcie_release_buff_func)dlsym(g_ep_handle, "rk_pcie_release_buff");
g_ep_ops.rk_pcie_get_buff_max_size = (rk_pcie_get_buff_max_size_func)dlsym(g_ep_handle, "rk_pcie_get_buff_max_size");
}
mBuffMgr = common::TvInputBufferManager::GetInstance();
memset(&mInputInfo, 0, sizeof(mInputInfo));
mBufPrepareList.clear();
mBufDoneList.clear();
}
TvPcieEp::~TvPcieEp() {
DEBUG_PRINT(3, "");
if (g_ep_handle) {
dlclose(g_ep_handle);
}
}
int TvPcieEp::recvStreamThread() {
int ret = isEpNeedRestart();
if (ret != PCIE_CMD_HDMIIN_NON) {
DEBUG_PRINT(3, "ep need restart cmd=%d", ret);
usleep(100000);
if (mCallback == NULL) {
DEBUG_PRINT(3, "mCallback is null");
} else {
mCallback(mContext, ret);
}
return -1;
}
Mutex::Autolock autoLock(mPcieLock);
if (!mRcConnected || ep_ctx.recv_rc_exit) {
DEBUG_PRINT(3, "not connect to Rc or recv exit %d %d", mRcConnected, ep_ctx.recv_rc_exit);
return ret;
}
struct pcie_buff_node *node = g_ep_ops.rk_pcie_get_buff(ep_ctx.task_id, E_RECV);
if (node) {
if (mBufPrepareList.empty()) {
DEBUG_PRINT(3, "skip stream frame");
} else {
int bufIndex = 0;
int dstWidth = mBuffMgr->GetWidth(mBufPrepareList[bufIndex]);
int dstHeight = mBuffMgr->GetHeight(mBufPrepareList[bufIndex]);
if (mUsedRgaCopy) {
DEBUG_PRINT(mDebugLevel, "rga_copy start %dx%d, %zu", dstWidth, dstHeight, node->phy_addr);
RgaCropScale::rga_copy(-1, nullptr, node->phy_addr,
dstWidth, dstHeight, HAL_PIXEL_FORMAT_YCbCr_422_SP,
mBufPrepareList[bufIndex]->data[0], nullptr, -1);
DEBUG_PRINT(mDebugLevel, "rga_copy end %dx%d", dstWidth, dstHeight);
} else {
char* tmpDstPtr = NULL;
int lockMode = GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_CAMERA_MASK;
mBuffMgr->LockLocked(mBufPrepareList[bufIndex], lockMode, 0, 0, dstWidth, dstHeight, (void**)&tmpDstPtr);
size_t dstDatasize = 0;
for (int i = 0; i < mBuffMgr->GetNumPlanes(mBufPrepareList[bufIndex]); i++) {
dstDatasize += mBuffMgr->GetPlaneSize(mBufPrepareList[bufIndex], i);
}
size_t size = dstDatasize < node->size ? dstDatasize : node->size;
DEBUG_PRINT(mDebugLevel, "memcpy start srcDatasize=%zu, node size=%zu", dstDatasize, node->size);
std::memcpy(tmpDstPtr, node->vir_addr, size);
DEBUG_PRINT(mDebugLevel, "memcpy end srcDatasize=%zu, node size=%zu", dstDatasize, node->size);
mBuffMgr->UnlockLocked(mBufPrepareList[0]);
}
{
Mutex::Autolock autoLock(mBufLock);
mBufDoneList.push_back(mBufPrepareList[0]);
mBufPrepareList.erase(mBufPrepareList.begin());
}
ret = 0;
}
g_ep_ops.rk_pcie_release_buff(ep_ctx.task_id, node);
DEBUG_PRINT(mDebugLevel, "task_id=%d end deal stream recv", ep_ctx.task_id);
}
usleep(1000);
return NO_ERROR;
}
int TvPcieEp::init(NotifyTvPcieEpCallback callback, void* context) {
int ret = -1;
if (g_ep_handle == NULL) {
DEBUG_PRINT(3, " failed with g_ep_handle NULL");
return ret;
}
Mutex::Autolock autoLock(mPcieLock);
DEBUG_PRINT(3, "");
ret = g_ep_ops.rk_pcie_device_init();
DEBUG_PRINT(3, "pcie init device ret=%d", ret);
if (ret == 0) {
mDevInited = true;
mCallback = callback;
mContext = context;
mStop = false;
}
return ret;
}
int TvPcieEp::connect(int timeout_ms) {
if (mRcConnected) {
DEBUG_PRINT(3, "already connect, direct return success");
return 0;
}
int ret = -1;
if (g_ep_handle == NULL || !mDevInited) {
DEBUG_PRINT(3, "failed with g_ep_handle NULL or deviceInit=%d", mDevInited);
return ret;
}
DEBUG_PRINT(3, "timeout_ms=%d", timeout_ms);
ret = waitRcMsg(timeout_ms, E_TASK_MSG_CREATE, -1);
if (ret != 0) {
DEBUG_PRINT(3, "pcie connect to rc fail");
return ret;
}
mRcConnected = true;
return ret;
}
void TvPcieEp::createWorkThread(int task_id) {
DEBUG_PRINT(3, "start task_id=%d", task_id);
memset(&ep_ctx, 0, sizeof(ep_ctx));
ep_ctx.task_id = task_id;
ep_ctx.recv_rc_exit = 0;
if (mRecvStreamThread) {
DEBUG_PRINT(3, "========recv stream thread not null !!!==========task_id=%d", task_id);
}
mRecvStreamThread = new RecvStreamThread(this);
mShareUserCmd = (struct pcie_user_cmd_st *)g_ep_ops.rk_pcie_get_user_cmd();
if (mShareUserCmd) {
DEBUG_PRINT(3, "set share user cmd: ep_exit 0");
mShareUserCmd->ep_exit = 0;
}
ep_ctx.enable = 1;
DEBUG_PRINT(3, "end task_id=%d", task_id);
}
void TvPcieEp::destoryWorkThread(int task_id) {
DEBUG_PRINT(3, "start task_id=%d", task_id);
if (mRecvStreamThread) {
mRecvStreamThread->requestExit();
mRecvStreamThread.clear();
mRecvStreamThread = nullptr;
DEBUG_PRINT(3, "end exit recv stream thread");
}
if (mRcConnected) {
ep_ctx.recv_rc_exit = 1;
ep_ctx.enable = 0;
}
DEBUG_PRINT(3, "end task_id=%d", task_id);
}
int TvPcieEp::stop() {
DEBUG_PRINT(3, "start");
mStop = true;
if (g_ep_handle == NULL) {
DEBUG_PRINT(3, "failed with g_ep_handle NULL");
return 0;
}
int task_id = ep_ctx.task_id;
DEBUG_PRINT(3, "start deviceInit=%d, connectedRc=%d, task_id=%d",
mDevInited, mRcConnected, task_id);
if (mShareUserCmd) {
DEBUG_PRINT(3, "set share user cmd: ep_exit 1");
mShareUserCmd->ep_exit = 1;
DEBUG_PRINT(3, "set share user cmd: ep_need_restart PCIE_CMD_HDMIIN_NON");
mShareUserCmd->ep_need_restart = PCIE_CMD_HDMIIN_NON;
}
Mutex::Autolock autoLock(mPcieLock);
DEBUG_PRINT(3, "enter lock do destory");
if (mRcConnected) {
mRcConnected = false;
destoryWorkThread(task_id);
g_ep_ops.rk_pcie_task_destroy(task_id);
}
if (mDevInited) {
mDevInited = false;
g_ep_ops.rk_pcie_device_deinit();
}
DEBUG_PRINT(3, "end");
return 0;
}
bool TvPcieEp::isRcExit() {
Mutex::Autolock autoLock(mPcieLock);
if (mRcConnected && mShareUserCmd && !mStop) {
return mShareUserCmd->rc_exit == 1;
}
return false;
}
int TvPcieEp::isEpNeedRestart() {
Mutex::Autolock autoLock(mPcieLock);
if (mRcConnected && mShareUserCmd && !mStop) {
return mShareUserCmd->ep_need_restart;
}
return PCIE_CMD_HDMIIN_NON;
}
void TvPcieEp::getInputInfo(int& width, int& height, int& pixelFormat,
int& inDevConnected) {
width = mInputInfo.frameWidth;
height = mInputInfo.frameHeight;
pixelFormat = mInputInfo.framePixelFormat;
inDevConnected = mInputInfo.inDevConnected;
}
int TvPcieEp::waitRcMsg(int timeout_ms, int limitMsg, int cmd) {
Mutex::Autolock autoLock(mPcieLock);
int ret = -1;
if (g_ep_handle == NULL || !mDevInited) {
DEBUG_PRINT(3, "failed with g_ep_handle NULL or deviceInited=%d", mDevInited);
return -1;
}
struct pcie_task_msg_st *msg = g_ep_ops.rk_pcie_wait_task_msg(timeout_ms);
if (msg == NULL) {
DEBUG_PRINT(3, "rk_pcie_wait_task_msg failed, timeout_ms=%d", timeout_ms);
return ret;
}
DEBUG_PRINT(3, "msg type=%d, task_id=%d", msg->type, msg->task_id);
bool limitMsgCompare = false;
switch (msg->type) {
case E_TASK_MSG_CREATE:
ret = g_ep_ops.rk_pcie_task_create(msg->task_id);
DEBUG_PRINT(3, "rk_pcie_task_create taskid=%d, ret=%d", msg->task_id, ret);
if (msg->type == limitMsg) {
limitMsgCompare = true;
}
break;
case E_TASK_MSG_DESTORY:
ret = g_ep_ops.rk_pcie_task_destroy(msg->task_id);
DEBUG_PRINT(3, "rk_pcie_task_destroy %d ret=%d", msg->task_id, ret);
if (msg->type == limitMsg) {
limitMsgCompare = true;
}
break;
case E_TASK_MSG_USER: {
struct pcie_user_cmd_st *data = (struct pcie_user_cmd_st *)msg->data;
DEBUG_PRINT(3, "E_TASK_MSG_USER cmd=%d", data->cmd);
int task_id = msg->task_id;
if (data->cmd == PCIE_CMD_HDMIIN_INIT) {
mInputInfo.frameWidth = data->frameWidth;
mInputInfo.frameHeight = data->frameHeight;
mInputInfo.framePixelFormat = data->framePixelFormat;
mInputInfo.inDevConnected = data->inDevConnected;
DEBUG_PRINT(3, "E_TASK_MSG_USER %dx%d pixel=%d, inDevConnected=%d",
mInputInfo.frameWidth, mInputInfo.frameHeight, mInputInfo.frameHeight, mInputInfo.inDevConnected);
createWorkThread(task_id);
if (mShareUserCmd) {
long msgTimestamp = mShareUserCmd->rcMsgTimestamp;
if (msgTimestamp != 0) {
long currentTimestamp = (long)(systemTime()/1000000);
mShareUserCmd->rcMsgTimestamp = 0;
DEBUG_PRINT(3, "%ld rev rc msg, set timestamp from %ld to 0", currentTimestamp, msgTimestamp);
}
}
}
if (msg->type == limitMsg && cmd == data->cmd) {
limitMsgCompare = true;
}
ret = 0;
break;
}
default:
DEBUG_PRINT(3, "error msg type!!! %d", msg->type);
break;
}
g_ep_ops.rk_pcie_task_msg_release(msg);
return limitMsgCompare && ret == 0 ? 0 : -1;
}
void TvPcieEp::qBuf(buffer_handle_t handle) {
Mutex::Autolock autoLock(mBufLock);
mBufPrepareList.push_back(handle);
}
int TvPcieEp::dqBufFd() {
Mutex::Autolock autoLock(mBufLock);
int ret = -1;
if (!mBufDoneList.empty()) {
ret = mBufDoneList[0]->data[0];
mBufDoneList.erase(mBufDoneList.begin());
DEBUG_PRINT(mDebugLevel, "success fd=%d", ret);
return ret;
}
return ret;
}
void TvPcieEp::setDebugLevel(int debugLevel) {
//debugLevel = 3;
if (mDebugLevel != debugLevel) {
mDebugLevel = debugLevel;
mEpDebugLevel = debugLevel;
}
}
}