Show a patch.

GET /api/1.1/patches/20184/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 20184,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/20184/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/20184/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20240601220320.6484-4-laurent.pinchart@ideasonboard.com>",
    "date": "2024-06-01T22:03:20",
    "name": "[3/3] libcamera: v4l2_subdevice: Update to the new kernel routing API",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "598290f3955c0ee1657cda12b30b3bc6974e5388",
    "submitter": {
        "id": 2,
        "url": "https://patchwork.libcamera.org/api/1.1/people/2/?format=api",
        "name": "Laurent Pinchart",
        "email": "laurent.pinchart@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/20184/mbox/",
    "series": [
        {
            "id": 4349,
            "url": "https://patchwork.libcamera.org/api/1.1/series/4349/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4349",
            "date": "2024-06-01T22:03:17",
            "name": "libcamera: Update to the new upstream subdev routing API",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/4349/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/20184/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/20184/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id A0523BDE6B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat,  1 Jun 2024 22:03:43 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 624D2634CA;\n\tSun,  2 Jun 2024 00:03:42 +0200 (CEST)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 59B00634BA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun,  2 Jun 2024 00:03:38 +0200 (CEST)",
            "from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 692F74CC;\n\tSun,  2 Jun 2024 00:03:32 +0200 (CEST)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"oTZLzhIn\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1717279412;\n\tbh=g0zsmQbXY9F6a/PB4Nh4uTPb7wC+4ks6mX7ysJnIQzo=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=oTZLzhInZLyCYiPCsA3hxsLNc+7ignDWm6LK3f4iPInOilywhHv6iiAC6y+0OTo8D\n\taGKI1owdaB+cmbwwV02ugcIhC9jDlE1WKToh4eYn2ysHGzgM+XrVLx/S+TS12J6HBc\n\tPVoh1oXrfcYDzF8qY3DgYl45sRs1A+2shoUHHbq8=",
        "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tHans de Goede <hdegoede@redhat.com>",
        "Subject": "[PATCH 3/3] libcamera: v4l2_subdevice: Update to the new kernel\n\trouting API",
        "Date": "Sun,  2 Jun 2024 01:03:20 +0300",
        "Message-ID": "<20240601220320.6484-4-laurent.pinchart@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.44.2",
        "In-Reply-To": "<20240601220320.6484-1-laurent.pinchart@ideasonboard.com>",
        "References": "<20240601220320.6484-1-laurent.pinchart@ideasonboard.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "The subdev embedded data support series includes a change to the\nVIDIOC_SUBDEV_G_ROUTING and VIDIOC_SUBDEV_S_ROUTING ioctls that impacts\nthe userspace API.\n\nUpdate to the new API, while preserving backward compatibility to ease\nthe transition. Document the backward compatibility to only be supported\nfor two kernel releases. As the routing API isn't enabled in any\nupstream kernel yet, users of the API need kernel patches, and are\nexpected to be able to upgrade quickly.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\nChanges since combined RFC:\n\n- Drop -ENOTTY special handling in getRouting()\n- Preserve backward compatibility for a couple of kernel releases.\n---\n include/libcamera/internal/v4l2_subdevice.h |   3 +\n src/libcamera/v4l2_subdevice.cpp            | 121 +++++++++++++++++++-\n 2 files changed, 120 insertions(+), 4 deletions(-)",
    "diff": "diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h\nindex a1de0fb00ee3..194382f84d97 100644\n--- a/include/libcamera/internal/v4l2_subdevice.h\n+++ b/include/libcamera/internal/v4l2_subdevice.h\n@@ -176,6 +176,9 @@ private:\n \tstd::vector<SizeRange> enumPadSizes(const Stream &stream,\n \t\t\t\t\t    unsigned int code);\n \n+\tint getRoutingLegacy(Routing *routing, Whence whence);\n+\tint setRoutingLegacy(Routing *routing, Whence whence);\n+\n \tconst MediaEntity *entity_;\n \n \tstd::string model_;\ndiff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp\nindex 6da77775778f..e7be21d7250e 100644\n--- a/src/libcamera/v4l2_subdevice.cpp\n+++ b/src/libcamera/v4l2_subdevice.cpp\n@@ -1366,8 +1366,62 @@ void routeToKernel(const V4L2Subdevice::Route &route,\n \tkroute.flags = route.flags;\n }\n \n+/*\n+ * Legacy routing support for pre-v6.10-rc1 kernels. Drop when v6.12-rc1 gets\n+ * released.\n+ */\n+struct v4l2_subdev_routing_legacy {\n+\t__u32 which;\n+\t__u32 num_routes;\n+\t__u64 routes;\n+\t__u32 reserved[6];\n+};\n+\n+#define VIDIOC_SUBDEV_G_ROUTING_LEGACY\t_IOWR('V', 38, struct v4l2_subdev_routing_legacy)\n+#define VIDIOC_SUBDEV_S_ROUTING_LEGACY\t_IOWR('V', 39, struct v4l2_subdev_routing_legacy)\n+\n } /* namespace */\n \n+int V4L2Subdevice::getRoutingLegacy(Routing *routing, Whence whence)\n+{\n+\tstruct v4l2_subdev_routing_legacy rt = {};\n+\n+\trt.which = whence;\n+\n+\tint ret = ioctl(VIDIOC_SUBDEV_G_ROUTING_LEGACY, &rt);\n+\tif (ret == 0 || ret == -ENOTTY)\n+\t\treturn ret;\n+\n+\tif (ret != -ENOSPC) {\n+\t\tLOG(V4L2, Error)\n+\t\t\t<< \"Failed to retrieve number of routes: \"\n+\t\t\t<< strerror(-ret);\n+\t\treturn ret;\n+\t}\n+\n+\tstd::vector<struct v4l2_subdev_route> routes{ rt.num_routes };\n+\trt.routes = reinterpret_cast<uintptr_t>(routes.data());\n+\n+\tret = ioctl(VIDIOC_SUBDEV_G_ROUTING_LEGACY, &rt);\n+\tif (ret) {\n+\t\tLOG(V4L2, Error)\n+\t\t\t<< \"Failed to retrieve routes: \" << strerror(-ret);\n+\t\treturn ret;\n+\t}\n+\n+\tif (rt.num_routes != routes.size()) {\n+\t\tLOG(V4L2, Error) << \"Invalid number of routes\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\trouting->resize(rt.num_routes);\n+\n+\tfor (const auto &[i, route] : utils::enumerate(routes))\n+\t\trouteFromKernel((*routing)[i], route);\n+\n+\treturn 0;\n+}\n+\n /**\n  * \\brief Retrieve the subdevice's internal routing table\n  * \\param[out] routing The routing table\n@@ -1388,19 +1442,25 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence)\n \trt.which = whence;\n \n \tint ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt);\n-\tif (ret == 0 || ret == -ENOTTY)\n-\t\treturn ret;\n+\tif (ret == -ENOTTY)\n+\t\treturn V4L2Subdevice::getRoutingLegacy(routing, whence);\n \n-\tif (ret != -ENOSPC) {\n+\tif (ret) {\n \t\tLOG(V4L2, Error)\n \t\t\t<< \"Failed to retrieve number of routes: \"\n \t\t\t<< strerror(-ret);\n \t\treturn ret;\n \t}\n \n+\tif (!rt.num_routes)\n+\t\treturn 0;\n+\n \tstd::vector<struct v4l2_subdev_route> routes{ rt.num_routes };\n \trt.routes = reinterpret_cast<uintptr_t>(routes.data());\n \n+\trt.len_routes = rt.num_routes;\n+\trt.num_routes = 0;\n+\n \tret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt);\n \tif (ret) {\n \t\tLOG(V4L2, Error)\n@@ -1421,6 +1481,33 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence)\n \treturn 0;\n }\n \n+int V4L2Subdevice::setRoutingLegacy(Routing *routing, Whence whence)\n+{\n+\tstd::vector<struct v4l2_subdev_route> routes{ routing->size() };\n+\n+\tfor (const auto &[i, route] : utils::enumerate(*routing))\n+\t\trouteToKernel(route, routes[i]);\n+\n+\tstruct v4l2_subdev_routing_legacy rt = {};\n+\trt.which = whence;\n+\trt.num_routes = routes.size();\n+\trt.routes = reinterpret_cast<uintptr_t>(routes.data());\n+\n+\tint ret = ioctl(VIDIOC_SUBDEV_S_ROUTING_LEGACY, &rt);\n+\tif (ret) {\n+\t\tLOG(V4L2, Error) << \"Failed to set routes: \" << strerror(-ret);\n+\t\treturn ret;\n+\t}\n+\n+\troutes.resize(rt.num_routes);\n+\trouting->resize(rt.num_routes);\n+\n+\tfor (const auto &[i, route] : utils::enumerate(routes))\n+\t\trouteFromKernel((*routing)[i], route);\n+\n+\treturn 0;\n+}\n+\n /**\n  * \\brief Set a routing table on the V4L2 subdevice\n  * \\param[inout] routing The routing table\n@@ -1447,16 +1534,42 @@ int V4L2Subdevice::setRouting(Routing *routing, Whence whence)\n \n \tstruct v4l2_subdev_routing rt = {};\n \trt.which = whence;\n+\trt.len_routes = routes.size();\n \trt.num_routes = routes.size();\n \trt.routes = reinterpret_cast<uintptr_t>(routes.data());\n \n \tint ret = ioctl(VIDIOC_SUBDEV_S_ROUTING, &rt);\n+\tif (ret == -ENOTTY)\n+\t\treturn setRoutingLegacy(routing, whence);\n+\n \tif (ret) {\n \t\tLOG(V4L2, Error) << \"Failed to set routes: \" << strerror(-ret);\n \t\treturn ret;\n \t}\n \n-\troutes.resize(rt.num_routes);\n+\t/*\n+\t * The kernel wants to return more routes than we have space for. We\n+\t * need to issue a VIDIOC_SUBDEV_G_ROUTING call.\n+\t */\n+\tif (rt.num_routes > routes.size()) {\n+\t\troutes.resize(rt.num_routes);\n+\n+\t\trt.len_routes = rt.num_routes;\n+\t\trt.num_routes = 0;\n+\n+\t\tret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt);\n+\t\tif (ret) {\n+\t\t\tLOG(V4L2, Error)\n+\t\t\t\t<< \"Failed to retrieve routes: \" << strerror(-ret);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\tif (rt.num_routes != routes.size()) {\n+\t\tLOG(V4L2, Error) << \"Invalid number of routes\";\n+\t\treturn -EINVAL;\n+\t}\n+\n \trouting->resize(rt.num_routes);\n \n \tfor (const auto &[i, route] : utils::enumerate(routes))\n",
    "prefixes": [
        "3/3"
    ]
}