xref: /openbmc/u-boot/common/eeprom/eeprom_field.c (revision 9d922450)
1 /*
2  * (C) Copyright 2009-2016 CompuLab, Ltd.
3  *
4  * Authors: Nikita Kiryanov <nikita@compulab.co.il>
5  *	    Igor Grinberg <grinberg@compulab.co.il>
6  *
7  * SPDX-License-Identifier:	GPL-2.0+
8  */
9 
10 #include <common.h>
11 #include <linux/string.h>
12 #include <eeprom_field.h>
13 
14 static void __eeprom_field_print_bin(const struct eeprom_field *field,
15 				     char *delimiter, bool reverse)
16 {
17 	int i;
18 	int from = reverse ? field->size - 1 : 0;
19 	int to = reverse ? 0 : field->size - 1;
20 
21 	printf(PRINT_FIELD_SEGMENT, field->name);
22 	for (i = from; i != to; reverse ? i-- : i++)
23 		printf("%02x%s", field->buf[i], delimiter);
24 
25 	printf("%02x\n", field->buf[i]);
26 }
27 
28 static int __eeprom_field_update_bin(struct eeprom_field *field,
29 				     const char *value, bool reverse)
30 {
31 	int len = strlen(value);
32 	int k, j, i = reverse ? len - 1 : 0;
33 	unsigned char byte;
34 	char *endptr;
35 
36 	/* each two characters in the string fit in one byte */
37 	if (len > field->size * 2)
38 		return -1;
39 
40 	memset(field->buf, 0, field->size);
41 
42 	/* i - string iterator, j - buf iterator */
43 	for (j = 0; j < field->size; j++) {
44 		byte = 0;
45 		char tmp[3] = { 0, 0, 0 };
46 
47 		if ((reverse && i < 0) || (!reverse && i >= len))
48 			break;
49 
50 		for (k = 0; k < 2; k++) {
51 			if (reverse && i == 0) {
52 				tmp[k] = value[i];
53 				break;
54 			}
55 
56 			tmp[k] = value[reverse ? i - 1 + k : i + k];
57 		}
58 
59 		byte = simple_strtoul(tmp, &endptr, 0);
60 		if (*endptr != '\0' || byte < 0)
61 			return -1;
62 
63 		field->buf[j] = byte;
64 		i = reverse ? i - 2 : i + 2;
65 	}
66 
67 	return 0;
68 }
69 
70 static int __eeprom_field_update_bin_delim(struct eeprom_field *field,
71 					   char *value, char *delimiter)
72 {
73 	int count = 0;
74 	int i, val;
75 	const char *tmp = value;
76 	char *tok;
77 	char *endptr;
78 
79 	tmp = strstr(tmp, delimiter);
80 	while (tmp != NULL) {
81 		count++;
82 		tmp++;
83 		tmp = strstr(tmp, delimiter);
84 	}
85 
86 	if (count > field->size)
87 		return -1;
88 
89 	tok = strtok(value, delimiter);
90 	for (i = 0; tok && i < field->size; i++) {
91 		val = simple_strtoul(tok, &endptr, 0);
92 		if (*endptr != '\0')
93 			return -1;
94 
95 		/* here we assume that each tok is no more than byte long */
96 		field->buf[i] = (unsigned char)val;
97 		tok = strtok(NULL, delimiter);
98 	}
99 
100 	return 0;
101 }
102 
103 /**
104  * eeprom_field_print_bin() - print a field which contains binary data
105  *
106  * Treat the field data as simple binary data, and print it as two digit
107  * hexadecimal values.
108  * Sample output:
109  *      Field Name       0102030405060708090a
110  *
111  * @field:	an initialized field to print
112  */
113 void eeprom_field_print_bin(const struct eeprom_field *field)
114 {
115 	__eeprom_field_print_bin(field, "", false);
116 }
117 
118 /**
119  * eeprom_field_update_bin() - Update field with new data in binary form
120  *
121  * @field:	an initialized field
122  * @value:	a string of values (i.e. "10b234a")
123  */
124 int eeprom_field_update_bin(struct eeprom_field *field, char *value)
125 {
126 	return __eeprom_field_update_bin(field, value, false);
127 }
128 
129 /**
130  * eeprom_field_update_reserved() - Update reserved field with new data in
131  *				    binary form
132  *
133  * @field:	an initialized field
134  * @value:	a space delimited string of byte values (i.e. "1 02 3 0x4")
135  */
136 int eeprom_field_update_reserved(struct eeprom_field *field, char *value)
137 {
138 	return __eeprom_field_update_bin_delim(field, value, " ");
139 }
140 
141 /**
142  * eeprom_field_print_bin_rev() - print a field which contains binary data in
143  *				  reverse order
144  *
145  * Treat the field data as simple binary data, and print it in reverse order
146  * as two digit hexadecimal values.
147  *
148  * Data in field:
149  *                      0102030405060708090a
150  * Sample output:
151  *      Field Name      0a090807060504030201
152  *
153  * @field:	an initialized field to print
154  */
155 void eeprom_field_print_bin_rev(const struct eeprom_field *field)
156 {
157 	__eeprom_field_print_bin(field, "", true);
158 }
159 
160 /**
161  * eeprom_field_update_bin_rev() - Update field with new data in binary form,
162  *				   storing it in reverse
163  *
164  * This function takes a string of byte values, and stores them
165  * in the field in the reverse order. i.e. if the input string was "1234",
166  * "3412" will be written to the field.
167  *
168  * @field:	an initialized field
169  * @value:	a string of byte values
170  */
171 int eeprom_field_update_bin_rev(struct eeprom_field *field, char *value)
172 {
173 	return __eeprom_field_update_bin(field, value, true);
174 }
175 
176 /**
177  * eeprom_field_print_mac_addr() - print a field which contains a mac address
178  *
179  * Treat the field data as simple binary data, and print it formatted as a MAC
180  * address.
181  * Sample output:
182  *      Field Name     01:02:03:04:05:06
183  *
184  * @field:	an initialized field to print
185  */
186 void eeprom_field_print_mac(const struct eeprom_field *field)
187 {
188 	__eeprom_field_print_bin(field, ":", false);
189 }
190 
191 /**
192  * eeprom_field_update_mac() - Update a mac address field which contains binary
193  *			       data
194  *
195  * @field:	an initialized field
196  * @value:	a colon delimited string of byte values (i.e. "1:02:3:ff")
197  */
198 int eeprom_field_update_mac(struct eeprom_field *field, char *value)
199 {
200 	return __eeprom_field_update_bin_delim(field, value, ":");
201 }
202 
203 /**
204  * eeprom_field_print_ascii() - print a field which contains ASCII data
205  * @field:	an initialized field to print
206  */
207 void eeprom_field_print_ascii(const struct eeprom_field *field)
208 {
209 	char format[8];
210 
211 	sprintf(format, "%%.%ds\n", field->size);
212 	printf(PRINT_FIELD_SEGMENT, field->name);
213 	printf(format, field->buf);
214 }
215 
216 /**
217  * eeprom_field_update_ascii() - Update field with new data in ASCII form
218  * @field:	an initialized field
219  * @value:	the new string data
220  *
221  * Returns 0 on success, -1 of failure (new string too long).
222  */
223 int eeprom_field_update_ascii(struct eeprom_field *field, char *value)
224 {
225 	if (strlen(value) >= field->size) {
226 		printf("%s: new data too long\n", field->name);
227 		return -1;
228 	}
229 
230 	strncpy((char *)field->buf, value, field->size - 1);
231 	field->buf[field->size - 1] = '\0';
232 
233 	return 0;
234 }
235 
236 /**
237  * eeprom_field_print_reserved() - print the "Reserved fields" field
238  *
239  * Print a notice that the following field_size bytes are reserved.
240  *
241  * Sample output:
242  *      Reserved fields              (64 bytes)
243  *
244  * @field:	an initialized field to print
245  */
246 void eeprom_field_print_reserved(const struct eeprom_field *field)
247 {
248 	printf(PRINT_FIELD_SEGMENT, "Reserved fields\t");
249 	printf("(%d bytes)\n", field->size);
250 }
251