[PATCH v2 06/16] libusbg: Add export gadget functionality

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Whole gadget setting process take a lot of simple
commands (or lines of code). Those shell commands
may take a while or require dedicated script and
hard-coding gadget configuration. To avoid such
situation add to library ability to export a whole
gadget into file.

Signed-off-by: Krzysztof Opasiak <k.opasiak@xxxxxxxxxxx>
---
 include/usbg/usbg.h |    8 ++
 src/usbg.c          |  314 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 322 insertions(+)

diff --git a/include/usbg/usbg.h b/include/usbg/usbg.h
index 02eb1dd..3a66ae3 100644
--- a/include/usbg/usbg.h
+++ b/include/usbg/usbg.h
@@ -915,6 +915,14 @@ extern int usbg_export_function(usbg_function *f, FILE *stream);
 extern int usbg_export_config(usbg_config *c, FILE *stream);
 
 /**
+ * @brief Exports whole gadget to file
+ * @param g Pointer to gadget to be exported
+ * @param stream where gadget should be saved
+ * @return 0 on success, usbg_error otherwise
+ */
+extern int usbg_export_gadget(usbg_gadget *g, FILE *stream);
+
+/**
  * @}
  */
 #endif /* __USBG_H__ */
diff --git a/src/usbg.c b/src/usbg.c
index 0c16113..ea4f85f 100644
--- a/src/usbg.c
+++ b/src/usbg.c
@@ -2476,6 +2476,7 @@ usbg_binding *usbg_get_next_binding(usbg_binding *b)
 #define USBG_ATTRS_TAG "attrs"
 #define USBG_STRINGS_TAG "strings"
 #define USBG_FUNCTIONS_TAG "functions"
+#define USBG_CONFIGS_TAG "configs"
 #define USBG_LANG_TAG "lang"
 #define USBG_TYPE_TAG "type"
 #define USBG_INSTANCE_TAG "instance"
@@ -2732,6 +2733,41 @@ out:
 
 }
 
+static int usbg_export_gadget_configs(usbg_gadget *g, config_setting_t *root)
+{
+	usbg_config *c;
+	config_setting_t *node, *id_node;
+	int ret = USBG_SUCCESS;
+	int cfg_ret;
+
+	TAILQ_FOREACH(c, &g->configs, cnode) {
+		node = config_setting_add(root, NULL, CONFIG_TYPE_GROUP);
+		if (!node) {
+			ret = USBG_ERROR_NO_MEM;
+			break;
+		}
+
+		id_node = config_setting_add(node, USBG_ID_TAG,
+					     CONFIG_TYPE_INT);
+		if (!id_node) {
+			ret = USBG_ERROR_NO_MEM;
+			break;
+		}
+
+		cfg_ret = config_setting_set_int(id_node, c->id);
+		if (cfg_ret != CONFIG_TRUE) {
+			ret = USBG_ERROR_OTHER_ERROR;
+			break;
+		}
+
+		ret = usbg_export_config_prep(c, node);
+		if (ret != USBG_SUCCESS)
+			break;
+	}
+
+	return ret;
+}
+
 static int usbg_export_f_net_attrs(usbg_f_net_attrs *attrs,
 				      config_setting_t *root)
 {
@@ -2853,6 +2889,258 @@ out:
 }
 
 
+static int usbg_export_gadget_functions(usbg_gadget *g, config_setting_t *root)
+{
+	usbg_function *f;
+	config_setting_t *node, *inst_node;
+	int ret = USBG_SUCCESS;
+	int cfg_ret;
+	char label[USBG_MAX_NAME_LENGTH];
+	char *func_label;
+	int nmb;
+
+	TAILQ_FOREACH(f, &g->functions, fnode) {
+		if (f->label) {
+			func_label = f->label;
+		} else {
+			nmb = generate_function_label(f, label, sizeof(label));
+			if (nmb >= sizeof(label)) {
+				ret = USBG_ERROR_OTHER_ERROR;
+				break;
+			}
+			func_label = label;
+		}
+
+		node = config_setting_add(root, func_label, CONFIG_TYPE_GROUP);
+		if (!node) {
+			ret = USBG_ERROR_NO_MEM;
+			break;
+		}
+
+		/* Add instance name to identify in this gadget */
+		inst_node = config_setting_add(node, USBG_INSTANCE_TAG,
+					  CONFIG_TYPE_STRING);
+		if (!inst_node) {
+			ret = USBG_ERROR_NO_MEM;
+			break;
+		}
+
+		cfg_ret = config_setting_set_string(inst_node, f->instance);
+		if (cfg_ret != CONFIG_TRUE) {
+			ret = USBG_ERROR_OTHER_ERROR;
+			break;
+		}
+
+		ret = usbg_export_function_prep(f, node);
+		if (ret != USBG_SUCCESS)
+			break;
+	}
+
+	return ret;
+}
+
+static int usbg_export_gadget_strs_lang(usbg_gadget *g, const char *lang_str,
+					config_setting_t *root)
+{
+	config_setting_t *node;
+	usbg_gadget_strs strs;
+	int lang;
+	int usbg_ret, cfg_ret;
+	int ret = USBG_ERROR_NO_MEM;
+
+	ret = sscanf(lang_str, "%x", &lang);
+	if (ret != 1) {
+		ret = USBG_ERROR_OTHER_ERROR;
+		goto out;
+	}
+
+	usbg_ret = usbg_get_gadget_strs(g, lang, &strs);
+	if (usbg_ret != USBG_SUCCESS) {
+		ret = usbg_ret;
+		goto out;
+	}
+
+	node = config_setting_add(root, USBG_LANG_TAG, CONFIG_TYPE_INT);
+	if (!node)
+		goto out;
+
+	cfg_ret = config_setting_set_format(node, CONFIG_FORMAT_HEX);
+	if (cfg_ret != CONFIG_TRUE) {
+		ret = USBG_ERROR_OTHER_ERROR;
+		goto out;
+	}
+
+	cfg_ret = config_setting_set_int(node, lang);
+	if (cfg_ret != CONFIG_TRUE) {
+		ret = USBG_ERROR_OTHER_ERROR;
+		goto out;
+	}
+
+#define ADD_GADGET_STR(str_name, field)					\
+	do {								\
+		node = config_setting_add(root, str_name, CONFIG_TYPE_STRING); \
+		if (!node)						\
+			goto out;					\
+		cfg_ret = config_setting_set_string(node, strs.field);	\
+		if (cfg_ret != CONFIG_TRUE) {				\
+			ret = USBG_ERROR_OTHER_ERROR;			\
+			goto out;					\
+		}							\
+	} while (0)
+
+	ADD_GADGET_STR("manufacturer", str_mnf);
+	ADD_GADGET_STR("product", str_prd);
+	ADD_GADGET_STR("serialnumber", str_ser);
+
+#undef ADD_GADGET_STR
+	ret = USBG_SUCCESS;
+out:
+	return ret;
+}
+
+static int usbg_export_gadget_strings(usbg_gadget *g, config_setting_t *root)
+{
+	config_setting_t *node;
+	int usbg_ret = USBG_SUCCESS;
+	int nmb, i;
+	int ret = USBG_ERROR_NO_MEM;
+	char spath[USBG_MAX_PATH_LENGTH];
+	struct dirent **dent;
+
+	nmb = snprintf(spath, sizeof(spath), "%s/%s/%s", g->path,
+		       g->name, STRINGS_DIR);
+	if (nmb >= sizeof(spath)) {
+		ret = USBG_ERROR_PATH_TOO_LONG;
+		goto out;
+	}
+
+	nmb = scandir(spath, &dent, file_select, alphasort);
+	if (nmb < 0) {
+		ret = usbg_translate_error(errno);
+		goto out;
+	}
+
+	for (i = 0; i < nmb; ++i) {
+		node = config_setting_add(root, NULL, CONFIG_TYPE_GROUP);
+		if (!node)
+			break;
+
+		usbg_ret = usbg_export_gadget_strs_lang(g, dent[i]->d_name,
+							node);
+		if (usbg_ret != USBG_SUCCESS)
+			break;
+
+		free(dent[i]);
+	}
+	/* This loop will be executed only if error occurred in previous one */
+	for (; i < nmb; ++i)
+		free(dent[i]);
+
+	free(dent);
+	ret = usbg_ret;
+out:
+	return ret;
+}
+
+static int usbg_export_gadget_attrs(usbg_gadget *g, config_setting_t *root)
+{
+	config_setting_t *node;
+	usbg_gadget_attrs attrs;
+	int usbg_ret, cfg_ret;
+	int ret = USBG_ERROR_NO_MEM;
+
+	usbg_ret = usbg_get_gadget_attrs(g, &attrs);
+	if (usbg_ret) {
+		ret = usbg_ret;
+		goto out;
+	}
+
+#define ADD_GADGET_ATTR(attr_name)					\
+	do {								\
+		node = config_setting_add(root, #attr_name, CONFIG_TYPE_INT); \
+		if (!node)						\
+			goto out;					\
+		cfg_ret = config_setting_set_format(node, CONFIG_FORMAT_HEX); \
+		if (cfg_ret != CONFIG_TRUE) {				\
+			ret = USBG_ERROR_OTHER_ERROR;			\
+			goto out;					\
+		}							\
+		cfg_ret = config_setting_set_int(node, attrs.attr_name); \
+		if (cfg_ret != CONFIG_TRUE) {				\
+			ret = USBG_ERROR_OTHER_ERROR;			\
+			goto out;					\
+		}							\
+	} while (0)
+
+	ADD_GADGET_ATTR(bcdUSB);
+	ADD_GADGET_ATTR(bDeviceClass);
+	ADD_GADGET_ATTR(bDeviceSubClass);
+	ADD_GADGET_ATTR(bDeviceProtocol);
+	ADD_GADGET_ATTR(bMaxPacketSize0);
+	ADD_GADGET_ATTR(idVendor);
+	ADD_GADGET_ATTR(idProduct);
+	ADD_GADGET_ATTR(bcdDevice);
+
+#undef ADD_GADGET_ATTR
+
+	ret = 0;
+out:
+	return ret;
+}
+
+static int usbg_export_gadget_prep(usbg_gadget *g, config_setting_t *root)
+{
+	config_setting_t *node;
+	int ret = USBG_ERROR_NO_MEM;
+	int usbg_ret;
+	int cfg_ret;
+
+	/* We don't export name tag because name should be given during
+	 * loading of gadget */
+
+	node = config_setting_add(root, USBG_ATTRS_TAG, CONFIG_TYPE_GROUP);
+	if (!node)
+		goto out;
+
+	usbg_ret = usbg_export_gadget_attrs(g, node);
+	if (usbg_ret) {
+		ret = usbg_ret;
+		goto out;
+	}
+
+	node = config_setting_add(root, USBG_STRINGS_TAG,
+				     CONFIG_TYPE_LIST);
+	if (!node)
+		goto out;
+
+	usbg_ret = usbg_export_gadget_strings(g, node);
+	if (usbg_ret) {
+		ret = usbg_ret;
+		goto out;
+	}
+
+	node = config_setting_add(root, USBG_FUNCTIONS_TAG,
+				  CONFIG_TYPE_GROUP);
+	if (!node)
+		goto out;
+
+	usbg_ret = usbg_export_gadget_functions(g, node);
+	if (usbg_ret) {
+		ret = usbg_ret;
+		goto out;
+	}
+
+	node = config_setting_add(root, USBG_CONFIGS_TAG,
+				     CONFIG_TYPE_LIST);
+	if (!node)
+		goto out;
+
+	usbg_ret = usbg_export_gadget_configs(g, node);
+	ret = usbg_ret;
+out:
+	return ret;
+}
+
 /* Export gadget/function/config API implementation */
 
 int usbg_export_function(usbg_function *f, FILE *stream)
@@ -2909,3 +3197,29 @@ out:
 	return ret;
 }
 
+int usbg_export_gadget(usbg_gadget *g, FILE *stream)
+{
+	config_t cfg;
+	config_setting_t *root;
+	int ret;
+
+	if (!g || !stream)
+		return USBG_ERROR_INVALID_PARAM;
+
+	config_init(&cfg);
+
+	/* Set format */
+	config_set_tab_width(&cfg, USBG_TAB_WIDTH);
+
+	/* Allways successful */
+	root = config_root_setting(&cfg);
+
+	ret = usbg_export_gadget_prep(g, root);
+	if (ret != USBG_SUCCESS)
+		goto out;
+
+	config_write(&cfg, stream);
+out:
+	config_destroy(&cfg);
+	return ret;
+}
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux