[libcamera-devel,RFC,8/9] libcamera: pipeline_handler: Add function to acquire a USB device
diff mbox series

Message ID 20230808125228.29043-9-jacopo.mondi@ideasonboard.com
State New
Headers show
Series
  • libcamera: Generalize device match and support USB devices
Related show

Commit Message

Jacopo Mondi Aug. 8, 2023, 12:52 p.m. UTC
Add a function to the PipelineHandler base class to acquire a USB device
by providing a USBDeviceMatch class instance.

Support multiple CameraDevice derived classes by generalizing whenever
possible the device type in use.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
 include/libcamera/internal/pipeline_handler.h |  9 ++-
 src/libcamera/pipeline_handler.cpp            | 69 +++++++++++++++----
 2 files changed, 64 insertions(+), 14 deletions(-)

Patch
diff mbox series

diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
index 02b2f33727a3..b6b68aab1521 100644
--- a/include/libcamera/internal/pipeline_handler.h
+++ b/include/libcamera/internal/pipeline_handler.h
@@ -26,6 +26,7 @@  namespace libcamera {
 
 class Camera;
 class CameraConfiguration;
+class CameraDevice;
 class CameraManager;
 class DeviceEnumerator;
 class MediaDeviceMatch;
@@ -33,6 +34,8 @@  class FrameBuffer;
 class MediaDevice;
 class PipelineHandler;
 class Request;
+class USBDevice;
+class USBDeviceMatch;
 
 class PipelineHandler : public std::enable_shared_from_this<PipelineHandler>,
 			public Object
@@ -44,6 +47,8 @@  public:
 	virtual bool match(DeviceEnumerator *enumerator) = 0;
 	MediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator,
 					const MediaDeviceMatch &dm);
+	USBDevice *acquireUSBDevice(DeviceEnumerator *enumerator,
+				    const USBDeviceMatch &dm);
 
 	bool acquire();
 	void release(Camera *camera);
@@ -82,7 +87,7 @@  protected:
 	CameraManager *manager_;
 
 private:
-	void unlockMediaDevices();
+	void unlockCameraDevices();
 
 	void mediaDeviceDisconnected(MediaDevice *media);
 	virtual void disconnect();
@@ -90,7 +95,7 @@  private:
 	void doQueueRequest(Request *request);
 	void doQueueRequests();
 
-	std::vector<std::shared_ptr<MediaDevice>> mediaDevices_;
+	std::vector<std::shared_ptr<CameraDevice>> cameraDevices_;
 	std::vector<std::weak_ptr<Camera>> cameras_;
 
 	std::queue<Request *> waitingRequests_;
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index ca177cad985c..0b3e0fd8fa8b 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -27,6 +27,7 @@ 
 #include "libcamera/internal/media_device.h"
 #include "libcamera/internal/request.h"
 #include "libcamera/internal/tracepoints.h"
+#include "libcamera/internal/usb_device.h"
 
 /**
  * \file pipeline_handler.h
@@ -76,8 +77,8 @@  PipelineHandler::PipelineHandler(CameraManager *manager)
 
 PipelineHandler::~PipelineHandler()
 {
-	for (std::shared_ptr<MediaDevice> media : mediaDevices_)
-		media->release();
+	for (std::shared_ptr<CameraDevice> device : cameraDevices_)
+		device->release();
 }
 
 /**
@@ -139,11 +140,42 @@  MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
 	if (!media->acquire())
 		return nullptr;
 
-	mediaDevices_.push_back(media);
+	cameraDevices_.push_back(media);
 
 	return media.get();
 }
 
+/**
+ * \brief Search and acquire a USBDevice matching a device pattern
+ * \param[in] enumerator Enumerator containing all media devices in the system
+ * \param[in] dm Device match pattern
+ *
+ * Search the device \a enumerator for an available USB device matching the
+ * device match pattern \a dm. Matching devices that have previously been
+ * acquired by MediaDevice::acquire() are not considered. If a match is found,
+ * the USB device is acquired and returned. The caller shall not release the
+ * device explicitly, it will be automatically released when the pipeline
+ * handler is destroyed.
+ *
+ * \context This function shall be called from the CameraManager thread.
+ *
+ * \return A pointer to the matching USBDevice, or nullptr if no match is found
+ */
+USBDevice *PipelineHandler::acquireUSBDevice(DeviceEnumerator *enumerator,
+					     const USBDeviceMatch &dm)
+{
+	std::shared_ptr<USBDevice> usb = enumerator->search(dm);
+	if (!usb)
+		return nullptr;
+
+	if (!usb->acquire())
+		return nullptr;
+
+	cameraDevices_.push_back(usb);
+
+	return usb.get();
+}
+
 /**
  * \brief Acquire exclusive access to the pipeline handler for the process
  *
@@ -173,9 +205,9 @@  bool PipelineHandler::acquire()
 		return true;
 	}
 
-	for (std::shared_ptr<MediaDevice> &media : mediaDevices_) {
-		if (!media->lock()) {
-			unlockMediaDevices();
+	for (std::shared_ptr<CameraDevice> &device : cameraDevices_) {
+		if (!device->lock()) {
+			unlockCameraDevices();
 			return false;
 		}
 	}
@@ -206,7 +238,7 @@  void PipelineHandler::release(Camera *camera)
 
 	ASSERT(useCount_);
 
-	unlockMediaDevices();
+	unlockCameraDevices();
 
 	releaseDevice(camera);
 
@@ -224,10 +256,10 @@  void PipelineHandler::releaseDevice([[maybe_unused]] Camera *camera)
 {
 }
 
-void PipelineHandler::unlockMediaDevices()
+void PipelineHandler::unlockCameraDevices()
 {
-	for (std::shared_ptr<MediaDevice> &media : mediaDevices_)
-		media->unlock();
+	for (std::shared_ptr<CameraDevice> &device : cameraDevices_)
+		device->unlock();
 }
 
 /**
@@ -606,7 +638,7 @@  void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera)
 {
 	cameras_.push_back(camera);
 
-	if (mediaDevices_.empty())
+	if (cameraDevices_.empty())
 		LOG(Pipeline, Fatal)
 			<< "Registering camera with no media devices!";
 
@@ -615,7 +647,20 @@  void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera)
 	 * to the camera.
 	 */
 	std::vector<int64_t> devnums;
-	for (const std::shared_ptr<MediaDevice> &media : mediaDevices_) {
+	for (const std::shared_ptr<CameraDevice> &device : cameraDevices_) {
+		/*
+		 * Only MediaDevice has entities and devnums.
+		 *
+		 * FIXME: This code path "abuses" RTTI. In general, conditional
+		 * execution based on type information is discouraged and is
+		 * a symptom of a fragile design. However this could be
+		 * considered a temporary workaround, as USB-based devices
+		 * should report devnums as well in future.
+		 */
+		MediaDevice *media = dynamic_cast<MediaDevice *>(device.get());
+		if (!media)
+			continue;
+
 		for (const MediaEntity *entity : media->entities()) {
 			if (entity->pads().size() == 1 &&
 			    (entity->pads()[0]->flags() & MEDIA_PAD_FL_SINK) &&