From patchwork Wed Aug 1 21:54:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 10553087 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5420B15E2 for ; Wed, 1 Aug 2018 21:54:33 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 422BF28825 for ; Wed, 1 Aug 2018 21:54:33 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 348D429492; Wed, 1 Aug 2018 21:54:33 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0173628825 for ; Wed, 1 Aug 2018 21:54:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731803AbeHAXmW (ORCPT ); Wed, 1 Aug 2018 19:42:22 -0400 Received: from perceval.ideasonboard.com ([213.167.242.64]:57906 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726174AbeHAXmW (ORCPT ); Wed, 1 Aug 2018 19:42:22 -0400 Received: from avalon.bb.dnainternet.fi (dfj612ybrt5fhg77mgycy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:2e86:4862:ef6a:2804]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 941A31AB6; Wed, 1 Aug 2018 23:54:27 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1533160468; bh=WekWXtKcGWiUj/ruIPooJ2ODYNXR9Ir6wRknkb5HFO0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oW6+KVWcEuGkcPHONxmz624BeWJo4UDt+7APDwnOL6A/6Zy4HYQgABlNL2HHnF5lF 6aVUla5/QnCvcjCQRHOl+ZJP17u8Q7Ybxvwxr9x6yoF+tKt2dkpLC0AdIhCT6NYVCO S8Oo9+uOJpJ5yUaDHa7rlxohBMEyFBXd07NsKFgs= From: Laurent Pinchart To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Joel Pepper , Kieran Bingham , Andrzej Pietrasiewicz Subject: [PATCH v2 1/8] usb: gadget: uvc: configfs: Don't wrap groups unnecessarily Date: Thu, 2 Aug 2018 00:54:58 +0300 Message-Id: <20180801215505.7658-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> References: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Various configfs groups (represented by config_group) are wrapped in structures that they're the only member of. This allows adding other data fields to groups, but it unnecessarily makes the code more complex. Remove the outer structures and use config_group directly to simplify the code. Groups can still be wrapped individually in the future if other data fields need to be added. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- drivers/usb/gadget/function/uvc_configfs.c | 302 +++++++++++------------------ 1 file changed, 117 insertions(+), 185 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index b51f0d278826..1df94b25abe1 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -162,9 +162,7 @@ static void uvcg_control_header_drop(struct config_group *group, } /* control/header */ -static struct uvcg_control_header_grp { - struct config_group group; -} uvcg_control_header_grp; +static struct config_group uvcg_control_header_grp; static struct configfs_group_operations uvcg_control_header_grp_ops = { .make_item = uvcg_control_header_make, @@ -177,31 +175,22 @@ static const struct config_item_type uvcg_control_header_grp_type = { }; /* control/processing/default */ -static struct uvcg_default_processing { - struct config_group group; -} uvcg_default_processing; - -static inline struct uvcg_default_processing -*to_uvcg_default_processing(struct config_item *item) -{ - return container_of(to_config_group(item), - struct uvcg_default_processing, group); -} +static struct config_group uvcg_default_processing_grp; #define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_processing_##cname##_show( \ struct config_item *item, char *page) \ { \ - struct uvcg_default_processing *dp = to_uvcg_default_processing(item); \ + struct config_group *group = to_config_group(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ - struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; \ + struct mutex *su_mutex = &group->cg_subsys->su_mutex; \ struct uvc_processing_unit_descriptor *pd; \ int result; \ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ \ - opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent; \ + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \ opts = to_f_uvc_opts(opts_item); \ pd = &opts->uvc_processing; \ \ @@ -229,17 +218,17 @@ UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, identity_conv); static ssize_t uvcg_default_processing_bm_controls_show( struct config_item *item, char *page) { - struct uvcg_default_processing *dp = to_uvcg_default_processing(item); + struct config_group *group = to_config_group(item); struct f_uvc_opts *opts; struct config_item *opts_item; - struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; + struct mutex *su_mutex = &group->cg_subsys->su_mutex; struct uvc_processing_unit_descriptor *pd; int result, i; char *pg = page; mutex_lock(su_mutex); /* for navigating configfs hierarchy */ - opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent; + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; opts = to_f_uvc_opts(opts_item); pd = &opts->uvc_processing; @@ -274,40 +263,29 @@ static const struct config_item_type uvcg_default_processing_type = { /* struct uvcg_processing {}; */ /* control/processing */ -static struct uvcg_processing_grp { - struct config_group group; -} uvcg_processing_grp; +static struct config_group uvcg_processing_grp; static const struct config_item_type uvcg_processing_grp_type = { .ct_owner = THIS_MODULE, }; /* control/terminal/camera/default */ -static struct uvcg_default_camera { - struct config_group group; -} uvcg_default_camera; - -static inline struct uvcg_default_camera -*to_uvcg_default_camera(struct config_item *item) -{ - return container_of(to_config_group(item), - struct uvcg_default_camera, group); -} +static struct config_group uvcg_default_camera_grp; #define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_camera_##cname##_show( \ struct config_item *item, char *page) \ { \ - struct uvcg_default_camera *dc = to_uvcg_default_camera(item); \ + struct config_group *group = to_config_group(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ - struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \ + struct mutex *su_mutex = &group->cg_subsys->su_mutex; \ struct uvc_camera_terminal_descriptor *cd; \ int result; \ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ \ - opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent-> \ + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> \ ci_parent; \ opts = to_f_uvc_opts(opts_item); \ cd = &opts->uvc_camera_terminal; \ @@ -343,17 +321,17 @@ UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength, static ssize_t uvcg_default_camera_bm_controls_show( struct config_item *item, char *page) { - struct uvcg_default_camera *dc = to_uvcg_default_camera(item); + struct config_group *group = to_config_group(item); struct f_uvc_opts *opts; struct config_item *opts_item; - struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; + struct mutex *su_mutex = &group->cg_subsys->su_mutex; struct uvc_camera_terminal_descriptor *cd; int result, i; char *pg = page; mutex_lock(su_mutex); /* for navigating configfs hierarchy */ - opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent-> + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> ci_parent; opts = to_f_uvc_opts(opts_item); cd = &opts->uvc_camera_terminal; @@ -391,40 +369,29 @@ static const struct config_item_type uvcg_default_camera_type = { /* struct uvcg_camera {}; */ /* control/terminal/camera */ -static struct uvcg_camera_grp { - struct config_group group; -} uvcg_camera_grp; +static struct config_group uvcg_camera_grp; static const struct config_item_type uvcg_camera_grp_type = { .ct_owner = THIS_MODULE, }; /* control/terminal/output/default */ -static struct uvcg_default_output { - struct config_group group; -} uvcg_default_output; - -static inline struct uvcg_default_output -*to_uvcg_default_output(struct config_item *item) -{ - return container_of(to_config_group(item), - struct uvcg_default_output, group); -} +static struct config_group uvcg_default_output_grp; #define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_output_##cname##_show( \ - struct config_item *item, char *page) \ + struct config_item *item, char *page) \ { \ - struct uvcg_default_output *dout = to_uvcg_default_output(item); \ + struct config_group *group = to_config_group(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ - struct mutex *su_mutex = &dout->group.cg_subsys->su_mutex; \ + struct mutex *su_mutex = &group->cg_subsys->su_mutex; \ struct uvc_output_terminal_descriptor *cd; \ int result; \ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ \ - opts_item = dout->group.cg_item.ci_parent->ci_parent-> \ + opts_item = group->cg_item.ci_parent->ci_parent-> \ ci_parent->ci_parent; \ opts = to_f_uvc_opts(opts_item); \ cd = &opts->uvc_output_terminal; \ @@ -469,39 +436,32 @@ static const struct config_item_type uvcg_default_output_type = { /* struct uvcg_output {}; */ /* control/terminal/output */ -static struct uvcg_output_grp { - struct config_group group; -} uvcg_output_grp; +static struct config_group uvcg_output_grp; static const struct config_item_type uvcg_output_grp_type = { .ct_owner = THIS_MODULE, }; /* control/terminal */ -static struct uvcg_terminal_grp { - struct config_group group; -} uvcg_terminal_grp; +static struct config_group uvcg_terminal_grp; static const struct config_item_type uvcg_terminal_grp_type = { .ct_owner = THIS_MODULE, }; /* control/class/{fs} */ -static struct uvcg_control_class { - struct config_group group; -} uvcg_control_class_fs, uvcg_control_class_ss; - +static struct config_group uvcg_control_class_fs_grp; +static struct config_group uvcg_control_class_ss_grp; static inline struct uvc_descriptor_header **uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o) { - struct uvcg_control_class *cl = container_of(to_config_group(i), - struct uvcg_control_class, group); + struct config_group *group = to_config_group(i); - if (cl == &uvcg_control_class_fs) + if (group == &uvcg_control_class_fs_grp) return o->uvc_fs_control_cls; - if (cl == &uvcg_control_class_ss) + if (group == &uvcg_control_class_ss_grp) return o->uvc_ss_control_cls; return NULL; @@ -593,36 +553,28 @@ static const struct config_item_type uvcg_control_class_type = { }; /* control/class */ -static struct uvcg_control_class_grp { - struct config_group group; -} uvcg_control_class_grp; +static struct config_group uvcg_control_class_grp; static const struct config_item_type uvcg_control_class_grp_type = { .ct_owner = THIS_MODULE, }; /* control */ -static struct uvcg_control_grp { - struct config_group group; -} uvcg_control_grp; +static struct config_group uvcg_control_grp; static const struct config_item_type uvcg_control_grp_type = { .ct_owner = THIS_MODULE, }; /* streaming/uncompressed */ -static struct uvcg_uncompressed_grp { - struct config_group group; -} uvcg_uncompressed_grp; +static struct config_group uvcg_uncompressed_grp; /* streaming/mjpeg */ -static struct uvcg_mjpeg_grp { - struct config_group group; -} uvcg_mjpeg_grp; +static struct config_group uvcg_mjpeg_grp; static struct config_item *fmt_parent[] = { - &uvcg_uncompressed_grp.group.cg_item, - &uvcg_mjpeg_grp.group.cg_item, + &uvcg_uncompressed_grp.cg_item, + &uvcg_mjpeg_grp.cg_item, }; enum uvcg_format_type { @@ -893,9 +845,7 @@ static void uvcg_streaming_header_drop(struct config_group *group, } /* streaming/header */ -static struct uvcg_streaming_header_grp { - struct config_group group; -} uvcg_streaming_header_grp; +static struct config_group uvcg_streaming_header_grp; static struct configfs_group_operations uvcg_streaming_header_grp_ops = { .make_item = uvcg_streaming_header_make, @@ -1670,32 +1620,22 @@ static const struct config_item_type uvcg_mjpeg_grp_type = { }; /* streaming/color_matching/default */ -static struct uvcg_default_color_matching { - struct config_group group; -} uvcg_default_color_matching; - -static inline struct uvcg_default_color_matching -*to_uvcg_default_color_matching(struct config_item *item) -{ - return container_of(to_config_group(item), - struct uvcg_default_color_matching, group); -} +static struct config_group uvcg_default_color_matching_grp; #define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_color_matching_##cname##_show( \ - struct config_item *item, char *page) \ + struct config_item *item, char *page) \ { \ - struct uvcg_default_color_matching *dc = \ - to_uvcg_default_color_matching(item); \ + struct config_group *group = to_config_group(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ - struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \ + struct mutex *su_mutex = &group->cg_subsys->su_mutex; \ struct uvc_color_matching_descriptor *cd; \ int result; \ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ \ - opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent; \ + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \ opts = to_f_uvc_opts(opts_item); \ cd = &opts->uvc_color_matching; \ \ @@ -1737,33 +1677,29 @@ static const struct config_item_type uvcg_default_color_matching_type = { /* struct uvcg_color_matching {}; */ /* streaming/color_matching */ -static struct uvcg_color_matching_grp { - struct config_group group; -} uvcg_color_matching_grp; +static struct config_group uvcg_color_matching_grp; static const struct config_item_type uvcg_color_matching_grp_type = { .ct_owner = THIS_MODULE, }; /* streaming/class/{fs|hs|ss} */ -static struct uvcg_streaming_class { - struct config_group group; -} uvcg_streaming_class_fs, uvcg_streaming_class_hs, uvcg_streaming_class_ss; - +static struct config_group uvcg_streaming_class_fs_grp; +static struct config_group uvcg_streaming_class_hs_grp; +static struct config_group uvcg_streaming_class_ss_grp; static inline struct uvc_descriptor_header ***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o) { - struct uvcg_streaming_class *cl = container_of(to_config_group(i), - struct uvcg_streaming_class, group); + struct config_group *group = to_config_group(i); - if (cl == &uvcg_streaming_class_fs) + if (group == &uvcg_streaming_class_fs_grp) return &o->uvc_fs_streaming_cls; - if (cl == &uvcg_streaming_class_hs) + if (group == &uvcg_streaming_class_hs_grp) return &o->uvc_hs_streaming_cls; - if (cl == &uvcg_streaming_class_ss) + if (group == &uvcg_streaming_class_ss_grp) return &o->uvc_ss_streaming_cls; return NULL; @@ -2092,18 +2028,14 @@ static const struct config_item_type uvcg_streaming_class_type = { }; /* streaming/class */ -static struct uvcg_streaming_class_grp { - struct config_group group; -} uvcg_streaming_class_grp; +static struct config_group uvcg_streaming_class_grp; static const struct config_item_type uvcg_streaming_class_grp_type = { .ct_owner = THIS_MODULE, }; /* streaming */ -static struct uvcg_streaming_grp { - struct config_group group; -} uvcg_streaming_grp; +static struct config_group uvcg_streaming_grp; static const struct config_item_type uvcg_streaming_grp_type = { .ct_owner = THIS_MODULE, @@ -2193,114 +2125,114 @@ static const struct config_item_type uvc_func_type = { int uvcg_attach_configfs(struct f_uvc_opts *opts) { - config_group_init_type_name(&uvcg_control_header_grp.group, + config_group_init_type_name(&uvcg_control_header_grp, "header", &uvcg_control_header_grp_type); - config_group_init_type_name(&uvcg_default_processing.group, + config_group_init_type_name(&uvcg_default_processing_grp, "default", &uvcg_default_processing_type); - config_group_init_type_name(&uvcg_processing_grp.group, + config_group_init_type_name(&uvcg_processing_grp, "processing", &uvcg_processing_grp_type); - configfs_add_default_group(&uvcg_default_processing.group, - &uvcg_processing_grp.group); + configfs_add_default_group(&uvcg_default_processing_grp, + &uvcg_processing_grp); - config_group_init_type_name(&uvcg_default_camera.group, + config_group_init_type_name(&uvcg_default_camera_grp, "default", &uvcg_default_camera_type); - config_group_init_type_name(&uvcg_camera_grp.group, + config_group_init_type_name(&uvcg_camera_grp, "camera", &uvcg_camera_grp_type); - configfs_add_default_group(&uvcg_default_camera.group, - &uvcg_camera_grp.group); + configfs_add_default_group(&uvcg_default_camera_grp, + &uvcg_camera_grp); - config_group_init_type_name(&uvcg_default_output.group, + config_group_init_type_name(&uvcg_default_output_grp, "default", &uvcg_default_output_type); - config_group_init_type_name(&uvcg_output_grp.group, + config_group_init_type_name(&uvcg_output_grp, "output", &uvcg_output_grp_type); - configfs_add_default_group(&uvcg_default_output.group, - &uvcg_output_grp.group); + configfs_add_default_group(&uvcg_default_output_grp, + &uvcg_output_grp); - config_group_init_type_name(&uvcg_terminal_grp.group, + config_group_init_type_name(&uvcg_terminal_grp, "terminal", &uvcg_terminal_grp_type); - configfs_add_default_group(&uvcg_camera_grp.group, - &uvcg_terminal_grp.group); - configfs_add_default_group(&uvcg_output_grp.group, - &uvcg_terminal_grp.group); + configfs_add_default_group(&uvcg_camera_grp, + &uvcg_terminal_grp); + configfs_add_default_group(&uvcg_output_grp, + &uvcg_terminal_grp); - config_group_init_type_name(&uvcg_control_class_fs.group, + config_group_init_type_name(&uvcg_control_class_fs_grp, "fs", &uvcg_control_class_type); - config_group_init_type_name(&uvcg_control_class_ss.group, + config_group_init_type_name(&uvcg_control_class_ss_grp, "ss", &uvcg_control_class_type); - config_group_init_type_name(&uvcg_control_class_grp.group, + config_group_init_type_name(&uvcg_control_class_grp, "class", &uvcg_control_class_grp_type); - configfs_add_default_group(&uvcg_control_class_fs.group, - &uvcg_control_class_grp.group); - configfs_add_default_group(&uvcg_control_class_ss.group, - &uvcg_control_class_grp.group); + configfs_add_default_group(&uvcg_control_class_fs_grp, + &uvcg_control_class_grp); + configfs_add_default_group(&uvcg_control_class_ss_grp, + &uvcg_control_class_grp); - config_group_init_type_name(&uvcg_control_grp.group, + config_group_init_type_name(&uvcg_control_grp, "control", &uvcg_control_grp_type); - configfs_add_default_group(&uvcg_control_header_grp.group, - &uvcg_control_grp.group); - configfs_add_default_group(&uvcg_processing_grp.group, - &uvcg_control_grp.group); - configfs_add_default_group(&uvcg_terminal_grp.group, - &uvcg_control_grp.group); - configfs_add_default_group(&uvcg_control_class_grp.group, - &uvcg_control_grp.group); - - config_group_init_type_name(&uvcg_streaming_header_grp.group, + configfs_add_default_group(&uvcg_control_header_grp, + &uvcg_control_grp); + configfs_add_default_group(&uvcg_processing_grp, + &uvcg_control_grp); + configfs_add_default_group(&uvcg_terminal_grp, + &uvcg_control_grp); + configfs_add_default_group(&uvcg_control_class_grp, + &uvcg_control_grp); + + config_group_init_type_name(&uvcg_streaming_header_grp, "header", &uvcg_streaming_header_grp_type); - config_group_init_type_name(&uvcg_uncompressed_grp.group, + config_group_init_type_name(&uvcg_uncompressed_grp, "uncompressed", &uvcg_uncompressed_grp_type); - config_group_init_type_name(&uvcg_mjpeg_grp.group, + config_group_init_type_name(&uvcg_mjpeg_grp, "mjpeg", &uvcg_mjpeg_grp_type); - config_group_init_type_name(&uvcg_default_color_matching.group, + config_group_init_type_name(&uvcg_default_color_matching_grp, "default", &uvcg_default_color_matching_type); - config_group_init_type_name(&uvcg_color_matching_grp.group, + config_group_init_type_name(&uvcg_color_matching_grp, "color_matching", &uvcg_color_matching_grp_type); - configfs_add_default_group(&uvcg_default_color_matching.group, - &uvcg_color_matching_grp.group); + configfs_add_default_group(&uvcg_default_color_matching_grp, + &uvcg_color_matching_grp); - config_group_init_type_name(&uvcg_streaming_class_fs.group, + config_group_init_type_name(&uvcg_streaming_class_fs_grp, "fs", &uvcg_streaming_class_type); - config_group_init_type_name(&uvcg_streaming_class_hs.group, + config_group_init_type_name(&uvcg_streaming_class_hs_grp, "hs", &uvcg_streaming_class_type); - config_group_init_type_name(&uvcg_streaming_class_ss.group, + config_group_init_type_name(&uvcg_streaming_class_ss_grp, "ss", &uvcg_streaming_class_type); - config_group_init_type_name(&uvcg_streaming_class_grp.group, + config_group_init_type_name(&uvcg_streaming_class_grp, "class", &uvcg_streaming_class_grp_type); - configfs_add_default_group(&uvcg_streaming_class_fs.group, - &uvcg_streaming_class_grp.group); - configfs_add_default_group(&uvcg_streaming_class_hs.group, - &uvcg_streaming_class_grp.group); - configfs_add_default_group(&uvcg_streaming_class_ss.group, - &uvcg_streaming_class_grp.group); - - config_group_init_type_name(&uvcg_streaming_grp.group, + configfs_add_default_group(&uvcg_streaming_class_fs_grp, + &uvcg_streaming_class_grp); + configfs_add_default_group(&uvcg_streaming_class_hs_grp, + &uvcg_streaming_class_grp); + configfs_add_default_group(&uvcg_streaming_class_ss_grp, + &uvcg_streaming_class_grp); + + config_group_init_type_name(&uvcg_streaming_grp, "streaming", &uvcg_streaming_grp_type); - configfs_add_default_group(&uvcg_streaming_header_grp.group, - &uvcg_streaming_grp.group); - configfs_add_default_group(&uvcg_uncompressed_grp.group, - &uvcg_streaming_grp.group); - configfs_add_default_group(&uvcg_mjpeg_grp.group, - &uvcg_streaming_grp.group); - configfs_add_default_group(&uvcg_color_matching_grp.group, - &uvcg_streaming_grp.group); - configfs_add_default_group(&uvcg_streaming_class_grp.group, - &uvcg_streaming_grp.group); + configfs_add_default_group(&uvcg_streaming_header_grp, + &uvcg_streaming_grp); + configfs_add_default_group(&uvcg_uncompressed_grp, + &uvcg_streaming_grp); + configfs_add_default_group(&uvcg_mjpeg_grp, + &uvcg_streaming_grp); + configfs_add_default_group(&uvcg_color_matching_grp, + &uvcg_streaming_grp); + configfs_add_default_group(&uvcg_streaming_class_grp, + &uvcg_streaming_grp); config_group_init_type_name(&opts->func_inst.group, "", &uvc_func_type); - configfs_add_default_group(&uvcg_control_grp.group, + configfs_add_default_group(&uvcg_control_grp, &opts->func_inst.group); - configfs_add_default_group(&uvcg_streaming_grp.group, + configfs_add_default_group(&uvcg_streaming_grp, &opts->func_inst.group); return 0; From patchwork Wed Aug 1 21:54:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 10553089 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8B98D1708 for ; Wed, 1 Aug 2018 21:54:33 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7B91F28825 for ; Wed, 1 Aug 2018 21:54:33 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6F76D29138; Wed, 1 Aug 2018 21:54:33 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C319428D82 for ; Wed, 1 Aug 2018 21:54:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731925AbeHAXmX (ORCPT ); Wed, 1 Aug 2018 19:42:23 -0400 Received: from perceval.ideasonboard.com ([213.167.242.64]:57922 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725956AbeHAXmX (ORCPT ); Wed, 1 Aug 2018 19:42:23 -0400 Received: from avalon.bb.dnainternet.fi (dfj612ybrt5fhg77mgycy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:2e86:4862:ef6a:2804]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4FB671AB8; Wed, 1 Aug 2018 23:54:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1533160468; bh=Yg5w9QlUCwswZdM2pdEWN7XkiERbJPlUTRDO0sTErEo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jPZ62gpGo2f3Qx32u0JyfF/JFU2xlWp5QDr6JqXUwqau7gxL00QgdkCZ+Y751vEYb MJkQDMH8m9JLKmUTFPg0rs/3yWWnPXdrn2t2RmcgoH7jOz/qCCg+AvtjzsDkIZSRYh /aqGoGrYoP4N5RoSc9e7GZeJOw2uiQn4WItkfdtU= From: Laurent Pinchart To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Joel Pepper , Kieran Bingham , Andrzej Pietrasiewicz Subject: [PATCH v2 2/8] usb: gadget: uvc: configfs: Add section header comments Date: Thu, 2 Aug 2018 00:54:59 +0300 Message-Id: <20180801215505.7658-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> References: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The UVC configfs implementation is large and difficult to navigate. Add a bit more air to the code to make it easier to read. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- drivers/usb/gadget/function/uvc_configfs.c | 120 ++++++++++++++++++++++------- 1 file changed, 91 insertions(+), 29 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 1df94b25abe1..dbc95c9558de 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -12,6 +12,10 @@ #include "u_uvc.h" #include "uvc_configfs.h" +/* ----------------------------------------------------------------------------- + * Global Utility Structures and Macros + */ + #define UVCG_STREAMING_CONTROL_SIZE 1 #define UVC_ATTR(prefix, cname, aname) \ @@ -37,7 +41,11 @@ static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item) func_inst.group); } -/* control/header/ */ +/* ----------------------------------------------------------------------------- + * control/header/ + * control/header + */ + DECLARE_UVC_HEADER_DESCRIPTOR(1); struct uvcg_control_header { @@ -161,7 +169,6 @@ static void uvcg_control_header_drop(struct config_group *group, kfree(h); } -/* control/header */ static struct config_group uvcg_control_header_grp; static struct configfs_group_operations uvcg_control_header_grp_ops = { @@ -174,7 +181,10 @@ static const struct config_item_type uvcg_control_header_grp_type = { .ct_owner = THIS_MODULE, }; -/* control/processing/default */ +/* ----------------------------------------------------------------------------- + * control/processing/default + */ + static struct config_group uvcg_default_processing_grp; #define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \ @@ -260,16 +270,20 @@ static const struct config_item_type uvcg_default_processing_type = { .ct_owner = THIS_MODULE, }; -/* struct uvcg_processing {}; */ +/* ----------------------------------------------------------------------------- + * control/processing + */ -/* control/processing */ static struct config_group uvcg_processing_grp; static const struct config_item_type uvcg_processing_grp_type = { .ct_owner = THIS_MODULE, }; -/* control/terminal/camera/default */ +/* ----------------------------------------------------------------------------- + * control/terminal/camera/default + */ + static struct config_group uvcg_default_camera_grp; #define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \ @@ -366,16 +380,20 @@ static const struct config_item_type uvcg_default_camera_type = { .ct_owner = THIS_MODULE, }; -/* struct uvcg_camera {}; */ +/* ----------------------------------------------------------------------------- + * control/terminal/camera + */ -/* control/terminal/camera */ static struct config_group uvcg_camera_grp; static const struct config_item_type uvcg_camera_grp_type = { .ct_owner = THIS_MODULE, }; -/* control/terminal/output/default */ +/* ----------------------------------------------------------------------------- + * control/terminal/output/default + */ + static struct config_group uvcg_default_output_grp; #define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \ @@ -433,23 +451,30 @@ static const struct config_item_type uvcg_default_output_type = { .ct_owner = THIS_MODULE, }; -/* struct uvcg_output {}; */ +/* ----------------------------------------------------------------------------- + * control/terminal/output + */ -/* control/terminal/output */ static struct config_group uvcg_output_grp; static const struct config_item_type uvcg_output_grp_type = { .ct_owner = THIS_MODULE, }; -/* control/terminal */ +/* ----------------------------------------------------------------------------- + * control/terminal + */ + static struct config_group uvcg_terminal_grp; static const struct config_item_type uvcg_terminal_grp_type = { .ct_owner = THIS_MODULE, }; -/* control/class/{fs} */ +/* ----------------------------------------------------------------------------- + * control/class/{fs|ss} + */ + static struct config_group uvcg_control_class_fs_grp; static struct config_group uvcg_control_class_ss_grp; @@ -552,24 +577,32 @@ static const struct config_item_type uvcg_control_class_type = { .ct_owner = THIS_MODULE, }; -/* control/class */ +/* ----------------------------------------------------------------------------- + * control/class + */ + static struct config_group uvcg_control_class_grp; static const struct config_item_type uvcg_control_class_grp_type = { .ct_owner = THIS_MODULE, }; -/* control */ +/* ----------------------------------------------------------------------------- + * control + */ + static struct config_group uvcg_control_grp; static const struct config_item_type uvcg_control_grp_type = { .ct_owner = THIS_MODULE, }; -/* streaming/uncompressed */ -static struct config_group uvcg_uncompressed_grp; +/* ----------------------------------------------------------------------------- + * streaming/uncompressed + * streaming/mjpeg + */ -/* streaming/mjpeg */ +static struct config_group uvcg_uncompressed_grp; static struct config_group uvcg_mjpeg_grp; static struct config_item *fmt_parent[] = { @@ -658,7 +691,11 @@ struct uvcg_format_ptr { struct list_head entry; }; -/* streaming/header/ */ +/* ----------------------------------------------------------------------------- + * streaming/header/ + * streaming/header + */ + struct uvcg_streaming_header { struct config_item item; struct uvc_input_header_descriptor desc; @@ -844,7 +881,6 @@ static void uvcg_streaming_header_drop(struct config_group *group, kfree(h); } -/* streaming/header */ static struct config_group uvcg_streaming_header_grp; static struct configfs_group_operations uvcg_streaming_header_grp_ops = { @@ -857,7 +893,10 @@ static const struct config_item_type uvcg_streaming_header_grp_type = { .ct_owner = THIS_MODULE, }; -/* streaming/// */ +/* ----------------------------------------------------------------------------- + * streaming/// + */ + struct uvcg_frame { struct { u8 b_length; @@ -1168,7 +1207,10 @@ static void uvcg_frame_drop(struct config_group *group, struct config_item *item mutex_unlock(&opts->lock); } -/* streaming/uncompressed/ */ +/* ----------------------------------------------------------------------------- + * streaming/uncompressed/ + */ + struct uvcg_uncompressed { struct uvcg_format fmt; struct uvc_format_uncompressed desc; @@ -1425,7 +1467,10 @@ static const struct config_item_type uvcg_uncompressed_grp_type = { .ct_owner = THIS_MODULE, }; -/* streaming/mjpeg/ */ +/* ----------------------------------------------------------------------------- + * streaming/mjpeg/ + */ + struct uvcg_mjpeg { struct uvcg_format fmt; struct uvc_format_mjpeg desc; @@ -1619,7 +1664,10 @@ static const struct config_item_type uvcg_mjpeg_grp_type = { .ct_owner = THIS_MODULE, }; -/* streaming/color_matching/default */ +/* ----------------------------------------------------------------------------- + * streaming/color_matching/default + */ + static struct config_group uvcg_default_color_matching_grp; #define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \ @@ -1674,16 +1722,20 @@ static const struct config_item_type uvcg_default_color_matching_type = { .ct_owner = THIS_MODULE, }; -/* struct uvcg_color_matching {}; */ +/* ----------------------------------------------------------------------------- + * streaming/color_matching + */ -/* streaming/color_matching */ static struct config_group uvcg_color_matching_grp; static const struct config_item_type uvcg_color_matching_grp_type = { .ct_owner = THIS_MODULE, }; -/* streaming/class/{fs|hs|ss} */ +/* ----------------------------------------------------------------------------- + * streaming/class/{fs|hs|ss} + */ + static struct config_group uvcg_streaming_class_fs_grp; static struct config_group uvcg_streaming_class_hs_grp; static struct config_group uvcg_streaming_class_ss_grp; @@ -2027,20 +2079,30 @@ static const struct config_item_type uvcg_streaming_class_type = { .ct_owner = THIS_MODULE, }; -/* streaming/class */ +/* ----------------------------------------------------------------------------- + * streaming/class + */ + static struct config_group uvcg_streaming_class_grp; static const struct config_item_type uvcg_streaming_class_grp_type = { .ct_owner = THIS_MODULE, }; -/* streaming */ +/* ----------------------------------------------------------------------------- + * streaming + */ + static struct config_group uvcg_streaming_grp; static const struct config_item_type uvcg_streaming_grp_type = { .ct_owner = THIS_MODULE, }; +/* ----------------------------------------------------------------------------- + * UVC function + */ + static void uvc_attr_release(struct config_item *item) { struct f_uvc_opts *opts = to_f_uvc_opts(item); From patchwork Wed Aug 1 21:55:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 10553091 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BDF4315E2 for ; Wed, 1 Aug 2018 21:54:34 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AE54728825 for ; Wed, 1 Aug 2018 21:54:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A2C3429492; Wed, 1 Aug 2018 21:54:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3A85228825 for ; Wed, 1 Aug 2018 21:54:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731956AbeHAXmY (ORCPT ); Wed, 1 Aug 2018 19:42:24 -0400 Received: from perceval.ideasonboard.com ([213.167.242.64]:57934 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726174AbeHAXmY (ORCPT ); Wed, 1 Aug 2018 19:42:24 -0400 Received: from avalon.bb.dnainternet.fi (dfj612ybrt5fhg77mgycy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:2e86:4862:ef6a:2804]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0D5561ABC; Wed, 1 Aug 2018 23:54:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1533160469; bh=k/u/G5MnmB7Oe6ZcOSGClNkshSfdJwEFjw6ovhjPnTM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dtnAQ81n38y6jTLRzX2OkFSlQmTC5NEHJRQEU3S+EN+BDLemWMc3euIpW2hBkJSZU fpTH0bil1LUqO433Kv8bDeq9+Z7u36VcHlslZRBIWn+vyTumXs7xny3wkiTrERrfRE Y64SIA4bR3o6ER0Da9e8Oq04uOYcskQvpp03criA= From: Laurent Pinchart To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Joel Pepper , Kieran Bingham , Andrzej Pietrasiewicz Subject: [PATCH v2 3/8] usb: gadget: uvc: configfs: Drop leaked references to config items Date: Thu, 2 Aug 2018 00:55:00 +0300 Message-Id: <20180801215505.7658-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> References: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Some of the .allow_link() and .drop_link() operations implementations call config_group_find_item() and then leak the reference to the returned item. Fix this by dropping those references where needed. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- drivers/usb/gadget/function/uvc_configfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index dbc95c9558de..8d513cc6fb8c 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -529,6 +529,7 @@ static int uvcg_control_class_allow_link(struct config_item *src, unlock: mutex_unlock(&opts->lock); out: + config_item_put(header); mutex_unlock(su_mutex); return ret; } @@ -564,6 +565,7 @@ static void uvcg_control_class_drop_link(struct config_item *src, unlock: mutex_unlock(&opts->lock); out: + config_item_put(header); mutex_unlock(su_mutex); } @@ -2026,6 +2028,7 @@ static int uvcg_streaming_class_allow_link(struct config_item *src, unlock: mutex_unlock(&opts->lock); out: + config_item_put(header); mutex_unlock(su_mutex); return ret; } @@ -2066,6 +2069,7 @@ static void uvcg_streaming_class_drop_link(struct config_item *src, unlock: mutex_unlock(&opts->lock); out: + config_item_put(header); mutex_unlock(su_mutex); } From patchwork Wed Aug 1 21:55:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 10553095 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D152C1708 for ; Wed, 1 Aug 2018 21:54:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BE6F528825 for ; Wed, 1 Aug 2018 21:54:38 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B2770295E2; Wed, 1 Aug 2018 21:54:38 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3474228825 for ; Wed, 1 Aug 2018 21:54:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732243AbeHAXm2 (ORCPT ); Wed, 1 Aug 2018 19:42:28 -0400 Received: from perceval.ideasonboard.com ([213.167.242.64]:57922 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725956AbeHAXm1 (ORCPT ); Wed, 1 Aug 2018 19:42:27 -0400 Received: from avalon.bb.dnainternet.fi (dfj612ybrt5fhg77mgycy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:2e86:4862:ef6a:2804]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9E57A1BE5; Wed, 1 Aug 2018 23:54:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1533160470; bh=yKcPfr3MldMzA9WeHl2+Ds7ogTtRh+g2NNL+Aa7B+ZY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SmPNNBYrECsGggkShbH5AzFUPVJc5MBH5octcZir7sro0hf86dT6hNvbfXVZcElZw Ah0Ow5qMHhMKNnN0KX1zUhSGjSa44+M7E8KlBZGbAK+ofsqTFeFpj/rWo+I/uuLTpp a8lWk+kD82c5nAIaQ/gl4MdqvT07M+I52OfgHIKQ= From: Laurent Pinchart To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Joel Pepper , Kieran Bingham , Andrzej Pietrasiewicz Subject: [PATCH v2 4/8] usb: gadget: uvc: configfs: Allocate groups dynamically Date: Thu, 2 Aug 2018 00:55:01 +0300 Message-Id: <20180801215505.7658-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> References: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The UVC configfs implementation creates all groups as global static variables. This prevents creation of multiple UVC function instances, as they would all require their own configfs group instances. Fix this by allocating all groups dynamically. To avoid duplicating code around, extend the config_item_type structure with group name and children, and implement helper functions to create children automatically for most groups. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Changes since v1: - Free groups by implementing .release() handler and removing children explicitly. --- drivers/usb/gadget/function/f_uvc.c | 8 +- drivers/usb/gadget/function/uvc_configfs.c | 581 ++++++++++++++++------------- 2 files changed, 338 insertions(+), 251 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index d8ce7868fe22..95cb1b5f5ffe 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -792,6 +792,7 @@ static struct usb_function_instance *uvc_alloc_inst(void) struct uvc_output_terminal_descriptor *od; struct uvc_color_matching_descriptor *md; struct uvc_descriptor_header **ctl_cls; + int ret; opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) @@ -868,7 +869,12 @@ static struct usb_function_instance *uvc_alloc_inst(void) opts->streaming_interval = 1; opts->streaming_maxpacket = 1024; - uvcg_attach_configfs(opts); + ret = uvcg_attach_configfs(opts); + if (ret < 0) { + kfree(opts); + return ERR_PTR(ret); + } + return &opts->func_inst; } diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 8d513cc6fb8c..ae722549eabc 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -41,6 +41,71 @@ static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item) func_inst.group); } +struct uvcg_config_group_type { + struct config_item_type type; + const char *name; + const struct uvcg_config_group_type **children; + int (*create_children)(struct config_group *group); +}; + +static void uvcg_config_item_release(struct config_item *item) +{ + struct config_group *group = to_config_group(item); + + kfree(group); +} + +static struct configfs_item_operations uvcg_config_item_ops = { + .release = uvcg_config_item_release, +}; + +static int uvcg_config_create_group(struct config_group *parent, + const struct uvcg_config_group_type *type); + +static int uvcg_config_create_children(struct config_group *group, + const struct uvcg_config_group_type *type) +{ + const struct uvcg_config_group_type **child; + int ret; + + if (type->create_children) + return type->create_children(group); + + for (child = type->children; child && *child; ++child) { + ret = uvcg_config_create_group(group, *child); + if (ret < 0) + return ret; + } + + return 0; +} + +static int uvcg_config_create_group(struct config_group *parent, + const struct uvcg_config_group_type *type) +{ + struct config_group *group; + + group = kzalloc(sizeof(*group), GFP_KERNEL); + if (!group) + return -ENOMEM; + + config_group_init_type_name(group, type->name, &type->type); + configfs_add_default_group(group, parent); + + return uvcg_config_create_children(group, type); +} + +static void uvcg_config_remove_children(struct config_group *group) +{ + struct config_group *child, *n; + + list_for_each_entry_safe(child, n, &group->default_groups, group_entry) { + list_del(&child->group_entry); + uvcg_config_remove_children(child); + config_item_put(&child->cg_item); + } +} + /* ----------------------------------------------------------------------------- * control/header/ * control/header @@ -137,6 +202,7 @@ static struct configfs_attribute *uvcg_control_header_attrs[] = { }; static const struct config_item_type uvcg_control_header_type = { + .ct_item_ops = &uvcg_config_item_ops, .ct_attrs = uvcg_control_header_attrs, .ct_owner = THIS_MODULE, }; @@ -161,32 +227,23 @@ static struct config_item *uvcg_control_header_make(struct config_group *group, return &h->item; } -static void uvcg_control_header_drop(struct config_group *group, - struct config_item *item) -{ - struct uvcg_control_header *h = to_uvcg_control_header(item); - - kfree(h); -} - -static struct config_group uvcg_control_header_grp; - static struct configfs_group_operations uvcg_control_header_grp_ops = { .make_item = uvcg_control_header_make, - .drop_item = uvcg_control_header_drop, }; -static const struct config_item_type uvcg_control_header_grp_type = { - .ct_group_ops = &uvcg_control_header_grp_ops, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_control_header_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_control_header_grp_ops, + .ct_owner = THIS_MODULE, + }, + .name = "header", }; /* ----------------------------------------------------------------------------- * control/processing/default */ -static struct config_group uvcg_default_processing_grp; - #define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_processing_##cname##_show( \ struct config_item *item, char *page) \ @@ -265,27 +322,35 @@ static struct configfs_attribute *uvcg_default_processing_attrs[] = { NULL, }; -static const struct config_item_type uvcg_default_processing_type = { - .ct_attrs = uvcg_default_processing_attrs, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_default_processing_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_default_processing_attrs, + .ct_owner = THIS_MODULE, + }, + .name = "default", }; /* ----------------------------------------------------------------------------- * control/processing */ -static struct config_group uvcg_processing_grp; - -static const struct config_item_type uvcg_processing_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_processing_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "processing", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_default_processing_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- * control/terminal/camera/default */ -static struct config_group uvcg_default_camera_grp; - #define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_camera_##cname##_show( \ struct config_item *item, char *page) \ @@ -375,27 +440,35 @@ static struct configfs_attribute *uvcg_default_camera_attrs[] = { NULL, }; -static const struct config_item_type uvcg_default_camera_type = { - .ct_attrs = uvcg_default_camera_attrs, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_default_camera_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_default_camera_attrs, + .ct_owner = THIS_MODULE, + }, + .name = "default", }; /* ----------------------------------------------------------------------------- * control/terminal/camera */ -static struct config_group uvcg_camera_grp; - -static const struct config_item_type uvcg_camera_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_camera_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "camera", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_default_camera_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- * control/terminal/output/default */ -static struct config_group uvcg_default_output_grp; - #define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_output_##cname##_show( \ struct config_item *item, char *page) \ @@ -446,47 +519,68 @@ static struct configfs_attribute *uvcg_default_output_attrs[] = { NULL, }; -static const struct config_item_type uvcg_default_output_type = { - .ct_attrs = uvcg_default_output_attrs, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_default_output_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_default_output_attrs, + .ct_owner = THIS_MODULE, + }, + .name = "default", }; /* ----------------------------------------------------------------------------- * control/terminal/output */ -static struct config_group uvcg_output_grp; - -static const struct config_item_type uvcg_output_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_output_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "output", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_default_output_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- * control/terminal */ -static struct config_group uvcg_terminal_grp; - -static const struct config_item_type uvcg_terminal_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_terminal_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "terminal", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_camera_grp_type, + &uvcg_output_grp_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- * control/class/{fs|ss} */ -static struct config_group uvcg_control_class_fs_grp; -static struct config_group uvcg_control_class_ss_grp; +struct uvcg_control_class_group { + struct config_group group; + const char *name; +}; static inline struct uvc_descriptor_header **uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o) { - struct config_group *group = to_config_group(i); + struct uvcg_control_class_group *group = + container_of(i, struct uvcg_control_class_group, + group.cg_item); - if (group == &uvcg_control_class_fs_grp) + if (!strcmp(group->name, "fs")) return o->uvc_fs_control_cls; - if (group == &uvcg_control_class_ss_grp) + if (!strcmp(group->name, "ss")) return o->uvc_ss_control_cls; return NULL; @@ -570,6 +664,7 @@ static void uvcg_control_class_drop_link(struct config_item *src, } static struct configfs_item_operations uvcg_control_class_item_ops = { + .release = uvcg_config_item_release, .allow_link = uvcg_control_class_allow_link, .drop_link = uvcg_control_class_drop_link, }; @@ -583,20 +678,54 @@ static const struct config_item_type uvcg_control_class_type = { * control/class */ -static struct config_group uvcg_control_class_grp; +static int uvcg_control_class_create_children(struct config_group *parent) +{ + static const char * const names[] = { "fs", "ss" }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(names); ++i) { + struct uvcg_control_class_group *group; -static const struct config_item_type uvcg_control_class_grp_type = { - .ct_owner = THIS_MODULE, + group = kzalloc(sizeof(*group), GFP_KERNEL); + if (!group) + return -ENOMEM; + + group->name = names[i]; + + config_group_init_type_name(&group->group, group->name, + &uvcg_control_class_type); + configfs_add_default_group(&group->group, parent); + } + + return 0; +} + +static const struct uvcg_config_group_type uvcg_control_class_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "class", + .create_children = uvcg_control_class_create_children, }; /* ----------------------------------------------------------------------------- * control */ -static struct config_group uvcg_control_grp; - -static const struct config_item_type uvcg_control_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_control_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "control", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_control_header_grp_type, + &uvcg_processing_grp_type, + &uvcg_terminal_grp_type, + &uvcg_control_class_grp_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- @@ -604,12 +733,9 @@ static const struct config_item_type uvcg_control_grp_type = { * streaming/mjpeg */ -static struct config_group uvcg_uncompressed_grp; -static struct config_group uvcg_mjpeg_grp; - -static struct config_item *fmt_parent[] = { - &uvcg_uncompressed_grp.cg_item, - &uvcg_mjpeg_grp.cg_item, +static const char * const uvcg_format_names[] = { + "uncompressed", + "mjpeg", }; enum uvcg_format_type { @@ -735,10 +861,22 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, goto out; } - for (i = 0; i < ARRAY_SIZE(fmt_parent); ++i) - if (target->ci_parent == fmt_parent[i]) + /* + * Linking is only allowed to direct children of the format nodes + * (streaming/uncompressed or streaming/mjpeg nodes). First check that + * the grand-parent of the target matches the grand-parent of the source + * (the streaming node), and then verify that the target parent is a + * format node. + */ + if (src->ci_parent->ci_parent != target->ci_parent->ci_parent) + goto out; + + for (i = 0; i < ARRAY_SIZE(uvcg_format_names); ++i) { + if (!strcmp(target->ci_parent->ci_name, uvcg_format_names[i])) break; - if (i == ARRAY_SIZE(fmt_parent)) + } + + if (i == ARRAY_SIZE(uvcg_format_names)) goto out; target_fmt = container_of(to_config_group(target), struct uvcg_format, @@ -798,8 +936,9 @@ static void uvcg_streaming_header_drop_link(struct config_item *src, } static struct configfs_item_operations uvcg_streaming_header_item_ops = { - .allow_link = uvcg_streaming_header_allow_link, - .drop_link = uvcg_streaming_header_drop_link, + .release = uvcg_config_item_release, + .allow_link = uvcg_streaming_header_allow_link, + .drop_link = uvcg_streaming_header_drop_link, }; #define UVCG_STREAMING_HEADER_ATTR(cname, aname, conv) \ @@ -875,24 +1014,17 @@ static struct config_item return &h->item; } -static void uvcg_streaming_header_drop(struct config_group *group, - struct config_item *item) -{ - struct uvcg_streaming_header *h = to_uvcg_streaming_header(item); - - kfree(h); -} - -static struct config_group uvcg_streaming_header_grp; - static struct configfs_group_operations uvcg_streaming_header_grp_ops = { .make_item = uvcg_streaming_header_make, - .drop_item = uvcg_streaming_header_drop, }; -static const struct config_item_type uvcg_streaming_header_grp_type = { - .ct_group_ops = &uvcg_streaming_header_grp_ops, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_streaming_header_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_streaming_header_grp_ops, + .ct_owner = THIS_MODULE, + }, + .name = "header", }; /* ----------------------------------------------------------------------------- @@ -900,6 +1032,8 @@ static const struct config_item_type uvcg_streaming_header_grp_type = { */ struct uvcg_frame { + struct config_item item; + enum uvcg_format_type fmt_type; struct { u8 b_length; u8 b_descriptor_type; @@ -915,8 +1049,6 @@ struct uvcg_frame { u8 b_frame_interval_type; } __attribute__((packed)) frame; u32 *dw_frame_interval; - enum uvcg_format_type fmt_type; - struct config_item item; }; static struct uvcg_frame *to_uvcg_frame(struct config_item *item) @@ -1143,6 +1275,7 @@ static struct configfs_attribute *uvcg_frame_attrs[] = { }; static const struct config_item_type uvcg_frame_type = { + .ct_item_ops = &uvcg_config_item_ops, .ct_attrs = uvcg_frame_attrs, .ct_owner = THIS_MODULE, }; @@ -1194,7 +1327,6 @@ static struct config_item *uvcg_frame_make(struct config_group *group, static void uvcg_frame_drop(struct config_group *group, struct config_item *item) { - struct uvcg_frame *h = to_uvcg_frame(item); struct uvcg_format *fmt; struct f_uvc_opts *opts; struct config_item *opts_item; @@ -1205,8 +1337,9 @@ static void uvcg_frame_drop(struct config_group *group, struct config_item *item mutex_lock(&opts->lock); fmt = to_uvcg_format(&group->cg_item); --fmt->num_frames; - kfree(h); mutex_unlock(&opts->lock); + + config_item_put(item); } /* ----------------------------------------------------------------------------- @@ -1415,6 +1548,7 @@ static struct configfs_attribute *uvcg_uncompressed_attrs[] = { }; static const struct config_item_type uvcg_uncompressed_type = { + .ct_item_ops = &uvcg_config_item_ops, .ct_group_ops = &uvcg_uncompressed_group_ops, .ct_attrs = uvcg_uncompressed_attrs, .ct_owner = THIS_MODULE, @@ -1451,22 +1585,17 @@ static struct config_group *uvcg_uncompressed_make(struct config_group *group, return &h->fmt.group; } -static void uvcg_uncompressed_drop(struct config_group *group, - struct config_item *item) -{ - struct uvcg_uncompressed *h = to_uvcg_uncompressed(item); - - kfree(h); -} - static struct configfs_group_operations uvcg_uncompressed_grp_ops = { .make_group = uvcg_uncompressed_make, - .drop_item = uvcg_uncompressed_drop, }; -static const struct config_item_type uvcg_uncompressed_grp_type = { - .ct_group_ops = &uvcg_uncompressed_grp_ops, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_uncompressed_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_uncompressed_grp_ops, + .ct_owner = THIS_MODULE, + }, + .name = "uncompressed", }; /* ----------------------------------------------------------------------------- @@ -1618,6 +1747,7 @@ static struct configfs_attribute *uvcg_mjpeg_attrs[] = { }; static const struct config_item_type uvcg_mjpeg_type = { + .ct_item_ops = &uvcg_config_item_ops, .ct_group_ops = &uvcg_mjpeg_group_ops, .ct_attrs = uvcg_mjpeg_attrs, .ct_owner = THIS_MODULE, @@ -1648,30 +1778,23 @@ static struct config_group *uvcg_mjpeg_make(struct config_group *group, return &h->fmt.group; } -static void uvcg_mjpeg_drop(struct config_group *group, - struct config_item *item) -{ - struct uvcg_mjpeg *h = to_uvcg_mjpeg(item); - - kfree(h); -} - static struct configfs_group_operations uvcg_mjpeg_grp_ops = { .make_group = uvcg_mjpeg_make, - .drop_item = uvcg_mjpeg_drop, }; -static const struct config_item_type uvcg_mjpeg_grp_type = { - .ct_group_ops = &uvcg_mjpeg_grp_ops, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_mjpeg_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_mjpeg_grp_ops, + .ct_owner = THIS_MODULE, + }, + .name = "mjpeg", }; /* ----------------------------------------------------------------------------- * streaming/color_matching/default */ -static struct config_group uvcg_default_color_matching_grp; - #define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_color_matching_##cname##_show( \ struct config_item *item, char *page) \ @@ -1719,41 +1842,54 @@ static struct configfs_attribute *uvcg_default_color_matching_attrs[] = { NULL, }; -static const struct config_item_type uvcg_default_color_matching_type = { - .ct_attrs = uvcg_default_color_matching_attrs, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_default_color_matching_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_default_color_matching_attrs, + .ct_owner = THIS_MODULE, + }, + .name = "default", }; /* ----------------------------------------------------------------------------- * streaming/color_matching */ -static struct config_group uvcg_color_matching_grp; - -static const struct config_item_type uvcg_color_matching_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_color_matching_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "color_matching", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_default_color_matching_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- * streaming/class/{fs|hs|ss} */ -static struct config_group uvcg_streaming_class_fs_grp; -static struct config_group uvcg_streaming_class_hs_grp; -static struct config_group uvcg_streaming_class_ss_grp; +struct uvcg_streaming_class_group { + struct config_group group; + const char *name; +}; static inline struct uvc_descriptor_header ***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o) { - struct config_group *group = to_config_group(i); + struct uvcg_streaming_class_group *group = + container_of(i, struct uvcg_streaming_class_group, + group.cg_item); - if (group == &uvcg_streaming_class_fs_grp) + if (!strcmp(group->name, "fs")) return &o->uvc_fs_streaming_cls; - if (group == &uvcg_streaming_class_hs_grp) + if (!strcmp(group->name, "hs")) return &o->uvc_hs_streaming_cls; - if (group == &uvcg_streaming_class_ss_grp) + if (!strcmp(group->name, "ss")) return &o->uvc_ss_streaming_cls; return NULL; @@ -2074,6 +2210,7 @@ static void uvcg_streaming_class_drop_link(struct config_item *src, } static struct configfs_item_operations uvcg_streaming_class_item_ops = { + .release = uvcg_config_item_release, .allow_link = uvcg_streaming_class_allow_link, .drop_link = uvcg_streaming_class_drop_link, }; @@ -2087,35 +2224,71 @@ static const struct config_item_type uvcg_streaming_class_type = { * streaming/class */ -static struct config_group uvcg_streaming_class_grp; +static int uvcg_streaming_class_create_children(struct config_group *parent) +{ + static const char * const names[] = { "fs", "hs", "ss" }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(names); ++i) { + struct uvcg_streaming_class_group *group; + + group = kzalloc(sizeof(*group), GFP_KERNEL); + if (!group) + return -ENOMEM; + + group->name = names[i]; -static const struct config_item_type uvcg_streaming_class_grp_type = { - .ct_owner = THIS_MODULE, + config_group_init_type_name(&group->group, group->name, + &uvcg_streaming_class_type); + configfs_add_default_group(&group->group, parent); + } + + return 0; +} + +static const struct uvcg_config_group_type uvcg_streaming_class_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "class", + .create_children = uvcg_streaming_class_create_children, }; /* ----------------------------------------------------------------------------- * streaming */ -static struct config_group uvcg_streaming_grp; - -static const struct config_item_type uvcg_streaming_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_streaming_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "streaming", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_streaming_header_grp_type, + &uvcg_uncompressed_grp_type, + &uvcg_mjpeg_grp_type, + &uvcg_color_matching_grp_type, + &uvcg_streaming_class_grp_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- * UVC function */ -static void uvc_attr_release(struct config_item *item) +static void uvc_func_item_release(struct config_item *item) { struct f_uvc_opts *opts = to_f_uvc_opts(item); + uvcg_config_remove_children(to_config_group(item)); usb_put_function_instance(&opts->func_inst); } -static struct configfs_item_operations uvc_item_ops = { - .release = uvc_attr_release, +static struct configfs_item_operations uvc_func_item_ops = { + .release = uvc_func_item_release, }; #define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \ @@ -2183,123 +2356,31 @@ static struct configfs_attribute *uvc_attrs[] = { NULL, }; -static const struct config_item_type uvc_func_type = { - .ct_item_ops = &uvc_item_ops, - .ct_attrs = uvc_attrs, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvc_func_type = { + .type = { + .ct_item_ops = &uvc_func_item_ops, + .ct_attrs = uvc_attrs, + .ct_owner = THIS_MODULE, + }, + .name = "", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_control_grp_type, + &uvcg_streaming_grp_type, + NULL, + }, }; int uvcg_attach_configfs(struct f_uvc_opts *opts) { - config_group_init_type_name(&uvcg_control_header_grp, - "header", - &uvcg_control_header_grp_type); - - config_group_init_type_name(&uvcg_default_processing_grp, - "default", &uvcg_default_processing_type); - config_group_init_type_name(&uvcg_processing_grp, - "processing", &uvcg_processing_grp_type); - configfs_add_default_group(&uvcg_default_processing_grp, - &uvcg_processing_grp); - - config_group_init_type_name(&uvcg_default_camera_grp, - "default", &uvcg_default_camera_type); - config_group_init_type_name(&uvcg_camera_grp, - "camera", &uvcg_camera_grp_type); - configfs_add_default_group(&uvcg_default_camera_grp, - &uvcg_camera_grp); - - config_group_init_type_name(&uvcg_default_output_grp, - "default", &uvcg_default_output_type); - config_group_init_type_name(&uvcg_output_grp, - "output", &uvcg_output_grp_type); - configfs_add_default_group(&uvcg_default_output_grp, - &uvcg_output_grp); - - config_group_init_type_name(&uvcg_terminal_grp, - "terminal", &uvcg_terminal_grp_type); - configfs_add_default_group(&uvcg_camera_grp, - &uvcg_terminal_grp); - configfs_add_default_group(&uvcg_output_grp, - &uvcg_terminal_grp); - - config_group_init_type_name(&uvcg_control_class_fs_grp, - "fs", &uvcg_control_class_type); - config_group_init_type_name(&uvcg_control_class_ss_grp, - "ss", &uvcg_control_class_type); - config_group_init_type_name(&uvcg_control_class_grp, - "class", - &uvcg_control_class_grp_type); - configfs_add_default_group(&uvcg_control_class_fs_grp, - &uvcg_control_class_grp); - configfs_add_default_group(&uvcg_control_class_ss_grp, - &uvcg_control_class_grp); - - config_group_init_type_name(&uvcg_control_grp, - "control", - &uvcg_control_grp_type); - configfs_add_default_group(&uvcg_control_header_grp, - &uvcg_control_grp); - configfs_add_default_group(&uvcg_processing_grp, - &uvcg_control_grp); - configfs_add_default_group(&uvcg_terminal_grp, - &uvcg_control_grp); - configfs_add_default_group(&uvcg_control_class_grp, - &uvcg_control_grp); - - config_group_init_type_name(&uvcg_streaming_header_grp, - "header", - &uvcg_streaming_header_grp_type); - config_group_init_type_name(&uvcg_uncompressed_grp, - "uncompressed", - &uvcg_uncompressed_grp_type); - config_group_init_type_name(&uvcg_mjpeg_grp, - "mjpeg", - &uvcg_mjpeg_grp_type); - config_group_init_type_name(&uvcg_default_color_matching_grp, - "default", - &uvcg_default_color_matching_type); - config_group_init_type_name(&uvcg_color_matching_grp, - "color_matching", - &uvcg_color_matching_grp_type); - configfs_add_default_group(&uvcg_default_color_matching_grp, - &uvcg_color_matching_grp); - - config_group_init_type_name(&uvcg_streaming_class_fs_grp, - "fs", &uvcg_streaming_class_type); - config_group_init_type_name(&uvcg_streaming_class_hs_grp, - "hs", &uvcg_streaming_class_type); - config_group_init_type_name(&uvcg_streaming_class_ss_grp, - "ss", &uvcg_streaming_class_type); - config_group_init_type_name(&uvcg_streaming_class_grp, - "class", &uvcg_streaming_class_grp_type); - configfs_add_default_group(&uvcg_streaming_class_fs_grp, - &uvcg_streaming_class_grp); - configfs_add_default_group(&uvcg_streaming_class_hs_grp, - &uvcg_streaming_class_grp); - configfs_add_default_group(&uvcg_streaming_class_ss_grp, - &uvcg_streaming_class_grp); - - config_group_init_type_name(&uvcg_streaming_grp, - "streaming", &uvcg_streaming_grp_type); - configfs_add_default_group(&uvcg_streaming_header_grp, - &uvcg_streaming_grp); - configfs_add_default_group(&uvcg_uncompressed_grp, - &uvcg_streaming_grp); - configfs_add_default_group(&uvcg_mjpeg_grp, - &uvcg_streaming_grp); - configfs_add_default_group(&uvcg_color_matching_grp, - &uvcg_streaming_grp); - configfs_add_default_group(&uvcg_streaming_class_grp, - &uvcg_streaming_grp); - - config_group_init_type_name(&opts->func_inst.group, - "", - &uvc_func_type); - configfs_add_default_group(&uvcg_control_grp, - &opts->func_inst.group); - configfs_add_default_group(&uvcg_streaming_grp, - &opts->func_inst.group); + int ret; - return 0; + config_group_init_type_name(&opts->func_inst.group, uvc_func_type.name, + &uvc_func_type.type); + + ret = uvcg_config_create_children(&opts->func_inst.group, + &uvc_func_type); + if (ret < 0) + config_group_put(&opts->func_inst.group); + + return ret; } From patchwork Wed Aug 1 21:55:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 10553093 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 836F015E2 for ; Wed, 1 Aug 2018 21:54:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 741FF28825 for ; Wed, 1 Aug 2018 21:54:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 68DA7295E2; Wed, 1 Aug 2018 21:54:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DE58728825 for ; Wed, 1 Aug 2018 21:54:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732127AbeHAXm0 (ORCPT ); Wed, 1 Aug 2018 19:42:26 -0400 Received: from perceval.ideasonboard.com ([213.167.242.64]:57934 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726174AbeHAXm0 (ORCPT ); Wed, 1 Aug 2018 19:42:26 -0400 Received: from avalon.bb.dnainternet.fi (dfj612ybrt5fhg77mgycy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:2e86:4862:ef6a:2804]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 50F911C88; Wed, 1 Aug 2018 23:54:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1533160470; bh=P2vloENvbZo/+DtZrHv+nGqYOZlNQcimdb7mQ7wJj28=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Hfp1PK1uhngfnt3zwf6uMQO1AHKsjGhNnYd3OFGTdrsjkqY93nn1tOebC04YQj0zV CX3kMUnqlT+peBsypCSSLlhmFHn6QLPnzTEucP8Payj7qN2UntoqZuKlrJJUq1rBy5 +lf+NpIBtP35iWgtWHX4VQARWncWK92kCVh32SFU= From: Laurent Pinchart To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Joel Pepper , Kieran Bingham , Andrzej Pietrasiewicz Subject: [PATCH v2 5/8] usb: gadget: uvc: configfs: Add interface number attributes Date: Thu, 2 Aug 2018 00:55:02 +0300 Message-Id: <20180801215505.7658-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> References: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The video control and video streaming interface numbers are needed in the UVC gadget userspace stack to reply to UVC requests. They are hardcoded to fixed values at the moment, preventing configurations with multiple functions. To fix this, make them dynamically discoverable by userspace through read-only configfs attributes in /control/bInterfaceNumber and /streaming/bInterfaceNumber respectively. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Changes since v1: - Document the new attribute --- Documentation/ABI/testing/configfs-usb-gadget-uvc | 8 +++ drivers/usb/gadget/function/f_uvc.c | 2 + drivers/usb/gadget/function/u_uvc.h | 3 ++ drivers/usb/gadget/function/uvc_configfs.c | 62 +++++++++++++++++++++++ 4 files changed, 75 insertions(+) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index 9281e2aa38df..490a0136fb02 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -12,6 +12,10 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Control descriptors + All attributes read only: + bInterfaceNumber - USB interface number for this + streaming interface + What: /config/usb-gadget/gadget/functions/uvc.name/control/class Date: Dec 2014 KernelVersion: 4.0 @@ -109,6 +113,10 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Streaming descriptors + All attributes read only: + bInterfaceNumber - USB interface number for this + streaming interface + What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class Date: Dec 2014 KernelVersion: 4.0 diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 95cb1b5f5ffe..4ea987741e6e 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -699,12 +699,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) uvc_iad.bFirstInterface = ret; uvc_control_intf.bInterfaceNumber = ret; uvc->control_intf = ret; + opts->control_interface = ret; if ((ret = usb_interface_id(c, f)) < 0) goto error; uvc_streaming_intf_alt0.bInterfaceNumber = ret; uvc_streaming_intf_alt1.bInterfaceNumber = ret; uvc->streaming_intf = ret; + opts->streaming_interface = ret; /* Copy descriptors */ f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h index 2ed292e94fbc..5242d489e20a 100644 --- a/drivers/usb/gadget/function/u_uvc.h +++ b/drivers/usb/gadget/function/u_uvc.h @@ -25,6 +25,9 @@ struct f_uvc_opts { unsigned int streaming_maxpacket; unsigned int streaming_maxburst; + unsigned int control_interface; + unsigned int streaming_interface; + /* * Control descriptors array pointers for full-/high-speed and * super-speed. They point by default to the uvc_fs_control_cls and diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index ae722549eabc..fa8d2e1f54ba 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -713,9 +713,40 @@ static const struct uvcg_config_group_type uvcg_control_class_grp_type = { * control */ +static ssize_t uvcg_default_control_b_interface_number_show( + struct config_item *item, char *page) +{ + struct config_group *group = to_config_group(item); + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct config_item *opts_item; + struct f_uvc_opts *opts; + int result = 0; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + opts_item = item->ci_parent; + opts = to_f_uvc_opts(opts_item); + + mutex_lock(&opts->lock); + result += sprintf(page, "%u\n", opts->control_interface); + mutex_unlock(&opts->lock); + + mutex_unlock(su_mutex); + + return result; +} + +UVC_ATTR_RO(uvcg_default_control_, b_interface_number, bInterfaceNumber); + +static struct configfs_attribute *uvcg_default_control_attrs[] = { + &uvcg_default_control_attr_b_interface_number, + NULL, +}; + static const struct uvcg_config_group_type uvcg_control_grp_type = { .type = { .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_default_control_attrs, .ct_owner = THIS_MODULE, }, .name = "control", @@ -2259,9 +2290,40 @@ static const struct uvcg_config_group_type uvcg_streaming_class_grp_type = { * streaming */ +static ssize_t uvcg_default_streaming_b_interface_number_show( + struct config_item *item, char *page) +{ + struct config_group *group = to_config_group(item); + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct config_item *opts_item; + struct f_uvc_opts *opts; + int result = 0; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + opts_item = item->ci_parent; + opts = to_f_uvc_opts(opts_item); + + mutex_lock(&opts->lock); + result += sprintf(page, "%u\n", opts->streaming_interface); + mutex_unlock(&opts->lock); + + mutex_unlock(su_mutex); + + return result; +} + +UVC_ATTR_RO(uvcg_default_streaming_, b_interface_number, bInterfaceNumber); + +static struct configfs_attribute *uvcg_default_streaming_attrs[] = { + &uvcg_default_streaming_attr_b_interface_number, + NULL, +}; + static const struct uvcg_config_group_type uvcg_streaming_grp_type = { .type = { .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_default_streaming_attrs, .ct_owner = THIS_MODULE, }, .name = "streaming", From patchwork Wed Aug 1 21:55:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 10553097 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2E65D1822 for ; Wed, 1 Aug 2018 21:54:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1F44428825 for ; Wed, 1 Aug 2018 21:54:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 139CB29492; Wed, 1 Aug 2018 21:54:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8D06C28D82 for ; Wed, 1 Aug 2018 21:54:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732312AbeHAXm3 (ORCPT ); Wed, 1 Aug 2018 19:42:29 -0400 Received: from perceval.ideasonboard.com ([213.167.242.64]:57934 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726174AbeHAXm2 (ORCPT ); Wed, 1 Aug 2018 19:42:28 -0400 Received: from avalon.bb.dnainternet.fi (dfj612ybrt5fhg77mgycy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:2e86:4862:ef6a:2804]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E1B371C8D; Wed, 1 Aug 2018 23:54:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1533160471; bh=siC8zOF4SluPXoQIJruqoQnumAMgwamah/EcwJ9EYTc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ox++R6MwwAmWU2s0KV/4Ip+GVrAwsROwTroMcWsBE+TbqvZr4L4tZwFTME3q+Si4X RnKvke+Ir5B1Z63j8yH6teLBpZKiuH2kqX1z7hW7WISfgbbScQNhPvORCEKoxjLwKa 5FSkMqQ/OrMKFulwFJKhVVmLMWicR2mjaXoXfFoQ= From: Laurent Pinchart To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Joel Pepper , Kieran Bingham , Andrzej Pietrasiewicz Subject: [PATCH v2 6/8] usb: gadget: uvc: configfs: Add bFormatIndex attributes Date: Thu, 2 Aug 2018 00:55:03 +0300 Message-Id: <20180801215505.7658-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> References: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The UVC format description are numbered using the descriptor's bFormatIndex field. The index is used in UVC requests, and is thus needed to handle requests in userspace. Make it dynamically discoverable by exposing it in a bFormatIndex configfs attribute of the uncompressed and mjpeg format config items. The bFormatIndex value exposed through the attribute is stored in the config item private data. However, that value is never set: the driver instead computes the bFormatIndex value when linking the stream class header in the configfs hierarchy and stores it directly in the class descriptors in a separate structure. In order to expose the value through the configfs attribute, store it in the config item private data as well. This results in a small code simplification. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Changes since v1: - Squash patch "usb: gadget: uvc: configfs: Document the bFormatIndex attribute". --- Documentation/ABI/testing/configfs-usb-gadget-uvc | 8 ++++++++ drivers/usb/gadget/function/uvc_configfs.c | 14 ++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index 490a0136fb02..a6cc8d6d398e 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -168,6 +168,10 @@ Description: Specific MJPEG format descriptors All attributes read only, except bmaControls and bDefaultFrameIndex: + bFormatIndex - unique id for this format descriptor; + only defined after parent header is + linked into the streaming class; + read-only bmaControls - this format's data for bmaControls in the streaming header bmInterfaceFlags - specifies interlace information, @@ -212,6 +216,10 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Specific uncompressed format descriptors + bFormatIndex - unique id for this format descriptor; + only defined after parent header is + linked into the streaming class; + read-only bmaControls - this format's data for bmaControls in the streaming header bmInterfaceFlags - specifies interlace information, diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index fa8d2e1f54ba..5cee8aca3734 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -1538,6 +1538,7 @@ UVC_ATTR(uvcg_uncompressed_, cname, aname); #define identity_conv(x) (x) +UVCG_UNCOMPRESSED_ATTR_RO(b_format_index, bFormatIndex, identity_conv); UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, identity_conv); UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex, identity_conv); @@ -1568,6 +1569,7 @@ uvcg_uncompressed_bma_controls_store(struct config_item *item, UVC_ATTR(uvcg_uncompressed_, bma_controls, bmaControls); static struct configfs_attribute *uvcg_uncompressed_attrs[] = { + &uvcg_uncompressed_attr_b_format_index, &uvcg_uncompressed_attr_guid_format, &uvcg_uncompressed_attr_b_bits_per_pixel, &uvcg_uncompressed_attr_b_default_frame_index, @@ -1738,6 +1740,7 @@ UVC_ATTR(uvcg_mjpeg_, cname, aname) #define identity_conv(x) (x) +UVCG_MJPEG_ATTR_RO(b_format_index, bFormatIndex, identity_conv); UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex, identity_conv); UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, identity_conv); @@ -1768,6 +1771,7 @@ uvcg_mjpeg_bma_controls_store(struct config_item *item, UVC_ATTR(uvcg_mjpeg_, bma_controls, bmaControls); static struct configfs_attribute *uvcg_mjpeg_attrs[] = { + &uvcg_mjpeg_attr_b_format_index, &uvcg_mjpeg_attr_b_default_frame_index, &uvcg_mjpeg_attr_bm_flags, &uvcg_mjpeg_attr_b_aspect_ratio_x, @@ -2079,24 +2083,22 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, struct uvcg_format *fmt = priv1; if (fmt->type == UVCG_UNCOMPRESSED) { - struct uvc_format_uncompressed *unc = *dest; struct uvcg_uncompressed *u = container_of(fmt, struct uvcg_uncompressed, fmt); + u->desc.bFormatIndex = n + 1; + u->desc.bNumFrameDescriptors = fmt->num_frames; memcpy(*dest, &u->desc, sizeof(u->desc)); *dest += sizeof(u->desc); - unc->bNumFrameDescriptors = fmt->num_frames; - unc->bFormatIndex = n + 1; } else if (fmt->type == UVCG_MJPEG) { - struct uvc_format_mjpeg *mjp = *dest; struct uvcg_mjpeg *m = container_of(fmt, struct uvcg_mjpeg, fmt); + m->desc.bFormatIndex = n + 1; + m->desc.bNumFrameDescriptors = fmt->num_frames; memcpy(*dest, &m->desc, sizeof(m->desc)); *dest += sizeof(m->desc); - mjp->bNumFrameDescriptors = fmt->num_frames; - mjp->bFormatIndex = n + 1; } else { return -EINVAL; } From patchwork Wed Aug 1 21:55:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 10553099 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2033515E2 for ; Wed, 1 Aug 2018 21:54:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0F62928825 for ; Wed, 1 Aug 2018 21:54:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0389F29492; Wed, 1 Aug 2018 21:54:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5636E28825 for ; Wed, 1 Aug 2018 21:54:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732291AbeHAXma (ORCPT ); Wed, 1 Aug 2018 19:42:30 -0400 Received: from perceval.ideasonboard.com ([213.167.242.64]:57922 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725956AbeHAXm3 (ORCPT ); Wed, 1 Aug 2018 19:42:29 -0400 Received: from avalon.bb.dnainternet.fi (dfj612ybrt5fhg77mgycy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:2e86:4862:ef6a:2804]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7D3A52A79; Wed, 1 Aug 2018 23:54:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1533160471; bh=Tm3h2hgct0W2TompN7ubrmGjBQMP4IEfnBbaBDNSFH4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pbn3igO97OqhzUgt2okqnt0wQI4NFSTExNVd54tP4bhAZZy0rKc7XUOSEcJdMNZrJ n7qdW+jqcVIHCNKduCf1k7dtzC/3OLwrAWCheBBiBkEOlT71NX+yND4hE0poGaT+Rt OdR51UM4GG8GkEL16bVJSG25zRYk9RX3+UcF1Vwg= From: Laurent Pinchart To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Joel Pepper , Kieran Bingham , Andrzej Pietrasiewicz Subject: [PATCH v2 7/8] usb: gadget: uvc: configfs: Add bFrameIndex attributes Date: Thu, 2 Aug 2018 00:55:04 +0300 Message-Id: <20180801215505.7658-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> References: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Joel Pepper - Add bFrameIndex as a UVCG_FRAME_ATTR_RO for each frame size. - Automatically assign ascending bFrameIndex to each frame in a format. Before all "bFrameindex" attributes were set to "1" with no way to configure the gadget otherwise. This resulted in the host always negotiating for bFrameIndex 1 (i.e. the first framesize of the gadget). After the negotiation the host driver will set the user or application selected framesize, while the gadget is actually set to the first framesize. Now, when the containing format is linked into the streaming header, iterate over all child frame descriptors and assign ascending indices. The automatically assigned indices can be read from the new read only bFrameIndex configsfs attribute in each frame descriptor item. Signed-off-by: Joel Pepper [Simplified documentation, renamed function, blank space update] Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Documentation/ABI/testing/configfs-usb-gadget-uvc | 8 ++++ drivers/usb/gadget/function/uvc_configfs.c | 56 +++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index a6cc8d6d398e..809765bd9573 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -189,6 +189,10 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Specific MJPEG frame descriptors + bFrameIndex - unique id for this framedescriptor; + only defined after parent format is + linked into the streaming header; + read-only dwFrameInterval - indicates how frame interval can be programmed; a number of values separated by newline can be specified @@ -240,6 +244,10 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Specific uncompressed frame descriptors + bFrameIndex - unique id for this framedescriptor; + only defined after parent format is + linked into the streaming header; + read-only dwFrameInterval - indicates how frame interval can be programmed; a number of values separated by newline can be specified diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 5cee8aca3734..b8763343dcae 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -868,6 +868,8 @@ static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item return container_of(item, struct uvcg_streaming_header, item); } +static void uvcg_format_set_indices(struct config_group *fmt); + static int uvcg_streaming_header_allow_link(struct config_item *src, struct config_item *target) { @@ -915,6 +917,8 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, if (!target_fmt) goto out; + uvcg_format_set_indices(to_config_group(target)); + format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL); if (!format_ptr) { ret = -ENOMEM; @@ -1146,6 +1150,41 @@ end: \ \ UVC_ATTR(uvcg_frame_, cname, aname); +static ssize_t uvcg_frame_b_frame_index_show(struct config_item *item, + char *page) +{ + struct uvcg_frame *f = to_uvcg_frame(item); + struct uvcg_format *fmt; + struct f_uvc_opts *opts; + struct config_item *opts_item; + struct config_item *fmt_item; + struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex; + int result; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + fmt_item = f->item.ci_parent; + fmt = to_uvcg_format(fmt_item); + + if (!fmt->linked) { + result = -EBUSY; + goto out; + } + + opts_item = fmt_item->ci_parent->ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + + mutex_lock(&opts->lock); + result = sprintf(page, "%d\n", f->frame.b_frame_index); + mutex_unlock(&opts->lock); + +out: + mutex_unlock(su_mutex); + return result; +} + +UVC_ATTR_RO(uvcg_frame_, b_frame_index, bFrameIndex); + #define noop_conversion(x) (x) UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, noop_conversion, @@ -1294,6 +1333,7 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item, UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval); static struct configfs_attribute *uvcg_frame_attrs[] = { + &uvcg_frame_attr_b_frame_index, &uvcg_frame_attr_bm_capabilities, &uvcg_frame_attr_w_width, &uvcg_frame_attr_w_height, @@ -1373,6 +1413,22 @@ static void uvcg_frame_drop(struct config_group *group, struct config_item *item config_item_put(item); } +static void uvcg_format_set_indices(struct config_group *fmt) +{ + struct config_item *ci; + unsigned int i = 1; + + list_for_each_entry(ci, &fmt->cg_children, ci_entry) { + struct uvcg_frame *frm; + + if (ci->ci_type != &uvcg_frame_type) + continue; + + frm = to_uvcg_frame(ci); + frm->frame.b_frame_index = i++; + } +} + /* ----------------------------------------------------------------------------- * streaming/uncompressed/ */ From patchwork Wed Aug 1 21:55:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 10553101 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9FC1C1708 for ; Wed, 1 Aug 2018 21:54:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8ED0328825 for ; Wed, 1 Aug 2018 21:54:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8362029492; Wed, 1 Aug 2018 21:54:41 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 71DB928825 for ; Wed, 1 Aug 2018 21:54:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732331AbeHAXma (ORCPT ); Wed, 1 Aug 2018 19:42:30 -0400 Received: from perceval.ideasonboard.com ([213.167.242.64]:57934 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726174AbeHAXma (ORCPT ); Wed, 1 Aug 2018 19:42:30 -0400 Received: from avalon.bb.dnainternet.fi (dfj612ybrt5fhg77mgycy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:2e86:4862:ef6a:2804]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 171612D14; Wed, 1 Aug 2018 23:54:32 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1533160472; bh=TkbZG6suQ+B1Sk3O4dDqq8G0q4m+erpiVLk7D+HliDs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=li2iSctARvJze1o9V4WZpbuMNeOfhYsBlqLU4fXuEOzy3MgTAMH7jF7XuBjGkGJOB Ytcg2cwUDNco24AY9M6jbppAQ8rl+bIxpQMl65e5J9NMII0hJpdjl4wJ4XCYMws3l6 zZEIBx4jGqolnC95uxttGcteVL0qrTCqkpSJhjuU= From: Laurent Pinchart To: linux-usb@vger.kernel.org Cc: Felipe Balbi , Joel Pepper , Kieran Bingham , Andrzej Pietrasiewicz Subject: [PATCH v2 8/8] usb: gadget: uvc: configfs: Prevent format changes after linking header Date: Thu, 2 Aug 2018 00:55:05 +0300 Message-Id: <20180801215505.7658-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> References: <20180801215505.7658-1-laurent.pinchart@ideasonboard.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Joel Pepper While checks are in place to avoid attributes and children of a format being manipulated after the format is linked into the streaming header, the linked flag was never actually set, invalidating the protections. Signed-off-by: Joel Pepper Reviewed-by: Kieran Bingham --- drivers/usb/gadget/function/uvc_configfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index b8763343dcae..799dc32c5bc7 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -928,6 +928,7 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, format_ptr->fmt = target_fmt; list_add_tail(&format_ptr->entry, &src_hdr->formats); ++src_hdr->num_fmt; + ++target_fmt->linked; out: mutex_unlock(&opts->lock); @@ -965,6 +966,8 @@ static void uvcg_streaming_header_drop_link(struct config_item *src, break; } + --target_fmt->linked; + out: mutex_unlock(&opts->lock); mutex_unlock(su_mutex);