summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ipa/vimc/vimc.cpp2
-rw-r--r--src/libcamera/base/file.cpp34
-rw-r--r--src/libcamera/ipa_manager.cpp2
-rw-r--r--src/libcamera/ipa_module.cpp6
4 files changed, 22 insertions, 22 deletions
diff --git a/src/ipa/vimc/vimc.cpp b/src/ipa/vimc/vimc.cpp
index 2f575853..0c0ee006 100644
--- a/src/ipa/vimc/vimc.cpp
+++ b/src/ipa/vimc/vimc.cpp
@@ -62,7 +62,7 @@ int IPAVimc::init(const IPASettings &settings)
<< settings.configurationFile;
File conf(settings.configurationFile);
- if (!conf.open(File::ReadOnly)) {
+ if (!conf.open(File::OpenModeFlag::ReadOnly)) {
LOG(IPAVimc, Error) << "Failed to open configuration file";
return -EINVAL;
}
diff --git a/src/libcamera/base/file.cpp b/src/libcamera/base/file.cpp
index 1c5879b3..ae4be1f9 100644
--- a/src/libcamera/base/file.cpp
+++ b/src/libcamera/base/file.cpp
@@ -45,9 +45,9 @@ LOG_DEFINE_CATEGORY(File)
/**
* \enum File::MapFlag
* \brief Flags for the File::map() function
- * \var File::MapNoOption
+ * \var File::MapFlag::NoOption
* \brief No option (used as default value)
- * \var File::MapPrivate
+ * \var File::MapFlag::Private
* \brief The memory region is mapped as private, changes are not reflected in
* the file constents
*/
@@ -60,13 +60,13 @@ LOG_DEFINE_CATEGORY(File)
/**
* \enum File::OpenModeFlag
* \brief Mode in which a file is opened
- * \var File::NotOpen
+ * \var File::OpenModeFlag::NotOpen
* \brief The file is not open
- * \var File::ReadOnly
+ * \var File::OpenModeFlag::ReadOnly
* \brief The file is open for reading
- * \var File::WriteOnly
+ * \var File::OpenModeFlag::WriteOnly
* \brief The file is open for writing
- * \var File::ReadWrite
+ * \var File::OpenModeFlag::ReadWrite
* \brief The file is open for reading and writing
*/
@@ -83,7 +83,7 @@ LOG_DEFINE_CATEGORY(File)
* before performing I/O operations.
*/
File::File(const std::string &name)
- : name_(name), fd_(-1), mode_(NotOpen), error_(0)
+ : name_(name), fd_(-1), mode_(OpenModeFlag::NotOpen), error_(0)
{
}
@@ -94,7 +94,7 @@ File::File(const std::string &name)
* setFileName().
*/
File::File()
- : fd_(-1), mode_(NotOpen), error_(0)
+ : fd_(-1), mode_(OpenModeFlag::NotOpen), error_(0)
{
}
@@ -173,8 +173,8 @@ bool File::open(File::OpenMode mode)
return false;
}
- int flags = static_cast<OpenMode::Type>(mode & ReadWrite) - 1;
- if (mode & WriteOnly)
+ int flags = static_cast<OpenMode::Type>(mode & OpenModeFlag::ReadWrite) - 1;
+ if (mode & OpenModeFlag::WriteOnly)
flags |= O_CREAT;
fd_ = ::open(name_.c_str(), flags, 0666);
@@ -214,7 +214,7 @@ void File::close()
::close(fd_);
fd_ = -1;
- mode_ = NotOpen;
+ mode_ = OpenModeFlag::NotOpen;
}
/**
@@ -374,8 +374,8 @@ ssize_t File::write(const Span<const uint8_t> &data)
* offset until the end of the file.
*
* The mapping memory protection is controlled by the file open mode, unless \a
- * flags contains MapPrivate in which case the region is mapped in read/write
- * mode.
+ * flags contains MapFlag::Private in which case the region is mapped in
+ * read/write mode.
*
* The error() status is updated.
*
@@ -398,14 +398,14 @@ Span<uint8_t> File::map(off_t offset, ssize_t size, File::MapFlags flags)
size -= offset;
}
- int mmapFlags = flags & MapPrivate ? MAP_PRIVATE : MAP_SHARED;
+ int mmapFlags = flags & MapFlag::Private ? MAP_PRIVATE : MAP_SHARED;
int prot = 0;
- if (mode_ & ReadOnly)
+ if (mode_ & OpenModeFlag::ReadOnly)
prot |= PROT_READ;
- if (mode_ & WriteOnly)
+ if (mode_ & OpenModeFlag::WriteOnly)
prot |= PROT_WRITE;
- if (flags & MapPrivate)
+ if (flags & MapFlag::Private)
prot |= PROT_WRITE;
void *map = mmap(NULL, size, prot, mmapFlags, fd_, offset);
diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp
index 55840896..771150ba 100644
--- a/src/libcamera/ipa_manager.cpp
+++ b/src/libcamera/ipa_manager.cpp
@@ -285,7 +285,7 @@ bool IPAManager::isSignatureValid([[maybe_unused]] IPAModule *ipa) const
}
File file{ ipa->path() };
- if (!file.open(File::ReadOnly))
+ if (!file.open(File::OpenModeFlag::ReadOnly))
return false;
Span<uint8_t> data = file.map();
diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp
index adfb8d40..7c52ad8d 100644
--- a/src/libcamera/ipa_module.cpp
+++ b/src/libcamera/ipa_module.cpp
@@ -275,7 +275,7 @@ IPAModule::~IPAModule()
int IPAModule::loadIPAModuleInfo()
{
File file{ libPath_ };
- if (!file.open(File::ReadOnly)) {
+ if (!file.open(File::OpenModeFlag::ReadOnly)) {
LOG(IPAModule, Error) << "Failed to open IPA library: "
<< strerror(-file.error());
return file.error();
@@ -317,13 +317,13 @@ int IPAModule::loadIPAModuleInfo()
/* Load the signature. Failures are not fatal. */
File sign{ libPath_ + ".sign" };
- if (!sign.open(File::ReadOnly)) {
+ if (!sign.open(File::OpenModeFlag::ReadOnly)) {
LOG(IPAModule, Debug)
<< "IPA module " << libPath_ << " is not signed";
return 0;
}
- data = sign.map(0, -1, File::MapPrivate);
+ data = sign.map(0, -1, File::MapFlag::Private);
signature_.resize(data.size());
memcpy(signature_.data(), data.data(), data.size());
='n331' href='#n331'>331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2018-2019, Google Inc.
 *
 * device_enumerator_udev.cpp - udev-based device enumerator
 */

#include "libcamera/internal/device_enumerator_udev.h"

#include <algorithm>
#include <fcntl.h>
#include <libudev.h>
#include <list>
#include <map>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/sysmacros.h>
#include <unistd.h>

#include <libcamera/base/event_notifier.h>
#include <libcamera/base/log.h>

#include "libcamera/internal/media_device.h"

namespace libcamera {

LOG_DECLARE_CATEGORY(DeviceEnumerator)

DeviceEnumeratorUdev::DeviceEnumeratorUdev()
	: udev_(nullptr), monitor_(nullptr), notifier_(nullptr)
{
}

DeviceEnumeratorUdev::~DeviceEnumeratorUdev()
{
	delete notifier_;

	if (monitor_)
		udev_monitor_unref(monitor_);
	if (udev_)
		udev_unref(udev_);
}

int DeviceEnumeratorUdev::init()
{
	int ret;

	if (udev_)
		return -EBUSY;

	udev_ = udev_new();
	if (!udev_)
		return -ENODEV;

	monitor_ = udev_monitor_new_from_netlink(udev_, "udev");
	if (!monitor_)
		return -ENODEV;

	ret = udev_monitor_filter_add_match_subsystem_devtype(monitor_, "media",
							      nullptr);
	if (ret < 0)
		return ret;

	ret = udev_monitor_filter_add_match_subsystem_devtype(monitor_, "video4linux",
							      nullptr);
	if (ret < 0)
		return ret;

	return 0;
}

int DeviceEnumeratorUdev::addUdevDevice(struct udev_device *dev)
{
	const char *subsystem = udev_device_get_subsystem(dev);
	if (!subsystem)
		return -ENODEV;

	if (!strcmp(subsystem, "media")) {
		std::unique_ptr<MediaDevice> media =
			createDevice(udev_device_get_devnode(dev));
		if (!media)
			return -ENODEV;

		DependencyMap deps;
		int ret = populateMediaDevice(media.get(), &deps);
		if (ret < 0) {
			LOG(DeviceEnumerator, Warning)
				<< "Failed to populate media device "
				<< media->deviceNode()
				<< " (" << media->driver() << "), skipping";
			return ret;
		}

		if (!deps.empty()) {
			LOG(DeviceEnumerator, Debug)
				<< "Defer media device " << media->deviceNode()
				<< " due to " << deps.size()
				<< " missing dependencies";

			pending_.emplace_back(std::move(media), std::move(deps));
			MediaDeviceDeps *mediaDeps = &pending_.back();
			for (const auto &dep : mediaDeps->deps_)
				devMap_[dep.first] = mediaDeps;

			return 0;
		}

		addDevice(std::move(media));
		return 0;
	}

	if (!strcmp(subsystem, "video4linux")) {
		addV4L2Device(udev_device_get_devnum(dev));
		return 0;
	}

	return -ENODEV;
}

int DeviceEnumeratorUdev::enumerate()
{
	struct udev_enumerate *udev_enum = nullptr;
	struct udev_list_entry *ents, *ent;
	int ret;

	udev_enum = udev_enumerate_new(udev_);
	if (!udev_enum)
		return -ENOMEM;

	ret = udev_enumerate_add_match_subsystem(udev_enum, "media");
	if (ret < 0)
		goto done;

	ret = udev_enumerate_add_match_subsystem(udev_enum, "video4linux");
	if (ret < 0)
		goto done;

	ret = udev_enumerate_add_match_is_initialized(udev_enum);
	if (ret < 0)
		goto done;

	ret = udev_enumerate_scan_devices(udev_enum);
	if (ret < 0)
		goto done;

	ents = udev_enumerate_get_list_entry(udev_enum);
	if (!ents)
		goto done;

	udev_list_entry_foreach(ent, ents) {
		struct udev_device *dev;
		const char *devnode;
		const char *syspath = udev_list_entry_get_name(ent);

		dev = udev_device_new_from_syspath(udev_, syspath);
		if (!dev) {
			LOG(DeviceEnumerator, Warning)
				<< "Failed to get device for '"
				<< syspath << "', skipping";
			continue;
		}

		devnode = udev_device_get_devnode(dev);
		if (!devnode) {
			udev_device_unref(dev);
			LOG(DeviceEnumerator, Warning)
				<< "Failed to get device node for '"
				<< syspath << "', skipping";
			continue;
		}

		if (addUdevDevice(dev) < 0)
			LOG(DeviceEnumerator, Warning)
				<< "Failed to add device for '"
				<< syspath << "', skipping";

		udev_device_unref(dev);
	}

done:
	udev_enumerate_unref(udev_enum);
	if (ret < 0)
		return ret;

	ret = udev_monitor_enable_receiving(monitor_);
	if (ret < 0)
		return ret;

	int fd = udev_monitor_get_fd(monitor_);
	notifier_ = new EventNotifier(fd, EventNotifier::Read);
	notifier_->activated.connect(this, &DeviceEnumeratorUdev::udevNotify);

	return 0;
}

int DeviceEnumeratorUdev::populateMediaDevice(MediaDevice *media, DependencyMap *deps)
{
	std::set<dev_t> children;

	/* Associate entities to device node paths. */
	for (MediaEntity *entity : media->entities()) {
		if (entity->deviceMajor() == 0 && entity->deviceMinor() == 0)
			continue;

		dev_t devnum = makedev(entity->deviceMajor(),
				       entity->deviceMinor());

		/*
		 * If the devnum isn't in the orphans list, add it to the unmet
		 * dependencies.
		 */
		if (orphans_.find(devnum) == orphans_.end()) {
			(*deps)[devnum].push_back(entity);
			continue;
		}

		/*
		 * Otherwise take it from the orphans list. Don't remove the
		 * entry from the list yet as other entities in this media
		 * device may need the same device.
		 */
		std::string deviceNode = lookupDeviceNode(devnum);
		if (deviceNode.empty())
			return -EINVAL;

		int ret = entity->setDeviceNode(deviceNode);
		if (ret)
			return ret;

		children.insert(devnum);
	}

	/* Remove all found children from the orphans list. */
	for (auto it = orphans_.begin(), last = orphans_.end(); it != last;) {
		if (children.find(*it) != children.end())
			it = orphans_.erase(it);
		else
			++it;
	}

	return 0;
}

/**
 * \brief Lookup device node path from device number
 * \param[in] devnum The device number
 *
 * Translate a device number given as \a devnum to a device node path.
 *
 * \return The device node path on success, or an empty string if the lookup
 * fails
 */
std::string DeviceEnumeratorUdev::lookupDeviceNode(dev_t devnum)
{
	struct udev_device *device;
	const char *name;
	std::string deviceNode = std::string();

	device = udev_device_new_from_devnum(udev_, 'c', devnum);
	if (!device)
		return std::string();

	name = udev_device_get_devnode(device);
	if (name)
		deviceNode = name;

	udev_device_unref(device);

	return deviceNode;
}

/**
 * \brief Add a V4L2 device to the media device that it belongs to
 * \param[in] devnum major:minor number of V4L2 device to add, as a dev_t
 *
 * Add V4L2 device identified by \a devnum to the MediaDevice that it belongs
 * to, if such a MediaDevice has been created. Otherwise add the V4L2 device
 * to the orphan list. If the V4L2 device is added to a MediaDevice, and it is
 * the last V4L2 device that the MediaDevice needs, then the MediaDevice is
 * added to the DeviceEnumerator, where it is available for pipeline handlers.
 *
 * \return 0 on success or a negative error code otherwise
 */
int DeviceEnumeratorUdev::addV4L2Device(dev_t devnum)
{
	/*
	 * If the devnum doesn't belong to any media device, add it to the
	 * orphans list.
	 */
	auto it = devMap_.find(devnum);
	if (it == devMap_.end()) {
		orphans_.insert(devnum);
		return 0;
	}

	/*
	 * Set the device node for all entities matching the devnum. Multiple
	 * entities can share the same device node, for instance for V4L2 M2M
	 * devices.
	 */
	std::string deviceNode = lookupDeviceNode(devnum);
	if (deviceNode.empty())
		return -EINVAL;

	MediaDeviceDeps *deps = it->second;
	for (MediaEntity *entity : deps->deps_[devnum]) {
		int ret = entity->setDeviceNode(deviceNode);
		if (ret)
			return ret;
	}

	/*
	 * Remove the devnum from the unmet dependencies for this media device.
	 * If no more dependency is unmet, add the media device to the
	 * enumerator.
	 */
	deps->deps_.erase(devnum);

	if (deps->deps_.empty()) {
		LOG(DeviceEnumerator, Debug)
			<< "All dependencies for media device "
			<< deps->media_->deviceNode() << " found";
		addDevice(std::move(deps->media_));
		pending_.remove(*deps);
	}

	return 0;
}

void DeviceEnumeratorUdev::udevNotify()
{
	struct udev_device *dev = udev_monitor_receive_device(monitor_);
	std::string action(udev_device_get_action(dev));
	std::string deviceNode(udev_device_get_devnode(dev));

	LOG(DeviceEnumerator, Debug)
		<< action << " device " << udev_device_get_devnode(dev);

	if (action == "add") {
		addUdevDevice(dev);
	} else if (action == "remove") {
		const char *subsystem = udev_device_get_subsystem(dev);
		if (subsystem && !strcmp(subsystem, "media"))
			removeDevice(deviceNode);
	}

	udev_device_unref(dev);
}

} /* namespace libcamera */