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