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>
This commit is contained in:
parent
4d84fa4fee
commit
0052aaa40e
2 changed files with 88 additions and 1 deletions
|
@ -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,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<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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue