Home | History | Annotate | Line # | Download | only in eeprom
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