diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2024-02-28 22:30:22 +0200 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2024-06-03 12:18:25 +0300 |
commit | 6cd17515ffeb67fb38ffcc4d57aadf9732b54800 (patch) | |
tree | 00e785a2cb253b0614a38b727f708a321164f0ce | |
parent | 70d553812eb40dd5f48f9e35b90610926842c802 (diff) |
libcamera: v4l2_subdevice: Update to the new kernel routing API
The subdev embedded data support series includes a change to the
VIDIOC_SUBDEV_G_ROUTING and VIDIOC_SUBDEV_S_ROUTING ioctls that impacts
the userspace API.
Update to the new API, while preserving backward compatibility to ease
the transition. Document the backward compatibility to only be supported
for two kernel releases. As the routing API isn't enabled in any
upstream kernel yet, users of the API need kernel patches, and are
expected to be able to upgrade quickly.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
-rw-r--r-- | include/libcamera/internal/v4l2_subdevice.h | 3 | ||||
-rw-r--r-- | src/libcamera/v4l2_subdevice.cpp | 122 |
2 files changed, 121 insertions, 4 deletions
diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h index a1de0fb0..194382f8 100644 --- a/include/libcamera/internal/v4l2_subdevice.h +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -176,6 +176,9 @@ private: std::vector<SizeRange> enumPadSizes(const Stream &stream, unsigned int code); + int getRoutingLegacy(Routing *routing, Whence whence); + int setRoutingLegacy(Routing *routing, Whence whence); + const MediaEntity *entity_; std::string model_; diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 6da77775..82824433 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -1366,8 +1366,62 @@ void routeToKernel(const V4L2Subdevice::Route &route, kroute.flags = route.flags; } +/* + * Legacy routing support for pre-v6.10-rc1 kernels. Drop when v6.12-rc1 gets + * released. + */ +struct v4l2_subdev_routing_legacy { + __u32 which; + __u32 num_routes; + __u64 routes; + __u32 reserved[6]; +}; + +#define VIDIOC_SUBDEV_G_ROUTING_LEGACY _IOWR('V', 38, struct v4l2_subdev_routing_legacy) +#define VIDIOC_SUBDEV_S_ROUTING_LEGACY _IOWR('V', 39, struct v4l2_subdev_routing_legacy) + } /* namespace */ +int V4L2Subdevice::getRoutingLegacy(Routing *routing, Whence whence) +{ + struct v4l2_subdev_routing_legacy rt = {}; + + rt.which = whence; + + int ret = ioctl(VIDIOC_SUBDEV_G_ROUTING_LEGACY, &rt); + if (ret == 0 || ret == -ENOTTY) + return ret; + + if (ret != -ENOSPC) { + LOG(V4L2, Error) + << "Failed to retrieve number of routes: " + << strerror(-ret); + return ret; + } + + std::vector<struct v4l2_subdev_route> routes{ rt.num_routes }; + rt.routes = reinterpret_cast<uintptr_t>(routes.data()); + + ret = ioctl(VIDIOC_SUBDEV_G_ROUTING_LEGACY, &rt); + if (ret) { + LOG(V4L2, Error) + << "Failed to retrieve routes: " << strerror(-ret); + return ret; + } + + if (rt.num_routes != routes.size()) { + LOG(V4L2, Error) << "Invalid number of routes"; + return -EINVAL; + } + + routing->resize(rt.num_routes); + + for (const auto &[i, route] : utils::enumerate(routes)) + routeFromKernel((*routing)[i], route); + + return 0; +} + /** * \brief Retrieve the subdevice's internal routing table * \param[out] routing The routing table @@ -1388,19 +1442,25 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) rt.which = whence; int ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); - if (ret == 0 || ret == -ENOTTY) - return ret; + if (ret == -ENOTTY) + return V4L2Subdevice::getRoutingLegacy(routing, whence); - if (ret != -ENOSPC) { + if (ret) { LOG(V4L2, Error) << "Failed to retrieve number of routes: " << strerror(-ret); return ret; } + if (!rt.num_routes) + return 0; + std::vector<struct v4l2_subdev_route> routes{ rt.num_routes }; rt.routes = reinterpret_cast<uintptr_t>(routes.data()); + rt.len_routes = rt.num_routes; + rt.num_routes = 0; + ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); if (ret) { LOG(V4L2, Error) @@ -1421,6 +1481,33 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) return 0; } +int V4L2Subdevice::setRoutingLegacy(Routing *routing, Whence whence) +{ + std::vector<struct v4l2_subdev_route> routes{ routing->size() }; + + for (const auto &[i, route] : utils::enumerate(*routing)) + routeToKernel(route, routes[i]); + + struct v4l2_subdev_routing_legacy rt = {}; + rt.which = whence; + rt.num_routes = routes.size(); + rt.routes = reinterpret_cast<uintptr_t>(routes.data()); + + int ret = ioctl(VIDIOC_SUBDEV_S_ROUTING_LEGACY, &rt); + if (ret) { + LOG(V4L2, Error) << "Failed to set routes: " << strerror(-ret); + return ret; + } + + routes.resize(rt.num_routes); + routing->resize(rt.num_routes); + + for (const auto &[i, route] : utils::enumerate(routes)) + routeFromKernel((*routing)[i], route); + + return 0; +} + /** * \brief Set a routing table on the V4L2 subdevice * \param[inout] routing The routing table @@ -1447,16 +1534,43 @@ int V4L2Subdevice::setRouting(Routing *routing, Whence whence) struct v4l2_subdev_routing rt = {}; rt.which = whence; + rt.len_routes = routes.size(); rt.num_routes = routes.size(); rt.routes = reinterpret_cast<uintptr_t>(routes.data()); int ret = ioctl(VIDIOC_SUBDEV_S_ROUTING, &rt); + if (ret == -ENOTTY) + return setRoutingLegacy(routing, whence); + if (ret) { LOG(V4L2, Error) << "Failed to set routes: " << strerror(-ret); return ret; } - routes.resize(rt.num_routes); + /* + * The kernel may want to return more routes than we have space for. In + * that event, we must issue a VIDIOC_SUBDEV_G_ROUTING call to retrieve + * the additional routes. + */ + if (rt.num_routes > routes.size()) { + routes.resize(rt.num_routes); + + rt.len_routes = rt.num_routes; + rt.num_routes = 0; + + ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); + if (ret) { + LOG(V4L2, Error) + << "Failed to retrieve routes: " << strerror(-ret); + return ret; + } + } + + if (rt.num_routes != routes.size()) { + LOG(V4L2, Error) << "Invalid number of routes"; + return -EINVAL; + } + routing->resize(rt.num_routes); for (const auto &[i, route] : utils::enumerate(routes)) |