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;
}