[PATCH 11/23] Add function to parse a string in dfu format

Sascha Hauer s.hauer at pengutronix.de
Mon Jul 21 08:14:35 PDT 2014


The dfu command parses a string which contains a list of
devices and flags. This format is useful for other users
aswell, so add common helper functions to parse it and
let the dfu command use this format.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 commands/dfu.c             |  90 +++---------------------------------
 common/Kconfig             |   3 ++
 common/Makefile            |   1 +
 common/file-list.c         | 113 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/Kconfig |   1 +
 drivers/usb/gadget/dfu.c   |  69 ++++++++++++++++-----------
 include/file-list.h        |  26 +++++++++++
 include/usb/dfu.h          |  14 +-----
 8 files changed, 196 insertions(+), 121 deletions(-)
 create mode 100644 common/file-list.c
 create mode 100644 include/file-list.h

diff --git a/commands/dfu.c b/commands/dfu.c
index a8948f1..1610349 100644
--- a/commands/dfu.c
+++ b/commands/dfu.c
@@ -24,71 +24,7 @@
 #include <fs.h>
 #include <xfuncs.h>
 #include <usb/dfu.h>
-
-#define PARSE_DEVICE	0
-#define PARSE_NAME	1
-#define PARSE_FLAGS	2
-
-static int dfu_do_parse_one(char *partstr, char **endstr, struct usb_dfu_dev *dfu)
-{
-	int i = 0, state = PARSE_DEVICE;
-	char device[PATH_MAX];
-	char name[PATH_MAX];
-
-	memset(device, 0, sizeof(device));
-	memset(name, 0, sizeof(name));
-	dfu->flags = 0;
-
-	while (*partstr && *partstr != ',') {
-		switch (state) {
-		case PARSE_DEVICE:
-			if (*partstr == '(') {
-				state = PARSE_NAME;
-				i = 0;
-			} else {
-				device[i++] = *partstr;
-			}
-			break;
-		case PARSE_NAME:
-			if (*partstr == ')') {
-				state = PARSE_FLAGS;
-				i = 0;
-			} else {
-				name[i++] = *partstr;
-			}
-			break;
-		case PARSE_FLAGS:
-			switch (*partstr) {
-			case 's':
-				dfu->flags |= DFU_FLAG_SAFE;
-				break;
-			case 'r':
-				dfu->flags |= DFU_FLAG_READBACK;
-				break;
-			case 'c':
-				dfu->flags |= DFU_FLAG_CREATE;
-				break;
-			default:
-				return -EINVAL;
-			}
-			break;
-		default:
-			return -EINVAL;
-		}
-		partstr++;
-	}
-
-	if (state != PARSE_FLAGS)
-		return -EINVAL;
-
-	dfu->name = xstrdup(name);
-	dfu->dev = xstrdup(device);
-	if (*partstr == ',')
-		partstr++;
-	*endstr = partstr;
-
-	return 0;
-}
+#include <linux/err.h>
 
 /* dfu /dev/self0(bootloader)sr,/dev/nand0.root.bb(root)
  *
@@ -97,9 +33,8 @@ static int dfu_do_parse_one(char *partstr, char **endstr, struct usb_dfu_dev *df
  */
 static int do_dfu(int argc, char *argv[])
 {
-	int n = 0;
 	struct usb_dfu_pdata pdata;
-	char *endptr, *argstr;
+	char *argstr;
 	struct usb_dfu_dev *dfu_alts = NULL;
 	int ret;
 
@@ -108,27 +43,16 @@ static int do_dfu(int argc, char *argv[])
 
 	argstr = argv[optind];
 
-	for (n = 0; *argstr; n++) {
-		dfu_alts = xrealloc(dfu_alts, sizeof(*dfu_alts) * (n + 1));
-		if (dfu_do_parse_one(argstr, &endptr, &dfu_alts[n])) {
-			printf("parse error\n");
-			ret = -EINVAL;
-			goto out;
-		}
-		argstr = endptr;
+	pdata.files = file_list_parse(argstr);
+	if (IS_ERR(pdata.files)) {
+		ret = PTR_ERR(pdata.files);
+		goto out;
 	}
 
-	pdata.alts = dfu_alts;
-	pdata.num_alts = n;
-
 	ret = usb_dfu_register(&pdata);
 
+	file_list_free(pdata.files);
 out:
-	while (n) {
-		n--;
-		free(dfu_alts[n].name);
-		free(dfu_alts[n].dev);
-	};
 
 	free(dfu_alts);
 
diff --git a/common/Kconfig b/common/Kconfig
index 469a5d7..5a2c125 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -72,6 +72,9 @@ config EFI_GUID
 config EFI_DEVICEPATH
 	bool
 
+config FILE_LIST
+	bool
+
 menu "General Settings"
 
 config LOCALVERSION
diff --git a/common/Makefile b/common/Makefile
index 4220e15..31a3ada 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_UIMAGE)		+= image.o uimage.o
 obj-$(CONFIG_MENUTREE)		+= menutree.o
 obj-$(CONFIG_EFI_GUID)		+= efi-guid.o
 obj-$(CONFIG_EFI_DEVICEPATH)	+= efi-devicepath.o
+obj-$(CONFIG_FILE_LIST)		+= file-list.o
 
 quiet_cmd_pwd_h = PWDH    $@
 ifdef CONFIG_PASSWORD
diff --git a/common/file-list.c b/common/file-list.c
new file mode 100644
index 0000000..90c0f42
--- /dev/null
+++ b/common/file-list.c
@@ -0,0 +1,113 @@
+#include <common.h>
+#include <malloc.h>
+#include <fs.h>
+#include <file-list.h>
+#include <linux/err.h>
+
+#define PARSE_DEVICE	0
+#define PARSE_NAME	1
+#define PARSE_FLAGS	2
+
+static int file_list_parse_one(struct file_list *files, const char *partstr, const char **endstr)
+{
+	int i = 0, state = PARSE_DEVICE;
+	char filename[PATH_MAX];
+	char name[PATH_MAX];
+	struct file_list_entry *entry = xzalloc(sizeof(*entry));
+
+	memset(filename, 0, sizeof(filename));
+	memset(name, 0, sizeof(name));
+
+	while (*partstr && *partstr != ',') {
+		switch (state) {
+		case PARSE_DEVICE:
+			if (*partstr == '(') {
+				state = PARSE_NAME;
+				i = 0;
+			} else {
+				filename[i++] = *partstr;
+			}
+			break;
+		case PARSE_NAME:
+			if (*partstr == ')') {
+				state = PARSE_FLAGS;
+				i = 0;
+			} else {
+				name[i++] = *partstr;
+			}
+			break;
+		case PARSE_FLAGS:
+			switch (*partstr) {
+			case 's':
+				entry->flags |= FILE_LIST_FLAG_SAFE;
+				break;
+			case 'r':
+				entry->flags |= FILE_LIST_FLAG_READBACK;
+				break;
+			case 'c':
+				entry->flags |= FILE_LIST_FLAG_CREATE;
+				break;
+			default:
+				return -EINVAL;
+			}
+			break;
+		default:
+			return -EINVAL;
+		}
+		partstr++;
+	}
+
+	if (state != PARSE_FLAGS)
+		return -EINVAL;
+
+	entry->name = xstrdup(name);
+	entry->filename = xstrdup(filename);
+	if (*partstr == ',')
+		partstr++;
+	*endstr = partstr;
+
+	list_add_tail(&entry->list, &files->list);
+
+	return 0;
+}
+
+struct file_list *file_list_parse(const char *str)
+{
+	struct file_list *files;
+	int ret;
+	const char *endptr;
+
+	files = xzalloc(sizeof(*files));
+
+	INIT_LIST_HEAD(&files->list);
+
+	while (*str) {
+		if (file_list_parse_one(files, str, &endptr)) {
+			printf("parse error\n");
+			ret = -EINVAL;
+			goto out;
+		}
+		str = endptr;
+
+		files->num_entries++;
+	}
+
+	return files;
+out:
+	free(files);
+
+	return ERR_PTR(ret);
+}
+
+void file_list_free(struct file_list *files)
+{
+	struct file_list_entry *entry, *tmp;
+
+	list_for_each_entry_safe(entry, tmp, &files->list, list) {
+		free(entry->name);
+		free(entry->filename);
+		free(entry);
+	}
+
+	free(files);
+}
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 806bb16..94d3bce 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -41,6 +41,7 @@ comment "USB Gadget drivers"
 
 config USB_GADGET_DFU
 	bool
+	select FILE_LIST
 	prompt "Device Firmware Update Gadget"
 
 config USB_GADGET_SERIAL
diff --git a/drivers/usb/gadget/dfu.c b/drivers/usb/gadget/dfu.c
index ac8ddb9..1db1932 100644
--- a/drivers/usb/gadget/dfu.c
+++ b/drivers/usb/gadget/dfu.c
@@ -126,10 +126,9 @@ enum dfu_state {
 #define CONFIG_USBD_DFU_XFER_SIZE     4096
 #define DFU_TEMPFILE "/dfu_temp"
 
-static int dfualt;
+struct file_list_entry *dfu_file_entry;
 static int dfufd = -EINVAL;
-static struct usb_dfu_dev *dfu_devs;
-static int dfu_num_alt;
+static struct file_list *dfu_files;
 static int dfudetach;
 
 /* USB DFU functional descriptor */
@@ -174,6 +173,7 @@ dfu_bind(struct usb_configuration *c, struct usb_function *f)
 	struct usb_composite_dev *cdev = c->cdev;
 	struct usb_descriptor_header **header;
 	struct usb_interface_descriptor *desc;
+	struct file_list_entry *fentry;
 	int i;
 	int			status;
 
@@ -182,9 +182,9 @@ dfu_bind(struct usb_configuration *c, struct usb_function *f)
 	if (status < 0)
 		return status;
 
-	header = xzalloc(sizeof(void *) * (dfu_num_alt + 2));
-	desc = xzalloc(sizeof(struct usb_interface_descriptor) * dfu_num_alt);
-	for (i = 0; i < dfu_num_alt; i++) {
+	header = xzalloc(sizeof(void *) * (dfu_files->num_entries + 2));
+	desc = xzalloc(sizeof(struct usb_interface_descriptor) * dfu_files->num_entries);
+	for (i = 0; i < dfu_files->num_entries; i++) {
 		desc[i].bLength =		USB_DT_INTERFACE_SIZE;
 		desc[i].bDescriptorType =	USB_DT_INTERFACE;
 		desc[i].bNumEndpoints	=	0;
@@ -206,9 +206,14 @@ dfu_bind(struct usb_configuration *c, struct usb_function *f)
 	if (status)
 		goto out;
 
-	for (i = 0; i < dfu_num_alt; i++)
+	i = 0;
+	file_list_for_each_entry(dfu_files, fentry) {
 		printf("dfu: register alt%d(%s) with device %s\n",
-				i, dfu_devs[i].name, dfu_devs[i].dev);
+				i, fentry->name, fentry->filename);
+		i++;
+	}
+
+	return 0;
 out:
 	free(desc);
 	free(header);
@@ -233,9 +238,19 @@ dfu_unbind(struct usb_configuration *c, struct usb_function *f)
 
 static int dfu_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
-	dfualt = alt;
+	struct file_list_entry	*fentry;
+	int i = 0;
 
-	return 0;
+	file_list_for_each_entry(dfu_files, fentry) {
+		if (i == alt) {
+			dfu_file_entry = fentry;
+			return 0;
+		}
+
+		i++;
+	}
+
+	return -EINVAL;
 }
 
 static int dfu_status(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
@@ -290,14 +305,14 @@ static int handle_dnload(struct usb_function *f, const struct usb_ctrlrequest *c
 
 	if (w_length == 0) {
 		dfu->dfu_state = DFU_STATE_dfuIDLE;
-		if (dfu_devs[dfualt].flags & DFU_FLAG_SAFE) {
+		if (dfu_file_entry->flags & FILE_LIST_FLAG_SAFE) {
 			int fd;
 			unsigned flags = O_WRONLY;
 
-			if (dfu_devs[dfualt].flags & DFU_FLAG_CREATE)
+			if (dfu_file_entry->flags & FILE_LIST_FLAG_CREATE)
 				flags |= O_CREAT | O_TRUNC;
 
-			fd = open(dfu_devs[dfualt].dev, flags);
+			fd = open(dfu_file_entry->filename, flags);
 			if (fd < 0) {
 				perror("open");
 				ret = -EINVAL;
@@ -310,7 +325,7 @@ static int handle_dnload(struct usb_function *f, const struct usb_ctrlrequest *c
 				ret = -EINVAL;
 				goto err_out;
 			}
-			ret = copy_file(DFU_TEMPFILE, dfu_devs[dfualt].dev, 0);
+			ret = copy_file(DFU_TEMPFILE, dfu_file_entry->filename, 0);
 			if (ret) {
 				printf("copy file failed\n");
 				ret = -EINVAL;
@@ -425,16 +440,16 @@ static int dfu_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 				value = -EINVAL;
 				goto out;
 			}
-			debug("dfu: starting download to %s\n", dfu_devs[dfualt].dev);
-			if (dfu_devs[dfualt].flags & DFU_FLAG_SAFE) {
+			debug("dfu: starting download to %s\n", dfu_file_entry->filename);
+			if (dfu_file_entry->flags & FILE_LIST_FLAG_SAFE) {
 				dfufd = open(DFU_TEMPFILE, O_WRONLY | O_CREAT);
 			} else {
 				unsigned flags = O_WRONLY;
 
-				if (dfu_devs[dfualt].flags & DFU_FLAG_CREATE)
+				if (dfu_file_entry->flags & FILE_LIST_FLAG_CREATE)
 					flags |= O_CREAT | O_TRUNC;
 
-				dfufd = open(dfu_devs[dfualt].dev, flags);
+				dfufd = open(dfu_file_entry->filename, flags);
 			}
 
 			if (dfufd < 0) {
@@ -456,12 +471,12 @@ static int dfu_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 			break;
 		case USB_REQ_DFU_UPLOAD:
 			dfu->dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
-			debug("dfu: starting upload from %s\n", dfu_devs[dfualt].dev);
-			if (!(dfu_devs[dfualt].flags & DFU_FLAG_READBACK)) {
+			debug("dfu: starting upload from %s\n", dfu_file_entry->filename);
+			if (!(dfu_file_entry->flags & FILE_LIST_FLAG_READBACK)) {
 				dfu->dfu_state = DFU_STATE_dfuERROR;
 				goto out;
 			}
-			dfufd = open(dfu_devs[dfualt].dev, O_RDONLY);
+			dfufd = open(dfu_file_entry->filename, O_RDONLY);
 			if (dfufd < 0) {
 				dfu->dfu_state = DFU_STATE_dfuERROR;
 				perror("open");
@@ -609,6 +624,7 @@ static int dfu_bind_config(struct usb_configuration *c)
 {
 	struct f_dfu *dfu;
 	struct usb_function *func;
+	struct file_list_entry *fentry;
 	int		status;
 	int i;
 
@@ -628,15 +644,17 @@ static int dfu_bind_config(struct usb_configuration *c)
 	dfu->dfu_state = DFU_STATE_appIDLE;
 	dfu->dfu_status = DFU_STATUS_OK;
 
-	dfu_string_defs = xzalloc(sizeof(struct usb_string) * (dfu_num_alt + 2));
+	dfu_string_defs = xzalloc(sizeof(struct usb_string) * (dfu_files->num_entries + 2));
 	dfu_string_defs[0].s = "Generic DFU";
 	dfu_string_defs[0].id = status;
-	for (i = 0; i < dfu_num_alt; i++) {
-		dfu_string_defs[i + 1].s = dfu_devs[i].name;
+	i = 0;
+	file_list_for_each_entry(dfu_files, fentry) {
+		dfu_string_defs[i + 1].s = fentry->name;
 		status = usb_string_id(c->cdev);
 		if (status < 0)
 			goto out;
 		dfu_string_defs[i + 1].id = status;
+		i++;
 	}
 	dfu_string_defs[i + 1].s = NULL;
 	dfu_string_table.strings = dfu_string_defs;
@@ -752,8 +770,7 @@ int usb_dfu_register(struct usb_dfu_pdata *pdata)
 {
 	int ret;
 
-	dfu_devs = pdata->alts;
-	dfu_num_alt = pdata->num_alts;
+	dfu_files = pdata->files;
 
 	ret = usb_composite_probe(&dfu_driver);
 	if (ret)
diff --git a/include/file-list.h b/include/file-list.h
new file mode 100644
index 0000000..608181f
--- /dev/null
+++ b/include/file-list.h
@@ -0,0 +1,26 @@
+#ifndef __FILE_LIST
+#define __FILE_LIST
+
+#define FILE_LIST_FLAG_SAFE	(1 << 0)
+#define FILE_LIST_FLAG_READBACK	(1 << 1)
+#define FILE_LIST_FLAG_CREATE	(1 << 2)
+
+struct file_list_entry {
+	char *name;
+	char *filename;
+	unsigned long flags;
+	struct list_head list;
+};
+
+struct file_list {
+	struct list_head list;
+	int num_entries;
+};
+
+struct file_list *file_list_parse(const char *str);
+void file_list_free(struct file_list *);
+
+#define file_list_for_each_entry(files, entry) \
+	list_for_each_entry(entry, &files->list, list)
+
+#endif /* __FILE_LIST */
diff --git a/include/usb/dfu.h b/include/usb/dfu.h
index db50437..f9dd381 100644
--- a/include/usb/dfu.h
+++ b/include/usb/dfu.h
@@ -21,20 +21,10 @@
  */
 
 #include <linux/types.h>
-
-#define DFU_FLAG_SAFE		(1 << 0)
-#define DFU_FLAG_READBACK	(1 << 1)
-#define DFU_FLAG_CREATE		(1 << 2)
-
-struct usb_dfu_dev {
-	char *name;
-	char *dev;
-	unsigned long flags;
-};
+#include <file-list.h>
 
 struct usb_dfu_pdata {
-	struct usb_dfu_dev	*alts;
-	int			num_alts;
+	struct file_list	*files;
 };
 
 int usb_dfu_register(struct usb_dfu_pdata *);
-- 
2.0.1




More information about the barebox mailing list