From patchwork Tue Aug 4 16:13:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 9190 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id B3A40BD87D for ; Tue, 4 Aug 2020 16:14:26 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1318E605AB; Tue, 4 Aug 2020 18:14:26 +0200 (CEST) Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C481660545 for ; Tue, 4 Aug 2020 18:14:24 +0200 (CEST) X-Halon-ID: 8f5e5ffc-d66d-11ea-b48b-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de [84.172.82.168]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 8f5e5ffc-d66d-11ea-b48b-0050569116f7; Tue, 04 Aug 2020 18:14:23 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= 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: Generate unique camera names X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Generate camera names that are unique and persistent between system resets. The name is constructed from the USB device information as well as the USB controller on the host. Before this change example of camera names: Venus USB2.0 Camera: Venus USB2 Logitech Webcam C930e After this change the same cameras are: \_SB_.PCI0.RP05.PXSX-2.1.1:1.0-0ac8:3420 \_SB_.PCI0.RP05.PXSX-2.4:1.0-046d:0843 On OF-based system: base/soc/usb@7e980000/usb-port@1-1.3:1.0-0ac8:3420 Signed-off-by: Niklas Söderlund --- * Changes since v5 - New algorithm to generate IDs. * Changes since v3 - Switch argument to generateName() to UVCCameraData pointer. --- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 77 +++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 93e3dc17e3a7105e..70c057b543f85c7b 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -20,6 +21,7 @@ #include "libcamera/internal/log.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/pipeline_handler.h" +#include "libcamera/internal/sysfs.h" #include "libcamera/internal/utils.h" #include "libcamera/internal/v4l2_controls.h" #include "libcamera/internal/v4l2_videodevice.h" @@ -81,6 +83,8 @@ public: bool match(DeviceEnumerator *enumerator) override; private: + std::string generateID(const UVCCameraData *data); + int processControl(ControlList *controls, unsigned int id, const ControlValue &value); int processControls(UVCCameraData *data, Request *request); @@ -379,6 +383,71 @@ int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request) return 0; } +std::string PipelineHandlerUVC::generateID(const UVCCameraData *data) +{ + const std::string path = data->video_->devicePath(); + + /* Creata a device ID from the USB devices vendor and product ID. */ + std::string deviceId; + for (const std::string &name : { "idVendor", "idProduct" }) { + std::ifstream file(path + "/../" + name); + + if (!file.is_open()) + return {}; + + std::string value; + std::getline(file, value); + file.close(); + + deviceId += value + (deviceId.empty() ? ":" : ""); + } + + /* + * Create a USB ID from the device path which has the known format: + * + * bus , "-", ports, ":", config, ".", interface ; + * bus = number ; + * ports = port, [ ".", ports ] ; + * port = number ; + * config = number ; + * interface = number ; + * + * Example: 3-2.4:1.0 + * + * The bus is not guaranteed to be stable and needs to be stripped from + * the USB ID. The final USB ID is built up of the ports, config and + * interface properties. + * + * Example 2.4:1.0. + */ + std::string usbId = basename(path.c_str()); + usbId = usbId.substr(usbId.find('-') + 1, std::string::npos); + + /* Create a controller ID from first device described in firmware. */ + std::string controllerId; + std::string searchPath = path; + while (true) { + searchPath += "/.."; + char *realPath = realpath(searchPath.c_str(), nullptr); + if (!realPath) { + LOG(UVC, Error) << "Failed to lookup " << searchPath; + return {}; + } + searchPath = realPath; + free(realPath); + + if (searchPath.empty() || searchPath == "/") { + LOG(UVC, Error) << "Can not find controller ID"; + return {}; + } + + if (!sysfs::firmwareId(searchPath, &controllerId)) + break; + } + + return controllerId + "-" + usbId + "-" + deviceId; +} + bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) { MediaDevice *media; @@ -405,8 +474,14 @@ bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) return false; /* Create and register the camera. */ + std::string id = generateID(data.get()); + if (id.empty()) { + LOG(UVC, Error) << "Failed to generate camera ID"; + return false; + } + std::set streams{ &data->stream_ }; - std::shared_ptr camera = Camera::create(this, media->model(), streams); + std::shared_ptr camera = Camera::create(this, id, streams); registerCamera(std::move(camera), std::move(data)); /* Enable hot-unplug notifications. */