Show a patch.

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

{
    "id": 23695,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/23695/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/23695/",
    "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": "<20250630150128.2435445-3-antoine.bouyer@nxp.com>",
    "date": "2025-06-30T15:01:28",
    "name": "[v3,2/2] pipeline: imx8-isi: Add multicamera support",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "098be2c767800f5456b70ded2ab31cffb9a68c66",
    "submitter": {
        "id": 218,
        "url": "https://patchwork.libcamera.org/api/1.1/people/218/?format=api",
        "name": "Antoine Bouyer",
        "email": "antoine.bouyer@nxp.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/23695/mbox/",
    "series": [
        {
            "id": 5258,
            "url": "https://patchwork.libcamera.org/api/1.1/series/5258/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5258",
            "date": "2025-06-30T15:01:26",
            "name": "pipeline: imx8-isi: Add multicamera support",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/5258/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/23695/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/23695/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 D147BBDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 30 Jun 2025 15:00:19 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id EB73D68E0F;\n\tMon, 30 Jun 2025 17:00:16 +0200 (CEST)",
            "from PA4PR04CU001.outbound.protection.outlook.com\n\t(mail-francecentralazlp170130007.outbound.protection.outlook.com\n\t[IPv6:2a01:111:f403:c20a::7])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 81B0568E0B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 30 Jun 2025 17:00:12 +0200 (CEST)",
            "from GVXPR04MB9831.eurprd04.prod.outlook.com (2603:10a6:150:11c::8)\n\tby AS5PR04MB9856.eurprd04.prod.outlook.com (2603:10a6:20b:678::13)\n\twith Microsoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8880.29;\n\tMon, 30 Jun 2025 15:00:10 +0000",
            "from GVXPR04MB9831.eurprd04.prod.outlook.com\n\t([fe80::4634:3d9c:c4a:641a]) by\n\tGVXPR04MB9831.eurprd04.prod.outlook.com\n\t([fe80::4634:3d9c:c4a:641a%5]) with mapi id 15.20.8880.024;\n\tMon, 30 Jun 2025 15:00:10 +0000"
        ],
        "Authentication-Results": [
            "lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxp.com header.i=@nxp.com header.b=\"dF2rdXH+\";\n\tdkim-atps=neutral",
            "dkim=none (message not signed)\n\theader.d=none;dmarc=none action=none header.from=nxp.com;"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;\n\tb=pvHz+TXChLJWtFzmBvb397DPFpL7SI1Z8zWL/Rk8ycByx6OH/hS4MSUiLgvMzBnvrlpJvWXYhULVRnTdNzCFQtibCVXH4QdRl9bOfafJVPYTpOwc3uAgz4FQ2cA/U7aVwWcK0jB9ifTSCY3M4Md6c3EYDXkq99Lo/kluycr/p2g25SaMxeCxXXk2Vte1z7g5J3pQBbH0PpAvPTGkcGCu/0RqpZlC8hwY1OAXT9XMlBZBGLrwx8djNRfPTvJv7bPlGE3ekYACOXVYjnGvD31r0km9RuUiTHlqaSldvHYGzpxVoSWGV3zqD0iW054wqvl1f8C9evN8mm3DIkbX6ei7Eg==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n\ts=arcselector10001;\n\th=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n\tbh=Ck0KVpu+pv0nQxaqCt/uQ+/L/sejm6Forh4S71njOB0=;\n\tb=bceq/GmpjEEpj8K3+GvwjXNLUwjAR81MJhudpk/9LsfHqDxS9SyGoqgD+EKtVms9kJlwfDnQSNpA+xgQ29LR+WxvxWF5kGNnuMvzyQinqYgTveWvk/qLTWPfTRfHihFiYxJeYXjqtHRUmj+Hho5pyGK4lPjJsiay1zImL3Mv8uNgClOo9T6ngbdW+1RAscaN4fQDn0NlmxEfTZnTTonmZ06PNrlxD4FgpUy8up21FJw5s1PujTPT+WMTEap+xvyGrw84PPygEZr2qfdw0Pa9nNmRabSF3SfOtFHE/qN+Q0TpDeqj5WCz+UBI0N6yHAfcEM4Ts1zHc8ppqJrqwXh/AA==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass\n\tsmtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com;\n\tdkim=pass header.d=nxp.com; arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1;\n\th=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n\tbh=Ck0KVpu+pv0nQxaqCt/uQ+/L/sejm6Forh4S71njOB0=;\n\tb=dF2rdXH+VVCqDDq7ZyNaBSIsAaeOtnHZATwAZ8IWkh5IZ6H8PsamUrfMlPGMMFlJIIxDv+m8E9VlI4oyau+k0pSfjx7y/scistAMjGt4yduNlmE6vX4sESufZ+I9mLEdNkGyIEGIWO4ucnfSX0fL1dEZE5b5vU4TSVq4FhAPYY7zKAXQ0AZc0PYGXmXqr4k8naE2xfBIG9R8X7AULjIX/j0IlAiwbYEPhtaFjZuU77fgSuCCbmZeGGMvtGDSAX6qlHHlxh/Q7fD3SVvv1YfdcLtFYqgoOWKv480sBc4bAjAnJgdNYYf8zghDbqT54fJuEnZ7/EAiNeyinS3uBv2/0g==",
        "From": "Antoine Bouyer <antoine.bouyer@nxp.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "julien.vuillaumier@nxp.com, Antoine Bouyer <antoine.bouyer@nxp.com>,\n\tLaurent Pinchart <laurent.pinchart@ideasonboard.com>",
        "Subject": "[PATCH v3 2/2] pipeline: imx8-isi: Add multicamera support",
        "Date": "Mon, 30 Jun 2025 17:01:28 +0200",
        "Message-Id": "<20250630150128.2435445-3-antoine.bouyer@nxp.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20250630150128.2435445-1-antoine.bouyer@nxp.com>",
        "References": "<20250630150128.2435445-1-antoine.bouyer@nxp.com>",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain",
        "X-ClientProxiedBy": "AM0PR02CA0120.eurprd02.prod.outlook.com\n\t(2603:10a6:20b:28c::17) To GVXPR04MB9831.eurprd04.prod.outlook.com\n\t(2603:10a6:150:11c::8)",
        "MIME-Version": "1.0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "GVXPR04MB9831:EE_|AS5PR04MB9856:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "112585bf-e063-4216-73b8-08ddb7e6cf5f",
        "X-LD-Processed": "686ea1d3-bc2b-4c6f-a92c-d99c5c301635,ExtAddr",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;\n\tARA:13230040|366016|52116014|376014|19092799006|1800799024|38350700014;",
        "X-Microsoft-Antispam-Message-Info": "6nn/QgZncJZymB/p8YlsCs8BUdUzHYAfeoZil6R8JmGr//iSBPf5rYB3TURWcNNfQQywbNfUXN4gfqyhS1RQENF7lJADWqhKzX0Ag4O61PptsGlptHhEzxvWuRkjuFUjeM3g/Fddk7+VnXePD53TqRoJrEHlj4s4PacnWnBqjWVXN9PMqzXL0pnS0xiNtSTcKQHw+jr/f4i+RneD2kKHtTMrYca9hbdAhKrRmu5e80o2OsVmY26GaBeGOvUX3p9xA4C8teINIre8WvLVTZFtV0eGzj6PMkHCM2Tjud/OYSpcN/jFsHV14r8mKd0H4J7BQyVXdKbP9CPHfjdALfFdLBiChmbHKgJUqMnZ7ghzeVFBz9RMyU7vW1/J7orSSL/hspT/P9A4aQQ896uXikpAif4YKXUDIErInRTp1cDB/IBecMhatbpOel5OMNk1TZNjOADO287HMQhx/MaidQWGviHjy0a10W+jmXazVXQunGRPXUa60/q3rGEyHnfiI46JW04goG831q+5IqWRV6rRKj3fX7Uai28dBgwCZ9zJZMWdEhmU0O9S9hU7EqrRGfWygxUioZlO3MLYNwp969sBY/TR6naMe6os464lzoKBgsWEnlnWkuqO7+wRDKy0SOgspouoBBPvRy0D32O8oA/mb0h9btR1McBvag8tfA4y58T/tbTFgCoBt2dk8Qyn5/bbhlMPUxYhg7Hsv6CrL0xRpgB4bnI+kcLWe69gD3+wBRrxIa6jiN2S+S2586TOTv14gbaXPtmDV9ogle7PobeU7xU6EYKhYsZa51JAx69QFUegg9XCPNx/3Z02QTkN/+IBLWZJILf+5y/7VnISV1nQHbbOL3zXH9bW6WsgZiwdSHI20C76VT5sOTeBY1hxxSjPAf8btVqNDQmRPkXl1/HmLod1mn/NDgPA99Zo5O01kdHqnLs+UKdOJNe5qsWCng/9MlRP3/swadvl5lCRHIy5L39WSRuCD5OdX60UkZIZrvCQJ0oXpEeq2lJOqtsFylEi+5RlQgujomhFX/KMrjJZHeYqVDpKmBu99Oa8mEDQmsGySKEO+tc+1QACsaeu5vfE3xUHF3+ZzlaKy7AJdhNfJUk8BfPbSsB3TVH1s3nFhFX2dwColOSeYyANgi9SUj4oKVqbWM6+ou9/bUtm5u2xJLnzP6E0jXiwkl66IFEgoxvUAgSrUNRukFkxVJIVvVNhi6YYw5kiMP4bsMCSPUvYFmu2x1pgBLu3m5J2VGGDeOtj3FVIWFicyFYayWGA9A0kRI/apCwCa4DsV4XrkF+T7EVliPce6Qt+gKe88M3ZZ192RRE4vXTOnj8TS2srjLxZ7fa+HY23/ybmWZJdhAiPRUFiQim4+2fTyf6dDUvXuvD8tINJYmd85OFIiHjud/iMeJy+5HqWL98+PI0xfTvlZkJGFmFTKkil7PnSM/rai0UUeocYh2DX/DQCRZrdm8ZkuTFwkC2fnhYbRcJy0zIzCg==",
        "X-Forefront-Antispam-Report": "CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:;\n\tIPV:NLI; SFV:NSPM; H:GVXPR04MB9831.eurprd04.prod.outlook.com; PTR:;\n\tCAT:NONE; \n\tSFS:(13230040)(366016)(52116014)(376014)(19092799006)(1800799024)(38350700014);\n\tDIR:OUT; SFP:1101; ",
        "X-MS-Exchange-AntiSpam-MessageData-ChunkCount": "1",
        "X-MS-Exchange-AntiSpam-MessageData-0": "P0xl107Z5q9TDtTtvps2TPo+CrwNGE0LNV24pCxTiX4inyqdXxtbBOoCa03WwLk3hWwdzdvT0WkgpJi3loTFZC9KGPhKmlidYElWQHixdLKElmzfyXbZJQYi2ob0CK0zNJ7zGjUfNPqxPlWA5R+iBnNa655r4L4SeUKR7dyZxpsjIg4hAyNX7DS/VrUV+fww++E3ILA65lmQx+ZLsG+vq8ADRwZigQ1lRf3w5FTzl3KC8K0xOqIN33yXeXuUPz/rc62Q2w/sm9WF5hJel5DRl2tctROA8YCIQAwkkkjZJ1bptjo3FUu8Ab+iRw42+vhK0Rhxt9P3h54FvAhfv8v28MyvWe5edqyle6U7ZDriLil+O2gxSES24BBY+WoSG3b08t0LnCwaUOB6KIVeR+cAg59eVHNkjrvU53AtROVt7qcAaiEiMft96fZkd6jSPRA1EDdczaVRWCjA/U1D4O6NgjOZnmZsKSc+G/QEas5UUdI0yprceEMsnVT4Gyx97sPZK+lsnroa/cG+03pB97zKIOTgpfeskYbORyZZSIsM6xabsRU5vzmOiJMA2efRY5ppNsKnjI4BVV6jcYlG3xz6YNAZL8/mK39nJljFc34W2tC3z7p80qmmv39yRIriFGQocE6wwXvcSv+lv5frn8iqDLR6+KqX4xVw0eoZzpIkhjQcI1pRnux9YouzXarWH8wHMf6zJAlbe9kqOALn6vJBRJ1EcNst4it2/M67Lxu1JvQJtG2cbZtYzK3WMvw/9EW3etVCQkj7ZoXheUDO3bAUZ4rQfpnP3eqF3o19sipNkw9c4xzmFKbnlCQYdFYBg7AnF4Rf7BC1TIred0f7A97yxyEfYrxXD02KMDLLjKRRP9oISO6KCLVeRmVEV9vBwJoxLnUFAUFmMG07ZPE54E9IuSm40s/vUy3GbcJO/bu7fJYItFDzA+QRf2VOliFtt9TKKM1PN0ogBJdtxY5mGAqF6iqm+3+9IlCMzcyxkhjonG85ospwLZjU0bu9Djb3hyI1bcOAt8uOp/SVDviBePpq3Hwco2W2Xp5eo39y8ej7SJRenI048IcDsV4h+Bp9TY5abMfm0LDgzPMl6ENAAJh9U9rx4V57b+tA6434FdU9Bn6KtEr/J5sxmUHcABqWQwSZTJNiEIyGu3dGoQz/o2Rm0CGYZrzrcbgI7eDhpZosleXz9fBsFEgVCzINihtDhPp82FEmGharpeNq6/L+g4M6wIIsdOnsYkTFuLjBmN2dcAYDUw265J0je1Hx16R10s2idm88L9/g3z+NJDM180LXGcQ6Cqd1Rh7C9UnRful/Cwyo6gDRdeoQWfnp7yDCBUWyTWGARjglK1/uskpHsF1fNYMzJxY6LhAPExg87Tz4XGj6/JeUKSq4deZiso5jdNO+I8gChivdSP28f1B18jfBXCBH+Xww47rTCjEFKfG+aeMGtm4YEluOa3R3uwTDnApEcveRIPoUDNDZlu5sq82DhBWm1DE2IPBxCGNxyHRQ2JQjNpeypMtMjMX5Sb8iJdcvsNeBiD39zfIqFi0ZjFn2qoFjuNcTbB7Q80jerNq29ILGwxXWLneif93pcmgikktONgjfw+hoV+ZZFVATRDRwYQ==",
        "X-OriginatorOrg": "nxp.com",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "112585bf-e063-4216-73b8-08ddb7e6cf5f",
        "X-MS-Exchange-CrossTenant-AuthSource": "GVXPR04MB9831.eurprd04.prod.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Internal",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "30 Jun 2025 15:00:10.7780\n\t(UTC)",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "Hosted",
        "X-MS-Exchange-CrossTenant-Id": "686ea1d3-bc2b-4c6f-a92c-d99c5c301635",
        "X-MS-Exchange-CrossTenant-MailboxType": "HOSTED",
        "X-MS-Exchange-CrossTenant-UserPrincipalName": "cHm9vpKeGsN3OWGrq4o35bIAkceotEnRrN8U2XI1z3V+eyGHHcp9ItyhGnjWCdHG9F/vNDDrLCtjrNLvuVx8wg==",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "AS5PR04MB9856",
        "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": "ISI can be used to support multiple cameras at the same time in the media\ndevice. A dedicated pad is assigned to each camera by HW (dts). We then\nassign one (or more) source pad(s) depending on ISI constraints in the SoC.\n\nSince ISI may have different number of pipes depending on SoC, the number\nof cameras is computed _before_ going through all pipeline's components,\nto limit number of pipes that could be assigned to a camera.\n\nFor instance, 3 is targeted as maximum amount of streams per camera as\ndefined by 'kNumStreams' constant. If 2 cameras are connected, with\nonly 5 ISI pipes, this target cannot be achieved. In such case, 2 streams\nare assigned to each camera.\n\nOn the other hand, if ISI has 8 source pads (from index 6 to 13) and 2\ncameras, first three source pads [6:8] are assigned to first camera, and\nthe three next source pads [9:11] are assigned to the second camera. All\nthese pads (sink and sources) must have same format to prevent configuration\nmismatch during start.\n\nHowever, since ISI routing must be performed _before_ any stream becomes\nactive, 'setRouting' is now executed during the 'match' step, instead of\n'configure'. Indeed, it is up to the application to decide when a camera\n'start' is executed: this could happen before or after the other camera\nconfiguration is executed. Moving routing into the 'match' step makes sure\nthe routing is correctly applied before any 'start' is executed.\n\nSigned-off-by: Antoine Bouyer <antoine.bouyer@nxp.com>\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n src/libcamera/pipeline/imx8-isi/imx8-isi.cpp | 112 ++++++++++++-------\n 1 file changed, 74 insertions(+), 38 deletions(-)",
    "diff": "diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\nindex 186b623df186..a29e361571a4 100644\n--- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n+++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n@@ -55,7 +55,7 @@ public:\n \n \tunsigned int pipeIndex(const Stream *stream)\n \t{\n-\t\treturn stream - &*streams_.begin();\n+\t\treturn stream - &*streams_.begin() + xbarSourceOffset_;\n \t}\n \n \tunsigned int getRawMediaBusFormat(PixelFormat *pixelFormat) const;\n@@ -69,7 +69,8 @@ public:\n \n \tstd::vector<Stream *> enabledStreams_;\n \n-\tunsigned int xbarSink_;\n+\tunsigned int xbarSink_ = 0;\n+\tunsigned int xbarSourceOffset_ = 0;\n };\n \n class ISICameraConfiguration : public CameraConfiguration\n@@ -809,34 +810,9 @@ int PipelineHandlerISI::configure(Camera *camera, CameraConfiguration *c)\n \tISICameraConfiguration *camConfig = static_cast<ISICameraConfiguration *>(c);\n \tISICameraData *data = cameraData(camera);\n \n-\t/* All links are immutable except the sensor -> csis link. */\n-\tconst MediaPad *sensorSrc = data->sensor_->entity()->getPadByIndex(0);\n-\tsensorSrc->links()[0]->setEnabled(true);\n-\n-\t/*\n-\t * Reset the crossbar switch routing and enable one route for each\n-\t * requested stream configuration.\n-\t *\n-\t * \\todo Handle concurrent usage of multiple cameras by adjusting the\n-\t * routing table instead of resetting it.\n-\t */\n-\tV4L2Subdevice::Routing routing = {};\n-\tunsigned int xbarFirstSource = crossbar_->entity()->pads().size() / 2 + 1;\n-\n-\tfor (const auto &[idx, config] : utils::enumerate(*c)) {\n-\t\tuint32_t sourcePad = xbarFirstSource + idx;\n-\t\trouting.emplace_back(V4L2Subdevice::Stream{ data->xbarSink_, 0 },\n-\t\t\t\t     V4L2Subdevice::Stream{ sourcePad, 0 },\n-\t\t\t\t     V4L2_SUBDEV_ROUTE_FL_ACTIVE);\n-\t}\n-\n-\tint ret = crossbar_->setRouting(&routing, V4L2Subdevice::ActiveFormat);\n-\tif (ret)\n-\t\treturn ret;\n-\n-\t/* Apply format to the sensor and CSIS receiver. */\n+\t/* Apply format to the sensor, CSIS receiver and crossbar sink pad. */\n \tV4L2SubdeviceFormat format = camConfig->sensorFormat_;\n-\tret = data->sensor_->setFormat(&format);\n+\tint ret = data->sensor_->setFormat(&format);\n \tif (ret)\n \t\treturn ret;\n \n@@ -848,10 +824,17 @@ int PipelineHandlerISI::configure(Camera *camera, CameraConfiguration *c)\n \tif (ret)\n \t\treturn ret;\n \n-\t/* Now configure the ISI and video node instances, one per stream. */\n-\tdata->enabledStreams_.clear();\n-\tfor (const auto &config : *c) {\n-\t\tPipe *pipe = pipeFromStream(camera, config.stream());\n+\t/*\n+\t * As links on the output of the crossbar switch are immutable, the\n+\t * routing table configured at match() time creates a media pipeline\n+\t * that includes all the ISI pipelines corresponding to streams of this\n+\t * camera, regardless of whether or not the streams are used in the\n+\t * camera configuration. Set the format on the sink pad of all\n+\t * corresponding ISI pipelines to avoid link validation failures when\n+\t * starting streaming on the media pipeline.\n+\t */\n+\tfor (unsigned i = 0; i < data->streams_.size(); i++) {\n+\t\tPipe *pipe = &pipes_.at(data->xbarSourceOffset_ + i);\n \n \t\t/*\n \t\t * Set the format on the ISI sink pad: it must match what is\n@@ -860,6 +843,15 @@ int PipelineHandlerISI::configure(Camera *camera, CameraConfiguration *c)\n \t\tret = pipe->isi->setFormat(0, &format);\n \t\tif (ret)\n \t\t\treturn ret;\n+\t}\n+\n+\t/*\n+\t * Now configure the ISI pipeline source pad and video node instances,\n+\t * one per enabled stream.\n+\t */\n+\tdata->enabledStreams_.clear();\n+\tfor (const auto &config : *c) {\n+\t\tPipe *pipe = pipeFromStream(camera, config.stream());\n \n \t\t/*\n \t\t * Configure the ISI sink compose rectangle to downscale the\n@@ -971,6 +963,20 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n \tif (!isiDev_)\n \t\treturn false;\n \n+\t/* Count the number of sensors, to create one camera per sensor. */\n+\tunsigned cameraCount = 0;\n+\tfor (MediaEntity *entity : isiDev_->entities()) {\n+\t\tif (entity->function() != MEDIA_ENT_F_CAM_SENSOR)\n+\t\t\tcontinue;\n+\n+\t\tcameraCount++;\n+\t}\n+\n+\tif (!cameraCount) {\n+\t\tLOG(ISI, Error) << \"No camera sensor found\";\n+\t\treturn false;\n+\t}\n+\n \t/*\n \t * Acquire the subdevs and video nodes for the crossbar switch and the\n \t * processing pipelines.\n@@ -1014,12 +1020,24 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n \t\treturn false;\n \t}\n \n+\tif (cameraCount > pipes_.size()) {\n+\t\tLOG(ISI, Error) << \"Too many cameras\";\n+\t\treturn false;\n+\t}\n+\n \t/*\n \t * Loop over all the crossbar switch sink pads to find connected CSI-2\n \t * receivers and camera sensors.\n+\t *\n+\t * In multicamera case, limit maximum amount of streams to allow all\n+\t * sensors to get at least one dedicated pipe.\n \t */\n \tunsigned int numCameras = 0;\n \tunsigned int numSinks = 0;\n+\tconst unsigned int xbarFirstSource = crossbar_->entity()->pads().size() - pipes_.size();\n+\tconst unsigned int maxStreams = pipes_.size() / cameraCount;\n+\tV4L2Subdevice::Routing routing = {};\n+\n \tfor (MediaPad *pad : crossbar_->entity()->pads()) {\n \t\tunsigned int sink = numSinks;\n \n@@ -1050,17 +1068,23 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n \t\t\tcontinue;\n \t\t}\n \n+\t\t/* All links are immutable except the sensor -> csis link. */\n+\t\tconst MediaPad *sensorSrc = sensor->getPadByIndex(0);\n+\t\tsensorSrc->links()[0]->setEnabled(true);\n+\n \t\t/* Create the camera data. */\n-\t\t/*\n-\t\t * \\todo compute available pipes per camera instead of using\n-\t\t * pipes_.size() for multi cameras case.\n-\t\t */\n \t\tstd::unique_ptr<ISICameraData> data =\n-\t\t\tstd::make_unique<ISICameraData>(this, pipes_.size());\n+\t\t\tstd::make_unique<ISICameraData>(this, maxStreams);\n \n \t\tdata->sensor_ = CameraSensorFactoryBase::create(sensor);\n \t\tdata->csis_ = std::make_unique<V4L2Subdevice>(csi);\n \t\tdata->xbarSink_ = sink;\n+\t\tdata->xbarSourceOffset_ = numCameras * data->streams_.size();\n+\n+\t\tLOG(ISI, Debug)\n+\t\t\t<< \"cam\" << numCameras\n+\t\t\t<< \" streams \" << data->streams_.size()\n+\t\t\t<< \" offset \" << data->xbarSourceOffset_;\n \n \t\tret = data->init();\n \t\tif (ret) {\n@@ -1075,6 +1099,14 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n \t\t\t       std::inserter(streams, streams.end()),\n \t\t\t       [](Stream &s) { return &s; });\n \n+\t\t/*  Add routes to the crossbar switch routing table. */\n+\t\tfor (unsigned i = 0; i < data->streams_.size(); i++) {\n+\t\t\tunsigned int sourcePad = xbarFirstSource + data->xbarSourceOffset_ + i;\n+\t\t\trouting.emplace_back(V4L2Subdevice::Stream{ data->xbarSink_, 0 },\n+\t\t\t\t\t     V4L2Subdevice::Stream{ sourcePad, 0 },\n+\t\t\t\t\t     V4L2_SUBDEV_ROUTE_FL_ACTIVE);\n+\t\t}\n+\n \t\tstd::shared_ptr<Camera> camera =\n \t\t\tCamera::create(std::move(data), id, streams);\n \n@@ -1082,6 +1114,10 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n \t\tnumCameras++;\n \t}\n \n+\tret = crossbar_->setRouting(&routing, V4L2Subdevice::ActiveFormat);\n+\tif (ret)\n+\t\treturn false;\n+\n \treturn numCameras > 0;\n }\n \n",
    "prefixes": [
        "v3",
        "2/2"
    ]
}