No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / hpcmips / stand / lcboot / main.c
blob7e47c4166c5e40ccdecff0583114a58f0f81ee4e
1 /* $NetBSD: main.c,v 1.3.2.3 2004/09/21 13:16:12 skrll Exp $ */
3 /*
4 * Copyright (c) 2003 Naoto Shimazaki.
5 * All rights reserved.
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.
16 * THIS SOFTWARE IS PROVIDED BY NAOTO SHIMAZAKI AND CONTRIBUTORS ``AS IS''
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE NAOTO OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
30 * Boot loader for L-Card+
32 * ROM Map
33 * -------
34 * ROM1
35 * BFFF FFFF ------------------------------
37 * reserved
39 * BF80 0000 ------------------------------
41 * ROM0
42 * BFFF FFFF ------------------------------
44 * user storage (max 2Mbytes)
46 * BFE0 0000 ------------------------------
48 * reserved
50 * BFD4 0000 ------------------------------
52 * boot params
54 * BFD2 0000 ------------------------------
56 * second boot loader (mirror image)
57 * or Linux Kernel
59 * BFD0 0000 ------------------------------
61 * first boot loader (L-Card+ original loader)
63 * reset vector
64 * BFC0 0000 ------------------------------
66 * gziped kernel image (max 4Mbytes)
68 * BF80 0000 ------------------------------
72 * RAM Map
73 * -------
75 * 80FF FFFF ------------------------------
76 * ROM ICE work
77 * 80FF FE00 ------------------------------
78 * ROM ICE stack
79 * 80FF FDA8 ------------------------------
83 * kernel
84 * 8004 0000 ------------------------------
85 * kernel stack (growing to lower)
88 * boot loader heap (growing to upper)
89 * boot loader text & data (at exec time)
90 * 8000 1000 ------------------------------
91 * vector table
92 * 8000 0000 ------------------------------
94 * virtual memory space
96 * 0000 0000 ------------------------------
100 * ROMCS0 <-> ROMCS3 mapping
102 * ROMCS0 ROMCS3
103 * BE7F FFFF <-> BFFF FFFF
104 * BE40 0000 <-> BFC0 0000 reset vector
105 * BE00 0000 <-> BF80 0000
109 #include <sys/cdefs.h>
110 __KERNEL_RCSID(0, "$NetBSD: main.c,v 1.3.2.3 2004/09/21 13:16:12 skrll Exp $");
112 #include <lib/libsa/stand.h>
114 #include <lib/libsa/loadfile.h>
115 #include <lib/libkern/libkern.h>
117 #include <hpcmips/vr/vripreg.h>
118 #include <hpcmips/vr/cmureg.h>
119 #include <hpcmips/vr/vr4181giureg.h>
121 #include "extern.h"
122 #include "i28f128reg.h"
124 /* XXX */
125 #define ISABRGCTL 0x00
126 #define ISABRGSTS 0x02
127 #define XISACTL 0x04
129 #define BOOTTIMEOUT 9 /* must less than 10 */
130 #define LINEBUFLEN 80
132 extern const char bootprog_rev[];
133 extern const char bootprog_name[];
134 extern const char bootprog_date[];
135 extern const char bootprog_maker[];
137 static void command_help(char *opt);
138 static void command_dump(char *opt);
139 static void command_boot(char *opt);
140 static void command_load(char *opt);
141 static void command_fill(char *opt);
142 static void command_write(char *opt);
143 static void command_option(char *subcmd);
144 static void opt_subcmd_print(char *opt);
145 static void opt_subcmd_read(char *opt);
146 static void opt_subcmd_write(char *opt);
147 static void opt_subcmd_path(char *opt);
148 static void opt_subcmd_bootp(char *opt);
149 static void opt_subcmd_ip(char *opt);
152 struct boot_option bootopts;
154 static struct bootmenu_command commands[] = {
155 { "?", command_help },
156 { "h", command_help },
157 { "d", command_dump },
158 { "b", command_boot },
159 { "l", command_load },
160 { "f", command_fill },
161 { "w", command_write },
162 { "o", command_option },
163 { NULL, NULL },
166 static struct bootmenu_command opt_subcommands[] = {
167 { "p", opt_subcmd_print },
168 { "r", opt_subcmd_read },
169 { "w", opt_subcmd_write },
170 { "path", opt_subcmd_path },
171 { "bootp", opt_subcmd_bootp },
172 { "ip", opt_subcmd_ip },
173 { NULL, NULL },
176 static void
177 print_banner(void)
179 printf("\n");
180 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
181 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
182 #if 0
183 printf(">> Memory: %d/%d k\n", getbasemem(), getextmem());
184 #endif
187 static void
188 init_devices(void)
190 /* Init RTC */
191 REGWRITE_2(VRETIMEH, 0, 0);
192 REGWRITE_2(VRETIMEM, 0, 0);
193 REGWRITE_2(VRETIMEL, 0, 0);
197 * CLKSPEEDREG 0x6012
198 * DIV DIV2 mode
199 * CLKSP 18 (0x12)
200 * PClock (CPU clock) 65.536MHz
201 * PClock = (18.432MHz / CLKSP) x 64
202 * = (18.432MHz / 18) x 64
203 * = 65.536MHz
204 * TClock (peripheral clock) 32.768MHz
205 * TClock = PClock / DIV
206 * = 65.536MHz / 2
207 * = 32.768MHz
211 * setup ISA BUS clock freqency
213 * set PCLK (internal peripheral clock) to 32.768MHz (TClock / 1)
214 * set External ISA bus clock to 10.922MHz (TClock / 3)
216 REGWRITE_2(VR4181_ISABRG_ADDR, ISABRGCTL, 0x0003);
217 REGWRITE_2(VR4181_ISABRG_ADDR, XISACTL, 0x0401);
220 * setup peripheral's clock supply
222 * CSU: disable
223 * AIU: enable (AIU, ADU, ADU18M)
224 * PIU: disable
225 * SIU: enable (SIU18M)
227 REGWRITE_2(VR4181_CMU_ADDR, 0, CMUMASK_SIU | CMUMASK_AIU);
230 * setup GPIO
232 #if 0
233 /* L-Card+ generic setup */
235 * pin mode comment
236 * GP0 : GPI not used
237 * GP1 : GPI not used
238 * GP2 : GPO LED6 (0: on 1: off)
239 * GP3 : PCS0 chip select for CS8900A Lan controller
240 * GP4 : GPI IRQ input from CS8900A
241 * GP5 : GPI not used
242 * GP6 : GPI not used
243 * GP7 : GPI reserved by TANBAC TB0193
245 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PIOD_L_REG_W, 0xffff);
246 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE0_REG_W,
247 GP3_PCS0 | GP2_GPO);
249 * pin mode comment
250 * GP8 : GPO LED5 (0: on 1: off)
251 * GP9 : GPI CD2
252 * GP10: GPI CD1
253 * GP11: GPI not used
254 * GP12: GPI not used
255 * GP13: GPI not used
256 * GP14: GPI not used
257 * GP15: GPI not used
259 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE1_REG_W, GP8_GPO);
261 * pin mode comment
262 * GP16: IORD ISA bus
263 * GP17: IOWR ISA bus
264 * GP18: IORDY ISA bus
265 * GP19: GPI not used
266 * GP20: GPI not used
267 * GP21: RESET resets CS8900A
268 * GP22: ROMCS0 ROM chip select
269 * GP23: ROMCS1 ROM chip select
271 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE2_REG_W,
272 GP23_ROMCS1 | GP22_ROMCS0 | GP21_RESET
273 | GP18_IORDY | GP17_IOWR | GP16_IORD);
275 * GP24: ROMCS2 ROM chip select
276 * GP25: RxD1 SIU1
277 * GP26: TxD1 SIU1
278 * GP27: RTS1 SIU1
279 * GP28: CTS1 SIU1
280 * GP29: GPI LED3
281 * GP30: GPI reserved by TANBAC TB0193
282 * GP31: GPI LED4
284 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE3_REG_W,
285 GP30_GPI
286 | GP28_CTS1 | GP27_RTS1 | GP26_TxD1 | GP25_RxD1
287 | GP24_ROMCS2);
288 #else
289 /* e-care node specific setup */
291 * pin mode comment
292 * GP0 : GPO ECNRTC_RST
293 * GP1 : GPO ECNRTC_CLK
294 * GP2 : GPO LED6 (0: on 1: off)
295 * GP3 : PCS0 chip select for CS8900A Lan controller
296 * GP4 : GPI IRQ input from CS8900A
297 * GP5 : GPO ECNRTC_DIR
298 * GP6 : GPO ECNRTC_OUT
299 * GP7 : GPI reserved by TANBAC TB0193
301 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PIOD_L_REG_W, 0xffff);
302 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE0_REG_W,
303 GP6_GPO | GP5_GPO | GP3_PCS0
304 | GP2_GPO | GP1_GPO | GP0_GPO);
307 * pin mode comment
308 * GP8 : GPO LED5 (0: on 1: off)
309 * GP9 : GPI CD2
310 * GP10: GPI CD1
311 * GP11: GPI not used
312 * GP12: GPI ECNRTC_IN
313 * GP13: GPI not used
314 * GP14: GPI not used
315 * GP15: GPI not used
317 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE1_REG_W,
318 GP12_GPI | GP8_GPO);
321 * pin mode comment
322 * GP16: IORD ISA bus
323 * GP17: IOWR ISA bus
324 * GP18: IORDY ISA bus
325 * GP19: GPI not used
326 * GP20: GPI not used
327 * GP21: RESET resets CS8900A
328 * GP22: ROMCS0 ROM chip select
329 * GP23: ROMCS1 ROM chip select
331 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE2_REG_W,
332 GP23_ROMCS1 | GP22_ROMCS0 | GP21_RESET
333 | GP18_IORDY | GP17_IOWR | GP16_IORD);
335 * GP24: ROMCS2 ROM chip select
336 * GP25: RxD1 SIU1
337 * GP26: TxD1 SIU1
338 * GP27: RTS1 SIU1
339 * GP28: CTS1 SIU1
340 * GP29: GPI LED3
341 * GP30: GPI reserved by TANBAC TB0193
342 * GP31: GPI LED4
344 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE3_REG_W,
345 GP30_GPI
346 | GP28_CTS1 | GP27_RTS1 | GP26_TxD1 | GP25_RxD1
347 | GP24_ROMCS2);
348 #endif
350 #if 0
352 * setup interrupt
354 * I4TYP: falling edge trigger
355 * GIMSK4: unmask
356 * GIEN4: enable
357 * other: unused, mask, disable
359 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_INTTYP_L_REG_W,
360 I4TYP_HIGH_LEVEL);
361 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_INTMASK_REG_W,
362 0xffffU & ~GIMSK4);
363 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_INTEN_REG_W, GIEN4);
364 #endif
367 * programmable chip select
369 * PCS0 is used to select CS8900A Ethernet controller
370 * on TB0193
372 * PCS0:
373 * 0x14010000 - 0x14010fff
374 * I/O access, 16bit cycle, both of read/write
375 * PCS1: unused
377 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PCS0STRA_REG_W, 0x0000);
378 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PCS0STPA_REG_W, 0x0fff);
379 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PCS0HIA_REG_W, 0x1401);
380 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PCSMODE_REG_W,
381 PCS0MIOB_IO | PCS0DSIZE_16BIT | PCS0MD_READWRITE);
385 * chops the head from the arguments and returns the arguments if any,
386 * or possibly an empty string.
388 static char *
389 get_next_arg(char *arg)
391 char *opt;
393 if ((opt = strchr(arg, ' ')) == NULL) {
394 opt = "";
395 } else {
396 *opt++ = '\0';
399 /* trim leading blanks */
400 while (*opt == ' ')
401 opt++;
403 return opt;
406 static void
407 command_help(char *opt)
409 printf("commands are:\n"
410 "boot:\tb\n"
411 "dump:\td addr [addr]\n"
412 "fill:\tf addr addr char\n"
413 "load:\tl [offset] (with following S-Record)\n"
414 "write:\tw dst src len\n"
415 "option:\to subcommand [params]\n"
416 "help:\th|?\n"
417 "\n"
418 "option subcommands are:\n"
419 "print:\to p\n"
420 "read:\to r\n"
421 "write:\to w\n"
422 "path:\to path pathname\n"
423 "bootp:\to bootp yes|no\n"
424 "ip:\to ip remote local netmask gateway\n"
428 static void
429 bad_param(void)
431 printf("bad param\n");
432 command_help(NULL);
435 static const u_int8_t print_cnv[] = {
436 '0', '1', '2', '3', '4', '5', '6', '7',
437 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
439 static void
440 printhexul(u_int32_t n)
442 int i;
444 for (i = 28; i >= 0; i -= 4)
445 putchar(print_cnv[(n >> i) & 0x0f]);
448 static void
449 printhexuc(u_int8_t n)
451 int i;
453 for (i = 4; i >= 0; i -= 4)
454 putchar(print_cnv[(n >> i) & 0x0f]);
457 static void
458 command_dump(char *opt)
460 char *endptr;
461 const char *p;
462 const char *line_fence;
463 const char *limit;
465 p = (const char *) strtoul(opt, &endptr, 16);
466 if (opt == endptr) {
467 bad_param();
468 return;
471 opt = get_next_arg(opt);
472 limit = (const char *) strtoul(opt, &endptr, 16);
473 if (opt == endptr) {
474 limit = p + 256;
477 for (;;) {
478 printhexul((u_int32_t) p);
479 putchar(' ');
480 line_fence = p + 16;
481 while (p < line_fence) {
482 printhexuc(*p++);
483 putchar(' ');
484 if (p >= limit) {
485 putchar('\n');
486 return;
489 putchar('\n');
490 if (ISKEY) {
491 if (getchar() == '\x03')
492 break;
497 static void
498 command_boot(char *opt)
500 u_long marks[MARK_MAX];
502 marks[MARK_START] = 0;
503 if (loadfile(bootopts.b_pathname, marks, LOAD_KERNEL)) {
504 printf("loadfile failed\n");
505 return;
507 start_netbsd();
508 /* no return */
512 * loading S-Record
514 static int
515 load_srec(char *offset)
517 char s2lbuf[9];
518 char c;
519 char rectype;
520 u_int32_t reclen;
521 u_int32_t reclen_bk;
522 u_int32_t recaddr;
523 char *endptr;
524 char *p;
525 u_int32_t sum;
526 int err = 0;
528 for (;;) {
530 * the first step is to read a S-Record.
532 if ((c = getchar()) != 'S')
533 goto out;
535 rectype = getchar();
537 s2lbuf[0] = getchar();
538 s2lbuf[1] = getchar();
539 s2lbuf[2] = '\0';
540 reclen_bk = reclen = strtoul(s2lbuf, &endptr, 16);
541 if (endptr != &s2lbuf[2])
542 goto out;
543 sum = reclen;
545 p = s2lbuf;
547 switch (rectype) {
548 case '0':
549 /* just ignore */
550 do {
551 c = getchar();
552 } while (c != '\r' && c != '\n');
553 continue;
555 case '3':
556 *p++ = getchar();
557 *p++ = getchar();
558 reclen--;
559 /* FALLTHRU */
560 case '2':
561 *p++ = getchar();
562 *p++ = getchar();
563 reclen--;
564 /* FALLTHRU */
565 case '1':
566 *p++ = getchar();
567 *p++ = getchar();
568 *p++ = getchar();
569 *p++ = getchar();
570 *p = '\0';
571 reclen -= 2;
573 recaddr = strtoul(s2lbuf, &endptr, 16);
574 if (endptr != p)
575 goto out;
576 sum += (recaddr >> 24) & 0xff;
577 sum += (recaddr >> 16) & 0xff;
578 sum += (recaddr >> 8) & 0xff;
579 sum += recaddr & 0xff;
581 p = offset + recaddr;
583 * XXX
584 * address range is must be chaked here!
586 reclen--;
587 s2lbuf[2] = '\0';
588 while (reclen > 0) {
589 s2lbuf[0] = getchar();
590 s2lbuf[1] = getchar();
591 *p = (u_int8_t) strtoul(s2lbuf, &endptr, 16);
592 if (endptr != &s2lbuf[2])
593 goto out;
594 sum += *p++;
595 reclen--;
597 break;
599 case '7':
600 case '8':
601 case '9':
602 goto out2;
604 default:
605 goto out;
608 s2lbuf[0] = getchar();
609 s2lbuf[1] = getchar();
610 s2lbuf[2] = '\0';
611 sum += (strtoul(s2lbuf, &endptr, 16) & 0xff);
612 sum &= 0xff;
613 if (sum != 0xff) {
614 printf("checksum error\n");
615 err = 1;
616 goto out2;
619 c = getchar();
620 if (c != '\r' && c != '\n')
621 goto out;
623 /* never reach */
624 return 1;
626 out:
627 printf("invalid S-Record\n");
628 err = 1;
630 out2:
631 do {
632 c = getchar();
633 } while (c != '\r' && c != '\n');
635 return err;
638 static void
639 command_load(char *opt)
641 char *endptr;
642 char *offset;
644 offset = (char *) strtoul(opt, &endptr, 16);
645 if (opt == endptr)
646 offset = 0;
647 load_srec(offset);
650 static void
651 command_fill(char *opt)
653 char *endptr;
654 char *p;
655 char *limit;
656 int c;
658 p = (char *) strtoul(opt, &endptr, 16);
659 if (opt == endptr) {
660 bad_param();
661 return;
664 opt = get_next_arg(opt);
665 limit = (char *) strtoul(opt, &endptr, 16);
666 if (opt == endptr) {
667 bad_param();
668 return;
671 opt = get_next_arg(opt);
672 c = strtoul(opt, &endptr, 16);
673 if (opt == endptr)
674 c = '\0';
676 memset(p, c, limit - p);
679 static void
680 check_write_verify_flash(u_int32_t src, u_int32_t dst, size_t len)
682 int status;
684 if ((dst & I28F128_BLOCK_MASK) != 0) {
685 printf("dst addr must be aligned to block boundary (0x%x)\n",
686 I28F128_BLOCK_SIZE);
687 return;
690 if (i28f128_probe((void *) dst)) {
691 printf("dst addr is not a intel 28F128\n");
692 } else {
693 printf("intel 28F128 detected\n");
696 if ((status = i28f128_region_write((void *) dst, (void *) src, len))
697 != 0) {
698 printf("write mem to flash failed status = %x\n", status);
699 return;
702 printf("verifying...");
703 if (memcmp((void *) dst, (void *) src, len)) {
704 printf("verify error\n");
705 return;
707 printf("ok\n");
709 printf("writing memory to flash succeeded\n");
712 static void
713 command_write(char *opt)
715 char *endptr;
716 u_int32_t src;
717 u_int32_t dst;
718 size_t len;
720 dst = strtoul(opt, &endptr, 16);
721 if (opt == endptr)
722 goto out;
724 opt = get_next_arg(opt);
725 src = strtoul(opt, &endptr, 16);
726 if (opt == endptr)
727 goto out;
729 opt = get_next_arg(opt);
730 len = strtoul(opt, &endptr, 16);
731 if (opt == endptr)
732 goto out;
734 check_write_verify_flash(src, dst, len);
735 return;
737 out:
738 bad_param();
739 return;
742 static void
743 command_option(char *subcmd)
745 char *opt;
746 int i;
748 opt = get_next_arg(subcmd);
750 /* dispatch subcommand */
751 for (i = 0; opt_subcommands[i].c_name != NULL; i++) {
752 if (strcmp(subcmd, opt_subcommands[i].c_name) == 0) {
753 opt_subcommands[i].c_fn(opt);
754 break;
757 if (opt_subcommands[i].c_name == NULL) {
758 printf("unknown option subcommand\n");
759 command_help(NULL);
763 static void
764 opt_subcmd_print(char *opt)
766 printf("boot options:\n"
767 "magic:\t\t%s\n"
768 "pathname:\t`%s'\n"
769 "bootp:\t\t%s\n",
770 bootopts.b_magic == BOOTOPT_MAGIC ? "ok" : "bad",
771 bootopts.b_pathname,
772 bootopts.b_flags & B_F_USE_BOOTP ? "yes" : "no");
773 printf("remote IP:\t%s\n", inet_ntoa(bootopts.b_remote_ip));
774 printf("local IP:\t%s\n", inet_ntoa(bootopts.b_local_ip));
775 printf("netmask:\t%s\n", intoa(bootopts.b_netmask));
776 printf("gateway IP:\t%s\n", inet_ntoa(bootopts.b_gate_ip));
779 static void
780 opt_subcmd_read(char *opt)
782 bootopts = *((struct boot_option *) BOOTOPTS_BASE);
783 if (bootopts.b_magic != BOOTOPT_MAGIC)
784 bootopts.b_pathname[0] = '\0';
787 static void
788 opt_subcmd_write(char *opt)
790 bootopts.b_magic = BOOTOPT_MAGIC;
792 check_write_verify_flash((u_int32_t) &bootopts, BOOTOPTS_BASE,
793 sizeof bootopts);
796 static void
797 opt_subcmd_path(char *opt)
799 strlcpy(bootopts.b_pathname, opt, sizeof bootopts.b_pathname);
802 static void
803 opt_subcmd_bootp(char *opt)
805 if (strcmp(opt, "yes") == 0) {
806 bootopts.b_flags |= B_F_USE_BOOTP;
807 } else if (strcmp(opt, "no") == 0) {
808 bootopts.b_flags &= ~B_F_USE_BOOTP;
809 } else {
810 bad_param();
814 static void
815 opt_subcmd_ip(char *opt)
817 bootopts.b_remote_ip.s_addr = inet_addr(opt);
818 opt = get_next_arg(opt);
819 bootopts.b_local_ip.s_addr = inet_addr(opt);
820 opt = get_next_arg(opt);
821 bootopts.b_netmask = inet_addr(opt);
822 opt = get_next_arg(opt);
823 bootopts.b_gate_ip.s_addr = inet_addr(opt);
826 static void
827 bootmenu(void)
829 char input[LINEBUFLEN];
830 char *cmd;
831 char *opt;
832 int i;
834 for (;;) {
836 /* input a line */
837 input[0] = '\0';
838 printf("> ");
839 gets(input);
840 cmd = input;
842 /* skip leading whitespace. */
843 while(*cmd == ' ')
844 cmd++;
846 if(*cmd) {
847 /* here, some command entered */
849 opt = get_next_arg(cmd);
851 /* dispatch command */
852 for (i = 0; commands[i].c_name != NULL; i++) {
853 if (strcmp(cmd, commands[i].c_name) == 0) {
854 commands[i].c_fn(opt);
855 break;
858 if (commands[i].c_name == NULL) {
859 printf("unknown command\n");
860 command_help(NULL);
867 static char
868 awaitkey(void)
870 int i;
871 int j;
872 char c = 0;
874 while (ISKEY)
875 getchar();
877 for (i = BOOTTIMEOUT; i > 0; i--) {
878 printf("%d\b", i);
879 for (j = 0; j < 1000000; j++) {
880 if (ISKEY) {
881 while (ISKEY)
882 c = getchar();
883 goto out;
888 out:
889 printf("0\n");
890 return(c);
893 __dead void
894 _rtt(void)
896 for (;;)
901 main(void)
903 char c;
905 init_devices();
907 comcninit();
909 opt_subcmd_read(NULL);
911 print_banner();
913 c = awaitkey();
914 if (c != '\r' && c != '\n' && c != '\0') {
915 printf("type \"?\" or \"h\" for help.\n");
916 bootmenu(); /* does not return */
919 command_boot(NULL);
921 * command_boot() returns only if it failed to boot.
922 * we enter to boot menu in this case.
924 bootmenu();
926 return 0;