libcamera: Make libudev optional

libcamera depends on libudev for device enumeration. It is however
useful to allow building documentation without requiring the dependency
to be installed. Make the libudev dependency optional and compile the
udev-based device enumerator out when libudev is not present.

Note that while libcamera will compile without libudev, it will not be
able to enumerate devices. A sysfs-based device enumerator is planned as
a fallback but not implemented yet.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
Laurent Pinchart
2019-04-27 05:12:18 +03:00
parent c34e09d33a
commit df587aa100
8 changed files with 223 additions and 182 deletions
+1 -1
View File
@@ -80,7 +80,7 @@ int CameraManager::start()
return -EBUSY;
enumerator_ = DeviceEnumerator::create();
if (enumerator_->enumerate())
if (!enumerator_ || enumerator_->enumerate())
return -ENODEV;
/*
+3 -154
View File
@@ -6,14 +6,9 @@
*/
#include "device_enumerator.h"
#include "device_enumerator_udev.h"
#include <fcntl.h>
#include <libudev.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <libcamera/event_notifier.h>
#include "log.h"
#include "media_device.h"
@@ -148,13 +143,11 @@ std::unique_ptr<DeviceEnumerator> DeviceEnumerator::create()
{
std::unique_ptr<DeviceEnumerator> enumerator;
/**
* \todo Add compile time checks to only try udev enumerator if libudev
* is available.
*/
#ifdef HAVE_LIBUDEV
enumerator = utils::make_unique<DeviceEnumeratorUdev>();
if (!enumerator->init())
return enumerator;
#endif
/*
* Either udev is not available or udev initialization failed. Fall back
@@ -327,148 +320,4 @@ std::shared_ptr<MediaDevice> DeviceEnumerator::search(const DeviceMatch &dm)
* fails
*/
/**
* \class DeviceEnumeratorUdev
* \brief Device enumerator based on libudev
*/
DeviceEnumeratorUdev::DeviceEnumeratorUdev()
: udev_(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;
return 0;
}
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_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);
ret = -ENODEV;
goto done;
}
addDevice(devnode);
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;
}
std::string DeviceEnumeratorUdev::lookupDeviceNode(int major, int minor)
{
struct udev_device *device;
const char *name;
dev_t devnum;
std::string deviceNode = std::string();
devnum = makedev(major, minor);
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;
}
void DeviceEnumeratorUdev::udevNotify(EventNotifier *notifier)
{
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") {
addDevice(deviceNode);
} else if (action == "remove") {
removeDevice(deviceNode);
}
udev_device_unref(dev);
}
} /* namespace libcamera */
+163
View File
@@ -0,0 +1,163 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2018-2019, Google Inc.
*
* device_enumerator_udev.cpp - udev-based device enumerator
*/
#include "device_enumerator_udev.h"
#include <fcntl.h>
#include <libudev.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <libcamera/event_notifier.h>
#include "log.h"
namespace libcamera {
LOG_DECLARE_CATEGORY(DeviceEnumerator)
DeviceEnumeratorUdev::DeviceEnumeratorUdev()
: udev_(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;
return 0;
}
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_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);
ret = -ENODEV;
goto done;
}
addDevice(devnode);
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;
}
std::string DeviceEnumeratorUdev::lookupDeviceNode(int major, int minor)
{
struct udev_device *device;
const char *name;
dev_t devnum;
std::string deviceNode = std::string();
devnum = makedev(major, minor);
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;
}
void DeviceEnumeratorUdev::udevNotify(EventNotifier *notifier)
{
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") {
addDevice(deviceNode);
} else if (action == "remove") {
removeDevice(deviceNode);
}
udev_device_unref(dev);
}
} /* namespace libcamera */
-24
View File
@@ -7,19 +7,14 @@
#ifndef __LIBCAMERA_DEVICE_ENUMERATOR_H__
#define __LIBCAMERA_DEVICE_ENUMERATOR_H__
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <linux/media.h>
struct udev;
struct udev_monitor;
namespace libcamera {
class EventNotifier;
class MediaDevice;
class DeviceMatch
@@ -58,25 +53,6 @@ private:
virtual std::string lookupDeviceNode(int major, int minor) = 0;
};
class DeviceEnumeratorUdev: public DeviceEnumerator
{
public:
DeviceEnumeratorUdev();
~DeviceEnumeratorUdev();
int init() final;
int enumerate() final;
private:
struct udev *udev_;
struct udev_monitor *monitor_;
EventNotifier *notifier_;
std::string lookupDeviceNode(int major, int minor) final;
void udevNotify(EventNotifier *notifier);
};
} /* namespace libcamera */
#endif /* __LIBCAMERA_DEVICE_ENUMERATOR_H__ */
@@ -0,0 +1,42 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2018-2019, Google Inc.
*
* device_enumerator_udev.h - udev-based device enumerator
*/
#ifndef __LIBCAMERA_DEVICE_ENUMERATOR_UDEV_H__
#define __LIBCAMERA_DEVICE_ENUMERATOR_UDEV_H__
#include <string>
#include "device_enumerator.h"
struct udev;
struct udev_monitor;
namespace libcamera {
class EventNotifier;
class DeviceEnumeratorUdev : public DeviceEnumerator
{
public:
DeviceEnumeratorUdev();
~DeviceEnumeratorUdev();
int init() final;
int enumerate() final;
private:
struct udev *udev_;
struct udev_monitor *monitor_;
EventNotifier *notifier_;
std::string lookupDeviceNode(int major, int minor) final;
void udevNotify(EventNotifier *notifier);
};
} /* namespace libcamera */
#endif /* __LIBCAMERA_DEVICE_ENUMERATOR_UDEV_H__ */
+9 -1
View File
@@ -26,6 +26,7 @@ libcamera_sources = files([
libcamera_headers = files([
'include/camera_sensor.h',
'include/device_enumerator.h',
'include/device_enumerator_udev.h',
'include/event_dispatcher_poll.h',
'include/formats.h',
'include/log.h',
@@ -46,7 +47,14 @@ includes = [
subdir('pipeline')
libudev = dependency('libudev')
libudev = dependency('libudev', required: false)
if libudev.found()
config_h.set('HAVE_LIBUDEV', 1)
libcamera_sources += files([
'device_enumerator_udev.cpp',
])
endif
libcamera = shared_library('camera',
libcamera_sources,