libcamera: media_device: Fallback to legacy ioctls on older kernels

Prior to kernel v4.19, the MEDIA_IOC_G_TOPOLOGY ioctl didn't expose
entity flags. Fallback to calling MEDIA_IOC_ENUM_ENTITIES for each
entity to retrieve the flags in that case.

Fixes: 67d313240c ("libcamera: pipeline: uvcvideo: create a V4L2Device for the default video entity")
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
Laurent Pinchart 2019-01-25 23:35:23 +02:00
parent ac0a3d7fb6
commit e4d2dcc549
2 changed files with 41 additions and 3 deletions

View file

@ -56,6 +56,8 @@ private:
std::string driver_; std::string driver_;
std::string deviceNode_; std::string deviceNode_;
std::string model_; std::string model_;
unsigned int version_;
int fd_; int fd_;
bool valid_; bool valid_;
bool acquired_; bool acquired_;
@ -72,6 +74,7 @@ private:
bool populateEntities(const struct media_v2_topology &topology); bool populateEntities(const struct media_v2_topology &topology);
bool populatePads(const struct media_v2_topology &topology); bool populatePads(const struct media_v2_topology &topology);
bool populateLinks(const struct media_v2_topology &topology); bool populateLinks(const struct media_v2_topology &topology);
void fixupEntityFlags(struct media_v2_entity *entity);
friend int MediaLink::setEnabled(bool enable); friend int MediaLink::setEnabled(bool enable);
int setupLink(const MediaLink *link, unsigned int flags); int setupLink(const MediaLink *link, unsigned int flags);

View file

@ -167,6 +167,7 @@ int MediaDevice::open()
driver_ = info.driver; driver_ = info.driver;
model_ = info.model; model_ = info.model;
version_ = info.media_version;
return 0; return 0;
} }
@ -553,20 +554,29 @@ bool MediaDevice::populateEntities(const struct media_v2_topology &topology)
(topology.ptr_entities); (topology.ptr_entities);
for (unsigned int i = 0; i < topology.num_entities; ++i) { for (unsigned int i = 0; i < topology.num_entities; ++i) {
struct media_v2_entity *ent = &mediaEntities[i];
/*
* The media_v2_entity structure was missing the flag field before
* v4.19.
*/
if (!MEDIA_V2_ENTITY_HAS_FLAGS(version_))
fixupEntityFlags(ent);
/* /*
* Find the interface linked to this entity to get the device * Find the interface linked to this entity to get the device
* node major and minor numbers. * node major and minor numbers.
*/ */
struct media_v2_interface *iface = struct media_v2_interface *iface =
findInterface(topology, mediaEntities[i].id); findInterface(topology, ent->id);
MediaEntity *entity; MediaEntity *entity;
if (iface) if (iface)
entity = new MediaEntity(this, &mediaEntities[i], entity = new MediaEntity(this, ent,
iface->devnode.major, iface->devnode.major,
iface->devnode.minor); iface->devnode.minor);
else else
entity = new MediaEntity(this, &mediaEntities[i]); entity = new MediaEntity(this, ent);
if (!addObject(entity)) { if (!addObject(entity)) {
delete entity; delete entity;
@ -657,6 +667,31 @@ bool MediaDevice::populateLinks(const struct media_v2_topology &topology)
return true; return true;
} }
/**
* \brief Fixup entity flags using the legacy API
* \param[in] entity The entity
*
* This function is used as a fallback to query entity flags using the legacy
* MEDIA_IOC_ENUM_ENTITIES ioctl when running on a kernel version that doesn't
* provide them through the MEDIA_IOC_G_TOPOLOGY ioctl.
*/
void MediaDevice::fixupEntityFlags(struct media_v2_entity *entity)
{
struct media_entity_desc desc = {};
desc.id = entity->id;
int ret = ioctl(fd_, MEDIA_IOC_ENUM_ENTITIES, &desc);
if (ret < 0) {
ret = -errno;
LOG(MediaDevice, Debug)
<< "Failed to retrieve information for entity "
<< entity->id << ": " << strerror(-ret);
return;
}
entity->flags = desc.flags;
}
/** /**
* \brief Apply \a flags to a link between two pads * \brief Apply \a flags to a link between two pads
* \param link The link to apply flags to * \param link The link to apply flags to