Home | History | Annotate | Line # | Download | only in eeprom
eehandlers.c revision 1.4
      1 /*	$NetBSD: eehandlers.c,v 1.4 1997/07/23 20:58:38 thorpej 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 REGENTS OR CONTRIBUTORS BE
     30  * 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 
     51 #include <machine/eeprom.h>
     52 #ifdef __sparc__
     53 #include <machine/openpromio.h>
     54 #endif /* __sparc__ */
     55 
     56 #include "defs.h"
     57 
     58 extern	char *path_eeprom;
     59 extern	int eval;
     60 extern	int update_checksums;
     61 extern	int ignore_checksum;
     62 extern	int fix_checksum;
     63 extern	int cksumfail;
     64 extern	u_short writecount;
     65 
     66 struct	timeb;
     67 extern	time_t get_date __P((char *, struct timeb *));
     68 
     69 static	char err_str[BUFSIZE];
     70 
     71 static	void badval __P((struct keytabent *, char *));
     72 static	int doio __P((struct keytabent *, u_char *, ssize_t, int));
     73 
     74 #define BARF(kt) {							\
     75 	badval((kt), arg);						\
     76 	++eval;								\
     77 	return;								\
     78 }
     79 
     80 #define FAILEDREAD(kt) {						\
     81 	warnx(err_str);							\
     82 	warnx("failed to read field `%s'", (kt)->kt_keyword);		\
     83 	++eval;								\
     84 	return;								\
     85 }
     86 
     87 #define FAILEDWRITE(kt) {						\
     88 	warnx(err_str);							\
     89 	warnx("failed to update field `%s'", (kt)->kt_keyword);		\
     90 	++eval;								\
     91 	return;								\
     92 }
     93 
     94 void
     95 ee_hwupdate(ktent, arg)
     96 	struct keytabent *ktent;
     97 	char *arg;
     98 {
     99 	time_t t;
    100 	char *cp, *cp2;
    101 
    102 	if (arg) {
    103 		if ((strcmp(arg, "now") == 0) ||
    104 		    (strcmp(arg, "today") == 0)) {
    105 			if ((t = time(NULL)) == (time_t)(-1)) {
    106 				warnx("can't get current time");
    107 				++eval;
    108 				return;
    109 			}
    110 		} else
    111 			if ((t = get_date(arg, NULL)) == (time_t)(-1))
    112 				BARF(ktent);
    113 
    114 		if (doio(ktent, (u_char *)&t, sizeof(t), IO_WRITE))
    115 			FAILEDWRITE(ktent);
    116 	} else
    117 		if (doio(ktent, (u_char *)&t, sizeof(t), IO_READ))
    118 			FAILEDREAD(ktent);
    119 
    120 	cp = ctime(&t);
    121 	if ((cp2 = strrchr(cp, '\n')) != NULL)
    122 		*cp2 = '\0';
    123 
    124 	printf("%s=%ld (%s)\n", ktent->kt_keyword, (long)t, cp);
    125 }
    126 
    127 void
    128 ee_num8(ktent, arg)
    129 	struct keytabent *ktent;
    130 	char *arg;
    131 {
    132 	u_char num8 = 0;
    133 	u_int num32;
    134 	int i;
    135 
    136 	if (arg) {
    137 		for (i = 0; i < (strlen(arg) - 1); ++i)
    138 			if (!isdigit(arg[i]))
    139 				BARF(ktent);
    140 		num32 = atoi(arg);
    141 		if (num32 > 0xff)
    142 			BARF(ktent);
    143 		num8 += num32;
    144 		if (doio(ktent, &num8, sizeof(num8), IO_WRITE))
    145 			FAILEDWRITE(ktent);
    146 	} else
    147 		if (doio(ktent, &num8, sizeof(num8), IO_READ))
    148 			FAILEDREAD(ktent);
    149 
    150 	printf("%s=%d\n", ktent->kt_keyword, num8);
    151 }
    152 
    153 void
    154 ee_num16(ktent, arg)
    155 	struct keytabent *ktent;
    156 	char *arg;
    157 {
    158 	u_int16_t num16 = 0;
    159 	u_int num32;
    160 	int i;
    161 
    162 	if (arg) {
    163 		for (i = 0; i < (strlen(arg) - 1); ++i)
    164 			if (!isdigit(arg[i]))
    165 				BARF(ktent);
    166 		num32 = atoi(arg);
    167 		if (num32 > 0xffff)
    168 			BARF(ktent);
    169 		num16 += num32;
    170 		if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_WRITE))
    171 			FAILEDWRITE(ktent);
    172 	} else
    173 		if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_READ))
    174 			FAILEDREAD(ktent);
    175 
    176 	printf("%s=%d\n", ktent->kt_keyword, num16);
    177 }
    178 
    179 static	struct strvaltabent scrsizetab[] = {
    180 	{ "1152x900",		EE_SCR_1152X900 },
    181 	{ "1024x1024",		EE_SCR_1024X1024 },
    182 	{ "1600x1280",		EE_SCR_1600X1280 },
    183 	{ "1440x1440",		EE_SCR_1440X1440 },
    184 	{ NULL,			0 },
    185 };
    186 
    187 void
    188 ee_screensize(ktent, arg)
    189 	struct keytabent *ktent;
    190 	char *arg;
    191 {
    192 	struct strvaltabent *svp;
    193 	u_char scsize;
    194 
    195 	if (arg) {
    196 		for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
    197 			if (strcmp(svp->sv_str, arg) == 0)
    198 				break;
    199 		if (svp->sv_str == NULL)
    200 			BARF(ktent);
    201 
    202 		scsize = svp->sv_val;
    203 		if (doio(ktent, &scsize, sizeof(scsize), IO_WRITE))
    204 			FAILEDWRITE(ktent);
    205 	} else {
    206 		if (doio(ktent, &scsize, sizeof(scsize), IO_READ))
    207 			FAILEDREAD(ktent);
    208 
    209 		for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
    210 			if (svp->sv_val == scsize)
    211 				break;
    212 		if (svp->sv_str == NULL) {
    213 			warnx("unknown %s value %d", ktent->kt_keyword,
    214 			    scsize);
    215 			return;
    216 		}
    217 	}
    218 	printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
    219 }
    220 
    221 static	struct strvaltabent truthtab[] = {
    222 	{ "true",		EE_TRUE },
    223 	{ "false",		EE_FALSE },
    224 	{ NULL,			0 },
    225 };
    226 
    227 void
    228 ee_truefalse(ktent, arg)
    229 	struct keytabent *ktent;
    230 	char *arg;
    231 {
    232 	struct strvaltabent *svp;
    233 	u_char truth;
    234 
    235 	if (arg) {
    236 		for (svp = truthtab; svp->sv_str != NULL; ++svp)
    237 			if (strcmp(svp->sv_str, arg) == 0)
    238 				break;
    239 		if (svp->sv_str == NULL)
    240 			BARF(ktent);
    241 
    242 		truth = svp->sv_val;
    243 		if (doio(ktent, &truth, sizeof(truth), IO_WRITE))
    244 			FAILEDWRITE(ktent);
    245 	} else {
    246 		if (doio(ktent, &truth, sizeof(truth), IO_READ))
    247 			FAILEDREAD(ktent);
    248 
    249 		for (svp = truthtab; svp->sv_str != NULL; ++svp)
    250 			if (svp->sv_val == truth)
    251 				break;
    252 		if (svp->sv_str == NULL) {
    253 			warnx("unknown truth value 0x%x for %s", truth,
    254 			    ktent->kt_keyword);
    255 			return;
    256 		}
    257 	}
    258 	printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
    259 }
    260 
    261 void
    262 ee_bootdev(ktent, arg)
    263 	struct keytabent *ktent;
    264 	char *arg;
    265 {
    266 	u_char dev[5];
    267 	int i;
    268 	size_t arglen;
    269 	char *cp;
    270 
    271 	if (arg) {
    272 		/*
    273 		 * The format of the string we accept is the following:
    274 		 *	cc(n,n,n)
    275 		 * where:
    276 		 *	c -- an alphabetical character [a-z]
    277 		 *	n -- a number in hexadecimal, between 0 and ff,
    278 		 *	     with no leading `0x'.
    279 		 */
    280 		arglen = strlen(arg);
    281 		if (arglen < 9 || arglen > 12 || arg[2] != '(' ||
    282 		     arg[arglen - 1] != ')')
    283 			BARF(ktent);
    284 
    285 		/* Handle the first 2 letters. */
    286 		for (i = 0; i < 2; ++i) {
    287 			if (arg[i] < 'a' || arg[i] > 'z')
    288 				BARF(ktent);
    289 			dev[i] = (u_char)arg[i];
    290 		}
    291 
    292 		/* Handle the 3 `0x'-less hex values. */
    293 		cp = &arg[3];
    294 		for (i = 2; i < 5; ++i) {
    295 			if (*cp == '\0')
    296 				BARF(ktent);
    297 
    298 			if (*cp >= '0' && *cp <= '9')
    299 				dev[i] = *cp++ - '0';
    300 			else if (*cp >= 'a' && *cp <= 'f')
    301 				dev[i] = 10 + (*cp++ - 'a');
    302 			else
    303 				BARF(ktent);
    304 
    305 			/* Deal with a second digit. */
    306 			if (*cp >= '0' && *cp <= '9') {
    307 				dev[i] <<= 4;
    308 				dev[i] &= 0xf0;
    309 				dev[i] += *cp++ - '0';
    310 			} else if (*cp >= 'a' && *cp <= 'f') {
    311 				dev[i] <<= 4;
    312 				dev[i] &= 0xf0;
    313 				dev[i] += 10 + (*cp++ - 'a');
    314 			}
    315 
    316 			/* Ensure we have the correct delimiter. */
    317 			if ((*cp == ',' && i < 4) || (*cp == ')' && i == 4)) {
    318 				++cp;
    319 				continue;
    320 			} else
    321 				BARF(ktent);
    322 		}
    323 		if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_WRITE))
    324 			FAILEDWRITE(ktent);
    325 	} else
    326 		if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_READ))
    327 			FAILEDREAD(ktent);
    328 
    329 	printf("%s=%c%c(%x,%x,%x)\n", ktent->kt_keyword, dev[0],
    330 	     dev[1], dev[2], dev[3], dev[4]);
    331 }
    332 
    333 void
    334 ee_kbdtype(ktent, arg)
    335 	struct keytabent *ktent;
    336 	char *arg;
    337 {
    338 	u_char kbd = 0;
    339 	u_int kbd2;
    340 	int i;
    341 
    342 	if (arg) {
    343 		for (i = 0; i < (strlen(arg) - 1); ++i)
    344 			if (!isdigit(arg[i]))
    345 				BARF(ktent);
    346 		kbd2 = atoi(arg);
    347 		if (kbd2 > 0xff)
    348 			BARF(ktent);
    349 		kbd += kbd2;
    350 		if (doio(ktent, &kbd, sizeof(kbd), IO_WRITE))
    351 			FAILEDWRITE(ktent);
    352 	} else
    353 		if (doio(ktent, &kbd, sizeof(kbd), IO_READ))
    354 			FAILEDREAD(ktent);
    355 
    356 	printf("%s=%d (%s)\n", ktent->kt_keyword, kbd, kbd ? "other" : "Sun");
    357 }
    358 
    359 static	struct strvaltabent constab[] = {
    360 	{ "b&w",		EE_CONS_BW },
    361 	{ "ttya",		EE_CONS_TTYA },
    362 	{ "ttyb",		EE_CONS_TTYB },
    363 	{ "color",		EE_CONS_COLOR },
    364 	{ "p4opt",		EE_CONS_P4OPT },
    365 	{ NULL,			0 },
    366 };
    367 
    368 void
    369 ee_constype(ktent, arg)
    370 	struct keytabent *ktent;
    371 	char *arg;
    372 {
    373 	struct strvaltabent *svp;
    374 	u_char cons;
    375 
    376 	if (arg) {
    377 		for (svp = constab; svp->sv_str != NULL; ++svp)
    378 			if (strcmp(svp->sv_str, arg) == 0)
    379 				break;
    380 		if (svp->sv_str == NULL)
    381 			BARF(ktent);
    382 
    383 		cons = svp->sv_val;
    384 		if (doio(ktent, &cons, sizeof(cons), IO_WRITE))
    385 			FAILEDWRITE(ktent);
    386 	} else {
    387 		if (doio(ktent, &cons, sizeof(cons), IO_READ))
    388 			FAILEDREAD(ktent);
    389 
    390 		for (svp = constab; svp->sv_str != NULL; ++svp)
    391 			if (svp->sv_val == cons)
    392 				break;
    393 		if (svp->sv_str == NULL) {
    394 			warnx("unknown type 0x%x for %s", cons,
    395 			    ktent->kt_keyword);
    396 			return;
    397 		}
    398 	}
    399 	printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
    400 
    401 }
    402 
    403 void
    404 ee_diagpath(ktent, arg)
    405 	struct keytabent *ktent;
    406 	char *arg;
    407 {
    408 	char path[40];
    409 
    410 	bzero(path, sizeof(path));
    411 	if (arg) {
    412 		if (strlen(arg) > sizeof(path))
    413 			BARF(ktent);
    414 		memcpy(path, arg, sizeof path);
    415 		if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_WRITE))
    416 			FAILEDWRITE(ktent);
    417 	} else
    418 		if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_READ))
    419 			FAILEDREAD(ktent);
    420 
    421 	printf("%s=%s\n", ktent->kt_keyword, path);
    422 }
    423 
    424 void
    425 ee_banner(ktent, arg)
    426 	struct keytabent *ktent;
    427 	char *arg;
    428 {
    429 	char string[80];
    430 	u_char enable;
    431 	struct keytabent kt;
    432 
    433 	kt.kt_keyword = "enable_banner";
    434 	kt.kt_offset = EE_BANNER_ENABLE_LOC;
    435 	kt.kt_handler = ee_notsupp;
    436 
    437 	memset(string, '\0', sizeof(string));
    438 	if (arg) {
    439 		if (strlen(arg) > sizeof(string))
    440 			BARF(ktent);
    441 		if (*arg != '\0') {
    442 			enable = EE_TRUE;
    443 			memcpy(string, arg, sizeof string);
    444 			if (doio(ktent, (u_char *)string,
    445 			    sizeof(string), IO_WRITE))
    446 				FAILEDWRITE(ktent);
    447 		} else {
    448 			enable = EE_FALSE;
    449 			if (doio(ktent, (u_char *)string,
    450 			    sizeof(string), IO_READ))
    451 				FAILEDREAD(ktent);
    452 		}
    453 
    454 		if (doio(&kt, &enable, sizeof(enable), IO_WRITE))
    455 			FAILEDWRITE(&kt);
    456 	} else {
    457 		if (doio(ktent, (u_char *)string, sizeof(string), IO_READ))
    458 			FAILEDREAD(ktent);
    459 		if (doio(&kt, &enable, sizeof(enable), IO_READ))
    460 			FAILEDREAD(&kt);
    461 	}
    462 	printf("%s=%s (%s)\n", ktent->kt_keyword, string,
    463 	    enable == EE_TRUE ? "enabled" : "disabled");
    464 }
    465 
    466 /* ARGSUSED */
    467 void
    468 ee_notsupp(ktent, arg)
    469 	struct keytabent *ktent;
    470 	char *arg;
    471 {
    472 
    473 	warnx("field `%s' not yet supported", ktent->kt_keyword);
    474 }
    475 
    476 static void
    477 badval(ktent, arg)
    478 	struct keytabent *ktent;
    479 	char *arg;
    480 {
    481 
    482 	warnx("inappropriate value `%s' for field `%s'", arg,
    483 	    ktent->kt_keyword);
    484 }
    485 
    486 static int
    487 doio(ktent, buf, len, wr)
    488 	struct keytabent *ktent;
    489 	u_char *buf;
    490 	ssize_t len;
    491 	int wr;
    492 {
    493 	int fd, rval = 0;
    494 	u_char *buf2;
    495 
    496 	buf2 = (u_char *)calloc(1, len);
    497 	if (buf2 == NULL) {
    498 		memcpy(err_str, "memory allocation failed", sizeof err_str);
    499 		return (1);
    500 	}
    501 
    502 	fd = open(path_eeprom, wr == IO_WRITE ? O_RDWR : O_RDONLY, 0640);
    503 	if (fd < 0) {
    504 		(void)snprintf(err_str, sizeof err_str, "open: %s: %s", path_eeprom,
    505 		    strerror(errno));
    506 		free(buf2);
    507 		return (1);
    508 	}
    509 
    510 	if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
    511 		(void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
    512 		    path_eeprom, strerror(errno));
    513 		rval = 1;
    514 		goto done;
    515 	}
    516 
    517 	if (read(fd, buf2, len) != len) {
    518 		(void)snprintf(err_str, sizeof err_str, "read: %s: %s",
    519 		    path_eeprom, strerror(errno));
    520 		return (1);
    521 	}
    522 
    523 	if (wr == IO_WRITE) {
    524 		if (bcmp(buf, buf2, len) == 0)
    525 			goto done;
    526 
    527 		if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
    528 			(void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
    529 			    path_eeprom, strerror(errno));
    530 			rval = 1;
    531 			goto done;
    532 		}
    533 
    534 		++update_checksums;
    535 		if (write(fd, buf, len) < 0) {
    536 			(void)snprintf(err_str, sizeof err_str, "write: %s: %s",
    537 			    path_eeprom, strerror(errno));
    538 			rval = 1;
    539 			goto done;
    540 		}
    541 	} else
    542 		bcopy(buf2, buf, len);
    543 
    544  done:
    545 	free(buf2);
    546 	(void)close(fd);
    547 	return (rval);
    548 }
    549 
    550 /*
    551  * Read from eeLastHwUpdate to just before eeReserved.  Calculate
    552  * a checksum, and deposit 3 copies of it sequentially starting at
    553  * eeChecksum[0].  Increment the write count, and deposit 3 copies
    554  * of it sequentially starting at eeWriteCount[0].
    555  */
    556 void
    557 ee_updatechecksums()
    558 {
    559 	struct keytabent kt;
    560 	u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
    561 	u_char checksum;
    562 	int i;
    563 
    564 	kt.kt_keyword = "eeprom contents";
    565 	kt.kt_offset = EE_HWUPDATE_LOC;
    566 	kt.kt_handler = ee_notsupp;
    567 
    568 	if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
    569 		cksumfail = 1;
    570 		FAILEDREAD(&kt);
    571 	}
    572 
    573 	checksum = ee_checksum(checkme, sizeof(checkme));
    574 
    575 	kt.kt_keyword = "eeprom checksum";
    576 	for (i = 0; i < 4; ++i) {
    577 		kt.kt_offset = EE_CKSUM_LOC + (i * sizeof(checksum));
    578 		if (doio(&kt, &checksum, sizeof(checksum), IO_WRITE)) {
    579 			cksumfail = 1;
    580 			FAILEDWRITE(&kt);
    581 		}
    582 	}
    583 
    584 	kt.kt_keyword = "eeprom writecount";
    585 	for (i = 0; i < 4; ++i) {
    586 		kt.kt_offset = EE_WC_LOC + (i * sizeof(writecount));
    587 		if (doio(&kt, (u_char *)&writecount, sizeof(writecount),
    588 		    IO_WRITE)) {
    589 			cksumfail = 1;
    590 			FAILEDWRITE(&kt);
    591 		}
    592 	}
    593 }
    594 
    595 void
    596 ee_verifychecksums()
    597 {
    598 	struct keytabent kt;
    599 	u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
    600 	u_char checksum, ochecksum[3];
    601 	u_short owritecount[3];
    602 
    603 	/*
    604 	 * Verify that the EEPROM's write counts match, and update the
    605 	 * global copy for use later.
    606 	 */
    607 	kt.kt_keyword = "eeprom writecount";
    608 	kt.kt_offset = EE_WC_LOC;
    609 	kt.kt_handler = ee_notsupp;
    610 
    611 	if (doio(&kt, (u_char *)&owritecount, sizeof(owritecount), IO_READ)) {
    612 		cksumfail = 1;
    613 		FAILEDREAD(&kt);
    614 	}
    615 
    616 	if (owritecount[0] != owritecount[1] ||
    617 	    owritecount[0] != owritecount[2]) {
    618 		warnx("eeprom writecount mismatch %s",
    619 		    ignore_checksum ? "(ignoring)" :
    620 		    (fix_checksum ? "(fixing)" : ""));
    621 
    622 		if (!ignore_checksum && !fix_checksum) {
    623 			cksumfail = 1;
    624 			return;
    625 		}
    626 
    627 		writecount = MAXIMUM(owritecount[0], owritecount[1]);
    628 		writecount = MAXIMUM(writecount, owritecount[2]);
    629 	} else
    630 		writecount = owritecount[0];
    631 
    632 	/*
    633 	 * Verify that the EEPROM's checksums match and are correct.
    634 	 */
    635 	kt.kt_keyword = "eeprom checksum";
    636 	kt.kt_offset = EE_CKSUM_LOC;
    637 
    638 	if (doio(&kt, ochecksum, sizeof(ochecksum), IO_READ)) {
    639 		cksumfail = 1;
    640 		FAILEDREAD(&kt);
    641 	}
    642 
    643 	if (ochecksum[0] != ochecksum[1] ||
    644 	    ochecksum[0] != ochecksum[2]) {
    645 		warnx("eeprom checksum mismatch %s",
    646 		    ignore_checksum ? "(ignoring)" :
    647 		    (fix_checksum ? "(fixing)" : ""));
    648 
    649 		if (!ignore_checksum && !fix_checksum) {
    650 			cksumfail = 1;
    651 			return;
    652 		}
    653 	}
    654 
    655 	kt.kt_keyword = "eeprom contents";
    656 	kt.kt_offset = EE_HWUPDATE_LOC;
    657 
    658 	if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
    659 		cksumfail = 1;
    660 		FAILEDREAD(&kt);
    661 	}
    662 
    663 	checksum = ee_checksum(checkme, sizeof(checkme));
    664 
    665 	if (ochecksum[0] != checksum) {
    666 		warnx("eeprom checksum incorrect %s",
    667 		    ignore_checksum ? "(ignoring)" :
    668 		    (fix_checksum ? "(fixing)" : ""));
    669 
    670 		if (!ignore_checksum && !fix_checksum) {
    671 			cksumfail = 1;
    672 			return;
    673 		}
    674 	}
    675 
    676 	if (fix_checksum)
    677 		ee_updatechecksums();
    678 }
    679 
    680 u_char
    681 ee_checksum(area, len)
    682 	u_char *area;
    683 	size_t len;
    684 {
    685 	u_char sum = 0;
    686 
    687 	while (len--)
    688 		sum += *area++;
    689 
    690 	return (0x100 - sum);
    691 }
    692