Commit 0df28607 authored by Daniel Scally's avatar Daniel Scally Committed by Greg Kroah-Hartman
Browse files

usb: gadget: uvc: Generalise helper functions for reuse



The __uvcg_*frm_intrv() helper functions can be helpful when adding
support for similar attributes. Generalise the functions and
move them higher in the file for better coverage.

Signed-off-by: default avatarDaniel Scally <dan.scally@ideasonboard.com>
Link: https://lore.kernel.org/r/20230206161802.892954-3-dan.scally@ideasonboard.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b3c839bd
Loading
Loading
Loading
Loading
+67 −53
Original line number Diff line number Diff line
@@ -47,6 +47,71 @@ static int uvcg_config_compare_u32(const void *l, const void *r)
	return li < ri ? -1 : li == ri ? 0 : 1;
}

static inline int __uvcg_count_item_entries(char *buf, void *priv, unsigned int size)
{
	++*((int *)priv);
	return 0;
}

static inline int __uvcg_fill_item_entries(char *buf, void *priv, unsigned int size)
{
	unsigned int num;
	u8 **values;
	int ret;

	ret = kstrtouint(buf, 0, &num);
	if (ret)
		return ret;

	if (num != (num & GENMASK((size * 8) - 1, 0)))
		return -ERANGE;

	values = priv;
	memcpy(*values, &num, size);
	*values += size;

	return 0;
}

static int __uvcg_iter_item_entries(const char *page, size_t len,
				    int (*fun)(char *, void *, unsigned int),
				    void *priv, unsigned int size)
{
	/* sign, base 2 representation, newline, terminator */
	unsigned int bufsize = 1 + size * 8 + 1 + 1;
	const char *pg = page;
	int i, ret = 0;
	char *buf;

	if (!fun)
		return -EINVAL;

	buf = kzalloc(bufsize, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	while (pg - page < len) {
		i = 0;
		while (i < sizeof(buf) && (pg - page < len) &&
		       *pg != '\0' && *pg != '\n')
			buf[i++] = *pg++;
		if (i == sizeof(buf)) {
			ret = -EINVAL;
			goto out_free_buf;
		}
		while ((pg - page < len) && (*pg == '\0' || *pg == '\n'))
			++pg;
		buf[i] = '\0';
		ret = fun(buf, priv, size);
		if (ret)
			goto out_free_buf;
	}

out_free_buf:
	kfree(buf);
	return ret;
}

struct uvcg_config_group_type {
	struct config_item_type type;
	const char *name;
@@ -1336,57 +1401,6 @@ static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item,
	return result;
}

static inline int __uvcg_count_frm_intrv(char *buf, void *priv)
{
	++*((int *)priv);
	return 0;
}

static inline int __uvcg_fill_frm_intrv(char *buf, void *priv)
{
	u32 num, **interv;
	int ret;

	ret = kstrtou32(buf, 0, &num);
	if (ret)
		return ret;

	interv = priv;
	**interv = num;
	++*interv;

	return 0;
}

static int __uvcg_iter_frm_intrv(const char *page, size_t len,
				 int (*fun)(char *, void *), void *priv)
{
	/* sign, base 2 representation, newline, terminator */
	char buf[1 + sizeof(u32) * 8 + 1 + 1];
	const char *pg = page;
	int i, ret;

	if (!fun)
		return -EINVAL;

	while (pg - page < len) {
		i = 0;
		while (i < sizeof(buf) && (pg - page < len) &&
				*pg != '\0' && *pg != '\n')
			buf[i++] = *pg++;
		if (i == sizeof(buf))
			return -EINVAL;
		while ((pg - page < len) && (*pg == '\0' || *pg == '\n'))
			++pg;
		buf[i] = '\0';
		ret = fun(buf, priv);
		if (ret)
			return ret;
	}

	return 0;
}

static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item,
						  const char *page, size_t len)
{
@@ -1410,7 +1424,7 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item,
		goto end;
	}

	ret = __uvcg_iter_frm_intrv(page, len, __uvcg_count_frm_intrv, &n);
	ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n, sizeof(u32));
	if (ret)
		goto end;

@@ -1420,7 +1434,7 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item,
		goto end;
	}

	ret = __uvcg_iter_frm_intrv(page, len, __uvcg_fill_frm_intrv, &tmp);
	ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp, sizeof(u32));
	if (ret) {
		kfree(frm_intrv);
		goto end;