From patchwork Thu Jan 24 10:16:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 365 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8B13660C83 for ; Thu, 24 Jan 2019 11:17:00 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 15AEB2F6; Thu, 24 Jan 2019 11:17:00 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1548325020; bh=tEpCdsWCcinodfYHjd5vdST7yxot6qVoCMBXfxD8qqc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KQffT/pA0Dtd95bp4su86TtQBb4SVMq1KR178lT5h5hLbueS1F6aKUKTApvKU6bKD Xe98G0snownxu1CgDBombCdf6foU1tbpUvjE0obN7r+hPJ/TmiUaJE6XQ0gp2FtSU/ mwFSewpgCFCCh2xvY3JxFPDJWS0E4kSUD8ZgMGH0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 24 Jan 2019 12:16:51 +0200 Message-Id: <20190124101651.9993-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20190124101651.9993-1-laurent.pinchart@ideasonboard.com> References: <20190124101651.9993-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 10/10] libcamera: device_enumerator: Add hotplug support X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 24 Jan 2019 10:17:01 -0000 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 --- src/libcamera/device_enumerator.cpp | 83 ++++++++++++++++++++++- src/libcamera/include/device_enumerator.h | 6 ++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/libcamera/device_enumerator.cpp b/src/libcamera/device_enumerator.cpp index 149ffbf9aea6..703b03dd418a 100644 --- a/src/libcamera/device_enumerator.cpp +++ b/src/libcamera/device_enumerator.cpp @@ -11,6 +11,8 @@ #include #include +#include + #include "device_enumerator.h" #include "log.h" #include "media_device.h" @@ -243,11 +245,47 @@ 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 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 3f87a6255303..22ed8dedcb06 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> 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 */