From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Thu, 29 Apr 2021 01:25:15 +0200 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by lore.white.stw.pengutronix.de with esmtp (Exim 4.92) (envelope-from ) id 1lbtYR-0000kZ-P1 for lore@lore.pengutronix.de; Thu, 29 Apr 2021 01:25:15 +0200 Received: from localhost ([127.0.0.1] helo=metis.ext.pengutronix.de) by metis.ext.pengutronix.de with esmtp (Exim 4.92) (envelope-from ) id 1lbtYR-0001nV-Gr; Thu, 29 Apr 2021 01:25:15 +0200 Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lbtXg-0001nO-KE for ptxdist@pengutronix.de; Thu, 29 Apr 2021 01:24:28 +0200 Received: from mgr by dude.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1lbtXg-0003xb-BJ for ptxdist@pengutronix.de; Thu, 29 Apr 2021 01:24:28 +0200 From: Michael Grzeschik To: ptxdist@pengutronix.de Date: Thu, 29 Apr 2021 01:24:10 +0200 Message-Id: <20210428232410.15059-1-m.grzeschik@pengutronix.de> X-Mailer: git-send-email 2.29.2 MIME-Version: 1.0 Subject: [ptxdist] [PATCH] libusbgx: new package X-BeenThere: ptxdist@pengutronix.de X-Mailman-Version: 2.1.29 Precedence: list List-Id: PTXdist Development Mailing List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: ptxdist@pengutronix.de Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "ptxdist" X-SA-Exim-Connect-IP: 127.0.0.1 X-SA-Exim-Mail-From: ptxdist-bounces@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false This patch adds libusbgx support to ptxdist. It includes patches to work with uvc gadgets. Signed-off-by: Michael Grzeschik --- 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 +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 + #include + #include ++#include + + 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 +Date: Mon, 10 Sep 2018 15:52:09 +0200 +Subject: [PATCH] libusbgx: fix build with glibc-2.28 since + is no more included by + +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 +--- + 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 + #include ++#include + #include + #include + +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 + #include + #include ++#include + #include + + 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 + #include ++#include + #include + #include + #include +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 + #include + #include ++#include + #include + #include + #include +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 + #include ++#include + #include + + 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 + #include + #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 +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 +--- + 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 + #include ++#include ++#include + #include + +-#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 +Date: Wed, 8 Jan 2020 14:43:45 +0100 +Subject: [PATCH] libusbgx: Add UVC support + +Signed-off-by: Thomas Haemmerle +Signed-off-by: Michael Grzeschik + +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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * @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 ++ ++#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 ++#include ++#include ++#include ++#include ++#ifdef HAS_GADGET_SCHEMES ++#include ++#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 +# +# 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 ") + @$(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