Show a patch.

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

{
    "id": 9190,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/9190/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/9190/",
    "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": "<20200804161358.1628962-8-niklas.soderlund@ragnatech.se>",
    "date": "2020-08-04T16:13:56",
    "name": "[libcamera-devel,v7,7/9] libcamera: pipeline: uvcvideo: Generate unique camera names",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "5dc9c297dc4987251877b4e13f7c5985a0806507",
    "submitter": {
        "id": 5,
        "url": "https://patchwork.libcamera.org/api/1.1/people/5/?format=api",
        "name": "Niklas Söderlund",
        "email": "niklas.soderlund@ragnatech.se"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/9190/mbox/",
    "series": [
        {
            "id": 1190,
            "url": "https://patchwork.libcamera.org/api/1.1/series/1190/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1190",
            "date": "2020-08-04T16:13:49",
            "name": "libcamera: Generate unique and stable camera IDs",
            "version": 7,
            "mbox": "https://patchwork.libcamera.org/series/1190/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/9190/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/9190/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 B3A40BD87D\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  4 Aug 2020 16:14:26 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1318E605AB;\n\tTue,  4 Aug 2020 18:14:26 +0200 (CEST)",
            "from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net\n\t[195.74.38.228])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C481660545\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  4 Aug 2020 18:14:24 +0200 (CEST)",
            "from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de\n\t[84.172.82.168]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA\n\tid 8f5e5ffc-d66d-11ea-b48b-0050569116f7;\n\tTue, 04 Aug 2020 18:14:23 +0200 (CEST)"
        ],
        "X-Halon-ID": "8f5e5ffc-d66d-11ea-b48b-0050569116f7",
        "Authorized-sender": "niklas@soderlund.pp.se",
        "From": "=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Tue,  4 Aug 2020 18:13:56 +0200",
        "Message-Id": "<20200804161358.1628962-8-niklas.soderlund@ragnatech.se>",
        "X-Mailer": "git-send-email 2.28.0",
        "In-Reply-To": "<20200804161358.1628962-1-niklas.soderlund@ragnatech.se>",
        "References": "<20200804161358.1628962-1-niklas.soderlund@ragnatech.se>",
        "MIME-Version": "1.0",
        "Subject": "[libcamera-devel] [PATCH v7 7/9] libcamera: pipeline: uvcvideo:\n\tGenerate unique camera names",
        "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>",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Generate camera names that are unique and persistent between system\nresets. The name is constructed from the USB device information as well\nas the USB controller on the host.\n\nBefore this change example of camera names:\n\nVenus USB2.0 Camera: Venus USB2\nLogitech Webcam C930e\n\nAfter this change the same cameras are:\n\n\\_SB_.PCI0.RP05.PXSX-2.1.1:1.0-0ac8:3420\n\\_SB_.PCI0.RP05.PXSX-2.4:1.0-046d:0843\n\nOn OF-based system:\n\nbase/soc/usb@7e980000/usb-port@1-1.3:1.0-0ac8:3420\n\nSigned-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\n* Changes since v5\n- New algorithm to generate IDs.\n\n* Changes since v3\n- Switch argument to generateName() to UVCCameraData pointer.\n---\n src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 77 +++++++++++++++++++-\n 1 file changed, 76 insertions(+), 1 deletion(-)",
    "diff": "diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\nindex 93e3dc17e3a7105e..70c057b543f85c7b 100644\n--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n@@ -6,6 +6,7 @@\n  */\n \n #include <algorithm>\n+#include <fstream>\n #include <iomanip>\n #include <math.h>\n #include <tuple>\n@@ -20,6 +21,7 @@\n #include \"libcamera/internal/log.h\"\n #include \"libcamera/internal/media_device.h\"\n #include \"libcamera/internal/pipeline_handler.h\"\n+#include \"libcamera/internal/sysfs.h\"\n #include \"libcamera/internal/utils.h\"\n #include \"libcamera/internal/v4l2_controls.h\"\n #include \"libcamera/internal/v4l2_videodevice.h\"\n@@ -81,6 +83,8 @@ public:\n \tbool match(DeviceEnumerator *enumerator) override;\n \n private:\n+\tstd::string generateID(const UVCCameraData *data);\n+\n \tint processControl(ControlList *controls, unsigned int id,\n \t\t\t   const ControlValue &value);\n \tint processControls(UVCCameraData *data, Request *request);\n@@ -379,6 +383,71 @@ int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request)\n \treturn 0;\n }\n \n+std::string PipelineHandlerUVC::generateID(const UVCCameraData *data)\n+{\n+\tconst std::string path = data->video_->devicePath();\n+\n+\t/* Creata a device ID from the USB devices vendor and product ID. */\n+\tstd::string deviceId;\n+\tfor (const std::string &name : { \"idVendor\", \"idProduct\" }) {\n+\t\tstd::ifstream file(path + \"/../\" + name);\n+\n+\t\tif (!file.is_open())\n+\t\t\treturn {};\n+\n+\t\tstd::string value;\n+\t\tstd::getline(file, value);\n+\t\tfile.close();\n+\n+\t\tdeviceId += value + (deviceId.empty() ? \":\" : \"\");\n+\t}\n+\n+\t/*\n+\t * Create a USB ID from the device path which has the known format:\n+\t *\n+\t *\tbus , \"-\", ports, \":\", config, \".\", interface ;\n+\t *\tbus = number ;\n+\t *\tports = port, [ \".\", ports ] ;\n+\t *\tport = number ;\n+\t *\tconfig = number ;\n+\t *\tinterface = number ;\n+\t *\n+\t * Example: 3-2.4:1.0\n+\t *\n+\t * The bus is not guaranteed to be stable and needs to be stripped from\n+\t * the USB ID. The final USB ID is built up of the ports, config and\n+\t * interface properties.\n+\t *\n+\t * Example 2.4:1.0.\n+\t */\n+\tstd::string usbId = basename(path.c_str());\n+\tusbId = usbId.substr(usbId.find('-') + 1, std::string::npos);\n+\n+\t/* Create a controller ID from first device described in firmware. */\n+\tstd::string controllerId;\n+\tstd::string searchPath = path;\n+\twhile (true) {\n+\t\tsearchPath += \"/..\";\n+\t\tchar *realPath = realpath(searchPath.c_str(), nullptr);\n+\t\tif (!realPath) {\n+\t\t\tLOG(UVC, Error) << \"Failed to lookup \" << searchPath;\n+\t\t\treturn {};\n+\t\t}\n+\t\tsearchPath = realPath;\n+\t\tfree(realPath);\n+\n+\t\tif (searchPath.empty() || searchPath == \"/\") {\n+\t\t\tLOG(UVC, Error) << \"Can not find controller ID\";\n+\t\t\treturn {};\n+\t\t}\n+\n+\t\tif (!sysfs::firmwareId(searchPath, &controllerId))\n+\t\t\tbreak;\n+\t}\n+\n+\treturn controllerId + \"-\" + usbId + \"-\" + deviceId;\n+}\n+\n bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)\n {\n \tMediaDevice *media;\n@@ -405,8 +474,14 @@ bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)\n \t\treturn false;\n \n \t/* Create and register the camera. */\n+\tstd::string id = generateID(data.get());\n+\tif (id.empty()) {\n+\t\tLOG(UVC, Error) << \"Failed to generate camera ID\";\n+\t\treturn false;\n+\t}\n+\n \tstd::set<Stream *> streams{ &data->stream_ };\n-\tstd::shared_ptr<Camera> camera = Camera::create(this, media->model(), streams);\n+\tstd::shared_ptr<Camera> camera = Camera::create(this, id, streams);\n \tregisterCamera(std::move(camera), std::move(data));\n \n \t/* Enable hot-unplug notifications. */\n",
    "prefixes": [
        "libcamera-devel",
        "v7",
        "7/9"
    ]
}