/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
* v4l2_camera_proxy.cpp - Proxy to V4L2 compatibility camera
*/
#include "v4l2_camera_proxy.h"
#include <algorithm>
#include <array>
#include <errno.h>
#include <linux/drm_fourcc.h>
#include <linux/videodev2.h>
#include <string.h>
#include <sys/mman.h>
#include <libcamera/camera.h>
#include <libcamera/object.h>
#include "log.h"
#include "utils.h"
#include "v4l2_camera.h"
#include "v4l2_compat_manager.h"
#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
using namespace libcamera;
LOG_DECLARE_CATEGORY(V4L2Compat);
V4L2CameraProxy::V4L2CameraProxy(unsigned int index,
std::shared_ptr<Camera> camera)
: refcount_(0), index_(index), bufferCount_(0), currentBuf_(0),
vcam_(std::make_unique<V4L2Camera>(camera))
{
querycap(camera);
}
int V4L2CameraProxy::open(bool nonBlocking)
{
LOG(V4L2Compat, Debug) << "Servicing open";
int ret = vcam_->invokeMethod(&V4L2Camera::open,
ConnectionTypeBlocking);
if (ret < 0) {
errno = -ret;
return -1;
}
nonBlocking_ = nonBlocking;
vcam_->invokeMethod(&V4L2Camera::getStreamConfig,
ConnectionTypeBlocking, &streamConfig_);
setFmtFromConfig(streamConfig_);
sizeimage_ = calculateSizeImage(streamConfig_);
refcount_++;
return 0;
}
void V4L2CameraProxy::dup()
{
refcount_++;
}
void V4L2CameraProxy::close()
{
LOG(V4L2Compat, Debug) << "Servicing close";
if (--refcount_ > 0)
return;
vcam_->invokeMethod(&V4L2Camera::close, ConnectionTypeBlocking);
}
void *V4L2CameraProxy::mmap(void *addr, size_t length, int prot, int flags,
off_t offset)
{
LOG(V4L2Compat, Debug) << "Servicing mmap";
/* \todo Validate prot and flags properly. */
if (prot != (PROT_READ | PROT_WRITE)) {
errno = EINVAL;
return MAP_FAILED;
}
unsigned int index = offset / sizeimage_;
if (index * sizeimage_ != offset || length != sizeimage_) {
errno = EINVAL;
return MAP_FAILED;
}
FileDescriptor fd = vcam_->getBufferFd(index);
if (!fd.isValid()) {
errno = EINVAL;
return MAP_FAILED;
}
void *map = V4L2CompatManager::instance()->fops().mmap(addr, length, prot,
flags, fd.fd(), 0);
if (map == MAP_FAILED)
return map;
buffers_[index].flags |= V4L2_BUF_FLAG_MAPPED;
mmaps_[map] = index;
return map;
|