mailarchive of the ptxdist mailing list
 help / color / mirror / Atom feed
* [ptxdist] [PATCH] libusbgx: new package
@ 2021-04-28 23:24 Michael Grzeschik
  2021-04-29 11:29 ` Roland Hieber
  2021-05-07  6:07 ` [ptxdist] [APPLIED] " Michael Olbrich
  0 siblings, 2 replies; 3+ messages in thread
From: Michael Grzeschik @ 2021-04-28 23:24 UTC (permalink / raw)
  To: ptxdist

This patch adds libusbgx support to ptxdist. It includes patches to work
with uvc gadgets.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
---

This patches are already mainline or already in a merge request of the project.

https://github.com/libusbgx/libusbgx/pull/54
https://github.com/libusbgx/libusbgx/pull/55

 ...1-Fix-39-Compilation-fails-on-gcc-v8.patch |  20 +
 ...ld-with-glibc-2.28-since-sys-sysmacr.patch |  90 +++
 ...vid-pid-remove-add-dynamic-vid-pid-s.patch |  67 ++
 .../0004-libusbgx-Add-UVC-support.patch       | 737 ++++++++++++++++++
 patches/libusbgx-0.2.0/autogen.sh             |  16 +
 patches/libusbgx-0.2.0/series                 |   7 +
 rules/libusbgx.in                             |   8 +
 rules/libusbgx.make                           |  66 ++
 8 files changed, 1011 insertions(+)
 create mode 100644 patches/libusbgx-0.2.0/0001-Fix-39-Compilation-fails-on-gcc-v8.patch
 create mode 100644 patches/libusbgx-0.2.0/0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch
 create mode 100644 patches/libusbgx-0.2.0/0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch
 create mode 100644 patches/libusbgx-0.2.0/0004-libusbgx-Add-UVC-support.patch
 create mode 100755 patches/libusbgx-0.2.0/autogen.sh
 create mode 100644 patches/libusbgx-0.2.0/series
 create mode 100644 rules/libusbgx.in
 create mode 100644 rules/libusbgx.make

diff --git a/patches/libusbgx-0.2.0/0001-Fix-39-Compilation-fails-on-gcc-v8.patch b/patches/libusbgx-0.2.0/0001-Fix-39-Compilation-fails-on-gcc-v8.patch
new file mode 100644
index 000000000..4e7ff0ca4
--- /dev/null
+++ b/patches/libusbgx-0.2.0/0001-Fix-39-Compilation-fails-on-gcc-v8.patch
@@ -0,0 +1,20 @@
+From: Federico Fuga <fuga@studiofuga.com>
+Date: Thu, 23 May 2019 13:40:39 +0200
+Subject: [PATCH] Fix #39 Compilation fails on gcc v8
+
+---
+ src/usbg_common.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/usbg_common.c b/src/usbg_common.c
+index f8822fcf727f..f3aa8b053c44 100644
+--- a/src/usbg_common.c
++++ b/src/usbg_common.c
+@@ -20,6 +20,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
++#include <sys/sysmacros.h>
+ 
+ int usbg_read_buf_limited(const char *path, const char *name,
+ 			  const char *file, char *buf, int len)
diff --git a/patches/libusbgx-0.2.0/0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch b/patches/libusbgx-0.2.0/0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch
new file mode 100644
index 000000000..9670d469a
--- /dev/null
+++ b/patches/libusbgx-0.2.0/0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch
@@ -0,0 +1,90 @@
+From: Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
+Date: Mon, 10 Sep 2018 15:52:09 +0200
+Subject: [PATCH] libusbgx: fix build with glibc-2.28 since <sys/sysmacros.h>
+ is no more included by <sys/types.h>
+
+Signed-off-by: Sid Spry R030t1@gmail.com
+Signed-off-by: Gwenhael Goavec-Merou gwenhael.goavec-merou@trabucayre.com
+[Copy sign-offs from pull requst to commit msg]
+Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
+---
+ examples/gadget-acm-ecm.c              | 1 +
+ examples/gadget-import.c               | 1 +
+ examples/gadget-ms.c                   | 1 +
+ examples/show-gadgets.c                | 1 +
+ examples/show-udcs.c                   | 1 +
+ include/usbg/usbg_internal_libconfig.h | 1 +
+ 6 files changed, 6 insertions(+)
+
+diff --git a/examples/gadget-acm-ecm.c b/examples/gadget-acm-ecm.c
+index 1c5e2ca5161c..29360da15811 100644
+--- a/examples/gadget-acm-ecm.c
++++ b/examples/gadget-acm-ecm.c
+@@ -20,6 +20,7 @@
+ 
+ #include <errno.h>
+ #include <stdio.h>
++#include <sys/sysmacros.h>
+ #include <linux/usb/ch9.h>
+ #include <usbg/usbg.h>
+ 
+diff --git a/examples/gadget-import.c b/examples/gadget-import.c
+index e684fdb861e8..63df4499926b 100644
+--- a/examples/gadget-import.c
++++ b/examples/gadget-import.c
+@@ -25,6 +25,7 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <stdio.h>
++#include <sys/sysmacros.h>
+ #include <usbg/usbg.h>
+ 
+ int main(int argc, char **argv)
+diff --git a/examples/gadget-ms.c b/examples/gadget-ms.c
+index 478c37097397..a5c668187a96 100644
+--- a/examples/gadget-ms.c
++++ b/examples/gadget-ms.c
+@@ -23,6 +23,7 @@
+ 
+ #include <errno.h>
+ #include <stdio.h>
++#include <sys/sysmacros.h>
+ #include <linux/usb/ch9.h>
+ #include <usbg/usbg.h>
+ #include <usbg/function/ms.h>
+diff --git a/examples/show-gadgets.c b/examples/show-gadgets.c
+index 707d4488d16b..a2a21c883b27 100644
+--- a/examples/show-gadgets.c
++++ b/examples/show-gadgets.c
+@@ -21,6 +21,7 @@
+ #include <errno.h>
+ #include <stdio.h>
+ #include <string.h>
++#include <sys/sysmacros.h>
+ #include <netinet/ether.h>
+ #include <usbg/usbg.h>
+ #include <usbg/function/ms.h>
+diff --git a/examples/show-udcs.c b/examples/show-udcs.c
+index 66e950f7bf85..2f5cc458ebb1 100644
+--- a/examples/show-udcs.c
++++ b/examples/show-udcs.c
+@@ -23,6 +23,7 @@
+ 
+ #include <errno.h>
+ #include <stdio.h>
++#include <sys/sysmacros.h>
+ #include <usbg/usbg.h>
+ 
+ int main(void)
+diff --git a/include/usbg/usbg_internal_libconfig.h b/include/usbg/usbg_internal_libconfig.h
+index ac51758b3d6c..3fa55c0b544b 100644
+--- a/include/usbg/usbg_internal_libconfig.h
++++ b/include/usbg/usbg_internal_libconfig.h
+@@ -12,6 +12,7 @@
+ #ifndef USBG_INTERNAL_LIBCONFIG_H
+ #define USBG_INTERNAL_LIBCONFIG_H
+ 
++#include <sys/sysmacros.h>
+ #include <libconfig.h>
+ #ifdef __cplusplus
+ extern "C" {
diff --git a/patches/libusbgx-0.2.0/0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch b/patches/libusbgx-0.2.0/0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch
new file mode 100644
index 000000000..63ddf347f
--- /dev/null
+++ b/patches/libusbgx-0.2.0/0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch
@@ -0,0 +1,67 @@
+From: Michael Grzeschik <m.grzeschik@pengutronix.de>
+Date: Wed, 28 Apr 2021 21:43:07 +0200
+Subject: [PATCH] examples: gadget-vid-pid-remove: add dynamic vid pid support
+
+Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
+---
+ examples/gadget-vid-pid-remove.c | 25 ++++++++++++++++++++-----
+ 1 file changed, 20 insertions(+), 5 deletions(-)
+
+diff --git a/examples/gadget-vid-pid-remove.c b/examples/gadget-vid-pid-remove.c
+index f6b950b38da3..f5eb9664b721 100644
+--- a/examples/gadget-vid-pid-remove.c
++++ b/examples/gadget-vid-pid-remove.c
+@@ -23,11 +23,10 @@
+ 
+ #include <errno.h>
+ #include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
+ #include <usbg/usbg.h>
+ 
+-#define VENDOR		0x1d6b
+-#define PRODUCT		0x0104
+-
+ int remove_gadget(usbg_gadget *g)
+ {
+ 	int usbg_ret;
+@@ -60,13 +59,29 @@ out:
+ 	return usbg_ret;
+ }
+ 
+-int main(void)
++int main(int argc, char **argv)
+ {
+ 	int usbg_ret;
+ 	int ret = -EINVAL;
+ 	usbg_state *s;
+ 	usbg_gadget *g;
+ 	struct usbg_gadget_attrs g_attrs;
++	char *cp;
++	int vendor = 0x1d6b, product = 0x0104;
++
++	if (argc >= 2) {
++		cp = strchr(argv[1], ':');
++		if (!cp) {
++			ret = -EINVAL;
++			fprintf(stderr, "Usage: gadget-vid-pid-remove vid:pid\n");
++			goto out1;
++		}
++		*cp++ = 0;
++		if (&argv[1])
++			vendor = strtoul(argv[1], NULL, 16);
++		if (*cp)
++			product = strtoul(cp, NULL, 16);
++	}
+ 
+ 	usbg_ret = usbg_init("/sys/kernel/config", &s);
+ 	if (usbg_ret != USBG_SUCCESS) {
+@@ -88,7 +103,7 @@ int main(void)
+ 		}
+ 
+ 		/* Compare attrs with given values and remove if suitable */
+-		if (g_attrs.idVendor == VENDOR && g_attrs.idProduct == PRODUCT) {
++		if (g_attrs.idVendor == vendor && g_attrs.idProduct == product) {
+ 			usbg_gadget *g_next = usbg_get_next_gadget(g);
+ 
+ 			usbg_ret = remove_gadget(g);
diff --git a/patches/libusbgx-0.2.0/0004-libusbgx-Add-UVC-support.patch b/patches/libusbgx-0.2.0/0004-libusbgx-Add-UVC-support.patch
new file mode 100644
index 000000000..0217bb02d
--- /dev/null
+++ b/patches/libusbgx-0.2.0/0004-libusbgx-Add-UVC-support.patch
@@ -0,0 +1,737 @@
+From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
+Date: Wed, 8 Jan 2020 14:43:45 +0100
+Subject: [PATCH] libusbgx: Add UVC support
+
+Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
+Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
+
+Notes:
+v2 -> v3: - simplified exit paths of functions with reutrns instead of gotos
+          - added cleanup code for remove
+	  - added gadget-uvc example file
+	  - simplified class link creation
+	  - added support for more than one format
+---
+ Makefile.am                 |   2 +-
+ examples/Makefile.am        |   3 +-
+ examples/gadget-uvc.c       | 156 ++++++++++++++++++
+ include/usbg/function/uvc.h |  90 +++++++++++
+ include/usbg/usbg.h         |   1 +
+ src/Makefile.am             |   2 +-
+ src/function/uvc.c          | 378 ++++++++++++++++++++++++++++++++++++++++++++
+ src/usbg.c                  |   2 +
+ 8 files changed, 631 insertions(+), 3 deletions(-)
+ create mode 100644 examples/gadget-uvc.c
+ create mode 100644 include/usbg/function/uvc.h
+ create mode 100644 src/function/uvc.c
+
+diff --git a/Makefile.am b/Makefile.am
+index a3cc337c18da..b3cd097d9d32 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -14,6 +14,6 @@ EXTRA_DIST = doxygen.cfg
+ library_includedir=$(includedir)/usbg
+ library_include_HEADERS = include/usbg/usbg.h include/usbg/usbg_version.h
+ function_includedir=$(includedir)/usbg/function
+-function_include_HEADERS = include/usbg/function/ffs.h include/usbg/function/loopback.h include/usbg/function/midi.h include/usbg/function/ms.h include/usbg/function/net.h include/usbg/function/phonet.h include/usbg/function/serial.h include/usbg/function/hid.h include/usbg/function/uac2.h
++function_include_HEADERS = include/usbg/function/ffs.h include/usbg/function/loopback.h include/usbg/function/midi.h include/usbg/function/ms.h include/usbg/function/net.h include/usbg/function/phonet.h include/usbg/function/serial.h include/usbg/function/hid.h include/usbg/function/uac2.h include/usbg/function/uvc.h
+ pkgconfigdir = $(libdir)/pkgconfig
+ pkgconfig_DATA = libusbgx.pc
+diff --git a/examples/Makefile.am b/examples/Makefile.am
+index 993432156d6c..3217eb3bfd6f 100644
+--- a/examples/Makefile.am
++++ b/examples/Makefile.am
+@@ -1,5 +1,6 @@
+-bin_PROGRAMS = show-gadgets gadget-acm-ecm gadget-vid-pid-remove gadget-ffs gadget-export gadget-import show-udcs gadget-ms gadget-midi gadget-hid gadget-rndis-os-desc gadget-uac2
++bin_PROGRAMS = show-gadgets gadget-acm-ecm gadget-vid-pid-remove gadget-uvc gadget-ffs gadget-export gadget-import show-udcs gadget-ms gadget-midi gadget-hid gadget-rndis-os-desc gadget-uac2
+ gadget_acm_ecm_SOURCES = gadget-acm-ecm.c
++gadget_uvc_SOURCES = gadget-uvc.c
+ show_gadgets_SOURCES = show-gadgets.c
+ gadget_vid_pid_remove_SOURCES = gadget-vid-pid-remove.c
+ gadget_ffs_SOURCES = gadget-ffs.c
+diff --git a/examples/gadget-uvc.c b/examples/gadget-uvc.c
+new file mode 100644
+index 000000000000..d3efe2deaebe
+--- /dev/null
++++ b/examples/gadget-uvc.c
+@@ -0,0 +1,156 @@
++/*
++ * Copyright (C) 2021 Pengutronix
++ *
++ * Michael Grzeschik <mgr@pengutronix.de>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <errno.h>
++#include <stdio.h>
++#include <sys/sysmacros.h>
++#include <linux/usb/ch9.h>
++#include <usbg/usbg.h>
++#include <usbg/function/uvc.h>
++
++/**
++ * @file gadget-uvc.c
++ * @example gadget-uvc.c
++ * This is an example of how to create an UVC gadget device.
++ */
++
++#define VENDOR		0x1d6b
++#define PRODUCT		0x0104
++
++int main(void)
++{
++	usbg_state *s;
++	usbg_gadget *g;
++	usbg_config *c;
++	usbg_function *f_uvc;
++	int ret = -EINVAL;
++	int usbg_ret;
++
++	struct usbg_gadget_attrs g_attrs = {
++		.bcdUSB = 0x0200,
++		.bDeviceClass =	USB_CLASS_PER_INTERFACE,
++		.bDeviceSubClass = 0x00,
++		.bDeviceProtocol = 0x00,
++		.bMaxPacketSize0 = 64, /* Max allowed ep0 packet size */
++		.idVendor = VENDOR,
++		.idProduct = PRODUCT,
++		.bcdDevice = 0x0001, /* Verson of device */
++	};
++
++	struct usbg_gadget_strs g_strs = {
++		.serial = "0123456789", /* Serial number */
++		.manufacturer = "Foo Inc.", /* Manufacturer */
++		.product = "Bar Gadget" /* Product string */
++	};
++
++	struct usbg_config_strs c_strs = {
++		.configuration = "UVC"
++	};
++
++	struct usbg_f_uvc_format_attrs uvc_format_attrs_array[] = {
++		{
++			.format = UVC_FORMAT_MJPEG,
++			.dwFrameInterval = "333333",
++			.height = 1080,
++			.width = 1920,
++		}, {
++			.format = UVC_FORMAT_MJPEG,
++			.dwFrameInterval = "333333",
++			.height = 3940,
++			.width = 2160,
++		}, {
++			.format = UVC_FORMAT_UNCOMPRESSED,
++			.dwFrameInterval = "333333",
++			.height = 1080,
++			.width = 1920,
++		}, {
++			.format = UVC_FORMAT_UNCOMPRESSED,
++			.dwFrameInterval = "333333",
++			.height = 3940,
++			.width = 2160,
++		}
++	};
++
++	struct usbg_f_uvc_format_attrs *uvc_format_attrs[] = {
++		&uvc_format_attrs_array[3],
++		&uvc_format_attrs_array[2],
++		&uvc_format_attrs_array[1],
++		&uvc_format_attrs_array[0],
++		NULL,
++	};
++
++	struct usbg_f_uvc_attrs uvc_attrs = {
++		.formats = uvc_format_attrs,
++	};
++
++	usbg_ret = usbg_init("/sys/kernel/config", &s);
++	if (usbg_ret != USBG_SUCCESS) {
++		fprintf(stderr, "Error on USB gadget init\n");
++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
++				usbg_strerror(usbg_ret));
++		goto out1;
++	}
++
++	usbg_ret = usbg_create_gadget(s, "g1", &g_attrs, &g_strs, &g);
++	if (usbg_ret != USBG_SUCCESS) {
++		fprintf(stderr, "Error on create gadget\n");
++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
++				usbg_strerror(usbg_ret));
++		goto out2;
++	}
++
++        usbg_ret = usbg_create_function(g, USBG_F_UVC, "uvc", &uvc_attrs, &f_uvc);
++        if(usbg_ret != USBG_SUCCESS)
++        {
++		fprintf(stderr, "Error creating uvc function\n");
++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
++				usbg_strerror(usbg_ret));
++		goto out2;
++	}
++
++	/* NULL can be passed to use kernel defaults */
++	usbg_ret = usbg_create_config(g, 1, "The only one", NULL, &c_strs, &c);
++	if (usbg_ret != USBG_SUCCESS) {
++		fprintf(stderr, "Error creating config\n");
++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
++				usbg_strerror(usbg_ret));
++		goto out2;
++	}
++
++        usbg_ret = usbg_add_config_function(c, "uvc.cam", f_uvc);
++	if (usbg_ret != USBG_SUCCESS) {
++		fprintf(stderr, "Error adding acm.GS0\n");
++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
++				usbg_strerror(usbg_ret));
++		goto out2;
++	}
++
++	usbg_ret = usbg_enable_gadget(g, DEFAULT_UDC);
++	if (usbg_ret != USBG_SUCCESS) {
++		fprintf(stderr, "Error enabling gadget\n");
++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
++				usbg_strerror(usbg_ret));
++		goto out2;
++	}
++
++	ret = 0;
++
++out2:
++	usbg_cleanup(s);
++
++out1:
++	return ret;
++}
+diff --git a/include/usbg/function/uvc.h b/include/usbg/function/uvc.h
+new file mode 100644
+index 000000000000..4c641dacdfcb
+--- /dev/null
++++ b/include/usbg/function/uvc.h
+@@ -0,0 +1,90 @@
++/*
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ */
++
++#ifndef USBG_FUNCTION_UVC__
++#define USBG_FUNCTION_UVC__
++
++#include <usbg/usbg.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++
++#define USBG_UVC_MAX_PATH_LENGTH 1024
++
++struct usbg_f_uvc;
++typedef struct usbg_f_uvc usbg_f_uvc;
++
++enum uvc_format
++{
++	UVC_FORMAT_MJPEG,
++	UVC_FORMAT_UNCOMPRESSED
++};
++
++struct usbg_f_uvc_format_attrs
++{
++	enum uvc_format format;
++	const char *dwFrameInterval;
++	int height;
++	int width;
++};
++
++struct usbg_f_uvc_attrs
++{
++	struct usbg_f_uvc_format_attrs **formats;
++};
++
++/**
++ * @brief Cast from generic function to uvc function
++ * @param[in] f function to be converted to uvc funciton.
++ *         Should be one of types:
++ *         ecm, subset, ncm, eem, rndis
++ * @return Converted uvc function or NULL if function hasn't suitable type
++ */
++usbg_f_uvc *usbg_to_uvc_function(usbg_function *f);
++
++/**
++ * @brief Cast form uvc function to generic one
++ * @param[in] uvc function to be converted to generic one
++ * @return Generic usbg function
++ */
++usbg_function *usbg_from_uvc_function(usbg_f_uvc *ff);
++
++/**
++ * @brief Cleanup attributes structure after usage
++ * @param[in] attrs to be cleaned up
++ */
++static inline void usbg_f_uvc_cleanup_attrs(struct usbg_f_uvc_attrs *attrs)
++{
++	struct usbg_f_uvc_format_attrs **format_attrs;
++	int i;
++
++	if (attrs) {
++		for(format_attrs = attrs->formats, i = 0; format_attrs[i]; ++i) {
++			if (format_attrs[i]) {
++				free((char *)format_attrs[i]->dwFrameInterval);
++				format_attrs[i]->dwFrameInterval = NULL;
++			}
++		}
++	}
++}
++
++int usbg_f_uvc_get_attrs(usbg_f_uvc *uvcf, struct usbg_f_uvc_attrs *attrs);
++int usbg_f_uvc_set_attrs(usbg_f_uvc *uvcf, const struct usbg_f_uvc_attrs *attrs);
++
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* USBG_FUNCTION_UVC__ */
+diff --git a/include/usbg/usbg.h b/include/usbg/usbg.h
+index 55c52a1c3768..de72793ddcf0 100644
+--- a/include/usbg/usbg.h
++++ b/include/usbg/usbg.h
+@@ -219,6 +219,7 @@ typedef enum
+ 	USBG_F_LOOPBACK,
+ 	USBG_F_HID,
+ 	USBG_F_UAC2,
++	USBG_F_UVC,
+ 	USBG_FUNCTION_TYPE_MAX,
+ } usbg_function_type;
+ 
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 6b2726ec5219..c51878fac2ff 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -1,6 +1,6 @@
+ AUTOMAKE_OPTIONS = std-options subdir-objects
+ lib_LTLIBRARIES = libusbgx.la
+-libusbgx_la_SOURCES = usbg.c usbg_error.c usbg_common.c function/ether.c function/ffs.c function/midi.c function/ms.c function/phonet.c function/serial.c function/loopback.c function/hid.c function/uac2.c
++libusbgx_la_SOURCES = usbg.c usbg_error.c usbg_common.c function/ether.c function/ffs.c function/midi.c function/ms.c function/phonet.c function/serial.c function/loopback.c function/hid.c function/uac2.c function/uvc.c
+ if TEST_GADGET_SCHEMES
+ libusbgx_la_SOURCES += usbg_schemes_libconfig.c usbg_common_libconfig.c
+ else
+diff --git a/src/function/uvc.c b/src/function/uvc.c
+new file mode 100644
+index 000000000000..92d738c5763c
+--- /dev/null
++++ b/src/function/uvc.c
+@@ -0,0 +1,378 @@
++/*
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ */
++
++#include "usbg/usbg.h"
++#include "usbg/usbg_internal.h"
++#include "usbg/function/uvc.h"
++
++#include <errno.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <malloc.h>
++#include <ftw.h>
++#ifdef HAS_GADGET_SCHEMES
++#include <libconfig.h>
++#endif
++
++#define UVC_PATH_CONTROL		"control"
++#define UVC_PATH_HEADER			"header/h"
++#define UVC_PATH_CLASS_FS		"class/fs/h"
++#define UVC_PATH_CLASS_HS		"class/hs/h"
++#define UVC_PATH_CLASS_SS		"class/ss/h"
++#define UVC_PATH_STREAMING		"streaming"
++#define UVC_PATH_STREAMING_UNCOMPRESSED	"uncompressed/u"
++#define UVC_PATH_STREAMING_MJPEG	"mjpeg/m"
++
++struct usbg_f_uvc
++{
++	struct usbg_function func;
++};
++
++GENERIC_ALLOC_INST(uvc, struct usbg_f_uvc, func);
++
++GENERIC_FREE_INST(uvc, struct usbg_f_uvc, func);
++
++static int uvc_set_attrs(struct usbg_function *f, void *f_attrs)
++{
++	return usbg_f_uvc_set_attrs(usbg_to_uvc_function(f), f_attrs);
++}
++
++static int uvc_get_attrs(struct usbg_function *f, void *f_attrs)
++{
++	return usbg_f_uvc_get_attrs(usbg_to_uvc_function(f), f_attrs);
++}
++
++static void uvc_cleanup_attrs(struct usbg_function *f, void *f_attrs)
++{
++	return usbg_f_uvc_cleanup_attrs(f_attrs);
++}
++
++static int uvc_libconfig_import(struct usbg_function *f, config_setting_t *root)
++{
++	return USBG_SUCCESS;
++}
++
++static int uvc_libconfig_export(struct usbg_function *f, config_setting_t *root)
++{
++	return USBG_SUCCESS;
++}
++
++static int uvc_create_dir(const char *path)
++{
++	char tmp[USBG_MAX_PATH_LENGTH];
++	char *p = NULL;
++	size_t len;
++	int nmb, ret = USBG_SUCCESS;
++
++	nmb = snprintf(tmp, sizeof(tmp), "%s", path);
++	if(nmb >= sizeof(tmp))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	len = strlen(tmp);
++	if(tmp[len - 1] == '/')
++		tmp[len - 1] = 0;
++
++	for (p = tmp + 1; *p; p++) {
++		if(*p == '/') {
++			*p = 0;
++			if((mkdir(tmp, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && errno != EEXIST) {
++				ret = usbg_translate_error(errno);
++				break;
++			}
++			*p = '/';
++		}
++	}
++	if(ret != USBG_SUCCESS)
++		return ret;
++
++	if((mkdir(tmp, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && errno != EEXIST)
++		return usbg_translate_error(errno);
++}
++
++static int uvc_link(char *path, char *to, char *from)
++{
++	char oldname[USBG_MAX_PATH_LENGTH];
++	char newname[USBG_MAX_PATH_LENGTH];
++	int nmb;
++
++	nmb = snprintf(oldname, sizeof(oldname), "%s/%s", path, to);
++	if (nmb >= sizeof(oldname))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	nmb = snprintf(newname, sizeof(newname), "%s/%s", path, from);
++	if (nmb >= sizeof(newname))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	if(symlink(oldname, newname))
++		return usbg_translate_error(errno);
++}
++
++static int uvc_set_class(char *func_path, char *cs)
++{
++	int ret, nmb;
++	char path[USBG_MAX_PATH_LENGTH];
++	char header_path[USBG_MAX_PATH_LENGTH];
++
++	nmb = snprintf(path, sizeof(path), "%s/%s", func_path, cs);
++	if (nmb >= sizeof(path))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	nmb = snprintf(header_path, sizeof(header_path), "%s/" UVC_PATH_HEADER, path);
++	if (nmb >= sizeof(header_path))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	ret = uvc_create_dir(header_path);
++	if (ret != USBG_SUCCESS)
++		return ret;
++
++	if (!strncmp(cs, UVC_PATH_STREAMING, strlen(UVC_PATH_STREAMING))) {
++		char check_path[USBG_MAX_PATH_LENGTH];
++		struct stat buffer;
++
++		nmb = snprintf(check_path, sizeof(check_path), "%s/" UVC_PATH_STREAMING_UNCOMPRESSED, path);
++		if (nmb >= sizeof(check_path))
++			return USBG_ERROR_PATH_TOO_LONG;
++
++		ret = stat(check_path, &buffer);
++		if (!ret) {
++			ret = uvc_link(path, UVC_PATH_STREAMING_UNCOMPRESSED, "header/h/u");
++			if (ret != USBG_SUCCESS)
++				return ret;
++		}
++
++		nmb = snprintf(check_path, sizeof(check_path), "%s/" UVC_PATH_STREAMING_MJPEG, path);
++		if (nmb >= sizeof(check_path))
++			return USBG_ERROR_PATH_TOO_LONG;
++
++		ret = stat(check_path, &buffer);
++		if (!ret) {
++			ret = uvc_link(path, UVC_PATH_STREAMING_MJPEG, "header/h/m");
++			if (ret != USBG_SUCCESS)
++				return ret;
++		}
++
++		ret = uvc_link(path, UVC_PATH_HEADER, UVC_PATH_CLASS_HS);
++		if (ret)
++			return ret;
++	}
++
++	ret = uvc_link(path, UVC_PATH_HEADER, UVC_PATH_CLASS_FS);
++	if (ret)
++		return ret;
++
++	return uvc_link(path, UVC_PATH_HEADER, UVC_PATH_CLASS_SS);
++}
++
++static int uvc_set_frame(char *format_path, char *format, const struct usbg_f_uvc_format_attrs *attrs)
++{
++	int nmb, ret, i;
++	char frame_path[USBG_MAX_PATH_LENGTH];
++	char full_frame_path[USBG_MAX_PATH_LENGTH];
++	char frame_interval[USBG_MAX_PATH_LENGTH];
++	char frame_name[32];
++
++	nmb = snprintf(frame_name, sizeof(frame_name), "%dp", attrs->height);
++	if (nmb >= sizeof(frame_name))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	nmb = snprintf(frame_path, sizeof(frame_path), "%s/%s", format_path, format);
++	if (nmb >= sizeof(frame_path))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	nmb = snprintf(full_frame_path, sizeof(frame_path), "%s/%s", frame_path, frame_name);
++	if (nmb >= sizeof(full_frame_path))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	ret = uvc_create_dir(full_frame_path);
++	if (ret != USBG_SUCCESS)
++		return ret;
++
++	ret = usbg_write_string(frame_path, frame_name, "dwFrameInterval", attrs->dwFrameInterval);
++	if (ret != USBG_SUCCESS)
++		return ret;
++
++	ret = usbg_write_dec(frame_path, frame_name, "wHeight", attrs->height);
++	if (ret != USBG_SUCCESS)
++		return ret;
++
++	return usbg_write_dec(frame_path, frame_name, "wWidth", attrs->width);
++}
++
++static int uvc_set_streaming(char *func_path, const struct usbg_f_uvc_format_attrs *attrs)
++{
++	char streaming_path[USBG_MAX_PATH_LENGTH];
++	int ret, nmb;
++
++	nmb = snprintf(streaming_path, sizeof(streaming_path), "%s/" UVC_PATH_STREAMING, func_path);
++	if (nmb >= sizeof(streaming_path))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	if (attrs->format == UVC_FORMAT_UNCOMPRESSED)
++		ret = uvc_set_frame(streaming_path, UVC_PATH_STREAMING_UNCOMPRESSED, attrs);
++	else
++		ret = uvc_set_frame(streaming_path, UVC_PATH_STREAMING_MJPEG, attrs);
++
++	return ret;
++}
++
++static int dir_nftw_cb(const char *pathname, const struct stat *sbuf, int type, struct FTW *ftwb)
++{
++	(void) sbuf;
++	(void) type;
++	(void) ftwb;
++	int ret;
++
++	ret = remove(pathname);
++	if (ret < -1)
++		ERROR("failed to remove %s - %s", pathname, strerror(ret));
++
++	return 0;
++}
++
++int remove_dir(const char *dirpath)
++{
++	const int max_open_descs = 8;
++	int ret;
++
++	ret = nftw(dirpath, dir_nftw_cb, max_open_descs, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
++	if (ret < 0) {
++		ERROR("nftw failed");
++		return ret;
++	}
++
++	return 0;
++}
++
++static int content_nftw_cb(const char *pathname, const struct stat *sbuf, int type, struct FTW *ftwb)
++{
++	(void) sbuf;
++	(void) type;
++	(void) ftwb;
++	int ret;
++
++	if(ftwb->level == 0)
++		return 0;
++
++	ret = remove(pathname);
++	if(ret < -1)
++		ERROR("failed to remove %s - %s", pathname, strerror(ret));
++
++	return 0;
++}
++
++int remove_dir_content(const char *dirpath)
++{
++	const int max_open_descs = 8;
++	int ret;
++
++	/* traverse in reverse order (handle directory after it's content), stay within the same file system and do not follow symbolic links */
++	ret = nftw(dirpath, content_nftw_cb, max_open_descs, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
++	if (ret < 0) {
++		ERROR("nftw failed");
++		return ret;
++	}
++
++	return 0;
++}
++
++static int uvc_remove(struct usbg_function *f, int opts)
++{
++	usbg_f_uvc *uvcf = usbg_to_uvc_function(f);
++	char streaming_path[USBG_MAX_PATH_LENGTH];
++	char control_path[USBG_MAX_PATH_LENGTH];
++	char path[USBG_UVC_MAX_PATH_LENGTH];
++	int nmb, ret = USBG_SUCCESS;
++
++	nmb = snprintf(path, sizeof(path), "%s/%s", uvcf->func.path, uvcf->func.name);
++	if (nmb >= sizeof(path))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	nmb = snprintf(streaming_path, sizeof(streaming_path), "%s/streaming", path);
++	if (nmb >= sizeof(streaming_path))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	nmb = snprintf(control_path, sizeof(control_path), "%s/control", path);
++	if (nmb >= sizeof(control_path))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	if(remove_dir_content(streaming_path) < 0)
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	if(remove_dir_content(control_path) < 0)
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	if(remove_dir(streaming_path) < 0)
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	if(remove_dir(control_path) < 0)
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	return 0;
++};
++
++struct usbg_function_type usbg_f_type_uvc = {
++	.name = "uvc",
++	.alloc_inst = uvc_alloc_inst,
++	.free_inst = uvc_free_inst,
++	.set_attrs = uvc_set_attrs,
++	.get_attrs = uvc_get_attrs,
++	.cleanup_attrs = uvc_cleanup_attrs,
++	.import = uvc_libconfig_import,
++	.export = uvc_libconfig_export,
++	.remove = uvc_remove,
++};
++
++/* API implementation */
++
++usbg_f_uvc *usbg_to_uvc_function(usbg_function *f)
++{
++	return f->ops == &usbg_f_type_uvc ?
++			container_of(f, struct usbg_f_uvc, func) : NULL;
++}
++
++usbg_function *usbg_from_uvc_function(usbg_f_uvc *ff)
++{
++	return &ff->func;
++}
++
++int usbg_f_uvc_get_attrs(usbg_f_uvc *uvcf, struct usbg_f_uvc_attrs *attrs)
++{
++	return USBG_SUCCESS;
++}
++
++int usbg_f_uvc_set_attrs(usbg_f_uvc *uvcf, const struct usbg_f_uvc_attrs *attrs)
++{
++	int nmb, ret = USBG_SUCCESS;
++	char path[USBG_UVC_MAX_PATH_LENGTH];
++	struct usbg_f_uvc_format_attrs **format_attrs;
++	int i;
++
++	nmb = snprintf(path, sizeof(path), "%s/%s", uvcf->func.path, uvcf->func.name);
++	if (nmb >= sizeof(path))
++		return USBG_ERROR_PATH_TOO_LONG;
++
++	for(format_attrs = attrs->formats, i = 0; format_attrs[i]; ++i) {
++		ret = uvc_set_streaming(path, format_attrs[i]);
++		if(ret != USBG_SUCCESS)
++			ERROR("Error: %d", ret);
++	}
++
++	ret = uvc_set_class(path, "control");
++	if (ret != USBG_SUCCESS)
++		return ret;
++
++	ret = uvc_set_class(path, "streaming");
++	if (ret != USBG_SUCCESS)
++		return ret;
++
++	return ret;
++}
+diff --git a/src/usbg.c b/src/usbg.c
+index d2bf38160358..b298ddc50ecf 100644
+--- a/src/usbg.c
++++ b/src/usbg.c
+@@ -52,6 +52,7 @@ extern struct usbg_function_type usbg_f_type_phonet;
+ extern struct usbg_function_type usbg_f_type_loopback;
+ extern struct usbg_function_type usbg_f_type_hid;
+ extern struct usbg_function_type usbg_f_type_uac2;
++extern struct usbg_function_type usbg_f_type_uvc;
+ 
+ /**
+  * @var function_types
+@@ -73,6 +74,7 @@ struct usbg_function_type* function_types[] = {
+ 	[USBG_F_LOOPBACK] = &usbg_f_type_loopback,
+ 	[USBG_F_HID] = &usbg_f_type_hid,
+ 	[USBG_F_UAC2] = &usbg_f_type_uac2,
++	[USBG_F_UVC] = &usbg_f_type_uvc,
+ };
+ 
+ ARRAY_SIZE_SENTINEL(function_types, USBG_FUNCTION_TYPE_MAX);
diff --git a/patches/libusbgx-0.2.0/autogen.sh b/patches/libusbgx-0.2.0/autogen.sh
new file mode 100755
index 000000000..2459647bf
--- /dev/null
+++ b/patches/libusbgx-0.2.0/autogen.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+aclocal $ACLOCAL_FLAGS
+
+libtoolize \
+	--force \
+	--copy
+
+autoreconf \
+	--force \
+	--install \
+	--warnings=syntax \
+	--warnings=obsolete \
+	--warnings=unsupported
diff --git a/patches/libusbgx-0.2.0/series b/patches/libusbgx-0.2.0/series
new file mode 100644
index 000000000..406d15acc
--- /dev/null
+++ b/patches/libusbgx-0.2.0/series
@@ -0,0 +1,7 @@
+# generated by git-ptx-patches
+#tag:base --start-number 1
+0001-Fix-39-Compilation-fails-on-gcc-v8.patch
+0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch
+0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch
+0004-libusbgx-Add-UVC-support.patch
+# 55b4c63ca7f6b97ceb9cd9588e1eacdd  - git-ptx-patches magic
diff --git a/rules/libusbgx.in b/rules/libusbgx.in
new file mode 100644
index 000000000..98776c026
--- /dev/null
+++ b/rules/libusbgx.in
@@ -0,0 +1,8 @@
+## SECTION=communication
+
+config LIBUSBGX
+	bool
+	prompt "libusbgx"
+	help
+	  libusbgx is a C library encapsulating the kernel USB gadget-configfs
+	  userspace API functionality.
diff --git a/rules/libusbgx.make b/rules/libusbgx.make
new file mode 100644
index 000000000..6c8fce429
--- /dev/null
+++ b/rules/libusbgx.make
@@ -0,0 +1,66 @@
+# -*-makefile-*-
+#
+# Copyright (C) 2018 by Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
+#
+# See CREDITS for details about who has contributed to this project.
+#
+# For further information about the PTXdist project and license conditions
+# see the README file.
+#
+
+#
+# We provide this package
+#
+PACKAGES-$(PTXCONF_LIBUSBGX) += libusbgx
+
+#
+# Paths and names
+#
+LIBUSBGX_VERSION	:= 0.2.0
+LIBUSBGX_MD5		:= a8ea2234c6355ac8ad2ca86c453297bd
+LIBUSBGX		:= libusbgx-$(LIBUSBGX_VERSION)
+LIBUSBGX_SUFFIX		:= zip
+LIBUSBGX_URL		:= \
+	https://github.com/libusbgx/libusbgx/archive/libusbgx-v$(LIBUSBGX_VERSION).zip
+LIBUSBGX_SOURCE	:= \
+	$(SRCDIR)/$(LIBUSBGX).$(LIBUSBGX_SUFFIX)
+LIBUSBGX_DIR		:= $(BUILDDIR)/$(LIBUSBGX)
+LIBUSBGX_LICENSE	:= GPLv2
+
+# ----------------------------------------------------------------------------
+# Prepare
+# ----------------------------------------------------------------------------
+
+LIBUSBGX_CONF_ENV	:= $(CROSS_ENV)
+
+#
+# autoconf
+#
+LIBUSBGX_CONF_TOOL	:= autoconf
+LIBUSBGX_CONF_OPT	:= \
+	$(CROSS_AUTOCONF_USR) \
+	--without-libconfig \
+	--enable-examples \
+	--disable-gadget-schemes
+
+# ----------------------------------------------------------------------------
+# Target-Install
+# ----------------------------------------------------------------------------
+
+$(STATEDIR)/libusbgx.targetinstall:
+	@$(call targetinfo)
+
+	@$(call install_init, libusbgx)
+	@$(call install_fixup, libusbgx, PRIORITY, optional)
+	@$(call install_fixup, libusbgx, SECTION, base)
+	@$(call install_fixup, libusbgx, AUTHOR, "Thomas Haemmerle <thomas.haemmerle@wolfvision.net>")
+	@$(call install_fixup, libusbgx, DESCRIPTION, missing)
+
+	@$(call install_lib, libusbgx, 0, 0, 0644, libusbgx)
+	@$(call install_tree, libusbgx, 0, 0, -, /usr/bin)
+
+	@$(call install_finish, libusbgx)
+
+	@$(call touch)
+
+# vim: syntax=make
-- 
2.29.2


_______________________________________________
ptxdist mailing list
ptxdist@pengutronix.de
To unsubscribe, send a mail with subject "unsubscribe" to ptxdist-request@pengutronix.de


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [ptxdist] [PATCH] libusbgx: new package
  2021-04-28 23:24 [ptxdist] [PATCH] libusbgx: new package Michael Grzeschik
@ 2021-04-29 11:29 ` Roland Hieber
  2021-05-07  6:07 ` [ptxdist] [APPLIED] " Michael Olbrich
  1 sibling, 0 replies; 3+ messages in thread
From: Roland Hieber @ 2021-04-29 11:29 UTC (permalink / raw)
  To: ptxdist; +Cc: Michael Grzeschik

On Thu, Apr 29, 2021 at 01:24:10AM +0200, Michael Grzeschik wrote:
> This patch adds libusbgx support to ptxdist. It includes patches to work
> with uvc gadgets.
> 
> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> ---
> 
> This patches are already mainline or already in a merge request of the project.
> 
> https://github.com/libusbgx/libusbgx/pull/54
> https://github.com/libusbgx/libusbgx/pull/55

Just as a heads-up, you can uses DEP-3 [1] annotations in the patch's
log message for this, e.g.:

    Origin: upstream, https://github.com/libusbgx/libusbgx/pull/54

[1]: https://dep-team.pages.debian.net/deps/dep3/

Hmmm… that information was once mentioned in the README, but apparently
I removed it in commit 46dbbe232c74, and it's also no longer mentioned
anywhere in the docs… don't know why… do you think it make sense to
bring it back? I find that it makes package version bumps easier for big
projects with a lot of code changes between releases.

 - Roland

>  ...1-Fix-39-Compilation-fails-on-gcc-v8.patch |  20 +
>  ...ld-with-glibc-2.28-since-sys-sysmacr.patch |  90 +++
>  ...vid-pid-remove-add-dynamic-vid-pid-s.patch |  67 ++
>  .../0004-libusbgx-Add-UVC-support.patch       | 737 ++++++++++++++++++
>  patches/libusbgx-0.2.0/autogen.sh             |  16 +
>  patches/libusbgx-0.2.0/series                 |   7 +
>  rules/libusbgx.in                             |   8 +
>  rules/libusbgx.make                           |  66 ++
>  8 files changed, 1011 insertions(+)
>  create mode 100644 patches/libusbgx-0.2.0/0001-Fix-39-Compilation-fails-on-gcc-v8.patch
>  create mode 100644 patches/libusbgx-0.2.0/0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch
>  create mode 100644 patches/libusbgx-0.2.0/0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch
>  create mode 100644 patches/libusbgx-0.2.0/0004-libusbgx-Add-UVC-support.patch
>  create mode 100755 patches/libusbgx-0.2.0/autogen.sh
>  create mode 100644 patches/libusbgx-0.2.0/series
>  create mode 100644 rules/libusbgx.in
>  create mode 100644 rules/libusbgx.make
> 
> diff --git a/patches/libusbgx-0.2.0/0001-Fix-39-Compilation-fails-on-gcc-v8.patch b/patches/libusbgx-0.2.0/0001-Fix-39-Compilation-fails-on-gcc-v8.patch
> new file mode 100644
> index 000000000..4e7ff0ca4
> --- /dev/null
> +++ b/patches/libusbgx-0.2.0/0001-Fix-39-Compilation-fails-on-gcc-v8.patch
> @@ -0,0 +1,20 @@
> +From: Federico Fuga <fuga@studiofuga.com>
> +Date: Thu, 23 May 2019 13:40:39 +0200
> +Subject: [PATCH] Fix #39 Compilation fails on gcc v8
> +
> +---
> + src/usbg_common.c | 1 +
> + 1 file changed, 1 insertion(+)
> +
> +diff --git a/src/usbg_common.c b/src/usbg_common.c
> +index f8822fcf727f..f3aa8b053c44 100644
> +--- a/src/usbg_common.c
> ++++ b/src/usbg_common.c
> +@@ -20,6 +20,7 @@
> + #include <stdio.h>
> + #include <stdlib.h>
> + #include <unistd.h>
> ++#include <sys/sysmacros.h>
> + 
> + int usbg_read_buf_limited(const char *path, const char *name,
> + 			  const char *file, char *buf, int len)
> diff --git a/patches/libusbgx-0.2.0/0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch b/patches/libusbgx-0.2.0/0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch
> new file mode 100644
> index 000000000..9670d469a
> --- /dev/null
> +++ b/patches/libusbgx-0.2.0/0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch
> @@ -0,0 +1,90 @@
> +From: Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
> +Date: Mon, 10 Sep 2018 15:52:09 +0200
> +Subject: [PATCH] libusbgx: fix build with glibc-2.28 since <sys/sysmacros.h>
> + is no more included by <sys/types.h>
> +
> +Signed-off-by: Sid Spry R030t1@gmail.com
> +Signed-off-by: Gwenhael Goavec-Merou gwenhael.goavec-merou@trabucayre.com
> +[Copy sign-offs from pull requst to commit msg]
> +Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
> +---
> + examples/gadget-acm-ecm.c              | 1 +
> + examples/gadget-import.c               | 1 +
> + examples/gadget-ms.c                   | 1 +
> + examples/show-gadgets.c                | 1 +
> + examples/show-udcs.c                   | 1 +
> + include/usbg/usbg_internal_libconfig.h | 1 +
> + 6 files changed, 6 insertions(+)
> +
> +diff --git a/examples/gadget-acm-ecm.c b/examples/gadget-acm-ecm.c
> +index 1c5e2ca5161c..29360da15811 100644
> +--- a/examples/gadget-acm-ecm.c
> ++++ b/examples/gadget-acm-ecm.c
> +@@ -20,6 +20,7 @@
> + 
> + #include <errno.h>
> + #include <stdio.h>
> ++#include <sys/sysmacros.h>
> + #include <linux/usb/ch9.h>
> + #include <usbg/usbg.h>
> + 
> +diff --git a/examples/gadget-import.c b/examples/gadget-import.c
> +index e684fdb861e8..63df4499926b 100644
> +--- a/examples/gadget-import.c
> ++++ b/examples/gadget-import.c
> +@@ -25,6 +25,7 @@
> + #include <errno.h>
> + #include <string.h>
> + #include <stdio.h>
> ++#include <sys/sysmacros.h>
> + #include <usbg/usbg.h>
> + 
> + int main(int argc, char **argv)
> +diff --git a/examples/gadget-ms.c b/examples/gadget-ms.c
> +index 478c37097397..a5c668187a96 100644
> +--- a/examples/gadget-ms.c
> ++++ b/examples/gadget-ms.c
> +@@ -23,6 +23,7 @@
> + 
> + #include <errno.h>
> + #include <stdio.h>
> ++#include <sys/sysmacros.h>
> + #include <linux/usb/ch9.h>
> + #include <usbg/usbg.h>
> + #include <usbg/function/ms.h>
> +diff --git a/examples/show-gadgets.c b/examples/show-gadgets.c
> +index 707d4488d16b..a2a21c883b27 100644
> +--- a/examples/show-gadgets.c
> ++++ b/examples/show-gadgets.c
> +@@ -21,6 +21,7 @@
> + #include <errno.h>
> + #include <stdio.h>
> + #include <string.h>
> ++#include <sys/sysmacros.h>
> + #include <netinet/ether.h>
> + #include <usbg/usbg.h>
> + #include <usbg/function/ms.h>
> +diff --git a/examples/show-udcs.c b/examples/show-udcs.c
> +index 66e950f7bf85..2f5cc458ebb1 100644
> +--- a/examples/show-udcs.c
> ++++ b/examples/show-udcs.c
> +@@ -23,6 +23,7 @@
> + 
> + #include <errno.h>
> + #include <stdio.h>
> ++#include <sys/sysmacros.h>
> + #include <usbg/usbg.h>
> + 
> + int main(void)
> +diff --git a/include/usbg/usbg_internal_libconfig.h b/include/usbg/usbg_internal_libconfig.h
> +index ac51758b3d6c..3fa55c0b544b 100644
> +--- a/include/usbg/usbg_internal_libconfig.h
> ++++ b/include/usbg/usbg_internal_libconfig.h
> +@@ -12,6 +12,7 @@
> + #ifndef USBG_INTERNAL_LIBCONFIG_H
> + #define USBG_INTERNAL_LIBCONFIG_H
> + 
> ++#include <sys/sysmacros.h>
> + #include <libconfig.h>
> + #ifdef __cplusplus
> + extern "C" {
> diff --git a/patches/libusbgx-0.2.0/0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch b/patches/libusbgx-0.2.0/0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch
> new file mode 100644
> index 000000000..63ddf347f
> --- /dev/null
> +++ b/patches/libusbgx-0.2.0/0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch
> @@ -0,0 +1,67 @@
> +From: Michael Grzeschik <m.grzeschik@pengutronix.de>
> +Date: Wed, 28 Apr 2021 21:43:07 +0200
> +Subject: [PATCH] examples: gadget-vid-pid-remove: add dynamic vid pid support
> +
> +Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> +---
> + examples/gadget-vid-pid-remove.c | 25 ++++++++++++++++++++-----
> + 1 file changed, 20 insertions(+), 5 deletions(-)
> +
> +diff --git a/examples/gadget-vid-pid-remove.c b/examples/gadget-vid-pid-remove.c
> +index f6b950b38da3..f5eb9664b721 100644
> +--- a/examples/gadget-vid-pid-remove.c
> ++++ b/examples/gadget-vid-pid-remove.c
> +@@ -23,11 +23,10 @@
> + 
> + #include <errno.h>
> + #include <stdio.h>
> ++#include <string.h>
> ++#include <stdlib.h>
> + #include <usbg/usbg.h>
> + 
> +-#define VENDOR		0x1d6b
> +-#define PRODUCT		0x0104
> +-
> + int remove_gadget(usbg_gadget *g)
> + {
> + 	int usbg_ret;
> +@@ -60,13 +59,29 @@ out:
> + 	return usbg_ret;
> + }
> + 
> +-int main(void)
> ++int main(int argc, char **argv)
> + {
> + 	int usbg_ret;
> + 	int ret = -EINVAL;
> + 	usbg_state *s;
> + 	usbg_gadget *g;
> + 	struct usbg_gadget_attrs g_attrs;
> ++	char *cp;
> ++	int vendor = 0x1d6b, product = 0x0104;
> ++
> ++	if (argc >= 2) {
> ++		cp = strchr(argv[1], ':');
> ++		if (!cp) {
> ++			ret = -EINVAL;
> ++			fprintf(stderr, "Usage: gadget-vid-pid-remove vid:pid\n");
> ++			goto out1;
> ++		}
> ++		*cp++ = 0;
> ++		if (&argv[1])
> ++			vendor = strtoul(argv[1], NULL, 16);
> ++		if (*cp)
> ++			product = strtoul(cp, NULL, 16);
> ++	}
> + 
> + 	usbg_ret = usbg_init("/sys/kernel/config", &s);
> + 	if (usbg_ret != USBG_SUCCESS) {
> +@@ -88,7 +103,7 @@ int main(void)
> + 		}
> + 
> + 		/* Compare attrs with given values and remove if suitable */
> +-		if (g_attrs.idVendor == VENDOR && g_attrs.idProduct == PRODUCT) {
> ++		if (g_attrs.idVendor == vendor && g_attrs.idProduct == product) {
> + 			usbg_gadget *g_next = usbg_get_next_gadget(g);
> + 
> + 			usbg_ret = remove_gadget(g);
> diff --git a/patches/libusbgx-0.2.0/0004-libusbgx-Add-UVC-support.patch b/patches/libusbgx-0.2.0/0004-libusbgx-Add-UVC-support.patch
> new file mode 100644
> index 000000000..0217bb02d
> --- /dev/null
> +++ b/patches/libusbgx-0.2.0/0004-libusbgx-Add-UVC-support.patch
> @@ -0,0 +1,737 @@
> +From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
> +Date: Wed, 8 Jan 2020 14:43:45 +0100
> +Subject: [PATCH] libusbgx: Add UVC support
> +
> +Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
> +Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> +
> +Notes:
> +v2 -> v3: - simplified exit paths of functions with reutrns instead of gotos
> +          - added cleanup code for remove
> +	  - added gadget-uvc example file
> +	  - simplified class link creation
> +	  - added support for more than one format
> +---
> + Makefile.am                 |   2 +-
> + examples/Makefile.am        |   3 +-
> + examples/gadget-uvc.c       | 156 ++++++++++++++++++
> + include/usbg/function/uvc.h |  90 +++++++++++
> + include/usbg/usbg.h         |   1 +
> + src/Makefile.am             |   2 +-
> + src/function/uvc.c          | 378 ++++++++++++++++++++++++++++++++++++++++++++
> + src/usbg.c                  |   2 +
> + 8 files changed, 631 insertions(+), 3 deletions(-)
> + create mode 100644 examples/gadget-uvc.c
> + create mode 100644 include/usbg/function/uvc.h
> + create mode 100644 src/function/uvc.c
> +
> +diff --git a/Makefile.am b/Makefile.am
> +index a3cc337c18da..b3cd097d9d32 100644
> +--- a/Makefile.am
> ++++ b/Makefile.am
> +@@ -14,6 +14,6 @@ EXTRA_DIST = doxygen.cfg
> + library_includedir=$(includedir)/usbg
> + library_include_HEADERS = include/usbg/usbg.h include/usbg/usbg_version.h
> + function_includedir=$(includedir)/usbg/function
> +-function_include_HEADERS = include/usbg/function/ffs.h include/usbg/function/loopback.h include/usbg/function/midi.h include/usbg/function/ms.h include/usbg/function/net.h include/usbg/function/phonet.h include/usbg/function/serial.h include/usbg/function/hid.h include/usbg/function/uac2.h
> ++function_include_HEADERS = include/usbg/function/ffs.h include/usbg/function/loopback.h include/usbg/function/midi.h include/usbg/function/ms.h include/usbg/function/net.h include/usbg/function/phonet.h include/usbg/function/serial.h include/usbg/function/hid.h include/usbg/function/uac2.h include/usbg/function/uvc.h
> + pkgconfigdir = $(libdir)/pkgconfig
> + pkgconfig_DATA = libusbgx.pc
> +diff --git a/examples/Makefile.am b/examples/Makefile.am
> +index 993432156d6c..3217eb3bfd6f 100644
> +--- a/examples/Makefile.am
> ++++ b/examples/Makefile.am
> +@@ -1,5 +1,6 @@
> +-bin_PROGRAMS = show-gadgets gadget-acm-ecm gadget-vid-pid-remove gadget-ffs gadget-export gadget-import show-udcs gadget-ms gadget-midi gadget-hid gadget-rndis-os-desc gadget-uac2
> ++bin_PROGRAMS = show-gadgets gadget-acm-ecm gadget-vid-pid-remove gadget-uvc gadget-ffs gadget-export gadget-import show-udcs gadget-ms gadget-midi gadget-hid gadget-rndis-os-desc gadget-uac2
> + gadget_acm_ecm_SOURCES = gadget-acm-ecm.c
> ++gadget_uvc_SOURCES = gadget-uvc.c
> + show_gadgets_SOURCES = show-gadgets.c
> + gadget_vid_pid_remove_SOURCES = gadget-vid-pid-remove.c
> + gadget_ffs_SOURCES = gadget-ffs.c
> +diff --git a/examples/gadget-uvc.c b/examples/gadget-uvc.c
> +new file mode 100644
> +index 000000000000..d3efe2deaebe
> +--- /dev/null
> ++++ b/examples/gadget-uvc.c
> +@@ -0,0 +1,156 @@
> ++/*
> ++ * Copyright (C) 2021 Pengutronix
> ++ *
> ++ * Michael Grzeschik <mgr@pengutronix.de>
> ++ *
> ++ * This program is free software; you can redistribute it and/or modify
> ++ * it under the terms of the GNU General Public License as published by
> ++ * the Free Software Foundation; either version 2 of the License, or
> ++ * (at your option) any later version.
> ++ *
> ++ * This program is distributed in the hope that it will be useful,
> ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> ++ * GNU General Public License for more details.
> ++ */
> ++
> ++#include <errno.h>
> ++#include <stdio.h>
> ++#include <sys/sysmacros.h>
> ++#include <linux/usb/ch9.h>
> ++#include <usbg/usbg.h>
> ++#include <usbg/function/uvc.h>
> ++
> ++/**
> ++ * @file gadget-uvc.c
> ++ * @example gadget-uvc.c
> ++ * This is an example of how to create an UVC gadget device.
> ++ */
> ++
> ++#define VENDOR		0x1d6b
> ++#define PRODUCT		0x0104
> ++
> ++int main(void)
> ++{
> ++	usbg_state *s;
> ++	usbg_gadget *g;
> ++	usbg_config *c;
> ++	usbg_function *f_uvc;
> ++	int ret = -EINVAL;
> ++	int usbg_ret;
> ++
> ++	struct usbg_gadget_attrs g_attrs = {
> ++		.bcdUSB = 0x0200,
> ++		.bDeviceClass =	USB_CLASS_PER_INTERFACE,
> ++		.bDeviceSubClass = 0x00,
> ++		.bDeviceProtocol = 0x00,
> ++		.bMaxPacketSize0 = 64, /* Max allowed ep0 packet size */
> ++		.idVendor = VENDOR,
> ++		.idProduct = PRODUCT,
> ++		.bcdDevice = 0x0001, /* Verson of device */
> ++	};
> ++
> ++	struct usbg_gadget_strs g_strs = {
> ++		.serial = "0123456789", /* Serial number */
> ++		.manufacturer = "Foo Inc.", /* Manufacturer */
> ++		.product = "Bar Gadget" /* Product string */
> ++	};
> ++
> ++	struct usbg_config_strs c_strs = {
> ++		.configuration = "UVC"
> ++	};
> ++
> ++	struct usbg_f_uvc_format_attrs uvc_format_attrs_array[] = {
> ++		{
> ++			.format = UVC_FORMAT_MJPEG,
> ++			.dwFrameInterval = "333333",
> ++			.height = 1080,
> ++			.width = 1920,
> ++		}, {
> ++			.format = UVC_FORMAT_MJPEG,
> ++			.dwFrameInterval = "333333",
> ++			.height = 3940,
> ++			.width = 2160,
> ++		}, {
> ++			.format = UVC_FORMAT_UNCOMPRESSED,
> ++			.dwFrameInterval = "333333",
> ++			.height = 1080,
> ++			.width = 1920,
> ++		}, {
> ++			.format = UVC_FORMAT_UNCOMPRESSED,
> ++			.dwFrameInterval = "333333",
> ++			.height = 3940,
> ++			.width = 2160,
> ++		}
> ++	};
> ++
> ++	struct usbg_f_uvc_format_attrs *uvc_format_attrs[] = {
> ++		&uvc_format_attrs_array[3],
> ++		&uvc_format_attrs_array[2],
> ++		&uvc_format_attrs_array[1],
> ++		&uvc_format_attrs_array[0],
> ++		NULL,
> ++	};
> ++
> ++	struct usbg_f_uvc_attrs uvc_attrs = {
> ++		.formats = uvc_format_attrs,
> ++	};
> ++
> ++	usbg_ret = usbg_init("/sys/kernel/config", &s);
> ++	if (usbg_ret != USBG_SUCCESS) {
> ++		fprintf(stderr, "Error on USB gadget init\n");
> ++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
> ++				usbg_strerror(usbg_ret));
> ++		goto out1;
> ++	}
> ++
> ++	usbg_ret = usbg_create_gadget(s, "g1", &g_attrs, &g_strs, &g);
> ++	if (usbg_ret != USBG_SUCCESS) {
> ++		fprintf(stderr, "Error on create gadget\n");
> ++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
> ++				usbg_strerror(usbg_ret));
> ++		goto out2;
> ++	}
> ++
> ++        usbg_ret = usbg_create_function(g, USBG_F_UVC, "uvc", &uvc_attrs, &f_uvc);
> ++        if(usbg_ret != USBG_SUCCESS)
> ++        {
> ++		fprintf(stderr, "Error creating uvc function\n");
> ++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
> ++				usbg_strerror(usbg_ret));
> ++		goto out2;
> ++	}
> ++
> ++	/* NULL can be passed to use kernel defaults */
> ++	usbg_ret = usbg_create_config(g, 1, "The only one", NULL, &c_strs, &c);
> ++	if (usbg_ret != USBG_SUCCESS) {
> ++		fprintf(stderr, "Error creating config\n");
> ++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
> ++				usbg_strerror(usbg_ret));
> ++		goto out2;
> ++	}
> ++
> ++        usbg_ret = usbg_add_config_function(c, "uvc.cam", f_uvc);
> ++	if (usbg_ret != USBG_SUCCESS) {
> ++		fprintf(stderr, "Error adding acm.GS0\n");
> ++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
> ++				usbg_strerror(usbg_ret));
> ++		goto out2;
> ++	}
> ++
> ++	usbg_ret = usbg_enable_gadget(g, DEFAULT_UDC);
> ++	if (usbg_ret != USBG_SUCCESS) {
> ++		fprintf(stderr, "Error enabling gadget\n");
> ++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
> ++				usbg_strerror(usbg_ret));
> ++		goto out2;
> ++	}
> ++
> ++	ret = 0;
> ++
> ++out2:
> ++	usbg_cleanup(s);
> ++
> ++out1:
> ++	return ret;
> ++}
> +diff --git a/include/usbg/function/uvc.h b/include/usbg/function/uvc.h
> +new file mode 100644
> +index 000000000000..4c641dacdfcb
> +--- /dev/null
> ++++ b/include/usbg/function/uvc.h
> +@@ -0,0 +1,90 @@
> ++/*
> ++ * This library is free software; you can redistribute it and/or
> ++ * modify it under the terms of the GNU Lesser General Public
> ++ * License as published by the Free Software Foundation; either
> ++ * version 2.1 of the License, or (at your option) any later version.
> ++ *
> ++ * This library is distributed in the hope that it will be useful,
> ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> ++ * Lesser General Public License for more details.
> ++ */
> ++
> ++#ifndef USBG_FUNCTION_UVC__
> ++#define USBG_FUNCTION_UVC__
> ++
> ++#include <usbg/usbg.h>
> ++
> ++#ifdef __cplusplus
> ++extern "C" {
> ++#endif
> ++
> ++
> ++#define USBG_UVC_MAX_PATH_LENGTH 1024
> ++
> ++struct usbg_f_uvc;
> ++typedef struct usbg_f_uvc usbg_f_uvc;
> ++
> ++enum uvc_format
> ++{
> ++	UVC_FORMAT_MJPEG,
> ++	UVC_FORMAT_UNCOMPRESSED
> ++};
> ++
> ++struct usbg_f_uvc_format_attrs
> ++{
> ++	enum uvc_format format;
> ++	const char *dwFrameInterval;
> ++	int height;
> ++	int width;
> ++};
> ++
> ++struct usbg_f_uvc_attrs
> ++{
> ++	struct usbg_f_uvc_format_attrs **formats;
> ++};
> ++
> ++/**
> ++ * @brief Cast from generic function to uvc function
> ++ * @param[in] f function to be converted to uvc funciton.
> ++ *         Should be one of types:
> ++ *         ecm, subset, ncm, eem, rndis
> ++ * @return Converted uvc function or NULL if function hasn't suitable type
> ++ */
> ++usbg_f_uvc *usbg_to_uvc_function(usbg_function *f);
> ++
> ++/**
> ++ * @brief Cast form uvc function to generic one
> ++ * @param[in] uvc function to be converted to generic one
> ++ * @return Generic usbg function
> ++ */
> ++usbg_function *usbg_from_uvc_function(usbg_f_uvc *ff);
> ++
> ++/**
> ++ * @brief Cleanup attributes structure after usage
> ++ * @param[in] attrs to be cleaned up
> ++ */
> ++static inline void usbg_f_uvc_cleanup_attrs(struct usbg_f_uvc_attrs *attrs)
> ++{
> ++	struct usbg_f_uvc_format_attrs **format_attrs;
> ++	int i;
> ++
> ++	if (attrs) {
> ++		for(format_attrs = attrs->formats, i = 0; format_attrs[i]; ++i) {
> ++			if (format_attrs[i]) {
> ++				free((char *)format_attrs[i]->dwFrameInterval);
> ++				format_attrs[i]->dwFrameInterval = NULL;
> ++			}
> ++		}
> ++	}
> ++}
> ++
> ++int usbg_f_uvc_get_attrs(usbg_f_uvc *uvcf, struct usbg_f_uvc_attrs *attrs);
> ++int usbg_f_uvc_set_attrs(usbg_f_uvc *uvcf, const struct usbg_f_uvc_attrs *attrs);
> ++
> ++
> ++#ifdef __cplusplus
> ++}
> ++#endif
> ++
> ++#endif /* USBG_FUNCTION_UVC__ */
> +diff --git a/include/usbg/usbg.h b/include/usbg/usbg.h
> +index 55c52a1c3768..de72793ddcf0 100644
> +--- a/include/usbg/usbg.h
> ++++ b/include/usbg/usbg.h
> +@@ -219,6 +219,7 @@ typedef enum
> + 	USBG_F_LOOPBACK,
> + 	USBG_F_HID,
> + 	USBG_F_UAC2,
> ++	USBG_F_UVC,
> + 	USBG_FUNCTION_TYPE_MAX,
> + } usbg_function_type;
> + 
> +diff --git a/src/Makefile.am b/src/Makefile.am
> +index 6b2726ec5219..c51878fac2ff 100644
> +--- a/src/Makefile.am
> ++++ b/src/Makefile.am
> +@@ -1,6 +1,6 @@
> + AUTOMAKE_OPTIONS = std-options subdir-objects
> + lib_LTLIBRARIES = libusbgx.la
> +-libusbgx_la_SOURCES = usbg.c usbg_error.c usbg_common.c function/ether.c function/ffs.c function/midi.c function/ms.c function/phonet.c function/serial.c function/loopback.c function/hid.c function/uac2.c
> ++libusbgx_la_SOURCES = usbg.c usbg_error.c usbg_common.c function/ether.c function/ffs.c function/midi.c function/ms.c function/phonet.c function/serial.c function/loopback.c function/hid.c function/uac2.c function/uvc.c
> + if TEST_GADGET_SCHEMES
> + libusbgx_la_SOURCES += usbg_schemes_libconfig.c usbg_common_libconfig.c
> + else
> +diff --git a/src/function/uvc.c b/src/function/uvc.c
> +new file mode 100644
> +index 000000000000..92d738c5763c
> +--- /dev/null
> ++++ b/src/function/uvc.c
> +@@ -0,0 +1,378 @@
> ++/*
> ++ * This library is free software; you can redistribute it and/or
> ++ * modify it under the terms of the GNU Lesser General Public
> ++ * License as published by the Free Software Foundation; either
> ++ * version 2.1 of the License, or (at your option) any later version.
> ++ *
> ++ * This library is distributed in the hope that it will be useful,
> ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> ++ * Lesser General Public License for more details.
> ++ */
> ++
> ++#include "usbg/usbg.h"
> ++#include "usbg/usbg_internal.h"
> ++#include "usbg/function/uvc.h"
> ++
> ++#include <errno.h>
> ++#include <sys/stat.h>
> ++#include <unistd.h>
> ++#include <malloc.h>
> ++#include <ftw.h>
> ++#ifdef HAS_GADGET_SCHEMES
> ++#include <libconfig.h>
> ++#endif
> ++
> ++#define UVC_PATH_CONTROL		"control"
> ++#define UVC_PATH_HEADER			"header/h"
> ++#define UVC_PATH_CLASS_FS		"class/fs/h"
> ++#define UVC_PATH_CLASS_HS		"class/hs/h"
> ++#define UVC_PATH_CLASS_SS		"class/ss/h"
> ++#define UVC_PATH_STREAMING		"streaming"
> ++#define UVC_PATH_STREAMING_UNCOMPRESSED	"uncompressed/u"
> ++#define UVC_PATH_STREAMING_MJPEG	"mjpeg/m"
> ++
> ++struct usbg_f_uvc
> ++{
> ++	struct usbg_function func;
> ++};
> ++
> ++GENERIC_ALLOC_INST(uvc, struct usbg_f_uvc, func);
> ++
> ++GENERIC_FREE_INST(uvc, struct usbg_f_uvc, func);
> ++
> ++static int uvc_set_attrs(struct usbg_function *f, void *f_attrs)
> ++{
> ++	return usbg_f_uvc_set_attrs(usbg_to_uvc_function(f), f_attrs);
> ++}
> ++
> ++static int uvc_get_attrs(struct usbg_function *f, void *f_attrs)
> ++{
> ++	return usbg_f_uvc_get_attrs(usbg_to_uvc_function(f), f_attrs);
> ++}
> ++
> ++static void uvc_cleanup_attrs(struct usbg_function *f, void *f_attrs)
> ++{
> ++	return usbg_f_uvc_cleanup_attrs(f_attrs);
> ++}
> ++
> ++static int uvc_libconfig_import(struct usbg_function *f, config_setting_t *root)
> ++{
> ++	return USBG_SUCCESS;
> ++}
> ++
> ++static int uvc_libconfig_export(struct usbg_function *f, config_setting_t *root)
> ++{
> ++	return USBG_SUCCESS;
> ++}
> ++
> ++static int uvc_create_dir(const char *path)
> ++{
> ++	char tmp[USBG_MAX_PATH_LENGTH];
> ++	char *p = NULL;
> ++	size_t len;
> ++	int nmb, ret = USBG_SUCCESS;
> ++
> ++	nmb = snprintf(tmp, sizeof(tmp), "%s", path);
> ++	if(nmb >= sizeof(tmp))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	len = strlen(tmp);
> ++	if(tmp[len - 1] == '/')
> ++		tmp[len - 1] = 0;
> ++
> ++	for (p = tmp + 1; *p; p++) {
> ++		if(*p == '/') {
> ++			*p = 0;
> ++			if((mkdir(tmp, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && errno != EEXIST) {
> ++				ret = usbg_translate_error(errno);
> ++				break;
> ++			}
> ++			*p = '/';
> ++		}
> ++	}
> ++	if(ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	if((mkdir(tmp, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && errno != EEXIST)
> ++		return usbg_translate_error(errno);
> ++}
> ++
> ++static int uvc_link(char *path, char *to, char *from)
> ++{
> ++	char oldname[USBG_MAX_PATH_LENGTH];
> ++	char newname[USBG_MAX_PATH_LENGTH];
> ++	int nmb;
> ++
> ++	nmb = snprintf(oldname, sizeof(oldname), "%s/%s", path, to);
> ++	if (nmb >= sizeof(oldname))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	nmb = snprintf(newname, sizeof(newname), "%s/%s", path, from);
> ++	if (nmb >= sizeof(newname))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	if(symlink(oldname, newname))
> ++		return usbg_translate_error(errno);
> ++}
> ++
> ++static int uvc_set_class(char *func_path, char *cs)
> ++{
> ++	int ret, nmb;
> ++	char path[USBG_MAX_PATH_LENGTH];
> ++	char header_path[USBG_MAX_PATH_LENGTH];
> ++
> ++	nmb = snprintf(path, sizeof(path), "%s/%s", func_path, cs);
> ++	if (nmb >= sizeof(path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	nmb = snprintf(header_path, sizeof(header_path), "%s/" UVC_PATH_HEADER, path);
> ++	if (nmb >= sizeof(header_path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	ret = uvc_create_dir(header_path);
> ++	if (ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	if (!strncmp(cs, UVC_PATH_STREAMING, strlen(UVC_PATH_STREAMING))) {
> ++		char check_path[USBG_MAX_PATH_LENGTH];
> ++		struct stat buffer;
> ++
> ++		nmb = snprintf(check_path, sizeof(check_path), "%s/" UVC_PATH_STREAMING_UNCOMPRESSED, path);
> ++		if (nmb >= sizeof(check_path))
> ++			return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++		ret = stat(check_path, &buffer);
> ++		if (!ret) {
> ++			ret = uvc_link(path, UVC_PATH_STREAMING_UNCOMPRESSED, "header/h/u");
> ++			if (ret != USBG_SUCCESS)
> ++				return ret;
> ++		}
> ++
> ++		nmb = snprintf(check_path, sizeof(check_path), "%s/" UVC_PATH_STREAMING_MJPEG, path);
> ++		if (nmb >= sizeof(check_path))
> ++			return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++		ret = stat(check_path, &buffer);
> ++		if (!ret) {
> ++			ret = uvc_link(path, UVC_PATH_STREAMING_MJPEG, "header/h/m");
> ++			if (ret != USBG_SUCCESS)
> ++				return ret;
> ++		}
> ++
> ++		ret = uvc_link(path, UVC_PATH_HEADER, UVC_PATH_CLASS_HS);
> ++		if (ret)
> ++			return ret;
> ++	}
> ++
> ++	ret = uvc_link(path, UVC_PATH_HEADER, UVC_PATH_CLASS_FS);
> ++	if (ret)
> ++		return ret;
> ++
> ++	return uvc_link(path, UVC_PATH_HEADER, UVC_PATH_CLASS_SS);
> ++}
> ++
> ++static int uvc_set_frame(char *format_path, char *format, const struct usbg_f_uvc_format_attrs *attrs)
> ++{
> ++	int nmb, ret, i;
> ++	char frame_path[USBG_MAX_PATH_LENGTH];
> ++	char full_frame_path[USBG_MAX_PATH_LENGTH];
> ++	char frame_interval[USBG_MAX_PATH_LENGTH];
> ++	char frame_name[32];
> ++
> ++	nmb = snprintf(frame_name, sizeof(frame_name), "%dp", attrs->height);
> ++	if (nmb >= sizeof(frame_name))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	nmb = snprintf(frame_path, sizeof(frame_path), "%s/%s", format_path, format);
> ++	if (nmb >= sizeof(frame_path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	nmb = snprintf(full_frame_path, sizeof(frame_path), "%s/%s", frame_path, frame_name);
> ++	if (nmb >= sizeof(full_frame_path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	ret = uvc_create_dir(full_frame_path);
> ++	if (ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	ret = usbg_write_string(frame_path, frame_name, "dwFrameInterval", attrs->dwFrameInterval);
> ++	if (ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	ret = usbg_write_dec(frame_path, frame_name, "wHeight", attrs->height);
> ++	if (ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	return usbg_write_dec(frame_path, frame_name, "wWidth", attrs->width);
> ++}
> ++
> ++static int uvc_set_streaming(char *func_path, const struct usbg_f_uvc_format_attrs *attrs)
> ++{
> ++	char streaming_path[USBG_MAX_PATH_LENGTH];
> ++	int ret, nmb;
> ++
> ++	nmb = snprintf(streaming_path, sizeof(streaming_path), "%s/" UVC_PATH_STREAMING, func_path);
> ++	if (nmb >= sizeof(streaming_path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	if (attrs->format == UVC_FORMAT_UNCOMPRESSED)
> ++		ret = uvc_set_frame(streaming_path, UVC_PATH_STREAMING_UNCOMPRESSED, attrs);
> ++	else
> ++		ret = uvc_set_frame(streaming_path, UVC_PATH_STREAMING_MJPEG, attrs);
> ++
> ++	return ret;
> ++}
> ++
> ++static int dir_nftw_cb(const char *pathname, const struct stat *sbuf, int type, struct FTW *ftwb)
> ++{
> ++	(void) sbuf;
> ++	(void) type;
> ++	(void) ftwb;
> ++	int ret;
> ++
> ++	ret = remove(pathname);
> ++	if (ret < -1)
> ++		ERROR("failed to remove %s - %s", pathname, strerror(ret));
> ++
> ++	return 0;
> ++}
> ++
> ++int remove_dir(const char *dirpath)
> ++{
> ++	const int max_open_descs = 8;
> ++	int ret;
> ++
> ++	ret = nftw(dirpath, dir_nftw_cb, max_open_descs, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
> ++	if (ret < 0) {
> ++		ERROR("nftw failed");
> ++		return ret;
> ++	}
> ++
> ++	return 0;
> ++}
> ++
> ++static int content_nftw_cb(const char *pathname, const struct stat *sbuf, int type, struct FTW *ftwb)
> ++{
> ++	(void) sbuf;
> ++	(void) type;
> ++	(void) ftwb;
> ++	int ret;
> ++
> ++	if(ftwb->level == 0)
> ++		return 0;
> ++
> ++	ret = remove(pathname);
> ++	if(ret < -1)
> ++		ERROR("failed to remove %s - %s", pathname, strerror(ret));
> ++
> ++	return 0;
> ++}
> ++
> ++int remove_dir_content(const char *dirpath)
> ++{
> ++	const int max_open_descs = 8;
> ++	int ret;
> ++
> ++	/* traverse in reverse order (handle directory after it's content), stay within the same file system and do not follow symbolic links */
> ++	ret = nftw(dirpath, content_nftw_cb, max_open_descs, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
> ++	if (ret < 0) {
> ++		ERROR("nftw failed");
> ++		return ret;
> ++	}
> ++
> ++	return 0;
> ++}
> ++
> ++static int uvc_remove(struct usbg_function *f, int opts)
> ++{
> ++	usbg_f_uvc *uvcf = usbg_to_uvc_function(f);
> ++	char streaming_path[USBG_MAX_PATH_LENGTH];
> ++	char control_path[USBG_MAX_PATH_LENGTH];
> ++	char path[USBG_UVC_MAX_PATH_LENGTH];
> ++	int nmb, ret = USBG_SUCCESS;
> ++
> ++	nmb = snprintf(path, sizeof(path), "%s/%s", uvcf->func.path, uvcf->func.name);
> ++	if (nmb >= sizeof(path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	nmb = snprintf(streaming_path, sizeof(streaming_path), "%s/streaming", path);
> ++	if (nmb >= sizeof(streaming_path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	nmb = snprintf(control_path, sizeof(control_path), "%s/control", path);
> ++	if (nmb >= sizeof(control_path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	if(remove_dir_content(streaming_path) < 0)
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	if(remove_dir_content(control_path) < 0)
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	if(remove_dir(streaming_path) < 0)
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	if(remove_dir(control_path) < 0)
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	return 0;
> ++};
> ++
> ++struct usbg_function_type usbg_f_type_uvc = {
> ++	.name = "uvc",
> ++	.alloc_inst = uvc_alloc_inst,
> ++	.free_inst = uvc_free_inst,
> ++	.set_attrs = uvc_set_attrs,
> ++	.get_attrs = uvc_get_attrs,
> ++	.cleanup_attrs = uvc_cleanup_attrs,
> ++	.import = uvc_libconfig_import,
> ++	.export = uvc_libconfig_export,
> ++	.remove = uvc_remove,
> ++};
> ++
> ++/* API implementation */
> ++
> ++usbg_f_uvc *usbg_to_uvc_function(usbg_function *f)
> ++{
> ++	return f->ops == &usbg_f_type_uvc ?
> ++			container_of(f, struct usbg_f_uvc, func) : NULL;
> ++}
> ++
> ++usbg_function *usbg_from_uvc_function(usbg_f_uvc *ff)
> ++{
> ++	return &ff->func;
> ++}
> ++
> ++int usbg_f_uvc_get_attrs(usbg_f_uvc *uvcf, struct usbg_f_uvc_attrs *attrs)
> ++{
> ++	return USBG_SUCCESS;
> ++}
> ++
> ++int usbg_f_uvc_set_attrs(usbg_f_uvc *uvcf, const struct usbg_f_uvc_attrs *attrs)
> ++{
> ++	int nmb, ret = USBG_SUCCESS;
> ++	char path[USBG_UVC_MAX_PATH_LENGTH];
> ++	struct usbg_f_uvc_format_attrs **format_attrs;
> ++	int i;
> ++
> ++	nmb = snprintf(path, sizeof(path), "%s/%s", uvcf->func.path, uvcf->func.name);
> ++	if (nmb >= sizeof(path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	for(format_attrs = attrs->formats, i = 0; format_attrs[i]; ++i) {
> ++		ret = uvc_set_streaming(path, format_attrs[i]);
> ++		if(ret != USBG_SUCCESS)
> ++			ERROR("Error: %d", ret);
> ++	}
> ++
> ++	ret = uvc_set_class(path, "control");
> ++	if (ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	ret = uvc_set_class(path, "streaming");
> ++	if (ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	return ret;
> ++}
> +diff --git a/src/usbg.c b/src/usbg.c
> +index d2bf38160358..b298ddc50ecf 100644
> +--- a/src/usbg.c
> ++++ b/src/usbg.c
> +@@ -52,6 +52,7 @@ extern struct usbg_function_type usbg_f_type_phonet;
> + extern struct usbg_function_type usbg_f_type_loopback;
> + extern struct usbg_function_type usbg_f_type_hid;
> + extern struct usbg_function_type usbg_f_type_uac2;
> ++extern struct usbg_function_type usbg_f_type_uvc;
> + 
> + /**
> +  * @var function_types
> +@@ -73,6 +74,7 @@ struct usbg_function_type* function_types[] = {
> + 	[USBG_F_LOOPBACK] = &usbg_f_type_loopback,
> + 	[USBG_F_HID] = &usbg_f_type_hid,
> + 	[USBG_F_UAC2] = &usbg_f_type_uac2,
> ++	[USBG_F_UVC] = &usbg_f_type_uvc,
> + };
> + 
> + ARRAY_SIZE_SENTINEL(function_types, USBG_FUNCTION_TYPE_MAX);
> diff --git a/patches/libusbgx-0.2.0/autogen.sh b/patches/libusbgx-0.2.0/autogen.sh
> new file mode 100755
> index 000000000..2459647bf
> --- /dev/null
> +++ b/patches/libusbgx-0.2.0/autogen.sh
> @@ -0,0 +1,16 @@
> +#!/bin/bash
> +
> +set -e
> +
> +aclocal $ACLOCAL_FLAGS
> +
> +libtoolize \
> +	--force \
> +	--copy
> +
> +autoreconf \
> +	--force \
> +	--install \
> +	--warnings=syntax \
> +	--warnings=obsolete \
> +	--warnings=unsupported
> diff --git a/patches/libusbgx-0.2.0/series b/patches/libusbgx-0.2.0/series
> new file mode 100644
> index 000000000..406d15acc
> --- /dev/null
> +++ b/patches/libusbgx-0.2.0/series
> @@ -0,0 +1,7 @@
> +# generated by git-ptx-patches
> +#tag:base --start-number 1
> +0001-Fix-39-Compilation-fails-on-gcc-v8.patch
> +0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch
> +0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch
> +0004-libusbgx-Add-UVC-support.patch
> +# 55b4c63ca7f6b97ceb9cd9588e1eacdd  - git-ptx-patches magic
> diff --git a/rules/libusbgx.in b/rules/libusbgx.in
> new file mode 100644
> index 000000000..98776c026
> --- /dev/null
> +++ b/rules/libusbgx.in
> @@ -0,0 +1,8 @@
> +## SECTION=communication
> +
> +config LIBUSBGX
> +	bool
> +	prompt "libusbgx"
> +	help
> +	  libusbgx is a C library encapsulating the kernel USB gadget-configfs
> +	  userspace API functionality.
> diff --git a/rules/libusbgx.make b/rules/libusbgx.make
> new file mode 100644
> index 000000000..6c8fce429
> --- /dev/null
> +++ b/rules/libusbgx.make
> @@ -0,0 +1,66 @@
> +# -*-makefile-*-
> +#
> +# Copyright (C) 2018 by Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
> +#
> +# See CREDITS for details about who has contributed to this project.
> +#
> +# For further information about the PTXdist project and license conditions
> +# see the README file.
> +#
> +
> +#
> +# We provide this package
> +#
> +PACKAGES-$(PTXCONF_LIBUSBGX) += libusbgx
> +
> +#
> +# Paths and names
> +#
> +LIBUSBGX_VERSION	:= 0.2.0
> +LIBUSBGX_MD5		:= a8ea2234c6355ac8ad2ca86c453297bd
> +LIBUSBGX		:= libusbgx-$(LIBUSBGX_VERSION)
> +LIBUSBGX_SUFFIX		:= zip
> +LIBUSBGX_URL		:= \
> +	https://github.com/libusbgx/libusbgx/archive/libusbgx-v$(LIBUSBGX_VERSION).zip
> +LIBUSBGX_SOURCE	:= \
> +	$(SRCDIR)/$(LIBUSBGX).$(LIBUSBGX_SUFFIX)
> +LIBUSBGX_DIR		:= $(BUILDDIR)/$(LIBUSBGX)
> +LIBUSBGX_LICENSE	:= GPLv2
> +
> +# ----------------------------------------------------------------------------
> +# Prepare
> +# ----------------------------------------------------------------------------
> +
> +LIBUSBGX_CONF_ENV	:= $(CROSS_ENV)
> +
> +#
> +# autoconf
> +#
> +LIBUSBGX_CONF_TOOL	:= autoconf
> +LIBUSBGX_CONF_OPT	:= \
> +	$(CROSS_AUTOCONF_USR) \
> +	--without-libconfig \
> +	--enable-examples \
> +	--disable-gadget-schemes
> +
> +# ----------------------------------------------------------------------------
> +# Target-Install
> +# ----------------------------------------------------------------------------
> +
> +$(STATEDIR)/libusbgx.targetinstall:
> +	@$(call targetinfo)
> +
> +	@$(call install_init, libusbgx)
> +	@$(call install_fixup, libusbgx, PRIORITY, optional)
> +	@$(call install_fixup, libusbgx, SECTION, base)
> +	@$(call install_fixup, libusbgx, AUTHOR, "Thomas Haemmerle <thomas.haemmerle@wolfvision.net>")
> +	@$(call install_fixup, libusbgx, DESCRIPTION, missing)
> +
> +	@$(call install_lib, libusbgx, 0, 0, 0644, libusbgx)
> +	@$(call install_tree, libusbgx, 0, 0, -, /usr/bin)
> +
> +	@$(call install_finish, libusbgx)
> +
> +	@$(call touch)
> +
> +# vim: syntax=make
> -- 
> 2.29.2
> 
> 
> _______________________________________________
> ptxdist mailing list
> ptxdist@pengutronix.de
> To unsubscribe, send a mail with subject "unsubscribe" to ptxdist-request@pengutronix.de
> 

-- 
Roland Hieber, Pengutronix e.K.          | r.hieber@pengutronix.de     |
Steuerwalder Str. 21                     | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686         | Fax:   +49-5121-206917-5555 |

_______________________________________________
ptxdist mailing list
ptxdist@pengutronix.de
To unsubscribe, send a mail with subject "unsubscribe" to ptxdist-request@pengutronix.de

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [ptxdist] [APPLIED] libusbgx: new package
  2021-04-28 23:24 [ptxdist] [PATCH] libusbgx: new package Michael Grzeschik
  2021-04-29 11:29 ` Roland Hieber
@ 2021-05-07  6:07 ` Michael Olbrich
  1 sibling, 0 replies; 3+ messages in thread
From: Michael Olbrich @ 2021-05-07  6:07 UTC (permalink / raw)
  To: ptxdist; +Cc: Michael Grzeschik

Thanks, applied as 6677792614505262f62e8b0a5dfbe1df130ed633.

Michael

[sent from post-receive hook]

On Fri, 07 May 2021 08:07:11 +0200, Michael Grzeschik <m.grzeschik@pengutronix.de> wrote:
> This patch adds libusbgx support to ptxdist. It includes patches to work
> with uvc gadgets.
> 
> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> Message-Id: <20210428232410.15059-1-m.grzeschik@pengutronix.de>
> Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
> 
> diff --git a/patches/libusbgx-0.2.0/0001-Fix-39-Compilation-fails-on-gcc-v8.patch b/patches/libusbgx-0.2.0/0001-Fix-39-Compilation-fails-on-gcc-v8.patch
> new file mode 100644
> index 000000000000..4e7ff0ca427e
> --- /dev/null
> +++ b/patches/libusbgx-0.2.0/0001-Fix-39-Compilation-fails-on-gcc-v8.patch
> @@ -0,0 +1,20 @@
> +From: Federico Fuga <fuga@studiofuga.com>
> +Date: Thu, 23 May 2019 13:40:39 +0200
> +Subject: [PATCH] Fix #39 Compilation fails on gcc v8
> +
> +---
> + src/usbg_common.c | 1 +
> + 1 file changed, 1 insertion(+)
> +
> +diff --git a/src/usbg_common.c b/src/usbg_common.c
> +index f8822fcf727f..f3aa8b053c44 100644
> +--- a/src/usbg_common.c
> ++++ b/src/usbg_common.c
> +@@ -20,6 +20,7 @@
> + #include <stdio.h>
> + #include <stdlib.h>
> + #include <unistd.h>
> ++#include <sys/sysmacros.h>
> + 
> + int usbg_read_buf_limited(const char *path, const char *name,
> + 			  const char *file, char *buf, int len)
> diff --git a/patches/libusbgx-0.2.0/0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch b/patches/libusbgx-0.2.0/0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch
> new file mode 100644
> index 000000000000..9670d469acb3
> --- /dev/null
> +++ b/patches/libusbgx-0.2.0/0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch
> @@ -0,0 +1,90 @@
> +From: Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
> +Date: Mon, 10 Sep 2018 15:52:09 +0200
> +Subject: [PATCH] libusbgx: fix build with glibc-2.28 since <sys/sysmacros.h>
> + is no more included by <sys/types.h>
> +
> +Signed-off-by: Sid Spry R030t1@gmail.com
> +Signed-off-by: Gwenhael Goavec-Merou gwenhael.goavec-merou@trabucayre.com
> +[Copy sign-offs from pull requst to commit msg]
> +Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
> +---
> + examples/gadget-acm-ecm.c              | 1 +
> + examples/gadget-import.c               | 1 +
> + examples/gadget-ms.c                   | 1 +
> + examples/show-gadgets.c                | 1 +
> + examples/show-udcs.c                   | 1 +
> + include/usbg/usbg_internal_libconfig.h | 1 +
> + 6 files changed, 6 insertions(+)
> +
> +diff --git a/examples/gadget-acm-ecm.c b/examples/gadget-acm-ecm.c
> +index 1c5e2ca5161c..29360da15811 100644
> +--- a/examples/gadget-acm-ecm.c
> ++++ b/examples/gadget-acm-ecm.c
> +@@ -20,6 +20,7 @@
> + 
> + #include <errno.h>
> + #include <stdio.h>
> ++#include <sys/sysmacros.h>
> + #include <linux/usb/ch9.h>
> + #include <usbg/usbg.h>
> + 
> +diff --git a/examples/gadget-import.c b/examples/gadget-import.c
> +index e684fdb861e8..63df4499926b 100644
> +--- a/examples/gadget-import.c
> ++++ b/examples/gadget-import.c
> +@@ -25,6 +25,7 @@
> + #include <errno.h>
> + #include <string.h>
> + #include <stdio.h>
> ++#include <sys/sysmacros.h>
> + #include <usbg/usbg.h>
> + 
> + int main(int argc, char **argv)
> +diff --git a/examples/gadget-ms.c b/examples/gadget-ms.c
> +index 478c37097397..a5c668187a96 100644
> +--- a/examples/gadget-ms.c
> ++++ b/examples/gadget-ms.c
> +@@ -23,6 +23,7 @@
> + 
> + #include <errno.h>
> + #include <stdio.h>
> ++#include <sys/sysmacros.h>
> + #include <linux/usb/ch9.h>
> + #include <usbg/usbg.h>
> + #include <usbg/function/ms.h>
> +diff --git a/examples/show-gadgets.c b/examples/show-gadgets.c
> +index 707d4488d16b..a2a21c883b27 100644
> +--- a/examples/show-gadgets.c
> ++++ b/examples/show-gadgets.c
> +@@ -21,6 +21,7 @@
> + #include <errno.h>
> + #include <stdio.h>
> + #include <string.h>
> ++#include <sys/sysmacros.h>
> + #include <netinet/ether.h>
> + #include <usbg/usbg.h>
> + #include <usbg/function/ms.h>
> +diff --git a/examples/show-udcs.c b/examples/show-udcs.c
> +index 66e950f7bf85..2f5cc458ebb1 100644
> +--- a/examples/show-udcs.c
> ++++ b/examples/show-udcs.c
> +@@ -23,6 +23,7 @@
> + 
> + #include <errno.h>
> + #include <stdio.h>
> ++#include <sys/sysmacros.h>
> + #include <usbg/usbg.h>
> + 
> + int main(void)
> +diff --git a/include/usbg/usbg_internal_libconfig.h b/include/usbg/usbg_internal_libconfig.h
> +index ac51758b3d6c..3fa55c0b544b 100644
> +--- a/include/usbg/usbg_internal_libconfig.h
> ++++ b/include/usbg/usbg_internal_libconfig.h
> +@@ -12,6 +12,7 @@
> + #ifndef USBG_INTERNAL_LIBCONFIG_H
> + #define USBG_INTERNAL_LIBCONFIG_H
> + 
> ++#include <sys/sysmacros.h>
> + #include <libconfig.h>
> + #ifdef __cplusplus
> + extern "C" {
> diff --git a/patches/libusbgx-0.2.0/0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch b/patches/libusbgx-0.2.0/0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch
> new file mode 100644
> index 000000000000..63ddf347f733
> --- /dev/null
> +++ b/patches/libusbgx-0.2.0/0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch
> @@ -0,0 +1,67 @@
> +From: Michael Grzeschik <m.grzeschik@pengutronix.de>
> +Date: Wed, 28 Apr 2021 21:43:07 +0200
> +Subject: [PATCH] examples: gadget-vid-pid-remove: add dynamic vid pid support
> +
> +Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> +---
> + examples/gadget-vid-pid-remove.c | 25 ++++++++++++++++++++-----
> + 1 file changed, 20 insertions(+), 5 deletions(-)
> +
> +diff --git a/examples/gadget-vid-pid-remove.c b/examples/gadget-vid-pid-remove.c
> +index f6b950b38da3..f5eb9664b721 100644
> +--- a/examples/gadget-vid-pid-remove.c
> ++++ b/examples/gadget-vid-pid-remove.c
> +@@ -23,11 +23,10 @@
> + 
> + #include <errno.h>
> + #include <stdio.h>
> ++#include <string.h>
> ++#include <stdlib.h>
> + #include <usbg/usbg.h>
> + 
> +-#define VENDOR		0x1d6b
> +-#define PRODUCT		0x0104
> +-
> + int remove_gadget(usbg_gadget *g)
> + {
> + 	int usbg_ret;
> +@@ -60,13 +59,29 @@ out:
> + 	return usbg_ret;
> + }
> + 
> +-int main(void)
> ++int main(int argc, char **argv)
> + {
> + 	int usbg_ret;
> + 	int ret = -EINVAL;
> + 	usbg_state *s;
> + 	usbg_gadget *g;
> + 	struct usbg_gadget_attrs g_attrs;
> ++	char *cp;
> ++	int vendor = 0x1d6b, product = 0x0104;
> ++
> ++	if (argc >= 2) {
> ++		cp = strchr(argv[1], ':');
> ++		if (!cp) {
> ++			ret = -EINVAL;
> ++			fprintf(stderr, "Usage: gadget-vid-pid-remove vid:pid\n");
> ++			goto out1;
> ++		}
> ++		*cp++ = 0;
> ++		if (&argv[1])
> ++			vendor = strtoul(argv[1], NULL, 16);
> ++		if (*cp)
> ++			product = strtoul(cp, NULL, 16);
> ++	}
> + 
> + 	usbg_ret = usbg_init("/sys/kernel/config", &s);
> + 	if (usbg_ret != USBG_SUCCESS) {
> +@@ -88,7 +103,7 @@ int main(void)
> + 		}
> + 
> + 		/* Compare attrs with given values and remove if suitable */
> +-		if (g_attrs.idVendor == VENDOR && g_attrs.idProduct == PRODUCT) {
> ++		if (g_attrs.idVendor == vendor && g_attrs.idProduct == product) {
> + 			usbg_gadget *g_next = usbg_get_next_gadget(g);
> + 
> + 			usbg_ret = remove_gadget(g);
> diff --git a/patches/libusbgx-0.2.0/0004-libusbgx-Add-UVC-support.patch b/patches/libusbgx-0.2.0/0004-libusbgx-Add-UVC-support.patch
> new file mode 100644
> index 000000000000..0217bb02d0ae
> --- /dev/null
> +++ b/patches/libusbgx-0.2.0/0004-libusbgx-Add-UVC-support.patch
> @@ -0,0 +1,737 @@
> +From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
> +Date: Wed, 8 Jan 2020 14:43:45 +0100
> +Subject: [PATCH] libusbgx: Add UVC support
> +
> +Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
> +Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> +
> +Notes:
> +v2 -> v3: - simplified exit paths of functions with reutrns instead of gotos
> +          - added cleanup code for remove
> +	  - added gadget-uvc example file
> +	  - simplified class link creation
> +	  - added support for more than one format
> +---
> + Makefile.am                 |   2 +-
> + examples/Makefile.am        |   3 +-
> + examples/gadget-uvc.c       | 156 ++++++++++++++++++
> + include/usbg/function/uvc.h |  90 +++++++++++
> + include/usbg/usbg.h         |   1 +
> + src/Makefile.am             |   2 +-
> + src/function/uvc.c          | 378 ++++++++++++++++++++++++++++++++++++++++++++
> + src/usbg.c                  |   2 +
> + 8 files changed, 631 insertions(+), 3 deletions(-)
> + create mode 100644 examples/gadget-uvc.c
> + create mode 100644 include/usbg/function/uvc.h
> + create mode 100644 src/function/uvc.c
> +
> +diff --git a/Makefile.am b/Makefile.am
> +index a3cc337c18da..b3cd097d9d32 100644
> +--- a/Makefile.am
> ++++ b/Makefile.am
> +@@ -14,6 +14,6 @@ EXTRA_DIST = doxygen.cfg
> + library_includedir=$(includedir)/usbg
> + library_include_HEADERS = include/usbg/usbg.h include/usbg/usbg_version.h
> + function_includedir=$(includedir)/usbg/function
> +-function_include_HEADERS = include/usbg/function/ffs.h include/usbg/function/loopback.h include/usbg/function/midi.h include/usbg/function/ms.h include/usbg/function/net.h include/usbg/function/phonet.h include/usbg/function/serial.h include/usbg/function/hid.h include/usbg/function/uac2.h
> ++function_include_HEADERS = include/usbg/function/ffs.h include/usbg/function/loopback.h include/usbg/function/midi.h include/usbg/function/ms.h include/usbg/function/net.h include/usbg/function/phonet.h include/usbg/function/serial.h include/usbg/function/hid.h include/usbg/function/uac2.h include/usbg/function/uvc.h
> + pkgconfigdir = $(libdir)/pkgconfig
> + pkgconfig_DATA = libusbgx.pc
> +diff --git a/examples/Makefile.am b/examples/Makefile.am
> +index 993432156d6c..3217eb3bfd6f 100644
> +--- a/examples/Makefile.am
> ++++ b/examples/Makefile.am
> +@@ -1,5 +1,6 @@
> +-bin_PROGRAMS = show-gadgets gadget-acm-ecm gadget-vid-pid-remove gadget-ffs gadget-export gadget-import show-udcs gadget-ms gadget-midi gadget-hid gadget-rndis-os-desc gadget-uac2
> ++bin_PROGRAMS = show-gadgets gadget-acm-ecm gadget-vid-pid-remove gadget-uvc gadget-ffs gadget-export gadget-import show-udcs gadget-ms gadget-midi gadget-hid gadget-rndis-os-desc gadget-uac2
> + gadget_acm_ecm_SOURCES = gadget-acm-ecm.c
> ++gadget_uvc_SOURCES = gadget-uvc.c
> + show_gadgets_SOURCES = show-gadgets.c
> + gadget_vid_pid_remove_SOURCES = gadget-vid-pid-remove.c
> + gadget_ffs_SOURCES = gadget-ffs.c
> +diff --git a/examples/gadget-uvc.c b/examples/gadget-uvc.c
> +new file mode 100644
> +index 000000000000..d3efe2deaebe
> +--- /dev/null
> ++++ b/examples/gadget-uvc.c
> +@@ -0,0 +1,156 @@
> ++/*
> ++ * Copyright (C) 2021 Pengutronix
> ++ *
> ++ * Michael Grzeschik <mgr@pengutronix.de>
> ++ *
> ++ * This program is free software; you can redistribute it and/or modify
> ++ * it under the terms of the GNU General Public License as published by
> ++ * the Free Software Foundation; either version 2 of the License, or
> ++ * (at your option) any later version.
> ++ *
> ++ * This program is distributed in the hope that it will be useful,
> ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> ++ * GNU General Public License for more details.
> ++ */
> ++
> ++#include <errno.h>
> ++#include <stdio.h>
> ++#include <sys/sysmacros.h>
> ++#include <linux/usb/ch9.h>
> ++#include <usbg/usbg.h>
> ++#include <usbg/function/uvc.h>
> ++
> ++/**
> ++ * @file gadget-uvc.c
> ++ * @example gadget-uvc.c
> ++ * This is an example of how to create an UVC gadget device.
> ++ */
> ++
> ++#define VENDOR		0x1d6b
> ++#define PRODUCT		0x0104
> ++
> ++int main(void)
> ++{
> ++	usbg_state *s;
> ++	usbg_gadget *g;
> ++	usbg_config *c;
> ++	usbg_function *f_uvc;
> ++	int ret = -EINVAL;
> ++	int usbg_ret;
> ++
> ++	struct usbg_gadget_attrs g_attrs = {
> ++		.bcdUSB = 0x0200,
> ++		.bDeviceClass =	USB_CLASS_PER_INTERFACE,
> ++		.bDeviceSubClass = 0x00,
> ++		.bDeviceProtocol = 0x00,
> ++		.bMaxPacketSize0 = 64, /* Max allowed ep0 packet size */
> ++		.idVendor = VENDOR,
> ++		.idProduct = PRODUCT,
> ++		.bcdDevice = 0x0001, /* Verson of device */
> ++	};
> ++
> ++	struct usbg_gadget_strs g_strs = {
> ++		.serial = "0123456789", /* Serial number */
> ++		.manufacturer = "Foo Inc.", /* Manufacturer */
> ++		.product = "Bar Gadget" /* Product string */
> ++	};
> ++
> ++	struct usbg_config_strs c_strs = {
> ++		.configuration = "UVC"
> ++	};
> ++
> ++	struct usbg_f_uvc_format_attrs uvc_format_attrs_array[] = {
> ++		{
> ++			.format = UVC_FORMAT_MJPEG,
> ++			.dwFrameInterval = "333333",
> ++			.height = 1080,
> ++			.width = 1920,
> ++		}, {
> ++			.format = UVC_FORMAT_MJPEG,
> ++			.dwFrameInterval = "333333",
> ++			.height = 3940,
> ++			.width = 2160,
> ++		}, {
> ++			.format = UVC_FORMAT_UNCOMPRESSED,
> ++			.dwFrameInterval = "333333",
> ++			.height = 1080,
> ++			.width = 1920,
> ++		}, {
> ++			.format = UVC_FORMAT_UNCOMPRESSED,
> ++			.dwFrameInterval = "333333",
> ++			.height = 3940,
> ++			.width = 2160,
> ++		}
> ++	};
> ++
> ++	struct usbg_f_uvc_format_attrs *uvc_format_attrs[] = {
> ++		&uvc_format_attrs_array[3],
> ++		&uvc_format_attrs_array[2],
> ++		&uvc_format_attrs_array[1],
> ++		&uvc_format_attrs_array[0],
> ++		NULL,
> ++	};
> ++
> ++	struct usbg_f_uvc_attrs uvc_attrs = {
> ++		.formats = uvc_format_attrs,
> ++	};
> ++
> ++	usbg_ret = usbg_init("/sys/kernel/config", &s);
> ++	if (usbg_ret != USBG_SUCCESS) {
> ++		fprintf(stderr, "Error on USB gadget init\n");
> ++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
> ++				usbg_strerror(usbg_ret));
> ++		goto out1;
> ++	}
> ++
> ++	usbg_ret = usbg_create_gadget(s, "g1", &g_attrs, &g_strs, &g);
> ++	if (usbg_ret != USBG_SUCCESS) {
> ++		fprintf(stderr, "Error on create gadget\n");
> ++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
> ++				usbg_strerror(usbg_ret));
> ++		goto out2;
> ++	}
> ++
> ++        usbg_ret = usbg_create_function(g, USBG_F_UVC, "uvc", &uvc_attrs, &f_uvc);
> ++        if(usbg_ret != USBG_SUCCESS)
> ++        {
> ++		fprintf(stderr, "Error creating uvc function\n");
> ++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
> ++				usbg_strerror(usbg_ret));
> ++		goto out2;
> ++	}
> ++
> ++	/* NULL can be passed to use kernel defaults */
> ++	usbg_ret = usbg_create_config(g, 1, "The only one", NULL, &c_strs, &c);
> ++	if (usbg_ret != USBG_SUCCESS) {
> ++		fprintf(stderr, "Error creating config\n");
> ++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
> ++				usbg_strerror(usbg_ret));
> ++		goto out2;
> ++	}
> ++
> ++        usbg_ret = usbg_add_config_function(c, "uvc.cam", f_uvc);
> ++	if (usbg_ret != USBG_SUCCESS) {
> ++		fprintf(stderr, "Error adding acm.GS0\n");
> ++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
> ++				usbg_strerror(usbg_ret));
> ++		goto out2;
> ++	}
> ++
> ++	usbg_ret = usbg_enable_gadget(g, DEFAULT_UDC);
> ++	if (usbg_ret != USBG_SUCCESS) {
> ++		fprintf(stderr, "Error enabling gadget\n");
> ++		fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
> ++				usbg_strerror(usbg_ret));
> ++		goto out2;
> ++	}
> ++
> ++	ret = 0;
> ++
> ++out2:
> ++	usbg_cleanup(s);
> ++
> ++out1:
> ++	return ret;
> ++}
> +diff --git a/include/usbg/function/uvc.h b/include/usbg/function/uvc.h
> +new file mode 100644
> +index 000000000000..4c641dacdfcb
> +--- /dev/null
> ++++ b/include/usbg/function/uvc.h
> +@@ -0,0 +1,90 @@
> ++/*
> ++ * This library is free software; you can redistribute it and/or
> ++ * modify it under the terms of the GNU Lesser General Public
> ++ * License as published by the Free Software Foundation; either
> ++ * version 2.1 of the License, or (at your option) any later version.
> ++ *
> ++ * This library is distributed in the hope that it will be useful,
> ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> ++ * Lesser General Public License for more details.
> ++ */
> ++
> ++#ifndef USBG_FUNCTION_UVC__
> ++#define USBG_FUNCTION_UVC__
> ++
> ++#include <usbg/usbg.h>
> ++
> ++#ifdef __cplusplus
> ++extern "C" {
> ++#endif
> ++
> ++
> ++#define USBG_UVC_MAX_PATH_LENGTH 1024
> ++
> ++struct usbg_f_uvc;
> ++typedef struct usbg_f_uvc usbg_f_uvc;
> ++
> ++enum uvc_format
> ++{
> ++	UVC_FORMAT_MJPEG,
> ++	UVC_FORMAT_UNCOMPRESSED
> ++};
> ++
> ++struct usbg_f_uvc_format_attrs
> ++{
> ++	enum uvc_format format;
> ++	const char *dwFrameInterval;
> ++	int height;
> ++	int width;
> ++};
> ++
> ++struct usbg_f_uvc_attrs
> ++{
> ++	struct usbg_f_uvc_format_attrs **formats;
> ++};
> ++
> ++/**
> ++ * @brief Cast from generic function to uvc function
> ++ * @param[in] f function to be converted to uvc funciton.
> ++ *         Should be one of types:
> ++ *         ecm, subset, ncm, eem, rndis
> ++ * @return Converted uvc function or NULL if function hasn't suitable type
> ++ */
> ++usbg_f_uvc *usbg_to_uvc_function(usbg_function *f);
> ++
> ++/**
> ++ * @brief Cast form uvc function to generic one
> ++ * @param[in] uvc function to be converted to generic one
> ++ * @return Generic usbg function
> ++ */
> ++usbg_function *usbg_from_uvc_function(usbg_f_uvc *ff);
> ++
> ++/**
> ++ * @brief Cleanup attributes structure after usage
> ++ * @param[in] attrs to be cleaned up
> ++ */
> ++static inline void usbg_f_uvc_cleanup_attrs(struct usbg_f_uvc_attrs *attrs)
> ++{
> ++	struct usbg_f_uvc_format_attrs **format_attrs;
> ++	int i;
> ++
> ++	if (attrs) {
> ++		for(format_attrs = attrs->formats, i = 0; format_attrs[i]; ++i) {
> ++			if (format_attrs[i]) {
> ++				free((char *)format_attrs[i]->dwFrameInterval);
> ++				format_attrs[i]->dwFrameInterval = NULL;
> ++			}
> ++		}
> ++	}
> ++}
> ++
> ++int usbg_f_uvc_get_attrs(usbg_f_uvc *uvcf, struct usbg_f_uvc_attrs *attrs);
> ++int usbg_f_uvc_set_attrs(usbg_f_uvc *uvcf, const struct usbg_f_uvc_attrs *attrs);
> ++
> ++
> ++#ifdef __cplusplus
> ++}
> ++#endif
> ++
> ++#endif /* USBG_FUNCTION_UVC__ */
> +diff --git a/include/usbg/usbg.h b/include/usbg/usbg.h
> +index 55c52a1c3768..de72793ddcf0 100644
> +--- a/include/usbg/usbg.h
> ++++ b/include/usbg/usbg.h
> +@@ -219,6 +219,7 @@ typedef enum
> + 	USBG_F_LOOPBACK,
> + 	USBG_F_HID,
> + 	USBG_F_UAC2,
> ++	USBG_F_UVC,
> + 	USBG_FUNCTION_TYPE_MAX,
> + } usbg_function_type;
> + 
> +diff --git a/src/Makefile.am b/src/Makefile.am
> +index 6b2726ec5219..c51878fac2ff 100644
> +--- a/src/Makefile.am
> ++++ b/src/Makefile.am
> +@@ -1,6 +1,6 @@
> + AUTOMAKE_OPTIONS = std-options subdir-objects
> + lib_LTLIBRARIES = libusbgx.la
> +-libusbgx_la_SOURCES = usbg.c usbg_error.c usbg_common.c function/ether.c function/ffs.c function/midi.c function/ms.c function/phonet.c function/serial.c function/loopback.c function/hid.c function/uac2.c
> ++libusbgx_la_SOURCES = usbg.c usbg_error.c usbg_common.c function/ether.c function/ffs.c function/midi.c function/ms.c function/phonet.c function/serial.c function/loopback.c function/hid.c function/uac2.c function/uvc.c
> + if TEST_GADGET_SCHEMES
> + libusbgx_la_SOURCES += usbg_schemes_libconfig.c usbg_common_libconfig.c
> + else
> +diff --git a/src/function/uvc.c b/src/function/uvc.c
> +new file mode 100644
> +index 000000000000..92d738c5763c
> +--- /dev/null
> ++++ b/src/function/uvc.c
> +@@ -0,0 +1,378 @@
> ++/*
> ++ * This library is free software; you can redistribute it and/or
> ++ * modify it under the terms of the GNU Lesser General Public
> ++ * License as published by the Free Software Foundation; either
> ++ * version 2.1 of the License, or (at your option) any later version.
> ++ *
> ++ * This library is distributed in the hope that it will be useful,
> ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> ++ * Lesser General Public License for more details.
> ++ */
> ++
> ++#include "usbg/usbg.h"
> ++#include "usbg/usbg_internal.h"
> ++#include "usbg/function/uvc.h"
> ++
> ++#include <errno.h>
> ++#include <sys/stat.h>
> ++#include <unistd.h>
> ++#include <malloc.h>
> ++#include <ftw.h>
> ++#ifdef HAS_GADGET_SCHEMES
> ++#include <libconfig.h>
> ++#endif
> ++
> ++#define UVC_PATH_CONTROL		"control"
> ++#define UVC_PATH_HEADER			"header/h"
> ++#define UVC_PATH_CLASS_FS		"class/fs/h"
> ++#define UVC_PATH_CLASS_HS		"class/hs/h"
> ++#define UVC_PATH_CLASS_SS		"class/ss/h"
> ++#define UVC_PATH_STREAMING		"streaming"
> ++#define UVC_PATH_STREAMING_UNCOMPRESSED	"uncompressed/u"
> ++#define UVC_PATH_STREAMING_MJPEG	"mjpeg/m"
> ++
> ++struct usbg_f_uvc
> ++{
> ++	struct usbg_function func;
> ++};
> ++
> ++GENERIC_ALLOC_INST(uvc, struct usbg_f_uvc, func);
> ++
> ++GENERIC_FREE_INST(uvc, struct usbg_f_uvc, func);
> ++
> ++static int uvc_set_attrs(struct usbg_function *f, void *f_attrs)
> ++{
> ++	return usbg_f_uvc_set_attrs(usbg_to_uvc_function(f), f_attrs);
> ++}
> ++
> ++static int uvc_get_attrs(struct usbg_function *f, void *f_attrs)
> ++{
> ++	return usbg_f_uvc_get_attrs(usbg_to_uvc_function(f), f_attrs);
> ++}
> ++
> ++static void uvc_cleanup_attrs(struct usbg_function *f, void *f_attrs)
> ++{
> ++	return usbg_f_uvc_cleanup_attrs(f_attrs);
> ++}
> ++
> ++static int uvc_libconfig_import(struct usbg_function *f, config_setting_t *root)
> ++{
> ++	return USBG_SUCCESS;
> ++}
> ++
> ++static int uvc_libconfig_export(struct usbg_function *f, config_setting_t *root)
> ++{
> ++	return USBG_SUCCESS;
> ++}
> ++
> ++static int uvc_create_dir(const char *path)
> ++{
> ++	char tmp[USBG_MAX_PATH_LENGTH];
> ++	char *p = NULL;
> ++	size_t len;
> ++	int nmb, ret = USBG_SUCCESS;
> ++
> ++	nmb = snprintf(tmp, sizeof(tmp), "%s", path);
> ++	if(nmb >= sizeof(tmp))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	len = strlen(tmp);
> ++	if(tmp[len - 1] == '/')
> ++		tmp[len - 1] = 0;
> ++
> ++	for (p = tmp + 1; *p; p++) {
> ++		if(*p == '/') {
> ++			*p = 0;
> ++			if((mkdir(tmp, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && errno != EEXIST) {
> ++				ret = usbg_translate_error(errno);
> ++				break;
> ++			}
> ++			*p = '/';
> ++		}
> ++	}
> ++	if(ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	if((mkdir(tmp, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && errno != EEXIST)
> ++		return usbg_translate_error(errno);
> ++}
> ++
> ++static int uvc_link(char *path, char *to, char *from)
> ++{
> ++	char oldname[USBG_MAX_PATH_LENGTH];
> ++	char newname[USBG_MAX_PATH_LENGTH];
> ++	int nmb;
> ++
> ++	nmb = snprintf(oldname, sizeof(oldname), "%s/%s", path, to);
> ++	if (nmb >= sizeof(oldname))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	nmb = snprintf(newname, sizeof(newname), "%s/%s", path, from);
> ++	if (nmb >= sizeof(newname))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	if(symlink(oldname, newname))
> ++		return usbg_translate_error(errno);
> ++}
> ++
> ++static int uvc_set_class(char *func_path, char *cs)
> ++{
> ++	int ret, nmb;
> ++	char path[USBG_MAX_PATH_LENGTH];
> ++	char header_path[USBG_MAX_PATH_LENGTH];
> ++
> ++	nmb = snprintf(path, sizeof(path), "%s/%s", func_path, cs);
> ++	if (nmb >= sizeof(path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	nmb = snprintf(header_path, sizeof(header_path), "%s/" UVC_PATH_HEADER, path);
> ++	if (nmb >= sizeof(header_path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	ret = uvc_create_dir(header_path);
> ++	if (ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	if (!strncmp(cs, UVC_PATH_STREAMING, strlen(UVC_PATH_STREAMING))) {
> ++		char check_path[USBG_MAX_PATH_LENGTH];
> ++		struct stat buffer;
> ++
> ++		nmb = snprintf(check_path, sizeof(check_path), "%s/" UVC_PATH_STREAMING_UNCOMPRESSED, path);
> ++		if (nmb >= sizeof(check_path))
> ++			return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++		ret = stat(check_path, &buffer);
> ++		if (!ret) {
> ++			ret = uvc_link(path, UVC_PATH_STREAMING_UNCOMPRESSED, "header/h/u");
> ++			if (ret != USBG_SUCCESS)
> ++				return ret;
> ++		}
> ++
> ++		nmb = snprintf(check_path, sizeof(check_path), "%s/" UVC_PATH_STREAMING_MJPEG, path);
> ++		if (nmb >= sizeof(check_path))
> ++			return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++		ret = stat(check_path, &buffer);
> ++		if (!ret) {
> ++			ret = uvc_link(path, UVC_PATH_STREAMING_MJPEG, "header/h/m");
> ++			if (ret != USBG_SUCCESS)
> ++				return ret;
> ++		}
> ++
> ++		ret = uvc_link(path, UVC_PATH_HEADER, UVC_PATH_CLASS_HS);
> ++		if (ret)
> ++			return ret;
> ++	}
> ++
> ++	ret = uvc_link(path, UVC_PATH_HEADER, UVC_PATH_CLASS_FS);
> ++	if (ret)
> ++		return ret;
> ++
> ++	return uvc_link(path, UVC_PATH_HEADER, UVC_PATH_CLASS_SS);
> ++}
> ++
> ++static int uvc_set_frame(char *format_path, char *format, const struct usbg_f_uvc_format_attrs *attrs)
> ++{
> ++	int nmb, ret, i;
> ++	char frame_path[USBG_MAX_PATH_LENGTH];
> ++	char full_frame_path[USBG_MAX_PATH_LENGTH];
> ++	char frame_interval[USBG_MAX_PATH_LENGTH];
> ++	char frame_name[32];
> ++
> ++	nmb = snprintf(frame_name, sizeof(frame_name), "%dp", attrs->height);
> ++	if (nmb >= sizeof(frame_name))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	nmb = snprintf(frame_path, sizeof(frame_path), "%s/%s", format_path, format);
> ++	if (nmb >= sizeof(frame_path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	nmb = snprintf(full_frame_path, sizeof(frame_path), "%s/%s", frame_path, frame_name);
> ++	if (nmb >= sizeof(full_frame_path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	ret = uvc_create_dir(full_frame_path);
> ++	if (ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	ret = usbg_write_string(frame_path, frame_name, "dwFrameInterval", attrs->dwFrameInterval);
> ++	if (ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	ret = usbg_write_dec(frame_path, frame_name, "wHeight", attrs->height);
> ++	if (ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	return usbg_write_dec(frame_path, frame_name, "wWidth", attrs->width);
> ++}
> ++
> ++static int uvc_set_streaming(char *func_path, const struct usbg_f_uvc_format_attrs *attrs)
> ++{
> ++	char streaming_path[USBG_MAX_PATH_LENGTH];
> ++	int ret, nmb;
> ++
> ++	nmb = snprintf(streaming_path, sizeof(streaming_path), "%s/" UVC_PATH_STREAMING, func_path);
> ++	if (nmb >= sizeof(streaming_path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	if (attrs->format == UVC_FORMAT_UNCOMPRESSED)
> ++		ret = uvc_set_frame(streaming_path, UVC_PATH_STREAMING_UNCOMPRESSED, attrs);
> ++	else
> ++		ret = uvc_set_frame(streaming_path, UVC_PATH_STREAMING_MJPEG, attrs);
> ++
> ++	return ret;
> ++}
> ++
> ++static int dir_nftw_cb(const char *pathname, const struct stat *sbuf, int type, struct FTW *ftwb)
> ++{
> ++	(void) sbuf;
> ++	(void) type;
> ++	(void) ftwb;
> ++	int ret;
> ++
> ++	ret = remove(pathname);
> ++	if (ret < -1)
> ++		ERROR("failed to remove %s - %s", pathname, strerror(ret));
> ++
> ++	return 0;
> ++}
> ++
> ++int remove_dir(const char *dirpath)
> ++{
> ++	const int max_open_descs = 8;
> ++	int ret;
> ++
> ++	ret = nftw(dirpath, dir_nftw_cb, max_open_descs, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
> ++	if (ret < 0) {
> ++		ERROR("nftw failed");
> ++		return ret;
> ++	}
> ++
> ++	return 0;
> ++}
> ++
> ++static int content_nftw_cb(const char *pathname, const struct stat *sbuf, int type, struct FTW *ftwb)
> ++{
> ++	(void) sbuf;
> ++	(void) type;
> ++	(void) ftwb;
> ++	int ret;
> ++
> ++	if(ftwb->level == 0)
> ++		return 0;
> ++
> ++	ret = remove(pathname);
> ++	if(ret < -1)
> ++		ERROR("failed to remove %s - %s", pathname, strerror(ret));
> ++
> ++	return 0;
> ++}
> ++
> ++int remove_dir_content(const char *dirpath)
> ++{
> ++	const int max_open_descs = 8;
> ++	int ret;
> ++
> ++	/* traverse in reverse order (handle directory after it's content), stay within the same file system and do not follow symbolic links */
> ++	ret = nftw(dirpath, content_nftw_cb, max_open_descs, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
> ++	if (ret < 0) {
> ++		ERROR("nftw failed");
> ++		return ret;
> ++	}
> ++
> ++	return 0;
> ++}
> ++
> ++static int uvc_remove(struct usbg_function *f, int opts)
> ++{
> ++	usbg_f_uvc *uvcf = usbg_to_uvc_function(f);
> ++	char streaming_path[USBG_MAX_PATH_LENGTH];
> ++	char control_path[USBG_MAX_PATH_LENGTH];
> ++	char path[USBG_UVC_MAX_PATH_LENGTH];
> ++	int nmb, ret = USBG_SUCCESS;
> ++
> ++	nmb = snprintf(path, sizeof(path), "%s/%s", uvcf->func.path, uvcf->func.name);
> ++	if (nmb >= sizeof(path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	nmb = snprintf(streaming_path, sizeof(streaming_path), "%s/streaming", path);
> ++	if (nmb >= sizeof(streaming_path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	nmb = snprintf(control_path, sizeof(control_path), "%s/control", path);
> ++	if (nmb >= sizeof(control_path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	if(remove_dir_content(streaming_path) < 0)
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	if(remove_dir_content(control_path) < 0)
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	if(remove_dir(streaming_path) < 0)
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	if(remove_dir(control_path) < 0)
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	return 0;
> ++};
> ++
> ++struct usbg_function_type usbg_f_type_uvc = {
> ++	.name = "uvc",
> ++	.alloc_inst = uvc_alloc_inst,
> ++	.free_inst = uvc_free_inst,
> ++	.set_attrs = uvc_set_attrs,
> ++	.get_attrs = uvc_get_attrs,
> ++	.cleanup_attrs = uvc_cleanup_attrs,
> ++	.import = uvc_libconfig_import,
> ++	.export = uvc_libconfig_export,
> ++	.remove = uvc_remove,
> ++};
> ++
> ++/* API implementation */
> ++
> ++usbg_f_uvc *usbg_to_uvc_function(usbg_function *f)
> ++{
> ++	return f->ops == &usbg_f_type_uvc ?
> ++			container_of(f, struct usbg_f_uvc, func) : NULL;
> ++}
> ++
> ++usbg_function *usbg_from_uvc_function(usbg_f_uvc *ff)
> ++{
> ++	return &ff->func;
> ++}
> ++
> ++int usbg_f_uvc_get_attrs(usbg_f_uvc *uvcf, struct usbg_f_uvc_attrs *attrs)
> ++{
> ++	return USBG_SUCCESS;
> ++}
> ++
> ++int usbg_f_uvc_set_attrs(usbg_f_uvc *uvcf, const struct usbg_f_uvc_attrs *attrs)
> ++{
> ++	int nmb, ret = USBG_SUCCESS;
> ++	char path[USBG_UVC_MAX_PATH_LENGTH];
> ++	struct usbg_f_uvc_format_attrs **format_attrs;
> ++	int i;
> ++
> ++	nmb = snprintf(path, sizeof(path), "%s/%s", uvcf->func.path, uvcf->func.name);
> ++	if (nmb >= sizeof(path))
> ++		return USBG_ERROR_PATH_TOO_LONG;
> ++
> ++	for(format_attrs = attrs->formats, i = 0; format_attrs[i]; ++i) {
> ++		ret = uvc_set_streaming(path, format_attrs[i]);
> ++		if(ret != USBG_SUCCESS)
> ++			ERROR("Error: %d", ret);
> ++	}
> ++
> ++	ret = uvc_set_class(path, "control");
> ++	if (ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	ret = uvc_set_class(path, "streaming");
> ++	if (ret != USBG_SUCCESS)
> ++		return ret;
> ++
> ++	return ret;
> ++}
> +diff --git a/src/usbg.c b/src/usbg.c
> +index d2bf38160358..b298ddc50ecf 100644
> +--- a/src/usbg.c
> ++++ b/src/usbg.c
> +@@ -52,6 +52,7 @@ extern struct usbg_function_type usbg_f_type_phonet;
> + extern struct usbg_function_type usbg_f_type_loopback;
> + extern struct usbg_function_type usbg_f_type_hid;
> + extern struct usbg_function_type usbg_f_type_uac2;
> ++extern struct usbg_function_type usbg_f_type_uvc;
> + 
> + /**
> +  * @var function_types
> +@@ -73,6 +74,7 @@ struct usbg_function_type* function_types[] = {
> + 	[USBG_F_LOOPBACK] = &usbg_f_type_loopback,
> + 	[USBG_F_HID] = &usbg_f_type_hid,
> + 	[USBG_F_UAC2] = &usbg_f_type_uac2,
> ++	[USBG_F_UVC] = &usbg_f_type_uvc,
> + };
> + 
> + ARRAY_SIZE_SENTINEL(function_types, USBG_FUNCTION_TYPE_MAX);
> diff --git a/patches/libusbgx-0.2.0/autogen.sh b/patches/libusbgx-0.2.0/autogen.sh
> new file mode 100755
> index 000000000000..2459647bfd3f
> --- /dev/null
> +++ b/patches/libusbgx-0.2.0/autogen.sh
> @@ -0,0 +1,16 @@
> +#!/bin/bash
> +
> +set -e
> +
> +aclocal $ACLOCAL_FLAGS
> +
> +libtoolize \
> +	--force \
> +	--copy
> +
> +autoreconf \
> +	--force \
> +	--install \
> +	--warnings=syntax \
> +	--warnings=obsolete \
> +	--warnings=unsupported
> diff --git a/patches/libusbgx-0.2.0/series b/patches/libusbgx-0.2.0/series
> new file mode 100644
> index 000000000000..406d15accf05
> --- /dev/null
> +++ b/patches/libusbgx-0.2.0/series
> @@ -0,0 +1,7 @@
> +# generated by git-ptx-patches
> +#tag:base --start-number 1
> +0001-Fix-39-Compilation-fails-on-gcc-v8.patch
> +0002-libusbgx-fix-build-with-glibc-2.28-since-sys-sysmacr.patch
> +0003-examples-gadget-vid-pid-remove-add-dynamic-vid-pid-s.patch
> +0004-libusbgx-Add-UVC-support.patch
> +# 55b4c63ca7f6b97ceb9cd9588e1eacdd  - git-ptx-patches magic
> diff --git a/rules/libusbgx.in b/rules/libusbgx.in
> new file mode 100644
> index 000000000000..98776c02660e
> --- /dev/null
> +++ b/rules/libusbgx.in
> @@ -0,0 +1,8 @@
> +## SECTION=communication
> +
> +config LIBUSBGX
> +	bool
> +	prompt "libusbgx"
> +	help
> +	  libusbgx is a C library encapsulating the kernel USB gadget-configfs
> +	  userspace API functionality.
> diff --git a/rules/libusbgx.make b/rules/libusbgx.make
> new file mode 100644
> index 000000000000..6c8fce429c34
> --- /dev/null
> +++ b/rules/libusbgx.make
> @@ -0,0 +1,66 @@
> +# -*-makefile-*-
> +#
> +# Copyright (C) 2018 by Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
> +#
> +# See CREDITS for details about who has contributed to this project.
> +#
> +# For further information about the PTXdist project and license conditions
> +# see the README file.
> +#
> +
> +#
> +# We provide this package
> +#
> +PACKAGES-$(PTXCONF_LIBUSBGX) += libusbgx
> +
> +#
> +# Paths and names
> +#
> +LIBUSBGX_VERSION	:= 0.2.0
> +LIBUSBGX_MD5		:= a8ea2234c6355ac8ad2ca86c453297bd
> +LIBUSBGX		:= libusbgx-$(LIBUSBGX_VERSION)
> +LIBUSBGX_SUFFIX		:= zip
> +LIBUSBGX_URL		:= \
> +	https://github.com/libusbgx/libusbgx/archive/libusbgx-v$(LIBUSBGX_VERSION).zip
> +LIBUSBGX_SOURCE	:= \
> +	$(SRCDIR)/$(LIBUSBGX).$(LIBUSBGX_SUFFIX)
> +LIBUSBGX_DIR		:= $(BUILDDIR)/$(LIBUSBGX)
> +LIBUSBGX_LICENSE	:= GPLv2
> +
> +# ----------------------------------------------------------------------------
> +# Prepare
> +# ----------------------------------------------------------------------------
> +
> +LIBUSBGX_CONF_ENV	:= $(CROSS_ENV)
> +
> +#
> +# autoconf
> +#
> +LIBUSBGX_CONF_TOOL	:= autoconf
> +LIBUSBGX_CONF_OPT	:= \
> +	$(CROSS_AUTOCONF_USR) \
> +	--without-libconfig \
> +	--enable-examples \
> +	--disable-gadget-schemes
> +
> +# ----------------------------------------------------------------------------
> +# Target-Install
> +# ----------------------------------------------------------------------------
> +
> +$(STATEDIR)/libusbgx.targetinstall:
> +	@$(call targetinfo)
> +
> +	@$(call install_init, libusbgx)
> +	@$(call install_fixup, libusbgx, PRIORITY, optional)
> +	@$(call install_fixup, libusbgx, SECTION, base)
> +	@$(call install_fixup, libusbgx, AUTHOR, "Thomas Haemmerle <thomas.haemmerle@wolfvision.net>")
> +	@$(call install_fixup, libusbgx, DESCRIPTION, missing)
> +
> +	@$(call install_lib, libusbgx, 0, 0, 0644, libusbgx)
> +	@$(call install_tree, libusbgx, 0, 0, -, /usr/bin)
> +
> +	@$(call install_finish, libusbgx)
> +
> +	@$(call touch)
> +
> +# vim: syntax=make

_______________________________________________
ptxdist mailing list
ptxdist@pengutronix.de
To unsubscribe, send a mail with subject "unsubscribe" to ptxdist-request@pengutronix.de


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-05-07  6:08 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-28 23:24 [ptxdist] [PATCH] libusbgx: new package Michael Grzeschik
2021-04-29 11:29 ` Roland Hieber
2021-05-07  6:07 ` [ptxdist] [APPLIED] " Michael Olbrich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox