Patch Detail
Show a patch.
GET /api/patches/24638/?format=api
{ "id": 24638, "url": "https://patchwork.libcamera.org/api/patches/24638/?format=api", "web_url": "https://patchwork.libcamera.org/patch/24638/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/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": "<20251014133404.3194952-2-paul.elder@ideasonboard.com>", "date": "2025-10-14T13:34:01", "name": "[v5,1/2] libcamera: control_serializer: Add array info to serialized ControlValue", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "7998fa78afed99ab2686babd26a6f09ced7c9642", "submitter": { "id": 17, "url": "https://patchwork.libcamera.org/api/people/17/?format=api", "name": "Paul Elder", "email": "paul.elder@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/24638/mbox/", "series": [ { "id": 5501, "url": "https://patchwork.libcamera.org/api/series/5501/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5501", "date": "2025-10-14T13:34:00", "name": "Fix ControlSerializer deserializing array controls", "version": 5, "mbox": "https://patchwork.libcamera.org/series/5501/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/24638/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/24638/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 6D631BE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 14 Oct 2025 13:34:27 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A048A605FA;\n\tTue, 14 Oct 2025 15:34:25 +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 DB9F3605DF\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 14 Oct 2025 15:34:23 +0200 (CEST)", "from neptunite.hamster-moth.ts.net (unknown\n\t[IPv6:2404:7a81:160:2100:946a:ef2f:f966:b71d])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 2E946C7B;\n\tTue, 14 Oct 2025 15:32:43 +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=\"EGVO/0UE\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1760448765;\n\tbh=e34LF+ryXjas6P/w+VyTV2IMngMaBxns3qPqeqQbiQI=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=EGVO/0UEytE87ydPCyQiDPZpeRXLUTLVIhoIIVvqAdflati0cKByNMQPPVCvEqKeI\n\tB/cA8m9dv8RH5EgkfJ1USaCtQWGQgQSBP9lko+jWWn/86TnPinQZy+4V/T2r32snUj\n\tOyFN42srq+quPDdLyXa9r7mg/FtNNyFw9LTXCz0E=", "From": "Paul Elder <paul.elder@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Paul Elder <paul.elder@ideasonboard.com>, =?utf-8?q?Barnab=C3=A1s_P?=\n\t=?utf-8?b?xZFjemU=?= <barnabas.pocze@ideasonboard.com>", "Subject": "[PATCH v5 1/2] libcamera: control_serializer: Add array info to\n\tserialized ControlValue", "Date": "Tue, 14 Oct 2025 22:34:01 +0900", "Message-ID": "<20251014133404.3194952-2-paul.elder@ideasonboard.com>", "X-Mailer": "git-send-email 2.47.2", "In-Reply-To": "<20251014133404.3194952-1-paul.elder@ideasonboard.com>", "References": "<20251014133404.3194952-1-paul.elder@ideasonboard.com>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "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": "Array controls (eg. ColourCorrectionMatrix, FrameDurationLimits,\nColourGains) are serialized properly by the ControlSerializer, but are\nnot deserialized properly. This is because their arrayness and size are\nnot considered during deserialization.\n\nFix this by adding arrayness and size to the serialized form of all\nControlValues. This is achieved by fully serializing the min/max/def\nControlValue's metadata associated with each ControlInfo entry in the\nControlInfoMap.\n\nWhile at it, clean up the serialization format of ControlValues and\nControlLists:\n- ControlValue's id is only used by ControlList, so add a new struct for\n ControlList entries to contain it, and remove id from ControlValue\n- Remove offset from ControlInfo's entry, as it is no longer needed,\n since the serialized data of a ControlInfo has now been converted to\n simply three serialized ControlValues\n- Remove the type from the serialized data of ControlValue, as it is\n already in the metadata entry\n\nThe issue regarding array controls was not noticed before because the\ndefault value of the ControlInfo of other array controls had been set to\nscalar values similar to how min/max are set, and ColourCorrectionMatrix\nwas the first control to properly define a non-scalar default value.\n\nBug: https://bugs.libcamera.org/show_bug.cgi?id=285\nSigned-off-by: Paul Elder <paul.elder@ideasonboard.com>\nTested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> # rkisp1\n\n---\nChanges in v5:\n- re/move reserved fields in ipa_controls.h\n- remote default parameters from loadControlValue\n- fix binarySize of ControlValue\n\nChanges in v4:\n- remove id from ipa_control_value_entry, as it is only used by\n ControlList\n - move id into a new struct ipa_control_list_entry\n- remove offset from ipa_control_info_entry, as it is no longer used\n - since ControlInfo is no longer serialized, and instead it is three\n ControlValues serialized individually\n- remove type from the serialized data portion of ControlValue, as the\n information is in the metadata entries\n- error-check the offsets when deserializing ControlInfoMap\n\nChanges in v3:\n- instead of adding an extra header to store isArray and numElements\n like in v2, just reuse struct ipa_control_value_entry, and add these\n entries to the serialized form of ControlInfoMap to store information\n for each of the three ControlValues that make of min and max and def\n in ControlInfoMap\n\nChanges in v2:\n- make it so that the *serialized form* of ControlValue includes\n arrayness and size instead\n - Compared to v1, this ties the arrayness and size information to\n ControlValue instead of ControlId, which as a side effect allows us\n to support scalar and array min/max values, not just def values.\n This also gives us support for variable-length arrays\n---\n .../libcamera/internal/control_serializer.h | 8 +-\n include/libcamera/ipa/ipa_controls.h | 11 +-\n src/libcamera/control_serializer.cpp | 119 ++++++++++++------\n src/libcamera/ipa_controls.cpp | 20 ++-\n 4 files changed, 108 insertions(+), 50 deletions(-)", "diff": "diff --git a/include/libcamera/internal/control_serializer.h b/include/libcamera/internal/control_serializer.h\nindex 8a63ae44a13e..307ecba572fc 100644\n--- a/include/libcamera/internal/control_serializer.h\n+++ b/include/libcamera/internal/control_serializer.h\n@@ -47,9 +47,13 @@ private:\n \tstatic void store(const ControlValue &value, ByteStreamBuffer &buffer);\n \tstatic void store(const ControlInfo &info, ByteStreamBuffer &buffer);\n \n+\tvoid populateControlValueEntry(struct ipa_control_value_entry &entry,\n+\t\t\t\t const ControlValue &value,\n+\t\t\t\t uint32_t offset);\n+\n \tControlValue loadControlValue(ByteStreamBuffer &buffer,\n-\t\t\t\t bool isArray = false, unsigned int count = 1);\n-\tControlInfo loadControlInfo(ByteStreamBuffer &buffer);\n+\t\t\t\t ControlType type,\n+\t\t\t\t bool isArray, unsigned int count);\n \n \tunsigned int serial_;\n \tunsigned int serialSeed_;\ndiff --git a/include/libcamera/ipa/ipa_controls.h b/include/libcamera/ipa/ipa_controls.h\nindex 980668c86bcc..ecdf6051ffd9 100644\n--- a/include/libcamera/ipa/ipa_controls.h\n+++ b/include/libcamera/ipa/ipa_controls.h\n@@ -15,7 +15,7 @@ namespace libcamera {\n extern \"C\" {\n #endif\n \n-#define IPA_CONTROLS_FORMAT_VERSION\t1\n+#define IPA_CONTROLS_FORMAT_VERSION\t2\n \n enum ipa_controls_id_map_type {\n \tIPA_CONTROL_ID_MAP_CONTROLS,\n@@ -34,20 +34,25 @@ struct ipa_controls_header {\n };\n \n struct ipa_control_value_entry {\n-\tuint32_t id;\n \tuint8_t type;\n \tuint8_t is_array;\n \tuint16_t count;\n \tuint32_t offset;\n \tuint32_t padding[1];\n+\tuint32_t reserved;\n+};\n+\n+struct ipa_control_list_entry {\n+\tuint32_t id;\n+\tstruct ipa_control_value_entry value;\n };\n \n struct ipa_control_info_entry {\n \tuint32_t id;\n \tuint32_t type;\n-\tuint32_t offset;\n \tuint8_t direction;\n \tuint8_t padding[3];\n+\tuint32_t reserved;\n };\n \n #ifdef __cplusplus\ndiff --git a/src/libcamera/control_serializer.cpp b/src/libcamera/control_serializer.cpp\nindex 050f8512bd52..f576a868204f 100644\n--- a/src/libcamera/control_serializer.cpp\n+++ b/src/libcamera/control_serializer.cpp\n@@ -144,7 +144,7 @@ void ControlSerializer::reset()\n \n size_t ControlSerializer::binarySize(const ControlValue &value)\n {\n-\treturn sizeof(ControlType) + value.data().size_bytes();\n+\treturn value.data().size_bytes();\n }\n \n size_t ControlSerializer::binarySize(const ControlInfo &info)\n@@ -164,7 +164,8 @@ size_t ControlSerializer::binarySize(const ControlInfo &info)\n size_t ControlSerializer::binarySize(const ControlInfoMap &infoMap)\n {\n \tsize_t size = sizeof(struct ipa_controls_header)\n-\t\t + infoMap.size() * sizeof(struct ipa_control_info_entry);\n+\t\t + infoMap.size() * (sizeof(struct ipa_control_info_entry) +\n+\t\t\t\t\t3 * sizeof(struct ipa_control_value_entry));\n \n \tfor (const auto &ctrl : infoMap)\n \t\tsize += binarySize(ctrl.second);\n@@ -184,7 +185,7 @@ size_t ControlSerializer::binarySize(const ControlInfoMap &infoMap)\n size_t ControlSerializer::binarySize(const ControlList &list)\n {\n \tsize_t size = sizeof(struct ipa_controls_header)\n-\t\t + list.size() * sizeof(struct ipa_control_value_entry);\n+\t\t + list.size() * sizeof(struct ipa_control_list_entry);\n \n \tfor (const auto &ctrl : list)\n \t\tsize += binarySize(ctrl.second);\n@@ -195,16 +196,17 @@ size_t ControlSerializer::binarySize(const ControlList &list)\n void ControlSerializer::store(const ControlValue &value,\n \t\t\t ByteStreamBuffer &buffer)\n {\n-\tconst ControlType type = value.type();\n-\tbuffer.write(&type);\n \tbuffer.write(value.data());\n }\n \n-void ControlSerializer::store(const ControlInfo &info, ByteStreamBuffer &buffer)\n+void ControlSerializer::populateControlValueEntry(struct ipa_control_value_entry &entry,\n+\t\t\t\t\t\t const ControlValue &value,\n+\t\t\t\t\t\t uint32_t offset)\n {\n-\tstore(info.min(), buffer);\n-\tstore(info.max(), buffer);\n-\tstore(info.def(), buffer);\n+\tentry.type = value.type();\n+\tentry.is_array = value.isArray();\n+\tentry.count = value.numElements();\n+\tentry.offset = offset;\n }\n \n /**\n@@ -232,7 +234,8 @@ int ControlSerializer::serialize(const ControlInfoMap &infoMap,\n \n \t/* Compute entries and data required sizes. */\n \tsize_t entriesSize = infoMap.size()\n-\t\t\t * sizeof(struct ipa_control_info_entry);\n+\t\t\t * (sizeof(struct ipa_control_info_entry) +\n+\t\t\t 3 * sizeof(struct ipa_control_value_entry));\n \tsize_t valuesSize = 0;\n \tfor (const auto &ctrl : infoMap)\n \t\tvaluesSize += binarySize(ctrl.second);\n@@ -280,11 +283,32 @@ int ControlSerializer::serialize(const ControlInfoMap &infoMap,\n \t\tstruct ipa_control_info_entry entry;\n \t\tentry.id = id->id();\n \t\tentry.type = id->type();\n-\t\tentry.offset = values.offset();\n \t\tentry.direction = static_cast<ControlId::DirectionFlags::Type>(id->direction());\n \t\tentries.write(&entry);\n \n-\t\tstore(info, values);\n+\t\t/*\n+\t\t * Write the metadata for the ControlValue entries as well,\n+\t\t * since we need type, isArray, and numElements information for\n+\t\t * min/max/def of the ControlInfo. Doing it this way is the\n+\t\t * least intrusive in terms of changing the structs in\n+\t\t * ipa_controls.h\n+\t\t */\n+\t\tstruct ipa_control_value_entry valueEntry;\n+\n+\t\tpopulateControlValueEntry(valueEntry, info.min(),\n+\t\t\t\t\t values.offset());\n+\t\tentries.write(&valueEntry);\n+\t\tstore(info.min(), values);\n+\n+\t\tpopulateControlValueEntry(valueEntry, info.max(),\n+\t\t\t\t\t values.offset());\n+\t\tentries.write(&valueEntry);\n+\t\tstore(info.max(), values);\n+\n+\t\tpopulateControlValueEntry(valueEntry, info.def(),\n+\t\t\t\t\t values.offset());\n+\t\tentries.write(&valueEntry);\n+\t\tstore(info.def(), values);\n \t}\n \n \tif (buffer.overflow())\n@@ -341,7 +365,7 @@ int ControlSerializer::serialize(const ControlList &list,\n \telse\n \t\tidMapType = IPA_CONTROL_ID_MAP_V4L2;\n \n-\tsize_t entriesSize = list.size() * sizeof(struct ipa_control_value_entry);\n+\tsize_t entriesSize = list.size() * sizeof(struct ipa_control_list_entry);\n \tsize_t valuesSize = 0;\n \tfor (const auto &ctrl : list)\n \t\tvaluesSize += binarySize(ctrl.second);\n@@ -365,12 +389,9 @@ int ControlSerializer::serialize(const ControlList &list,\n \t\tunsigned int id = ctrl.first;\n \t\tconst ControlValue &value = ctrl.second;\n \n-\t\tstruct ipa_control_value_entry entry;\n+\t\tstruct ipa_control_list_entry entry;\n \t\tentry.id = id;\n-\t\tentry.type = value.type();\n-\t\tentry.is_array = value.isArray();\n-\t\tentry.count = value.numElements();\n-\t\tentry.offset = values.offset();\n+\t\tpopulateControlValueEntry(entry.value, value, values.offset());\n \t\tentries.write(&entry);\n \n \t\tstore(value, values);\n@@ -383,12 +404,10 @@ int ControlSerializer::serialize(const ControlList &list,\n }\n \n ControlValue ControlSerializer::loadControlValue(ByteStreamBuffer &buffer,\n+\t\t\t\t\t\t ControlType type,\n \t\t\t\t\t\t bool isArray,\n \t\t\t\t\t\t unsigned int count)\n {\n-\tControlType type;\n-\tbuffer.read(&type);\n-\n \tControlValue value;\n \n \tvalue.reserve(type, isArray, count);\n@@ -397,15 +416,6 @@ ControlValue ControlSerializer::loadControlValue(ByteStreamBuffer &buffer,\n \treturn value;\n }\n \n-ControlInfo ControlSerializer::loadControlInfo(ByteStreamBuffer &b)\n-{\n-\tControlValue min = loadControlValue(b);\n-\tControlValue max = loadControlValue(b);\n-\tControlValue def = loadControlValue(b);\n-\n-\treturn ControlInfo(min, max, def);\n-}\n-\n /**\n * \\fn template<typename T> T ControlSerializer::deserialize(ByteStreamBuffer &buffer)\n * \\brief Deserialize an object from a binary buffer\n@@ -483,9 +493,11 @@ ControlInfoMap ControlSerializer::deserialize<ControlInfoMap>(ByteStreamBuffer &\n \n \tControlInfoMap::Map ctrls;\n \tfor (unsigned int i = 0; i < hdr->entries; ++i) {\n-\t\tconst struct ipa_control_info_entry *entry =\n-\t\t\tentries.read<decltype(*entry)>();\n-\t\tif (!entry) {\n+\t\tconst auto *entry = entries.read<const ipa_control_info_entry>();\n+\t\tconst auto *min_entry = entries.read<const ipa_control_value_entry>();\n+\t\tconst auto *max_entry = entries.read<const ipa_control_value_entry>();\n+\t\tconst auto *def_entry = entries.read<const ipa_control_value_entry>();\n+\t\tif (!entry || !min_entry || !max_entry || !def_entry) {\n \t\t\tLOG(Serializer, Error) << \"Out of data\";\n \t\t\treturn {};\n \t\t}\n@@ -511,15 +523,39 @@ ControlInfoMap ControlSerializer::deserialize<ControlInfoMap>(ByteStreamBuffer &\n \t\tconst ControlId *controlId = idMap->at(entry->id);\n \t\tASSERT(controlId);\n \n-\t\tif (entry->offset != values.offset()) {\n+\t\tif (min_entry->offset != values.offset()) {\n \t\t\tLOG(Serializer, Error)\n-\t\t\t\t<< \"Bad data, entry offset mismatch (entry \"\n+\t\t\t\t<< \"Bad data, entry offset mismatch (min entry \"\n+\t\t\t\t<< i << \")\";\n+\t\t\treturn {};\n+\t\t}\n+\t\tControlValue min =\n+\t\t\tloadControlValue(values, static_cast<ControlType>(min_entry->type),\n+\t\t\t\t\t min_entry->is_array, min_entry->count);\n+\n+\t\tif (max_entry->offset != values.offset()) {\n+\t\t\tLOG(Serializer, Error)\n+\t\t\t\t<< \"Bad data, entry offset mismatch (max entry \"\n \t\t\t\t<< i << \")\";\n \t\t\treturn {};\n \t\t}\n+\t\tControlValue max =\n+\t\t\tloadControlValue(values, static_cast<ControlType>(max_entry->type),\n+\t\t\t\t\t max_entry->is_array, max_entry->count);\n+\n+\t\tif (def_entry->offset != values.offset()) {\n+\t\t\tLOG(Serializer, Error)\n+\t\t\t\t<< \"Bad data, entry offset mismatch (def entry \"\n+\t\t\t\t<< i << \")\";\n+\t\t\treturn {};\n+\t\t}\n+\t\tControlValue def =\n+\t\t\tloadControlValue(values, static_cast<ControlType>(def_entry->type),\n+\t\t\t\t\t def_entry->is_array, def_entry->count);\n+\n \n \t\t/* Create and store the ControlInfo. */\n-\t\tctrls.emplace(controlId, loadControlInfo(values));\n+\t\tctrls.emplace(controlId, ControlInfo(min, max, def));\n \t}\n \n \t/*\n@@ -618,12 +654,12 @@ ControlList ControlSerializer::deserialize<ControlList>(ByteStreamBuffer &buffer\n \tControlList ctrls(*idMap);\n \n \tfor (unsigned int i = 0; i < hdr->entries; ++i) {\n-\t\tconst struct ipa_control_value_entry *entry =\n-\t\t\tentries.read<decltype(*entry)>();\n-\t\tif (!entry) {\n+\t\tauto *list_entry = entries.read<const ipa_control_list_entry>();\n+\t\tif (!list_entry) {\n \t\t\tLOG(Serializer, Error) << \"Out of data\";\n \t\t\treturn {};\n \t\t}\n+\t\tconst ipa_control_value_entry *entry = &list_entry->value;\n \n \t\tif (entry->offset != values.offset()) {\n \t\t\tLOG(Serializer, Error)\n@@ -632,8 +668,9 @@ ControlList ControlSerializer::deserialize<ControlList>(ByteStreamBuffer &buffer\n \t\t\treturn {};\n \t\t}\n \n-\t\tctrls.set(entry->id,\n-\t\t\t loadControlValue(values, entry->is_array, entry->count));\n+\t\tctrls.set(list_entry->id,\n+\t\t\t loadControlValue(values, static_cast<ControlType>(entry->type),\n+\t\t\t\t\t entry->is_array, entry->count));\n \t}\n \n \treturn ctrls;\ndiff --git a/src/libcamera/ipa_controls.cpp b/src/libcamera/ipa_controls.cpp\nindex 12d92ebe894d..8f73c8fda811 100644\n--- a/src/libcamera/ipa_controls.cpp\n+++ b/src/libcamera/ipa_controls.cpp\n@@ -192,8 +192,6 @@ static_assert(sizeof(ipa_controls_header) == 32,\n /**\n * \\struct ipa_control_value_entry\n * \\brief Description of a serialized ControlValue entry\n- * \\var ipa_control_value_entry::id\n- * The numerical ID of the control\n * \\var ipa_control_value_entry::type\n * The type of the control (defined by enum ControlType)\n * \\var ipa_control_value_entry::is_array\n@@ -205,11 +203,25 @@ static_assert(sizeof(ipa_controls_header) == 32,\n * value data (shall be a multiple of 8 bytes).\n * \\var ipa_control_value_entry::padding\n * Padding bytes (shall be set to 0)\n+ * \\var ipa_control_value_entry::reserved\n+ * Reserved for future extensions\n */\n \n static_assert(sizeof(ipa_control_value_entry) == 16,\n \t \"Invalid ABI size change for struct ipa_control_value_entry\");\n \n+/**\n+ * \\struct ipa_control_list_entry\n+ * \\brief Description of a serialized ControlList entry\n+ * \\var ipa_control_list_entry::id\n+ * The numerical ID of the control\n+ * \\var ipa_control_list_entry::value\n+ * The description of the serialized ControlValue\n+ */\n+\n+static_assert(sizeof(ipa_control_list_entry) == 20,\n+\t \"Invalid ABI size change for struct ipa_control_list_entry\");\n+\n /**\n * \\struct ipa_control_info_entry\n * \\brief Description of a serialized ControlInfo entry\n@@ -217,8 +229,6 @@ static_assert(sizeof(ipa_control_value_entry) == 16,\n * The numerical ID of the control\n * \\var ipa_control_info_entry::type\n * The type of the control (defined by enum ControlType)\n- * \\var ipa_control_info_entry::offset\n- * The offset in bytes from the beginning of the data section to the control\n * info data (shall be a multiple of 8 bytes)\n * \\var ipa_control_info_entry::direction\n * The directions in which the control is allowed to be sent. This is a flags\n@@ -226,6 +236,8 @@ static_assert(sizeof(ipa_control_value_entry) == 16,\n * metadata). \\sa ControlId::Direction\n * \\var ipa_control_info_entry::padding\n * Padding bytes (shall be set to 0)\n+ * \\var ipa_control_info_entry::reserved\n+ * Reserved for future extensions\n */\n \n static_assert(sizeof(ipa_control_info_entry) == 16,\n", "prefixes": [ "v5", "1/2" ] }