libcamera: device_enumerator: add DeviceEnumeratorSysfs class
A udev-based device enumerator is not sufficient, since libudev is an optional dependency, or udev might fail. In these cases, we should fall back to using sysfs to enumerate devices. Add a DeviceEnumeratorSysfs class which is a specialization of DeviceEnumerator that uses sysfs to enumerate media devices on the system. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
05ff3d56e0
commit
977cfbd526
5 changed files with 142 additions and 3 deletions
|
@ -833,7 +833,9 @@ RECURSIVE = YES
|
|||
# Note that relative paths are relative to the directory from which doxygen is
|
||||
# run.
|
||||
|
||||
EXCLUDE = ../src/libcamera/device_enumerator_udev.cpp \
|
||||
EXCLUDE = ../src/libcamera/device_enumerator_sysfs.cpp \
|
||||
../src/libcamera/device_enumerator_udev.cpp \
|
||||
../src/libcamera/include/device_enumerator_sysfs.h \
|
||||
../src/libcamera/include/device_enumerator_udev.h \
|
||||
../src/libcamera/pipeline/
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include "device_enumerator.h"
|
||||
#include "device_enumerator_sysfs.h"
|
||||
#include "device_enumerator_udev.h"
|
||||
|
||||
#include <string.h>
|
||||
|
@ -153,8 +154,9 @@ std::unique_ptr<DeviceEnumerator> DeviceEnumerator::create()
|
|||
* Either udev is not available or udev initialization failed. Fall back
|
||||
* on the sysfs enumerator.
|
||||
*/
|
||||
|
||||
/** \todo Add a sysfs-based enumerator. */
|
||||
enumerator = utils::make_unique<DeviceEnumeratorSysfs>();
|
||||
if (!enumerator->init())
|
||||
return enumerator;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
105
src/libcamera/device_enumerator_sysfs.cpp
Normal file
105
src/libcamera/device_enumerator_sysfs.cpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019, Google Inc.
|
||||
*
|
||||
* device_enumerator_sysfs.cpp - sysfs-based device enumerator
|
||||
*/
|
||||
|
||||
#include "device_enumerator_sysfs.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <fstream>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
LOG_DECLARE_CATEGORY(DeviceEnumerator)
|
||||
|
||||
int DeviceEnumeratorSysfs::init()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DeviceEnumeratorSysfs::enumerate()
|
||||
{
|
||||
struct dirent *ent;
|
||||
DIR *dir;
|
||||
|
||||
static const char * const sysfs_dirs[] = {
|
||||
"/sys/subsystem/media/devices",
|
||||
"/sys/bus/media/devices",
|
||||
"/sys/class/media/devices",
|
||||
};
|
||||
|
||||
for (const char *dirname : sysfs_dirs) {
|
||||
dir = opendir(dirname);
|
||||
if (dir)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!dir) {
|
||||
LOG(DeviceEnumerator, Error)
|
||||
<< "No valid sysfs media device directory";
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
while ((ent = readdir(dir)) != nullptr) {
|
||||
if (strncmp(ent->d_name, "media", 5))
|
||||
continue;
|
||||
|
||||
char *end;
|
||||
unsigned int idx = strtoul(ent->d_name + 5, &end, 10);
|
||||
if (*end != '\0')
|
||||
continue;
|
||||
|
||||
std::string devnode = "/dev/media" + std::to_string(idx);
|
||||
|
||||
/* Verify that the device node exists. */
|
||||
struct stat devstat;
|
||||
if (stat(devnode.c_str(), &devstat) < 0) {
|
||||
LOG(DeviceEnumerator, Warning)
|
||||
<< "Device node /dev/media" << idx
|
||||
<< " should exist but doesn't";
|
||||
continue;
|
||||
}
|
||||
|
||||
addDevice(devnode);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string DeviceEnumeratorSysfs::lookupDeviceNode(int major, int minor)
|
||||
{
|
||||
std::string deviceNode;
|
||||
std::string line;
|
||||
std::ifstream ueventFile;
|
||||
|
||||
ueventFile.open("/sys/dev/char/" + std::to_string(major) + ":" +
|
||||
std::to_string(minor) + "/uevent");
|
||||
if (!ueventFile)
|
||||
return std::string();
|
||||
|
||||
while (ueventFile >> line) {
|
||||
if (line.find("DEVNAME=") == 0) {
|
||||
deviceNode = "/dev/" + line.substr(strlen("DEVNAME="));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ueventFile.close();
|
||||
|
||||
return deviceNode;
|
||||
}
|
||||
|
||||
} /* namespace libcamera */
|
28
src/libcamera/include/device_enumerator_sysfs.h
Normal file
28
src/libcamera/include/device_enumerator_sysfs.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019, Google Inc.
|
||||
*
|
||||
* device_enumerator_sysfs.h - sysfs-based device enumerator
|
||||
*/
|
||||
#ifndef __LIBCAMERA_DEVICE_ENUMERATOR_SYSFS_H__
|
||||
#define __LIBCAMERA_DEVICE_ENUMERATOR_SYSFS_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "device_enumerator.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
class DeviceEnumeratorSysfs final : public DeviceEnumerator
|
||||
{
|
||||
public:
|
||||
int init();
|
||||
int enumerate();
|
||||
|
||||
private:
|
||||
std::string lookupDeviceNode(int major, int minor);
|
||||
};
|
||||
|
||||
} /* namespace libcamera */
|
||||
|
||||
#endif /* __LIBCAMERA_DEVICE_ENUMERATOR_SYSFS_H__ */
|
|
@ -4,6 +4,7 @@ libcamera_sources = files([
|
|||
'camera_manager.cpp',
|
||||
'camera_sensor.cpp',
|
||||
'device_enumerator.cpp',
|
||||
'device_enumerator_sysfs.cpp',
|
||||
'event_dispatcher.cpp',
|
||||
'event_dispatcher_poll.cpp',
|
||||
'event_notifier.cpp',
|
||||
|
@ -26,6 +27,7 @@ libcamera_sources = files([
|
|||
libcamera_headers = files([
|
||||
'include/camera_sensor.h',
|
||||
'include/device_enumerator.h',
|
||||
'include/device_enumerator_sysfs.h',
|
||||
'include/device_enumerator_udev.h',
|
||||
'include/event_dispatcher_poll.h',
|
||||
'include/formats.h',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue