diff options
author | John Keeping <john@metanate.com> | 2018-01-11 16:52:45 +0000 |
---|---|---|
committer | John Keeping <john@metanate.com> | 2018-01-17 14:38:58 +0000 |
commit | 5740ca8a5ea96316cc9363aed7d2fe8268201b15 (patch) | |
tree | a35e584eb82beafa4c03a0a413ac8a82c9be0bd2 | |
parent | 1c3f1b4660ae2cc858f83806cf7d9d5543ff0298 (diff) | |
download | libusbg-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.am | 2 | ||||
-rw-r--r-- | include/usbg/function/uac2.h | 265 | ||||
-rw-r--r-- | include/usbg/usbg.h | 1 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/function/uac2.c | 200 | ||||
-rw-r--r-- | src/usbg.c | 2 |
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); +} @@ -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); |