* [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