[libcamera-devel,RFC,5/9] libcamera: device_enumerator_udev: Enumerate USB devices
diff mbox series

Message ID 20230808125228.29043-6-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 experimental support for USB device enumeration in the udev-based
device enumerator.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
 .../libcamera/internal/device_enumerator.h    |  5 +++
 .../internal/device_enumerator_udev.h         |  1 +
 src/libcamera/device_enumerator.cpp           | 21 ++++++++++++
 src/libcamera/device_enumerator_udev.cpp      | 32 +++++++++++++++++++
 4 files changed, 59 insertions(+)

Patch
diff mbox series

diff --git a/include/libcamera/internal/device_enumerator.h b/include/libcamera/internal/device_enumerator.h
index 8df6a3e2ac92..1d6dbcb104b8 100644
--- a/include/libcamera/internal/device_enumerator.h
+++ b/include/libcamera/internal/device_enumerator.h
@@ -18,6 +18,7 @@ 
 namespace libcamera {
 
 class MediaDevice;
+class USBDevice;
 
 class DeviceEnumerator
 {
@@ -38,8 +39,12 @@  protected:
 	void addMediaDevice(std::unique_ptr<MediaDevice> media);
 	void removeMediaDevice(const std::string &deviceNode);
 
+	void addUSBDevice(std::unique_ptr<USBDevice> usb);
+	/* \todo implement remove() */
+
 private:
 	std::vector<std::shared_ptr<MediaDevice>> mediaDevices_;
+	std::vector<std::shared_ptr<USBDevice>> usbDevices_;
 };
 
 } /* namespace libcamera */
diff --git a/include/libcamera/internal/device_enumerator_udev.h b/include/libcamera/internal/device_enumerator_udev.h
index 1b3360df31ba..e67ee31e0376 100644
--- a/include/libcamera/internal/device_enumerator_udev.h
+++ b/include/libcamera/internal/device_enumerator_udev.h
@@ -59,6 +59,7 @@  private:
 	std::string lookupDeviceNode(dev_t devnum);
 
 	int addV4L2Device(dev_t devnum);
+	int createUSBDevice(struct udev_device *dev);
 	void udevNotify();
 
 	struct udev *udev_;
diff --git a/src/libcamera/device_enumerator.cpp b/src/libcamera/device_enumerator.cpp
index 2ab731c68db9..1fde7367cfa8 100644
--- a/src/libcamera/device_enumerator.cpp
+++ b/src/libcamera/device_enumerator.cpp
@@ -7,6 +7,7 @@ 
 
 #include "libcamera/internal/device_enumerator.h"
 
+#include <algorithm>
 #include <string.h>
 
 #include <libcamera/base/log.h>
@@ -14,6 +15,7 @@ 
 #include "libcamera/internal/device_enumerator_sysfs.h"
 #include "libcamera/internal/device_enumerator_udev.h"
 #include "libcamera/internal/media_device.h"
+#include "libcamera/internal/usb_device.h"
 
 /**
  * \file device_enumerator.h
@@ -189,6 +191,25 @@  void DeviceEnumerator::addMediaDevice(std::unique_ptr<MediaDevice> media)
 	devicesAdded.emit();
 }
 
+void DeviceEnumerator::addUSBDevice(std::unique_ptr<USBDevice> usb)
+{
+	/*
+	 * This is a bit of an hack and could be improved!
+	 *
+	 * Can't use std::sort() + std::unique() because we're storing
+	 * unique_ptr<>
+	 */
+	for (const auto &dev : usbDevices_) {
+		if (dev->pid() == usb->pid() && dev->vid() == usb->vid())
+			return;
+	}
+
+	LOG(DeviceEnumerator, Debug)
+		<< "Added USB device " << usb->vid() << "-" << usb->pid();
+
+	usbDevices_.push_back(std::move(usb));
+}
+
 /**
  * \brief Remove a media device from the enumerator
  * \param[in] deviceNode Path to the media device to remove
diff --git a/src/libcamera/device_enumerator_udev.cpp b/src/libcamera/device_enumerator_udev.cpp
index 3cb0044a9434..ce4543698ed4 100644
--- a/src/libcamera/device_enumerator_udev.cpp
+++ b/src/libcamera/device_enumerator_udev.cpp
@@ -12,6 +12,7 @@ 
 #include <libudev.h>
 #include <list>
 #include <map>
+#include <memory>
 #include <string.h>
 #include <string_view>
 #include <sys/ioctl.h>
@@ -22,6 +23,7 @@ 
 #include <libcamera/base/log.h>
 
 #include "libcamera/internal/media_device.h"
+#include "libcamera/internal/usb_device.h"
 
 namespace libcamera {
 
@@ -115,6 +117,9 @@  int DeviceEnumeratorUdev::addUdevDevice(struct udev_device *dev)
 		return 0;
 	}
 
+	if (!strcmp(subsystem, "input"))
+		return createUSBDevice(dev);
+
 	return -ENODEV;
 }
 
@@ -136,6 +141,14 @@  int DeviceEnumeratorUdev::enumerate()
 	if (ret < 0)
 		goto done;
 
+	/*
+	 * FIXME: this should use the appoprtiate subsystem for USB cameras.
+	 * As a test, match on USB input devices.
+	 */
+	ret = udev_enumerate_add_match_subsystem(udev_enum, "input");
+	if (ret < 0)
+		goto done;
+
 	ret = udev_enumerate_add_match_is_initialized(udev_enum);
 	if (ret < 0)
 		goto done;
@@ -329,6 +342,25 @@  int DeviceEnumeratorUdev::addV4L2Device(dev_t devnum)
 	return 0;
 }
 
+int DeviceEnumeratorUdev::createUSBDevice(struct udev_device *dev)
+{
+	/* Get the USB parent device to get VID/PID information. */
+	struct udev_device *usb_device =
+		udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device");
+	if (!usb_device)
+		return -ENODEV;
+
+	const char *vid = udev_device_get_sysattr_value(usb_device, "idVendor");
+	const char *pid = udev_device_get_sysattr_value(usb_device, "idProduct");
+	if (!vid || !pid)
+		return -ENODEV;
+
+	std::unique_ptr<USBDevice> usbDev = std::make_unique<USBDevice>(vid, pid);
+	addUSBDevice(std::move(usbDev));
+
+	return 0;
+}
+
 void DeviceEnumeratorUdev::udevNotify()
 {
 	struct udev_device *dev = udev_monitor_receive_device(monitor_);