Ais client LA8295 camx KMD enqueue dequeue

news2024/10/6 4:11:36

 Ais client 调用qcarcam_s_buffers 设置buffer 进行enqueue buf

PUBLIC_API qcarcam_ret_t qcarcam_s_buffers(qcarcam_hndl_t hndl, qcarcam_buffers_t* p_buffers)
{
    return camera_to_qcarcam_result(ais_s_buffers(hndl, p_buffers));
}
qcarcam_s_buffers(input_ctxt->qcarcam_context, &input_ctxt->p_buffers_output)

AisBufferManager::MapBuffers 进行buf map

CameraResult AisEngine::ais_s_buffers(qcarcam_hndl_t hndl, qcarcam_buffers_t* p_buffers)
{
    CameraResult rc = CAMERA_SUCCESS;
    AisUsrCtxt* pUsrCtxt;

    AIS_API_ENTER_HNDL(hndl);

    pUsrCtxt = GetUsrCtxt(hndl);
    if (pUsrCtxt)
    {
        pUsrCtxt->Lock();

        /*check we are in correct state*/
        if (!p_buffers)
        {
            AIS_LOG(ENGINE, ERROR, "p_buffers is NULL");
            rc = CAMERA_EMEMPTR;
        }
        else if (AIS_USR_STATE_OPENED != pUsrCtxt->m_state &&
            AIS_USR_STATE_RESERVED != pUsrCtxt->m_state)
        {
            AIS_LOG(ENGINE, ERROR, "Usrctxt %p in incorrect state %d",
                    pUsrCtxt, pUsrCtxt->m_state);
            rc = CAMERA_EBADSTATE;
        }
        else if (p_buffers->n_buffers < MIN_USR_NUMBER_OF_BUFFERS || p_buffers->n_buffers > pUsrCtxt->m_numBufMax)
        {
            AIS_LOG(ENGINE, ERROR, "Invalid number of buffers set [%d] for user %p. Need in range [%d->%d]",
                    p_buffers->n_buffers, pUsrCtxt, MIN_USR_NUMBER_OF_BUFFERS, pUsrCtxt->m_numBufMax);
            rc = CAMERA_EBADPARM;
        }
        else if ((pUsrCtxt->m_secureMode && !(p_buffers->flags & QCARCAM_BUFFER_FLAG_SECURE)) ||
                 (!pUsrCtxt->m_secureMode && (p_buffers->flags & QCARCAM_BUFFER_FLAG_SECURE)))
        {
            AIS_LOG(ENGINE, ERROR, "Invalid secure flag 0x%x set for usrCtxt secure mode %d",
                    p_buffers->flags, pUsrCtxt->m_secureMode);
            rc = CAMERA_EBADPARM;
        }
        else
        {
            AisBufferList* pBufferList;

            pBufferList = pUsrCtxt->m_bufferList[AIS_BUFLIST_OUTPUT_USR];
            if (pBufferList->m_nBuffers)
            {
                AIS_LOG(ENGINE, HIGH, "ais_s_buffers usrctxt %p unmap buffers", pUsrCtxt);
                rc = AisBufferManager::UnmapBuffers(pBufferList);
            }

            rc = AisBufferManager::MapBuffers(pBufferList, p_buffers);

        }

        pUsrCtxt->Unlock();

        PutUsrCtxt(pUsrCtxt);
    }
    else
    {
        AIS_LOG(ENGINE, ERROR, "Invalid hndl %p", hndl);
        rc = CAMERA_EBADHANDLE;
    }
    return rc;
}

AisBufferManager::MapBuffers 对 buffers[i].planes[0].p_buf 指针进行转换成fd

/**
 * MapBuffers
 *
 * @brief Map buffers to a buffer_list
 *
 * @param pBufferList - buffer list to hold mapping
 * @param pQcarcamBuffers - buffers to map
 *
 * @return CameraResult
 */
CameraResult AisBufferManager::MapBuffers(AisBufferList* pBufferList,
        qcarcam_buffers_t* pQcarcamBuffers)
{
    CameraHwBlockType hwBlock = CAMERA_HWBLOCK_IFE;
    CameraResult rc = CAMERA_SUCCESS;
    int i = 0;

    for (i = 0; i < (int)pQcarcamBuffers->n_buffers; i++)
    {
        AisBuffer* pBuffer = &pBufferList->m_pBuffers[i];

        pBuffer->idx = i;
        pBuffer->pMemHndl = pQcarcamBuffers->buffers[i].planes[0].p_buf;
        pBuffer->colorFmt = pQcarcamBuffers->color_fmt;

        pBuffer->flags = GetBufferFlags(pQcarcamBuffers->flags);

        if (pQcarcamBuffers->buffers[i].n_planes <= QCARCAM_MAX_NUM_PLANES)
        {
            pBuffer->size = 0;
            pBuffer->bufferInfo.n_planes = pQcarcamBuffers->buffers[i].n_planes;
            for (uint32 j = 0; j < pQcarcamBuffers->buffers[i].n_planes; ++j)
            {
                pBuffer->bufferInfo.planes[j].width = pQcarcamBuffers->buffers[i].planes[j].width;
                pBuffer->bufferInfo.planes[j].height = pQcarcamBuffers->buffers[i].planes[j].height;
                pBuffer->bufferInfo.planes[j].stride = pQcarcamBuffers->buffers[i].planes[j].stride;
                pBuffer->bufferInfo.planes[j].size = pQcarcamBuffers->buffers[i].planes[j].size;
                pBuffer->bufferInfo.planes[j].hndl = (unsigned long long)pQcarcamBuffers->buffers[i].planes[j].p_buf;
                pBuffer->bufferInfo.planes[j].offset = pBuffer->size;

                pBuffer->size += pQcarcamBuffers->buffers[i].planes[j].size;
            }
        }

        AIS_LOG(ENGINE, MED, "Mapping %d (%p %d)", i, pBuffer->pMemHndl, pBuffer->size);

        rc = CameraBufferMap(pBuffer, pBuffer->flags, 0x0, &hwBlock, 1);
        if (CAMERA_SUCCESS != rc)
        {
            AIS_LOG(ENGINE, ERROR, "Failed to map buffer idx %d (%p %d)", i, pBuffer->pMemHndl, pBuffer->size);

            /*cleanup by unmapping previously mapped buffers*/
            while (i > 0)
            {
                i--;
                CameraBufferUnmap(&pBufferList->m_pBuffers[i]);
            }
            std_memset(pBufferList->m_pBuffers, 0x0, sizeof(pBufferList->m_pBuffers));
            rc = CAMERA_EFAILED;
            break;
        }

        pBuffer->bufferInfo.n_planes = pQcarcamBuffers->buffers[i].n_planes;
        pBuffer->bufferInfo.n_planes = pQcarcamBuffers->buffers[i].n_planes;
        pBuffer->pDa = CameraBufferGetDeviceAddress(pBuffer, hwBlock);
        pBuffer->isInternal = FALSE;
        pBuffer->state = AIS_BUFFER_INITIALIZED;
    }

    if (CAMERA_SUCCESS == rc)
    {
        pBufferList->SetProperties(pQcarcamBuffers->n_buffers,
                pQcarcamBuffers->buffers[0].planes[0].width,
                pQcarcamBuffers->buffers[0].planes[0].height,
                pQcarcamBuffers->color_fmt);
        AIS_LOG(ENGINE, HIGH, "Successfully mapped %d buffers", pBufferList->m_nBuffers);
    }

    return rc;
}

使用ioctl 对将数据发送到kernel获取dma 映射后的pBuffer->pDa

 /**
1608  * This function maps a buffer into the camera SMMU context.
1609  *
1610  * @param[in] pBuffer    The buffer to be mapped
1611  * @param[in] flags      Bit mask of flags for allocation (cont, cached, secure, read/write, etc...)
1612  * @param[in] devAddr    Dev address if fixed mapping flag is set
1613  * @param[in] pHwBlocks  List of hw blocks to map to
1614  * @param[in] nHwBlocks  Number of hw blocks in pHwBlocks
1615  
1616  * @return CameraResult
1617  */
1618  CameraResult CameraBufferMap(AisBuffer* pBuffer,
1619          uint32 flags,
1620          uint64 devAddr,
1621          const CameraHwBlockType* pHwBlocks,
1622          uint32 nHwBlocks)
1623  {
1624      CameraResult result = CAMERA_SUCCESS;
1625  
1626      CAM_UNUSED(devAddr);
1627  
1628      if (!pBuffer || !pBuffer->pMemHndl)
1629      {
1630          CAM_MSG(ERROR, "null pMemHandle");
1631          return CAMERA_EBADPARM;
1632      }
1633      if (!pHwBlocks)
1634      {
1635          CAM_MSG(ERROR, "null pHwBlocks");
1636          return CAMERA_EFAILED;
1637      }
1638  
1639      struct cam_mem_mgr_map_cmd  mapCmd = {};
1640  
1641      CameraBufferPopulateMmuHandles(mapCmd.mmu_hdls, &mapCmd.num_hdl, flags, pHwBlocks, nHwBlocks);
1642  
1643      mapCmd.flags = CAM_MEM_FLAG_HW_READ_WRITE;
1644  
1645      if (flags & CAMERA_BUFFER_FLAG_SECURE)
1646      {
1647          mapCmd.flags |= CAM_MEM_FLAG_CP_PIXEL;
1648      }
1649  
1650      mapCmd.fd = (int)(uintptr_t)pBuffer->pMemHndl;
1651  
1652      CameraLockMutex(gPlatformCtxt.m_allocLock);
1653      result = gPlatformCtxt.m_pCamReqMgr->Ioctl2(CAM_REQ_MGR_MAP_BUF, &mapCmd, 0, sizeof(mapCmd));
1654      CameraUnlockMutex(gPlatformCtxt.m_allocLock);
1655  
1656      CAM_MSG_ON_ERR(result, "Failed to Map buffer %d 0x%x", mapCmd.fd, mapCmd.flags);
1657  
1658      if (CAMERA_SUCCESS == result)
1659      {
             //获取pDa的地址指向dev 的sg 物理地址
1660          pBuffer->pDa = mapCmd.out.buf_handle;
1661          //map VA if non-secure
1662          if (!(flags & CAMERA_BUFFER_FLAG_SECURE))
1663          {
1664              pBuffer->pVa = OSMemMap(mapCmd.fd, pBuffer->size, 0);
1665          }
1666      }
1667  
1668      return result;
1669  }


282  CameraResult CamReqManager::Ioctl2(uint32 opcode, void* pArg, uint32 hType, uint32 size)
283  {
284      CameraResult       result = CAMERA_SUCCESS;
285      struct cam_control ioctlCmd;
286      int returnCode;
287  
288      CAM_UNUSED(hType);
289 
290      CAM_MSG(MEDIUM, "Entering Ioctl %d", opcode);
291  
292      ioctlCmd.op_code         = opcode;
293      ioctlCmd.size            = size;
294      ioctlCmd.handle_type     = CAM_HANDLE_USER_POINTER;
295      ioctlCmd.reserved        = 0;
296      ioctlCmd.handle          = VoidPtrToUINT64(pArg);//mapcmd
297  
298      returnCode = ioctl(m_camReqMgrKmdFd, VIDIOC_CAM_CONTROL, &ioctlCmd);
299      if (0 != returnCode)
300      {
301          CAM_MSG(ERROR, "IFE: ioctl[%d] failed with return %d", opcode, returnCode);
302          result = CAMERA_EFAILED;
303      }
304      else
305      {
306          CAM_MSG(MEDIUM, "Return Ioctl %d success!", opcode);
307      }
308  
309      return result;
310  }

通过v4l2框架将ioctl 下发的数据转换成cam_req_mgr 调用vidioc_default处理


static long __video_do_ioctl(struct file *file,
                unsigned int cmd, void *arg)
{
        struct video_device *vfd = video_devdata(file);
        struct mutex *req_queue_lock = NULL;
        struct mutex *lock; /* ioctl serialization mutex */
        const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
        bool write_only = false;
        struct v4l2_ioctl_info default_info;
        const struct v4l2_ioctl_info *info;
        void *fh = file->private_data;
        struct v4l2_fh *vfh = NULL;
        int dev_debug = vfd->dev_debug;
        long ret = -ENOTTY;

        if (ops == NULL) {
                pr_warn("%s: has no ioctl_ops.\n",
                                video_device_node_name(vfd));
                return ret;
        }

        if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags))
                vfh = file->private_data;

        /*
         * We need to serialize streamon/off with queueing new requests.
         * These ioctls may trigger the cancellation of a streaming
         * operation, and that should not be mixed with queueing a new
         * request at the same time.
         */
        if (v4l2_device_supports_requests(vfd->v4l2_dev) &&
            (cmd == VIDIOC_STREAMON || cmd == VIDIOC_STREAMOFF)) {
                req_queue_lock = &vfd->v4l2_dev->mdev->req_queue_mutex;

                if (mutex_lock_interruptible(req_queue_lock))
                        return -ERESTARTSYS;
        }

        lock = v4l2_ioctl_get_lock(vfd, vfh, cmd, arg);

        if (lock && mutex_lock_interruptible(lock)) {
                if (req_queue_lock)
                        mutex_unlock(req_queue_lock);
                return -ERESTARTSYS;
        }

        if (!video_is_registered(vfd)) {
                ret = -ENODEV;
                goto unlock;
        }

        if (v4l2_is_known_ioctl(cmd)) {
                info = &v4l2_ioctls[_IOC_NR(cmd)];

                if (!test_bit(_IOC_NR(cmd), vfd->valid_ioctls) &&
                    !((info->flags & INFO_FL_CTRL) && vfh && vfh->ctrl_handler))
                        goto done;

                if (vfh && (info->flags & INFO_FL_PRIO)) {
                        ret = v4l2_prio_check(vfd->prio, vfh->prio);
                        if (ret)
                                goto done;
                }
        } else {
                default_info.ioctl = cmd;
                default_info.flags = 0;
                default_info.debug = v4l_print_default;
                info = &default_info;
        }

        write_only = _IOC_DIR(cmd) == _IOC_WRITE;
        if (info != &default_info) {
                ret = info->func(ops, file, fh, arg);
        } else if (!ops->vidioc_default) {
                ret = -ENOTTY;
        } else {
                ret = ops->vidioc_default(file, fh,
                        vfh ? v4l2_prio_check(vfd->prio, vfh->prio) >= 0 : 0,
                        cmd, arg);
        }

done:
        if (dev_debug & (V4L2_DEV_DEBUG_IOCTL | V4L2_DEV_DEBUG_IOCTL_ARG)) {
                if (!(dev_debug & V4L2_DEV_DEBUG_STREAMING) &&
                    (cmd == VIDIOC_QBUF || cmd == VIDIOC_DQBUF))
                        goto unlock;

                v4l_printk_ioctl(video_device_node_name(vfd), cmd);
                if (ret < 0)
                        pr_cont(": error %ld", ret);
                if (!(dev_debug & V4L2_DEV_DEBUG_IOCTL_ARG))
                        pr_cont("\n");
                else if (_IOC_DIR(cmd) == _IOC_NONE)
                        info->debug(arg, write_only);
                else {
                        pr_cont(": ");
                        info->debug(arg, write_only);
                }
        }

unlock:
        if (lock)
                mutex_unlock(lock);
        if (req_queue_lock)
                mutex_unlock(req_queue_lock);
        return ret;
}

将用户空间的ioctlCmd进行获取

         ioctlCmd.op_code         = opcode;
293      ioctlCmd.size            = size;
294      ioctlCmd.handle_type     = CAM_HANDLE_USER_POINTER;
295      ioctlCmd.reserved        = 0;
296      ioctlCmd.handle          = VoidPtrToUINT64(pArg);
 static long cam_private_ioctl(struct file *file, void *fh,
        bool valid_prio, unsigned int cmd, void *arg)
{
        int rc;
        struct cam_control *k_ioctl;

        if ((!arg) || (cmd != VIDIOC_CAM_CONTROL))
                return -EINVAL;

        k_ioctl = (struct cam_control *)arg;// ioctlCmd

        if (!k_ioctl->handle)
                return -EINVAL;

        switch (k_ioctl->op_code) {

        case CAM_REQ_MGR_MAP_BUF: {
                struct cam_mem_mgr_map_cmd cmd;

                if (k_ioctl->size != sizeof(cmd))
                        return -EINVAL;
                 //cmd=k_ioctl->handle=mapcmd
                if (copy_from_user(&cmd,
                        u64_to_user_ptr(k_ioctl->handle),
                        sizeof(struct cam_mem_mgr_map_cmd))) {
                        rc = -EFAULT;
                        break;
                }

                rc = cam_mem_mgr_map(&cmd);
                if (!rc)
                        if (copy_to_user(
                                u64_to_user_ptr(k_ioctl->handle),
                                &cmd, sizeof(struct cam_mem_mgr_map_cmd))) {
                                rc = -EFAULT;
                                break;
                        }
                }
                break;

Kernel 使用cam_mem_mgr_map通过buffers[i].planes[0].p_buf 获取一个file 结构转换成dma_buf,通过cam_mem_util_map_hw_va获取hw_addr

794  int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd)
795  {
796          int32_t idx;
797          int rc;
798          struct dma_buf *dmabuf;
799          dma_addr_t hw_vaddr = 0;
800          size_t len = 0;
801  
802          if (!atomic_read(&cam_mem_mgr_refcnt)) {
803                  CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
804                  return -EINVAL;
805          }
806  
807          if (!cmd || (cmd->fd < 0)) {
808                  CAM_ERR(CAM_MEM, "Invalid argument");
809                  return -EINVAL;
810          }
811  
812          if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) {
813                  CAM_ERR(CAM_MEM, "Num of mmu hdl %d exceeded maximum(%d)",
814                          cmd->num_hdl, CAM_MEM_MMU_MAX_HANDLE);
815                  return -EINVAL;
816          }
817  
818          rc = cam_mem_util_check_map_flags(cmd);
819          if (rc) {
820                  CAM_ERR(CAM_MEM, "Invalid flags: flags = %X", cmd->flags);
821                  return rc;
822          }
823          
824          dmabuf = dma_buf_get(cmd->fd);// file->private_data
825          if (IS_ERR_OR_NULL((void *)(dmabuf))) {
826                  CAM_ERR(CAM_MEM, "Failed to import dma_buf fd %d, rc %d",
827                          cmd->fd, (IS_ERR(dmabuf) ? PTR_ERR(dmabuf) : 0));
828                  return -EINVAL;
829          }
830  
831          if ((cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) ||
832                  (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)) {
                      //获取hw_vaddr
833                  rc = cam_mem_util_map_hw_va(cmd->flags,
834                          cmd->mmu_hdls,
835                          cmd->num_hdl,
836                          cmd->fd,
837                          dmabuf,
838                          &hw_vaddr,
839                          &len,
840                          CAM_SMMU_REGION_IO);
841                  if (rc) {
842                          CAM_ERR(CAM_MEM,
843                                  "Failed in map_hw_va, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d",
844                                  cmd->flags, cmd->fd, CAM_SMMU_REGION_IO,
845                                  cmd->num_hdl, rc);
846                          goto map_fail;
847                  }
848          }
849 
850          idx = cam_mem_get_slot();
851          if (idx < 0) {
852                  rc = -ENOMEM;
853                  goto map_fail;
854          }
855  
856          mutex_lock(&tbl.bufq[idx].q_lock);
857          tbl.bufq[idx].fd = cmd->fd;
858          tbl.bufq[idx].dma_buf = NULL;
859          tbl.bufq[idx].flags = cmd->flags;
860          tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, cmd->fd);
861          if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)
862                  CAM_MEM_MGR_SET_SECURE_HDL(tbl.bufq[idx].buf_handle, true);
863          tbl.bufq[idx].kmdvaddr = 0;
864  
865          if (cmd->num_hdl > 0)
                   //添加硬件sg 物理地址
866                  tbl.bufq[idx].vaddr = hw_vaddr;
867          else
868                  tbl.bufq[idx].vaddr = 0;
869  
870          tbl.bufq[idx].dma_buf = dmabuf;
871          tbl.bufq[idx].len = len;
872          tbl.bufq[idx].num_hdl = cmd->num_hdl;
873          memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls,
874                  sizeof(int32_t) * cmd->num_hdl);
875          tbl.bufq[idx].is_imported = true;
876          mutex_unlock(&tbl.bufq[idx].q_lock);
877  
878          cmd->out.buf_handle = tbl.bufq[idx].buf_handle;
879          cmd->out.vaddr = 0;
880  
881          CAM_DBG(CAM_MEM,
882                  "fd=%d, flags=0x%x, num_hdl=%d, idx=%d, buf handle=%x, len=%zu",
883                  cmd->fd, cmd->flags, cmd->num_hdl, idx, cmd->out.buf_handle,
884                  tbl.bufq[idx].len);
885  
886          return rc;
887  
888  map_fail:
889          dma_buf_put(dmabuf);
890          return rc;
891  }

hw_vaddr获取的设备的sg 的物理内存地址(应该是设备映射的dma地址)

|--cam_mem_util_map_hw_va

|-->cam_smmu_map_user_iova

|---->cam_smmu_map_buffer_and_add_to_list

|-------->cam_smmu_map_buffer_validate

 cam_smmu_map_user_iova(mmu_hdls[i],fd,dmabuf,dir,(dma_addr_t *)hw_vaddr,len,region);


2658  int cam_smmu_map_user_iova(int handle, int ion_fd, struct dma_buf *dmabuf,
2659          enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr,
2660          size_t *len_ptr, enum cam_smmu_region_id region_id)
2661  {
2662          int idx, rc = 0;
2663          enum cam_smmu_buf_state buf_state;
2664          enum dma_data_direction dma_dir;
2665  
2666          rc = cam_smmu_map_iova_validate_params(handle, dir, paddr_ptr,
2667                  len_ptr, region_id);
2668          if (rc) {
2669                  CAM_ERR(CAM_SMMU, "initial checks failed, unable to proceed");
2670                  return rc;
2671          }
2672  
2673          dma_dir = (enum dma_data_direction)dir;
2674          idx = GET_SMMU_TABLE_IDX(handle);
2675          mutex_lock(&iommu_cb_set.cb_info[idx].lock);
2676          if (iommu_cb_set.cb_info[idx].is_secure) {
2677                  CAM_ERR(CAM_SMMU,
2678                          "Error: can't map non-secure mem to secure cb idx=%d",
2679                          idx);
2680                  rc = -EINVAL;
2681                  goto get_addr_end;
2682          }
2683  
2684          if (iommu_cb_set.cb_info[idx].handle != handle) {
2685                  CAM_ERR(CAM_SMMU,
2686                          "hdl is not valid, idx=%d, table_hdl = %x, hdl = %x",
2687                          idx, iommu_cb_set.cb_info[idx].handle, handle);
2688                  rc = -EINVAL;
2689                  goto get_addr_end;
2690          }
2691  
2692          if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
2693                  CAM_ERR(CAM_SMMU,
2694                          "Err:Dev %s should call SMMU attach before map buffer",
2695                          iommu_cb_set.cb_info[idx].name);
2696                  rc = -EINVAL;
2697                  goto get_addr_end;
2698          }
2699  
2700          buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr);
2701          if (buf_state == CAM_SMMU_BUFF_EXIST) {
2702                  CAM_ERR(CAM_SMMU,
2703                          "fd:%d already in list idx:%d, handle=%d, give same addr back",
2704                          ion_fd, idx, handle);
2705                  rc = -EALREADY;
2706                  goto get_addr_end;
2707          }
2708  
2709          rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, dma_dir,
2710                          paddr_ptr, len_ptr, region_id, dmabuf);
2711          if (rc < 0)
2712                  CAM_ERR(CAM_SMMU,
2713                          "mapping or add list fail, idx=%d, fd=%d, region=%d, rc=%d",
2714                          idx, ion_fd, region_id, rc);
2715  
2716  get_addr_end:
2717          mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
2718          return rc;
2719  }
2720  EXPORT_SYMBOL(cam_smmu_map_user_iova);
static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
1826           enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
1827           size_t *len_ptr, enum cam_smmu_region_id region_id, struct dma_buf *buf)
1828  {
1829          int rc = -1;
1830          struct cam_dma_buff_info *mapping_info = NULL;
1831  
1832          rc = cam_smmu_map_buffer_validate(buf, idx, dma_dir, paddr_ptr, len_ptr,
1833                  region_id, &mapping_info);
1834  
1835          if (rc) {
1836                  CAM_ERR(CAM_SMMU, "buffer validation failure");
1837                  return rc;
1838          }
1839  
1840          mapping_info->ion_fd = ion_fd;
1841          /* add to the list */
1842          list_add(&mapping_info->list,
1843                  &iommu_cb_set.cb_info[idx].smmu_buf_list);
1844  
1845          return 0;
1846  }

获取dma-buf,通过dma-buf 获取对应设备的sg物理地址

初始化mapping_info的值,将mapping_info 添加到smmu_buf_list

1665  static int cam_smmu_map_buffer_validate(struct dma_buf *buf,
1666          int idx, enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
1667          size_t *len_ptr, enum cam_smmu_region_id region_id,
1668          struct cam_dma_buff_info **mapping_info)
1669  {
1670          struct dma_buf_attachment *attach = NULL;
1671          struct sg_table *table = NULL;
1672          struct iommu_domain *domain;
1673          size_t size = 0;
1674          uint32_t iova = 0;
1675          int rc = 0;
1676  
1677          if (IS_ERR_OR_NULL(buf)) {
1678                  rc = PTR_ERR(buf);
1679                  CAM_ERR(CAM_SMMU,
1680                          "Error: dma get buf failed. rc = %d", rc);
1681                  goto err_out;
1682          }
1683  
1684          if (!mapping_info) {
1685                  rc = -EINVAL;
1686                  CAM_ERR(CAM_SMMU, "Error: mapping_info is invalid");
1687                  goto err_out;
1688          }
1689         //将file->private_dat = buf 与dev 进行关联
1690          attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev);
1691          if (IS_ERR_OR_NULL(attach)) {
1692                  rc = PTR_ERR(attach);
1693                  CAM_ERR(CAM_SMMU, "Error: dma buf attach failed");
1694                  goto err_out;
1695          }
1696  
1697          if (region_id == CAM_SMMU_REGION_SHARED) {
1698                  table = dma_buf_map_attachment(attach, dma_dir);
1699                  if (IS_ERR_OR_NULL(table)) {
1700                          rc = PTR_ERR(table);
1701                          CAM_ERR(CAM_SMMU, "Error: dma map attachment failed");
1702                          goto err_detach;
1703                  }
1704  
1705                  domain = iommu_cb_set.cb_info[idx].domain;
1706                  if (!domain) {
1707                          CAM_ERR(CAM_SMMU, "CB has no domain set");
1708                          goto err_unmap_sg;
1709                  }
1710                  //从SMMU的内存池分配IOVA的内存
1711                  rc = cam_smmu_alloc_iova(*len_ptr,
1712                          iommu_cb_set.cb_info[idx].handle,
1713                          &iova);
1714  
1715                  if (rc < 0) {
1716                          CAM_ERR(CAM_SMMU,
1717                                  "IOVA alloc failed for shared memory, size=%zu, idx=%d, handle=%d",
1718                                  *len_ptr, idx,
1719                                  iommu_cb_set.cb_info[idx].handle);
1720                          goto err_unmap_sg;
1721                  }
1722                   //进行dma map 获取sg_table
1723                  size = iommu_map_sg(domain, iova, table->sgl, table->nents,
1724                                  IOMMU_READ | IOMMU_WRITE);
1725  
1726                  if (size < 0) {
1727                          CAM_ERR(CAM_SMMU, "IOMMU mapping failed");
1728                          rc = cam_smmu_free_iova(iova,
1729                                  size, iommu_cb_set.cb_info[idx].handle);
1730                          if (rc)
1731                                  CAM_ERR(CAM_SMMU, "IOVA free failed");
1732                          rc = -ENOMEM;
1733                          goto err_unmap_sg;
1734                  } else {
1735                          CAM_DBG(CAM_SMMU,
1736                                  "iommu_map_sg returned iova=%pK, size=%zu",
1737                                  iova, size);
1738                          *paddr_ptr = iova;
1739                          *len_ptr = size;
1740                  }
               //cam_mem_mgr_map 设置的CAM_SMMU_REGION_IO
1741          } else if (region_id == CAM_SMMU_REGION_IO) {
1742                  attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP;
1743  
1744                  table = dma_buf_map_attachment(attach, dma_dir);
1745                  if (IS_ERR_OR_NULL(table)) {
1746                          rc = PTR_ERR(table);
1747                          CAM_ERR(CAM_SMMU, "Error: dma map attachment failed");
1748                          goto err_detach;
1749                  }
1750                   //获取设备scatterlist的物理地址
1751                  *paddr_ptr = sg_dma_address(table->sgl);
1752                  *len_ptr = (size_t)buf->size;
1753          } else {
1754                  CAM_ERR(CAM_SMMU, "Error: Wrong region id passed");
1755                  rc = -EINVAL;
1756                  goto err_unmap_sg;
1757          }
1758  
1759          CAM_DBG(CAM_SMMU, "iova=%pK, region_id=%d, paddr=%pK, len=%d",
1760                  iova, region_id, *paddr_ptr, *len_ptr);
1761  
1762          if (table->sgl) {
1763                  CAM_DBG(CAM_SMMU,
1764                          "DMA buf: %pK, device: %pK, attach: %pK, table: %pK",
1765                          (void *)buf,
1766                          (void *)iommu_cb_set.cb_info[idx].dev,
1767                          (void *)attach, (void *)table);
1768                  CAM_DBG(CAM_SMMU, "table sgl: %pK, rc: %d, dma_address: 0x%x",
1769                          (void *)table->sgl, rc,
1770                          (unsigned int)table->sgl->dma_address);
1771          } else {
1772                  rc = -EINVAL;
1773                  CAM_ERR(CAM_SMMU, "Error: table sgl is null");
1774                  goto err_unmap_sg;
1775          }
1776  
1777          /* fill up mapping_info */
1778          *mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL);
1779          if (!(*mapping_info)) {
1780                  rc = -ENOSPC;
1781                  goto err_alloc;
1782          }
1783  
1784          (*mapping_info)->buf = buf;
1785          (*mapping_info)->attach = attach;
1786          (*mapping_info)->table = table;
1787          (*mapping_info)->paddr = *paddr_ptr;
1788          (*mapping_info)->len = *len_ptr;
1789          (*mapping_info)->dir = dma_dir;
1790          (*mapping_info)->ref_count = 1;
1791          (*mapping_info)->region_id = region_id;
1792  
1793          if (!*paddr_ptr || !*len_ptr) {
1794                  CAM_ERR(CAM_SMMU, "Error: Space Allocation failed");
1795                  kfree(*mapping_info);
1796                  *mapping_info = NULL;
1797                  rc = -ENOSPC;
1798                  goto err_alloc;
1799          }
1800          CAM_DBG(CAM_SMMU, "idx=%d, dma_buf=%pK, dev=%pK, paddr=%pK, len=%u",
1801                  idx, buf, (void *)iommu_cb_set.cb_info[idx].dev,
1802                  (void *)*paddr_ptr, (unsigned int)*len_ptr);
1803  
1804          return 0;
1805  
1806  err_alloc:
1807          if (region_id == CAM_SMMU_REGION_SHARED) {
1808                  cam_smmu_free_iova(iova,
1809                          size,
1810                          iommu_cb_set.cb_info[idx].handle);
1811  
1812                  iommu_unmap(iommu_cb_set.cb_info[idx].domain,
1813                          *paddr_ptr,
1814                          *len_ptr);
1815          }
1816  err_unmap_sg:
1817          dma_buf_unmap_attachment(attach, table, dma_dir);
1818  err_detach:
1819          dma_buf_detach(buf, attach);
1820  err_out:
1821          return rc;
1822  }

Map之后iova与物理地址关系

Ais_server cam_mem_mgr_alloc_and_map从SMMU的内存池分配IOVA的内存


1034  static int cam_smmu_alloc_iova(size_t size,
1035          int32_t smmu_hdl, uint32_t *iova)
1036  {
1037          int rc = 0;
1038          int idx;
1039          uint32_t vaddr = 0;
1040  
1041          if (!iova || !size || (smmu_hdl == HANDLE_INIT)) {
1042                  CAM_ERR(CAM_SMMU, "Error: Input args are invalid");
1043                  return -EINVAL;
1044          }
1045  
1046          CAM_DBG(CAM_SMMU, "Allocating iova size = %zu for smmu hdl=%X",
1047                  size, smmu_hdl);
1048         // 获取dev的smmu内存的index
1049          idx = GET_SMMU_TABLE_IDX(smmu_hdl); 
1050          if (idx < 0 || idx >= iommu_cb_set.cb_num) {
1051                  CAM_ERR(CAM_SMMU,
1052                          "Error: handle or index invalid. idx = %d hdl = %x",
1053                          idx, smmu_hdl);
1054                  return -EINVAL;
1055          }
1056  
1057          if (iommu_cb_set.cb_info[idx].handle != smmu_hdl) {
1058                  CAM_ERR(CAM_SMMU,
1059                          "Error: hdl is not valid, table_hdl = %x, hdl = %x",
1060                          iommu_cb_set.cb_info[idx].handle, smmu_hdl);
1061                  rc = -EINVAL;
1062                  goto get_addr_end;
1063          }
1064  
1065          if (!iommu_cb_set.cb_info[idx].shared_support) {
1066                  CAM_ERR(CAM_SMMU,
1067                          "Error: Shared memory not supported for hdl = %X",
1068                          smmu_hdl);
1069                  rc = -EINVAL;
1070                  goto get_addr_end;
1071          }
1072         //内核的genalloc是给一些需要自己维护内存分配的内核模块使用的
            //使用预留给camera的内存池分配内存
1073          vaddr = gen_pool_alloc(iommu_cb_set.cb_info[idx].shared_mem_pool, size);
1074          if (!vaddr)
1075                  return -ENOMEM;
1076  
1077          *iova = vaddr;
1078  
1079  get_addr_end:
1080          return rc;
1081  }

iommu_map_sg 将内存池中的地址进行dma映射

iommu_map_sg-> arm_smmu_map_sg

 4261  static struct msm_iommu_ops arm_smmu_ops = {
4262          .map_sg                        = arm_smmu_map_sg,
4263          .iova_to_phys_hard        = arm_smmu_iova_to_phys_hard,
4264          .is_iova_coherent        = arm_smmu_is_iova_coherent,
4265          .tlbi_domain                = arm_smmu_tlbi_domain,
4266          .iova_to_pte                = arm_smmu_iova_to_pte,
4267          .iommu_ops = {
4268  
4269                  .capable                = arm_smmu_capable,
4270                  .domain_alloc                = arm_smmu_domain_alloc,
4271                  .domain_free                = arm_smmu_domain_free,
4272                  .attach_dev                = arm_smmu_attach_dev,
4273                  .detach_dev                = arm_smmu_detach_dev,
4274                  .map                        = arm_smmu_map,
4275                  .unmap                        = arm_smmu_unmap,
4276                  .flush_iotlb_all        = arm_smmu_flush_iotlb_all,
4277                  .iotlb_sync                = arm_smmu_iotlb_sync,
4278                  .iova_to_phys                = arm_smmu_iova_to_phys,
4279                  .add_device                = arm_smmu_add_device,
4280                  .remove_device                = arm_smmu_remove_device,
4281                  .device_group                = arm_smmu_device_group,
4282                  .domain_get_attr        = arm_smmu_domain_get_attr,
4283                  .domain_set_attr        = arm_smmu_domain_set_attr,
4284                  .of_xlate                = arm_smmu_of_xlate,
4285                  .get_resv_regions        = arm_smmu_get_resv_regions,
4286                  .put_resv_regions        = arm_smmu_put_resv_regions,
4287                  /* Restricted during device attach */
4288                  .pgsize_bitmap                = -1UL,
4289          }
4290  };
2049  size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
2050                      struct scatterlist *sg, unsigned int nents, int prot)
2051  {
2052          size_t mapped = 0;
2053          struct msm_iommu_ops *ops = to_msm_iommu_ops(domain->ops);
2054  
2055          if (ops->map_sg)
2056                  mapped = ops->map_sg(domain, iova, sg, nents, prot);
2057          trace_map_sg(to_msm_iommu_domain(domain), iova, mapped, prot);
2058          return mapped;
2059  }
2060  EXPORT_SYMBOL_GPL(iommu_map_sg);

arm_smmu_map_sg

static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova,
3365                             struct scatterlist *sg, unsigned int nents, int prot)
3366  {
3367          int ret;
3368          size_t size, batch_size, size_to_unmap = 0;
3369          unsigned long flags;
3370          struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
3371          struct io_pgtable_ops *ops;
3372          struct msm_io_pgtable_info *pgtbl_info = &smmu_domain->pgtbl_info[0];
3373          unsigned int idx_start, idx_end;
3374          struct scatterlist *sg_start, *sg_end;
3375          unsigned long __saved_iova_start;
3376          LIST_HEAD(nonsecure_pool);
3377  
3378          if (!pgtbl_info->map_sg)
3379                  return 0;
3380  
3381          ops = arm_smmu_get_pgtable_ops(smmu_domain, iova);
3382          if (IS_ERR_OR_NULL(ops))
3383                  return 0;
3384          iova = arm_smmu_mask_iova(smmu_domain, iova);
3385  
3386          if (!IS_ENABLED(CONFIG_ARM_SMMU_SKIP_MAP_POWER_ON)) {
3387                  ret = arm_smmu_domain_power_on(domain, smmu_domain->smmu);
3388                  if (ret)
3389                          return ret;
3390          }
3391  
3392          arm_smmu_secure_domain_lock(smmu_domain);
3393  
3394          __saved_iova_start = iova;
3395          idx_start = idx_end = 0;
3396          sg_start = sg_end = sg;
3397          while (idx_end < nents) {
3398                  batch_size = sg_end->length;
3399                  sg_end = sg_next(sg_end);
3400                  idx_end++;
3401                  while ((idx_end < nents) &&
3402                         (batch_size + sg_end->length < MAX_MAP_SG_BATCH_SIZE)) {
3403  
3404                          batch_size += sg_end->length;
3405                          sg_end = sg_next(sg_end);
3406                          idx_end++;
3407                  }
3408  
3409                  spin_lock_irqsave(&smmu_domain->cb_lock, flags);
3410                  ret = pgtbl_info->map_sg(ops, iova, sg_start,
3411                                           idx_end - idx_start, prot, &size);
3412                  arm_smmu_deferred_flush(smmu_domain);
3413                  spin_unlock_irqrestore(&smmu_domain->cb_lock, flags);
3414  
3415                  if (ret == -ENOMEM) {
3416                          /* unmap any partially mapped iova */
3417                          if (size) {
3418                                  arm_smmu_secure_domain_unlock(smmu_domain);
3419                                  arm_smmu_unmap(domain, iova, size, NULL);
3420                                  arm_smmu_secure_domain_lock(smmu_domain);
3421                          }
3422                          arm_smmu_prealloc_memory(smmu_domain,
3423                                                   batch_size, &nonsecure_pool);
3424                          spin_lock_irqsave(&smmu_domain->cb_lock, flags);
3425                          list_splice_init(&nonsecure_pool,
3426                                           &smmu_domain->nonsecure_pool);
3427                          ret = pgtbl_info->map_sg(ops, iova, sg_start,
3428                                                   idx_end - idx_start, prot,
3429                                                   &size);
3430                          list_splice_init(&smmu_domain->nonsecure_pool,
3431                                           &nonsecure_pool);
3432                          arm_smmu_deferred_flush(smmu_domain);
3433                          spin_unlock_irqrestore(&smmu_domain->cb_lock, flags);
3434                          arm_smmu_release_prealloc_memory(smmu_domain,
3435                                                           &nonsecure_pool);
3436                  }
3437  
3438                  /* Returns -ve val on error */
3439                  if (ret < 0) {
3440                          size_to_unmap = iova + size - __saved_iova_start;
3441                          goto out;
3442                  }
3443  
3444                  iova += batch_size;
3445                  idx_start = idx_end;
3446                  sg_start = sg_end;
3447                  size = 0;
3448          }
3449  
3450  out:
3451          if (!IS_ENABLED(CONFIG_ARM_SMMU_SKIP_MAP_POWER_ON))
3452                  arm_smmu_domain_power_off(domain, smmu_domain->smmu);
3453  
3454          arm_smmu_assign_table(smmu_domain);
3455          arm_smmu_secure_domain_unlock(smmu_domain);
3456  
3457          if (size_to_unmap) {
3458                  arm_smmu_unmap(domain, __saved_iova_start, size_to_unmap, NULL);
3459                  iova = __saved_iova_start;
3460          }
3461          return iova - __saved_iova_start;
3462  }

qcarcam_input_start enqueue buf获取数据通知,client 进行数据获取

static qcarcam_ret_t qcarcam_input_start(qcarcam_test_input_t *input_ctxt)
{
    qcarcam_ret_t ret = QCARCAM_RET_OK;

    qcarcam_test_get_time(&input_ctxt->t_start);

    ret = qcarcam_start(input_ctxt->qcarcam_context);
    if (ret == QCARCAM_RET_OK)
    {
        input_ctxt->state = QCARCAMTEST_STATE_START;
        input_ctxt->frameCnt = 0;
        input_ctxt->releaseframeCnt = 0;
        input_ctxt->prev_frameCnt = 0;
        input_ctxt->prev_releaseframeCnt = 0;
        input_ctxt->signal_lost = 0;

        qcarcam_test_get_time(&input_ctxt->t_start_success);

        QCARCAM_INFOMSG("Client %d Input %d qcarcam_start successfully", input_ctxt->idx, input_ctxt->qcarcam_input_id);
    }
    else
    {
        input_ctxt->state = QCARCAMTEST_STATE_ERROR;
        QCARCAM_ERRORMSG("Client %d Input %d qcarcam_start failed: %d", input_ctxt->idx, input_ctxt->qcarcam_input_id, ret);
    }

    return ret;
}

/**
 * AisIFEConfigurer::QueueStreamBuffer
 *
 * @param AisUsrCtxt
 * @param pStream
 * @param pBuffer
 *
 * @return CameraResult
 */
CameraResult AisIFEConfigurer::QueueStreamBuffer(AisUsrCtxt* pUsrCtxt, uint32 streamIdx, AisBuffer* pBuffer)
{
    CameraResult rc = CAMERA_SUCCESS;
    AisUsrCtxtStreamType* pStream = &pUsrCtxt->m_streams[streamIdx];
    AisIfeStreamType* pIfePath = &pStream->resources.ifeStream;
    IFECoreCtxtType* pIfeCtxt = GetIfeCtxt(pIfePath->ifeCore);

    if (!pIfeCtxt)
    {
        AIS_LOG(ENGINE, ERROR, "Failed to access invalid IFE:%d resource", pIfePath->ifeCore);
        return CAMERA_EFAILED;
    }
    IfeCmdEnqOutputBuffer sBufferEnqCmd = {};
    pIfePath = &pStream->resources.ifeStream;
    sBufferEnqCmd.outputPath = pIfePath->ifeOutput;
    sBufferEnqCmd.pBuffer = pBuffer;

    if (QCARCAM_OPMODE_RDI_CONVERSION == pUsrCtxt->m_opMode)
    {
        //changes buffer offset for multiple planes on 1 buffer
        sBufferEnqCmd.bufferOffset = pBuffer->bufferInfo.planes[streamIdx].offset;
    }

    #ifndef AIS_PAIRED_INPUT_GPU_SYNC
        // In the case of paired input use case where user context
        // has 2 streams and stream #1 should populate offset field by width of 1st stream.
        // This will tell IFE driver to configure proper address to HW.
        if ((QCARCAM_OPMODE_PAIRED_INPUT == pUsrCtxt->m_opMode) && (1 == streamIdx))
        {
            uint32 bytesPerLine = GetBytesPerLine(pUsrCtxt->m_streams[0].inputCfg.inputModeInfo.width,
                    pBuffer->colorFmt);
            if (bytesPerLine)
            {
                // In the case of paired input user buffer is divided into halves
                // so the offset is configured to be half of bytes per line.
                sBufferEnqCmd.bufferOffset = bytesPerLine;
            }
            else
            {
                AIS_LOG(ENGINE, ERROR,
                    "Usrctxt %p : failed to get bytesPerLine %d for width %d format %",
                    pUsrCtxt, pBuffer->bufferInfo.planes[0].width, pBuffer->colorFmt);
                return CAMERA_EFAILED;
            }
        }
    #endif
    rc = CameraDeviceControl(pIfeCtxt->hIfeHandle, IFE_CMD_ID_OUTPUT_BUFFER_ENQUEUE,
             &sBufferEnqCmd, sizeof(sBufferEnqCmd), NULL, 0, NULL);

    if (rc == CAMERA_SUCCESS)
    {
        pBuffer->state = AIS_IFE_OUTPUT_QUEUE;
    }
    AIS_LOG_ON_ERR(ENGINE, rc, "IFE_CMD_ID_OUTPUT_BUFFER_ENQUEUE failed ife%d rc %d", pIfePath->ifeCore, rc);

    return rc;
}

CameraResult CameraDeviceControl (
    CameraDeviceHandle hDevice,
    uint32 uidControl,
    const void *pIn,
    int nInLen,
    void *pOut,
    int nOutLen,
    int* pnOutLenReq)
{
    CameraResult result = CAMERA_EBADHANDLE;

    CameraDeviceHandleType* pDeviceHandle =
        (CameraDeviceHandleType*)hDevice;
    if (pDeviceHandle != NULL)
    {
        result = pDeviceHandle->Control(
            uidControl,
            pIn, nInLen,
            pOut, nOutLen, pnOutLenReq);
    }

    return result;
}
CameraResult IFEDevice::Control(uint32 uidControl,
        const void* pIn, int nInLen,
        void* pOut, int nOutLen, int* pnOutLenReq)

 case IFE_CMD_ID_OUTPUT_BUFFER_ENQUEUE:
        {
            IfeBufferEnqueueType bufEnqCmd = {};

            if (nInLen != sizeof(IfeCmdEnqOutputBuffer))
            {
                return CAMERA_EBADPARM;
            }
            IfeCmdEnqOutputBuffer* pBuf = (IfeCmdEnqOutputBuffer*)pIn;

            bufEnqCmd.outputPath = pBuf->outputPath;
            bufEnqCmd.buffer.idx = pBuf->pBuffer->idx;
            bufEnqCmd.buffer.mem_handle = (int32_t)pBuf->pBuffer->pDa;
            bufEnqCmd.buffer.offset = pBuf->bufferOffset;

            result = SendIoctl("bufEnq", AIS_IFE_BUFFER_ENQ, sizeof(bufEnqCmd), &bufEnqCmd);

CameraResult IFEDevice::SendIoctl(const char* name, uint32 opCode, uint32 size, void* handle)
{
    int rc = 0;

    struct cam_control ioctlCmd;
    ioctlCmd.op_code     = opCode;
    ioctlCmd.size        = size;
    ioctlCmd.handle_type = AIS_IFE_CMD_TYPE;
    ioctlCmd.reserved    = 0;
    ioctlCmd.handle      = (uint64)(handle);

    rc = ioctl(m_ifeKmdFd, VIDIOC_CAM_CONTROL, &ioctlCmd);
    if (rc < 0) {
        AIS_LOG(IFE_DRV, ERROR, "%s failed with rc %d", name, rc);
    }

    return rc ? CAMERA_EFAILED : CAMERA_SUCCESS;
}

kernel  KMD对UMD 发来的Ioctl 事件进行处理

CRM ioctl

case AIS_IFE_BUFFER_ENQ: {
                struct ais_ife_enqueue_buffer_args enq_buf;

                if (cmd->size != sizeof(enq_buf)) {
                        CAM_ERR(CAM_ISP, "Invalid cmd size");
                        rc = -EINVAL;
                } else if (copy_from_user(&enq_buf,//bufEnqCmd
                                u64_to_user_ptr(cmd->handle),
                                cmd->size)) {
                        rc = -EFAULT;
                } else {
                        rc = vfe_drv->hw_ops.process_cmd(vfe_drv->hw_priv,
                                        AIS_VFE_CMD_ENQ_BUFFER, &enq_buf,
                                        cmd->size);
                }
        }

对buf 进行enqueue 

rc = vfe_drv->hw_ops.process_cmd(vfe_drv->hw_priv,
                                        AIS_VFE_CMD_ENQ_BUFFER, &enq_buf,
                                        cmd->size);

                                     
int ais_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
        void *cmd_args, uint32_t arg_size)
{
        struct cam_hw_info                *vfe_hw = hw_priv;
        struct cam_hw_soc_info            *soc_info = NULL;
        struct ais_vfe_hw_core_info       *core_info = NULL;
        struct ais_vfe_hw_info            *hw_info = NULL;
        int rc = 0;

        if (!hw_priv) {
                CAM_ERR(CAM_ISP, "Invalid arguments");
                return -EINVAL;
        }

        soc_info = &vfe_hw->soc_info;
        core_info = (struct ais_vfe_hw_core_info *)vfe_hw->core_info;
        hw_info = core_info->vfe_hw_info;

        mutex_lock(&vfe_hw->hw_mutex);

        switch (cmd_type) {
        case AIS_VFE_CMD_ENQ_BUFFER: {
                struct ais_ife_enqueue_buffer_args *enq_buf =
                        (struct ais_ife_enqueue_buffer_args *)cmd_args;
                if (arg_size != sizeof(*enq_buf))
                        rc = -EINVAL;
                else
                        rc = ais_vfe_cmd_enq_buf(core_info, enq_buf);
                break;
        }
        default:
                CAM_ERR(CAM_ISP, "Invalid cmd type:%d", cmd_type);
                rc = -EINVAL;
                break;
        }

        mutex_unlock(&vfe_hw->hw_mutex);

        return rc;
}

将freebuf 获取进行enqueue

static int ais_vfe_cmd_enq_buf(struct ais_vfe_hw_core_info *core_info,
                struct ais_ife_enqueue_buffer_args *enq_buf)
{
        int rc;
        struct ais_vfe_buffer_t *vfe_buf[4] = {};
        struct ais_vfe_rdi_output *rdi_path = NULL;
        int32_t mmu_hdl;
        size_t  src_buf_size;
        uint32_t i = 0;
        uint32_t batch_id = 0;
        uint64_t base_addr = 0;

        if (enq_buf->path >= AIS_IFE_PATH_MAX) {
                CAM_ERR(CAM_ISP, "Invalid output path %d", enq_buf->path);
                rc = -EINVAL;
                goto EXIT;
        }

        rdi_path = &core_info->rdi_out[enq_buf->path];
        if (rdi_path->state < AIS_ISP_RESOURCE_STATE_RESERVED) {
                CAM_ERR(CAM_ISP, "RDI%d invalid state %d", enq_buf->path,
                                rdi_path->state);
                rc = -EINVAL;
                goto EXIT;
        }

        spin_lock(&rdi_path->buffer_lock);
        for (batch_id = 0; batch_id < rdi_path->batchConfig.numBatchFrames; batch_id++) {
                if (!list_empty(&rdi_path->free_buffer_list)) {
                      //获取freebuf
                        vfe_buf[batch_id] = list_first_entry(&rdi_path->free_buffer_list,
                                struct ais_vfe_buffer_t, list);
                        list_del_init(&vfe_buf[batch_id]->list);
                }
                if (!vfe_buf[batch_id]) {
                        CAM_ERR(CAM_ISP, "RDI%d No more free buffers!", enq_buf->path);
                        for (i = 0; i < batch_id; i++)
                                list_add_tail(&vfe_buf[i]->list, &rdi_path->free_buffer_list);
                        spin_unlock(&rdi_path->buffer_lock);
                        return -ENOMEM;
                }
        }
        spin_unlock(&rdi_path->buffer_lock);

          //buffer.mem_handle = pBuffer->pDa IFE 的sg 的物理地址
        vfe_buf[0]->mem_handle = enq_buf->buffer.mem_handle;

        mmu_hdl = core_info->iommu_hdl;

        if (cam_mem_is_secure_buf(vfe_buf[0]->mem_handle) || rdi_path->secure_mode)
                mmu_hdl = core_info->iommu_hdl_secure;

        rc = cam_mem_get_io_buf(vfe_buf[0]->mem_handle,
                mmu_hdl, &vfe_buf[0]->iova_addr, &src_buf_size);
        if (rc < 0) {
                CAM_ERR(CAM_ISP,
                        "get src buf address fail mem_handle 0x%x",
                        vfe_buf[0]->mem_handle);
        }
        if (vfe_buf[0]->iova_addr >> 32) {
                CAM_ERR(CAM_ISP, "Invalid mapped address");
                rc = -EINVAL;
        }

        if (enq_buf->buffer.offset >= src_buf_size) {
                CAM_ERR(CAM_ISP, "Invalid buffer offset");
                rc = -EINVAL;
        }

        //if any error, return buffer list object to being free
        if (rc) {
                spin_lock(&rdi_path->buffer_lock);
                for (batch_id = 0; batch_id < rdi_path->batchConfig.numBatchFrames; batch_id++)
                        list_add_tail(&vfe_buf[batch_id]->list, &rdi_path->free_buffer_list);
                spin_unlock(&rdi_path->buffer_lock);
        } else {
               
                base_addr  = vfe_buf[0]->iova_addr + enq_buf->buffer.offset;
                spin_lock(&rdi_path->buffer_lock);
                for (batch_id = 0; batch_id < rdi_path->batchConfig.numBatchFrames; batch_id++) {
                        vfe_buf[batch_id]->bufIdx = enq_buf->buffer.idx;

                        vfe_buf[batch_id]->iova_addr = base_addr +
                                batch_id * rdi_path->batchConfig.frameIncrement;

                        vfe_buf[batch_id]->batchId = batch_id;

                        trace_ais_isp_vfe_enq_req(core_info->vfe_idx, enq_buf->path,
                                        enq_buf->buffer.idx);
                        //将获取的vfe_buf 信息添加到 rdi_path->buffer_q
                        list_add_tail(&vfe_buf[batch_id]->list, &rdi_path->buffer_q);
                        }
                        spin_unlock(&rdi_path->buffer_lock);

                        if (rdi_path->state < AIS_ISP_RESOURCE_STATE_STREAMING)
                                ais_vfe_q_bufs_to_hw(core_info, enq_buf->path);
        }

EXIT:
        return rc;
}

获取ais server alloc_and_map分配的内存地址

int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle,
        uint64_t *iova_ptr, size_t *len_ptr)
{
        int rc = 0, idx;

        *len_ptr = 0;

        if (!atomic_read(&cam_mem_mgr_refcnt)) {
                CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
                return -EINVAL;
        }

        idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle);
        if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0)
                return -EINVAL;

        if (!tbl.bufq[idx].active)
                return -EINVAL;

        mutex_lock(&tbl.bufq[idx].q_lock);
        if (buf_handle != tbl.bufq[idx].buf_handle) {
                rc = -EINVAL;
                goto handle_mismatch;
        }

        if (CAM_MEM_MGR_IS_SECURE_HDL(buf_handle))
                rc = cam_smmu_get_stage2_iova(mmu_handle,
                        tbl.bufq[idx].fd,
                        iova_ptr,
                        len_ptr);
        else
          //获取ais_s_buffer分别配的内存地址
                rc = cam_smmu_get_iova(mmu_handle,
                        tbl.bufq[idx].fd,
                        iova_ptr,
                        len_ptr);
        if (rc) {
                CAM_ERR(CAM_MEM,
                        "fail to map buf_hdl:0x%x, mmu_hdl: 0x%x for fd:%d",
                        buf_handle, mmu_handle, tbl.bufq[idx].fd);
                goto handle_mismatch;
        }

        CAM_DBG(CAM_MEM,
                "handle:0x%x fd:%d iova_ptr:%pK len_ptr:%llu",
                mmu_handle, tbl.bufq[idx].fd, iova_ptr, *len_ptr);
handle_mismatch:
        mutex_unlock(&tbl.bufq[idx].q_lock);
        return rc;
}
EXPORT_SYMBOL(cam_mem_get_io_buf);

int cam_smmu_get_iova(int handle, int ion_fd,
        dma_addr_t *paddr_ptr, size_t *len_ptr)
{
        int idx, rc = 0;
        enum cam_smmu_buf_state buf_state;

        if (!paddr_ptr || !len_ptr) {
                CAM_ERR(CAM_SMMU, "Error: Input pointers are invalid");
                return -EINVAL;
        }

        if (handle == HANDLE_INIT) {
                CAM_ERR(CAM_SMMU, "Error: Invalid handle");
                return -EINVAL;
        }

        /* clean the content from clients */
        *paddr_ptr = (dma_addr_t)NULL;
        *len_ptr = (size_t)0;

        idx = GET_SMMU_TABLE_IDX(handle);
        if (idx < 0 || idx >= iommu_cb_set.cb_num) {
                CAM_ERR(CAM_SMMU,
                        "Error: handle or index invalid. idx = %d hdl = %x",
                        idx, handle);
                return -EINVAL;
        }

        if (iommu_cb_set.cb_info[idx].is_secure) {
                CAM_ERR(CAM_SMMU,
                        "Error: can't get non-secure mem from secure cb");
                return -EINVAL;
        }

        mutex_lock(&iommu_cb_set.cb_info[idx].lock);
        if (iommu_cb_set.cb_info[idx].handle != handle) {
                CAM_ERR(CAM_SMMU,
                        "Error: hdl is not valid, table_hdl = %x, hdl = %x",
                        iommu_cb_set.cb_info[idx].handle, handle);
                rc = -EINVAL;
                goto get_addr_end;
        }
         //获取对应的index 和ion_fd 的paddr_ptr  len_ptr
        buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr);
        if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) {
                CAM_ERR(CAM_SMMU, "ion_fd:%d not in the mapped list", ion_fd);
                rc = -EINVAL;
                goto get_addr_end;
        }

get_addr_end:
        mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
        return rc;
}
EXPORT_SYMBOL(cam_smmu_get_iova);

static enum cam_smmu_buf_state cam_smmu_check_fd_in_list(int idx,
        int ion_fd, dma_addr_t *paddr_ptr, size_t *len_ptr)
{
        struct cam_dma_buff_info *mapping;

        list_for_each_entry(mapping,
                &iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
                if (mapping->ion_fd == ion_fd) {
                        *paddr_ptr = mapping->paddr;
                        *len_ptr = mapping->len;
                        return CAM_SMMU_BUFF_EXIST;
                }
        }

        return CAM_SMMU_BUFF_NOT_EXIST;
}

static void ais_vfe_q_bufs_to_hw(struct ais_vfe_hw_core_info *core_info,
                enum ais_ife_output_path_id path)
{
        struct ais_vfe_rdi_output *rdi_path = NULL;
        struct ais_vfe_buffer_t *vfe_buf = NULL;
        struct ais_vfe_bus_ver2_hw_info   *bus_hw_info = NULL;
        struct ais_vfe_bus_ver2_reg_offset_bus_client  *client_regs = NULL;
        uint32_t fifo_status = 0;
        bool is_full = false;
        struct ais_ife_rdi_get_timestamp_args get_ts;

        rdi_path = &core_info->rdi_out[path];
        bus_hw_info = core_info->vfe_hw_info->bus_hw_info;
        client_regs = &bus_hw_info->bus_client_reg[path];

        fifo_status = cam_io_r_mb(core_info->mem_base +
                        bus_hw_info->common_reg.addr_fifo_status);

        is_full =  fifo_status & (1 << path);

        while (!is_full) {
                if (list_empty(&rdi_path->buffer_q))
                        break;
                 //从rdi_path->buffer_q获取vfe_buf 信息添加到 
                vfe_buf = list_first_entry(&rdi_path->buffer_q,
                                struct ais_vfe_buffer_t, list);
                list_del_init(&vfe_buf->list);

                get_ts.path = path;
                get_ts.ts = &vfe_buf->ts_hw;
                core_info->csid_hw->hw_ops.process_cmd(
                        core_info->csid_hw->hw_priv,
                        AIS_IFE_CSID_CMD_GET_TIME_STAMP,
                        &get_ts,
                        sizeof(get_ts));


                CAM_DBG(CAM_ISP, "IFE%d|RDI%d: Q %d(0x%x) FIFO:%d ts %llu",
                        core_info->vfe_idx, path,
                        vfe_buf->bufIdx, vfe_buf->iova_addr,
                        rdi_path->num_buffer_hw_q, vfe_buf->ts_hw.cur_sof_ts);
               //将mipi数据写入iova_addr
                cam_io_w_mb(vfe_buf->iova_addr,
                        core_info->mem_base + client_regs->image_addr);
              //将获取数据后的vfe_buf 添加到dequeue 队列 rdi_path->buffer_hw_q 
                list_add_tail(&vfe_buf->list, &rdi_path->buffer_hw_q);
                ++rdi_path->num_buffer_hw_q;


                fifo_status = cam_io_r_mb(core_info->mem_base +
                        bus_hw_info->common_reg.addr_fifo_status);
                is_full =  fifo_status & (1 << path);

                trace_ais_isp_vfe_enq_buf_hw(core_info->vfe_idx, path,
                        vfe_buf->bufIdx, rdi_path->num_buffer_hw_q, is_full);
        }

        if (rdi_path->num_buffer_hw_q > MAX_NUM_BUF_SW_FIFOQ_ERR)
                CAM_WARN(CAM_ISP, "Excessive number of buffers in SW FIFO (%d)",
                        rdi_path->num_buffer_hw_q);
}

将数据dequeue 到ais server


static void ais_vfe_bus_handle_client_frame_done(
        struct ais_vfe_hw_core_info *core_info,
        enum ais_ife_output_path_id path,
        uint32_t last_addr)
{
        struct ais_vfe_rdi_output         *rdi_path = NULL;
        struct ais_vfe_buffer_t           *vfe_buf = NULL;
        struct ais_vfe_bus_ver2_hw_info   *bus_hw_info = NULL;
        uint64_t                           frame_cnt = 0;
        uint64_t                           sof_ts;
        uint64_t                           cur_sof_hw_ts;
        bool last_addr_match = false;
        uint32_t i = 0;

        CAM_DBG(CAM_ISP, "I%d|R%d last_addr 0x%x",
                        core_info->vfe_idx, path, last_addr);

        if (last_addr == 0) {
                CAM_ERR(CAM_ISP, "I%d|R%d null last_addr",
                                core_info->vfe_idx, path);
                return;
        }

        rdi_path = &core_info->rdi_out[path];
        bus_hw_info = core_info->vfe_hw_info->bus_hw_info;

        core_info->event.msg.type = AIS_IFE_MSG_FRAME_DONE;
        core_info->event.msg.path = path;
        core_info->event.msg.reserved = sizeof(struct ais_ife_event_data);

        while (rdi_path->num_buffer_hw_q && !last_addr_match) {
                struct ais_sof_info_t *p_sof_info = NULL;
                bool is_sof_match = false;

                spin_lock_bh(&rdi_path->buffer_lock);
                if (list_empty(&rdi_path->buffer_hw_q)) {
                        CAM_DBG(CAM_ISP, "I%d|R%d: FD while HW Q empty",
                                core_info->vfe_idx, path);
                        spin_unlock_bh(&rdi_path->buffer_lock);
                        break;
                }

                vfe_buf = list_first_entry(&rdi_path->buffer_hw_q,
                                struct ais_vfe_buffer_t, list);
                list_del_init(&vfe_buf->list);
                --rdi_path->num_buffer_hw_q;

                if (last_addr == vfe_buf->iova_addr)
                        last_addr_match = true;
                else
                        CAM_WARN(CAM_ISP, "IFE%d buf %d did not match addr",
                                core_info->vfe_idx, vfe_buf->bufIdx);

                CAM_DBG(CAM_ISP, "I%d|R%d BUF DQ %d (0x%x) FIFO:%d|0x%x",
                        core_info->vfe_idx, path,
                        vfe_buf->bufIdx, vfe_buf->iova_addr,
                        rdi_path->num_buffer_hw_q, last_addr);

                if (!list_empty(&rdi_path->sof_info_q)) {
                        while (!is_sof_match &&
                                !list_empty(&rdi_path->sof_info_q)) {
                                p_sof_info =
                                        list_first_entry(&rdi_path->sof_info_q,
                                                struct ais_sof_info_t, list);
                                list_del_init(&p_sof_info->list);
                                rdi_path->num_sof_info_q--;
                                if (p_sof_info->cur_sof_hw_ts >
                                        vfe_buf->ts_hw.cur_sof_ts) {
                                        is_sof_match = true;
                                        break;
                                }
                                list_add_tail(&p_sof_info->list,
                                        &rdi_path->free_sof_info_list);
                        }

                        if (!is_sof_match) {
                                p_sof_info = NULL;
                                CAM_ERR(CAM_ISP,
                                        "I%d|R%d: can't find the match sof",
                                        core_info->vfe_idx, path);
                        }

                } else
                        CAM_ERR(CAM_ISP, "I%d|R%d: SOF info Q is empty",
                                core_info->vfe_idx, path);

                if (p_sof_info) {
                        frame_cnt = p_sof_info->frame_cnt;
                        sof_ts = p_sof_info->sof_ts;
                        cur_sof_hw_ts = p_sof_info->cur_sof_hw_ts;
                        list_add_tail(&p_sof_info->list,
                                        &rdi_path->free_sof_info_list);
                } else {
                        frame_cnt = sof_ts = cur_sof_hw_ts = 0;
                }

                list_add_tail(&vfe_buf->list, &rdi_path->free_buffer_list);
                spin_unlock_bh(&rdi_path->buffer_lock);

                trace_ais_isp_vfe_buf_done(core_info->vfe_idx, path,
                                vfe_buf->bufIdx,
                                frame_cnt,
                                rdi_path->num_buffer_hw_q,
                                last_addr_match);

                rdi_path->batchFrameInfo[vfe_buf->batchId].batchId = vfe_buf->batchId;
                rdi_path->batchFrameInfo[vfe_buf->batchId].frameId = frame_cnt;
                rdi_path->batchFrameInfo[vfe_buf->batchId].hwTimestamp = cur_sof_hw_ts;

                if (vfe_buf->batchId == (rdi_path->batchConfig.numBatchFrames - 1)) {
                        core_info->event.u.frame_msg.buf_idx = vfe_buf->bufIdx;
                        core_info->event.u.frame_msg.num_batch_frames =
                                rdi_path->batchConfig.numBatchFrames;
                        core_info->event.u.frame_msg.ts = sof_ts;
                        core_info->event.msg.frame_id =
                                rdi_path->batchFrameInfo[i].frameId;
                        for (i = 0; i < rdi_path->batchConfig.numBatchFrames; i++) {
                                core_info->event.u.frame_msg.hw_ts[i] =
                                        rdi_path->batchFrameInfo[i].hwTimestamp;
                        }
                        //ais_ife_dev_cb core_info->event
                        core_info->event_cb(core_info->event_cb_priv,
                                        &core_info->event);

                        CAM_DBG(CAM_ISP, "I%d|R%d|F%llu: si [%llu, %llu]",
                                core_info->vfe_idx, path,
                                core_info->event.msg.frame_id,
                                sof_ts,
                                core_info->event.u.frame_msg.hw_ts[0]);
                }
        }

        if (!last_addr_match) {
                CAM_ERR(CAM_ISP, "IFE%d BUF| RDI%d NO MATCH addr 0x%x",
                        core_info->vfe_idx, path, last_addr);

                trace_ais_isp_vfe_error(core_info->vfe_idx, path, 1, 1);

                //send warning
                core_info->event.msg.type = AIS_IFE_MSG_OUTPUT_WARNING;
                core_info->event.msg.path = path;
                core_info->event.u.err_msg.reserved = 1;

                core_info->event_cb(core_info->event_cb_priv,
                        &core_info->event);
        }

        /* Flush SOF info Q if HW Buffer Q is empty */
        if (rdi_path->num_buffer_hw_q == 0) {
                struct ais_sof_info_t *p_sof_info = NULL;

                CAM_DBG(CAM_ISP, "I%d|R%d|F%llu: Flush SOF (%d) HW Q empty",
                        core_info->vfe_idx, path, frame_cnt,
                        rdi_path->num_sof_info_q);

                spin_lock_bh(&rdi_path->buffer_lock);
                while (!list_empty(&rdi_path->sof_info_q)) {
                        p_sof_info = list_first_entry(&rdi_path->sof_info_q,
                                        struct ais_sof_info_t, list);
                        list_del_init(&p_sof_info->list);
                        list_add_tail(&p_sof_info->list,
                                &rdi_path->free_sof_info_list);
                }

                rdi_path->num_sof_info_q = 0;
                spin_unlock_bh(&rdi_path->buffer_lock);

                trace_ais_isp_vfe_error(core_info->vfe_idx, path, 1, 0);

                //send warning
                core_info->event.msg.type = AIS_IFE_MSG_OUTPUT_WARNING;
                core_info->event.msg.path = path;
                core_info->event.u.err_msg.reserved = 0;

                core_info->event_cb(core_info->event_cb_priv,
                        &core_info->event);
        }

        spin_lock_bh(&rdi_path->buffer_lock);

        ais_vfe_q_bufs_to_hw(core_info, path);

        spin_unlock_bh(&rdi_path->buffer_lock);
}

通过回调函数通知ais server 获取数据

static int ais_ife_dev_cb(void *priv, struct ais_ife_event_data *evt_data)
{
        struct ais_ife_dev  *p_ife_dev;
        struct v4l2_event event = {};

        p_ife_dev = (struct ais_ife_dev *)priv;

        if (!evt_data) {
                CAM_ERR(CAM_ISP, "IFE%d callback with NULL event",
                        p_ife_dev->hw_idx);
                return -EINVAL;
        }

        CAM_DBG(CAM_ISP, "IFE%d CALLBACK %d frameId %d structsize%d",
                p_ife_dev->hw_idx, evt_data->msg.type,
                evt_data->msg.frame_id, evt_data->msg.reserved);

        if (sizeof(struct ais_ife_event_data) > sizeof(event.u.data)) {
                CAM_ERR(CAM_ISP, "IFE Msg struct too large (%d)!",
                        sizeof(struct ais_ife_event_data));
                return -EINVAL;
        }

        /* Queue the event */
        memcpy(event.u.data, (void *)evt_data, sizeof(struct ais_ife_event_data));

        event.id = V4L_EVENT_ID_AIS_IFE;
        event.type = V4L_EVENT_TYPE_AIS_IFE;
        v4l2_event_queue(p_ife_dev->cam_sd.sd.devnode, &event);

        return 0;
}

Ais 监听底层的event 事件收到event 事件,对事件进行处理

CameraResult IFEDevice::Init()
{
    CameraResult result = CAMERA_SUCCESS;

    //Only 1 KMD IFE Manager
    m_ifeKmdFd = CameraPlatformGetFd(AIS_SUBDEV_IFE, m_ifeId);

    result = pipe(m_pipeFd);
    if (result < 0)
    {
        CAM_MSG(ERROR, "Failed to create ife pipe %d");
        result = CAMERA_EFAILED;
    }

    if (0 == m_ifeKmdFd)
    {
        AIS_LOG(IFE_DRV, ERROR,   "Failed to get the Camera AIS_SUBDEV_IFE");
        result = CAMERA_EFAILED;
    }
    else
    {
        //Create event thread that polls
        result = SubscribeEvents(V4L_EVENT_TYPE_AIS_IFE, V4L_EVENT_ID_AIS_IFE);
        if (CAMERA_SUCCESS == result)
        {
            char name[64];
            snprintf(name, sizeof(name), "ife%d_v4l2", m_ifeId);

            m_v4l2EentThreadExit = FALSE;
            result = CameraCreateThread(CAMERA_THREAD_PRIO_HIGH_REALTIME,
                    0, IFEDevice::IfeV4L2EventThread, this, 0x8000, name, &m_v4l2EentThread);
            if(CAMERA_SUCCESS != result)
            {
                AIS_LOG(IFE_DRV, ERROR, "Create IfeEvent thread failed for VFE");
            }
        }
    }

    return result;
}


int IFEDevice::IfeV4L2EventThread(void* arg)

{
    int pollStatus = -1;
    int exit_thread = 0;
    struct pollfd pollFds[2];
    int pollNumFds;
    CameraResult result = CAMERA_SUCCESS;
    IFEDevice* pIfeCtxt = (IFEDevice*)arg;

    pollFds[0].fd     = pIfeCtxt->m_pipeFd[0];
    pollFds[0].events = POLLIN|POLLRDNORM;
    pollFds[1].fd = pIfeCtxt->m_ifeKmdFd;
    pollFds[1].events = POLLIN|POLLRDNORM|POLLPRI;
    pollNumFds        = 2;

    while(!pIfeCtxt->m_v4l2EentThreadExit)
    {
        pollStatus = poll(pollFds, pollNumFds, -1);
        if(0 < pollStatus)
        {
            result = pIfeCtxt->ProcessV4L2Event();
        }
        else
        {
            AIS_LOG(IFE_DRV, ERROR, "IFE%d poll failed", pIfeCtxt->m_ifeId);
        }
    }
    return 0;
}

对event 事件进行处理

CameraResult IFEDevice::ProcessV4L2Event()
{
    CameraResult result = CAMERA_SUCCESS;
    struct v4l2_event v4l2Event = {};
    int rc = -1;

    rc = ioctl(m_ifeKmdFd, VIDIOC_DQEVENT, &v4l2Event);
    if (rc >= 0)
    {
        if (V4L_EVENT_TYPE_AIS_IFE != v4l2Event.type)
        {
            AIS_LOG(IFE_DRV, ERROR, "IFE%d incorrect v4l2 type %d", m_ifeId, v4l2Event.type);
            result = CAMERA_EFAILED;
        }
        else if (v4l2Event.id != V4L_EVENT_ID_AIS_IFE)
        {
            AIS_LOG(IFE_DRV, ERROR, "IFE%d incorrect v4l2 ID %d", m_ifeId, v4l2Event.id);
            result =  CAMERA_EFAILED;
        }
        else
        {
            IfeEventKernelMsgType* pKernelMessage = reinterpret_cast<IfeEventKernelMsgType*>(v4l2Event.u.data); //v4l2Event.u.data = core_info->event
            if (pKernelMessage->msg.reserved != sizeof(IfeEventKernelMsgType))
            {
                AIS_LOG(IFE_DRV, ERROR, "IFE event struct size mismatch(%d != %d)! Incompatible kernel version",
                        pKernelMessage->msg.reserved, sizeof(IfeEventKernelMsgType));
                result =  CAMERA_EFAILED;
            }
            else
            {
                AIS_LOG(IFE_DRV, LOW, "IFE%d Received Event %d %llu",
                        m_ifeId, pKernelMessage->msg.type, pKernelMessage->msg.timestamp);

                //convert kernel IFE event msg struct to 
                 //UMD IFE event msg struct IfeEventMsgType
                IfeEventMsgType message = {};
                message.timestamp = pKernelMessage->msg.timestamp;
                message.type = pKernelMessage->msg.type;
                message.idx = pKernelMessage->msg.idx;
                message.path = pKernelMessage->msg.path;

                switch(message.type)
                {
                    case IFE_MSG_ID_SOF:
                    {
                        message.u.sofMsg.hwTimestamp = 
                                               pKernelMessage->u.sof_msg.hwTimestamp;
                        message.u.sofMsg.frameId = pKernelMessage->msg.frameId;
                        AIS_LOG(IFE_DRV, LOW, "IFE%d RDI%d SOF %d",
                                m_ifeId, message.path, message.u.sofMsg.frameId);
                        result = SendMessage(&message);
                    }
                    break;

                    case IFE_MSG_ID_OUPUT_WARNING:
                    {
                        message.u.errMsg.reserved = pKernelMessage->u.err_msg.reserved;
                        AIS_LOG(IFE_DRV, WARN, "IFE%d RDI%d WARNING %d",
                                                    m_ifeId, message.path,
                                                    message.u.errMsg.reserved);
                        result = SendMessage(&message);
                    }
                    break;

                    case IFE_MSG_ID_OUPUT_ERROR:
                    case IFE_MSG_ID_CSID_ERROR:
                    {
                        message.u.errMsg.reserved = pKernelMessage->u.err_msg.reserved;
                        AIS_LOG(IFE_DRV, ERROR, "IFE%d Received error event [%u %u]",
                                m_ifeId, message.path, message.u.errMsg.reserved);
                        result = SendMessage(&message);
                    }
                    break;

                    case IFE_MSG_ID_FRAME_DONE:// AIS_IFE_MSG_FRAME_DONE
                    {
                        for (int i = 0; i < pKernelMessage->u.frame_msg.numBatchFrames; i++)
                        {
                            message.u.frameMsg.hwTimestamp[i] = 
                                               pKernelMessage->u.frame_msg.hwTimestamp[i];
                            message.u.frameMsg.frameId[i] =  
                                               pKernelMessage->msg.frameId + i;
                        }
                        message.u.frameMsg.timestamp = 
                                               pKernelMessage->u.frame_msg.timestamp;
                        message.u.frameMsg.bufIdx = pKernelMessage->u.frame_msg.bufIdx;
                        message.u.frameMsg.numBatchFrames = 
                                               pKernelMessage->u.frame_msg.numBatchFrames;
                        AIS_LOG(IFE_DRV, LOW, "IFE%d RDI%d Frame Done %d buf %d [%llu]",
                                m_ifeId, message.path,message.u.frameMsg.frameId[0],
                                message.u.frameMsg.bufIdx,
                                 message.u.frameMsg.hwTimestamp[0]);
                        result = SendMessage(&message);
                    }
                    break;

                    default:
                        AIS_LOG(IFE_DRV, HIGH, "Received Unknown v4l2 event %d", message.type);
                        return CAMERA_EFAILED;
                }
            }
        }
    }
    else
    {
        AIS_LOG(IFE_DRV, ERROR, "IFE%d VIDIOC_DQEVENT failed", m_ifeId);
        result = CAMERA_EFAILED;
    }

    return result;

CameraResult IFEDevice::SendMessage(IfeEventMsgType* pIfeMsg)
{
    CameraResult result = CAMERA_SUCCESS;

    if (m_pfnCallback)
    {
        result = m_pfnCallback(m_pClientData, (uint32)(pIfeMsg->type), sizeof(*pIfeMsg), (void*)(pIfeMsg));
        if (result != CAMERA_SUCCESS)
        {
            AIS_LOG(IFE_DRV, ERROR, "VFE%d: Failed to send message %u", m_ifeId, pIfeMsg->type);
        }
    }
    else
    {
        AIS_LOG(IFE_DRV, ERROR, "VFE%d::SendMessage(%u) Null VFE callback function", m_ifeId, pIfeMsg->type);
        result = CAMERA_EMEMPTR;
    }

    return result;
}

CameraResult AisIFEConfigurer::IfeDeviceCallback(void* pClientData,
        uint32 uidEvent, int nEventDataLen, void* pEventData)
{
    CameraResult rc = CAMERA_SUCCESS;
    AisIFEConfigurer* pIfeCtxt = (AisIFEConfigurer*)pClientData;

    AIS_LOG(ENGINE, DBG, "Received IFE %p callback %d", pIfeCtxt, uidEvent);

    IfeEventMsgType* pPayload = ((IfeEventMsgType*)pEventData);
    IfeCoreType ifeId;

    if (nEventDataLen != sizeof(IfeEventMsgType))
    {
        AIS_LOG(ENGINE, ERROR, "Received IFE %p callback %d with wrong size", pClientData, uidEvent);
        return CAMERA_EBADPARM;
    }
    else if (!pIfeCtxt || !pPayload)
    {
        AIS_LOG(ENGINE, ERROR, "Received IFE %p callback %d with no payload", pClientData, uidEvent);
        return CAMERA_EMEMPTR;
    }

    ifeId = (IfeCoreType)pPayload->idx;

    if (ifeId >= IFE_CORE_MAX)
    {
        AIS_LOG(ENGINE, ERROR, "IFE Core %d exceeds MAX %d", ifeId, IFE_CORE_MAX);
        return CAMERA_EBADPARM;
    }

    switch (uidEvent)
    {
        case IFE_MSG_ID_FRAME_DONE:
        {
            IfeFrameEventMsg* pRawMsg = &pPayload->u.frameMsg;
            AisEventMsgType msg = {};
    
            msg.eventId = AIS_EVENT_RAW_FRAME_DONE;
    
            msg.payload.ifeFrameDone.ifeCore = ifeId;
            msg.payload.ifeFrameDone.ifeOutput = (IfeOutputPathType)pPayload->path;
    
            msg.payload.ifeFrameDone.frameInfo.idx = pRawMsg->bufIdx;
            msg.payload.ifeFrameDone.frameInfo.seq_no[0] = pRawMsg->frameId[0];
            msg.payload.ifeFrameDone.frameInfo.timestamp = pRawMsg->timestamp;
            msg.payload.ifeFrameDone.frameInfo.sof_qtimestamp[0] =  pRawMsg->hwTimestamp[0];
            msg.payload.ifeFrameDone.frameInfo.timestamp_system = pPayload->timestamp;
    
            AIS_LOG(ENGINE, MED, "IFE %d:%d Frame Done %d (%u:%llu:%llu)",
                    msg.payload.ifeFrameDone.ifeCore,
                    msg.payload.ifeFrameDone.ifeOutput,
                    msg.payload.ifeFrameDone.frameInfo.idx,
                    msg.payload.ifeFrameDone.frameInfo.seq_no[0],
                    msg.payload.ifeFrameDone.frameInfo.timestamp,
                    msg.payload.ifeFrameDone.frameInfo.sof_qtimestamp[0]);
    
            if (pRawMsg->numBatchFrames > 1)
            {
                for(uint32 i = 1; i < pRawMsg->numBatchFrames; i++)
                {
                    msg.payload.ifeFrameDone.frameInfo.seq_no[i] = pRawMsg->frameId[i];
                    msg.payload.ifeFrameDone.frameInfo.sof_qtimestamp[i] = pRawMsg->hwTimestamp[i];
    
                    AIS_LOG(ENGINE, DBG, "IFE %d:%d Frame Done %d (batch %d) (%u:%llu)",
                        msg.payload.ifeFrameDone.ifeCore,
                        msg.payload.ifeFrameDone.ifeOutput,
                        msg.payload.ifeFrameDone.frameInfo.idx,
                        i,
                        msg.payload.ifeFrameDone.frameInfo.seq_no[i],
                        msg.payload.ifeFrameDone.frameInfo.sof_qtimestamp[i]);
                }
            }
    
            AIS_TRACE_MESSAGE_F(AISTraceGroupIFE, "IFE %d:%d idx %d_%d fd",
                msg.payload.ifeFrameDone.ifeCore,
                msg.payload.ifeFrameDone.ifeOutput,
                msg.payload.ifeFrameDone.frameInfo.idx,
                msg.payload.ifeFrameDone.frameInfo.seq_no[0]);
    
            AisEngine::GetInstance()->QueueEvent(&msg);
    
            break;
        }

/**
 * QueueEvent
 *
 * @brief Queues events for engine
 *
 * @param pMsg
 *
 * @return CameraResult
 */
CameraResult AisEngine::QueueEvent(AisEventMsgType* pMsg)
{
    CameraResult result;

    AIS_LOG(ENGINE, LOW, "q_event %d", pMsg->eventId);

    result = CameraQueueEnqueue(m_eventQ[AIS_ENGINE_QUEUE_EVENTS], pMsg);
    if (result == CAMERA_SUCCESS)
    {
        result = CameraSetSignal(m_eventHandlerSignal);
    }
    else
    {
        AIS_LOG(ENGINE, ERROR,"Failed to enqueue event %d (%d)", pMsg->eventId, result);
    }
    return result;
}

 * @return int
 */
int AisEngine::ProcessEvent(AisEventMsgType* pMsg)
{
    CameraResult rc;

    rc = CameraQueueDequeue(m_eventQ[AIS_ENGINE_QUEUE_EVENTS], pMsg);
    if (CAMERA_SUCCESS != rc)
    {
        if (CAMERA_ENOMORE != rc)
        {
            AIS_LOG(ENGINE, ERROR, "Failed to dequeue event (%d)", rc);
        }
        return 0;
    }

    switch (pMsg->eventId)
    {
    case AIS_EVENT_RAW_FRAME_DONE:
    {
        ProcessRawFrameDone(pMsg);
        break;
    }
    case AIS_EVENT_PPROC_JOB:
    {
        ProcessPProcJob(pMsg);
        break;
    }
    case AIS_EVENT_PPROC_JOB_DONE:
    {
        ProcessPProcJobDone(pMsg);
        break;
    }
    case AIS_EVENT_PPROC_JOB_FAIL:
    {
        ProcessPProcJobFail(pMsg);
        break;
    }
    case AIS_EVENT_CSID_FATAL_ERROR:
    {
        ProcessCsidFatalError(pMsg);
        break;
    }
    case AIS_EVENT_INPUT_STATUS:
    {
        ProcessInputStatusEvent(pMsg);
        break;
    }
    case AIS_EVENT_INPUT_FATAL_ERROR:
    {
        ProcessInputFatalError(pMsg);
        break;
    }
    case AIS_EVENT_INPUT_FRAME_FREEZE:
    {
        ProcessInputFrameFreeze(pMsg);
        break;
    }
    case AIS_EVENT_SOF:
    {
        ProcessSOF(pMsg);
        break;
    }
    case AIS_EVENT_IFE_OUTPUT_ERROR:
    {
        ProcessIfeOutputError(pMsg);
        break;
    }
    case AIS_EVENT_APPLY_PARAM:
    {
        ProcessApplyParam(pMsg);
        break;
    }
    case AIS_EVENT_DEFER_INPUT_DETECT:
    {
        ProcessDeferInputDetect(pMsg);

        /* This means all the Initializations of ais_server done, can initialize device Diagnostic stats */
        m_DiagManager->InitializeDiagstats();
        break;
    }
    case AIS_EVENT_DELAYED_SUSPEND:
    {
        ProcessDelayedSuspend(pMsg);
        break;
    }
    case AIS_EVENT_VENDOR:
    {
        ProcessVendorEvent(pMsg);
        break;
    }
    case AIS_EVENT_USER_NOTIFICATION:
    {
        ProcessEventUserNotification(pMsg);
        break;
    }
    default:
        break;
    }

    return 1;
}

typedef enum
{
    AIS_PPROC_USR_DONE,
    AIS_PPROC_ISP,
    AIS_PPROC_GPU,
    AIS_PPROC_FRAMESYNC,
    AIS_PPROC_MEMCPY,
    AIS_PPROC_RGBIR,
    AIS_PPROC_EXT,
    AIS_PPROC_MAX
}AisPProcIdType;

/**
 * ProcessRawFrameDone
 *
 * @brief Process RAW frame done event. Queues new PPROC job.
 *
 * @param pMsg
 */
void AisEngine::ProcessRawFrameDone(AisEventMsgType* pMsg)
{
    CameraResult rc;
    AisUsrCtxt* pUsrCtxt = NULL;
    AisEventFrameDoneType* pFrameDone = &pMsg->payload.ifeFrameDone;

    AisResMgrMatch sMatch = {};
    AisUsrCtxtList matchList;
    sMatch.matchType = AIS_RESMGR_MATCH_IFE_PATH;
    sMatch.dataType = AIS_RESMGR_MATCH_DATA_IFE;
    sMatch.device = pFrameDone->ifeCore;
    sMatch.path = pFrameDone->ifeOutput;

    rc = m_ResourceManager->MatchUserList(&sMatch, &matchList);
    if (CAMERA_SUCCESS == rc && !matchList.empty())
    {
        pUsrCtxt = matchList.front();
        matchList.pop_front();
    }

    if (pUsrCtxt)
    {
        AisEventMsgType sNewJob = {};
        uint32 streamIdx;

        pUsrCtxt->Lock();

        // move to streaming state on receiving first frame during recovery
        if (AIS_USR_STATE_RECOVERY == pUsrCtxt->m_state)
        {
            pUsrCtxt->ProcessRecoverySuccessEvent();
        }

        if (pUsrCtxt->m_state != AIS_USR_STATE_STREAMING)
        {
            AIS_LOG(ENGINE, HIGH, "ctxt %p aborted!", pUsrCtxt);
            pUsrCtxt->Unlock();
            pUsrCtxt->DecRefCnt();
            return;
        }

        pUsrCtxt->m_numFrameDone++;

        if (pUsrCtxt->m_isPendingStart)
        {
            AIS_LOG(ENGINE, HIGH, "IFE %d Output %d First Frame buffer %d",
                    pFrameDone->ifeCore, pFrameDone->ifeOutput, pFrameDone->frameInfo.idx);
            pUsrCtxt->m_isPendingStart = FALSE;
        }

        AisIfeStreamType* pIfeStream = NULL;
        for (streamIdx = 0; streamIdx < pUsrCtxt->m_numStreams; streamIdx++)
        {
            pIfeStream = &pUsrCtxt->m_streams[streamIdx].resources.ifeStream;
            if (pIfeStream->ifeCore == pFrameDone->ifeCore &&
                pIfeStream->ifeOutput == pFrameDone->ifeOutput)
            {
                break;
            }
        }

        if (streamIdx == pUsrCtxt->m_numStreams)
        {
            AIS_LOG(ENGINE, ERROR, "Could not find matching stream for FrameDone %d %d",
                    pFrameDone->ifeCore, pFrameDone->ifeOutput);
            streamIdx = 0;
            pIfeStream = &pUsrCtxt->m_streams[streamIdx].resources.ifeStream;
        }

        if (pUsrCtxt->m_streams[streamIdx].inputCfg.inputModeInfo.interlaced == INTERLACED_QUERY_FIELD_TYPE)
        {
            pUsrCtxt->GetFrameFieldInfo(pFrameDone);
        }

        AisBufferList* pBufferList = pUsrCtxt->m_bufferList[pIfeStream->bufferListIdx];
        AisBuffer* pBuffer = pBufferList->GetBuffer(pFrameDone->frameInfo.idx);
        if (NULL == pBuffer)
        {
            AIS_LOG(ENGINE, HIGH, "ctxt %p invalid buffer index %d (%d, %d)",
                    pUsrCtxt, pFrameDone->frameInfo.idx, pBufferList->GetId(), pBufferList->m_nBuffers);
            pUsrCtxt->Unlock();
            pUsrCtxt->DecRefCnt();
            return;
        }

        pUsrCtxt->Unlock();


        //post process frame data if not secure
        if (!pUsrCtxt->m_secureMode)
        {
            rc = ((AisInputConfigurer*)m_Configurers[AIS_CONFIGURER_INPUT])->ProcessFrameData(pUsrCtxt, pBuffer, &pFrameDone->frameInfo);
        }

        uint64 jobId = AisCreateJobId(pUsrCtxt,
                streamIdx,
                pFrameDone->frameInfo.seq_no[0],
                pFrameDone->ifeCore, pFrameDone->ifeOutput);

        //push buffer as ready to consume and queue PPROC event
        pBufferList->QueueReadyBuffer(jobId, pBuffer);

        sNewJob.eventId = AIS_EVENT_PPROC_JOB;
        sNewJob.payload.pprocJob.pUsrCtxt = pUsrCtxt;
        sNewJob.payload.pprocJob.jobId = jobId;
        sNewJob.payload.pprocJob.currentHop = 0;
        sNewJob.payload.pprocJob.streamIdx = streamIdx;
        sNewJob.payload.pprocJob.frameInfo = pFrameDone->frameInfo;

        if (pUsrCtxt->m_usrSettings.isp_ctrls.param_mask & (1 << QCARCAM_CONTROL_DUMP_FRAME))
        {
            sNewJob.payload.pprocJob.bDumpBuffers = TRUE;
            pUsrCtxt->m_usrSettings.isp_ctrls.param_mask &= ~(1 << QCARCAM_CONTROL_DUMP_FRAME);
        }

        QueueEvent(&sNewJob);

        AIS_TRACE_MESSAGE_F(AISTraceGroupEngine, "IFE %d:%d idx %d_%d ProcessRawFrameDone",
                    pUsrCtxt->m_streams[streamIdx].resources.ifeStream.ifeCore,
                    pUsrCtxt->m_streams[streamIdx].resources.ifeStream.ifeOutput,
                    pFrameDone->frameInfo.idx,
                    pFrameDone->frameInfo.seq_no[0]);

        //pUsrCtxt->DecRefCnt(); <== do not decrement as we have it Queued for PPROC!
    }
}

/**
 * QueueReadyBuffer
 *
 * @brief Queues buffer associated with job ID to buffer ready list
 *
 * @param jobId      job ID
 * @param pBuffer    buffer
 *
 * @return CameraResult
 */
CameraResult AisBufferList::QueueReadyBuffer(uint64 jobId, AisBuffer* pBuffer)
{
    AisBuflistReadyQType readyQ = {jobId, pBuffer};

    Lock();
    m_readyQ.push_back(readyQ);
    Unlock();

    AIS_LOG(ENGINE, DBG, "Q 0x%llx %p", jobId, pBuffer);

    return CAMERA_SUCCESS;
}

/**
 * QueueEvent
 *
 * @brief Queues events for engine
 *
 * @param pMsg
 *
 * @return CameraResult
 */
CameraResult AisEngine::QueueEvent(AisEventMsgType* pMsg)
{
    CameraResult result;

    AIS_LOG(ENGINE, LOW, "q_event %d", pMsg->eventId);

    result = CameraQueueEnqueue(m_eventQ[AIS_ENGINE_QUEUE_EVENTS], pMsg);
    if (result == CAMERA_SUCCESS)
    {
        result = CameraSetSignal(m_eventHandlerSignal);
    }
    else
    {
        AIS_LOG(ENGINE, ERROR,"Failed to enqueue event %d (%d)", pMsg->eventId, result);
    }
    return result;
}

 case AIS_EVENT_PPROC_JOB:
    {
        ProcessPProcJob(pMsg);
        break;
    }

/**
 * ProcessPProcJob
 *
 * @brief Process PPROC Job
 *
 * @param pMsg
 */
void AisEngine::ProcessPProcJob(AisEventMsgType* pMsg)
{
    CameraResult result;
    AisEventPProcJobType* pPPJob = &pMsg->payload.pprocJob;
    AisUsrCtxt* pUsrCtxt = pPPJob->pUsrCtxt;

    //pUsrCtxt->IncRefCnt() <== pUsrCtxt incremented by caller on queueing so no need to increment again

    pUsrCtxt->Lock();
    if (pUsrCtxt->m_state != AIS_USR_STATE_STREAMING)
    {
        AIS_LOG(ENGINE, HIGH, "job %p aborted!", pUsrCtxt);
        pUsrCtxt->Unlock();
        pUsrCtxt->DecRefCnt();
        return;
    }
    pUsrCtxt->m_ppjobInProgress++;
    pUsrCtxt->Unlock();


    pPPJob->pProcChain = &pUsrCtxt->m_pProcChainDef->pProcChain[pPPJob->currentHop];
    //pPPJob->currentHop=0  AisPProcUsrDone::ProcessEvent
    result = pUsrCtxt->m_pPProc[pPPJob->currentHop]->ProcessEvent(pUsrCtxt, pMsg);

    if (CAMERA_ENOREADYBUFFER == result &&
        AIS_PPROC_STEP_OPTIONAL_INPUT_BUFFERS == pPPJob->pProcChain->stepType)
    {
        AIS_LOG(ENGINE, HIGH, "job 0x%llx skip optional hop %d", pPPJob->currentHop);
        pPPJob->status = CAMERA_SUCCESS;

        ProcessPProcJobDone(pMsg);
    }
    else if (CAMERA_SUCCESS != result)
    {
        //bail out on failure in one of the stages
        //ENEEDMORE is abort on purpose and need not print as error
        AIS_LOG_ON_ERR(ENGINE, (CAMERA_ENEEDMORE != result), "job 0x%llx failed on hop %d (%d)",
                pPPJob->jobId, pPPJob->currentHop, result);

        pUsrCtxt->Lock();
        pUsrCtxt->m_ppjobInProgress--;
        pUsrCtxt->Unlock();

        pUsrCtxt->DecRefCnt();
    }

}

 *
 * @brief Process Event by queuing frame buffer to client buffer done Q.
 *        If the buffer done Q exceeds latency max limit, the head of the Q is returned
 *        to be processed by the engine.
 *
 * @param pUsrCtxt
 * @param pEvent
 *
 * @return CameraResult
 */
CameraResult AisPProcUsrDone::ProcessEvent(AisUsrCtxt* pUsrCtxt, AisEventMsgType* pEvent)
{
    CameraResult result = CAMERA_SUCCESS;
    AisEventPProcJobType* pJob = &pEvent->payload.pprocJob;
    uint bufferlistId = pJob->pProcChain->inBuflistId[pJob->streamIdx];

    if (bufferlistId >= AIS_BUFLIST_MAX)
    {
        AIS_LOG(ENGINE, ERROR, "Context %p invalid bufferlist id %d", pUsrCtxt, bufferlistId);
        return CAMERA_EBADSTATE;
    }

    AisBufferList* pBufferList = pUsrCtxt->m_bufferList[bufferlistId];

    pUsrCtxt->Lock();

    //context must be streaming
    if (pUsrCtxt->m_state != AIS_USR_STATE_STREAMING)
    {
        AIS_LOG(ENGINE, ERROR, "Context %p in bad state %d", pUsrCtxt, pUsrCtxt->m_state);
        pUsrCtxt->Unlock();
        return CAMERA_EBADSTATE;
    }

    if (pUsrCtxt->m_isPendingStart)
    {
        pUsrCtxt->m_isPendingStart = FALSE;
    }

    AisBuffer* pBuffer = pBufferList->GetReadyBuffer(pJob->jobId);
    if (!pBuffer)
    {
        AIS_LOG(ENGINE, ERROR, "Context %p cannot find input buffer (%d) for jobId 0x%llx", pUsrCtxt, bufferlistId, pJob->jobId);
        pUsrCtxt->Unlock();
        return CAMERA_ENOREADYBUFFER;
    }

    if (pJob->frameInfo.timestamp < pUsrCtxt->m_startTime)
    {
        AIS_LOG(ENGINE, ERROR, "Drop buffer %d due to frame timestamp (%llu) <= starttime (%llu)",
                pBuffer->idx, pJob->frameInfo.timestamp, pUsrCtxt->m_startTime);

        pBufferList->SetBufferState(pBuffer->idx, AIS_BUFFER_INITIALIZED);
        pBufferList->ReturnBuffer(pUsrCtxt, pBuffer->idx);

        pUsrCtxt->Unlock();
        return CAMERA_EFAILED;
    }

    pJob->frameInfo.id = bufferlistId;
    pJob->frameInfo.idx = pBuffer->idx;


    //Only invalidate if buffer is cached
    if (CAMERA_BUFFER_FLAG_CACHED & pBuffer->flags)
    {
        result = CameraBufferCacheInvalidate(pBuffer);
        if (CAMERA_SUCCESS != result)
        {
            AIS_LOG(ENGINE, ERROR, "buffer%d cache invalidate failed %d",
                    pBuffer->idx, result);
        }
    }

    AisBuflistEnqueueUser(pUsrCtxt, pBufferList, &pJob->frameInfo);

    pUsrCtxt->Unlock();

    pEvent->eventId = AIS_EVENT_PPROC_JOB_DONE;
    AisEngine::GetInstance()->QueueEvent(pEvent);

    return result;
};
/**
 * GetReadyBuffer
 *
 * @brief Get ready buffer associated with job ID
 *
 * @param jobId
 *
 * @return AisBuffer
 */
AisBuffer* AisBufferList::GetReadyBuffer(uint64 jobId)
{
    AisBuffer* pBuffer = NULL;
    std::list<AisBuflistReadyQType>::iterator  it;

    Lock();
    for(it = m_readyQ.begin(); it != m_readyQ.end(); ++it)
    {
        if (it->jobId == jobId)
        {
            pBuffer = it->pBuffer;
            m_readyQ.erase(it);
            break;
        }
    }
    Unlock();

    AIS_LOG(ENGINE, DBG, "DQ 0x%llx %p", jobId, pBuffer);

    return pBuffer;
}

通知client进行数据处理

 * AisBuflistEnqueueUser
 *
 * @brief Enqueue buffer done to user
 *
 * @return CameraResult
 */
CameraResult AisBuflistEnqueueUser(AisUsrCtxt* pUsrCtxt, AisBufferList* pBufferList, qcarcam_frame_info_v2_t* pFrameDone)
{
    CameraResult result = CAMERA_SUCCESS;
    int rc = EOK;
    uint32 buffer_done_q_length = 0;

    pthread_mutex_lock(&pBufferList->m_bufferDoneQMutex);

    /*Check latency and reduce if needed*/
    CameraQueueGetLength(pBufferList->m_bufferDoneQ, &buffer_done_q_length);
    if (buffer_done_q_length > pUsrCtxt->m_usrSettings.n_latency_max)
    {
        uint32 i;

        for (i = 0; i < pUsrCtxt->m_usrSettings.n_latency_reduce_rate; i++)
        {
            qcarcam_frame_info_v2_t frame_info;
            result = CameraQueueDequeue(pBufferList->m_bufferDoneQ, (CameraQueueDataType)&frame_info);
            if (CAMERA_SUCCESS == result)
            {
                AIS_LOG(ENGINE, WARN, "Drop buffer %d from bufferDoneQ and requeue", frame_info.idx);
                pBufferList->SetBufferState(frame_info.idx, AIS_BUFFER_INITIALIZED);
                pBufferList->ReturnBuffer(pUsrCtxt, frame_info.idx);
            }
            else
            {
                AIS_LOG(ENGINE, ERROR, "ctxt %p failed (%d) to dequeue frame to requeue", pUsrCtxt, result);
            }
        }
    }

    /*Queue new frame and signal condition*/
    result = CameraQueueEnqueue(pBufferList->m_bufferDoneQ, (CameraQueueDataType)pFrameDone);
    pBufferList->SetBufferState(pFrameDone->idx, AIS_DELIVERY_QUEUE);

    if (EOK != (rc = pthread_cond_signal(&pBufferList->m_bufferDoneQCond)))
    {
        AIS_LOG(ENGINE, ERROR, "pthread_cond_signal failed: %s", strerror(rc));
        result = ERRNO_TO_RESULT(rc);
    }

    pthread_mutex_unlock(&pBufferList->m_bufferDoneQMutex);

    /*send callback if needed*/
    if (pUsrCtxt->m_eventCbFcn && (pUsrCtxt->m_eventMask & QCARCAM_EVENT_FRAME_READY))
    {
        qcarcam_event_payload_t payload = {};
        payload.frame_info = *pFrameDone;

        if (AisEngine::GetInstance()->GetLatencyMeasurementMode() == CAMERA_LM_MODE_ALL_STEPS)
        {
            uint64 ptimestamp = 0;

            //set flags to indicate latency measurement is enabled
            payload.frame_info.flags = 0x1;

            CameraGetTime(&ptimestamp);
            AIS_LOG(ENGINE, HIGH, "LATENCY| input %d  qcarcamHndl %lu buff list enqueue latency from frame done %llu us",
                    pUsrCtxt->m_inputId,
                    pUsrCtxt->m_qcarcamHndl,
                    (ptimestamp - pFrameDone->timestamp_system) / 1000);
        }

        pUsrCtxt->m_eventCbFcn(pUsrCtxt->m_qcarcamHndl, QCARCAM_EVENT_FRAME_READY, (qcarcam_event_payload_t *)&payload);
    }

    return result;
}



///
/// ais_get_frame_v2
///
/// @brief Get available frame
///
/// @param hndl          Handle of input
/// @param p_frame_info  Pointer to frame information that will be filled
/// @param timeout       Max wait time in ms for frame to be available before timeout
/// @param flags         Flags
///
/// @return CAMERA_SUCCESS if successful; CAMERA_EEXPIRED if timeout
///
CameraResult AisEngine::ais_get_frame_v2(qcarcam_hndl_t hndl,
        qcarcam_frame_info_v2_t* p_frame_info,
        unsigned long long int timeout,
        unsigned int flags)
{
    CameraResult rc = CAMERA_SUCCESS;
    struct timespec t;
    struct timespec to;
    AisUsrCtxt* pUsrCtxt;

    AIS_API_ENTER_HNDL(hndl);

    pUsrCtxt = GetUsrCtxt(hndl);
    if (pUsrCtxt)
    {
        AisBufferList* pBufferList = NULL;
        uint32 bufferlistId = flags;

        if (!p_frame_info)
        {
            AIS_LOG(ENGINE, ERROR, "p_frame_info is null");
            PutUsrCtxt(pUsrCtxt);
            return CAMERA_EMEMPTR;
        }

        if (bufferlistId > AIS_BUFLIST_USR_LAST)
        {
            AIS_LOG(ENGINE, ERROR, "invalid buffer list id %d", bufferlistId);
            PutUsrCtxt(pUsrCtxt);
            return CAMERA_EMEMPTR;
        }

        pBufferList = pUsrCtxt->m_bufferList[bufferlistId];

        pUsrCtxt->Lock();

        /*must be started to be able to get frame*/
        if (pUsrCtxt->m_state != AIS_USR_STATE_STREAMING &&
            pUsrCtxt->m_state != AIS_USR_STATE_RECOVERY_START &&
            pUsrCtxt->m_state != AIS_USR_STATE_RECOVERY)
        {
            AIS_LOG(ENGINE, ERROR, "Usrctxt %p in incorrect state %d",
                                pUsrCtxt, pUsrCtxt->m_state);
            pUsrCtxt->Unlock();
            PutUsrCtxt(pUsrCtxt);
            return CAMERA_EBADSTATE;
        }

        pUsrCtxt->Unlock();

        if (timeout != QCARCAM_TIMEOUT_NO_WAIT && timeout != QCARCAM_TIMEOUT_INIFINITE)
        {
#ifndef __INTEGRITY
            if (-1 == clock_gettime(CLOCK_MONOTONIC, &to))
#else
            if (-1 == clock_gettime(CLOCK_REALTIME, &to))
#endif
            {
                AIS_LOG(ENGINE, ERROR, "clock_gettime failed: %s", strerror(errno));
                rc = ERRNO_TO_RESULT(errno);
            }
            else
            {
#if defined (__QNXNTO__)
                nsec2timespec(&t, timeout);
#else
                t.tv_sec = timeout / NANOSEC_TO_SEC;
                t.tv_nsec = timeout % NANOSEC_TO_SEC;
#endif

                AIS_LOG(ENGINE, LOW, "t.tv_sec %d t.tv_nsec %d: timeout %d ns",
                    t.tv_sec,  t.tv_nsec, timeout);

                to.tv_sec  += t.tv_sec;
                to.tv_nsec += t.tv_nsec;
                if (to.tv_nsec >= NANOSEC_TO_SEC)
                {
                    to.tv_sec  += 1;
                    to.tv_nsec -= NANOSEC_TO_SEC;
                }
            }
        }

        if (CAMERA_SUCCESS == rc)
        {
            int result = EOK;
            boolean isEmpty = TRUE;

            pthread_mutex_lock(&pBufferList->m_bufferDoneQMutex);

            do {
                /*in case of abort*/
                if (pUsrCtxt->m_state != AIS_USR_STATE_STREAMING &&
                    pUsrCtxt->m_state != AIS_USR_STATE_RECOVERY_START &&
                    pUsrCtxt->m_state != AIS_USR_STATE_RECOVERY)
                {
                    AIS_LOG(ENGINE, ERROR, "abort called %d", pUsrCtxt->m_state);
                    rc = CAMERA_ENOMORE;
                    isEmpty = TRUE;
                    break;
                }

                rc = CameraQueueIsEmpty(pBufferList->m_bufferDoneQ, &isEmpty);

                if (isEmpty)
                {
                    if (QCARCAM_TIMEOUT_NO_WAIT == timeout)
                    {
                        rc = CAMERA_EEXPIRED;
                    }
                    else if (QCARCAM_TIMEOUT_INIFINITE == timeout)
                    {
                        //等待pBufferList->m_bufferDoneQCond,
                        //进行循环检测pBufferList->m_bufferDoneQ
                        result = pthread_cond_wait(&pBufferList->m_bufferDoneQCond,
                                &pBufferList->m_bufferDoneQMutex);
                    }
                    else
                    {
                        result = pthread_cond_timedwait(&pBufferList->m_bufferDoneQCond,
                                &pBufferList->m_bufferDoneQMutex, &to);
                    }
                }
                else
                {
                    //Something in Q, break out of loop
                    result = EOK;
                    break;
                }

                AIS_LOG(ENGINE, LOW, "ais_get_frame usrctxt %p(%d) isEmpty %d 
                          result %d rc %d",
                        pUsrCtxt, bufferlistId, isEmpty, result, rc);

            } while (isEmpty && (EOK == result) && rc == CAMERA_SUCCESS);

            if (EOK != result)
            {
                AIS_LOG(ENGINE, ERROR, "pthread_cond_wait failed: %s", strerror(result));
                rc = ERRNO_TO_RESULT(result);
            }
            else if(CAMERA_SUCCESS != rc)
            {
                AIS_LOG(ENGINE, ERROR, "CameraQueueIsEmpty call failed: %d", rc);
            }
            else if (!isEmpty)
            {  
               //获取pBufferList->m_bufferDoneQ中的数据到p_frame_info
                rc = CameraQueueDequeue(pBufferList->m_bufferDoneQ, p_frame_info);

                if (rc == CAMERA_SUCCESS)
                {
                    rc = pBufferList->SetBufferState(p_frame_info->idx, AIS_USER_ACQUIRED);

                    AIS_LOG(ENGINE, LOW, "usrctxt %p(%d) idx=%d", pUsrCtxt, bufferlistId, p_frame_info->idx);
                }
            }

            pthread_mutex_unlock(&pBufferList->m_bufferDoneQMutex);

        }
        PutUsrCtxt(pUsrCtxt);
    }
    else
    {
        AIS_LOG(ENGINE, ERROR, "Invalid hndl %p", hndl);
        rc = CAMERA_EBADHANDLE;
    }
    return rc;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1574342.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

卷积神经网络实战

构建卷积神经网络 卷积网络中的输入和层与传统神经网络有些区别&#xff0c;需重新设计&#xff0c;训练模块基本一致 1.首先读取数据 - 分别构建训练集和测试集&#xff08;验证集&#xff09; - DataLoader来迭代取数据 # 定义超参数 input_size 28 #图像的总尺寸28*28…

使用Springfox Swagger实现API自动生成单元测试

目录 第一步&#xff1a;在pom.xml中添加依赖 第二步&#xff1a;加入以下代码&#xff0c;并作出适当修改 第三步&#xff1a;在application.yaml中添加 第四步&#xff1a;添加注解 第五步&#xff1a;运行成功之后&#xff0c;访问相应网址 另外&#xff1a;还可以导出…

JavaScript代码小挑战

题目如下&#xff1a; 朱莉娅和凯特正在做一项关于狗的研究。于是&#xff0c;她们分别询问了 5 位狗主人他们的狗的年龄&#xff0c;并将数据存储到一个数组中&#xff08;每人一个数组&#xff09;。目前&#xff0c;她们只想知道一只狗是成年狗还是小狗。如果狗的年龄至少为…

算力在现实生活中的多方面应用!

算力在现实生活中的应用是多方面的&#xff0c;它已经成为推动现代社会发展的重要力量。 以下是算力在不同领域中的具体应用&#xff1a; 立即免费体验&#xff1a;https://gpumall.com/login?typeregister&sourcecsdn #分布式云服务#算力#GpuMall#GpuMall智算云#训练#…

【AI-3】Transformer

Transformer? Transformer是一个利用注意力机制来提高模型训练速度的模型&#xff0c;因其适用于并行化计算以及本身模型的复杂程度使其在精度和性能上都要高于之前流行的循环神经网络。 标准的Transformer结构如下图所示&#xff08;图来自知乎-慕文&#xff09;&#xff0c…

特征提取算法

特征提取算法 0. 写在前边1. Harris算法1.1 写在前面1.2 Harris算法的本质1.3 Harris算法的简化 2. Harris3D2.1 Harris3D算法问题定义2.2 Harris3D with intensity2.3 Harris3D without intensity 3. ISS特征点的应用 0. 写在前边 本篇将介绍几种特征提取算法&#xff0c;特征…

C++从入门到精通——类对象模型

类对象模型 前言一、如何计算类对象的大小问题 二、类对象的存储方式猜测对象中包含类的各个成员代码只保存一份&#xff0c;在对象中保存存放代码的地址只保存成员变量&#xff0c;成员函数存放在公共的代码段问题总结 三、结构体内存对齐规则四、例题结构体怎么对齐&#xff…

3D桌面端可视化引擎HOOPS Visualize如何实现3D应用快速开发?

HOOPS Visualize是一个开发平台&#xff0c;可实现高性能、跨平台3D工程应用程序的快速开发。一些主要功能包括&#xff1a; 高性能、以工程为中心的可视化&#xff0c;使用高度优化的OpenGL或DirectX驱动程序来充分利用可用的图形硬件线程安全的C和C#接口&#xff0c;内部利用…

mysql索引相关知识点

1. 索引是什么&#xff1f; 索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分)&#xff0c;它们包含着对数据表里所有记录的引用指针。 索引是一种数据结构。数据库索引&#xff0c;是数据库管理系统中一个排序的数据结构&#xff0c;以协助快速查询、更新数…

【Java业务需求解决方案】分布式锁应用详情,多种方案选择,轻松解决,手把手操作(非全数字编码依次加一问题)

背景&#xff1a; 现有编码格式为业务常量数字&#xff0c;每新增一条数据在基础上1,比如&#xff1a; 文件类型1 编码为ZS01 文件类型1下文件1 编码为ZS0101 文件类型1下文件2 编码为ZS0102 文件类型2 编码…

Vue - 3( 15000 字 Vue 入门级教程)

一&#xff1a;初识 Vue 1.1 收集表单数据 收集表单数据在Vue.js中是一个常见且重要的任务&#xff0c;它使得前端交互变得更加灵活和直观。 Vue中&#xff0c;我们通常使用v-model指令来实现表单元素与数据之间的双向绑定&#xff0c;从而实现数据的收集和更新。下面总结了…

Springboot引入swagger

讲在前面&#xff1a;在spring引入swagger时&#xff0c;由于使用的JDK、Spring、swagger 的版本不匹配&#xff0c;导致启动报错&#xff0c;一直存在版本依赖问题。所以在此声明清楚使用版本。JDK 1.8、Spring boot 2.6.13、 Swagger 2.9.2。 引入maven依赖 <dependency&…

【Canvas与艺术】绘制金色Brand Award品牌嘉奖奖章

【成果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>金色Brand Award品牌嘉奖</title><style type"text/…

WebGL异步绘制多点

异步绘制线段 1.先画一个点 2.一秒钟后&#xff0c;在左下角画一个点 3.两秒钟后&#xff0c;我再画一条线段 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"…

Games101-几何(基本表示方法)

几何分类 几何分类&#xff1a;隐式几何和显示几何 隐式几何&#xff1a;不会告诉空间中的点具体在哪&#xff0c;告诉这些点满足的一定关系。 如球的描述 x 2 y 2 z 2 1 x^2 y^2 z^2 1 x2y2z21 缺点&#xff1a;这个面都有哪些点是不容易看出来的&#xff0c;从上述的…

[Apple Vision Pro]开源项目 Beautiful Things App Template

1. 技术框架概述&#xff1a; - Beautiful Things App Template是一个为visionOS设计的免费开源软件&#xff08;FOSS&#xff09;&#xff0c;用于展示3D模型画廊。 2. 定位&#xff1a; - 该模板作为Beautiful Things网站的延伸&#xff0c;旨在为Apple Vision Pro用户…

从300亿分子中筛出6款,结构新且易合成,斯坦福抗生素设计AI模型登Nature子刊

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 全球每年有近 500 万人死于抗生素耐药性&#xff0c;因此迫切需要新的方法来对抗耐药菌株。 …

最具有影响力的三个视觉平台 | 3D高斯、场景重建、三维点云、工业3D视觉、SLAM、三维重建、自动驾驶

大家好&#xff0c;我是小柠檬 这里给大家推荐三个国内具有影响力的3D视觉方向平台&#xff01; 原文&#xff1a;最具有影响力的三个视觉平台 | 3D高斯、场景重建、三维点云、工业3D视觉、SLAM、三维重建、自动驾驶

青风环境带您了解2024第13届生物发酵展

参展企业介绍 浙江青风环境股份有限公司创立于1998年&#xff0c;是一家集科研、生产及贸易为一体的高新技术企业。公司座落于浙江省丽水市水阁工业区&#xff0c;占地面积120亩&#xff0c;建筑面积近11万平方米&#xff0c;年产值可达20亿元&#xff0c;建有标准的冷&#x…

【JAVASE】带你了解instanceof和equals的魅力

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;再无B&#xff5e;U&#xff5e;G-CSDN博客 1.instanceof instanceof 是 Java 的保留关键字。它的作用是测试…