/* 
 | 
 * Copyright 2020 Rockchip Electronics 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. 
 | 
 */ 
 | 
  
 | 
#define MODULE_TAG "mpp_serivce" 
 | 
  
 | 
#include <sys/ioctl.h> 
 | 
#include <fcntl.h> 
 | 
#include <errno.h> 
 | 
#include <string.h> 
 | 
  
 | 
#include "mpp_env.h" 
 | 
#include "mpp_mem.h" 
 | 
#include "mpp_debug.h" 
 | 
#include "mpp_common.h" 
 | 
#include "osal_2str.h" 
 | 
  
 | 
#include "mpp_device_debug.h" 
 | 
#include "mpp_service_api.h" 
 | 
#include "mpp_service_impl.h" 
 | 
#include "mpp_server.h" 
 | 
  
 | 
typedef struct MppServiceQueryCfg_t { 
 | 
    RK_U32      cmd_butt; 
 | 
    const char  *name; 
 | 
} MppServiceQueryCfg; 
 | 
  
 | 
static const MppServiceQueryCfg query_cfg[] = { 
 | 
    {   MPP_CMD_QUERY_BASE,     "query_cmd",    }, 
 | 
    {   MPP_CMD_INIT_BASE,      "init_cmd",     }, 
 | 
    {   MPP_CMD_SEND_BASE,      "query_cmd",    }, 
 | 
    {   MPP_CMD_POLL_BASE,      "init_cmd",     }, 
 | 
    {   MPP_CMD_CONTROL_BASE,   "control_cmd",  }, 
 | 
}; 
 | 
  
 | 
static const RK_U32 query_count = MPP_ARRAY_ELEMS(query_cfg); 
 | 
  
 | 
const char *mpp_get_mpp_service_name(void) 
 | 
{ 
 | 
    static const char *mpp_service_name = NULL; 
 | 
    static const char *mpp_service_dev[] = { 
 | 
        "/dev/mpp_service", 
 | 
        "/dev/mpp-service", 
 | 
    }; 
 | 
  
 | 
    if (mpp_service_name) 
 | 
        return mpp_service_name; 
 | 
  
 | 
    if (!access(mpp_service_dev[0], F_OK | R_OK | W_OK)) { 
 | 
        mpp_service_name = mpp_service_dev[0]; 
 | 
    } else if (!access(mpp_service_dev[1], F_OK | R_OK | W_OK)) 
 | 
        mpp_service_name = mpp_service_dev[1]; 
 | 
  
 | 
    return mpp_service_name; 
 | 
} 
 | 
  
 | 
RK_S32 mpp_service_ioctl(RK_S32 fd, RK_U32 cmd, RK_U32 size, void *param) 
 | 
{ 
 | 
    MppReqV1 mpp_req; 
 | 
  
 | 
    memset(&mpp_req, 0, sizeof(mpp_req)); 
 | 
  
 | 
    mpp_req.cmd = cmd; 
 | 
    mpp_req.flag = 0; 
 | 
    mpp_req.size = size; 
 | 
    mpp_req.offset = 0; 
 | 
    mpp_req.data_ptr = REQ_DATA_PTR(param); 
 | 
  
 | 
    return (RK_S32)ioctl(fd, MPP_IOC_CFG_V1, &mpp_req); 
 | 
} 
 | 
  
 | 
RK_S32 mpp_service_ioctl_request(RK_S32 fd, MppReqV1 *req) 
 | 
{ 
 | 
    return (RK_S32)ioctl(fd, MPP_IOC_CFG_V1, req); 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_check_cmd_valid(RK_U32 cmd, const MppServiceCmdCap *cap) 
 | 
{ 
 | 
    RK_U32 found = 0; 
 | 
  
 | 
    if (cap->support_cmd > 0) { 
 | 
        found = (cmd < cap->query_cmd) ? 1 : 0; 
 | 
        found = (cmd >= MPP_CMD_INIT_BASE && cmd < cap->init_cmd)    ? 1 : found; 
 | 
        found = (cmd >= MPP_CMD_SEND_BASE && cmd < cap->send_cmd)    ? 1 : found; 
 | 
        found = (cmd >= MPP_CMD_POLL_BASE && cmd < cap->poll_cmd)    ? 1 : found; 
 | 
        found = (cmd >= MPP_CMD_CONTROL_BASE && cmd < cap->ctrl_cmd) ? 1 : found; 
 | 
    } else { 
 | 
        /* old kernel before support_cmd query is valid */ 
 | 
        found = (cmd >= MPP_CMD_INIT_BASE && cmd <= MPP_CMD_INIT_TRANS_TABLE)    ? 1 : found; 
 | 
        found = (cmd >= MPP_CMD_SEND_BASE && cmd <= MPP_CMD_SET_REG_ADDR_OFFSET) ? 1 : found; 
 | 
        found = (cmd >= MPP_CMD_POLL_BASE && cmd <= MPP_CMD_POLL_HW_FINISH)      ? 1 : found; 
 | 
        found = (cmd >= MPP_CMD_CONTROL_BASE && cmd <= MPP_CMD_RELEASE_FD)       ? 1 : found; 
 | 
    } 
 | 
  
 | 
    return found ? MPP_OK : MPP_NOK; 
 | 
} 
 | 
  
 | 
void check_mpp_service_cap(RK_U32 *codec_type, RK_U32 *hw_ids, MppServiceCmdCap *cap) 
 | 
{ 
 | 
    MppReqV1 mpp_req; 
 | 
    RK_S32 fd = -1; 
 | 
    RK_S32 ret = 0; 
 | 
    RK_U32 *cmd_butt = &cap->query_cmd;; 
 | 
    RK_U32 hw_support = 0; 
 | 
    RK_U32 val; 
 | 
    RK_U32 i; 
 | 
  
 | 
    /* for device check on startup */ 
 | 
    mpp_env_get_u32("mpp_device_debug", &mpp_device_debug, 0); 
 | 
  
 | 
    *codec_type = 0; 
 | 
    memset(hw_ids, 0, sizeof(RK_U32) * 32); 
 | 
  
 | 
    /* check hw_support flag for valid client type */ 
 | 
    fd = open(mpp_get_mpp_service_name(), O_RDWR | O_CLOEXEC); 
 | 
    if (fd < 0) { 
 | 
        mpp_err("open mpp_service to check cmd capability failed\n"); 
 | 
        memset(cap, 0, sizeof(*cap)); 
 | 
        return ; 
 | 
    } 
 | 
    ret = mpp_service_ioctl(fd, MPP_CMD_PROBE_HW_SUPPORT, 0, &hw_support); 
 | 
    if (!ret) { 
 | 
        mpp_dev_dbg_probe("vcodec_support %08x\n", hw_support); 
 | 
        *codec_type = hw_support; 
 | 
    } 
 | 
    cap->support_cmd = !access("/proc/mpp_service/supports-cmd", F_OK) || 
 | 
                       !access("/proc/mpp_service/support_cmd", F_OK); 
 | 
    if (cap->support_cmd) { 
 | 
        for (i = 0; i < query_count; i++, cmd_butt++) { 
 | 
            const MppServiceQueryCfg *cfg = &query_cfg[i]; 
 | 
  
 | 
            memset(&mpp_req, 0, sizeof(mpp_req)); 
 | 
  
 | 
            val = cfg->cmd_butt; 
 | 
            mpp_req.cmd = MPP_CMD_QUERY_CMD_SUPPORT; 
 | 
            mpp_req.data_ptr = REQ_DATA_PTR(&val); 
 | 
  
 | 
            ret = (RK_S32)ioctl(fd, MPP_IOC_CFG_V1, &mpp_req); 
 | 
            if (ret) 
 | 
                mpp_err_f("query %-11s support error %s.\n", cfg->name, strerror(errno)); 
 | 
            else { 
 | 
                *cmd_butt = val; 
 | 
                mpp_dev_dbg_probe("query %-11s support %04x\n", cfg->name, val); 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
    close(fd); 
 | 
  
 | 
    /* check each valid client type for hw_id */ 
 | 
    /* kernel need to set client type then get hw_id */ 
 | 
    for (i = 0; i < 32; i++) { 
 | 
        if (hw_support & (1 << i)) { 
 | 
            val = i; 
 | 
  
 | 
            fd = open(mpp_get_mpp_service_name(), O_RDWR | O_CLOEXEC); 
 | 
            if (fd < 0) { 
 | 
                mpp_err("open mpp_service to check cmd capability failed\n"); 
 | 
                break; 
 | 
            } 
 | 
            /* set client type first */ 
 | 
            ret = mpp_service_ioctl(fd, MPP_CMD_INIT_CLIENT_TYPE, sizeof(val), &val); 
 | 
            if (ret) { 
 | 
                mpp_err("check valid client type %d failed\n", i); 
 | 
            } else { 
 | 
                /* then get hw_id */ 
 | 
                ret = mpp_service_ioctl(fd, MPP_CMD_QUERY_HW_ID, sizeof(val), &val); 
 | 
                if (!ret) { 
 | 
                    mpp_dev_dbg_probe("client %-10s hw_id %08x\n", 
 | 
                                      strof_client_type((MppClientType)i), val); 
 | 
                    hw_ids[i] = val; 
 | 
                } else 
 | 
                    mpp_err("check valid client %-10s for hw_id failed\n", 
 | 
                            strof_client_type((MppClientType)i)); 
 | 
            } 
 | 
            close(fd); 
 | 
        } 
 | 
    } 
 | 
} 
 | 
  
 | 
MppReqV1 *mpp_service_next_req(MppDevMppService *p) 
 | 
{ 
 | 
    MppReqV1 *mpp_req = NULL; 
 | 
  
 | 
    if (p->req_cnt >= p->req_max) { 
 | 
        mpp_dev_dbg_msg("enlarge request count %d -> %d\n", 
 | 
                        p->req_max, p->req_max * 2); 
 | 
        p->reqs = mpp_realloc(p->reqs, MppReqV1, p->req_max * 2); 
 | 
        if (NULL == p->reqs) { 
 | 
            mpp_err_f("failed to enlarge request buffer\n"); 
 | 
            return NULL; 
 | 
        } 
 | 
  
 | 
        p->req_max *= 2; 
 | 
    } 
 | 
  
 | 
    mpp_req = &p->reqs[p->req_cnt++]; 
 | 
  
 | 
    return mpp_req; 
 | 
} 
 | 
  
 | 
RegOffsetInfo *mpp_service_next_reg_offset(MppDevMppService *p) 
 | 
{ 
 | 
    RegOffsetInfo *info = NULL; 
 | 
  
 | 
    if (p->reg_offset_count + p->reg_offset_pos >= p->reg_offset_max) { 
 | 
        mpp_dev_dbg_msg("enlarge reg offset count %d -> %d\n", 
 | 
                        p->reg_offset_max, p->reg_offset_max * 2); 
 | 
        p->reg_offset_info = mpp_realloc(p->reg_offset_info, RegOffsetInfo, p->reg_offset_max * 2); 
 | 
        if (NULL == p->reg_offset_info) { 
 | 
            mpp_err_f("failed to enlarge request buffer\n"); 
 | 
            return NULL; 
 | 
        } 
 | 
  
 | 
        p->reg_offset_max *= 2; 
 | 
    } 
 | 
  
 | 
    info = &p->reg_offset_info[p->reg_offset_count + p->reg_offset_pos]; 
 | 
    mpp_dev_dbg_msg("reg offset %d : %d\n", p->reg_offset_pos, p->reg_offset_count); 
 | 
    p->reg_offset_count++; 
 | 
  
 | 
    return info; 
 | 
} 
 | 
  
 | 
  
 | 
RcbInfo *mpp_service_next_rcb_info(MppDevMppService *p) 
 | 
{ 
 | 
    RcbInfo *info = NULL; 
 | 
  
 | 
    if (p->rcb_count + p->rcb_pos >= p->rcb_max) { 
 | 
        mpp_dev_dbg_msg("enlarge rcb info count %d -> %d\n", 
 | 
                        p->rcb_max, p->rcb_max * 2); 
 | 
        p->rcb_info = mpp_realloc(p->rcb_info, RcbInfo, p->rcb_max * 2); 
 | 
        if (NULL == p->rcb_info) { 
 | 
            mpp_err_f("failed to enlarge request buffer\n"); 
 | 
            return NULL; 
 | 
        } 
 | 
  
 | 
        p->rcb_max *= 2; 
 | 
    } 
 | 
  
 | 
    info = &p->rcb_info[p->rcb_count + p->rcb_pos]; 
 | 
    mpp_dev_dbg_msg("rcb info %d : %d\n", p->rcb_pos, p->rcb_count); 
 | 
    p->rcb_count++; 
 | 
  
 | 
    return info; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_init(void *ctx, MppClientType type) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
    MPP_RET ret = MPP_NOK; 
 | 
  
 | 
    p->cap = mpp_get_mpp_service_cmd_cap(); 
 | 
    p->client = open(mpp_get_mpp_service_name(), O_RDWR | O_CLOEXEC); 
 | 
    if (p->client < 0) { 
 | 
        mpp_err("open mpp_service failed\n"); 
 | 
        return ret; 
 | 
    } 
 | 
  
 | 
    /* set client type first */ 
 | 
    ret = mpp_service_ioctl(p->client, MPP_CMD_INIT_CLIENT_TYPE, sizeof(type), &type); 
 | 
    if (ret) 
 | 
        mpp_err("set client type %d failed\n", type); 
 | 
  
 | 
    mpp_assert(p->cap); 
 | 
    if (MPP_OK == mpp_service_check_cmd_valid(MPP_CMD_SEND_CODEC_INFO, p->cap)) 
 | 
        p->support_set_info = 1; 
 | 
    if (MPP_OK == mpp_service_check_cmd_valid(MPP_CMD_SET_RCB_INFO, p->cap)) 
 | 
        p->support_set_rcb_info = 1; 
 | 
    if (MPP_OK == mpp_service_check_cmd_valid(MPP_CMD_POLL_HW_IRQ, p->cap)) 
 | 
        p->support_hw_irq = 1; 
 | 
  
 | 
    /* default server fd is the opened client fd */ 
 | 
    p->client_type = type; 
 | 
    p->server = p->client; 
 | 
    p->batch_io = 0; 
 | 
    p->serv_ctx = NULL; 
 | 
    p->dev_cb   = NULL; 
 | 
  
 | 
    p->bat_cmd.flag = 0; 
 | 
    p->bat_cmd.client = p->client; 
 | 
    p->bat_cmd.ret = 0; 
 | 
  
 | 
    p->req_max = MAX_REQ_NUM; 
 | 
    p->reqs = mpp_malloc(MppReqV1, p->req_max); 
 | 
    if (NULL == p->reqs) { 
 | 
        mpp_err("create request buffer failed\n"); 
 | 
        ret = MPP_ERR_MALLOC; 
 | 
    } 
 | 
  
 | 
    p->reg_offset_max = MAX_REG_OFFSET; 
 | 
    p->reg_offset_info = mpp_malloc(RegOffsetInfo, p->reg_offset_max); 
 | 
    if (NULL == p->reg_offset_info) { 
 | 
        mpp_err("create register offset buffer failed\n"); 
 | 
        ret = MPP_ERR_MALLOC; 
 | 
    } 
 | 
    p->reg_offset_pos = 0; 
 | 
    p->reg_offset_count = 0; 
 | 
  
 | 
    p->rcb_max = MAX_RCB_OFFSET; 
 | 
    p->rcb_info = mpp_malloc(RcbInfo, p->rcb_max); 
 | 
    if (NULL == p->rcb_info) { 
 | 
        mpp_err("create rcb info buffer failed\n"); 
 | 
        ret = MPP_ERR_MALLOC; 
 | 
    } 
 | 
    p->rcb_pos = 0; 
 | 
    p->rcb_count = 0; 
 | 
  
 | 
    return ret; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_deinit(void *ctx) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
  
 | 
    if (p->batch_io) 
 | 
        mpp_server_detach(p); 
 | 
  
 | 
    if (p->client) 
 | 
        close(p->client); 
 | 
  
 | 
    MPP_FREE(p->reqs); 
 | 
    MPP_FREE(p->reg_offset_info); 
 | 
    MPP_FREE(p->rcb_info); 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_attach(void *ctx) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
  
 | 
    if (p->req_cnt) { 
 | 
        mpp_err_f("can not switch on bat mode when service working\n"); 
 | 
        return MPP_NOK; 
 | 
    } 
 | 
  
 | 
    if (!p->batch_io) 
 | 
        mpp_server_attach(p); 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_detach(void *ctx) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
  
 | 
    if (p->req_cnt) { 
 | 
        mpp_err_f("can not switch off bat mode when service working\n"); 
 | 
        return MPP_NOK; 
 | 
    } 
 | 
  
 | 
    if (p->batch_io) 
 | 
        mpp_server_detach(p); 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_delimit(void *ctx) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
    MppReqV1 *mpp_req = NULL; 
 | 
  
 | 
    /* set fd trans info if needed */ 
 | 
    if (p->reg_offset_count) { 
 | 
        mpp_req = mpp_service_next_req(p); 
 | 
  
 | 
        mpp_req->cmd = MPP_CMD_SET_REG_ADDR_OFFSET; 
 | 
        mpp_req->flag = MPP_FLAGS_REG_OFFSET_ALONE; 
 | 
        mpp_req->size = (p->reg_offset_count) * sizeof(RegOffsetInfo); 
 | 
        mpp_req->offset = 0; 
 | 
        mpp_req->data_ptr = REQ_DATA_PTR(&p->reg_offset_info[p->reg_offset_pos]); 
 | 
        p->reg_offset_pos += p->reg_offset_count; 
 | 
        p->reg_offset_count = 0; 
 | 
    } 
 | 
  
 | 
    /* set rcb offst info if needed */ 
 | 
    if (p->rcb_count) { 
 | 
        mpp_req = mpp_service_next_req(p); 
 | 
  
 | 
        mpp_req->cmd = MPP_CMD_SET_RCB_INFO; 
 | 
        mpp_req->flag = 0; 
 | 
        mpp_req->size = p->rcb_count * sizeof(RcbInfo); 
 | 
        mpp_req->offset = 0; 
 | 
        mpp_req->data_ptr = REQ_DATA_PTR(&p->rcb_info[p->rcb_pos]); 
 | 
        p->rcb_pos += p->rcb_count; 
 | 
        p->rcb_count = 0; 
 | 
    } 
 | 
  
 | 
    mpp_req = mpp_service_next_req(p); 
 | 
    mpp_req->cmd = MPP_CMD_SET_SESSION_FD; 
 | 
    mpp_req->flag = MPP_FLAGS_MULTI_MSG; 
 | 
    mpp_req->offset = 0; 
 | 
    mpp_req->size = sizeof(p->bat_cmd); 
 | 
    mpp_req->data_ptr = REQ_DATA_PTR(&p->bat_cmd); 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_set_cb_ctx(void *ctx, MppCbCtx *cb_ctx) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
  
 | 
    p->dev_cb = cb_ctx; 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_reg_wr(void *ctx, MppDevRegWrCfg *cfg) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
    MppReqV1 *mpp_req = mpp_service_next_req(p); 
 | 
  
 | 
    mpp_req->cmd = MPP_CMD_SET_REG_WRITE; 
 | 
    mpp_req->flag = 0; 
 | 
    mpp_req->size = cfg->size; 
 | 
    mpp_req->offset = cfg->offset; 
 | 
    mpp_req->data_ptr = REQ_DATA_PTR(cfg->reg); 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_reg_rd(void *ctx, MppDevRegRdCfg *cfg) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
    MppReqV1 *mpp_req = mpp_service_next_req(p); 
 | 
  
 | 
    mpp_req->cmd = MPP_CMD_SET_REG_READ; 
 | 
    mpp_req->flag = 0; 
 | 
    mpp_req->size = cfg->size; 
 | 
    mpp_req->offset = cfg->offset; 
 | 
    mpp_req->data_ptr = REQ_DATA_PTR(cfg->reg); 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_reg_offset(void *ctx, MppDevRegOffsetCfg *cfg) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
    RegOffsetInfo *info; 
 | 
    RK_S32 i; 
 | 
  
 | 
    if (!cfg->offset) 
 | 
        return MPP_OK; 
 | 
  
 | 
    if (p->reg_offset_count >= MAX_REG_OFFSET) { 
 | 
        mpp_err_f("reach max offset definition\n", MAX_REG_OFFSET); 
 | 
        return MPP_NOK; 
 | 
    } 
 | 
  
 | 
    for (i = 0; i < p->reg_offset_count; i++) { 
 | 
        info = &p->reg_offset_info[p->reg_offset_pos + i]; 
 | 
  
 | 
        if (info->reg_idx == cfg->reg_idx) { 
 | 
            mpp_err_f("reg[%d] offset has been set, cover old %d -> %d\n", 
 | 
                      info->reg_idx, info->offset, cfg->offset); 
 | 
            info->offset = cfg->offset; 
 | 
            return MPP_OK; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    info = mpp_service_next_reg_offset(p);; 
 | 
    info->reg_idx = cfg->reg_idx; 
 | 
    info->offset = cfg->offset; 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_reg_offsets(void *ctx, MppDevRegOffCfgs *cfgs) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
    RegOffsetInfo *info; 
 | 
    RK_S32 i; 
 | 
  
 | 
    if (cfgs->count <= 0) 
 | 
        return MPP_OK; 
 | 
  
 | 
    if (p->reg_offset_count >= MAX_REG_OFFSET || 
 | 
        p->reg_offset_count + cfgs->count >= MAX_REG_OFFSET) { 
 | 
        mpp_err_f("reach max offset definition\n", MAX_REG_OFFSET); 
 | 
        return MPP_NOK; 
 | 
    } 
 | 
  
 | 
    for (i = 0; i < cfgs->count; i++) { 
 | 
        MppDevRegOffsetCfg *cfg = &cfgs->cfgs[i]; 
 | 
        RK_S32 j; 
 | 
  
 | 
        for (j = 0; j < p->reg_offset_count; j++) { 
 | 
            info = &p->reg_offset_info[p->reg_offset_pos + j]; 
 | 
  
 | 
            if (info->reg_idx == cfg->reg_idx) { 
 | 
                mpp_err_f("reg[%d] offset has been set, cover old %d -> %d\n", 
 | 
                          info->reg_idx, info->offset, cfg->offset); 
 | 
                info->offset = cfg->offset; 
 | 
                continue; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        info = mpp_service_next_reg_offset(p);; 
 | 
        info->reg_idx = cfg->reg_idx; 
 | 
        info->offset = cfg->offset; 
 | 
    } 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_rcb_info(void *ctx, MppDevRcbInfoCfg *cfg) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
    RK_U32 rcb_info_disable = 0; 
 | 
  
 | 
    mpp_env_get_u32("disable_rcb_info", &rcb_info_disable, 0); 
 | 
    if (rcb_info_disable) 
 | 
        return MPP_OK; 
 | 
  
 | 
    if (!p->support_set_rcb_info) 
 | 
        return MPP_OK; 
 | 
  
 | 
    if (p->rcb_count >= MAX_RCB_OFFSET) { 
 | 
        mpp_err_f("reach max offset definition\n", MAX_RCB_OFFSET); 
 | 
        return MPP_NOK; 
 | 
    } 
 | 
  
 | 
    RcbInfo *info = mpp_service_next_rcb_info(p); 
 | 
  
 | 
    info->reg_idx = cfg->reg_idx; 
 | 
    info->size = cfg->size; 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_set_info(void *ctx, MppDevInfoCfg *cfg) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
  
 | 
    if (!p->support_set_info) 
 | 
        return MPP_OK; 
 | 
  
 | 
    if (!p->info_count) 
 | 
        memset(p->info, 0, sizeof(p->info)); 
 | 
  
 | 
    memcpy(&p->info[p->info_count], cfg, sizeof(MppDevInfoCfg)); 
 | 
    p->info_count++; 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_cmd_send(void *ctx) 
 | 
{ 
 | 
    MPP_RET ret = MPP_OK; 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
  
 | 
    if (p->req_cnt <= 0 || p->req_cnt > p->req_max) { 
 | 
        mpp_err_f("ctx %p invalid request count %d\n", ctx, p->req_cnt); 
 | 
        return MPP_ERR_VALUE; 
 | 
    } 
 | 
  
 | 
    if (p->info_count) { 
 | 
        if (p->support_set_info) { 
 | 
            MppReqV1 mpp_req; 
 | 
  
 | 
            mpp_req.cmd = MPP_CMD_SEND_CODEC_INFO; 
 | 
            mpp_req.flag = MPP_FLAGS_LAST_MSG; 
 | 
            mpp_req.size = p->info_count * sizeof(p->info[0]); 
 | 
            mpp_req.offset = 0; 
 | 
            mpp_req.data_ptr = REQ_DATA_PTR(p->info); 
 | 
  
 | 
            ret = mpp_service_ioctl_request(p->client, &mpp_req); 
 | 
            if (ret) 
 | 
                p->support_set_info = 0; 
 | 
        } 
 | 
        p->info_count = 0; 
 | 
    } 
 | 
  
 | 
    /* set fd trans info if needed */ 
 | 
    if (p->reg_offset_count) { 
 | 
        MppReqV1 *mpp_req = mpp_service_next_req(p); 
 | 
  
 | 
        mpp_req->cmd = MPP_CMD_SET_REG_ADDR_OFFSET; 
 | 
        mpp_req->flag = MPP_FLAGS_REG_OFFSET_ALONE; 
 | 
        mpp_req->size = (p->reg_offset_count) * sizeof(RegOffsetInfo); 
 | 
        mpp_req->offset = 0; 
 | 
        mpp_req->data_ptr = REQ_DATA_PTR(&p->reg_offset_info[p->reg_offset_pos]); 
 | 
        p->reg_offset_pos += p->reg_offset_count; 
 | 
    } 
 | 
  
 | 
    /* set rcb offst info if needed */ 
 | 
    if (p->rcb_count) { 
 | 
        MppReqV1 *mpp_req = mpp_service_next_req(p); 
 | 
  
 | 
        mpp_req->cmd = MPP_CMD_SET_RCB_INFO; 
 | 
        mpp_req->flag = 0; 
 | 
        mpp_req->size = p->rcb_count * sizeof(RcbInfo); 
 | 
        mpp_req->offset = 0; 
 | 
        mpp_req->data_ptr = REQ_DATA_PTR(&p->rcb_info[p->rcb_pos]); 
 | 
        p->rcb_pos += p->rcb_count; 
 | 
    } 
 | 
  
 | 
    /* setup flag for multi message request */ 
 | 
    if (p->req_cnt > 1) { 
 | 
        RK_S32 i; 
 | 
  
 | 
        for (i = 0; i < p->req_cnt; i++) 
 | 
            p->reqs[i].flag |= MPP_FLAGS_MULTI_MSG; 
 | 
    } 
 | 
    p->reqs[p->req_cnt - 1].flag |=  MPP_FLAGS_LAST_MSG; 
 | 
  
 | 
    if (p->batch_io) { 
 | 
        ret = mpp_server_send_task(ctx); 
 | 
        if (ret) 
 | 
            mpp_err_f("send task to server ret %d\n", ret); 
 | 
    } else { 
 | 
        ret = mpp_service_ioctl_request(p->server, &p->reqs[0]); 
 | 
        if (ret) { 
 | 
            mpp_err_f("ioctl MPP_IOC_CFG_V1 failed ret %d errno %d %s\n", 
 | 
                      ret, errno, strerror(errno)); 
 | 
            ret = errno; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    p->req_cnt = 0; 
 | 
    p->reg_offset_count = 0; 
 | 
    p->reg_offset_pos = 0; 
 | 
    p->rcb_count = 0; 
 | 
    p->rcb_pos = 0; 
 | 
    p->rcb_count = 0; 
 | 
    return ret; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_service_cmd_poll(void *ctx, MppDevPollCfg *cfg) 
 | 
{ 
 | 
    MppDevMppService *p = (MppDevMppService *)ctx; 
 | 
    MPP_RET ret = MPP_OK; 
 | 
  
 | 
    if (p->batch_io) { 
 | 
        ret = mpp_server_wait_task(ctx, 0); 
 | 
    } else { 
 | 
        MppReqV1 dev_req; 
 | 
  
 | 
        memset(&dev_req, 0, sizeof(dev_req)); 
 | 
  
 | 
        if (p->support_hw_irq && cfg) { 
 | 
            dev_req.cmd = MPP_CMD_POLL_HW_IRQ; 
 | 
            dev_req.flag |= MPP_FLAGS_LAST_MSG; 
 | 
  
 | 
            dev_req.size = sizeof(*cfg) + cfg->count_max * sizeof(cfg->slice_info[0]); 
 | 
            dev_req.offset = 0; 
 | 
            dev_req.data_ptr = REQ_DATA_PTR(cfg); 
 | 
        } else { 
 | 
            dev_req.cmd = MPP_CMD_POLL_HW_FINISH; 
 | 
            dev_req.flag |= MPP_FLAGS_LAST_MSG; 
 | 
  
 | 
            if (cfg) { 
 | 
                mpp_assert(cfg->count_max); 
 | 
                if (cfg->count_max) { 
 | 
                    cfg->count_ret = 1; 
 | 
                    cfg->slice_info[0].val = 0; 
 | 
                    cfg->slice_info[0].last = 1; 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
  
 | 
        ret = mpp_service_ioctl_request(p->server, &dev_req); 
 | 
        if (ret) { 
 | 
            mpp_err_f("ioctl MPP_IOC_CFG_V1 failed ret %d errno %d %s\n", 
 | 
                      ret, errno, strerror(errno)); 
 | 
            ret = errno; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    return ret; 
 | 
} 
 | 
  
 | 
const MppDevApi mpp_service_api = { 
 | 
    "mpp_service", 
 | 
    sizeof(MppDevMppService), 
 | 
    mpp_service_init, 
 | 
    mpp_service_deinit, 
 | 
    mpp_service_attach, 
 | 
    mpp_service_detach, 
 | 
    mpp_service_delimit, 
 | 
    mpp_service_set_cb_ctx, 
 | 
    mpp_service_reg_wr, 
 | 
    mpp_service_reg_rd, 
 | 
    mpp_service_reg_offset, 
 | 
    mpp_service_reg_offsets, 
 | 
    mpp_service_rcb_info, 
 | 
    mpp_service_set_info, 
 | 
    mpp_service_cmd_send, 
 | 
    mpp_service_cmd_poll, 
 | 
}; 
 |