]>
Commit | Line | Data |
---|---|---|
4f745bf4 HB |
1 | /* |
2 | * (C) Copyright 2011 | |
3 | * Holger Brunck, Keymile GmbH Hannover, holger.brunck@keymile.com | |
4 | * | |
5 | * See file CREDITS for list of people who contributed to this | |
6 | * project. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation; either version 2 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | * MA 02111-1307 USA | |
22 | */ | |
23 | ||
24 | #include <common.h> | |
25 | #include <hush.h> | |
26 | #include <i2c.h> | |
27 | #include "common.h" | |
28 | ||
29 | int ivm_calc_crc(unsigned char *buf, int len) | |
30 | { | |
31 | const unsigned short crc_tab[16] = { | |
32 | 0x0000, 0xCC01, 0xD801, 0x1400, | |
33 | 0xF001, 0x3C00, 0x2800, 0xE401, | |
34 | 0xA001, 0x6C00, 0x7800, 0xB401, | |
35 | 0x5000, 0x9C01, 0x8801, 0x4400}; | |
36 | ||
37 | unsigned short crc = 0; /* final result */ | |
38 | unsigned short r1 = 0; /* temp */ | |
39 | unsigned char byte = 0; /* input buffer */ | |
40 | int i; | |
41 | ||
42 | /* calculate CRC from array data */ | |
43 | for (i = 0; i < len; i++) { | |
44 | byte = buf[i]; | |
45 | ||
46 | /* lower 4 bits */ | |
47 | r1 = crc_tab[crc & 0xF]; | |
48 | crc = ((crc) >> 4) & 0x0FFF; | |
49 | crc = crc ^ r1 ^ crc_tab[byte & 0xF]; | |
50 | ||
51 | /* upper 4 bits */ | |
52 | r1 = crc_tab[crc & 0xF]; | |
53 | crc = (crc >> 4) & 0x0FFF; | |
54 | crc = crc ^ r1 ^ crc_tab[(byte >> 4) & 0xF]; | |
55 | } | |
56 | return crc; | |
57 | } | |
58 | ||
59 | static int ivm_set_value(char *name, char *value) | |
60 | { | |
61 | char tempbuf[256]; | |
62 | ||
63 | if (value != NULL) { | |
64 | sprintf(tempbuf, "%s=%s", name, value); | |
65 | return set_local_var(tempbuf, 0); | |
66 | } else { | |
67 | unset_local_var(name); | |
68 | } | |
69 | return 0; | |
70 | } | |
71 | ||
72 | static int ivm_get_value(unsigned char *buf, int len, char *name, int off, | |
73 | int check) | |
74 | { | |
75 | unsigned short val; | |
76 | unsigned char valbuf[30]; | |
77 | ||
78 | if ((buf[off + 0] != buf[off + 2]) && | |
79 | (buf[off + 2] != buf[off + 4])) { | |
80 | printf("%s Error corrupted %s\n", __func__, name); | |
81 | val = -1; | |
82 | } else { | |
83 | val = buf[off + 0] + (buf[off + 1] << 8); | |
84 | if ((val == 0) && (check == 1)) | |
85 | val = -1; | |
86 | } | |
87 | sprintf((char *)valbuf, "%x", val); | |
88 | ivm_set_value(name, (char *)valbuf); | |
89 | return val; | |
90 | } | |
91 | ||
92 | #define INV_BLOCKSIZE 0x100 | |
93 | #define INV_DATAADDRESS 0x21 | |
94 | #define INVENTORYDATASIZE (INV_BLOCKSIZE - INV_DATAADDRESS - 3) | |
95 | ||
96 | #define IVM_POS_SHORT_TEXT 0 | |
97 | #define IVM_POS_MANU_ID 1 | |
98 | #define IVM_POS_MANU_SERIAL 2 | |
99 | #define IVM_POS_PART_NUMBER 3 | |
100 | #define IVM_POS_BUILD_STATE 4 | |
101 | #define IVM_POS_SUPPLIER_PART_NUMBER 5 | |
102 | #define IVM_POS_DELIVERY_DATE 6 | |
103 | #define IVM_POS_SUPPLIER_BUILD_STATE 7 | |
104 | #define IVM_POS_CUSTOMER_ID 8 | |
105 | #define IVM_POS_CUSTOMER_PROD_ID 9 | |
106 | #define IVM_POS_HISTORY 10 | |
107 | #define IVM_POS_SYMBOL_ONLY 11 | |
108 | ||
109 | static char convert_char(char c) | |
110 | { | |
111 | return (c < ' ' || c > '~') ? '.' : c; | |
112 | } | |
113 | ||
114 | static int ivm_findinventorystring(int type, | |
115 | unsigned char *const string, | |
116 | unsigned long maxlen, | |
117 | unsigned char *buf) | |
118 | { | |
119 | int xcode = 0; | |
120 | unsigned long cr = 0; | |
121 | unsigned long addr = INV_DATAADDRESS; | |
122 | unsigned long size = 0; | |
123 | unsigned long nr = type; | |
124 | int stop = 0; /* stop on semicolon */ | |
125 | ||
126 | memset(string, '\0', maxlen); | |
127 | switch (type) { | |
128 | case IVM_POS_SYMBOL_ONLY: | |
129 | nr = 0; | |
130 | stop = 1; | |
131 | break; | |
132 | default: | |
133 | nr = type; | |
134 | stop = 0; | |
135 | } | |
136 | ||
137 | /* Look for the requested number of CR. */ | |
138 | while ((cr != nr) && (addr < INVENTORYDATASIZE)) { | |
139 | if ((buf[addr] == '\r')) | |
140 | cr++; | |
141 | addr++; | |
142 | } | |
143 | ||
144 | /* | |
145 | * the expected number of CR was found until the end of the IVM | |
146 | * content --> fill string | |
147 | */ | |
148 | if (addr < INVENTORYDATASIZE) { | |
149 | /* Copy the IVM string in the corresponding string */ | |
150 | for (; (buf[addr] != '\r') && | |
151 | ((buf[addr] != ';') || (!stop)) && | |
152 | (size < (maxlen - 1) && | |
153 | (addr < INVENTORYDATASIZE)); addr++) { | |
154 | size += sprintf((char *)string + size, "%c", | |
155 | convert_char (buf[addr])); | |
156 | } | |
157 | ||
158 | /* | |
159 | * copy phase is done: check if everything is ok. If not, | |
160 | * the inventory data is most probably corrupted: tell | |
161 | * the world there is a problem! | |
162 | */ | |
163 | if (addr == INVENTORYDATASIZE) { | |
164 | xcode = -1; | |
165 | printf("Error end of string not found\n"); | |
62c9b960 | 166 | } else if ((size > (maxlen - 1)) && |
4f745bf4 HB |
167 | (buf[addr] != '\r')) { |
168 | xcode = -1; | |
169 | printf("string too long till next CR\n"); | |
170 | } | |
171 | } else { | |
172 | /* | |
173 | * some CR are missing... | |
174 | * the inventory data is most probably corrupted | |
175 | */ | |
176 | xcode = -1; | |
177 | printf("not enough cr found\n"); | |
178 | } | |
179 | return xcode; | |
180 | } | |
181 | ||
182 | #define GET_STRING(name, which, len) \ | |
183 | if (ivm_findinventorystring(which, valbuf, len, buf) == 0) { \ | |
184 | ivm_set_value(name, (char *)valbuf); \ | |
185 | } | |
186 | ||
187 | static int ivm_check_crc(unsigned char *buf, int block) | |
188 | { | |
189 | unsigned long crc; | |
190 | unsigned long crceeprom; | |
191 | ||
192 | crc = ivm_calc_crc(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2); | |
193 | crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] + \ | |
194 | buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2] * 256); | |
195 | if (crc != crceeprom) { | |
196 | if (block == 0) | |
197 | printf("Error CRC Block: %d EEprom: calculated: \ | |
198 | %lx EEprom: %lx\n", block, crc, crceeprom); | |
199 | return -1; | |
200 | } | |
201 | return 0; | |
202 | } | |
203 | ||
204 | static int ivm_analyze_block2(unsigned char *buf, int len) | |
205 | { | |
206 | unsigned char valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN]; | |
207 | unsigned long count; | |
208 | ||
6478021f HB |
209 | /* IVM_MAC Adress begins at offset 1 */ |
210 | sprintf((char *)valbuf, "%pM", buf + 1); | |
4f745bf4 HB |
211 | ivm_set_value("IVM_MacAddress", (char *)valbuf); |
212 | /* if an offset is defined, add it */ | |
213 | #if defined(CONFIG_PIGGY_MAC_ADRESS_OFFSET) | |
214 | if (CONFIG_PIGGY_MAC_ADRESS_OFFSET > 0) { | |
215 | unsigned long val = (buf[4] << 16) + (buf[5] << 8) + buf[6]; | |
216 | ||
217 | val += CONFIG_PIGGY_MAC_ADRESS_OFFSET; | |
218 | buf[4] = (val >> 16) & 0xff; | |
219 | buf[5] = (val >> 8) & 0xff; | |
220 | buf[6] = val & 0xff; | |
d8f87f6c | 221 | sprintf((char *)valbuf, "%pM", buf + 1); |
4f745bf4 HB |
222 | } |
223 | #endif | |
0eb0e59e | 224 | #ifdef MACH_TYPE_KM_KIRKWOOD |
4f745bf4 | 225 | setenv((char *)"ethaddr", (char *)valbuf); |
0eb0e59e HB |
226 | #else |
227 | if (getenv("ethaddr") == NULL) | |
228 | setenv((char *)"ethaddr", (char *)valbuf); | |
229 | #endif | |
4f745bf4 HB |
230 | |
231 | /* IVM_MacCount */ | |
232 | count = (buf[10] << 24) + | |
233 | (buf[11] << 16) + | |
234 | (buf[12] << 8) + | |
235 | buf[13]; | |
236 | if (count == 0xffffffff) | |
237 | count = 1; | |
238 | sprintf((char *)valbuf, "%lx", count); | |
239 | ivm_set_value("IVM_MacCount", (char *)valbuf); | |
240 | return 0; | |
241 | } | |
242 | ||
243 | int ivm_analyze_eeprom(unsigned char *buf, int len) | |
244 | { | |
245 | unsigned short val; | |
246 | unsigned char valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN]; | |
247 | unsigned char *tmp; | |
248 | ||
249 | if (ivm_check_crc(buf, 0) != 0) | |
250 | return -1; | |
251 | ||
252 | ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, | |
253 | "IVM_BoardId", 0, 1); | |
254 | val = ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, | |
255 | "IVM_HWKey", 6, 1); | |
256 | if (val != 0xffff) { | |
257 | sprintf((char *)valbuf, "%x", ((val / 100) % 10)); | |
258 | ivm_set_value("IVM_HWVariant", (char *)valbuf); | |
259 | sprintf((char *)valbuf, "%x", (val % 100)); | |
260 | ivm_set_value("IVM_HWVersion", (char *)valbuf); | |
261 | } | |
262 | ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, | |
263 | "IVM_Functions", 12, 0); | |
264 | ||
265 | GET_STRING("IVM_Symbol", IVM_POS_SYMBOL_ONLY, 8) | |
266 | GET_STRING("IVM_DeviceName", IVM_POS_SHORT_TEXT, 64) | |
267 | tmp = (unsigned char *) getenv("IVM_DeviceName"); | |
268 | if (tmp) { | |
269 | int len = strlen((char *)tmp); | |
270 | int i = 0; | |
271 | ||
272 | while (i < len) { | |
273 | if (tmp[i] == ';') { | |
274 | ivm_set_value("IVM_ShortText", | |
275 | (char *)&tmp[i + 1]); | |
276 | break; | |
277 | } | |
278 | i++; | |
279 | } | |
280 | if (i >= len) | |
281 | ivm_set_value("IVM_ShortText", NULL); | |
282 | } else { | |
283 | ivm_set_value("IVM_ShortText", NULL); | |
284 | } | |
285 | GET_STRING("IVM_ManufacturerID", IVM_POS_MANU_ID, 32) | |
286 | GET_STRING("IVM_ManufacturerSerialNumber", IVM_POS_MANU_SERIAL, 20) | |
287 | GET_STRING("IVM_ManufacturerPartNumber", IVM_POS_PART_NUMBER, 32) | |
288 | GET_STRING("IVM_ManufacturerBuildState", IVM_POS_BUILD_STATE, 32) | |
289 | GET_STRING("IVM_SupplierPartNumber", IVM_POS_SUPPLIER_PART_NUMBER, 32) | |
290 | GET_STRING("IVM_DelieveryDate", IVM_POS_DELIVERY_DATE, 32) | |
291 | GET_STRING("IVM_SupplierBuildState", IVM_POS_SUPPLIER_BUILD_STATE, 32) | |
292 | GET_STRING("IVM_CustomerID", IVM_POS_CUSTOMER_ID, 32) | |
293 | GET_STRING("IVM_CustomerProductID", IVM_POS_CUSTOMER_PROD_ID, 32) | |
294 | ||
295 | if (ivm_check_crc(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 2) != 0) | |
296 | return 0; | |
297 | ivm_analyze_block2(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], | |
298 | CONFIG_SYS_IVM_EEPROM_PAGE_LEN); | |
299 | ||
300 | return 0; | |
301 | } | |
302 | ||
303 | int ivm_read_eeprom(void) | |
304 | { | |
305 | #if defined(CONFIG_I2C_MUX) | |
306 | I2C_MUX_DEVICE *dev = NULL; | |
307 | #endif | |
308 | uchar i2c_buffer[CONFIG_SYS_IVM_EEPROM_MAX_LEN]; | |
309 | uchar *buf; | |
310 | unsigned long dev_addr = CONFIG_SYS_IVM_EEPROM_ADR; | |
311 | int ret; | |
312 | ||
313 | #if defined(CONFIG_I2C_MUX) | |
314 | /* First init the Bus, select the Bus */ | |
4f745bf4 HB |
315 | buf = (unsigned char *) getenv("EEprom_ivm"); |
316 | if (buf != NULL) | |
317 | dev = i2c_mux_ident_muxstring(buf); | |
4f745bf4 HB |
318 | if (dev == NULL) { |
319 | printf("Error couldnt add Bus for IVM\n"); | |
320 | return -1; | |
321 | } | |
322 | i2c_set_bus_num(dev->busid); | |
323 | #endif | |
4f745bf4 HB |
324 | /* add deblocking here */ |
325 | i2c_make_abort(); | |
326 | ||
327 | ret = i2c_read(dev_addr, 0, 1, i2c_buffer, | |
328 | CONFIG_SYS_IVM_EEPROM_MAX_LEN); | |
329 | if (ret != 0) { | |
330 | printf("Error reading EEprom\n"); | |
331 | return -2; | |
332 | } | |
333 | ||
334 | return ivm_analyze_eeprom(i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN); | |
335 | } |