[v2,1/1] libcamera: Add request API support for media controller device
diff mbox series

Message ID 20241106173651.2859827-2-chenghaoyang@chromium.org
State New
Headers show
Series
  • Add request API support for MediaDevice
Related show

Commit Message

Cheng-Hao Yang Nov. 6, 2024, 5:35 p.m. UTC
From: Han-Lin Chen <hanlinchen@chromium.org>

This patch adds `allocateRequest` with MEDIA_IOC_REQUEST_ALLOC in
MediaDevice, and introduces class MediaDevice::Request that allows users
to queue the request and be notified when the request is recycled.

Signed-off-by: Han-Lin Chen <hanlinchen@chromium.org>
Co-developed-by: Harvey Yang <chenghaoyang@chromium.org>
---
 include/libcamera/internal/media_device.h |  26 ++++++
 src/libcamera/media_device.cpp            | 106 ++++++++++++++++++++++
 2 files changed, 132 insertions(+)

Patch
diff mbox series

diff --git a/include/libcamera/internal/media_device.h b/include/libcamera/internal/media_device.h
index e412d3a0b..c7ac76440 100644
--- a/include/libcamera/internal/media_device.h
+++ b/include/libcamera/internal/media_device.h
@@ -13,6 +13,7 @@ 
 
 #include <linux/media.h>
 
+#include <libcamera/base/event_notifier.h>
 #include <libcamera/base/log.h>
 #include <libcamera/base/signal.h>
 #include <libcamera/base/unique_fd.h>
@@ -24,6 +25,29 @@  namespace libcamera {
 class MediaDevice : protected Loggable
 {
 public:
+	class Request : protected Loggable
+	{
+	public:
+		Request(MediaDevice *mediaDevice, UniqueFD fd);
+
+		int queueRequest();
+
+		int fd() const { return fd_.get(); }
+
+		Signal<Request *> recycled_;
+
+	protected:
+		std::string logPrefix() const override;
+
+	private:
+		void reinit();
+
+		MediaDevice *mediaDevice_;
+		UniqueFD fd_;
+
+		EventNotifier eventNotifier_;
+	};
+
 	MediaDevice(const std::string &deviceNode);
 	~MediaDevice();
 
@@ -53,6 +77,8 @@  public:
 	MediaLink *link(const MediaPad *source, const MediaPad *sink);
 	int disableLinks();
 
+	std::unique_ptr<Request> allocateRequest();
+
 	Signal<> disconnected;
 
 protected:
diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp
index d71dad74d..f25d05043 100644
--- a/src/libcamera/media_device.cpp
+++ b/src/libcamera/media_device.cpp
@@ -55,6 +55,91 @@  LOG_DEFINE_CATEGORY(MediaDevice)
  * managers to claim media devices they support during enumeration.
  */
 
+/**
+ * \class MediaDevice::Request
+ * \brief The request from a MediaDevice that supports request API
+ */
+
+/**
+ * \brief Construct a MediaDevice::Request
+ * \param[in] mediaDevice The MediaDevice instance that allocate this request
+ * \param[in] fd The request's fild descriptor
+ */
+MediaDevice::Request::Request(MediaDevice *mediaDevice, UniqueFD fd)
+	: mediaDevice_(mediaDevice), fd_(std::move(fd)),
+	  eventNotifier_(fd_.get(), EventNotifier::Type::Exception)
+{
+	eventNotifier_.activated.connect(this, &MediaDevice::Request::reinit);
+}
+
+std::string MediaDevice::Request::logPrefix() const
+{
+	return mediaDevice_->logPrefix() + " Request";
+}
+
+/**
+ * \brief Queue a request to the media device
+ *
+ * A request needs to be re-init'ed before being queued again. This class will
+ * notify the user with signal `recycled` when the request is re-init'ed.
+ *
+ * \sa reinit()
+ *
+ * \return 0 on success or a negative error code otherwise
+ */
+int MediaDevice::Request::queueRequest()
+{
+	int requestFd = fd_.get();
+	int ret = ioctl(requestFd, MEDIA_REQUEST_IOC_QUEUE, NULL);
+	if (ret) {
+		LOG(MediaDevice, Error) << "QueueRequest fd " << requestFd
+					<< "failed: " << strerror(-ret);
+		return ret;
+	}
+
+	eventNotifier_.setEnabled(true);
+
+	return ret;
+}
+
+/**
+ * \fn int MediaDevice::Request::fd()
+ * \return The request's file descriptor in int
+ */
+
+/**
+ * \var MediaDevice::Request::recycled_
+ * \brief The signal to notify the user when this request is recycled and ready
+ * to be queued again
+ *
+ * After this request is queued with `queueRequest()`, the user needs to wait
+ * for signal `recycled_` being emitted, before queueing this request again.
+ */
+
+/**
+ * \brief Re-init a request
+ *
+ * This function recycles a request that was queued before. It's triggered when
+ * `eventNotifier_` confirms the file descriptor is completed.
+ *
+ * \sa queueRequest()
+ */
+void MediaDevice::Request::reinit()
+{
+	eventNotifier_.setEnabled(false);
+
+	int requestFd = fd_.get();
+	int ret = ::ioctl(requestFd, MEDIA_REQUEST_IOC_REINIT, NULL);
+	if (ret) {
+		LOG(MediaDevice, Error) << "The request " << requestFd
+					<< " is queued but not yet completed: "
+					<< strerror(-ret);
+		return;
+	}
+
+	recycled_.emit(this);
+}
+
 /**
  * \brief Construct a MediaDevice
  * \param[in] deviceNode The media device node path
@@ -828,4 +913,25 @@  int MediaDevice::setupLink(const MediaLink *link, unsigned int flags)
 	return 0;
 }
 
+/**
+ * \brief Allocate a request from the media device
+ *
+ * This function returns a request containing a file descriptor if the
+ * MediaDevice supports request API.
+ *
+ * \return A request on success or nullptr otherwise
+ */
+std::unique_ptr<MediaDevice::Request> MediaDevice::allocateRequest()
+{
+	int fd;
+	int ret = ioctl(fd_.get(), MEDIA_IOC_REQUEST_ALLOC, &fd);
+	if (ret) {
+		LOG(MediaDevice, Error) << "Allocate request failed "
+					<< strerror(-ret);
+		return nullptr;
+	}
+
+	return std::make_unique<MediaDevice::Request>(this, UniqueFD(fd));
+}
+
 } /* namespace libcamera */