#include "system/camerad/cameras/camera_util.h" #include #include #include #include "common/swaglog.h" #include "common/util.h" // ************** low level camera helpers **************** int do_cam_control(int fd, int op_code, void *handle, int size) { struct cam_control camcontrol = {0}; camcontrol.op_code = op_code; camcontrol.handle = (uint64_t)handle; if (size == 0) { camcontrol.size = 8; camcontrol.handle_type = CAM_HANDLE_MEM_HANDLE; } else { camcontrol.size = size; camcontrol.handle_type = CAM_HANDLE_USER_POINTER; } int ret = HANDLE_EINTR(ioctl(fd, VIDIOC_CAM_CONTROL, &camcontrol)); if (ret == -1) { LOGE("VIDIOC_CAM_CONTROL error: op_code %d - errno %d", op_code, errno); } return ret; } std::optional device_acquire(int fd, int32_t session_handle, void *data, uint32_t num_resources) { struct cam_acquire_dev_cmd cmd = { .session_handle = session_handle, .handle_type = CAM_HANDLE_USER_POINTER, .num_resources = (uint32_t)(data ? num_resources : 0), .resource_hdl = (uint64_t)data, }; int err = do_cam_control(fd, CAM_ACQUIRE_DEV, &cmd, sizeof(cmd)); return err == 0 ? std::make_optional(cmd.dev_handle) : std::nullopt; } int device_config(int fd, int32_t session_handle, int32_t dev_handle, uint64_t packet_handle) { struct cam_config_dev_cmd cmd = { .session_handle = session_handle, .dev_handle = dev_handle, .packet_handle = packet_handle, }; return do_cam_control(fd, CAM_CONFIG_DEV, &cmd, sizeof(cmd)); } int device_control(int fd, int op_code, int session_handle, int dev_handle) { // start stop and release are all the same struct cam_start_stop_dev_cmd cmd { .session_handle = session_handle, .dev_handle = dev_handle }; return do_cam_control(fd, op_code, &cmd, sizeof(cmd)); } void *alloc_w_mmu_hdl(int video0_fd, int len, uint32_t *handle, int align, int flags, int mmu_hdl, int mmu_hdl2) { struct cam_mem_mgr_alloc_cmd mem_mgr_alloc_cmd = {0}; mem_mgr_alloc_cmd.len = len; mem_mgr_alloc_cmd.align = align; mem_mgr_alloc_cmd.flags = flags; mem_mgr_alloc_cmd.num_hdl = 0; if (mmu_hdl != 0) { mem_mgr_alloc_cmd.mmu_hdls[0] = mmu_hdl; mem_mgr_alloc_cmd.num_hdl++; } if (mmu_hdl2 != 0) { mem_mgr_alloc_cmd.mmu_hdls[1] = mmu_hdl2; mem_mgr_alloc_cmd.num_hdl++; } do_cam_control(video0_fd, CAM_REQ_MGR_ALLOC_BUF, &mem_mgr_alloc_cmd, sizeof(mem_mgr_alloc_cmd)); *handle = mem_mgr_alloc_cmd.out.buf_handle; void *ptr = NULL; if (mem_mgr_alloc_cmd.out.fd > 0) { ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, mem_mgr_alloc_cmd.out.fd, 0); assert(ptr != MAP_FAILED); } // LOGD("allocated: %x %d %llx mapped %p", mem_mgr_alloc_cmd.out.buf_handle, mem_mgr_alloc_cmd.out.fd, mem_mgr_alloc_cmd.out.vaddr, ptr); return ptr; } void release(int video0_fd, uint32_t handle) { int ret; struct cam_mem_mgr_release_cmd mem_mgr_release_cmd = {0}; mem_mgr_release_cmd.buf_handle = handle; ret = do_cam_control(video0_fd, CAM_REQ_MGR_RELEASE_BUF, &mem_mgr_release_cmd, sizeof(mem_mgr_release_cmd)); assert(ret == 0); } void release_fd(int video0_fd, uint32_t handle) { // handle to fd close(handle>>16); release(video0_fd, handle); } void *MemoryManager::alloc_buf(int size, uint32_t *handle) { lock.lock(); void *ptr; if (!cached_allocations[size].empty()) { ptr = cached_allocations[size].front(); cached_allocations[size].pop(); *handle = handle_lookup[ptr]; } else { ptr = alloc_w_mmu_hdl(video0_fd, size, handle); handle_lookup[ptr] = *handle; size_lookup[ptr] = size; } lock.unlock(); return ptr; } void MemoryManager::free(void *ptr) { lock.lock(); cached_allocations[size_lookup[ptr]].push(ptr); lock.unlock(); } MemoryManager::~MemoryManager() { for (auto& x : cached_allocations) { while (!x.second.empty()) { void *ptr = x.second.front(); x.second.pop(); LOGD("freeing cached allocation %p with size %d", ptr, size_lookup[ptr]); munmap(ptr, size_lookup[ptr]); release_fd(video0_fd, handle_lookup[ptr]); handle_lookup.erase(ptr); size_lookup.erase(ptr); } } }