mirror of
https://github.com/linux-usb-gadgets/libusbgx.git
synced 2025-07-21 01:35:06 +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>
|
||||
#else
|
||||
typedef struct _should_not_be_used config_t;
|
||||
typedef struct _should_not_be_used config_setting_t;
|
||||
void config_destroy(config_t *config);
|
||||
#endif
|
||||
|
||||
|
@ -39,6 +40,37 @@
|
|||
})
|
||||
#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
|
||||
{
|
||||
char *path;
|
||||
|
@ -74,8 +106,6 @@ struct usbg_config
|
|||
int id;
|
||||
};
|
||||
|
||||
typedef int (*usbg_rm_function_callback)(usbg_function *, int);
|
||||
|
||||
struct usbg_function
|
||||
{
|
||||
TAILQ_ENTRY(usbg_function) fnode;
|
||||
|
@ -87,7 +117,7 @@ struct usbg_function
|
|||
/* Only for internal library usage */
|
||||
char *label;
|
||||
usbg_function_type type;
|
||||
usbg_rm_function_callback rm_callback;
|
||||
struct usbg_function_type *ops;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
|
||||
|
||||
int usbg_read_buf(const char *path, const char *name,
|
||||
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_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 */
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
AUTOMAKE_OPTIONS = std-options subdir-objects
|
||||
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
|
||||
libusbgx_la_SOURCES += usbg_schemes_libconfig.c
|
||||
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
|
||||
*/
|
||||
|
||||
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
|
||||
* @brief Name strings for supported USB function types
|
||||
* @var function_types
|
||||
* @brief Types of functions supported by library
|
||||
*/
|
||||
const char *function_names[] =
|
||||
{
|
||||
"gser",
|
||||
"acm",
|
||||
"obex",
|
||||
"ecm",
|
||||
"geth",
|
||||
"ncm",
|
||||
"eem",
|
||||
"rndis",
|
||||
"phonet",
|
||||
"ffs",
|
||||
"mass_storage",
|
||||
"midi",
|
||||
"Loopback",
|
||||
struct usbg_function_type* function_types[] = {
|
||||
[F_ACM] = &usbg_f_type_acm,
|
||||
[F_SERIAL] = &usbg_f_type_serial,
|
||||
[F_OBEX] = &usbg_f_type_obex,
|
||||
[F_ECM] = &usbg_f_type_ecm,
|
||||
[F_SUBSET] = &usbg_f_type_subset,
|
||||
[F_NCM] = &usbg_f_type_ncm,
|
||||
[F_EEM] = &usbg_f_type_eem,
|
||||
[F_RNDIS] = &usbg_f_type_rndis,
|
||||
[F_FFS] = &usbg_f_type_ffs,
|
||||
[F_MIDI] = &usbg_f_type_midi,
|
||||
[F_MASS_STORAGE] = &usbg_f_type_ms,
|
||||
[F_PHONET] = &usbg_f_type_phonet,
|
||||
[F_LOOPBACK] = &usbg_f_type_loopback,
|
||||
};
|
||||
|
||||
ARRAY_SIZE_SENTINEL(function_names, USBG_FUNCTION_TYPE_MAX);
|
||||
ARRAY_SIZE_SENTINEL(function_types, USBG_FUNCTION_TYPE_MAX);
|
||||
|
||||
const char *gadget_attr_names[] =
|
||||
{
|
||||
|
@ -127,7 +139,7 @@ int usbg_lookup_function_type(const char *name)
|
|||
return USBG_ERROR_INVALID_PARAM;
|
||||
|
||||
do {
|
||||
if (!strcmp(name, function_names[i]))
|
||||
if (!strcmp(name, function_types[i]->name))
|
||||
return i;
|
||||
i++;
|
||||
} 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 &&
|
||||
type < USBG_FUNCTION_TYPE_MAX ?
|
||||
function_names[type] : NULL;
|
||||
function_types[type]->name : NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const char *dot;
|
||||
|
@ -281,6 +293,7 @@ static inline void usbg_free_function(usbg_function *f)
|
|||
static void usbg_free_config(usbg_config *c)
|
||||
{
|
||||
usbg_binding *b;
|
||||
|
||||
while (!TAILQ_EMPTY(&c->bindings)) {
|
||||
b = TAILQ_FIRST(&c->bindings);
|
||||
TAILQ_REMOVE(&c->bindings, b, bnode);
|
||||
|
@ -413,8 +426,6 @@ out:
|
|||
return c;
|
||||
}
|
||||
|
||||
static int usbg_rm_ms_function(usbg_function *f, int opts);
|
||||
|
||||
static usbg_function *usbg_allocate_function(const char *path,
|
||||
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->parent = parent;
|
||||
f->type = 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;
|
||||
}
|
||||
f->ops = function_types[type];
|
||||
|
||||
if (!(f->path)) {
|
||||
free(f->name);
|
||||
|
@ -517,311 +519,6 @@ char *usbg_ether_ntoa_r(const struct ether_addr *addr, char *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)
|
||||
{
|
||||
usbg_function *f;
|
||||
|
@ -1502,45 +1199,6 @@ out:
|
|||
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 ret = USBG_ERROR_INVALID_PARAM;
|
||||
|
@ -1574,8 +1232,8 @@ int usbg_rm_function(usbg_function *f, int opts)
|
|||
} /* TAILQ_FOREACH */
|
||||
}
|
||||
|
||||
if (f->rm_callback) {
|
||||
ret = f->rm_callback(f, opts);
|
||||
if (f->ops->remove) {
|
||||
ret = f->ops->remove(f, opts);
|
||||
if (ret != USBG_SUCCESS)
|
||||
goto out;
|
||||
}
|
||||
|
@ -2190,14 +1848,6 @@ int usbg_create_function(usbg_gadget *g, usbg_function_type type,
|
|||
if (!g || !f)
|
||||
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 someone creates ffs function and doesn't pass instance name
|
||||
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;
|
||||
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);
|
||||
if (!ret) {
|
||||
/* Success */
|
||||
ret = USBG_SUCCESS;
|
||||
if (f_attrs)
|
||||
ret = usbg_set_function_attrs(func, f_attrs);
|
||||
} else {
|
||||
if (ret) {
|
||||
ret = usbg_translate_error(errno);
|
||||
}
|
||||
goto free_func;
|
||||
}
|
||||
|
||||
if (ret == USBG_SUCCESS)
|
||||
INSERT_TAILQ_STRING_ORDER(&g->functions, fhead, name,
|
||||
func, fnode);
|
||||
else
|
||||
if (f_attrs) {
|
||||
ret = usbg_set_function_attrs(func, f_attrs);
|
||||
if (ret != USBG_SUCCESS)
|
||||
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);
|
||||
|
||||
out:
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
const usbg_function_attrs *f_attrs)
|
||||
{
|
||||
int ret = USBG_ERROR_INVALID_PARAM;
|
||||
int attrs_type;
|
||||
|
||||
if (!f || !f_attrs)
|
||||
return ret;
|
||||
|
||||
attrs_type = usbg_lookup_function_attrs_type(f->type);
|
||||
if (attrs_type < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
ret = f->ops->set_attrs(f, f_attrs);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -313,263 +313,14 @@ static int usbg_export_gadget_configs(usbg_gadget *g, config_setting_t *root)
|
|||
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)
|
||||
{
|
||||
config_setting_t *node;
|
||||
usbg_function_attrs f_attrs;
|
||||
int usbg_ret, cfg_ret;
|
||||
int ret = USBG_ERROR_NO_MEM;
|
||||
int ret = USBG_ERROR_NOT_SUPPORTED;
|
||||
|
||||
usbg_ret = usbg_get_function_attrs(f, &f_attrs);
|
||||
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)
|
||||
if (!f->ops->export)
|
||||
goto out;
|
||||
|
||||
cfg_ret = config_setting_set_int(node, f_attrs.attrs.serial.port_num);
|
||||
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);
|
||||
ret = f->ops->export(f, root);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
@ -937,10 +688,6 @@ out:
|
|||
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,
|
||||
const char **instance)
|
||||
{
|
||||
|
@ -983,337 +730,14 @@ static void usbg_set_failed_import(config_t **to_set, config_t *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)
|
||||
{
|
||||
int ret = USBG_SUCCESS;
|
||||
int attrs_type;
|
||||
int ret = USBG_ERROR_NOT_SUPPORTED;
|
||||
|
||||
attrs_type = usbg_lookup_function_attrs_type(f->type);
|
||||
if (attrs_type < 0) {
|
||||
ret = attrs_type;
|
||||
if (!f->ops->import)
|
||||
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:
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue