| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * (C) Copyright 2009-2016 CompuLab, Ltd. |
| * |
| * Authors: Nikita Kiryanov <nikita@compulab.co.il> |
| * Igor Grinberg <grinberg@compulab.co.il> |
| */ |
| |
| #include <stdio.h> |
| #include <vsprintf.h> |
| #include <linux/string.h> |
| #include <eeprom_field.h> |
| |
| 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); |
| } |