eehandlers.c revision 1.12 1 /* $NetBSD: eehandlers.c,v 1.12 2006/11/20 20:36:12 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/types.h>
40 #include <ctype.h>
41 #include <err.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <time.h>
49 #include <unistd.h>
50 #include <util.h>
51
52 #include <machine/eeprom.h>
53 #ifdef __sparc__
54 #include <machine/openpromio.h>
55 #endif /* __sparc__ */
56
57 #include "defs.h"
58
59 extern char *path_eeprom;
60 extern int eval;
61 extern int update_checksums;
62 extern int ignore_checksum;
63 extern int fix_checksum;
64 extern int cksumfail;
65 extern u_short writecount;
66
67 static char err_str[BUFSIZE];
68
69 static void badval (struct keytabent *, char *);
70 static int doio (struct keytabent *, u_char *, ssize_t, int);
71
72 struct keytabent eekeytab[] = {
73 { "hwupdate", 0x10, ee_hwupdate },
74 { "memsize", 0x14, ee_num8 },
75 { "memtest", 0x15, ee_num8 },
76 { "scrsize", 0x16, ee_screensize },
77 { "watchdog_reboot", 0x17, ee_truefalse },
78 { "default_boot", 0x18, ee_truefalse },
79 { "bootdev", 0x19, ee_bootdev },
80 { "kbdtype", 0x1e, ee_kbdtype },
81 { "console", 0x1f, ee_constype },
82 { "keyclick", 0x21, ee_truefalse },
83 { "diagdev", 0x22, ee_bootdev },
84 { "diagpath", 0x28, ee_diagpath },
85 { "columns", 0x50, ee_num8 },
86 { "rows", 0x51, ee_num8 },
87 { "ttya_use_baud", 0x58, ee_truefalse },
88 { "ttya_baud", 0x59, ee_num16 },
89 { "ttya_no_rtsdtr", 0x5b, ee_truefalse },
90 { "ttyb_use_baud", 0x60, ee_truefalse },
91 { "ttyb_baud", 0x61, ee_num16 },
92 { "ttyb_no_rtsdtr", 0x63, ee_truefalse },
93 { "banner", 0x68, ee_banner },
94 { "secure", 0, ee_notsupp },
95 { "bad_login", 0, ee_notsupp },
96 { "password", 0, ee_notsupp },
97 { NULL, 0, ee_notsupp },
98 };
99
100 #define BARF(kt) { \
101 badval((kt), arg); \
102 ++eval; \
103 return; \
104 }
105
106 #define FAILEDREAD(kt) { \
107 warnx("%s", err_str); \
108 warnx("failed to read field `%s'", (kt)->kt_keyword); \
109 ++eval; \
110 return; \
111 }
112
113 #define FAILEDWRITE(kt) { \
114 warnx("%s", err_str); \
115 warnx("failed to update field `%s'", (kt)->kt_keyword); \
116 ++eval; \
117 return; \
118 }
119
120 void
121 ee_action(keyword, arg)
122 char *keyword, *arg;
123 {
124 struct keytabent *ktent;
125
126 for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent) {
127 if (strcmp(ktent->kt_keyword, keyword) == 0) {
128 (*ktent->kt_handler)(ktent, arg);
129 return;
130 }
131 }
132
133 warnx("unknown keyword %s", keyword);
134 ++eval;
135 }
136
137 void
138 ee_dump()
139 {
140 struct keytabent *ktent;
141
142 for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent)
143 (*ktent->kt_handler)(ktent, NULL);
144 }
145
146 void
147 ee_hwupdate(ktent, arg)
148 struct keytabent *ktent;
149 char *arg;
150 {
151 time_t t;
152 char *cp, *cp2;
153
154 if (arg) {
155 if ((strcmp(arg, "now") == 0) ||
156 (strcmp(arg, "today") == 0)) {
157 if ((t = time(NULL)) == (time_t)(-1)) {
158 warnx("can't get current time");
159 ++eval;
160 return;
161 }
162 } else
163 if ((t = parsedate(arg, NULL, NULL)) == (time_t)(-1))
164 BARF(ktent);
165
166 if (doio(ktent, (u_char *)&t, sizeof(t), IO_WRITE))
167 FAILEDWRITE(ktent);
168 } else
169 if (doio(ktent, (u_char *)&t, sizeof(t), IO_READ))
170 FAILEDREAD(ktent);
171
172 cp = ctime(&t);
173 if ((cp2 = strrchr(cp, '\n')) != NULL)
174 *cp2 = '\0';
175
176 printf("%s=%ld (%s)\n", ktent->kt_keyword, (long)t, cp);
177 }
178
179 void
180 ee_num8(ktent, arg)
181 struct keytabent *ktent;
182 char *arg;
183 {
184 u_char num8 = 0;
185 u_int num32;
186 int i;
187
188 if (arg) {
189 for (i = 0; i < (strlen(arg) - 1); ++i)
190 if (!isdigit((unsigned char)arg[i]))
191 BARF(ktent);
192 num32 = atoi(arg);
193 if (num32 > 0xff)
194 BARF(ktent);
195 num8 += num32;
196 if (doio(ktent, &num8, sizeof(num8), IO_WRITE))
197 FAILEDWRITE(ktent);
198 } else
199 if (doio(ktent, &num8, sizeof(num8), IO_READ))
200 FAILEDREAD(ktent);
201
202 printf("%s=%d\n", ktent->kt_keyword, num8);
203 }
204
205 void
206 ee_num16(ktent, arg)
207 struct keytabent *ktent;
208 char *arg;
209 {
210 u_int16_t num16 = 0;
211 u_int num32;
212 int i;
213
214 if (arg) {
215 for (i = 0; i < (strlen(arg) - 1); ++i)
216 if (!isdigit((unsigned char)arg[i]))
217 BARF(ktent);
218 num32 = atoi(arg);
219 if (num32 > 0xffff)
220 BARF(ktent);
221 num16 += num32;
222 if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_WRITE))
223 FAILEDWRITE(ktent);
224 } else
225 if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_READ))
226 FAILEDREAD(ktent);
227
228 printf("%s=%d\n", ktent->kt_keyword, num16);
229 }
230
231 static struct strvaltabent scrsizetab[] = {
232 { "1152x900", EE_SCR_1152X900 },
233 { "1024x1024", EE_SCR_1024X1024 },
234 { "1600x1280", EE_SCR_1600X1280 },
235 { "1440x1440", EE_SCR_1440X1440 },
236 { NULL, 0 },
237 };
238
239 void
240 ee_screensize(ktent, arg)
241 struct keytabent *ktent;
242 char *arg;
243 {
244 struct strvaltabent *svp;
245 u_char scsize;
246
247 if (arg) {
248 for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
249 if (strcmp(svp->sv_str, arg) == 0)
250 break;
251 if (svp->sv_str == NULL)
252 BARF(ktent);
253
254 scsize = svp->sv_val;
255 if (doio(ktent, &scsize, sizeof(scsize), IO_WRITE))
256 FAILEDWRITE(ktent);
257 } else {
258 if (doio(ktent, &scsize, sizeof(scsize), IO_READ))
259 FAILEDREAD(ktent);
260
261 for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
262 if (svp->sv_val == scsize)
263 break;
264 if (svp->sv_str == NULL) {
265 warnx("unknown %s value %d", ktent->kt_keyword,
266 scsize);
267 return;
268 }
269 }
270 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
271 }
272
273 static struct strvaltabent truthtab[] = {
274 { "true", EE_TRUE },
275 { "false", EE_FALSE },
276 { NULL, 0 },
277 };
278
279 void
280 ee_truefalse(ktent, arg)
281 struct keytabent *ktent;
282 char *arg;
283 {
284 struct strvaltabent *svp;
285 u_char truth;
286
287 if (arg) {
288 for (svp = truthtab; svp->sv_str != NULL; ++svp)
289 if (strcmp(svp->sv_str, arg) == 0)
290 break;
291 if (svp->sv_str == NULL)
292 BARF(ktent);
293
294 truth = svp->sv_val;
295 if (doio(ktent, &truth, sizeof(truth), IO_WRITE))
296 FAILEDWRITE(ktent);
297 } else {
298 if (doio(ktent, &truth, sizeof(truth), IO_READ))
299 FAILEDREAD(ktent);
300
301 for (svp = truthtab; svp->sv_str != NULL; ++svp)
302 if (svp->sv_val == truth)
303 break;
304 if (svp->sv_str == NULL) {
305 warnx("unknown truth value 0x%x for %s", truth,
306 ktent->kt_keyword);
307 return;
308 }
309 }
310 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
311 }
312
313 void
314 ee_bootdev(ktent, arg)
315 struct keytabent *ktent;
316 char *arg;
317 {
318 u_char dev[5];
319 int i;
320 size_t arglen;
321 char *cp;
322
323 if (arg) {
324 /*
325 * The format of the string we accept is the following:
326 * cc(n,n,n)
327 * where:
328 * c -- an alphabetical character [a-z]
329 * n -- a number in hexadecimal, between 0 and ff,
330 * with no leading `0x'.
331 */
332 arglen = strlen(arg);
333 if (arglen < 9 || arglen > 12 || arg[2] != '(' ||
334 arg[arglen - 1] != ')')
335 BARF(ktent);
336
337 /* Handle the first 2 letters. */
338 for (i = 0; i < 2; ++i) {
339 if (arg[i] < 'a' || arg[i] > 'z')
340 BARF(ktent);
341 dev[i] = (u_char)arg[i];
342 }
343
344 /* Handle the 3 `0x'-less hex values. */
345 cp = &arg[3];
346 for (i = 2; i < 5; ++i) {
347 if (*cp == '\0')
348 BARF(ktent);
349
350 if (*cp >= '0' && *cp <= '9')
351 dev[i] = *cp++ - '0';
352 else if (*cp >= 'a' && *cp <= 'f')
353 dev[i] = 10 + (*cp++ - 'a');
354 else
355 BARF(ktent);
356
357 /* Deal with a second digit. */
358 if (*cp >= '0' && *cp <= '9') {
359 dev[i] <<= 4;
360 dev[i] &= 0xf0;
361 dev[i] += *cp++ - '0';
362 } else if (*cp >= 'a' && *cp <= 'f') {
363 dev[i] <<= 4;
364 dev[i] &= 0xf0;
365 dev[i] += 10 + (*cp++ - 'a');
366 }
367
368 /* Ensure we have the correct delimiter. */
369 if ((*cp == ',' && i < 4) || (*cp == ')' && i == 4)) {
370 ++cp;
371 continue;
372 } else
373 BARF(ktent);
374 }
375 if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_WRITE))
376 FAILEDWRITE(ktent);
377 } else
378 if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_READ))
379 FAILEDREAD(ktent);
380
381 printf("%s=%c%c(%x,%x,%x)\n", ktent->kt_keyword, dev[0],
382 dev[1], dev[2], dev[3], dev[4]);
383 }
384
385 void
386 ee_kbdtype(ktent, arg)
387 struct keytabent *ktent;
388 char *arg;
389 {
390 u_char kbd = 0;
391 u_int kbd2;
392 int i;
393
394 if (arg) {
395 for (i = 0; i < (strlen(arg) - 1); ++i)
396 if (!isdigit((unsigned char)arg[i]))
397 BARF(ktent);
398 kbd2 = atoi(arg);
399 if (kbd2 > 0xff)
400 BARF(ktent);
401 kbd += kbd2;
402 if (doio(ktent, &kbd, sizeof(kbd), IO_WRITE))
403 FAILEDWRITE(ktent);
404 } else
405 if (doio(ktent, &kbd, sizeof(kbd), IO_READ))
406 FAILEDREAD(ktent);
407
408 printf("%s=%d (%s)\n", ktent->kt_keyword, kbd, kbd ? "other" : "Sun");
409 }
410
411 static struct strvaltabent constab[] = {
412 { "b&w", EE_CONS_BW },
413 { "ttya", EE_CONS_TTYA },
414 { "ttyb", EE_CONS_TTYB },
415 { "color", EE_CONS_COLOR },
416 { "p4opt", EE_CONS_P4OPT },
417 { NULL, 0 },
418 };
419
420 void
421 ee_constype(ktent, arg)
422 struct keytabent *ktent;
423 char *arg;
424 {
425 struct strvaltabent *svp;
426 u_char cons;
427
428 if (arg) {
429 for (svp = constab; svp->sv_str != NULL; ++svp)
430 if (strcmp(svp->sv_str, arg) == 0)
431 break;
432 if (svp->sv_str == NULL)
433 BARF(ktent);
434
435 cons = svp->sv_val;
436 if (doio(ktent, &cons, sizeof(cons), IO_WRITE))
437 FAILEDWRITE(ktent);
438 } else {
439 if (doio(ktent, &cons, sizeof(cons), IO_READ))
440 FAILEDREAD(ktent);
441
442 for (svp = constab; svp->sv_str != NULL; ++svp)
443 if (svp->sv_val == cons)
444 break;
445 if (svp->sv_str == NULL) {
446 warnx("unknown type 0x%x for %s", cons,
447 ktent->kt_keyword);
448 return;
449 }
450 }
451 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
452
453 }
454
455 void
456 ee_diagpath(ktent, arg)
457 struct keytabent *ktent;
458 char *arg;
459 {
460 char path[40];
461
462 memset(path, 0, sizeof(path));
463 if (arg) {
464 if (strlen(arg) > sizeof(path))
465 BARF(ktent);
466 memcpy(path, arg, sizeof path);
467 if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_WRITE))
468 FAILEDWRITE(ktent);
469 } else
470 if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_READ))
471 FAILEDREAD(ktent);
472
473 printf("%s=%s\n", ktent->kt_keyword, path);
474 }
475
476 void
477 ee_banner(ktent, arg)
478 struct keytabent *ktent;
479 char *arg;
480 {
481 char string[80];
482 u_char enable;
483 struct keytabent kt;
484
485 kt.kt_keyword = "enable_banner";
486 kt.kt_offset = EE_BANNER_ENABLE_LOC;
487 kt.kt_handler = ee_notsupp;
488
489 memset(string, '\0', sizeof(string));
490 if (arg) {
491 if (strlen(arg) > sizeof(string))
492 BARF(ktent);
493 if (*arg != '\0') {
494 enable = EE_TRUE;
495 memcpy(string, arg, sizeof string);
496 if (doio(ktent, (u_char *)string,
497 sizeof(string), IO_WRITE))
498 FAILEDWRITE(ktent);
499 } else {
500 enable = EE_FALSE;
501 if (doio(ktent, (u_char *)string,
502 sizeof(string), IO_READ))
503 FAILEDREAD(ktent);
504 }
505
506 if (doio(&kt, &enable, sizeof(enable), IO_WRITE))
507 FAILEDWRITE(&kt);
508 } else {
509 if (doio(ktent, (u_char *)string, sizeof(string), IO_READ))
510 FAILEDREAD(ktent);
511 if (doio(&kt, &enable, sizeof(enable), IO_READ))
512 FAILEDREAD(&kt);
513 }
514 printf("%s=%s (%s)\n", ktent->kt_keyword, string,
515 enable == EE_TRUE ? "enabled" : "disabled");
516 }
517
518 /* ARGSUSED */
519 void
520 ee_notsupp(ktent, arg)
521 struct keytabent *ktent;
522 char *arg;
523 {
524
525 warnx("field `%s' not yet supported", ktent->kt_keyword);
526 }
527
528 static void
529 badval(ktent, arg)
530 struct keytabent *ktent;
531 char *arg;
532 {
533
534 warnx("inappropriate value `%s' for field `%s'", arg,
535 ktent->kt_keyword);
536 }
537
538 static int
539 doio(ktent, buf, len, wr)
540 struct keytabent *ktent;
541 u_char *buf;
542 ssize_t len;
543 int wr;
544 {
545 int fd, rval = 0;
546 u_char *buf2;
547
548 buf2 = (u_char *)calloc(1, len);
549 if (buf2 == NULL) {
550 memcpy(err_str, "memory allocation failed", sizeof err_str);
551 return (1);
552 }
553
554 fd = open(path_eeprom, wr == IO_WRITE ? O_RDWR : O_RDONLY, 0640);
555 if (fd < 0) {
556 (void)snprintf(err_str, sizeof err_str, "open: %s: %s", path_eeprom,
557 strerror(errno));
558 free(buf2);
559 return (1);
560 }
561
562 if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
563 (void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
564 path_eeprom, strerror(errno));
565 rval = 1;
566 goto done;
567 }
568
569 if (read(fd, buf2, len) != len) {
570 (void)snprintf(err_str, sizeof err_str, "read: %s: %s",
571 path_eeprom, strerror(errno));
572 return (1);
573 }
574
575 if (wr == IO_WRITE) {
576 if (memcmp(buf, buf2, len) == 0)
577 goto done;
578
579 if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
580 (void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
581 path_eeprom, strerror(errno));
582 rval = 1;
583 goto done;
584 }
585
586 ++update_checksums;
587 if (write(fd, buf, len) < 0) {
588 (void)snprintf(err_str, sizeof err_str, "write: %s: %s",
589 path_eeprom, strerror(errno));
590 rval = 1;
591 goto done;
592 }
593 } else
594 memmove(buf, buf2, len);
595
596 done:
597 free(buf2);
598 (void)close(fd);
599 return (rval);
600 }
601
602 /*
603 * Read from eeLastHwUpdate to just before eeReserved. Calculate
604 * a checksum, and deposit 3 copies of it sequentially starting at
605 * eeChecksum[0]. Increment the write count, and deposit 3 copies
606 * of it sequentially starting at eeWriteCount[0].
607 */
608 void
609 ee_updatechecksums()
610 {
611 struct keytabent kt;
612 u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
613 u_char checksum;
614 int i;
615
616 kt.kt_keyword = "eeprom contents";
617 kt.kt_offset = EE_HWUPDATE_LOC;
618 kt.kt_handler = ee_notsupp;
619
620 if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
621 cksumfail = 1;
622 FAILEDREAD(&kt);
623 }
624
625 checksum = ee_checksum(checkme, sizeof(checkme));
626
627 kt.kt_keyword = "eeprom checksum";
628 for (i = 0; i < 4; ++i) {
629 kt.kt_offset = EE_CKSUM_LOC + (i * sizeof(checksum));
630 if (doio(&kt, &checksum, sizeof(checksum), IO_WRITE)) {
631 cksumfail = 1;
632 FAILEDWRITE(&kt);
633 }
634 }
635
636 kt.kt_keyword = "eeprom writecount";
637 for (i = 0; i < 4; ++i) {
638 kt.kt_offset = EE_WC_LOC + (i * sizeof(writecount));
639 if (doio(&kt, (u_char *)&writecount, sizeof(writecount),
640 IO_WRITE)) {
641 cksumfail = 1;
642 FAILEDWRITE(&kt);
643 }
644 }
645 }
646
647 void
648 ee_verifychecksums()
649 {
650 struct keytabent kt;
651 u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
652 u_char checksum, ochecksum[3];
653 u_short owritecount[3];
654
655 /*
656 * Verify that the EEPROM's write counts match, and update the
657 * global copy for use later.
658 */
659 kt.kt_keyword = "eeprom writecount";
660 kt.kt_offset = EE_WC_LOC;
661 kt.kt_handler = ee_notsupp;
662
663 if (doio(&kt, (u_char *)&owritecount, sizeof(owritecount), IO_READ)) {
664 cksumfail = 1;
665 FAILEDREAD(&kt);
666 }
667
668 if (owritecount[0] != owritecount[1] ||
669 owritecount[0] != owritecount[2]) {
670 warnx("eeprom writecount mismatch %s",
671 ignore_checksum ? "(ignoring)" :
672 (fix_checksum ? "(fixing)" : ""));
673
674 if (!ignore_checksum && !fix_checksum) {
675 cksumfail = 1;
676 return;
677 }
678
679 writecount = MAXIMUM(owritecount[0], owritecount[1]);
680 writecount = MAXIMUM(writecount, owritecount[2]);
681 } else
682 writecount = owritecount[0];
683
684 /*
685 * Verify that the EEPROM's checksums match and are correct.
686 */
687 kt.kt_keyword = "eeprom checksum";
688 kt.kt_offset = EE_CKSUM_LOC;
689
690 if (doio(&kt, ochecksum, sizeof(ochecksum), IO_READ)) {
691 cksumfail = 1;
692 FAILEDREAD(&kt);
693 }
694
695 if (ochecksum[0] != ochecksum[1] ||
696 ochecksum[0] != ochecksum[2]) {
697 warnx("eeprom checksum mismatch %s",
698 ignore_checksum ? "(ignoring)" :
699 (fix_checksum ? "(fixing)" : ""));
700
701 if (!ignore_checksum && !fix_checksum) {
702 cksumfail = 1;
703 return;
704 }
705 }
706
707 kt.kt_keyword = "eeprom contents";
708 kt.kt_offset = EE_HWUPDATE_LOC;
709
710 if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
711 cksumfail = 1;
712 FAILEDREAD(&kt);
713 }
714
715 checksum = ee_checksum(checkme, sizeof(checkme));
716
717 if (ochecksum[0] != checksum) {
718 warnx("eeprom checksum incorrect %s",
719 ignore_checksum ? "(ignoring)" :
720 (fix_checksum ? "(fixing)" : ""));
721
722 if (!ignore_checksum && !fix_checksum) {
723 cksumfail = 1;
724 return;
725 }
726 }
727
728 if (fix_checksum)
729 ee_updatechecksums();
730 }
731
732 u_char
733 ee_checksum(area, len)
734 u_char *area;
735 size_t len;
736 {
737 u_char sum = 0;
738
739 while (len--)
740 sum += *area++;
741
742 return (0x100 - sum);
743 }
744