From: Chanho Park Date: Tue, 1 Dec 2015 10:39:02 +0000 (+0900) Subject: common: introduce factory_info command X-Git-Tag: submit/tizen/20160318.071304~26 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d82fb6dee5b1016fc61429c11e9dcf763321036d;p=profile%2Fcommon%2Fplatform%2Fkernel%2Fu-boot-artik.git common: introduce factory_info command This patch introduces factory_info command to save/load the factory information such as s/n, mac address. The command supports mmc interface to save/load data into mmc device. Please refer below command usage. "Factory Information commands", "list - List factory information\n" "factory_info load \n" " - Load factory information from the interface\n" "factory_info save \n" " - Save factory information to the interface\n" "factory_info read - Read a value of entity name\n" "factory_info write - Write a value of entity name\n" "factory_info clean - Clean factioy information\n" Change-Id: Ia1f4cebf264f6f573000d001fe24a6cc88c5a8e8 Signed-off-by: Chanho Park --- diff --git a/common/Makefile b/common/Makefile index d3921d76d..18780dcab 100644 --- a/common/Makefile +++ b/common/Makefile @@ -96,6 +96,7 @@ COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o COBJS-$(CONFIG_OF_LIBFDT) += cmd_fdt.o fdt_support.o +COBJS-$(CONFIG_FACTORY_INFO) += cmd_factory_info.o COBJS-$(CONFIG_CMD_FDOS) += cmd_fdos.o COBJS-$(CONFIG_CMD_FITUPD) += cmd_fitupd.o COBJS-$(CONFIG_CMD_FLASH) += cmd_flash.o diff --git a/common/cmd_factory_info.c b/common/cmd_factory_info.c new file mode 100644 index 000000000..c01913b80 --- /dev/null +++ b/common/cmd_factory_info.c @@ -0,0 +1,369 @@ +/* + * copyright (c) 2015 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Factory Information support */ +#include +#include +#include +#include +#include + +#define FACTORY_INFO_HEADER_MAGIC 0x46414354 +#define FACTORY_INFO_HEADER_MAJOR 0x0001 +#define FACTORY_INFO_HEADER_MINOR 0x0000 + +struct fi_header { + unsigned int magic; + unsigned short major; + unsigned short minor; + unsigned int total_count; /* A count of entities */ + unsigned int total_bytes; /* Last position of buffer */ +}; + +struct fi_entity_header { + unsigned int name_len; + unsigned int val_len; +}; + +struct fi_entity { + struct list_head link; + struct fi_entity_header e_hdr; + char *name; + char *val; +}; + +static struct list_head entity_list; +static struct fi_header f_hdr; +static int info_loaded; + +enum fi_state { + LOAD, + SAVE +}; + +static int fi_mmc_ops(int state, int dev, u32 blk, u32 cnt, void *addr) +{ + u32 n; + struct mmc *mmc = find_mmc_device(dev); + if (!mmc) { + printf("no mmc device at slot %x\n", dev); + return -1; + } + + mmc_init(mmc); + + if (state == LOAD) + n = mmc->block_dev.block_read(dev, blk, cnt, addr); + else + n = mmc->block_dev.block_write(dev, blk, cnt, addr); + + return (n == cnt) ? 0 : -1; +} + +static void factory_header_init(struct fi_header *hdr) +{ + hdr->magic = FACTORY_INFO_HEADER_MAGIC; + hdr->major = FACTORY_INFO_HEADER_MAJOR; + hdr->minor = FACTORY_INFO_HEADER_MINOR; + hdr->total_count = 0; + hdr->total_bytes = sizeof(struct fi_header); +} + +static int check_header(struct fi_header *hdr) +{ + if (hdr->magic != FACTORY_INFO_HEADER_MAGIC) + return -1; + + if (hdr->major != FACTORY_INFO_HEADER_MAJOR || + hdr->minor != FACTORY_INFO_HEADER_MINOR) + return -1; + + return 0; +} + +static inline char *alloc_string(const char *buf, int len) +{ + char *new_str = malloc(len + 1); + memcpy(new_str, buf, len); + new_str[len] = 0; + + return new_str; +} + +static struct fi_entity *alloc_new_entity(const char *name, int name_len, + const char *val, int val_len) +{ + struct fi_entity *entity = malloc(sizeof(struct fi_entity)); + entity->e_hdr.name_len = name_len; + entity->e_hdr.val_len = val_len; + entity->name = alloc_string(name, name_len); + entity->val = alloc_string(val, val_len); + return entity; +} + +static struct fi_entity *find_entity(const char *entity_name) +{ + struct fi_entity *pos; + + list_for_each_entry(pos, &entity_list, link) { + if (!strcmp(entity_name, pos->name)) + return pos; + } + + return NULL; +} + +/* Parse entities from memory buffer */ +static int fi_deserialize(char *buf) +{ + struct fi_entity *entity; + struct fi_entity_header hdr; + int i, offset = 0; + + memcpy(&f_hdr, buf, sizeof(struct fi_header)); + + if (check_header(&f_hdr)) + factory_header_init(&f_hdr); + + offset += sizeof(struct fi_header); + + for (i = 0; i < f_hdr.total_count; i++) { + memcpy(&hdr, buf + offset, sizeof(struct fi_entity_header)); + offset += sizeof(struct fi_entity_header); + + entity = alloc_new_entity(buf + offset, hdr.name_len, + buf + offset + hdr.name_len, hdr.val_len); + list_add_tail(&entity->link, &entity_list); + + offset += hdr.name_len + hdr.val_len; + + setenv(entity->name, entity->val); + } + + f_hdr.total_bytes = offset; + + info_loaded = 1; + + return 0; +} + +/* Store entities into memory buffer */ +static void fi_serialize(char *buf) +{ + int offset = 0; + struct fi_entity *pos; + + offset = sizeof(struct fi_header); + + list_for_each_entry(pos, &entity_list, link) { + memcpy(buf + offset, &pos->e_hdr, + sizeof(struct fi_entity_header)); + offset += sizeof(struct fi_entity_header); + memcpy(buf + offset, pos->name, pos->e_hdr.name_len); + offset += pos->e_hdr.name_len; + memcpy(buf + offset, pos->val, pos->e_hdr.val_len); + offset += pos->e_hdr.val_len; + } + + f_hdr.total_bytes = offset; + memcpy(buf, &f_hdr, sizeof(struct fi_header)); +} + +static void factory_info_destroy(void) +{ + struct fi_entity *pos, *tmp; + + list_for_each_entry_safe_reverse(pos, tmp, &entity_list, link) { + list_del(&pos->link); + free(pos->name); + free(pos->val); + free(pos); + } + + factory_header_init(&f_hdr); +} + +static int factory_info_load(const char *interface, const char *device, + const char *offset, const char *count) +{ + int err; + + if (info_loaded) + factory_info_destroy(); + + INIT_LIST_HEAD(&entity_list); + + if (!strncmp(interface, "mmc", 3)) { + int dev = simple_strtoul(device, NULL, 10); + u32 blk = simple_strtoul(offset, NULL, 16); + u32 cnt = simple_strtoul(count, NULL, 16); + err = fi_mmc_ops(LOAD, dev, blk, cnt, + (void *)CONFIG_FACTORY_INFO_BUF_ADDR); + if (err) + return err; + } + + return fi_deserialize((char *)CONFIG_FACTORY_INFO_BUF_ADDR); +} + +static int factory_info_save(const char *interface, const char *device, + const char *offset, const char *count) +{ + int err; + + if (!info_loaded) { + printf("Please load the information at first\n"); + return -1; + } + + fi_serialize((char *)CONFIG_FACTORY_INFO_BUF_ADDR); + + if (!strncmp(interface, "mmc", 3)) { + int dev = simple_strtoul(device, NULL, 10); + u32 blk = simple_strtoul(offset, NULL, 16); + u32 cnt = simple_strtoul(count, NULL, 16); + err = fi_mmc_ops(SAVE, dev, blk, cnt, + (void *)CONFIG_FACTORY_INFO_BUF_ADDR); + if (err) + return err; + } + + return 0; +} + +static int factory_info_read_entity(const char *entity_name) +{ + struct fi_entity *entity; + + if (!info_loaded) { + printf("Please load the information at first\n"); + return -1; + } + + entity = find_entity(entity_name); + if (entity) { + printf("%s\n", entity->val); + return 0; + } + + return -1; +} + +static void update_entity_value(struct fi_entity *entity, const char *value) +{ + free(entity->val); + entity->e_hdr.val_len = strlen(value); + entity->val = alloc_string(value, entity->e_hdr.val_len); +} + +static int factory_info_write_entity(const char *entity_name, + const char *value) +{ + struct fi_entity *entity; + + if (!info_loaded) { + printf("Please load the information at first\n"); + return -1; + } + + entity = find_entity(entity_name); + if (entity) + update_entity_value(entity, value); + else { + entity = alloc_new_entity(entity_name, strlen(entity_name), + value, strlen(value)); + list_add_tail(&entity->link, &entity_list); + f_hdr.total_count++; + f_hdr.total_bytes += sizeof(struct fi_entity_header) + + entity->e_hdr.name_len + entity->e_hdr.val_len; + } + + return 0; +} + +static int factory_info_list(void) +{ + struct fi_entity *pos; + + if (!info_loaded) { + printf("Please load the information at first\n"); + return -1; + } + + list_for_each_entry(pos, &entity_list, link) + printf("%s %s\n", pos->name, pos->val); + + return 0; +} + +static int factory_info_clean(void) +{ + if (!info_loaded) { + printf("Please load the information at first\n"); + return -1; + } + + factory_info_destroy(); + + return 0; +} + +int do_factory_info(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + switch (argc) { + case 6: + if (!strncmp(argv[1], "load", 4)) + factory_info_load(argv[2], argv[3], argv[4], + argv[5]); + else if (!strncmp(argv[1], "save", 4)) + factory_info_save(argv[2], argv[3], argv[4], + argv[5]); + case 4: + if (!strncmp(argv[1], "write", 5)) + factory_info_write_entity(argv[2], argv[3]); + break; + case 3: + if (!strncmp(argv[1], "read", 4)) + factory_info_read_entity(argv[2]); + break; + case 2: + if (!strncmp(argv[1], "list", 4)) + factory_info_list(); + else if (!strncmp(argv[1], "clean", 5)) + factory_info_clean(); + break; + case 1: + default: + return CMD_RET_USAGE; + } + + return 0; +} + +U_BOOT_CMD(factory_info, 6, 0, do_factory_info, + "Factory Information commands", + "list - List factory information\n" + "factory_info load \n" + " - Load factory information from the interface\n" + "factory_info save \n" + " - Save factory information to the interface\n" + "factory_info read - Read a value of entity name\n" + "factory_info write - Write a value of entity name\n" + "factory_info clean - Clean factioy information\n" +);