Re: [PATCH v2 4/8] usb: gadget: uvc: configfs: Allocate groups dynamically

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Laurent,

On 01/08/18 22:55, Laurent Pinchart wrote:
> 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 <laurent.pinchart@xxxxxxxxxxxxxxxx>
> ---
> Changes since v1:
> 
> - Free groups by implementing .release() handler and removing children
>   explicitly.

Great - that resolves my concerns from the previous iteration.

Reviewed-by: Kieran Bingham <kieran.bingham@xxxxxxxxxxxxxxxx>


> ---
>  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/<NAME>
>   * 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;
>  }
> 

-- 
Regards
--
Kieran



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux