9
0
Fork 0

Add function to parse a string in dfu format

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@pengutronix.de>
This commit is contained in:
Sascha Hauer 2014-07-17 08:12:09 +02:00
parent 55ebc38493
commit 057a57448d
8 changed files with 196 additions and 121 deletions

View File

@ -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);

View File

@ -64,6 +64,9 @@ config MENUTREE
select GLOB
select GLOB_SORT
config FILE_LIST
bool
menu "General Settings"
config LOCALVERSION

View File

@ -44,6 +44,7 @@ obj-$(CONFIG_SHELL_HUSH) += hush.o
obj-$(CONFIG_SHELL_SIMPLE) += parser.o
obj-$(CONFIG_UIMAGE) += image.o uimage.o
obj-$(CONFIG_MENUTREE) += menutree.o
obj-$(CONFIG_FILE_LIST) += file-list.o
quiet_cmd_pwd_h = PWDH $@
ifdef CONFIG_PASSWORD

113
common/file-list.c Normal file
View File

@ -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);
}

View File

@ -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

View File

@ -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)

26
include/file-list.h Normal file
View File

@ -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 */

View File

@ -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 *);