Merge branch 'master' of git://git.denx.de/u-boot-fsl-qoriq
[oweals/u-boot.git] / common / eeprom / eeprom_field.c
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 }