mirror of
https://github.com/linux-usb-gadgets/libusbgx.git
synced 2025-07-21 01:15:05 +03:00
libusbgx: Add internal API for defining function types
Adding support for a new function type was quite complicated. Moreover the main library source fail was growing realy fast. As a solution introduce internal OO API for defining function. Thanks to this support for each function may be placed in a separate file. Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
This commit is contained in:
parent
639a329af5
commit
013b9cc990
11 changed files with 1674 additions and 1284 deletions
|
@ -21,6 +21,7 @@
|
||||||
#include <libconfig.h>
|
#include <libconfig.h>
|
||||||
#else
|
#else
|
||||||
typedef struct _should_not_be_used config_t;
|
typedef struct _should_not_be_used config_t;
|
||||||
|
typedef struct _should_not_be_used config_setting_t;
|
||||||
void config_destroy(config_t *config);
|
void config_destroy(config_t *config);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -39,6 +40,37 @@
|
||||||
})
|
})
|
||||||
#endif /* container_of */
|
#endif /* container_of */
|
||||||
|
|
||||||
|
struct usbg_function_type
|
||||||
|
{
|
||||||
|
/* Name of this function type */
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when user would like to remove this function.
|
||||||
|
* If this callback is provided it will be always called
|
||||||
|
* before rmdir on function directory. This function
|
||||||
|
* should check received flags and remove composed function
|
||||||
|
* attributes (directories) only if USBG_RM_RECURSE flag
|
||||||
|
* has been passed.
|
||||||
|
*/
|
||||||
|
int (*remove)(struct usbg_function *, int);
|
||||||
|
|
||||||
|
/* Set the value of all given attributes */
|
||||||
|
int (*set_attrs)(struct usbg_function *, const usbg_function_attrs *);
|
||||||
|
|
||||||
|
/* Get the value of all function attributes */
|
||||||
|
int (*get_attrs)(struct usbg_function *, usbg_function_attrs *);
|
||||||
|
|
||||||
|
/* Free the additional memory allocated for function attributes */
|
||||||
|
void (*cleanup_attrs)(struct usbg_function *, usbg_function_attrs *);
|
||||||
|
|
||||||
|
/* Should import all function attributes from libconfig format */
|
||||||
|
int (*import)(struct usbg_function *, config_setting_t *);
|
||||||
|
|
||||||
|
/* Should export all functions attributes to libconfig format */
|
||||||
|
int (*export)(struct usbg_function *, config_setting_t *);
|
||||||
|
};
|
||||||
|
|
||||||
struct usbg_state
|
struct usbg_state
|
||||||
{
|
{
|
||||||
char *path;
|
char *path;
|
||||||
|
@ -74,8 +106,6 @@ struct usbg_config
|
||||||
int id;
|
int id;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*usbg_rm_function_callback)(usbg_function *, int);
|
|
||||||
|
|
||||||
struct usbg_function
|
struct usbg_function
|
||||||
{
|
{
|
||||||
TAILQ_ENTRY(usbg_function) fnode;
|
TAILQ_ENTRY(usbg_function) fnode;
|
||||||
|
@ -87,7 +117,7 @@ struct usbg_function
|
||||||
/* Only for internal library usage */
|
/* Only for internal library usage */
|
||||||
char *label;
|
char *label;
|
||||||
usbg_function_type type;
|
usbg_function_type type;
|
||||||
usbg_rm_function_callback rm_callback;
|
struct usbg_function_type *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct usbg_binding
|
struct usbg_binding
|
||||||
|
@ -170,6 +200,8 @@ int usbg_translate_error(int error);
|
||||||
|
|
||||||
char *usbg_ether_ntoa_r(const struct ether_addr *addr, char *buf);
|
char *usbg_ether_ntoa_r(const struct ether_addr *addr, char *buf);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int usbg_read_buf(const char *path, const char *name,
|
int usbg_read_buf(const char *path, const char *name,
|
||||||
const char *file, char *buf);
|
const char *file, char *buf);
|
||||||
|
|
||||||
|
@ -209,5 +241,9 @@ int usbg_rm_dir(const char *path, const char *name);
|
||||||
int usbg_rm_all_dirs(const char *path);
|
int usbg_rm_all_dirs(const char *path);
|
||||||
|
|
||||||
int usbg_check_dir(const char *path);
|
int usbg_check_dir(const char *path);
|
||||||
|
#define usbg_config_is_int(node) (config_setting_type(node) == CONFIG_TYPE_INT)
|
||||||
|
#define usbg_config_is_string(node) \
|
||||||
|
(config_setting_type(node) == CONFIG_TYPE_STRING)
|
||||||
|
|
||||||
#endif /* USBG_INTERNAL_H */
|
#endif /* USBG_INTERNAL_H */
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
AUTOMAKE_OPTIONS = std-options subdir-objects
|
||||||
lib_LTLIBRARIES = libusbgx.la
|
lib_LTLIBRARIES = libusbgx.la
|
||||||
libusbgx_la_SOURCES = usbg.c usbg_error.c usbg_common.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
|
||||||
if TEST_GADGET_SCHEMES
|
if TEST_GADGET_SCHEMES
|
||||||
libusbgx_la_SOURCES += usbg_schemes_libconfig.c
|
libusbgx_la_SOURCES += usbg_schemes_libconfig.c
|
||||||
else
|
else
|
||||||
|
|
248
src/function/ether.c
Normal file
248
src/function/ether.c
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
/*
|
||||||
|
* 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 <malloc.h>
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
#include <libconfig.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int ether_set_attrs(struct usbg_function *f,
|
||||||
|
const usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
int ret = USBG_SUCCESS;
|
||||||
|
char addr_buf[USBG_MAX_STR_LENGTH];
|
||||||
|
const usbg_f_net_attrs *attrs = &f_attrs->attrs.net;
|
||||||
|
char *addr;
|
||||||
|
|
||||||
|
/* ifname is read only so we accept only empty string for this param */
|
||||||
|
if (attrs->ifname && attrs->ifname[0]) {
|
||||||
|
ret = USBG_ERROR_INVALID_PARAM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = usbg_ether_ntoa_r(&attrs->dev_addr, addr_buf);
|
||||||
|
ret = usbg_write_string(f->path, f->name, "dev_addr", addr);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
addr = usbg_ether_ntoa_r(&attrs->host_addr, addr_buf);
|
||||||
|
ret = usbg_write_string(f->path, f->name, "host_addr", addr);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_dec(f->path, f->name, "qmult", attrs->qmult);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ether_get_attrs(struct usbg_function *f,
|
||||||
|
usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
struct ether_addr *addr;
|
||||||
|
struct ether_addr addr_buf;
|
||||||
|
char str_addr[USBG_MAX_STR_LENGTH];
|
||||||
|
usbg_f_net_attrs *attrs = &f_attrs->attrs.net;
|
||||||
|
int ret = USBG_ERROR_INVALID_PARAM;
|
||||||
|
|
||||||
|
ret = usbg_read_string(f->path, f->name, "dev_addr", str_addr);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
addr = ether_aton_r(str_addr, &addr_buf);
|
||||||
|
if (addr) {
|
||||||
|
attrs->dev_addr = *addr;
|
||||||
|
} else {
|
||||||
|
ret = USBG_ERROR_IO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = usbg_read_string(f->path, f->name, "host_addr", str_addr);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
addr = ether_aton_r(str_addr, &addr_buf);
|
||||||
|
if (addr) {
|
||||||
|
attrs->host_addr = *addr;
|
||||||
|
} else {
|
||||||
|
ret = USBG_ERROR_IO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = usbg_read_dec(f->path, f->name, "qmult", &(attrs->qmult));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_read_string_alloc(f->path, f->name, "ifname",
|
||||||
|
&(attrs->ifname));
|
||||||
|
|
||||||
|
f_attrs->header.attrs_type = USBG_F_ATTRS_NET;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ether_cleanup_attrs(struct usbg_function *f,
|
||||||
|
usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
free((char*)f_attrs->attrs.net.ifname);
|
||||||
|
f_attrs->attrs.net.ifname = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
|
||||||
|
static int ether_libconfig_import(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
config_setting_t *node;
|
||||||
|
int ret = USBG_SUCCESS;
|
||||||
|
int qmult;
|
||||||
|
struct ether_addr *addr;
|
||||||
|
struct ether_addr addr_buf;
|
||||||
|
const char *str;
|
||||||
|
|
||||||
|
#define GET_OPTIONAL_ADDR(NAME) \
|
||||||
|
do { \
|
||||||
|
node = config_setting_get_member(root, #NAME); \
|
||||||
|
if (node) { \
|
||||||
|
str = config_setting_get_string(node); \
|
||||||
|
if (!str) { \
|
||||||
|
ret = USBG_ERROR_INVALID_TYPE; \
|
||||||
|
goto out; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
addr = ether_aton_r(str, &addr_buf); \
|
||||||
|
if (!addr) { \
|
||||||
|
ret = USBG_ERROR_INVALID_VALUE; \
|
||||||
|
goto out; \
|
||||||
|
} \
|
||||||
|
ret = usbg_set_net_##NAME(f, addr); \
|
||||||
|
if (ret != USBG_SUCCESS) \
|
||||||
|
goto out; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
GET_OPTIONAL_ADDR(host_addr);
|
||||||
|
GET_OPTIONAL_ADDR(dev_addr);
|
||||||
|
|
||||||
|
#undef GET_OPTIONAL_ADDR
|
||||||
|
|
||||||
|
node = config_setting_get_member(root, "qmult");
|
||||||
|
if (node) {
|
||||||
|
if (!usbg_config_is_int(node)) {
|
||||||
|
ret = USBG_ERROR_INVALID_TYPE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
qmult = config_setting_get_int(node);
|
||||||
|
ret = usbg_set_net_qmult(f, qmult);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ether_libconfig_export(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
config_setting_t *node;
|
||||||
|
char *addr;
|
||||||
|
char addr_buf[USBG_MAX_STR_LENGTH];
|
||||||
|
int cfg_ret, usbg_ret;
|
||||||
|
usbg_function_attrs f_attrs;
|
||||||
|
usbg_f_net_attrs *attrs = &f_attrs.attrs.net;
|
||||||
|
int ret = USBG_ERROR_NO_MEM;
|
||||||
|
|
||||||
|
usbg_ret = ether_get_attrs(f, &f_attrs);
|
||||||
|
if (usbg_ret != USBG_SUCCESS) {
|
||||||
|
ret = usbg_ret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = config_setting_add(root, "dev_addr", CONFIG_TYPE_STRING);
|
||||||
|
if (!node)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
addr = usbg_ether_ntoa_r(&attrs->dev_addr, addr_buf);
|
||||||
|
cfg_ret = config_setting_set_string(node, addr);
|
||||||
|
if (cfg_ret != CONFIG_TRUE) {
|
||||||
|
ret = USBG_ERROR_OTHER_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = config_setting_add(root, "host_addr", CONFIG_TYPE_STRING);
|
||||||
|
if (!node)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
addr = usbg_ether_ntoa_r(&attrs->host_addr, addr_buf);
|
||||||
|
cfg_ret = config_setting_set_string(node, addr);
|
||||||
|
if (cfg_ret != CONFIG_TRUE) {
|
||||||
|
ret = USBG_ERROR_OTHER_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = config_setting_add(root, "qmult", CONFIG_TYPE_INT);
|
||||||
|
if (!node)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
cfg_ret = config_setting_set_int(node, attrs->qmult);
|
||||||
|
ret = cfg_ret == CONFIG_TRUE ? 0 : USBG_ERROR_OTHER_ERROR;
|
||||||
|
|
||||||
|
/* ifname is read only so we don't export it */
|
||||||
|
cleanup:
|
||||||
|
ether_cleanup_attrs(f, &f_attrs);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ETHER_LIBCONFIG_DEP_OPS \
|
||||||
|
.import = ether_libconfig_import, \
|
||||||
|
.export = ether_libconfig_export
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ETHER_LIBCONFIG_DEP_OPS
|
||||||
|
|
||||||
|
#endif /* HAS_LIBCONFIG */
|
||||||
|
|
||||||
|
#define ETHER_FUNCTION_OPTS \
|
||||||
|
.set_attrs = ether_set_attrs, \
|
||||||
|
.get_attrs = ether_get_attrs, \
|
||||||
|
.cleanup_attrs = ether_cleanup_attrs, \
|
||||||
|
ETHER_LIBCONFIG_DEP_OPS
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_ecm = {
|
||||||
|
.name = "ecm",
|
||||||
|
ETHER_FUNCTION_OPTS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_subset = {
|
||||||
|
.name = "geth",
|
||||||
|
ETHER_FUNCTION_OPTS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_ncm = {
|
||||||
|
.name = "ncm",
|
||||||
|
ETHER_FUNCTION_OPTS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_eem = {
|
||||||
|
.name = "eem",
|
||||||
|
ETHER_FUNCTION_OPTS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_rndis = {
|
||||||
|
.name = "rndis",
|
||||||
|
ETHER_FUNCTION_OPTS
|
||||||
|
};
|
||||||
|
|
80
src/function/ffs.c
Normal file
80
src/function/ffs.c
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
#include <libconfig.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int ffs_set_attrs(struct usbg_function *f,
|
||||||
|
const usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
const usbg_f_ffs_attrs *ffs_attrs = &(f_attrs->attrs.ffs);
|
||||||
|
int ret = USBG_ERROR_INVALID_PARAM;
|
||||||
|
|
||||||
|
if (f_attrs->header.attrs_type &&
|
||||||
|
f_attrs->header.attrs_type != USBG_F_ATTRS_FFS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = ffs_attrs->dev_name && ffs_attrs->dev_name[0] ?
|
||||||
|
USBG_ERROR_INVALID_PARAM : USBG_SUCCESS;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ffs_get_attrs(struct usbg_function *f,
|
||||||
|
usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
usbg_f_ffs_attrs *ffs_attrs = &(f_attrs->attrs.ffs);
|
||||||
|
int ret = USBG_SUCCESS;
|
||||||
|
|
||||||
|
ffs_attrs->dev_name = strdup(f->instance);
|
||||||
|
if (!ffs_attrs->dev_name) {
|
||||||
|
ret = USBG_ERROR_NO_MEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_attrs->header.attrs_type = USBG_F_ATTRS_FFS;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ffs_cleanup_attrs(struct usbg_function *f,
|
||||||
|
usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
free((char*)f_attrs->attrs.ffs.dev_name);
|
||||||
|
f_attrs->attrs.ffs.dev_name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ffs_libconfig_import(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
return USBG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ffs_libconfig_export(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
return USBG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_ffs = {
|
||||||
|
.name = "ffs",
|
||||||
|
.set_attrs = ffs_set_attrs,
|
||||||
|
.get_attrs = ffs_get_attrs,
|
||||||
|
.cleanup_attrs = ffs_cleanup_attrs,
|
||||||
|
.import = ffs_libconfig_import,
|
||||||
|
.export = ffs_libconfig_export,
|
||||||
|
};
|
151
src/function/loopback.c
Normal file
151
src/function/loopback.c
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
#include <libconfig.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int loopback_set_attrs(struct usbg_function *f,
|
||||||
|
const usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
int ret = USBG_ERROR_INVALID_PARAM;
|
||||||
|
const usbg_f_loopback_attrs *attrs = &f_attrs->attrs.loopback;
|
||||||
|
|
||||||
|
if (f_attrs->header.attrs_type &&
|
||||||
|
f_attrs->header.attrs_type != USBG_F_ATTRS_LOOPBACK)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_dec(f->path, f->name, "buflen", attrs->buflen);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_dec(f->path, f->name, "qlen", attrs->qlen);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int loopback_get_attrs(struct usbg_function *f,
|
||||||
|
usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
const usbg_f_loopback_attrs *attrs = &f_attrs->attrs.loopback;
|
||||||
|
|
||||||
|
ret = usbg_read_dec(f->path, f->name, "buflen", (int *)&(attrs->buflen));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_read_dec(f->path, f->name, "qlen", (int *)&(attrs->qlen));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
f_attrs->header.attrs_type = USBG_F_ATTRS_LOOPBACK;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
|
||||||
|
static int loopback_libconfig_export(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
config_setting_t *node;
|
||||||
|
usbg_function_attrs f_attrs;
|
||||||
|
usbg_f_loopback_attrs *attrs = &f_attrs.attrs.loopback;
|
||||||
|
int cfg_ret;
|
||||||
|
int ret = USBG_ERROR_NO_MEM;
|
||||||
|
|
||||||
|
ret = loopback_get_attrs(f, &f_attrs);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
#define ADD_F_LOOPBACK_INT_ATTR(attr, minval) \
|
||||||
|
do { \
|
||||||
|
if ((int)attrs->attr < minval) { \
|
||||||
|
ret = USBG_ERROR_INVALID_VALUE; \
|
||||||
|
goto out; \
|
||||||
|
} \
|
||||||
|
node = config_setting_add(root, #attr, CONFIG_TYPE_INT);\
|
||||||
|
if (!node) \
|
||||||
|
goto out; \
|
||||||
|
cfg_ret = config_setting_set_int(node, attrs->attr); \
|
||||||
|
if (cfg_ret != CONFIG_TRUE) { \
|
||||||
|
ret = USBG_ERROR_OTHER_ERROR; \
|
||||||
|
goto out; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
ADD_F_LOOPBACK_INT_ATTR(buflen, 0);
|
||||||
|
ADD_F_LOOPBACK_INT_ATTR(qlen, 0);
|
||||||
|
|
||||||
|
#undef ADD_F_LOOPBACK_INT_ATTR
|
||||||
|
|
||||||
|
ret = USBG_SUCCESS;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int loopback_libconfig_import(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
config_setting_t *node;
|
||||||
|
int ret = USBG_ERROR_NO_MEM;
|
||||||
|
int tmp;
|
||||||
|
usbg_function_attrs attrs;
|
||||||
|
usbg_f_loopback_attrs *loopback_attrs = &attrs.attrs.loopback;
|
||||||
|
|
||||||
|
attrs.header.attrs_type = USBG_F_ATTRS_LOOPBACK;
|
||||||
|
|
||||||
|
#define ADD_F_LOOPBACK_INT_ATTR(attr, defval, minval) \
|
||||||
|
do { \
|
||||||
|
node = config_setting_get_member(root, #attr); \
|
||||||
|
if (node) { \
|
||||||
|
if (!usbg_config_is_int(node)) { \
|
||||||
|
ret = USBG_ERROR_INVALID_TYPE; \
|
||||||
|
goto out; \
|
||||||
|
} \
|
||||||
|
tmp = config_setting_get_int(node); \
|
||||||
|
if (tmp < minval) { \
|
||||||
|
ret = USBG_ERROR_INVALID_VALUE; \
|
||||||
|
goto out; \
|
||||||
|
} \
|
||||||
|
loopback_attrs->attr = tmp; \
|
||||||
|
} else { \
|
||||||
|
loopback_attrs->attr = defval; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
ADD_F_LOOPBACK_INT_ATTR(buflen, 4096, 0);
|
||||||
|
ADD_F_LOOPBACK_INT_ATTR(qlen, 32, 0);
|
||||||
|
|
||||||
|
#undef ADD_F_LOOPBACK_INT_ATTR
|
||||||
|
|
||||||
|
ret = usbg_set_function_attrs(f, &attrs);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAS_LIBCONFIG */
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_loopback = {
|
||||||
|
.name = "loopback",
|
||||||
|
.set_attrs = loopback_set_attrs,
|
||||||
|
.get_attrs = loopback_get_attrs,
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
.import = loopback_libconfig_import,
|
||||||
|
.export = loopback_libconfig_export,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
228
src/function/midi.c
Normal file
228
src/function/midi.c
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
/*
|
||||||
|
* 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 <malloc.h>
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
#include <libconfig.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int midi_set_attrs(struct usbg_function *f,
|
||||||
|
const usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
const usbg_f_midi_attrs *attrs = &f_attrs->attrs.midi;
|
||||||
|
int ret = USBG_ERROR_INVALID_PARAM;
|
||||||
|
|
||||||
|
if (f_attrs->header.attrs_type &&
|
||||||
|
f_attrs->header.attrs_type != USBG_F_ATTRS_MIDI)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_dec(f->path, f->name, "index", attrs->index);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_string(f->path, f->name, "id", attrs->id);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_dec(f->path, f->name, "in_ports", attrs->in_ports);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_dec(f->path, f->name, "out_ports", attrs->out_ports);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_dec(f->path, f->name, "buflen", attrs->buflen);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_dec(f->path, f->name, "qlen", attrs->qlen);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int midi_get_attrs(struct usbg_function *f,
|
||||||
|
usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
usbg_f_midi_attrs *attrs = &f_attrs->attrs.midi;
|
||||||
|
|
||||||
|
ret = usbg_read_dec(f->path, f->name, "index", &(attrs->index));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_read_string_alloc(f->path, f->name, "id", &(attrs->id));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_read_dec(f->path, f->name, "in_ports", (int*)&(attrs->in_ports));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_read_dec(f->path, f->name, "out_ports", (int*)&(attrs->out_ports));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_read_dec(f->path, f->name, "buflen", (int*)&(attrs->buflen));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_read_dec(f->path, f->name, "qlen", (int*)&(attrs->qlen));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
f_attrs->header.attrs_type = USBG_F_ATTRS_MIDI;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void midi_cleanup_attrs(struct usbg_function *f,
|
||||||
|
usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
free((char*)f_attrs->attrs.midi.id);
|
||||||
|
f_attrs->attrs.midi.id = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
|
||||||
|
static int midi_libconfig_import(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
config_setting_t *node;
|
||||||
|
int ret = USBG_ERROR_NO_MEM;
|
||||||
|
int tmp;
|
||||||
|
usbg_function_attrs attrs;
|
||||||
|
usbg_f_midi_attrs *midi_attrs = &attrs.attrs.midi;
|
||||||
|
|
||||||
|
attrs.header.attrs_type = USBG_F_ATTRS_MIDI;
|
||||||
|
|
||||||
|
#define ADD_F_MIDI_INT_ATTR(attr, defval, minval) \
|
||||||
|
do { \
|
||||||
|
node = config_setting_get_member(root, #attr); \
|
||||||
|
if (node) { \
|
||||||
|
if (!usbg_config_is_int(node)) { \
|
||||||
|
ret = USBG_ERROR_INVALID_TYPE; \
|
||||||
|
goto out; \
|
||||||
|
} \
|
||||||
|
tmp = config_setting_get_int(node); \
|
||||||
|
if (tmp < minval) { \
|
||||||
|
ret = USBG_ERROR_INVALID_VALUE; \
|
||||||
|
goto out; \
|
||||||
|
} \
|
||||||
|
midi_attrs->attr = tmp; \
|
||||||
|
} else { \
|
||||||
|
midi_attrs->attr = defval; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
ADD_F_MIDI_INT_ATTR(index, -1, INT_MIN);
|
||||||
|
ADD_F_MIDI_INT_ATTR(in_ports, 1, 0);
|
||||||
|
ADD_F_MIDI_INT_ATTR(out_ports, 1, 0);
|
||||||
|
ADD_F_MIDI_INT_ATTR(buflen, 256, 0);
|
||||||
|
ADD_F_MIDI_INT_ATTR(qlen, 32, 0);
|
||||||
|
|
||||||
|
#undef ADD_F_MIDI_INT_ATTR
|
||||||
|
|
||||||
|
node = config_setting_get_member(root, "id");
|
||||||
|
if (node) {
|
||||||
|
if (!usbg_config_is_string(node)) {
|
||||||
|
ret = USBG_ERROR_INVALID_TYPE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
midi_attrs->id = config_setting_get_string(node);
|
||||||
|
} else {
|
||||||
|
midi_attrs->id = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ret = usbg_set_function_attrs(f, &attrs);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int midi_libconfig_export(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
config_setting_t *node;
|
||||||
|
int cfg_ret, usbg_ret;
|
||||||
|
usbg_function_attrs f_attrs;
|
||||||
|
usbg_f_midi_attrs *attrs = &f_attrs.attrs.midi;
|
||||||
|
int ret = USBG_ERROR_NO_MEM;
|
||||||
|
|
||||||
|
usbg_ret = midi_get_attrs(f, &f_attrs);
|
||||||
|
if (usbg_ret != USBG_SUCCESS) {
|
||||||
|
ret = usbg_ret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ADD_F_MIDI_INT_ATTR(attr, minval) \
|
||||||
|
do { \
|
||||||
|
if ((int)attrs->attr < minval) { \
|
||||||
|
ret = USBG_ERROR_INVALID_VALUE; \
|
||||||
|
goto cleanup; \
|
||||||
|
} \
|
||||||
|
node = config_setting_add(root, #attr, CONFIG_TYPE_INT);\
|
||||||
|
if (!node) \
|
||||||
|
goto cleanup; \
|
||||||
|
cfg_ret = config_setting_set_int(node, attrs->attr); \
|
||||||
|
if (cfg_ret != CONFIG_TRUE) { \
|
||||||
|
ret = USBG_ERROR_OTHER_ERROR; \
|
||||||
|
goto cleanup; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
ADD_F_MIDI_INT_ATTR(index, INT_MIN);
|
||||||
|
|
||||||
|
node = config_setting_add(root, "id", CONFIG_TYPE_STRING);
|
||||||
|
if (!node)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
cfg_ret = config_setting_set_string(node, attrs->id);
|
||||||
|
if (cfg_ret != CONFIG_TRUE) {
|
||||||
|
ret = USBG_ERROR_OTHER_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADD_F_MIDI_INT_ATTR(in_ports, 0);
|
||||||
|
ADD_F_MIDI_INT_ATTR(out_ports, 0);
|
||||||
|
ADD_F_MIDI_INT_ATTR(buflen, 0);
|
||||||
|
ADD_F_MIDI_INT_ATTR(qlen, 0);
|
||||||
|
|
||||||
|
#undef ADD_F_MIDI_INT_ATTR
|
||||||
|
|
||||||
|
ret = USBG_SUCCESS;
|
||||||
|
cleanup:
|
||||||
|
midi_cleanup_attrs(f, &f_attrs);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAS_LIBCONFIG */
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_midi = {
|
||||||
|
.name = "midi",
|
||||||
|
.set_attrs = midi_set_attrs,
|
||||||
|
.get_attrs = midi_get_attrs,
|
||||||
|
.cleanup_attrs = midi_cleanup_attrs,
|
||||||
|
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
.import = midi_libconfig_import,
|
||||||
|
.export = midi_libconfig_export,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
666
src/function/ms.c
Normal file
666
src/function/ms.c
Normal file
|
@ -0,0 +1,666 @@
|
||||||
|
/*
|
||||||
|
* 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 <malloc.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
#include <libconfig.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int lun_select(const struct dirent *dent)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
ret = file_select(dent);
|
||||||
|
if (!ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = sscanf(dent->d_name, "lun.%d", &id);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lun_sort(const struct dirent **d1, const struct dirent **d2)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int id1, id2;
|
||||||
|
|
||||||
|
ret = sscanf((*d1)->d_name, "lun.%d", &id1);
|
||||||
|
if (ret != 1)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
ret = sscanf((*d2)->d_name, "lun.%d", &id2);
|
||||||
|
if (ret != 1)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (id1 < id2)
|
||||||
|
ret = 1;
|
||||||
|
|
||||||
|
return id1 < id2 ? -1 : id1 > id2;
|
||||||
|
err:
|
||||||
|
/*
|
||||||
|
* This should not happened because dentries has been
|
||||||
|
* already checked by lun_select function. This
|
||||||
|
* error procedure is just in case.
|
||||||
|
*/
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ms_set_lun_attrs(const char *path, const char *lun,
|
||||||
|
usbg_f_ms_lun_attrs *lun_attrs)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = usbg_write_bool(path, lun, "cdrom", lun_attrs->cdrom);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_bool(path, lun, "ro", lun_attrs->ro);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_bool(path, lun, "nofua", lun_attrs->nofua);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_bool(path, lun, "removable", lun_attrs->removable);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_string(path, lun, "file",
|
||||||
|
lun_attrs->filename);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ms_set_attrs(struct usbg_function *f,
|
||||||
|
const usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
int i, nmb;
|
||||||
|
int space_left;
|
||||||
|
char *new_lun_mask;
|
||||||
|
char lpath[USBG_MAX_PATH_LENGTH];
|
||||||
|
char *lpath_end;
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent **dent;
|
||||||
|
const usbg_f_ms_attrs *attrs = &f_attrs->attrs.ms;
|
||||||
|
int ret = USBG_ERROR_INVALID_PARAM;
|
||||||
|
|
||||||
|
if (f_attrs->header.attrs_type &&
|
||||||
|
f_attrs->header.attrs_type != USBG_F_ATTRS_MS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_write_bool(f->path, f->name, "stall", attrs->stall);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* lun0 cannot be removed */
|
||||||
|
if (!attrs->luns || attrs->nluns <= 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = snprintf(lpath, sizeof(lpath), "%s/%s/", f->path, f->name);
|
||||||
|
if (ret >= sizeof(lpath)) {
|
||||||
|
ret = USBG_ERROR_PATH_TOO_LONG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpath_end = lpath + strlen(lpath);
|
||||||
|
space_left = sizeof(lpath) - (lpath_end - lpath);
|
||||||
|
|
||||||
|
new_lun_mask = calloc(attrs->nluns, sizeof (char));
|
||||||
|
if (!new_lun_mask) {
|
||||||
|
ret = USBG_ERROR_NO_MEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < attrs->nluns; ++i) {
|
||||||
|
usbg_f_ms_lun_attrs *lun = attrs->luns[i];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* id may be left unset in lun attrs but
|
||||||
|
* if it is set it has to be equal to position
|
||||||
|
* in lun array
|
||||||
|
*/
|
||||||
|
if (lun && lun->id >= 0 && lun->id != i) {
|
||||||
|
ret = USBG_ERROR_INVALID_PARAM;
|
||||||
|
goto err_lun_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = snprintf(lpath_end, space_left, "/lun.%d/", i);
|
||||||
|
if (ret >= space_left) {
|
||||||
|
ret = USBG_ERROR_PATH_TOO_LONG;
|
||||||
|
goto err_lun_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if dir exist and create it if needed
|
||||||
|
*/
|
||||||
|
dir = opendir(lpath);
|
||||||
|
if (dir) {
|
||||||
|
closedir(dir);
|
||||||
|
} else if (errno != ENOENT) {
|
||||||
|
ret = usbg_translate_error(errno);
|
||||||
|
goto err_lun_loop;
|
||||||
|
} else {
|
||||||
|
ret = mkdir(lpath, S_IRWXU|S_IRWXG|S_IRWXO);
|
||||||
|
if (!ret) {
|
||||||
|
/*
|
||||||
|
* If we have created a new directory in
|
||||||
|
* this function let's mark it so we can
|
||||||
|
* cleanup in case of error
|
||||||
|
*/
|
||||||
|
new_lun_mask[i] = 1;
|
||||||
|
} else {
|
||||||
|
ret = usbg_translate_error(errno);
|
||||||
|
goto err_lun_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if attributes has not been provided just go to next one */
|
||||||
|
if (!lun)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = ms_set_lun_attrs(lpath, "", lun);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto err_lun_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if function has more luns and remove them */
|
||||||
|
*lpath_end = '\0';
|
||||||
|
i = 0;
|
||||||
|
nmb = scandir(lpath, &dent, lun_select, lun_sort);
|
||||||
|
if (nmb < 0) {
|
||||||
|
ret = usbg_translate_error(errno);
|
||||||
|
goto err_lun_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < attrs->nluns; ++i)
|
||||||
|
free(dent[i]);
|
||||||
|
|
||||||
|
for (; i < nmb; ++i) {
|
||||||
|
ret = usbg_rm_dir(lpath, dent[i]->d_name);
|
||||||
|
free(dent[i]);
|
||||||
|
/* There is no good way to recover form this */
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto err_rm_loop;
|
||||||
|
}
|
||||||
|
free(dent);
|
||||||
|
|
||||||
|
return USBG_SUCCESS;
|
||||||
|
|
||||||
|
err_rm_loop:
|
||||||
|
while (++i < nmb)
|
||||||
|
free(dent[i]);
|
||||||
|
free(dent);
|
||||||
|
|
||||||
|
i = attrs->nluns;
|
||||||
|
err_lun_loop:
|
||||||
|
/* array is null terminated so we may access lun[nluns] */
|
||||||
|
for (; i >= 0; --i) {
|
||||||
|
if (!new_lun_mask[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = snprintf(lpath_end, space_left, "/lun.%d/", i);
|
||||||
|
if (ret >= space_left) {
|
||||||
|
/*
|
||||||
|
* This should not happen because if we were
|
||||||
|
* able to create this directory we should be
|
||||||
|
* also able to remove it.
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rmdir(lpath);
|
||||||
|
}
|
||||||
|
free(new_lun_mask);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ms_cleanup_lun_attrs(usbg_f_ms_lun_attrs *lun_attrs)
|
||||||
|
{
|
||||||
|
if (!lun_attrs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
free((char*)lun_attrs->filename);
|
||||||
|
lun_attrs->id = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ms_cleanup_attrs(struct usbg_function *f,
|
||||||
|
usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
usbg_f_ms_attrs *attrs = &f_attrs->attrs.ms;
|
||||||
|
|
||||||
|
if (!attrs->luns)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < attrs->nluns; ++i) {
|
||||||
|
if (!attrs->luns[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ms_cleanup_lun_attrs(attrs->luns[i]);
|
||||||
|
free(attrs->luns[i]);
|
||||||
|
}
|
||||||
|
free(attrs->luns);
|
||||||
|
attrs->luns = NULL;
|
||||||
|
attrs->nluns = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ms_get_lun_attrs(const char *path, const char *lun,
|
||||||
|
usbg_f_ms_lun_attrs *lun_attrs)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset(lun_attrs, 0, sizeof(*lun_attrs));
|
||||||
|
|
||||||
|
ret = sscanf(lun, "lun.%d", &lun_attrs->id);
|
||||||
|
if (ret != 1)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_read_bool(path, lun, "cdrom", &(lun_attrs->cdrom));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_read_bool(path, lun, "ro", &(lun_attrs->ro));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_read_bool(path, lun, "nofua", &(lun_attrs->nofua));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_read_bool(path, lun, "removable", &(lun_attrs->removable));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = usbg_read_string_alloc(path, lun, "file",
|
||||||
|
&(lun_attrs->filename));
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ms_get_attrs(struct usbg_function *f,
|
||||||
|
usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
int nmb;
|
||||||
|
int i = 0;
|
||||||
|
char fpath[USBG_MAX_PATH_LENGTH];
|
||||||
|
usbg_f_ms_lun_attrs *lun_attrs;
|
||||||
|
usbg_f_ms_lun_attrs **luns;
|
||||||
|
struct dirent **dent;
|
||||||
|
usbg_f_ms_attrs *attrs = &f_attrs->attrs.ms;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = usbg_read_bool(f->path, f->name, "stall",
|
||||||
|
&(attrs->stall));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
|
||||||
|
nmb = snprintf(fpath, sizeof(fpath), "%s/%s/",
|
||||||
|
f->path, f->name);
|
||||||
|
if (nmb >= sizeof(fpath)) {
|
||||||
|
ret = USBG_ERROR_PATH_TOO_LONG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
nmb = scandir(fpath, &dent, lun_select, lun_sort);
|
||||||
|
if (nmb < 0) {
|
||||||
|
ret = usbg_translate_error(errno);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
luns = calloc(nmb + 1, sizeof(*luns));
|
||||||
|
if (!luns) {
|
||||||
|
ret = USBG_ERROR_NO_MEM;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs->luns = luns;
|
||||||
|
attrs->nluns = nmb;
|
||||||
|
|
||||||
|
for (i = 0; i < nmb; i++) {
|
||||||
|
lun_attrs = malloc(sizeof(*lun_attrs));
|
||||||
|
if (!lun_attrs) {
|
||||||
|
ret = USBG_ERROR_NO_MEM;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ms_get_lun_attrs(fpath, dent[i]->d_name,
|
||||||
|
lun_attrs);
|
||||||
|
if (ret != USBG_SUCCESS) {
|
||||||
|
free(lun_attrs);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
luns[i] = lun_attrs;
|
||||||
|
free(dent[i]);
|
||||||
|
}
|
||||||
|
free(dent);
|
||||||
|
|
||||||
|
f_attrs->header.attrs_type = USBG_F_ATTRS_MS;
|
||||||
|
|
||||||
|
return USBG_SUCCESS;
|
||||||
|
|
||||||
|
err:
|
||||||
|
while (i < nmb) {
|
||||||
|
free(dent[i]);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
free(dent);
|
||||||
|
|
||||||
|
ms_cleanup_attrs(f, f_attrs);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
|
||||||
|
static int ms_import_lun_attrs(usbg_f_ms_lun_attrs *lattrs,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
config_setting_t *node;
|
||||||
|
int i;
|
||||||
|
int ret = USBG_ERROR_NO_MEM;
|
||||||
|
|
||||||
|
#define BOOL_ATTR(_name, _default_val) \
|
||||||
|
{ .name = #_name, .value = &lattrs->_name, }
|
||||||
|
struct {
|
||||||
|
char *name;
|
||||||
|
bool *value;
|
||||||
|
bool default_val;
|
||||||
|
} bool_attrs[] = {
|
||||||
|
BOOL_ATTR(cdrom, false),
|
||||||
|
BOOL_ATTR(ro, false),
|
||||||
|
BOOL_ATTR(nofua, false),
|
||||||
|
BOOL_ATTR(removable, true),
|
||||||
|
};
|
||||||
|
#undef BOOL_ATTR
|
||||||
|
|
||||||
|
memset(lattrs, 0, sizeof(*lattrs));
|
||||||
|
lattrs->id = -1;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(bool_attrs); ++i) {
|
||||||
|
*(bool_attrs[i].value) = bool_attrs[i].default_val;
|
||||||
|
|
||||||
|
node = config_setting_get_member(root, bool_attrs[i].name);
|
||||||
|
if (!node)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = config_setting_type(node);
|
||||||
|
switch (ret) {
|
||||||
|
case CONFIG_TYPE_INT:
|
||||||
|
*(bool_attrs[i].value) = !!config_setting_get_int(node);
|
||||||
|
break;
|
||||||
|
case CONFIG_TYPE_BOOL:
|
||||||
|
*(bool_attrs[i].value) = config_setting_get_bool(node);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = USBG_ERROR_INVALID_TYPE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node = config_setting_get_member(root, "filename");
|
||||||
|
if (node) {
|
||||||
|
if (!usbg_config_is_string(node)) {
|
||||||
|
ret = USBG_ERROR_INVALID_PARAM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
lattrs->filename = (char *)config_setting_get_string(node);
|
||||||
|
} else {
|
||||||
|
lattrs->filename = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = USBG_SUCCESS;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ms_libconfig_import(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
config_setting_t *luns_node, *node;
|
||||||
|
int i;
|
||||||
|
int ret = USBG_ERROR_NO_MEM;
|
||||||
|
usbg_function_attrs f_attrs;
|
||||||
|
usbg_f_ms_attrs *attrs = &f_attrs.attrs.ms;
|
||||||
|
|
||||||
|
memset(&attrs, 0, sizeof(attrs));
|
||||||
|
|
||||||
|
node = config_setting_get_member(root, "stall");
|
||||||
|
if (node) {
|
||||||
|
ret = config_setting_type(node);
|
||||||
|
switch (ret) {
|
||||||
|
case CONFIG_TYPE_INT:
|
||||||
|
attrs->stall = !!config_setting_get_int(node);
|
||||||
|
break;
|
||||||
|
case CONFIG_TYPE_BOOL:
|
||||||
|
attrs->stall = config_setting_get_bool(node);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = USBG_ERROR_INVALID_TYPE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
luns_node = config_setting_get_member(root, "luns");
|
||||||
|
if (!node) {
|
||||||
|
ret = USBG_ERROR_INVALID_PARAM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config_setting_is_list(luns_node)) {
|
||||||
|
ret = USBG_ERROR_INVALID_TYPE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs->nluns = config_setting_length(luns_node);
|
||||||
|
|
||||||
|
attrs->luns = calloc(attrs->nluns + 1, sizeof(*(attrs->luns)));
|
||||||
|
if (!attrs->luns) {
|
||||||
|
ret = USBG_ERROR_NO_MEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < attrs->nluns; ++i) {
|
||||||
|
node = config_setting_get_elem(luns_node, i);
|
||||||
|
if (!node) {
|
||||||
|
ret = USBG_ERROR_INVALID_FORMAT;
|
||||||
|
goto free_luns;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config_setting_is_group(node)) {
|
||||||
|
ret = USBG_ERROR_INVALID_TYPE;
|
||||||
|
goto free_luns;
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs->luns[i] = malloc(sizeof(*(attrs->luns[i])));
|
||||||
|
if (!attrs->luns[i]) {
|
||||||
|
ret = USBG_ERROR_NO_MEM;
|
||||||
|
goto free_luns;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ms_import_lun_attrs(attrs->luns[i], node);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto free_luns;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = usbg_set_function_attrs(f, &f_attrs);
|
||||||
|
|
||||||
|
free_luns:
|
||||||
|
while (--i >= 0)
|
||||||
|
if (attrs->luns[i])
|
||||||
|
free(attrs->luns[i]);
|
||||||
|
free(attrs->luns);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ms_export_lun_attrs(usbg_f_ms_lun_attrs *lattrs,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
config_setting_t *node;
|
||||||
|
int cfg_ret;
|
||||||
|
int i;
|
||||||
|
int ret = USBG_ERROR_NO_MEM;
|
||||||
|
|
||||||
|
#define BOOL_ATTR(_name) { .name = #_name, .value = &lattrs->_name, }
|
||||||
|
struct {
|
||||||
|
char *name;
|
||||||
|
bool *value;
|
||||||
|
} bool_attrs[] = {
|
||||||
|
BOOL_ATTR(cdrom),
|
||||||
|
BOOL_ATTR(ro),
|
||||||
|
BOOL_ATTR(nofua),
|
||||||
|
BOOL_ATTR(removable),
|
||||||
|
};
|
||||||
|
#undef BOOL_ATTR
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(bool_attrs); ++i) {
|
||||||
|
node = config_setting_add(root, bool_attrs[i].name, CONFIG_TYPE_BOOL);
|
||||||
|
if (!node)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
cfg_ret = config_setting_set_bool(node, *(bool_attrs[i].value));
|
||||||
|
if (cfg_ret != CONFIG_TRUE) {
|
||||||
|
ret = USBG_ERROR_OTHER_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node = config_setting_add(root, "filename", CONFIG_TYPE_STRING);
|
||||||
|
if (!node)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
cfg_ret = config_setting_set_string(node, lattrs->filename);
|
||||||
|
ret = cfg_ret == CONFIG_TRUE ? USBG_SUCCESS : USBG_ERROR_OTHER_ERROR;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ms_libconfig_export(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
config_setting_t *luns_node, *node;
|
||||||
|
int i;
|
||||||
|
int cfg_ret, usbg_ret;
|
||||||
|
usbg_function_attrs f_attrs;
|
||||||
|
usbg_f_ms_attrs *attrs = &f_attrs.attrs.ms;
|
||||||
|
int ret = USBG_ERROR_NO_MEM;
|
||||||
|
|
||||||
|
usbg_ret = ms_get_attrs(f, &f_attrs);
|
||||||
|
if (usbg_ret != USBG_SUCCESS) {
|
||||||
|
ret = usbg_ret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = config_setting_add(root, "stall", CONFIG_TYPE_BOOL);
|
||||||
|
if (!node)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
cfg_ret = config_setting_set_bool(node, attrs->stall);
|
||||||
|
if (cfg_ret != CONFIG_TRUE) {
|
||||||
|
ret = USBG_ERROR_OTHER_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
luns_node = config_setting_add(root, "luns", CONFIG_TYPE_LIST);
|
||||||
|
if (!luns_node)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
for (i = 0; i < attrs->nluns; ++i) {
|
||||||
|
node = config_setting_add(luns_node, "", CONFIG_TYPE_GROUP);
|
||||||
|
if (!node)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = ms_export_lun_attrs(attrs->luns[i], node);
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = USBG_SUCCESS;
|
||||||
|
cleanup:
|
||||||
|
ms_cleanup_attrs(f, &f_attrs);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAS_LIBCONFIG */
|
||||||
|
|
||||||
|
static int ms_remove(struct usbg_function *f, int opts)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int nmb;
|
||||||
|
int i;
|
||||||
|
char lpath[USBG_MAX_PATH_LENGTH];
|
||||||
|
struct dirent **dent;
|
||||||
|
|
||||||
|
if (!(opts & USBG_RM_RECURSE))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = snprintf(lpath, sizeof(lpath), "%s/%s/", f->path, f->name);
|
||||||
|
if (ret >= sizeof(lpath)) {
|
||||||
|
ret = USBG_ERROR_PATH_TOO_LONG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
nmb = scandir(lpath, &dent, lun_select, lun_sort);
|
||||||
|
if (nmb < 0) {
|
||||||
|
ret = usbg_translate_error(errno);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = nmb - 1; i > 0; --i) {
|
||||||
|
ret = usbg_rm_dir(lpath, dent[i]->d_name);
|
||||||
|
free(dent[i]);
|
||||||
|
if (ret)
|
||||||
|
goto err_free_dent_loop;
|
||||||
|
}
|
||||||
|
free(dent[0]);
|
||||||
|
free(dent);
|
||||||
|
|
||||||
|
return USBG_SUCCESS;
|
||||||
|
|
||||||
|
err_free_dent_loop:
|
||||||
|
while (--i >= 0)
|
||||||
|
free(dent[i]);
|
||||||
|
free(dent[i]);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_ms = {
|
||||||
|
.name = "mass_storage",
|
||||||
|
.set_attrs = ms_set_attrs,
|
||||||
|
.get_attrs = ms_get_attrs,
|
||||||
|
.cleanup_attrs = ms_cleanup_attrs,
|
||||||
|
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
.import = ms_libconfig_import,
|
||||||
|
.export = ms_libconfig_export,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.remove = ms_remove,
|
||||||
|
};
|
||||||
|
|
79
src/function/phonet.c
Normal file
79
src/function/phonet.c
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* 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 <malloc.h>
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
#include <libconfig.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int phonet_set_attrs(struct usbg_function *f,
|
||||||
|
const usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
int ret = USBG_ERROR_INVALID_PARAM;
|
||||||
|
const usbg_f_phonet_attrs *attrs = &f_attrs->attrs.phonet;
|
||||||
|
|
||||||
|
if (f_attrs->header.attrs_type &&
|
||||||
|
f_attrs->header.attrs_type != USBG_F_ATTRS_PHONET)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = attrs->ifname && attrs->ifname[0] ?
|
||||||
|
USBG_ERROR_INVALID_PARAM : USBG_SUCCESS;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int phonet_get_attrs(struct usbg_function *f,
|
||||||
|
usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = usbg_read_string_alloc(f->path, f->name, "ifname",
|
||||||
|
&(f_attrs->attrs.phonet.ifname));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
f_attrs->header.attrs_type = USBG_F_ATTRS_PHONET;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void phonet_cleanup_attrs(struct usbg_function *f,
|
||||||
|
usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
free((char*)f_attrs->attrs.phonet.ifname);
|
||||||
|
f_attrs->attrs.phonet.ifname = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int phonet_libconfig_import(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
return USBG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int phonet_libconfig_export(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
return USBG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_phonet = {
|
||||||
|
.name = "phonet",
|
||||||
|
.set_attrs = phonet_set_attrs,
|
||||||
|
.get_attrs = phonet_get_attrs,
|
||||||
|
.cleanup_attrs = phonet_cleanup_attrs,
|
||||||
|
.import = phonet_libconfig_import,
|
||||||
|
.export = phonet_libconfig_export,
|
||||||
|
};
|
113
src/function/serial.c
Normal file
113
src/function/serial.c
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
#include <libconfig.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int serial_set_attrs(struct usbg_function *f,
|
||||||
|
const usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
int ret = USBG_ERROR_INVALID_PARAM;
|
||||||
|
|
||||||
|
if (f_attrs->header.attrs_type &&
|
||||||
|
f_attrs->header.attrs_type != USBG_F_ATTRS_SERIAL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = f_attrs->attrs.serial.port_num ?
|
||||||
|
USBG_ERROR_INVALID_PARAM : USBG_SUCCESS;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serial_get_attrs(struct usbg_function *f,
|
||||||
|
usbg_function_attrs *f_attrs)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = usbg_read_dec(f->path, f->name, "port_num",
|
||||||
|
&(f_attrs->attrs.serial.port_num));
|
||||||
|
if (ret != USBG_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
f_attrs->header.attrs_type = USBG_F_ATTRS_SERIAL;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAS_LIBCONFIG
|
||||||
|
|
||||||
|
static int serial_libconfig_export(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
config_setting_t *node;
|
||||||
|
usbg_function_attrs f_attrs;
|
||||||
|
usbg_f_serial_attrs *attrs = &f_attrs.attrs.serial;
|
||||||
|
int cfg_ret;
|
||||||
|
int ret = USBG_ERROR_NO_MEM;
|
||||||
|
|
||||||
|
ret = serial_get_attrs(f, &f_attrs);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
node = config_setting_add(root, "port_num", CONFIG_TYPE_INT);
|
||||||
|
if (!node) {
|
||||||
|
ret = USBG_ERROR_NO_MEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_ret = config_setting_set_int(node, attrs->port_num);
|
||||||
|
ret = cfg_ret == CONFIG_TRUE ? 0 : USBG_ERROR_OTHER_ERROR;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SERIAL_LIBCONFIG_DEP_OPS \
|
||||||
|
.export = serial_libconfig_export
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define SERIAL_LIBCONFIG_DEP_OPS
|
||||||
|
|
||||||
|
#endif /* HAS_LIBCONFIG */
|
||||||
|
|
||||||
|
static int serial_libconfig_import(struct usbg_function *f,
|
||||||
|
config_setting_t *root)
|
||||||
|
{
|
||||||
|
return USBG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We don' import port_num as it is read only */
|
||||||
|
#define SERIAL_FUNCTION_OPTS \
|
||||||
|
.set_attrs = serial_set_attrs, \
|
||||||
|
.get_attrs = serial_get_attrs, \
|
||||||
|
SERIAL_LIBCONFIG_DEP_OPS, \
|
||||||
|
.import = serial_libconfig_import
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_acm = {
|
||||||
|
.name = "acm",
|
||||||
|
SERIAL_FUNCTION_OPTS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_serial = {
|
||||||
|
.name = "gser",
|
||||||
|
SERIAL_FUNCTION_OPTS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct usbg_function_type usbg_f_type_obex = {
|
||||||
|
.name = "obex",
|
||||||
|
SERIAL_FUNCTION_OPTS
|
||||||
|
};
|
756
src/usbg.c
756
src/usbg.c
|
@ -33,29 +33,41 @@
|
||||||
* @file usbg.c
|
* @file usbg.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
extern struct usbg_function_type usbg_f_type_acm;
|
||||||
|
extern struct usbg_function_type usbg_f_type_serial;
|
||||||
|
extern struct usbg_function_type usbg_f_type_obex;
|
||||||
|
extern struct usbg_function_type usbg_f_type_ecm;
|
||||||
|
extern struct usbg_function_type usbg_f_type_subset;
|
||||||
|
extern struct usbg_function_type usbg_f_type_ncm;
|
||||||
|
extern struct usbg_function_type usbg_f_type_eem;
|
||||||
|
extern struct usbg_function_type usbg_f_type_rndis;
|
||||||
|
extern struct usbg_function_type usbg_f_type_ffs;
|
||||||
|
extern struct usbg_function_type usbg_f_type_midi;
|
||||||
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var function_names
|
* @var function_types
|
||||||
* @brief Name strings for supported USB function types
|
* @brief Types of functions supported by library
|
||||||
*/
|
*/
|
||||||
const char *function_names[] =
|
struct usbg_function_type* function_types[] = {
|
||||||
{
|
[F_ACM] = &usbg_f_type_acm,
|
||||||
"gser",
|
[F_SERIAL] = &usbg_f_type_serial,
|
||||||
"acm",
|
[F_OBEX] = &usbg_f_type_obex,
|
||||||
"obex",
|
[F_ECM] = &usbg_f_type_ecm,
|
||||||
"ecm",
|
[F_SUBSET] = &usbg_f_type_subset,
|
||||||
"geth",
|
[F_NCM] = &usbg_f_type_ncm,
|
||||||
"ncm",
|
[F_EEM] = &usbg_f_type_eem,
|
||||||
"eem",
|
[F_RNDIS] = &usbg_f_type_rndis,
|
||||||
"rndis",
|
[F_FFS] = &usbg_f_type_ffs,
|
||||||
"phonet",
|
[F_MIDI] = &usbg_f_type_midi,
|
||||||
"ffs",
|
[F_MASS_STORAGE] = &usbg_f_type_ms,
|
||||||
"mass_storage",
|
[F_PHONET] = &usbg_f_type_phonet,
|
||||||
"midi",
|
[F_LOOPBACK] = &usbg_f_type_loopback,
|
||||||
"Loopback",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ARRAY_SIZE_SENTINEL(function_names, USBG_FUNCTION_TYPE_MAX);
|
ARRAY_SIZE_SENTINEL(function_types, USBG_FUNCTION_TYPE_MAX);
|
||||||
|
|
||||||
const char *gadget_attr_names[] =
|
const char *gadget_attr_names[] =
|
||||||
{
|
{
|
||||||
|
@ -127,7 +139,7 @@ int usbg_lookup_function_type(const char *name)
|
||||||
return USBG_ERROR_INVALID_PARAM;
|
return USBG_ERROR_INVALID_PARAM;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!strcmp(name, function_names[i]))
|
if (!strcmp(name, function_types[i]->name))
|
||||||
return i;
|
return i;
|
||||||
i++;
|
i++;
|
||||||
} while (i != USBG_FUNCTION_TYPE_MAX);
|
} while (i != USBG_FUNCTION_TYPE_MAX);
|
||||||
|
@ -139,7 +151,7 @@ const char *usbg_get_function_type_str(usbg_function_type type)
|
||||||
{
|
{
|
||||||
return type >= USBG_FUNCTION_TYPE_MIN &&
|
return type >= USBG_FUNCTION_TYPE_MIN &&
|
||||||
type < USBG_FUNCTION_TYPE_MAX ?
|
type < USBG_FUNCTION_TYPE_MAX ?
|
||||||
function_names[type] : NULL;
|
function_types[type]->name : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usbg_lookup_gadget_attr(const char *name)
|
int usbg_lookup_gadget_attr(const char *name)
|
||||||
|
@ -188,7 +200,7 @@ const char *usbg_get_gadget_str_name(usbg_gadget_str str)
|
||||||
gadget_str_names[str] : NULL;
|
gadget_str_names[str] : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static usbg_error usbg_split_function_instance_type(const char *full_name,
|
static int usbg_split_function_instance_type(const char *full_name,
|
||||||
usbg_function_type *f_type, const char **instance)
|
usbg_function_type *f_type, const char **instance)
|
||||||
{
|
{
|
||||||
const char *dot;
|
const char *dot;
|
||||||
|
@ -281,6 +293,7 @@ static inline void usbg_free_function(usbg_function *f)
|
||||||
static void usbg_free_config(usbg_config *c)
|
static void usbg_free_config(usbg_config *c)
|
||||||
{
|
{
|
||||||
usbg_binding *b;
|
usbg_binding *b;
|
||||||
|
|
||||||
while (!TAILQ_EMPTY(&c->bindings)) {
|
while (!TAILQ_EMPTY(&c->bindings)) {
|
||||||
b = TAILQ_FIRST(&c->bindings);
|
b = TAILQ_FIRST(&c->bindings);
|
||||||
TAILQ_REMOVE(&c->bindings, b, bnode);
|
TAILQ_REMOVE(&c->bindings, b, bnode);
|
||||||
|
@ -413,8 +426,6 @@ out:
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usbg_rm_ms_function(usbg_function *f, int opts);
|
|
||||||
|
|
||||||
static usbg_function *usbg_allocate_function(const char *path,
|
static usbg_function *usbg_allocate_function(const char *path,
|
||||||
usbg_function_type type, const char *instance, usbg_gadget *parent)
|
usbg_function_type type, const char *instance, usbg_gadget *parent)
|
||||||
{
|
{
|
||||||
|
@ -444,16 +455,7 @@ static usbg_function *usbg_allocate_function(const char *path,
|
||||||
f->path = strdup(path);
|
f->path = strdup(path);
|
||||||
f->parent = parent;
|
f->parent = parent;
|
||||||
f->type = type;
|
f->type = type;
|
||||||
|
f->ops = function_types[type];
|
||||||
/* only composed functions (with subdirs) require this callback */
|
|
||||||
switch (usbg_lookup_function_attrs_type(type)) {
|
|
||||||
case USBG_F_ATTRS_MS:
|
|
||||||
f->rm_callback = usbg_rm_ms_function;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
f->rm_callback = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(f->path)) {
|
if (!(f->path)) {
|
||||||
free(f->name);
|
free(f->name);
|
||||||
|
@ -517,311 +519,6 @@ char *usbg_ether_ntoa_r(const struct ether_addr *addr, char *buf)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usbg_parse_function_net_attrs(usbg_function *f,
|
|
||||||
usbg_f_net_attrs *f_net_attrs)
|
|
||||||
{
|
|
||||||
struct ether_addr *addr;
|
|
||||||
struct ether_addr addr_buf;
|
|
||||||
char str_addr[USBG_MAX_STR_LENGTH];
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = usbg_read_string(f->path, f->name, "dev_addr", str_addr);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
addr = ether_aton_r(str_addr, &addr_buf);
|
|
||||||
if (addr) {
|
|
||||||
f_net_attrs->dev_addr = *addr;
|
|
||||||
} else {
|
|
||||||
ret = USBG_ERROR_IO;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = usbg_read_string(f->path, f->name, "host_addr", str_addr);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
addr = ether_aton_r(str_addr, &addr_buf);
|
|
||||||
if (addr) {
|
|
||||||
f_net_attrs->host_addr = *addr;
|
|
||||||
} else {
|
|
||||||
ret = USBG_ERROR_IO;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = usbg_read_dec(f->path, f->name, "qmult", &(f_net_attrs->qmult));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_string_alloc(f->path, f->name, "ifname",
|
|
||||||
&(f_net_attrs->ifname));
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_parse_function_ms_lun_attrs(const char *path, const char *lun,
|
|
||||||
usbg_f_ms_lun_attrs *lun_attrs)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
memset(lun_attrs, 0, sizeof(*lun_attrs));
|
|
||||||
|
|
||||||
ret = sscanf(lun, "lun.%d", &lun_attrs->id);
|
|
||||||
if (ret != 1)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_bool(path, lun, "cdrom", &(lun_attrs->cdrom));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_bool(path, lun, "ro", &(lun_attrs->ro));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_bool(path, lun, "nofua", &(lun_attrs->nofua));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_bool(path, lun, "removable", &(lun_attrs->removable));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_string_alloc(path, lun, "file",
|
|
||||||
&(lun_attrs->filename));
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lun_select(const struct dirent *dent)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int id;
|
|
||||||
|
|
||||||
ret = file_select(dent);
|
|
||||||
if (!ret)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = sscanf(dent->d_name, "lun.%d", &id);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lun_sort(const struct dirent **d1, const struct dirent **d2)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int id1, id2;
|
|
||||||
|
|
||||||
ret = sscanf((*d1)->d_name, "lun.%d", &id1);
|
|
||||||
if (ret != 1)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
ret = sscanf((*d2)->d_name, "lun.%d", &id2);
|
|
||||||
if (ret != 1)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (id1 < id2)
|
|
||||||
ret = 1;
|
|
||||||
|
|
||||||
return id1 < id2 ? -1 : id1 > id2;
|
|
||||||
err:
|
|
||||||
/*
|
|
||||||
* This should not happened because dentries has been
|
|
||||||
* already checked by lun_select function. This
|
|
||||||
* error procedure is just in case.
|
|
||||||
*/
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_parse_function_ms_attrs(usbg_function *f,
|
|
||||||
usbg_f_ms_attrs *f_ms_attrs)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int nmb;
|
|
||||||
int i = 0;
|
|
||||||
char fpath[USBG_MAX_PATH_LENGTH];
|
|
||||||
usbg_f_ms_lun_attrs *lun_attrs;
|
|
||||||
usbg_f_ms_lun_attrs **luns;
|
|
||||||
struct dirent **dent;
|
|
||||||
|
|
||||||
ret = usbg_read_bool(f->path, f->name, "stall",
|
|
||||||
&(f_ms_attrs->stall));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
|
|
||||||
nmb = snprintf(fpath, sizeof(fpath), "%s/%s/",
|
|
||||||
f->path, f->name);
|
|
||||||
if (nmb >= sizeof(fpath)) {
|
|
||||||
ret = USBG_ERROR_PATH_TOO_LONG;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
nmb = scandir(fpath, &dent, lun_select, lun_sort);
|
|
||||||
if (nmb < 0) {
|
|
||||||
ret = usbg_translate_error(errno);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
luns = calloc(nmb + 1, sizeof(*luns));
|
|
||||||
if (!luns) {
|
|
||||||
ret = USBG_ERROR_NO_MEM;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
f_ms_attrs->luns = luns;
|
|
||||||
f_ms_attrs->nluns = nmb;
|
|
||||||
|
|
||||||
for (i = 0; i < nmb; i++) {
|
|
||||||
lun_attrs = malloc(sizeof(*lun_attrs));
|
|
||||||
if (!lun_attrs) {
|
|
||||||
ret = USBG_ERROR_NO_MEM;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = usbg_parse_function_ms_lun_attrs(fpath, dent[i]->d_name,
|
|
||||||
lun_attrs);
|
|
||||||
if (ret != USBG_SUCCESS) {
|
|
||||||
free(lun_attrs);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
luns[i] = lun_attrs;
|
|
||||||
free(dent[i]);
|
|
||||||
}
|
|
||||||
free(dent);
|
|
||||||
|
|
||||||
return USBG_SUCCESS;
|
|
||||||
|
|
||||||
err:
|
|
||||||
while (i < nmb) {
|
|
||||||
free(dent[i]);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
free(dent);
|
|
||||||
|
|
||||||
usbg_cleanup_function_attrs(
|
|
||||||
container_of((usbg_f_attrs *)f_ms_attrs,
|
|
||||||
usbg_function_attrs, attrs));
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_parse_function_midi_attrs(usbg_function *f,
|
|
||||||
usbg_f_midi_attrs *attrs)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = usbg_read_dec(f->path, f->name, "index", &(attrs->index));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_string_alloc(f->path, f->name, "id", &(attrs->id));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_dec(f->path, f->name, "in_ports", (int*)&(attrs->in_ports));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_dec(f->path, f->name, "out_ports", (int*)&(attrs->out_ports));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_dec(f->path, f->name, "buflen", (int*)&(attrs->buflen));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_dec(f->path, f->name, "qlen", (int*)&(attrs->qlen));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_parse_function_loopback_attrs(usbg_function *f,
|
|
||||||
usbg_f_loopback_attrs *attrs)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = usbg_read_dec(f->path, f->name, "buflen", (int *)&(attrs->buflen));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_dec(f->path, f->name, "qlen", (int *)&(attrs->qlen));
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_parse_function_attrs(usbg_function *f,
|
|
||||||
usbg_function_attrs *f_attrs)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int attrs_type;
|
|
||||||
|
|
||||||
attrs_type = usbg_lookup_function_attrs_type(f->type);
|
|
||||||
if (attrs_type < 0) {
|
|
||||||
ret = attrs_type;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (attrs_type) {
|
|
||||||
case USBG_F_ATTRS_SERIAL:
|
|
||||||
f_attrs->header.attrs_type = USBG_F_ATTRS_SERIAL;
|
|
||||||
ret = usbg_read_dec(f->path, f->name, "port_num",
|
|
||||||
&(f_attrs->attrs.serial.port_num));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_NET:
|
|
||||||
f_attrs->header.attrs_type = USBG_F_ATTRS_NET;
|
|
||||||
ret = usbg_parse_function_net_attrs(f, &(f_attrs->attrs.net));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_PHONET:
|
|
||||||
f_attrs->header.attrs_type = USBG_F_ATTRS_PHONET;
|
|
||||||
ret = usbg_read_string_alloc(f->path, f->name, "ifname",
|
|
||||||
&(f_attrs->attrs.phonet.ifname));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_FFS:
|
|
||||||
{
|
|
||||||
usbg_f_ffs_attrs *ffs_attrs = &(f_attrs->attrs.ffs);
|
|
||||||
|
|
||||||
f_attrs->header.attrs_type = USBG_F_ATTRS_FFS;
|
|
||||||
ffs_attrs->dev_name = strdup(f->instance);
|
|
||||||
if (!ffs_attrs->dev_name)
|
|
||||||
ret = USBG_ERROR_NO_MEM;
|
|
||||||
else
|
|
||||||
ret = USBG_SUCCESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_MS:
|
|
||||||
f_attrs->header.attrs_type = USBG_F_ATTRS_MS;
|
|
||||||
ret = usbg_parse_function_ms_attrs(f, &(f_attrs->attrs.ms));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_MIDI:
|
|
||||||
f_attrs->header.attrs_type = USBG_F_ATTRS_MIDI;
|
|
||||||
ret = usbg_parse_function_midi_attrs(f, &(f_attrs->attrs.midi));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_LOOPBACK:
|
|
||||||
f_attrs->header.attrs_type = USBG_F_ATTRS_LOOPBACK;
|
|
||||||
ret = usbg_parse_function_loopback_attrs(f, &(f_attrs->attrs.loopback));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ERROR("Unsupported function type\n");
|
|
||||||
ret = USBG_ERROR_NOT_SUPPORTED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_parse_functions(const char *path, usbg_gadget *g)
|
static int usbg_parse_functions(const char *path, usbg_gadget *g)
|
||||||
{
|
{
|
||||||
usbg_function *f;
|
usbg_function *f;
|
||||||
|
@ -1502,45 +1199,6 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usbg_rm_ms_function(usbg_function *f, int opts)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int nmb;
|
|
||||||
int i;
|
|
||||||
char lpath[USBG_MAX_PATH_LENGTH];
|
|
||||||
struct dirent **dent;
|
|
||||||
|
|
||||||
ret = snprintf(lpath, sizeof(lpath), "%s/%s/", f->path, f->name);
|
|
||||||
if (ret >= sizeof(lpath)) {
|
|
||||||
ret = USBG_ERROR_PATH_TOO_LONG;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
nmb = scandir(lpath, &dent, lun_select, lun_sort);
|
|
||||||
if (nmb < 0) {
|
|
||||||
ret = usbg_translate_error(errno);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = nmb - 1; i > 0; --i) {
|
|
||||||
ret = usbg_rm_dir(lpath, dent[i]->d_name);
|
|
||||||
free(dent[i]);
|
|
||||||
if (ret)
|
|
||||||
goto err_free_dent_loop;
|
|
||||||
}
|
|
||||||
free(dent[0]);
|
|
||||||
free(dent);
|
|
||||||
|
|
||||||
return USBG_SUCCESS;
|
|
||||||
|
|
||||||
err_free_dent_loop:
|
|
||||||
while (--i >= 0)
|
|
||||||
free(dent[i]);
|
|
||||||
free(dent[i]);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int usbg_rm_function(usbg_function *f, int opts)
|
int usbg_rm_function(usbg_function *f, int opts)
|
||||||
{
|
{
|
||||||
int ret = USBG_ERROR_INVALID_PARAM;
|
int ret = USBG_ERROR_INVALID_PARAM;
|
||||||
|
@ -1574,8 +1232,8 @@ int usbg_rm_function(usbg_function *f, int opts)
|
||||||
} /* TAILQ_FOREACH */
|
} /* TAILQ_FOREACH */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->rm_callback) {
|
if (f->ops->remove) {
|
||||||
ret = f->rm_callback(f, opts);
|
ret = f->ops->remove(f, opts);
|
||||||
if (ret != USBG_SUCCESS)
|
if (ret != USBG_SUCCESS)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -2190,14 +1848,6 @@ int usbg_create_function(usbg_gadget *g, usbg_function_type type,
|
||||||
if (!g || !f)
|
if (!g || !f)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* if attrs type is set, check if it has correct type */
|
|
||||||
if (f_attrs && f_attrs->header.attrs_type) {
|
|
||||||
int attrs_type;
|
|
||||||
attrs_type = usbg_lookup_function_attrs_type(type);
|
|
||||||
if (attrs_type < 0 || attrs_type != f_attrs->header.attrs_type)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
/* If someone creates ffs function and doesn't pass instance name
|
/* If someone creates ffs function and doesn't pass instance name
|
||||||
this means that device name from attrs should be used */
|
this means that device name from attrs should be used */
|
||||||
|
@ -2233,24 +1883,31 @@ int usbg_create_function(usbg_gadget *g, usbg_function_type type,
|
||||||
|
|
||||||
free_space = sizeof(fpath) - n;
|
free_space = sizeof(fpath) - n;
|
||||||
n = snprintf(&(fpath[n]), free_space, "/%s", func->name);
|
n = snprintf(&(fpath[n]), free_space, "/%s", func->name);
|
||||||
if (n < free_space) {
|
if (n >= free_space) {
|
||||||
|
ret = USBG_ERROR_PATH_TOO_LONG;
|
||||||
|
goto free_func;
|
||||||
|
}
|
||||||
|
|
||||||
ret = mkdir(fpath, S_IRWXU | S_IRWXG | S_IRWXO);
|
ret = mkdir(fpath, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||||
if (!ret) {
|
if (ret) {
|
||||||
/* Success */
|
|
||||||
ret = USBG_SUCCESS;
|
|
||||||
if (f_attrs)
|
|
||||||
ret = usbg_set_function_attrs(func, f_attrs);
|
|
||||||
} else {
|
|
||||||
ret = usbg_translate_error(errno);
|
ret = usbg_translate_error(errno);
|
||||||
}
|
goto free_func;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == USBG_SUCCESS)
|
if (f_attrs) {
|
||||||
INSERT_TAILQ_STRING_ORDER(&g->functions, fhead, name,
|
ret = usbg_set_function_attrs(func, f_attrs);
|
||||||
func, fnode);
|
if (ret != USBG_SUCCESS)
|
||||||
else
|
goto remove_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
INSERT_TAILQ_STRING_ORDER(&g->functions, fhead, name, func, fnode);
|
||||||
|
|
||||||
|
return USBG_SUCCESS;
|
||||||
|
|
||||||
|
remove_dir:
|
||||||
|
usbg_rm_dir(fpath, "");
|
||||||
|
free_func:
|
||||||
usbg_free_function(func);
|
usbg_free_function(func);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2593,7 +2250,7 @@ usbg_function_type usbg_get_function_type(usbg_function *f)
|
||||||
|
|
||||||
int usbg_get_function_attrs(usbg_function *f, usbg_function_attrs *f_attrs)
|
int usbg_get_function_attrs(usbg_function *f, usbg_function_attrs *f_attrs)
|
||||||
{
|
{
|
||||||
return f && f_attrs ? usbg_parse_function_attrs(f, f_attrs)
|
return f && f_attrs ? f->ops->get_attrs(f, f_attrs)
|
||||||
: USBG_ERROR_INVALID_PARAM;
|
: USBG_ERROR_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2670,309 +2327,16 @@ void usbg_cleanup_function_attrs(usbg_function_attrs *f_attrs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int usbg_set_function_net_attrs(usbg_function *f, const usbg_f_net_attrs *attrs)
|
|
||||||
{
|
|
||||||
int ret = USBG_SUCCESS;
|
|
||||||
char addr_buf[USBG_MAX_STR_LENGTH];
|
|
||||||
char *addr;
|
|
||||||
|
|
||||||
/* ifname is read only so we accept only empty string for this param */
|
|
||||||
if (attrs->ifname && attrs->ifname[0]) {
|
|
||||||
ret = USBG_ERROR_INVALID_PARAM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr = usbg_ether_ntoa_r(&attrs->dev_addr, addr_buf);
|
|
||||||
ret = usbg_write_string(f->path, f->name, "dev_addr", addr);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
addr = usbg_ether_ntoa_r(&attrs->host_addr, addr_buf);
|
|
||||||
ret = usbg_write_string(f->path, f->name, "host_addr", addr);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_write_dec(f->path, f->name, "qmult", attrs->qmult);
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_set_f_ms_lun_attrs(const char *path, const char *lun,
|
|
||||||
usbg_f_ms_lun_attrs *lun_attrs)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = usbg_write_bool(path, lun, "cdrom", lun_attrs->cdrom);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_write_bool(path, lun, "ro", lun_attrs->ro);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_write_bool(path, lun, "nofua", lun_attrs->nofua);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_write_bool(path, lun, "removable", lun_attrs->removable);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_write_string(path, lun, "file",
|
|
||||||
lun_attrs->filename);
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_set_function_ms_attrs(usbg_function *f,
|
|
||||||
const usbg_f_ms_attrs *f_attrs)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int i, nmb;
|
|
||||||
int space_left;
|
|
||||||
char *new_lun_mask;
|
|
||||||
char lpath[USBG_MAX_PATH_LENGTH];
|
|
||||||
char *lpath_end;
|
|
||||||
DIR *dir;
|
|
||||||
struct dirent **dent;
|
|
||||||
|
|
||||||
ret = usbg_write_bool(f->path, f->name, "stall", f_attrs->stall);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* lun0 cannot be removed */
|
|
||||||
if (!f_attrs->luns || f_attrs->nluns <= 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = snprintf(lpath, sizeof(lpath), "%s/%s/", f->path, f->name);
|
|
||||||
if (ret >= sizeof(lpath)) {
|
|
||||||
ret = USBG_ERROR_PATH_TOO_LONG;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
lpath_end = lpath + strlen(lpath);
|
|
||||||
space_left = sizeof(lpath) - (lpath_end - lpath);
|
|
||||||
|
|
||||||
new_lun_mask = calloc(f_attrs->nluns, sizeof (char));
|
|
||||||
if (!new_lun_mask) {
|
|
||||||
ret = USBG_ERROR_NO_MEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < f_attrs->nluns; ++i) {
|
|
||||||
usbg_f_ms_lun_attrs *lun = f_attrs->luns[i];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* id may be left unset in lun attrs but
|
|
||||||
* if it is set it has to be equal to position
|
|
||||||
* in lun array
|
|
||||||
*/
|
|
||||||
if (lun && lun->id >= 0 && lun->id != i) {
|
|
||||||
ret = USBG_ERROR_INVALID_PARAM;
|
|
||||||
goto err_lun_loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = snprintf(lpath_end, space_left, "/lun.%d/", i);
|
|
||||||
if (ret >= space_left) {
|
|
||||||
ret = USBG_ERROR_PATH_TOO_LONG;
|
|
||||||
goto err_lun_loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if dir exist and create it if needed
|
|
||||||
*/
|
|
||||||
dir = opendir(lpath);
|
|
||||||
if (dir) {
|
|
||||||
closedir(dir);
|
|
||||||
} else if (errno != ENOENT) {
|
|
||||||
ret = usbg_translate_error(errno);
|
|
||||||
goto err_lun_loop;
|
|
||||||
} else {
|
|
||||||
ret = mkdir(lpath, S_IRWXU|S_IRWXG|S_IRWXO);
|
|
||||||
if (!ret) {
|
|
||||||
/*
|
|
||||||
* If we have created a new directory in
|
|
||||||
* this function let's mark it so we can
|
|
||||||
* cleanup in case of error
|
|
||||||
*/
|
|
||||||
new_lun_mask[i] = 1;
|
|
||||||
} else {
|
|
||||||
ret = usbg_translate_error(errno);
|
|
||||||
goto err_lun_loop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if attributes has not been provided just go to next one */
|
|
||||||
if (!lun)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ret = usbg_set_f_ms_lun_attrs(lpath, "", lun);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto err_lun_loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if function has more luns and remove them */
|
|
||||||
*lpath_end = '\0';
|
|
||||||
i = 0;
|
|
||||||
nmb = scandir(lpath, &dent, lun_select, lun_sort);
|
|
||||||
if (nmb < 0) {
|
|
||||||
ret = usbg_translate_error(errno);
|
|
||||||
goto err_lun_loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < f_attrs->nluns; ++i)
|
|
||||||
free(dent[i]);
|
|
||||||
|
|
||||||
for (; i < nmb; ++i) {
|
|
||||||
ret = usbg_rm_dir(lpath, dent[i]->d_name);
|
|
||||||
free(dent[i]);
|
|
||||||
/* There is no good way to recover form this */
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto err_rm_loop;
|
|
||||||
}
|
|
||||||
free(dent);
|
|
||||||
free(new_lun_mask);
|
|
||||||
|
|
||||||
return USBG_SUCCESS;
|
|
||||||
|
|
||||||
err_rm_loop:
|
|
||||||
while (++i < nmb)
|
|
||||||
free(dent[i]);
|
|
||||||
free(dent);
|
|
||||||
|
|
||||||
i = f_attrs->nluns;
|
|
||||||
err_lun_loop:
|
|
||||||
/* array is null terminated so we may access lun[nluns] */
|
|
||||||
for (; i >= 0; --i) {
|
|
||||||
if (!new_lun_mask[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ret = snprintf(lpath_end, space_left, "/lun.%d/", i);
|
|
||||||
if (ret >= space_left) {
|
|
||||||
/*
|
|
||||||
* This should not happen because if we were
|
|
||||||
* able to create this directory we should be
|
|
||||||
* also able to remove it.
|
|
||||||
*/
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
rmdir(lpath);
|
|
||||||
}
|
|
||||||
free(new_lun_mask);
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int usbg_set_function_midi_attrs(usbg_function *f,
|
|
||||||
const usbg_f_midi_attrs *attrs)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = usbg_write_dec(f->path, f->name, "index", attrs->index);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_write_string(f->path, f->name, "id", attrs->id);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_write_dec(f->path, f->name, "in_ports", attrs->in_ports);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_write_dec(f->path, f->name, "out_ports", attrs->out_ports);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_write_dec(f->path, f->name, "buflen", attrs->buflen);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_write_dec(f->path, f->name, "qlen", attrs->qlen);
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int usbg_set_function_loopback_attrs(usbg_function *f,
|
|
||||||
const usbg_f_loopback_attrs *attrs)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = usbg_write_dec(f->path, f->name, "buflen", attrs->buflen);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_write_dec(f->path, f->name, "qlen", attrs->qlen);
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int usbg_set_function_attrs(usbg_function *f,
|
int usbg_set_function_attrs(usbg_function *f,
|
||||||
const usbg_function_attrs *f_attrs)
|
const usbg_function_attrs *f_attrs)
|
||||||
{
|
{
|
||||||
int ret = USBG_ERROR_INVALID_PARAM;
|
int ret = USBG_ERROR_INVALID_PARAM;
|
||||||
int attrs_type;
|
|
||||||
|
|
||||||
if (!f || !f_attrs)
|
if (!f || !f_attrs)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
attrs_type = usbg_lookup_function_attrs_type(f->type);
|
ret = f->ops->set_attrs(f, f_attrs);
|
||||||
if (attrs_type < 0)
|
out:
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* if attrs type is set, check if it has correct type */
|
|
||||||
if (f_attrs->header.attrs_type && attrs_type != f_attrs->header.attrs_type)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
switch (attrs_type) {
|
|
||||||
case USBG_F_ATTRS_SERIAL:
|
|
||||||
/* port_num attribute is read only so we accept only 0
|
|
||||||
* and do nothing with it */
|
|
||||||
ret = f_attrs->attrs.serial.port_num ? USBG_ERROR_INVALID_PARAM
|
|
||||||
: USBG_SUCCESS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_NET:
|
|
||||||
ret = usbg_set_function_net_attrs(f, &f_attrs->attrs.net);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_PHONET:
|
|
||||||
/* ifname attribute is read only
|
|
||||||
* so we accept only empty string */
|
|
||||||
ret = f_attrs->attrs.phonet.ifname && f_attrs->attrs.phonet.ifname[0] ?
|
|
||||||
USBG_ERROR_INVALID_PARAM : USBG_SUCCESS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_FFS:
|
|
||||||
/* dev_name is a virtual attribute so allow only to use empty
|
|
||||||
* empty string which means nop */
|
|
||||||
ret = f_attrs->attrs.ffs.dev_name && f_attrs->attrs.ffs.dev_name[0] ?
|
|
||||||
USBG_ERROR_INVALID_PARAM : USBG_SUCCESS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_MS:
|
|
||||||
ret = usbg_set_function_ms_attrs(f, &f_attrs->attrs.ms);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_MIDI:
|
|
||||||
ret = usbg_set_function_midi_attrs(f, &f_attrs->attrs.midi);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_LOOPBACK:
|
|
||||||
ret = usbg_set_function_loopback_attrs(f, &f_attrs->attrs.loopback);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ERROR("Unsupported function type\n");
|
|
||||||
ret = USBG_ERROR_NOT_SUPPORTED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -313,263 +313,14 @@ static int usbg_export_gadget_configs(usbg_gadget *g, config_setting_t *root)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usbg_export_f_net_attrs(usbg_f_net_attrs *attrs,
|
|
||||||
config_setting_t *root)
|
|
||||||
{
|
|
||||||
config_setting_t *node;
|
|
||||||
char *addr;
|
|
||||||
char addr_buf[USBG_MAX_STR_LENGTH];
|
|
||||||
int cfg_ret;
|
|
||||||
int ret = USBG_ERROR_NO_MEM;
|
|
||||||
|
|
||||||
node = config_setting_add(root, "dev_addr", CONFIG_TYPE_STRING);
|
|
||||||
if (!node)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
addr = usbg_ether_ntoa_r(&attrs->dev_addr, addr_buf);
|
|
||||||
cfg_ret = config_setting_set_string(node, addr);
|
|
||||||
if (cfg_ret != CONFIG_TRUE) {
|
|
||||||
ret = USBG_ERROR_OTHER_ERROR;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
node = config_setting_add(root, "host_addr", CONFIG_TYPE_STRING);
|
|
||||||
if (!node)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
addr = usbg_ether_ntoa_r(&attrs->host_addr, addr_buf);
|
|
||||||
cfg_ret = config_setting_set_string(node, addr);
|
|
||||||
if (cfg_ret != CONFIG_TRUE) {
|
|
||||||
ret = USBG_ERROR_OTHER_ERROR;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
node = config_setting_add(root, "qmult", CONFIG_TYPE_INT);
|
|
||||||
if (!node)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
cfg_ret = config_setting_set_int(node, attrs->qmult);
|
|
||||||
ret = cfg_ret == CONFIG_TRUE ? 0 : USBG_ERROR_OTHER_ERROR;
|
|
||||||
|
|
||||||
/* if name is read only so we don't export it */
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_export_f_ms_lun_attrs(usbg_f_ms_lun_attrs *lattrs,
|
|
||||||
config_setting_t *root)
|
|
||||||
{
|
|
||||||
config_setting_t *node;
|
|
||||||
int cfg_ret;
|
|
||||||
int i;
|
|
||||||
int ret = USBG_ERROR_NO_MEM;
|
|
||||||
|
|
||||||
#define BOOL_ATTR(_name) { .name = #_name, .value = &lattrs->_name, }
|
|
||||||
struct {
|
|
||||||
char *name;
|
|
||||||
bool *value;
|
|
||||||
} bool_attrs[] = {
|
|
||||||
BOOL_ATTR(cdrom),
|
|
||||||
BOOL_ATTR(ro),
|
|
||||||
BOOL_ATTR(nofua),
|
|
||||||
BOOL_ATTR(removable),
|
|
||||||
};
|
|
||||||
#undef BOOL_ATTR
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(bool_attrs); ++i) {
|
|
||||||
node = config_setting_add(root, bool_attrs[i].name, CONFIG_TYPE_BOOL);
|
|
||||||
if (!node)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
cfg_ret = config_setting_set_bool(node, *(bool_attrs[i].value));
|
|
||||||
if (cfg_ret != CONFIG_TRUE) {
|
|
||||||
ret = USBG_ERROR_OTHER_ERROR;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node = config_setting_add(root, "filename", CONFIG_TYPE_STRING);
|
|
||||||
if (!node)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
cfg_ret = config_setting_set_string(node, lattrs->filename);
|
|
||||||
ret = cfg_ret == CONFIG_TRUE ? USBG_SUCCESS : USBG_ERROR_OTHER_ERROR;
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_export_f_ms_attrs(usbg_f_ms_attrs *attrs,
|
|
||||||
config_setting_t *root)
|
|
||||||
{
|
|
||||||
config_setting_t *luns_node, *node;
|
|
||||||
int i;
|
|
||||||
int cfg_ret;
|
|
||||||
int ret = USBG_ERROR_NO_MEM;
|
|
||||||
|
|
||||||
node = config_setting_add(root, "stall", CONFIG_TYPE_BOOL);
|
|
||||||
if (!node)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
cfg_ret = config_setting_set_bool(node, attrs->stall);
|
|
||||||
if (cfg_ret != CONFIG_TRUE) {
|
|
||||||
ret = USBG_ERROR_OTHER_ERROR;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
luns_node = config_setting_add(root, "luns", CONFIG_TYPE_LIST);
|
|
||||||
if (!luns_node)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
for (i = 0; i < attrs->nluns; ++i) {
|
|
||||||
node = config_setting_add(luns_node, "", CONFIG_TYPE_GROUP);
|
|
||||||
if (!node)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_export_f_ms_lun_attrs(attrs->luns[i], node);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = USBG_SUCCESS;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_export_f_midi_attrs(usbg_f_midi_attrs *attrs,
|
|
||||||
config_setting_t *root)
|
|
||||||
{
|
|
||||||
config_setting_t *node;
|
|
||||||
int cfg_ret;
|
|
||||||
int ret = USBG_ERROR_NO_MEM;
|
|
||||||
|
|
||||||
#define ADD_F_MIDI_INT_ATTR(attr, minval) \
|
|
||||||
do { \
|
|
||||||
if ((int)attrs->attr < minval) { \
|
|
||||||
ret = USBG_ERROR_INVALID_VALUE; \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
node = config_setting_add(root, #attr, CONFIG_TYPE_INT);\
|
|
||||||
if (!node) \
|
|
||||||
goto out; \
|
|
||||||
cfg_ret = config_setting_set_int(node, attrs->attr); \
|
|
||||||
if (cfg_ret != CONFIG_TRUE) { \
|
|
||||||
ret = USBG_ERROR_OTHER_ERROR; \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
ADD_F_MIDI_INT_ATTR(index, INT_MIN);
|
|
||||||
|
|
||||||
node = config_setting_add(root, "id", CONFIG_TYPE_STRING);
|
|
||||||
if (!node)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
cfg_ret = config_setting_set_string(node, attrs->id);
|
|
||||||
if (cfg_ret != CONFIG_TRUE) {
|
|
||||||
ret = USBG_ERROR_OTHER_ERROR;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ADD_F_MIDI_INT_ATTR(in_ports, 0);
|
|
||||||
ADD_F_MIDI_INT_ATTR(out_ports, 0);
|
|
||||||
ADD_F_MIDI_INT_ATTR(buflen, 0);
|
|
||||||
ADD_F_MIDI_INT_ATTR(qlen, 0);
|
|
||||||
|
|
||||||
#undef ADD_F_MIDI_INT_ATTR
|
|
||||||
|
|
||||||
ret = USBG_SUCCESS;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_export_f_loopback_attrs(usbg_f_loopback_attrs *attrs,
|
|
||||||
config_setting_t *root)
|
|
||||||
{
|
|
||||||
config_setting_t *node;
|
|
||||||
int cfg_ret;
|
|
||||||
int ret = USBG_ERROR_NO_MEM;
|
|
||||||
|
|
||||||
#define ADD_F_LOOPBACK_INT_ATTR(attr, minval) \
|
|
||||||
do { \
|
|
||||||
if ((int)attrs->attr < minval) { \
|
|
||||||
ret = USBG_ERROR_INVALID_VALUE; \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
node = config_setting_add(root, #attr, CONFIG_TYPE_INT);\
|
|
||||||
if (!node) \
|
|
||||||
goto out; \
|
|
||||||
cfg_ret = config_setting_set_int(node, attrs->attr); \
|
|
||||||
if (cfg_ret != CONFIG_TRUE) { \
|
|
||||||
ret = USBG_ERROR_OTHER_ERROR; \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
ADD_F_LOOPBACK_INT_ATTR(buflen, 0);
|
|
||||||
ADD_F_LOOPBACK_INT_ATTR(qlen, 0);
|
|
||||||
|
|
||||||
#undef ADD_F_LOOPBACK_INT_ATTR
|
|
||||||
|
|
||||||
ret = USBG_SUCCESS;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_export_function_attrs(usbg_function *f, config_setting_t *root)
|
static int usbg_export_function_attrs(usbg_function *f, config_setting_t *root)
|
||||||
{
|
{
|
||||||
config_setting_t *node;
|
int ret = USBG_ERROR_NOT_SUPPORTED;
|
||||||
usbg_function_attrs f_attrs;
|
|
||||||
int usbg_ret, cfg_ret;
|
|
||||||
int ret = USBG_ERROR_NO_MEM;
|
|
||||||
|
|
||||||
usbg_ret = usbg_get_function_attrs(f, &f_attrs);
|
if (!f->ops->export)
|
||||||
if (usbg_ret) {
|
|
||||||
ret = usbg_ret;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (f_attrs.header.attrs_type) {
|
|
||||||
case USBG_F_ATTRS_SERIAL:
|
|
||||||
node = config_setting_add(root, "port_num", CONFIG_TYPE_INT);
|
|
||||||
if (!node)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
cfg_ret = config_setting_set_int(node, f_attrs.attrs.serial.port_num);
|
ret = f->ops->export(f, root);
|
||||||
ret = cfg_ret == CONFIG_TRUE ? 0 : USBG_ERROR_OTHER_ERROR;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_NET:
|
|
||||||
ret = usbg_export_f_net_attrs(&f_attrs.attrs.net, root);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_MS:
|
|
||||||
ret = usbg_export_f_ms_attrs(&f_attrs.attrs.ms, root);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_MIDI:
|
|
||||||
ret = usbg_export_f_midi_attrs(&f_attrs.attrs.midi, root);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_LOOPBACK:
|
|
||||||
ret = usbg_export_f_loopback_attrs(&f_attrs.attrs.loopback, root);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_PHONET:
|
|
||||||
/* Don't export ifname because it is read only */
|
|
||||||
case USBG_F_ATTRS_FFS:
|
|
||||||
/* We don't need to export ffs attributes
|
|
||||||
* due to instance name export */
|
|
||||||
ret = USBG_SUCCESS;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR("Unsupported function type\n");
|
|
||||||
ret = USBG_ERROR_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
usbg_cleanup_function_attrs(&f_attrs);
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -937,10 +688,6 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define usbg_config_is_int(node) (config_setting_type(node) == CONFIG_TYPE_INT)
|
|
||||||
#define usbg_config_is_string(node) \
|
|
||||||
(config_setting_type(node) == CONFIG_TYPE_STRING)
|
|
||||||
|
|
||||||
static int split_function_label(const char *label, usbg_function_type *type,
|
static int split_function_label(const char *label, usbg_function_type *type,
|
||||||
const char **instance)
|
const char **instance)
|
||||||
{
|
{
|
||||||
|
@ -983,337 +730,14 @@ static void usbg_set_failed_import(config_t **to_set, config_t *failed)
|
||||||
*to_set = failed;
|
*to_set = failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usbg_import_f_net_attrs(config_setting_t *root, usbg_function *f)
|
|
||||||
{
|
|
||||||
config_setting_t *node;
|
|
||||||
int ret = USBG_SUCCESS;
|
|
||||||
int qmult;
|
|
||||||
struct ether_addr *addr;
|
|
||||||
struct ether_addr addr_buf;
|
|
||||||
const char *str;
|
|
||||||
|
|
||||||
#define GET_OPTIONAL_ADDR(NAME) \
|
|
||||||
do { \
|
|
||||||
node = config_setting_get_member(root, #NAME); \
|
|
||||||
if (node) { \
|
|
||||||
str = config_setting_get_string(node); \
|
|
||||||
if (!str) { \
|
|
||||||
ret = USBG_ERROR_INVALID_TYPE; \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
addr = ether_aton_r(str, &addr_buf); \
|
|
||||||
if (!addr) { \
|
|
||||||
ret = USBG_ERROR_INVALID_VALUE; \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
ret = usbg_set_net_##NAME(f, addr); \
|
|
||||||
if (ret != USBG_SUCCESS) \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
GET_OPTIONAL_ADDR(host_addr);
|
|
||||||
GET_OPTIONAL_ADDR(dev_addr);
|
|
||||||
|
|
||||||
#undef GET_OPTIONAL_ADDR
|
|
||||||
|
|
||||||
node = config_setting_get_member(root, "qmult");
|
|
||||||
if (node) {
|
|
||||||
if (!usbg_config_is_int(node)) {
|
|
||||||
ret = USBG_ERROR_INVALID_TYPE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
qmult = config_setting_get_int(node);
|
|
||||||
ret = usbg_set_net_qmult(f, qmult);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_import_f_ms_lun_attrs(usbg_f_ms_lun_attrs *lattrs,
|
|
||||||
config_setting_t *root)
|
|
||||||
{
|
|
||||||
config_setting_t *node;
|
|
||||||
int i;
|
|
||||||
int ret = USBG_ERROR_NO_MEM;
|
|
||||||
|
|
||||||
#define BOOL_ATTR(_name, _default_val) \
|
|
||||||
{ .name = #_name, .value = &lattrs->_name, }
|
|
||||||
struct {
|
|
||||||
char *name;
|
|
||||||
bool *value;
|
|
||||||
bool default_val;
|
|
||||||
} bool_attrs[] = {
|
|
||||||
BOOL_ATTR(cdrom, false),
|
|
||||||
BOOL_ATTR(ro, false),
|
|
||||||
BOOL_ATTR(nofua, false),
|
|
||||||
BOOL_ATTR(removable, true),
|
|
||||||
};
|
|
||||||
#undef BOOL_ATTR
|
|
||||||
|
|
||||||
memset(lattrs, 0, sizeof(*lattrs));
|
|
||||||
lattrs->id = -1;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(bool_attrs); ++i) {
|
|
||||||
*(bool_attrs[i].value) = bool_attrs[i].default_val;
|
|
||||||
|
|
||||||
node = config_setting_get_member(root, bool_attrs[i].name);
|
|
||||||
if (!node)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ret = config_setting_type(node);
|
|
||||||
switch (ret) {
|
|
||||||
case CONFIG_TYPE_INT:
|
|
||||||
*(bool_attrs[i].value) = !!config_setting_get_int(node);
|
|
||||||
break;
|
|
||||||
case CONFIG_TYPE_BOOL:
|
|
||||||
*(bool_attrs[i].value) = config_setting_get_bool(node);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = USBG_ERROR_INVALID_TYPE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node = config_setting_get_member(root, "filename");
|
|
||||||
if (node) {
|
|
||||||
if (!usbg_config_is_string(node)) {
|
|
||||||
ret = USBG_ERROR_INVALID_PARAM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
lattrs->filename = (char *)config_setting_get_string(node);
|
|
||||||
} else {
|
|
||||||
lattrs->filename = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = USBG_SUCCESS;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_import_f_ms_attrs(config_setting_t *root, usbg_function *f)
|
|
||||||
{
|
|
||||||
config_setting_t *luns_node, *node;
|
|
||||||
int i;
|
|
||||||
int ret = USBG_ERROR_NO_MEM;
|
|
||||||
usbg_function_attrs attrs;
|
|
||||||
usbg_f_ms_attrs *ms_attrs = &attrs.attrs.ms;
|
|
||||||
|
|
||||||
memset(&attrs, 0, sizeof(attrs));
|
|
||||||
|
|
||||||
node = config_setting_get_member(root, "stall");
|
|
||||||
if (node) {
|
|
||||||
ret = config_setting_type(node);
|
|
||||||
switch (ret) {
|
|
||||||
case CONFIG_TYPE_INT:
|
|
||||||
ms_attrs->stall = !!config_setting_get_int(node);
|
|
||||||
break;
|
|
||||||
case CONFIG_TYPE_BOOL:
|
|
||||||
ms_attrs->stall = config_setting_get_bool(node);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = USBG_ERROR_INVALID_TYPE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
luns_node = config_setting_get_member(root, "luns");
|
|
||||||
if (!node) {
|
|
||||||
ret = USBG_ERROR_INVALID_PARAM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config_setting_is_list(luns_node)) {
|
|
||||||
ret = USBG_ERROR_INVALID_TYPE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ms_attrs->nluns = config_setting_length(luns_node);
|
|
||||||
|
|
||||||
ms_attrs->luns = calloc(ms_attrs->nluns + 1, sizeof(*(ms_attrs->luns)));
|
|
||||||
if (!ms_attrs->luns) {
|
|
||||||
ret = USBG_ERROR_NO_MEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < ms_attrs->nluns; ++i) {
|
|
||||||
node = config_setting_get_elem(luns_node, i);
|
|
||||||
if (!node) {
|
|
||||||
ret = USBG_ERROR_INVALID_FORMAT;
|
|
||||||
goto free_luns;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config_setting_is_group(node)) {
|
|
||||||
ret = USBG_ERROR_INVALID_TYPE;
|
|
||||||
goto free_luns;
|
|
||||||
}
|
|
||||||
|
|
||||||
ms_attrs->luns[i] = malloc(sizeof(*(ms_attrs->luns[i])));
|
|
||||||
if (!ms_attrs->luns[i]) {
|
|
||||||
ret = USBG_ERROR_NO_MEM;
|
|
||||||
goto free_luns;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = usbg_import_f_ms_lun_attrs(ms_attrs->luns[i], node);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto free_luns;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = usbg_set_function_attrs(f, &attrs);
|
|
||||||
|
|
||||||
free_luns:
|
|
||||||
while (--i >= 0)
|
|
||||||
if (ms_attrs->luns[i])
|
|
||||||
free(ms_attrs->luns[i]);
|
|
||||||
free(ms_attrs->luns);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_import_f_midi_attrs(config_setting_t *root, usbg_function *f)
|
|
||||||
{
|
|
||||||
config_setting_t *node;
|
|
||||||
int ret = USBG_ERROR_NO_MEM;
|
|
||||||
int tmp;
|
|
||||||
usbg_function_attrs attrs;
|
|
||||||
usbg_f_midi_attrs *midi_attrs = &attrs.attrs.midi;
|
|
||||||
|
|
||||||
attrs.header.attrs_type = USBG_F_ATTRS_MIDI;
|
|
||||||
|
|
||||||
#define ADD_F_MIDI_INT_ATTR(attr, defval, minval) \
|
|
||||||
do { \
|
|
||||||
node = config_setting_get_member(root, #attr); \
|
|
||||||
if (node) { \
|
|
||||||
if (!usbg_config_is_int(node)) { \
|
|
||||||
ret = USBG_ERROR_INVALID_TYPE; \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
tmp = config_setting_get_int(node); \
|
|
||||||
if (tmp < minval) { \
|
|
||||||
ret = USBG_ERROR_INVALID_VALUE; \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
midi_attrs->attr = tmp; \
|
|
||||||
} else { \
|
|
||||||
midi_attrs->attr = defval; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
ADD_F_MIDI_INT_ATTR(index, -1, INT_MIN);
|
|
||||||
ADD_F_MIDI_INT_ATTR(in_ports, 1, 0);
|
|
||||||
ADD_F_MIDI_INT_ATTR(out_ports, 1, 0);
|
|
||||||
ADD_F_MIDI_INT_ATTR(buflen, 256, 0);
|
|
||||||
ADD_F_MIDI_INT_ATTR(qlen, 32, 0);
|
|
||||||
|
|
||||||
#undef ADD_F_MIDI_INT_ATTR
|
|
||||||
|
|
||||||
node = config_setting_get_member(root, "id");
|
|
||||||
if (node) {
|
|
||||||
if (!usbg_config_is_string(node)) {
|
|
||||||
ret = USBG_ERROR_INVALID_TYPE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
midi_attrs->id = config_setting_get_string(node);
|
|
||||||
} else {
|
|
||||||
midi_attrs->id = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ret = usbg_set_function_attrs(f, &attrs);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_import_f_loopback_attrs(config_setting_t *root, usbg_function *f)
|
|
||||||
{
|
|
||||||
config_setting_t *node;
|
|
||||||
int ret = USBG_ERROR_NO_MEM;
|
|
||||||
int tmp;
|
|
||||||
usbg_function_attrs attrs;
|
|
||||||
usbg_f_loopback_attrs *loopback_attrs = &attrs.attrs.loopback;
|
|
||||||
|
|
||||||
attrs.header.attrs_type = USBG_F_ATTRS_LOOPBACK;
|
|
||||||
|
|
||||||
#define ADD_F_LOOPBACK_INT_ATTR(attr, defval, minval) \
|
|
||||||
do { \
|
|
||||||
node = config_setting_get_member(root, #attr); \
|
|
||||||
if (node) { \
|
|
||||||
if (!usbg_config_is_int(node)) { \
|
|
||||||
ret = USBG_ERROR_INVALID_TYPE; \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
tmp = config_setting_get_int(node); \
|
|
||||||
if (tmp < minval) { \
|
|
||||||
ret = USBG_ERROR_INVALID_VALUE; \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
loopback_attrs->attr = tmp; \
|
|
||||||
} else { \
|
|
||||||
loopback_attrs->attr = defval; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
ADD_F_LOOPBACK_INT_ATTR(buflen, 4096, 0);
|
|
||||||
ADD_F_LOOPBACK_INT_ATTR(qlen, 32, 0);
|
|
||||||
|
|
||||||
#undef ADD_F_LOOPBACK_INT_ATTR
|
|
||||||
|
|
||||||
ret = usbg_set_function_attrs(f, &attrs);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usbg_import_function_attrs(config_setting_t *root, usbg_function *f)
|
static int usbg_import_function_attrs(config_setting_t *root, usbg_function *f)
|
||||||
{
|
{
|
||||||
int ret = USBG_SUCCESS;
|
int ret = USBG_ERROR_NOT_SUPPORTED;
|
||||||
int attrs_type;
|
|
||||||
|
|
||||||
attrs_type = usbg_lookup_function_attrs_type(f->type);
|
if (!f->ops->import)
|
||||||
if (attrs_type < 0) {
|
|
||||||
ret = attrs_type;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
switch (attrs_type) {
|
|
||||||
case USBG_F_ATTRS_SERIAL:
|
|
||||||
/* Don't import port_num because it is read only */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_NET:
|
|
||||||
ret = usbg_import_f_net_attrs(root, f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_PHONET:
|
|
||||||
/* Don't import ifname because it is read only */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_FFS:
|
|
||||||
/* We don't need to import ffs attributes
|
|
||||||
* due to instance name import */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_MS:
|
|
||||||
ret = usbg_import_f_ms_attrs(root, f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_MIDI:
|
|
||||||
ret = usbg_import_f_midi_attrs(root, f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USBG_F_ATTRS_LOOPBACK:
|
|
||||||
ret = usbg_import_f_loopback_attrs(root, f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ERROR("Unsupported function type\n");
|
|
||||||
ret = USBG_ERROR_NOT_SUPPORTED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ret = f->ops->import(f, root);
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue