From nobody Sun Dec 14 21:34:11 2025 Received: from mail-vs1-f49.google.com (mail-vs1-f49.google.com [209.85.217.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 DCE692054F9 for ; Mon, 3 Feb 2025 11:55:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.217.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738583761; cv=none; b=uKbixxN6s0Me59w+4KC/LShF+UU5DSPPPevg+xsNt9/St69NOmkJRN+rJUg4q55odkh1zLpO39uj56pv3UuJWR9+qzvGI5AHzL6HieBh33W5JU86XM6XRENzREpW7VXp2Nyb5bw2SUwqiTkwSkiodP0hHXUctL3XB0AG+DYKTBM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738583761; c=relaxed/simple; bh=IfDfnmI9WexGaCozjlG56eHWRNpkJwSGj+oicfx0AIA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=krpzMOONZQ9+lfq0Bcgb7EIVUb+FZcA/CwGVs2uw1yivmMmglUCY03RnNefmldrPsXs+NIX9VNlNiAIMbu89GkrxoVImjasKLu0WO5i28ebLNW8b47puk5aPoP2Iw0Sn+dOl1A4iU07CWrGAhXFSh0FIeMcGH00l/4xTocMeJs4= 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=khe9klhu; arc=none smtp.client-ip=209.85.217.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="khe9klhu" Received: by mail-vs1-f49.google.com with SMTP id ada2fe7eead31-4b68cb2abacso1008162137.3 for ; Mon, 03 Feb 2025 03:55:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1738583759; x=1739188559; 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=Y1eOFJCjuwi+7HI+8fuv+RZbg2mJZX4fHHxSxUTTx/0=; b=khe9klhu53bpcCexLIKhtRQLM9HLkJLgz9R/ymeFkg1DbH6/lb0WxPrfl+Yjt4Cqf6 G0XT+i/1U7GSr/sL2OGn0+4igQnnqJGSR4zNabwpy2ST1Fdaym0GvWICoAFaa2/Gwk/z oI23EV/sSmTAN3zMfzuyBtIn6k1dULiLmo+CY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738583759; x=1739188559; 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=Y1eOFJCjuwi+7HI+8fuv+RZbg2mJZX4fHHxSxUTTx/0=; b=sASAb4FxrhPyRqN/rHK15L2U39fYSKaN8dy1paceBeO6ZBp7aAYRKtjD5nB/XWKnqX Oy6H6EoYrV2ZbE1bDrP/WF62wkXinxvgn2r+ZIM2Nz2OplWUnWaol+dMSaSbCkrj8WYw vliZCD+4ACCwyZQmBXJTa+5F0Uzspy1ux7Y5rtCgouutsY7DUbHFymTdU1+OQpNcpNCV HRtt1/Fs24XtYrPsrcAwZY9n9Jb+Io2mzfwdMnyky7YUQaGtANQj8p5SmamyVm4uWk/v 9/NB1sjtLIzFHP1NAJ98q72FRD/sqDPLc1HOyMs5LPzUCo4k6dEoLb0nlbzdpZtMR6im hHGQ== X-Forwarded-Encrypted: i=1; AJvYcCUW1DVf6AJZdKJ2X9ytFqdIlVPnp5Z0pGahuyNieRKeIqyqcocjS2J/aRe4YNvskTlI6cEFMAFsIXvQ21o=@vger.kernel.org X-Gm-Message-State: AOJu0YyCjal4jPqdYSXhPwCY8Aq/I0c+fJJboPBmDepjcQG60jWL5sPl C9FfMrHMsB2f6us41Rwhv33+bx72st2TDhH+boZPGbGb/lJdZvRkHyMw+Edizg== X-Gm-Gg: ASbGncuAH9tUv401EbXrXWKWhi3twivMiWd/XeRe+2zEBA3S8yaLtqZ+/QrdrBR+m/3 Z3v0FJU81PL7Zg/ss7+YmpM0jRwLy9cr1inBJsRVv+dE3KZBjPTdn6Zu12N1LhHNqTjMjAku64w Zgl0/G1nUZyD1+8iG0KzNw+4oL8K0daXVKLu6JvOoeAH+ZhPfQHKVnXv2gZyjlnFW6CGdbtQV1u yqB68DQhtodl2q29hNU9gX1P0ZFRbnFw3CpMDHsAZekB8AHjETaUESu4uqktef/9GQLt8cPUYyY kCZU9ad7c4UmtiOmUERXG8+4afj25+BaKfxDiUoPVkz3rBeOhOQFHeaJ3cCHhGbvHA== X-Google-Smtp-Source: AGHT+IHE/glGASrHlXx81gQujZaYMBk1kjOiTOdazBG8eg6EqYAu3Io5LOiy1wwKRjVdc8juoLGChQ== X-Received: by 2002:a05:6102:4687:b0:4b9:bd00:454b with SMTP id ada2fe7eead31-4b9bd004832mr5990018137.13.1738583758746; Mon, 03 Feb 2025 03:55: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 ada2fe7eead31-4b9baa9aefcsm1592770137.12.2025.02.03.03.55.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 03 Feb 2025 03:55:57 -0800 (PST) From: Ricardo Ribalda Date: Mon, 03 Feb 2025 11:55:44 +0000 Subject: [PATCH v17 08/17] 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: <20250203-uvc-roi-v17-8-5900a9fed613@chromium.org> References: <20250203-uvc-roi-v17-0-5900a9fed613@chromium.org> In-Reply-To: <20250203-uvc-roi-v17-0-5900a9fed613@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 201af66a874d..a0156b79ab48 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; } @@ -1625,7 +1696,7 @@ void uvc_ctrl_status_event(struct uvc_video_chain *ch= ain, uvc_ctrl_set_handle(handle, ctrl, 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 @@ -1974,8 +2045,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 @@ -2014,12 +2085,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 @@ -2098,8 +2169,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 ctrl->dirty =3D 1; ctrl->modified =3D 1; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvi= deo.h index 018613f98f48..b55d5c23dfca 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -132,10 +132,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.48.1.362.g079036d154-goog