From nobody Sun Dec 14 21:37:28 2025 Received: from mail-qv1-f49.google.com (mail-qv1-f49.google.com [209.85.219.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 41E8E2153FB for ; Tue, 10 Dec 2024 09:42:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733823781; cv=none; b=EfabpwDJkfJKK7ejd8HyKKHwg2ed4wTgLZFBzn0Sey+Na7dZu8MN/l5uQC6m5RPtkaIBfG0H79zAD0QuX8MbmEE97DbiEcQZQC9/xCCevw65d7QqN1ehPtuUXpHaG3P559DQ3vTUP0DtAH1M3P9tHIg/Jpv9RlJJBJkGmoQ2fFc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733823781; c=relaxed/simple; bh=4xbVKX6i7so/xLpTZa/XjbZr4+Bsicj6dDAFUgCiOPQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=sWTAvDKQESgHEYSp2A48By0dn7F7h1RFhKlyR1uEcSBZSvKAAk+dUXl5zcQ3gt4l8rAt9enepAFbwWbGaIb8pkfPfQAvHH4j4+skR9e6m6zu+QlYr6e/9ZBkr2lR3ymGmvY6wBrzaOU7sU2UnVRIO9cXLq4t6WPFbANQ+BWpvVM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=GQNS8Reu; arc=none smtp.client-ip=209.85.219.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="GQNS8Reu" Received: by mail-qv1-f49.google.com with SMTP id 6a1803df08f44-6d87ab49423so52345216d6.0 for ; Tue, 10 Dec 2024 01:42:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1733823778; x=1734428578; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=BFj66RyTk6sqT9V9Y9d3LeaKrBJRM9mSw2F5nWt5/Tw=; b=GQNS8ReuQ4z/uRrHUQbCHlnTcr1i9t3zuY5UUu6cFFBl5i1dGCWj8gt8iRim4oRu0r OVurlvRPnUgZ7yTfpR03E+D+cTFHyG5TNcU8uHsshoOuJXdYFeD7+t5eOd/5ZdlMV9Kd i++09WD2ybdh1VD9/lN6w8dQMQ4cBgXIG03tE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733823778; x=1734428578; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BFj66RyTk6sqT9V9Y9d3LeaKrBJRM9mSw2F5nWt5/Tw=; b=ewuPW7neuwNFqJpxWr02dlQtbfmsu5vqEP0C5MQ/SkcNRCcpao43cmuIMWkQWcftoo Zd45d/KZ5Bc7F412IfCqex2e08Ug7i0rYyxXJQJmdrOv6YvvXlcwLfzLBVnAPuiaSwxY dMBpTcx47azRiqhv/CCAJFAQiAjnnxQBverOSCVeuGf88AD33OC1laOP5+hdzdxX/fop vvmG7fbCxaPXOYp83rU0VJgQb8EQHKUiGKX4wTNf2JcbT6ae2FbCH53NWlsOI+iJkoCa GtmJfhWScY23HqEiqshENRKqk8aPNSfoxw+QEXduZLvrrwXbNIcEMT1CXOuQaUQ/4VT+ nB4g== X-Forwarded-Encrypted: i=1; AJvYcCUStA0jlZa43a+Vk7aRcd4UGfXwkZGgkfMIQ5BL/KyGdjE7xb0DsB+MaUVxeg/0Txg1Az6A1es8mCU7Ex0=@vger.kernel.org X-Gm-Message-State: AOJu0Yy3Kf7eHzpA2AZywwXFcYDv9L2uFJqieVgoIvYI9bt3fW1aYl7p D92EQ1SOYGj/pQYawLqhePWU3hoEclSBy4633fpgooziVvdkhxBPL8rgk8m9QQ== X-Gm-Gg: ASbGnct17UCYyHpcaGV+bj3JWdSxxHmtVX9uOKNBG3vI2HPD9CYKWRdvbRFzSSvlPUq oxdFW21cmxo59xUHWmCLbls1rKHOafgCeIYdNDSbNE4+huTkBmvkkeu+sZI8ORmrkW6fLCgMHwk 3EznFjN0kaBnH79yjg7fI8IalS5D6cmmSFkMwWLNjvZZ+kW2K1HZpzzJ8EukjwNmOhm+4MVewXG 9uiC3Ywbtyz7wWq4xWMjyg/kLxqg+APKeH3DTk1q6fuii2U8mblazj7aCbZDxCWpogO2ATqI1JG XGNkrDzBrHAAkcSnl1b/6X3tC5Li X-Google-Smtp-Source: AGHT+IHYM3HgfWV26yqIYegG7eG1m3LG+GjVuVqNl6AyxQo8dS/maLswppMMcvwBORh7NXSiVEHMOA== X-Received: by 2002:a05:6214:d8d:b0:6d4:1f6d:695f with SMTP id 6a1803df08f44-6d91e2d2d35mr80814336d6.2.1733823778212; Tue, 10 Dec 2024 01:42:58 -0800 (PST) Received: from denia.c.googlers.com (5.236.236.35.bc.googleusercontent.com. [35.236.236.5]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-6d92f7c2bc1sm773326d6.83.2024.12.10.01.42.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Dec 2024 01:42:57 -0800 (PST) From: Ricardo Ribalda Date: Tue, 10 Dec 2024 09:42:45 +0000 Subject: [PATCH v16 09/18] media: uvcvideo: Support any size for mapping get/set Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20241210-uvc-roi-v16-9-e8201f7e8e57@chromium.org> References: <20241210-uvc-roi-v16-0-e8201f7e8e57@chromium.org> In-Reply-To: <20241210-uvc-roi-v16-0-e8201f7e8e57@chromium.org> To: Laurent Pinchart , Mauro Carvalho Chehab , Hans de Goede , Sakari Ailus , Hans Verkuil Cc: Yunke Cao , linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, Ricardo Ribalda , Yunke Cao X-Mailer: b4 0.13.0 Right now, we only support mappings for v4l2 controls with a max size of s32. This patch modifies the prototype of get/set so it can support any size. This is done to prepare for compound controls. Suggested-by: Laurent Pinchart Reviewed-by: Yunke Cao Reviewed-by: Hans de Goede Tested-by: Yunke Cao Signed-off-by: Ricardo Ribalda --- drivers/media/usb/uvc/uvc_ctrl.c | 181 +++++++++++++++++++++++++++--------= ---- drivers/media/usb/uvc/uvcvideo.h | 8 +- 2 files changed, 130 insertions(+), 59 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_c= trl.c index 12ce7e38d6f6..8fc83961c76e 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -367,6 +367,22 @@ static const u32 uvc_control_classes[] =3D { =20 static const int exposure_auto_mapping[] =3D { 2, 1, 4, 8 }; =20 +static s32 uvc_mapping_get_s32(struct uvc_control_mapping *mapping, + u8 query, const void *data_in) +{ + s32 data_out =3D 0; + + mapping->get(mapping, query, data_in, sizeof(data_out), &data_out); + + return data_out; +} + +static void uvc_mapping_set_s32(struct uvc_control_mapping *mapping, + s32 data_in, void *data_out) +{ + mapping->set(mapping, sizeof(data_in), &data_in, data_out); +} + /* * This function translates the V4L2 menu index @idx, as exposed to usersp= ace as * the V4L2 control value, to the corresponding UVC control value used by = the @@ -405,58 +421,93 @@ uvc_mapping_get_menu_name(const struct uvc_control_ma= pping *mapping, u32 idx) return v4l2_ctrl_get_menu(mapping->id)[idx]; } =20 -static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, - u8 query, const u8 *data) +static int uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, u8 query, + const void *uvc_in, size_t v4l2_size, + void *v4l2_out) { - s8 zoom =3D (s8)data[0]; + u8 value =3D ((u8 *)uvc_in)[2]; + s8 sign =3D ((s8 *)uvc_in)[0]; + s32 *out =3D v4l2_out; + + if (WARN_ON(v4l2_size !=3D sizeof(s32))) + return -EINVAL; =20 switch (query) { case UVC_GET_CUR: - return (zoom =3D=3D 0) ? 0 : (zoom > 0 ? data[2] : -data[2]); + *out =3D (sign =3D=3D 0) ? 0 : (sign > 0 ? value : -value); + return 0; =20 case UVC_GET_MIN: case UVC_GET_MAX: case UVC_GET_RES: case UVC_GET_DEF: default: - return data[2]; + *out =3D value; + return 0; } } =20 -static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping, - s32 value, u8 *data) +static int uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping, + size_t v4l2_size, const void *v4l2_in, + void *uvc_out) { - data[0] =3D value =3D=3D 0 ? 0 : (value > 0) ? 1 : 0xff; - data[2] =3D min((int)abs(value), 0xff); + u8 *out =3D uvc_out; + s32 value; + + if (WARN_ON(v4l2_size !=3D sizeof(s32))) + return -EINVAL; + + value =3D *(u32 *)v4l2_in; + out[0] =3D value =3D=3D 0 ? 0 : (value > 0) ? 1 : 0xff; + out[2] =3D min_t(int, abs(value), 0xff); + + return 0; } =20 -static s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, - u8 query, const u8 *data) +static int uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, + u8 query, const void *uvc_in, + size_t v4l2_size, void *v4l2_out) { unsigned int first =3D mapping->offset / 8; - s8 rel =3D (s8)data[first]; + u8 value =3D ((u8 *)uvc_in)[first + 1]; + s8 sign =3D ((s8 *)uvc_in)[first]; + s32 *out =3D v4l2_out; + + if (WARN_ON(v4l2_size !=3D sizeof(s32))) + return -EINVAL; =20 switch (query) { case UVC_GET_CUR: - return (rel =3D=3D 0) ? 0 : (rel > 0 ? data[first+1] - : -data[first+1]); + *out =3D (sign =3D=3D 0) ? 0 : (sign > 0 ? value : -value); + return 0; case UVC_GET_MIN: - return -data[first+1]; + *out =3D -value; + return 0; case UVC_GET_MAX: case UVC_GET_RES: case UVC_GET_DEF: default: - return data[first+1]; + *out =3D value; + return 0; } } =20 -static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping, - s32 value, u8 *data) +static int uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping, + size_t v4l2_size, const void *v4l2_in, + void *uvc_out) { unsigned int first =3D mapping->offset / 8; + u8 *out =3D uvc_out; + s32 value; + + if (WARN_ON(v4l2_size !=3D sizeof(s32))) + return -EINVAL; + + value =3D *(u32 *)v4l2_in; + out[first] =3D value =3D=3D 0 ? 0 : (value > 0) ? 1 : 0xff; + out[first + 1] =3D min_t(int, abs(value), 0xff); =20 - data[first] =3D value =3D=3D 0 ? 0 : (value > 0) ? 1 : 0xff; - data[first+1] =3D min_t(int, abs(value), 0xff); + return 0; } =20 static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limite= d =3D { @@ -887,14 +938,20 @@ static s32 uvc_menu_to_v4l2_menu(struct uvc_control_m= apping *mapping, s32 val) * a signed 32bit integer. Sign extension will be performed if the mapping * references a signed data type. */ -static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, - u8 query, const u8 *data) +static int uvc_get_le_value(struct uvc_control_mapping *mapping, + u8 query, const void *uvc_in, size_t v4l2_size, + void *v4l2_out) { - int bits =3D mapping->size; int offset =3D mapping->offset; + int bits =3D mapping->size; + const u8 *data =3D uvc_in; + s32 *out =3D v4l2_out; s32 value =3D 0; u8 mask; =20 + if (WARN_ON(v4l2_size !=3D sizeof(s32))) + return -EINVAL; + data +=3D offset / 8; offset &=3D 7; mask =3D ((1LL << bits) - 1) << offset; @@ -916,29 +973,41 @@ static s32 uvc_get_le_value(struct uvc_control_mappin= g *mapping, value |=3D -(value & (1 << (mapping->size - 1))); =20 /* If it is a menu, convert from uvc to v4l2. */ - if (mapping->v4l2_type !=3D V4L2_CTRL_TYPE_MENU) - return value; + if (mapping->v4l2_type !=3D V4L2_CTRL_TYPE_MENU) { + *out =3D value; + return 0; + } =20 switch (query) { case UVC_GET_CUR: case UVC_GET_DEF: - return uvc_menu_to_v4l2_menu(mapping, value); + *out =3D uvc_menu_to_v4l2_menu(mapping, value); + return 0; } =20 - return value; + *out =3D value; + return 0; } =20 /* * Set the bit string specified by mapping->offset and mapping->size * in the little-endian data stored at 'data' to the value 'value'. */ -static void uvc_set_le_value(struct uvc_control_mapping *mapping, - s32 value, u8 *data) +static int uvc_set_le_value(struct uvc_control_mapping *mapping, + size_t v4l2_size, const void *v4l2_in, + void *uvc_out) { - int bits =3D mapping->size; int offset =3D mapping->offset; + int bits =3D mapping->size; + u8 *data =3D uvc_out; + s32 value; u8 mask; =20 + if (WARN_ON(v4l2_size !=3D sizeof(s32))) + return -EINVAL; + + value =3D *(s32 *)v4l2_in; + switch (mapping->v4l2_type) { case V4L2_CTRL_TYPE_MENU: value =3D uvc_mapping_get_menu_value(mapping, value); @@ -966,6 +1035,8 @@ static void uvc_set_le_value(struct uvc_control_mappin= g *mapping, bits -=3D 8 - offset; offset =3D 0; } + + return 0; } =20 /* ------------------------------------------------------------------------ @@ -1147,8 +1218,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *cha= in, if (ret < 0) return ret; =20 - *value =3D mapping->get(mapping, UVC_GET_CUR, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); + *value =3D uvc_mapping_get_s32(mapping, UVC_GET_CUR, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); =20 return 0; } @@ -1281,12 +1352,12 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *= ctrl, * as supported. */ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) - return mapping->get(mapping, UVC_GET_RES, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); + return uvc_mapping_get_s32(mapping, UVC_GET_RES, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); =20 if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) - return mapping->get(mapping, UVC_GET_MAX, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); + return uvc_mapping_get_s32(mapping, UVC_GET_MAX, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); =20 return ~0; } @@ -1331,8 +1402,8 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_cha= in *chain, } =20 if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) { - v4l2_ctrl->default_value =3D mapping->get(mapping, UVC_GET_DEF, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); + v4l2_ctrl->default_value =3D uvc_mapping_get_s32(mapping, + UVC_GET_DEF, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); } =20 switch (mapping->v4l2_type) { @@ -1365,16 +1436,16 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_c= hain *chain, } =20 if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) - v4l2_ctrl->minimum =3D mapping->get(mapping, UVC_GET_MIN, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); + v4l2_ctrl->minimum =3D uvc_mapping_get_s32(mapping, UVC_GET_MIN, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); =20 if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) - v4l2_ctrl->maximum =3D mapping->get(mapping, UVC_GET_MAX, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); + v4l2_ctrl->maximum =3D uvc_mapping_get_s32(mapping, UVC_GET_MAX, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); =20 if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) - v4l2_ctrl->step =3D mapping->get(mapping, UVC_GET_RES, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); + v4l2_ctrl->step =3D uvc_mapping_get_s32(mapping, UVC_GET_RES, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); =20 return 0; } @@ -1587,7 +1658,7 @@ void uvc_ctrl_status_event(struct uvc_video_chain *ch= ain, ctrl->handle =3D NULL; =20 list_for_each_entry(mapping, &ctrl->info.mappings, list) { - s32 value =3D mapping->get(mapping, UVC_GET_CUR, data); + s32 value =3D uvc_mapping_get_s32(mapping, UVC_GET_CUR, data); =20 /* * handle may be NULL here if the device sends auto-update @@ -1931,8 +2002,8 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, u32 w= hich, if (ret < 0) return ret; } - xctrl->value =3D mapping->get(mapping, UVC_GET_DEF, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); + xctrl->value =3D uvc_mapping_get_s32(mapping, UVC_GET_DEF, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); return 0; } =20 @@ -1969,12 +2040,12 @@ int uvc_ctrl_set(struct uvc_fh *handle, return ret; } =20 - min =3D mapping->get(mapping, UVC_GET_MIN, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); - max =3D mapping->get(mapping, UVC_GET_MAX, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); - step =3D mapping->get(mapping, UVC_GET_RES, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); + min =3D uvc_mapping_get_s32(mapping, UVC_GET_MIN, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); + max =3D uvc_mapping_get_s32(mapping, UVC_GET_MAX, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); + step =3D uvc_mapping_get_s32(mapping, UVC_GET_RES, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); if (step =3D=3D 0) step =3D 1; =20 @@ -2053,8 +2124,8 @@ int uvc_ctrl_set(struct uvc_fh *handle, ctrl->info.size); } =20 - mapping->set(mapping, value, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); + uvc_mapping_set_s32(mapping, value, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); =20 if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) ctrl->handle =3D handle; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvi= deo.h index 6ebaabd11443..3d32a56c5ff8 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -131,10 +131,10 @@ struct uvc_control_mapping { const struct uvc_control_mapping *(*filter_mapping) (struct uvc_video_chain *chain, struct uvc_control *ctrl); - s32 (*get)(struct uvc_control_mapping *mapping, u8 query, - const u8 *data); - void (*set)(struct uvc_control_mapping *mapping, s32 value, - u8 *data); + int (*get)(struct uvc_control_mapping *mapping, u8 query, + const void *uvc_in, size_t v4l2_size, void *v4l2_out); + int (*set)(struct uvc_control_mapping *mapping, size_t v4l2_size, + const void *v4l2_in, void *uvc_out); }; =20 struct uvc_control { --=20 2.47.0.338.g60cca15819-goog