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_field.c | 250 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 common/eeprom/eeprom_field.c (limited to 'common/eeprom/eeprom_field.c') diff --git a/common/eeprom/eeprom_field.c b/common/eeprom/eeprom_field.c new file mode 100644 index 0000000000..7f095a64a2 --- /dev/null +++ b/common/eeprom/eeprom_field.c @@ -0,0 +1,250 @@ +/* + * (C) Copyright 2009-2016 CompuLab, Ltd. + * + * Authors: Nikita Kiryanov + * Igor Grinberg + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +static void __eeprom_field_print_bin(const struct eeprom_field *field, + char *delimiter, bool reverse) +{ + int i; + int from = reverse ? field->size - 1 : 0; + int to = reverse ? 0 : field->size - 1; + + printf(PRINT_FIELD_SEGMENT, field->name); + for (i = from; i != to; reverse ? i-- : i++) + printf("%02x%s", field->buf[i], delimiter); + + printf("%02x\n", field->buf[i]); +} + +static int __eeprom_field_update_bin(struct eeprom_field *field, + const char *value, bool reverse) +{ + int len = strlen(value); + int k, j, i = reverse ? len - 1 : 0; + unsigned char byte; + char *endptr; + + /* each two characters in the string fit in one byte */ + if (len > field->size * 2) + return -1; + + memset(field->buf, 0, field->size); + + /* i - string iterator, j - buf iterator */ + for (j = 0; j < field->size; j++) { + byte = 0; + char tmp[3] = { 0, 0, 0 }; + + if ((reverse && i < 0) || (!reverse && i >= len)) + break; + + for (k = 0; k < 2; k++) { + if (reverse && i == 0) { + tmp[k] = value[i]; + break; + } + + tmp[k] = value[reverse ? i - 1 + k : i + k]; + } + + byte = simple_strtoul(tmp, &endptr, 0); + if (*endptr != '\0' || byte < 0) + return -1; + + field->buf[j] = byte; + i = reverse ? i - 2 : i + 2; + } + + return 0; +} + +static int __eeprom_field_update_bin_delim(struct eeprom_field *field, + char *value, char *delimiter) +{ + int count = 0; + int i, val; + const char *tmp = value; + char *tok; + char *endptr; + + tmp = strstr(tmp, delimiter); + while (tmp != NULL) { + count++; + tmp++; + tmp = strstr(tmp, delimiter); + } + + if (count > field->size) + return -1; + + tok = strtok(value, delimiter); + for (i = 0; tok && i < field->size; i++) { + val = simple_strtoul(tok, &endptr, 0); + if (*endptr != '\0') + return -1; + + /* here we assume that each tok is no more than byte long */ + field->buf[i] = (unsigned char)val; + tok = strtok(NULL, delimiter); + } + + return 0; +} + +/** + * eeprom_field_print_bin() - print a field which contains binary data + * + * Treat the field data as simple binary data, and print it as two digit + * hexadecimal values. + * Sample output: + * Field Name 0102030405060708090a + * + * @field: an initialized field to print + */ +void eeprom_field_print_bin(const struct eeprom_field *field) +{ + __eeprom_field_print_bin(field, "", false); +} + +/** + * eeprom_field_update_bin() - Update field with new data in binary form + * + * @field: an initialized field + * @value: a string of values (i.e. "10b234a") + */ +int eeprom_field_update_bin(struct eeprom_field *field, char *value) +{ + return __eeprom_field_update_bin(field, value, false); +} + +/** + * eeprom_field_update_reserved() - Update reserved field with new data in + * binary form + * + * @field: an initialized field + * @value: a space delimited string of byte values (i.e. "1 02 3 0x4") + */ +int eeprom_field_update_reserved(struct eeprom_field *field, char *value) +{ + return __eeprom_field_update_bin_delim(field, value, " "); +} + +/** + * eeprom_field_print_bin_rev() - print a field which contains binary data in + * reverse order + * + * Treat the field data as simple binary data, and print it in reverse order + * as two digit hexadecimal values. + * + * Data in field: + * 0102030405060708090a + * Sample output: + * Field Name 0a090807060504030201 + * + * @field: an initialized field to print + */ +void eeprom_field_print_bin_rev(const struct eeprom_field *field) +{ + __eeprom_field_print_bin(field, "", true); +} + +/** + * eeprom_field_update_bin_rev() - Update field with new data in binary form, + * storing it in reverse + * + * This function takes a string of byte values, and stores them + * in the field in the reverse order. i.e. if the input string was "1234", + * "3412" will be written to the field. + * + * @field: an initialized field + * @value: a string of byte values + */ +int eeprom_field_update_bin_rev(struct eeprom_field *field, char *value) +{ + return __eeprom_field_update_bin(field, value, true); +} + +/** + * eeprom_field_print_mac_addr() - print a field which contains a mac address + * + * Treat the field data as simple binary data, and print it formatted as a MAC + * address. + * Sample output: + * Field Name 01:02:03:04:05:06 + * + * @field: an initialized field to print + */ +void eeprom_field_print_mac(const struct eeprom_field *field) +{ + __eeprom_field_print_bin(field, ":", false); +} + +/** + * eeprom_field_update_mac() - Update a mac address field which contains binary + * data + * + * @field: an initialized field + * @value: a colon delimited string of byte values (i.e. "1:02:3:ff") + */ +int eeprom_field_update_mac(struct eeprom_field *field, char *value) +{ + return __eeprom_field_update_bin_delim(field, value, ":"); +} + +/** + * eeprom_field_print_ascii() - print a field which contains ASCII data + * @field: an initialized field to print + */ +void eeprom_field_print_ascii(const struct eeprom_field *field) +{ + char format[8]; + + sprintf(format, "%%.%ds\n", field->size); + printf(PRINT_FIELD_SEGMENT, field->name); + printf(format, field->buf); +} + +/** + * eeprom_field_update_ascii() - Update field with new data in ASCII form + * @field: an initialized field + * @value: the new string data + * + * Returns 0 on success, -1 of failure (new string too long). + */ +int eeprom_field_update_ascii(struct eeprom_field *field, char *value) +{ + if (strlen(value) >= field->size) { + printf("%s: new data too long\n", field->name); + return -1; + } + + strncpy((char *)field->buf, value, field->size - 1); + field->buf[field->size - 1] = '\0'; + + return 0; +} + +/** + * eeprom_field_print_reserved() - print the "Reserved fields" field + * + * Print a notice that the following field_size bytes are reserved. + * + * Sample output: + * Reserved fields (64 bytes) + * + * @field: an initialized field to print + */ +void eeprom_field_print_reserved(const struct eeprom_field *field) +{ + printf(PRINT_FIELD_SEGMENT, "Reserved fields\t"); + printf("(%d bytes)\n", field->size); +} -- cgit v1.2.1