/* 
 | 
 * 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_device" 
 | 
  
 | 
#include <string.h> 
 | 
  
 | 
#include "mpp_env.h" 
 | 
#include "mpp_mem.h" 
 | 
#include "mpp_common.h" 
 | 
  
 | 
#include "mpp_platform.h" 
 | 
#include "mpp_device_debug.h" 
 | 
#include "mpp_service_api.h" 
 | 
#include "vcodec_service_api.h" 
 | 
  
 | 
typedef struct MppDevImpl_t { 
 | 
    MppClientType   type; 
 | 
  
 | 
    void            *ctx; 
 | 
    const MppDevApi *api; 
 | 
} MppDevImpl; 
 | 
  
 | 
RK_U32 mpp_device_debug = 0; 
 | 
  
 | 
MPP_RET mpp_dev_init(MppDev *ctx, MppClientType type) 
 | 
{ 
 | 
    if (NULL == ctx) { 
 | 
        mpp_err_f("found NULL input ctx\n"); 
 | 
        return MPP_ERR_NULL_PTR; 
 | 
    } 
 | 
  
 | 
    mpp_env_get_u32("mpp_device_debug", &mpp_device_debug, 0); 
 | 
  
 | 
    *ctx = NULL; 
 | 
  
 | 
    RK_U32 codec_type = mpp_get_vcodec_type(); 
 | 
    if (!(codec_type & (1 << type))) { 
 | 
        mpp_err_f("found unsupported client type %d in platform %x\n", 
 | 
                  type, codec_type); 
 | 
        return MPP_ERR_VALUE; 
 | 
    } 
 | 
  
 | 
    MppIoctlVersion ioctl_version = mpp_get_ioctl_version(); 
 | 
    const MppDevApi *api = NULL; 
 | 
  
 | 
    switch (ioctl_version) { 
 | 
    case IOCTL_VCODEC_SERVICE : { 
 | 
        api = &vcodec_service_api; 
 | 
    } break; 
 | 
    case IOCTL_MPP_SERVICE_V1 : { 
 | 
        api = &mpp_service_api; 
 | 
    } break; 
 | 
    default : { 
 | 
        mpp_err_f("invalid ioctl verstion %d\n", ioctl_version); 
 | 
        return MPP_NOK; 
 | 
    } break; 
 | 
    } 
 | 
  
 | 
    MppDevImpl *impl = mpp_calloc(MppDevImpl, 1); 
 | 
    void *impl_ctx = mpp_calloc_size(void, api->ctx_size); 
 | 
    if (NULL == impl || NULL == impl_ctx) { 
 | 
        mpp_err_f("malloc failed impl %p impl_ctx %p\n", impl, impl_ctx); 
 | 
        MPP_FREE(impl); 
 | 
        MPP_FREE(impl_ctx); 
 | 
        return MPP_ERR_MALLOC; 
 | 
    } 
 | 
  
 | 
    impl->ctx = impl_ctx; 
 | 
    impl->api = api; 
 | 
    impl->type = type; 
 | 
    *ctx = impl; 
 | 
  
 | 
    return api->init(impl_ctx, type); 
 | 
} 
 | 
  
 | 
MPP_RET mpp_dev_deinit(MppDev ctx) 
 | 
{ 
 | 
    if (NULL == ctx) { 
 | 
        mpp_err_f("found NULL input ctx\n"); 
 | 
        return MPP_ERR_NULL_PTR; 
 | 
    } 
 | 
  
 | 
    MppDevImpl *p = (MppDevImpl *)ctx; 
 | 
    MPP_RET ret = MPP_OK; 
 | 
  
 | 
    if (p->api && p->api->deinit && p->ctx) 
 | 
        ret = p->api->deinit(p->ctx); 
 | 
  
 | 
    MPP_FREE(p->ctx); 
 | 
    MPP_FREE(p); 
 | 
  
 | 
    return ret; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_dev_ioctl(MppDev ctx, RK_S32 cmd, void *param) 
 | 
{ 
 | 
    if (NULL == ctx) { 
 | 
        mpp_err_f("found NULL input ctx\n"); 
 | 
        return MPP_ERR_NULL_PTR; 
 | 
    } 
 | 
  
 | 
    MppDevImpl *p = (MppDevImpl *)ctx; 
 | 
    const MppDevApi *api = p->api; 
 | 
    void *impl_ctx = p->ctx; 
 | 
    MPP_RET ret = MPP_OK; 
 | 
  
 | 
    if (NULL == impl_ctx || NULL == api) 
 | 
        return ret; 
 | 
  
 | 
    switch (cmd) { 
 | 
    case MPP_DEV_BATCH_ON : { 
 | 
        if (api->attach) 
 | 
            ret = api->attach(impl_ctx); 
 | 
    } break; 
 | 
    case MPP_DEV_BATCH_OFF : { 
 | 
        if (api->detach) 
 | 
            ret = api->detach(impl_ctx); 
 | 
    } break; 
 | 
    case MPP_DEV_DELIMIT : { 
 | 
        if (api->delimit) 
 | 
            ret = api->delimit(impl_ctx); 
 | 
    } break; 
 | 
    case MPP_DEV_SET_CB_CTX: { 
 | 
        if (api->set_cb_ctx) 
 | 
            ret = api->set_cb_ctx(impl_ctx, param); 
 | 
    } break; 
 | 
    case MPP_DEV_REG_WR : { 
 | 
        if (api->reg_wr) 
 | 
            ret = api->reg_wr(impl_ctx, param); 
 | 
    } break; 
 | 
    case MPP_DEV_REG_RD : { 
 | 
        if (api->reg_rd) 
 | 
            ret = api->reg_rd(impl_ctx, param); 
 | 
    } break; 
 | 
    case MPP_DEV_REG_OFFSET : { 
 | 
        if (api->reg_offset) 
 | 
            ret = api->reg_offset(impl_ctx, param); 
 | 
    } break; 
 | 
    case MPP_DEV_REG_OFFS : { 
 | 
        if (api->reg_offs) 
 | 
            ret = api->reg_offs(impl_ctx, param); 
 | 
    } break; 
 | 
    case MPP_DEV_RCB_INFO : { 
 | 
        if (api->rcb_info) 
 | 
            ret = api->rcb_info(impl_ctx, param); 
 | 
    } break; 
 | 
    case MPP_DEV_SET_INFO : { 
 | 
        if (api->set_info) 
 | 
            ret = api->set_info(impl_ctx, param); 
 | 
    } break; 
 | 
    case MPP_DEV_CMD_SEND : { 
 | 
        if (api->cmd_send) 
 | 
            ret = api->cmd_send(impl_ctx); 
 | 
    } break; 
 | 
    case MPP_DEV_CMD_POLL : { 
 | 
        if (api->cmd_poll) 
 | 
            ret = api->cmd_poll(impl_ctx, param); 
 | 
    } break; 
 | 
    default : { 
 | 
        mpp_err_f("invalid cmd %d\n", cmd); 
 | 
    } break; 
 | 
    } 
 | 
  
 | 
    return ret; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_dev_set_reg_offset(MppDev dev, RK_S32 index, RK_U32 offset) 
 | 
{ 
 | 
    MppDevRegOffsetCfg trans_cfg; 
 | 
  
 | 
    trans_cfg.reg_idx = index; 
 | 
    trans_cfg.offset = offset; 
 | 
  
 | 
    return mpp_dev_ioctl(dev, MPP_DEV_REG_OFFSET, &trans_cfg); 
 | 
} 
 | 
  
 | 
/* register offset multi config */ 
 | 
MPP_RET mpp_dev_multi_offset_init(MppDevRegOffCfgs **cfgs, RK_S32 size) 
 | 
{ 
 | 
    RK_S32 cfg_size = sizeof(MppDevRegOffCfgs) + size * sizeof(MppDevRegOffsetCfg); 
 | 
    MppDevRegOffCfgs *p = NULL; 
 | 
  
 | 
    if (NULL == cfgs || size <= 0) { 
 | 
        mpp_err_f("invalid pointer %p size %d\n", cfgs, size); 
 | 
        return MPP_NOK; 
 | 
    } 
 | 
  
 | 
    p = mpp_calloc_size(MppDevRegOffCfgs, cfg_size); 
 | 
    if (p) 
 | 
        p->size = size; 
 | 
  
 | 
    *cfgs = p; 
 | 
  
 | 
    return (p) ? MPP_OK : MPP_NOK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_dev_multi_offset_deinit(MppDevRegOffCfgs *cfgs) 
 | 
{ 
 | 
    MPP_FREE(cfgs); 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_dev_multi_offset_reset(MppDevRegOffCfgs *cfgs) 
 | 
{ 
 | 
    if (cfgs) { 
 | 
        memset(cfgs->cfgs, 0, cfgs->count * sizeof(cfgs->cfgs[0])); 
 | 
        cfgs->count = 0; 
 | 
    } 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 | 
  
 | 
MPP_RET mpp_dev_multi_offset_update(MppDevRegOffCfgs *cfgs, RK_S32 index, RK_U32 offset) 
 | 
{ 
 | 
    MppDevRegOffsetCfg *cfg; 
 | 
    RK_S32 count; 
 | 
    RK_S32 i; 
 | 
  
 | 
    if (NULL == cfgs) 
 | 
        return MPP_NOK; 
 | 
  
 | 
    if (cfgs->count >= cfgs->size) { 
 | 
        mpp_err_f("invalid cfgs count %d : %d\n", cfgs->count, cfgs->size); 
 | 
        return MPP_NOK; 
 | 
    } 
 | 
  
 | 
    count = cfgs->count; 
 | 
    cfg = cfgs->cfgs; 
 | 
  
 | 
    for (i = 0; i < count; i++, cfg++) { 
 | 
  
 | 
        if (cfg->reg_idx == (RK_U32)index) { 
 | 
            cfg->offset = offset; 
 | 
            return MPP_OK; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    cfg->reg_idx = index; 
 | 
    cfg->offset = offset; 
 | 
    cfgs->count++; 
 | 
  
 | 
    return MPP_OK; 
 | 
} 
 |