common: introduce factory_info command
authorChanho Park <chanho61.park@samsung.com>
Tue, 1 Dec 2015 10:39:02 +0000 (19:39 +0900)
committerChanho Park <chanho61.park@samsung.com>
Wed, 2 Dec 2015 02:39:17 +0000 (11:39 +0900)
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 <interface> <device> <offset> <cnt>\n"
"        - Load factory information from the interface\n"
"factory_info save <interface> <device> <offset> <cnt>\n"
"        - Save factory information to the interface\n"
"factory_info read <entity name> - Read a value of entity name\n"
"factory_info write <entity name> <val> - Write a value of entity name\n"
"factory_info clean - Clean factioy information\n"

Change-Id: Ia1f4cebf264f6f573000d001fe24a6cc88c5a8e8
Signed-off-by: Chanho Park <chanho61.park@samsung.com>
common/Makefile
common/cmd_factory_info.c [new file with mode: 0644]

index d3921d76d870c926d669113fce81f251bcfc6a6c..18780dcabb924ff8ad425788d3a8ae12a5f85785 100644 (file)
@@ -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 (file)
index 0000000..c01913b
--- /dev/null
@@ -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 <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <linux/list.h>
+#include <mmc.h>
+
+#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 <interface> <device> <offset> <cnt>\n"
+       "        - Load factory information from the interface\n"
+       "factory_info save <interface> <device> <offset> <cnt>\n"
+       "        - Save factory information to the interface\n"
+       "factory_info read <entity name> - Read a value of entity name\n"
+       "factory_info write <entity name> <val> - Write a value of entity name\n"
+       "factory_info clean - Clean factioy information\n"
+);