summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Keeping <john@metanate.com>2018-01-11 16:52:45 +0000
committerJohn Keeping <john@metanate.com>2018-01-17 14:38:58 +0000
commit5740ca8a5ea96316cc9363aed7d2fe8268201b15 (patch)
treea35e584eb82beafa4c03a0a413ac8a82c9be0bd2
parent1c3f1b4660ae2cc858f83806cf7d9d5543ff0298 (diff)
downloadlibusbg-5740ca8a5ea96316cc9363aed7d2fe8268201b15.tar.gz
libusbg-5740ca8a5ea96316cc9363aed7d2fe8268201b15.tar.bz2
libusbg-5740ca8a5ea96316cc9363aed7d2fe8268201b15.zip
libusbgx: Add support for UAC2 function
This is the USB Audio Class 2 function that creates an ALSA audio device exposed as a USB gadget function. Signed-off-by: John Keeping <john@metanate.com> [Set import/export callbacks to correct values, adjust convention of set_attr(), fix union cast in c++] Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com
-rw-r--r--Makefile.am2
-rw-r--r--include/usbg/function/uac2.h265
-rw-r--r--include/usbg/usbg.h1
-rw-r--r--src/Makefile.am2
-rw-r--r--src/function/uac2.c200
-rw-r--r--src/usbg.c2
6 files changed, 470 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am
index f382e6b..e88ada4 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
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
+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
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libusbgx.pc
diff --git a/include/usbg/function/uac2.h b/include/usbg/function/uac2.h
new file mode 100644
index 0000000..3fdd664
--- /dev/null
+++ b/include/usbg/function/uac2.h
@@ -0,0 +1,265 @@
+/*
+ * 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_UAC2__
+#define USBG_FUNCTION_UAC2__
+
+#include <usbg/usbg.h>
+
+#include <malloc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct usbg_f_uac2;
+typedef struct usbg_f_uac2 usbg_f_uac2;
+
+struct usbg_f_uac2_attrs {
+ int c_chmask;
+ int c_srate;
+ int c_ssize;
+ int p_chmask;
+ int p_srate;
+ int p_ssize;
+};
+
+enum usbg_f_uac2_attr {
+ USBG_F_UAC2_ATTR_MIN = 0,
+ USBG_F_UAC2_C_CHMASK = USBG_F_UAC2_ATTR_MIN,
+ USBG_F_UAC2_C_SRATE,
+ USBG_F_UAC2_C_SSIZE,
+ USBG_F_UAC2_P_CHMASK,
+ USBG_F_UAC2_P_SRATE,
+ USBG_F_UAC2_P_SSIZE,
+ USBG_F_UAC2_ATTR_MAX
+};
+
+union usbg_f_uac2_attr_val {
+ int c_chmask;
+ int c_srate;
+ int c_ssize;
+ int p_chmask;
+ int p_srate;
+ int p_ssize;
+};
+
+/**
+ * @brief Cast from generic function to uac2 function
+ * @param[in] f function to be converted to uac2 funciton.
+ * Function should be one of type uac2.
+ * @return Converted uac2 function or NULL if function hasn't suitable type
+ */
+usbg_f_uac2 *usbg_to_uac2_function(usbg_function *f);
+
+/**
+ * @brief Cast form uac2 function to generic one
+ * @param[in] af function to be converted to generic one
+ * @return Generic usbg function
+ */
+usbg_function *usbg_from_uac2_function(usbg_f_uac2 *af);
+
+/**
+ * @brief Get attributes of given uac2 function
+ * @param[in] af Pointer to uac2 function
+ * @param[out] attrs Structure to be filled with data
+ * @return 0 on success usbg_error if error occurred.
+ */
+int usbg_f_uac2_get_attrs(usbg_f_uac2 *af,
+ struct usbg_f_uac2_attrs *attrs);
+
+/**
+ * @brief Set attributes of given uac2 function
+ * @param[in] af Pointer to uac2 function
+ * @param[in] attrs to be set
+ * @return 0 on success usbg_error if error occurred.
+ */
+int usbg_f_uac2_set_attrs(usbg_f_uac2 *af,
+ const struct usbg_f_uac2_attrs *attrs);
+
+/**
+ * @brief Cleanup attributes structure after usage
+ * @param[in] attrs to be cleaned up
+ */
+static inline void usbg_f_uac2_cleanup_attrs(struct usbg_f_uac2_attrs *attrs)
+{
+}
+
+/**
+ * @brief Get the value of single attribute
+ * @param[in] af Pointer to uac2 function
+ * @param[in] attr Code of attribute which value should be taken
+ * @param[out] val Current value of this attribute
+ * @return 0 on success usbg_error if error occurred.
+ */
+int usbg_f_uac2_get_attr_val(usbg_f_uac2 *af, enum usbg_f_uac2_attr attr,
+ union usbg_f_uac2_attr_val *val);
+
+/**
+ * @brief Set the value of single attribute
+ * @param[in] af Pointer to uac2 function
+ * @param[in] attr Code of attribute which value should be set
+ * @param[in] val Value of attribute which should be set
+ * @return 0 on success usbg_error if error occurred.
+ */
+int usbg_f_uac2_set_attr_val(usbg_f_uac2 *af, enum usbg_f_uac2_attr attr,
+ union usbg_f_uac2_attr_val val);
+
+/**
+ * @brief Get the capture channel mask of UAC2 adapter
+ * @param[in] af Pointer to uac2 function
+ * @param[out] index Current capture channel mask of UAC2 adapter
+ * @return 0 on success usbg_error if error occurred.
+ */
+static inline int usbg_f_uac2_get_c_chmask(usbg_f_uac2 *af, int *c_chmask)
+{
+ return usbg_f_uac2_get_attr_val(af, USBG_F_UAC2_C_CHMASK,
+ (union usbg_f_uac2_attr_val *)c_chmask);
+}
+
+/**
+ * @brief Set the capture channel mask of UAC2 adapter
+ * @param[in] af Pointer to uac2 function
+ * @param[in] capture channel mask which should be set
+ * @return 0 on success usbg_error if error occurred.
+ */
+static inline int usbg_f_uac2_set_c_chmask(usbg_f_uac2 *af, int c_chmask)
+{
+ return usbg_f_uac2_set_attr_val(af, USBG_F_UAC2_C_CHMASK,
+ *(union usbg_f_uac2_attr_val *)&c_chmask);
+}
+
+/**
+ * @brief Get the capture sample rate of UAC2 adapter
+ * @param[in] af Pointer to uac2 function
+ * @param[out] index Current sample rate mask of UAC2 adapter
+ * @return 0 on success usbg_error if error occurred.
+ */
+static inline int usbg_f_uac2_get_c_srate(usbg_f_uac2 *af, int *c_srate)
+{
+ return usbg_f_uac2_get_attr_val(af, USBG_F_UAC2_C_SRATE,
+ (union usbg_f_uac2_attr_val *)c_srate);
+}
+
+/**
+ * @brief Set the capture sample rate of UAC2 adapter
+ * @param[in] af Pointer to uac2 function
+ * @param[in] capture sample rate which should be set
+ * @return 0 on success usbg_error if error occurred.
+ */
+static inline int usbg_f_uac2_set_c_srate(usbg_f_uac2 *af, int c_srate)
+{
+ return usbg_f_uac2_set_attr_val(af, USBG_F_UAC2_C_SRATE,
+ *(union usbg_f_uac2_attr_val *)&c_srate);
+}
+
+/**
+ * @brief Get the capture sample size of UAC2 adapter
+ * @param[in] af Pointer to uac2 function
+ * @param[out] index Current sample size mask of UAC2 adapter
+ * @return 0 on success usbg_error if error occurred.
+ */
+static inline int usbg_f_uac2_get_c_ssize(usbg_f_uac2 *af, int *c_ssize)
+{
+ return usbg_f_uac2_get_attr_val(af, USBG_F_UAC2_C_SSIZE,
+ (union usbg_f_uac2_attr_val *)c_ssize);
+}
+
+/**
+ * @brief Set the capture sample size of UAC2 adapter
+ * @param[in] af Pointer to uac2 function
+ * @param[in] capture sample size which should be set
+ * @return 0 on success usbg_error if error occurred.
+ */
+static inline int usbg_f_uac2_set_c_ssize(usbg_f_uac2 *af, int c_ssize)
+{
+ return usbg_f_uac2_set_attr_val(af, USBG_F_UAC2_C_SSIZE,
+ *(union usbg_f_uac2_attr_val *)&c_ssize);
+}
+
+/**
+ * @brief Get the playback channel mask of UAC2 adapter
+ * @param[in] af Pointer to uac2 function
+ * @param[out] index Current playback channel mask of UAC2 adapter
+ * @return 0 on success usbg_error if error occurred.
+ */
+static inline int usbg_f_uac2_get_p_chmask(usbg_f_uac2 *af, int *p_chmask)
+{
+ return usbg_f_uac2_get_attr_val(af, USBG_F_UAC2_P_CHMASK,
+ (union usbg_f_uac2_attr_val *)p_chmask);
+}
+
+/**
+ * @brief Set the playback channel mask of UAC2 adapter
+ * @param[in] af Pointer to uac2 function
+ * @param[in] playback channel mask which should be set
+ * @return 0 on success usbg_error if error occurred.
+ */
+static inline int usbg_f_uac2_set_p_chmask(usbg_f_uac2 *af, int p_chmask)
+{
+ return usbg_f_uac2_set_attr_val(af, USBG_F_UAC2_P_CHMASK,
+ *(union usbg_f_uac2_attr_val *)&p_chmask);
+}
+
+/**
+ * @brief Get the playback sample rate of UAC2 adapter
+ * @param[in] af Pointer to uac2 function
+ * @param[out] index Current sample rate mask of UAC2 adapter
+ * @return 0 on success usbg_error if error occurred.
+ */
+static inline int usbg_f_uac2_get_p_srate(usbg_f_uac2 *af, int *p_srate)
+{
+ return usbg_f_uac2_get_attr_val(af, USBG_F_UAC2_P_SRATE,
+ (union usbg_f_uac2_attr_val *)p_srate);
+}
+
+/**
+ * @brief Set the playback sample rate of UAC2 adapter
+ * @param[in] af Pointer to uac2 function
+ * @param[in] playback sample rate which should be set
+ * @return 0 on success usbg_error if error occurred.
+ */
+static inline int usbg_f_uac2_set_p_srate(usbg_f_uac2 *af, int p_srate)
+{
+ return usbg_f_uac2_set_attr_val(af, USBG_F_UAC2_P_SRATE,
+ *(union usbg_f_uac2_attr_val *)&p_srate);
+}
+
+/**
+ * @brief Get the playback sample size of UAC2 adapter
+ * @param[in] af Pointer to uac2 function
+ * @param[out] index Current sample size mask of UAC2 adapter
+ * @return 0 on success usbg_error if error occurred.
+ */
+static inline int usbg_f_uac2_get_p_ssize(usbg_f_uac2 *af, int *p_ssize)
+{
+ return usbg_f_uac2_get_attr_val(af, USBG_F_UAC2_P_SSIZE,
+ (union usbg_f_uac2_attr_val *)p_ssize);
+}
+
+/**
+ * @brief Set the playback sample size of UAC2 adapter
+ * @param[in] af Pointer to uac2 function
+ * @param[in] playback sample size which should be set
+ * @return 0 on success usbg_error if error occurred.
+ */
+static inline int usbg_f_uac2_set_p_ssize(usbg_f_uac2 *af, int p_ssize)
+{
+ return usbg_f_uac2_set_attr_val(af, USBG_F_UAC2_P_SSIZE,
+ *(union usbg_f_uac2_attr_val *)&p_ssize);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBG_FUNCTION_UAC2__ */
diff --git a/include/usbg/usbg.h b/include/usbg/usbg.h
index 2dc06ad..86dfed9 100644
--- a/include/usbg/usbg.h
+++ b/include/usbg/usbg.h
@@ -213,6 +213,7 @@ typedef enum
USBG_F_MIDI,
USBG_F_LOOPBACK,
USBG_F_HID,
+ USBG_F_UAC2,
USBG_FUNCTION_TYPE_MAX,
} usbg_function_type;
diff --git a/src/Makefile.am b/src/Makefile.am
index 1302af0..64c8d9d 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
+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
if TEST_GADGET_SCHEMES
libusbgx_la_SOURCES += usbg_schemes_libconfig.c usbg_common_libconfig.c
else
diff --git a/src/function/uac2.c b/src/function/uac2.c
new file mode 100644
index 0000000..f2c1a49
--- /dev/null
+++ b/src/function/uac2.c
@@ -0,0 +1,200 @@
+/*
+ * 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/uac2.h"
+
+#include <malloc.h>
+#ifdef HAS_GADGET_SCHEMES
+#include <libconfig.h>
+#endif
+
+struct usbg_f_uac2 {
+ struct usbg_function func;
+};
+
+#define UAC2_DEC_ATTR(_name) \
+ { \
+ .name = #_name, \
+ .offset = offsetof(struct usbg_f_uac2_attrs, _name), \
+ .get = usbg_get_dec, \
+ .set = usbg_set_dec, \
+ .import = usbg_get_config_node_int, \
+ .export = usbg_set_config_node_int, \
+ }
+
+static struct {
+ const char *name;
+ size_t offset;
+ usbg_attr_get_func get;
+ usbg_attr_set_func set;
+ usbg_import_node_func import;
+ usbg_export_node_func export;
+} uac2_attr[USBG_F_UAC2_ATTR_MAX] = {
+ [USBG_F_UAC2_C_CHMASK] = UAC2_DEC_ATTR(c_chmask),
+ [USBG_F_UAC2_C_SRATE] = UAC2_DEC_ATTR(c_srate),
+ [USBG_F_UAC2_C_SSIZE] = UAC2_DEC_ATTR(c_ssize),
+ [USBG_F_UAC2_P_CHMASK] = UAC2_DEC_ATTR(p_chmask),
+ [USBG_F_UAC2_P_SRATE] = UAC2_DEC_ATTR(p_srate),
+ [USBG_F_UAC2_P_SSIZE] = UAC2_DEC_ATTR(p_ssize),
+};
+
+#undef UAC2_DEC_ATTR
+
+GENERIC_ALLOC_INST(uac2, struct usbg_f_uac2, func);
+
+GENERIC_FREE_INST(uac2, struct usbg_f_uac2, func);
+
+static int uac2_set_attrs(struct usbg_function *f, void *f_attrs)
+{
+ return usbg_f_uac2_set_attrs(usbg_to_uac2_function(f), f_attrs);
+}
+
+static int uac2_get_attrs(struct usbg_function *f, void *f_attrs)
+{
+ return usbg_f_uac2_get_attrs(usbg_to_uac2_function(f), f_attrs);
+}
+
+static void uac2_cleanup_attrs(struct usbg_function *f, void *f_attrs)
+{
+ usbg_f_uac2_cleanup_attrs(f_attrs);
+}
+
+#ifdef HAS_GADGET_SCHEMES
+
+static int uac2_libconfig_import(struct usbg_function *f,
+ config_setting_t *root)
+{
+ struct usbg_f_uac2 *af = usbg_to_uac2_function(f);
+ union usbg_f_uac2_attr_val val;
+ int i;
+ int ret = 0;
+
+ for (i = USBG_F_UAC2_ATTR_MIN; i < USBG_F_UAC2_ATTR_MAX; ++i) {
+ ret = uac2_attr[i].import(root, uac2_attr[i].name, &val);
+ /* node not found */
+ if (ret == 0)
+ continue;
+ /* error */
+ if (ret < 0)
+ break;
+
+ ret = usbg_f_uac2_set_attr_val(af, i, val);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int uac2_libconfig_export(struct usbg_function *f,
+ config_setting_t *root)
+{
+ struct usbg_f_uac2 *af = usbg_to_uac2_function(f);
+ union usbg_f_uac2_attr_val val;
+ int i;
+ int ret = 0;
+
+ for (i = USBG_F_UAC2_ATTR_MIN; i < USBG_F_UAC2_ATTR_MAX; ++i) {
+ ret = usbg_f_uac2_get_attr_val(af, i, &val);
+ if (ret)
+ break;
+
+ ret = uac2_attr[i].export(root, uac2_attr[i].name, &val);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+#endif /* HAS_GADGET_SCHEMES */
+
+struct usbg_function_type usbg_f_type_uac2 = {
+ .name = "uac2",
+ .alloc_inst = uac2_alloc_inst,
+ .free_inst = uac2_free_inst,
+ .set_attrs = uac2_set_attrs,
+ .get_attrs = uac2_get_attrs,
+ .cleanup_attrs = uac2_cleanup_attrs,
+
+#ifdef HAS_GADGET_SCHEMES
+ .import = uac2_libconfig_import,
+ .export = uac2_libconfig_export,
+#endif
+};
+
+/* API implementation */
+
+usbg_f_uac2 *usbg_to_uac2_function(usbg_function *f)
+{
+ return f->ops == &usbg_f_type_uac2 ?
+ container_of(f, struct usbg_f_uac2, func) : NULL;
+}
+
+usbg_function *usbg_from_uac2_function(usbg_f_uac2 *af)
+{
+ return &af->func;
+}
+
+int usbg_f_uac2_get_attrs(usbg_f_uac2 *af,
+ struct usbg_f_uac2_attrs *attrs)
+{
+ int i;
+ int ret = 0;
+
+ for (i = USBG_F_UAC2_ATTR_MIN; i < USBG_F_UAC2_ATTR_MAX; ++i) {
+ ret = usbg_f_uac2_get_attr_val(af, i,
+ (union usbg_f_uac2_attr_val *)
+ ((char *)attrs
+ + uac2_attr[i].offset));
+ if (ret)
+ break;
+ }
+
+ return ret;
+
+}
+
+int usbg_f_uac2_set_attrs(usbg_f_uac2 *af,
+ const struct usbg_f_uac2_attrs *attrs)
+{
+ int i;
+ int ret = 0;
+
+ for (i = USBG_F_UAC2_ATTR_MIN; i < USBG_F_UAC2_ATTR_MAX; ++i) {
+ ret = usbg_f_uac2_set_attr_val(af, i,
+ *(union usbg_f_uac2_attr_val *)
+ ((char *)attrs
+ + uac2_attr[i].offset));
+ if (ret)
+ break;
+ }
+
+ return ret;
+
+}
+
+int usbg_f_uac2_get_attr_val(usbg_f_uac2 *af, enum usbg_f_uac2_attr attr,
+ union usbg_f_uac2_attr_val *val)
+{
+ return uac2_attr[attr].get(af->func.path, af->func.name,
+ uac2_attr[attr].name, val);
+}
+
+int usbg_f_uac2_set_attr_val(usbg_f_uac2 *af, enum usbg_f_uac2_attr attr,
+ union usbg_f_uac2_attr_val val)
+{
+ return uac2_attr[attr].set(af->func.path, af->func.name,
+ uac2_attr[attr].name, &val);
+}
diff --git a/src/usbg.c b/src/usbg.c
index d78cc42..09ba767 100644
--- a/src/usbg.c
+++ b/src/usbg.c
@@ -51,6 +51,7 @@ extern struct usbg_function_type usbg_f_type_ms;
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;
/**
* @var function_types
@@ -71,6 +72,7 @@ struct usbg_function_type* function_types[] = {
[USBG_F_PHONET] = &usbg_f_type_phonet,
[USBG_F_LOOPBACK] = &usbg_f_type_loopback,
[USBG_F_HID] = &usbg_f_type_hid,
+ [USBG_F_UAC2] = &usbg_f_type_uac2,
};
ARRAY_SIZE_SENTINEL(function_types, USBG_FUNCTION_TYPE_MAX);