[{"id":11883,"web_url":"https://patchwork.libcamera.org/comment/11883/","msgid":"<20200805134613.GD6751@pendragon.ideasonboard.com>","date":"2020-08-05T13:46:13","subject":"Re: [libcamera-devel] [PATCH v8 7/9] libcamera: pipeline: uvcvideo:\n\tGenerate unique camera names","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Niklas,\n\nThank you for the patch.\n\nOn Wed, Aug 05, 2020 at 12:48:58PM +0200, Niklas Söderlund wrote:\n> Generate camera names that are unique and persistent between system\n> resets. The name is constructed from the USB device information as well\n> as the USB controller on the host.\n> \n> Before this change example of camera names:\n> \n> Venus USB2.0 Camera: Venus USB2\n> Logitech Webcam C930e\n> \n> After 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> \n> On OF-based system:\n> \n> /base/soc/usb@7e980000/usb-port@1-1.2:1.0-0ac8:3420\n> \n> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> ---\n> * Changes since v7\n> - Rename function to generateId()\n> - Improve logic to generate deviceId\n> - Update format description of USB ID\n> - Fetch controllerId without using realpath()\n> - Order the generation of the different parts of the ID to match the\n>   order in the ID string :-)\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 | 75 +++++++++++++++++++-\n>  1 file changed, 74 insertions(+), 1 deletion(-)\n> \n> diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> index 93e3dc17e3a7105e..9f66844e40cb3cd3 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,69 @@ 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/* Create a controller ID from first device described in firmware. */\n> +\tstd::string controllerId;\n> +\tstd::string searchPath = path;\n> +\twhile (true) {\n> +\t\tstd::string::size_type pos = searchPath.rfind('/');\n> +\t\tif (pos <= 1) {\n> +\t\t\tLOG(UVC, Error) << \"Can not find controller ID\";\n> +\t\t\treturn {};\n> +\t\t}\n> +\n> +\t\tsearchPath = searchPath.substr(0, pos);\n> +\n> +\t\tcontrollerId = sysfs::firmwareNodePath(searchPath);\n> +\t\tif (!controllerId.empty())\n> +\t\t\tbreak;\n> +\t}\n> +\n> +\t/*\n> +\t * Create a USB ID from the device path which has the known format:\n> +\t *\n> +\t *\tpath = bus, \"-\", 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\nPlease use utils::basename(), as basename() is provided in different\nversions by different C libraries.\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> +\tusbId = usbId.substr(usbId.find('-') + 1);\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\tif (!deviceId.empty())\n> +\t\t\tdeviceId += \":\";\n> +\n> +\t\tdeviceId += value;\n> +\t}\n> +\n> +\treturn controllerId + \"-\" + usbId + \"-\" + deviceId;\n> +}\n> +\n>  bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)\n>  {\n>  \tMediaDevice *media;\n> @@ -405,8 +472,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. */","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 BC059BD86F\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  5 Aug 2020 13:46:27 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4AF2660599;\n\tWed,  5 Aug 2020 15:46:27 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E98BB6039D\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  5 Aug 2020 15:46:25 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 6730A2C0;\n\tWed,  5 Aug 2020 15:46:25 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"LhlS0uNm\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1596635185;\n\tbh=6NaEvIKja1DBWBrdIp4kOimPs2a9fFL7xlV5q2aq75o=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=LhlS0uNmJZSwIvebLoPF+aCZVMlAvRIl7P+7YjP18fDUwgs84w81BP9fNXXtHDbmI\n\tbbI+I28OfI8Pm/bDQgCQzfi7pBXsM1R9jcBUYWev72yFDA96ZKS9s8gIbvdaBYdu06\n\tuEopQpJq79G7swTEXeUttJnZEA4pMS5psyWc3I3w=","Date":"Wed, 5 Aug 2020 16:46:13 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","Message-ID":"<20200805134613.GD6751@pendragon.ideasonboard.com>","References":"<20200805104900.2172763-1-niklas.soderlund@ragnatech.se>\n\t<20200805104900.2172763-8-niklas.soderlund@ragnatech.se>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20200805104900.2172763-8-niklas.soderlund@ragnatech.se>","Subject":"Re: [libcamera-devel] [PATCH v8 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>","Cc":"libcamera-devel@lists.libcamera.org","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>"}}]