diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2019-01-06 12:19:24 +0200 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2019-01-25 01:59:29 +0200 |
commit | 0052aaa40e9d9c92f4ada41987f03015adf4953e (patch) | |
tree | 683f6bc5b2a3050540dbd19bcd47970f573a884a /src | |
parent | 4d84fa4fee4c138cc672715309de00dfbe4fc711 (diff) |
libcamera: device_enumerator: Add hotplug support
Create a udev_monitor in the udev device enumerator to listen to media
device disconnection, and emit the corresponding media device's
disconnect signal in response.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/libcamera/device_enumerator.cpp | 83 | ||||
-rw-r--r-- | src/libcamera/include/device_enumerator.h | 6 |
2 files changed, 88 insertions, 1 deletions
diff --git a/src/libcamera/device_enumerator.cpp b/src/libcamera/device_enumerator.cpp index 149ffbf9..703b03dd 100644 --- a/src/libcamera/device_enumerator.cpp +++ b/src/libcamera/device_enumerator.cpp @@ -11,6 +11,8 @@ #include <sys/ioctl.h> #include <unistd.h> +#include <libcamera/event_notifier.h> + #include "device_enumerator.h" #include "log.h" #include "media_device.h" @@ -243,12 +245,48 @@ int DeviceEnumerator::addDevice(const std::string &deviceNode) media->close(); + LOG(DeviceEnumerator, Debug) + << "Added device " << deviceNode << ": " << media->driver(); + devices_.push_back(std::move(media)); return 0; } /** + * \brief Remove a media device from the enumerator + * \param[in] deviceNode Path to the media device to remove + * + * Remove the media device identified by \a deviceNode previously added to the + * enumerator with addDevice(). The media device's MediaDevice::disconnected + * signal is emitted. + */ +void DeviceEnumerator::removeDevice(const std::string &deviceNode) +{ + std::shared_ptr<MediaDevice> media; + + for (auto iter = devices_.begin(); iter != devices_.end(); ++iter) { + if ((*iter)->deviceNode() == deviceNode) { + media = std::move(*iter); + devices_.erase(iter); + break; + } + } + + if (!media) { + LOG(DeviceEnumerator, Warning) + << "Media device for node " << deviceNode + << " not found"; + return; + } + + LOG(DeviceEnumerator, Debug) + << "Media device for node " << deviceNode << " removed."; + + media->disconnected.emit(media.get()); +} + +/** * \brief Search available media devices for a pattern match * \param[in] dm Search pattern * @@ -301,12 +339,18 @@ DeviceEnumeratorUdev::DeviceEnumeratorUdev() DeviceEnumeratorUdev::~DeviceEnumeratorUdev() { + delete notifier_; + + if (monitor_) + udev_monitor_unref(monitor_); if (udev_) udev_unref(udev_); } int DeviceEnumeratorUdev::init() { + int ret; + if (udev_) return -EBUSY; @@ -314,6 +358,15 @@ int DeviceEnumeratorUdev::init() 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; } @@ -365,7 +418,18 @@ int DeviceEnumeratorUdev::enumerate() } done: udev_enumerate_unref(udev_enum); - return ret >= 0 ? 0 : ret; + 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) @@ -389,4 +453,21 @@ std::string DeviceEnumeratorUdev::lookupDeviceNode(int major, int minor) 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(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 */ diff --git a/src/libcamera/include/device_enumerator.h b/src/libcamera/include/device_enumerator.h index 3f87a625..22ed8ded 100644 --- a/src/libcamera/include/device_enumerator.h +++ b/src/libcamera/include/device_enumerator.h @@ -16,6 +16,7 @@ namespace libcamera { +class EventNotifier; class MediaDevice; class DeviceMatch @@ -46,6 +47,7 @@ public: protected: int addDevice(const std::string &deviceNode); + void removeDevice(const std::string &deviceNode); private: std::vector<std::shared_ptr<MediaDevice>> devices_; @@ -64,8 +66,12 @@ public: private: struct udev *udev_; + struct udev_monitor *monitor_; + EventNotifier *notifier_; std::string lookupDeviceNode(int major, int minor) final; + + void udevNotify(EventNotifier *notifier); }; } /* namespace libcamera */ |