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