From aa9e60441095ee3f20a109742e3ba5cdfd28458b Mon Sep 17 00:00:00 2001 From: Nikita Kiryanov Date: Sat, 16 Apr 2016 17:55:03 +0300 Subject: cmd: eeprom: add support for layout aware commands Introduce the (optional) eeprom print and eeprom update commands. These commands are eeprom layout aware: * The eeprom print command prints the contents of the eeprom in a human readable way (eeprom layout fields, and data formatted to be fit for human consumption). * The eeprom update command allows user to update eeprom fields by specifying the field name, and providing the new data in a human readable format (same format as displayed by the eeprom print command). * Both commands can either auto detect the layout, or be told which layout to use. New CONFIG options: CONFIG_CMD_EEPROM_LAYOUT - enables commands. CONFIG_EEPROM_LAYOUT_HELP_STRING - tells user what layout names are supported Feature API: __weak int parse_layout_version(char *str) - override to provide your own layout name parsing __weak void __eeprom_layout_assign(struct eeprom_layout *layout, int layout_version); - override to setup the layout metadata based on the version __weak int eeprom_layout_detect(unsigned char *data) - override to provide your own algorithm for detecting layout version eeprom_field.c - contains various printing and updating functions for common types of eeprom fields. Can be used for defining custom layouts. Cc: Heiko Schocher Cc: Marek Vasut Cc: Simon Glass Cc: Igor Grinberg Cc: Tom Rini Signed-off-by: Nikita Kiryanov --- common/eeprom/eeprom_layout.c | 125 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 common/eeprom/eeprom_layout.c (limited to 'common/eeprom/eeprom_layout.c') diff --git a/common/eeprom/eeprom_layout.c b/common/eeprom/eeprom_layout.c new file mode 100644 index 0000000000..c05923328a --- /dev/null +++ b/common/eeprom/eeprom_layout.c @@ -0,0 +1,125 @@ +/* + * (C) Copyright 2009-2016 CompuLab, Ltd. + * + * Authors: Nikita Kiryanov + * Igor Grinberg + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#define NO_LAYOUT_FIELDS "Unknown layout. Dumping raw data\n" + +struct eeprom_field layout_unknown[1] = { + { NO_LAYOUT_FIELDS, 256, NULL, eeprom_field_print_bin, + eeprom_field_update_bin }, +}; + +/* + * eeprom_layout_detect() - detect layout based on the contents of the data. + * @data: Pointer to the data to be analyzed. + * + * Returns: the detected layout version. + */ +__weak int eeprom_layout_detect(unsigned char *data) +{ + return LAYOUT_VERSION_UNRECOGNIZED; +} + +/* + * __eeprom_layout_assign() - set the layout fields + * @layout: A pointer to an existing struct layout. + * @layout_version: The version number of the desired layout + */ +__weak void __eeprom_layout_assign(struct eeprom_layout *layout, + int layout_version) +{ + layout->fields = layout_unknown; + layout->num_of_fields = ARRAY_SIZE(layout_unknown); +} +void eeprom_layout_assign(struct eeprom_layout *layout, int layout_version) \ + __attribute__((weak, alias("__eeprom_layout_assign"))); + +/* + * eeprom_layout_print() - print the layout and the data which is assigned to it + * @layout: A pointer to an existing struct layout. + */ +static void eeprom_layout_print(const struct eeprom_layout *layout) +{ + int i; + struct eeprom_field *fields = layout->fields; + + for (i = 0; i < layout->num_of_fields; i++) + fields[i].print(&fields[i]); +} + +/* + * eeprom_layout_update_field() - update a single field in the layout data. + * @layout: A pointer to an existing struct layout. + * @field_name: The name of the field to update. + * @new_data: The new field data (a string. Format depends on the field) + * + * Returns: 0 on success, negative error value on failure. + */ +static int eeprom_layout_update_field(struct eeprom_layout *layout, + char *field_name, char *new_data) +{ + int i, err; + struct eeprom_field *fields = layout->fields; + + if (new_data == NULL) + return 0; + + if (field_name == NULL) + return -1; + + for (i = 0; i < layout->num_of_fields; i++) { + if (fields[i].name == RESERVED_FIELDS || + strcmp(fields[i].name, field_name)) + continue; + + err = fields[i].update(&fields[i], new_data); + if (err) + printf("Invalid data for field %s\n", field_name); + + return err; + } + + printf("No such field '%s'\n", field_name); + + return -1; +} + +/* + * eeprom_layout_setup() - setup layout struct with the layout data and + * metadata as dictated by layout_version + * @layout: A pointer to an existing struct layout. + * @buf: A buffer initialized with the eeprom data. + * @buf_size: Size of buf in bytes. + * @layout version: The version number of the layout. + */ +void eeprom_layout_setup(struct eeprom_layout *layout, unsigned char *buf, + unsigned int buf_size, int layout_version) +{ + int i; + + if (layout_version == LAYOUT_VERSION_AUTODETECT) + layout->layout_version = eeprom_layout_detect(buf); + else + layout->layout_version = layout_version; + + eeprom_layout_assign(layout, layout_version); + layout->data = buf; + for (i = 0; i < layout->num_of_fields; i++) { + layout->fields[i].buf = buf; + buf += layout->fields[i].size; + } + + layout->data_size = buf_size; + layout->print = eeprom_layout_print; + layout->update = eeprom_layout_update_field; +} -- cgit