Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/trunkAutoResolution/i386/boot2/options.c

1/*
2 * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2004 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include "boot.h"
26#include "bootstruct.h"
27#include "fdisk.h"
28#include "ramdisk.h"
29#include "gui.h"
30#include "embedded.h"
31#include "pci.h"
32#include "autoresolution.h" //Azi:autoresolution
33
34
35bool showBootBanner = true; //Azi:showinfo
36static bool shouldboot = false;
37
38extern int multiboot_timeout;
39extern int multiboot_timeout_set;
40
41extern BVRef bvChain;
42//extern intmenucount;
43
44extern intgDeviceCount;
45
46intselectIndex = 0;
47MenuItem * menuItems = NULL;
48
49enum {
50 kMenuTopRow = 5,
51 kMenuMaxItems = 10,
52 kScreenLastRow = 24
53};
54
55//==========================================================================
56
57typedef struct {
58 int x;
59 int y;
60 int type;
61} CursorState;
62
63static void changeCursor( int col, int row, int type, CursorState * cs )
64{
65 if (cs) getCursorPositionAndType( &cs->x, &cs->y, &cs->type );
66 setCursorType( type );
67 setCursorPosition( col, row, 0 );
68}
69
70static void moveCursor( int col, int row )
71{
72 setCursorPosition( col, row, 0 );
73}
74
75static void restoreCursor( const CursorState * cs )
76{
77 setCursorPosition( cs->x, cs->y, 0 );
78 setCursorType( cs->type );
79}
80
81//==========================================================================
82
83/* Flush keyboard buffer; returns TRUE if any of the flushed
84 * characters was F8.
85 */
86
87static bool flushKeyboardBuffer(void)
88{
89 bool status = false;
90
91 while ( readKeyboardStatus() ) {
92 if (bgetc() == 0x4200) status = true;
93 }
94 return status;
95}
96
97//==========================================================================
98
99static int countdown( const char * msg, int row, int timeout )
100{
101 unsigned long time;
102 int ch = 0;
103 int col = strlen(msg) + 1;
104
105 flushKeyboardBuffer();
106
107if( bootArgs->Video.v_display == VGA_TEXT_MODE )
108{
109moveCursor( 0, row );
110printf(msg);
111
112} else {
113
114position_t p = pos( gui.screen.width / 2 + 1 , ( gui.devicelist.pos.y + 3 ) + ( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) );
115
116char dummy[80];
117getBootVolumeDescription( gBootVolume, dummy, sizeof(dummy) - 1, true );
118drawDeviceIcon( gBootVolume, gui.screen.pixmap, p, true );
119drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos );
120
121// make this screen the new background
122memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
123
124}
125
126int multi_buff = 18 * (timeout);
127 int multi = ++multi_buff;
128
129 int lasttime=0;
130
131 for ( time = time18(), timeout++; timeout > 0; )
132 {
133if( time18() > lasttime)
134{
135multi--;
136lasttime=time18();
137}
138
139 if (ch = readKeyboardStatus())
140 break;
141
142 // Count can be interrupted by holding down shift,
143 // control or alt key
144 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
145{
146 ch = 1;
147 break;
148 }
149
150 if ( time18() >= time )
151 {
152 time += 18;
153 timeout--;
154
155if( bootArgs->Video.v_display == VGA_TEXT_MODE )
156{
157moveCursor( col, row );
158printf("(%d) ", timeout);
159}
160 }
161
162if( bootArgs->Video.v_display != VGA_TEXT_MODE )
163{
164drawProgressBar( gui.screen.pixmap, 100, gui.progressbar.pos , ( multi * 100 / multi_buff ) );
165gui.redraw = true;
166updateVRAM();
167}
168
169 }
170
171 flushKeyboardBuffer();
172
173 return ch;
174}
175
176//==========================================================================
177
178char gBootArgs[BOOT_STRING_LEN];
179static char * gBootArgsPtr = gBootArgs;
180static char * gBootArgsEnd = gBootArgs + BOOT_STRING_LEN - 1;
181static char booterCommand[BOOT_STRING_LEN];
182static char booterParam[BOOT_STRING_LEN];
183
184static void clearBootArgs(void)
185{
186gBootArgsPtr = gBootArgs;
187memset(gBootArgs, '\0', BOOT_STRING_LEN);
188
189if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
190clearGraphicBootPrompt();
191}
192}
193
194static void addBootArg(const char * argStr)
195{
196if ( (gBootArgsPtr + strlen(argStr) + 1) < gBootArgsEnd)
197{
198*gBootArgsPtr++ = ' ';
199strcat(gBootArgs, argStr);
200gBootArgsPtr += strlen(argStr);
201}
202}
203
204//==========================================================================
205
206static void showBootPrompt(int row, bool visible)
207{
208extern char bootPrompt[];
209extern char bootRescanPrompt[];
210
211if( bootArgs->Video.v_display == VGA_TEXT_MODE ) {
212changeCursor( 0, row, kCursorTypeUnderline, 0 );
213clearScreenRows( row, kScreenLastRow );
214}
215
216//clearBootArgs();
217
218if (visible) {
219if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
220if (gEnableCDROMRescan) {
221printf( bootRescanPrompt );
222} else {
223printf( bootPrompt );
224 printf( gBootArgs );
225}
226}
227} else {
228if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
229//clearGraphicBootPrompt();
230} else {
231printf("Press Enter to start up the foreign OS. ");
232}
233}
234}
235
236//==========================================================================
237
238static void updateBootArgs( int key )
239{
240 key &= kASCIIKeyMask;
241
242 switch ( key )
243 {
244 case kBackspaceKey:
245 if ( gBootArgsPtr > gBootArgs )
246 {
247 *--gBootArgsPtr = '\0';
248
249 int x, y, t;
250 getCursorPositionAndType( &x, &y, &t );
251 if ( x == 0 && y )
252 {
253 x = 80; y--;
254 }
255 if (x) x--;
256
257if( bootArgs->Video.v_display == VGA_TEXT_MODE )
258{
259setCursorPosition( x, y, 0 );
260putca(' ', 0x07, 1);
261}
262 else
263 {
264 updateGraphicBootPrompt();
265 }
266 }
267break;
268
269 default:
270 if ( key >= ' ' && gBootArgsPtr < gBootArgsEnd)
271 {
272 *gBootArgsPtr++ = key;
273
274 if( bootArgs->Video.v_display != VGA_TEXT_MODE ) updateGraphicBootPrompt();
275 else if ( key >= ' ' && key < 0x7f) putchar(key);
276}
277
278break;
279 }
280}
281
282//==========================================================================
283
284static const MenuItem * gMenuItems = NULL;
285
286static int gMenuItemCount;
287static int gMenuRow;
288static int gMenuHeight;
289static int gMenuTop;
290static int gMenuBottom;
291static int gMenuSelection;
292
293static int gMenuStart;
294static int gMenuEnd;
295
296static void printMenuItem( const MenuItem * item, int highlight )
297{
298 printf(" ");
299
300 if ( highlight )
301 putca(' ', 0x70, strlen(item->name) + 4);
302 else
303 putca(' ', 0x07, 40);
304
305 printf(" %40s\n", item->name);
306}
307
308//==========================================================================
309
310static void showMenu( const MenuItem * items, int count,
311 int selection, int row, int height )
312{
313 int i;
314 CursorState cursorState;
315
316 if ( items == NULL || count == 0 )
317return;
318
319 // head and tail points to the start and the end of the list.
320 // top and bottom points to the first and last visible items
321 // in the menu window.
322
323 gMenuItems= items;
324 gMenuRow= row;
325 gMenuHeight= height;
326 gMenuItemCount= count;
327 gMenuTop= 0;
328 gMenuBottom= MIN( count, height ) - 1;
329 gMenuSelection= selection;
330
331 gMenuStart= 0;
332 gMenuEnd = MIN( count, gui.maxdevices ) - 1;
333
334// If the selected item is not visible, shift the list down.
335
336 if ( gMenuSelection > gMenuBottom )
337 {
338 gMenuTop += ( gMenuSelection - gMenuBottom );
339 gMenuBottom = gMenuSelection;
340 }
341
342if ( gMenuSelection > gMenuEnd )
343 {
344gMenuStart += ( gMenuSelection - gMenuEnd );
345 gMenuEnd = gMenuSelection;
346 }
347
348// Draw the visible items.
349
350if( bootArgs->Video.v_display != VGA_TEXT_MODE )
351
352drawDeviceList(gMenuStart, gMenuEnd, gMenuSelection);
353
354else {
355
356changeCursor( 0, row, kCursorTypeHidden, &cursorState );
357
358for ( i = gMenuTop; i <= gMenuBottom; i++ )
359{
360printMenuItem( &items[i], (i == gMenuSelection) );
361}
362
363restoreCursor( &cursorState );
364 }
365}
366
367//==========================================================================
368
369static int updateMenu( int key, void ** paramPtr )
370{
371 int moved = 0;
372
373 union {
374 struct {
375 unsigned int
376 selectionUp : 1,
377 selectionDown : 1,
378 scrollUp : 1,
379 scrollDown : 1;
380 } f;
381 unsigned int w;
382 } draw = {{0}};
383
384 if ( gMenuItems == NULL )
385return 0;
386
387if( bootArgs->Video.v_display != VGA_TEXT_MODE )
388{
389int res;
390
391// set navigation keys for horizontal layout as defaults
392int previous= 0x4B00;// left arrow
393int subsequent= 0x4D00;// right arrow
394int menu= 0x5000;// down arrow
395
396if ( gui.layout == VerticalLayout )
397{
398// set navigation keys for vertical layout
399previous= 0x4800;// up arrow
400subsequent= 0x5000;// down arrow
401menu= 0x4B00;// right arrow
402}
403
404if ( key == previous )
405{
406if ( gMenuSelection > gMenuTop )
407draw.f.selectionUp = 1;
408else if ( gMenuTop > 0 )
409draw.f.scrollDown = 1;
410
411}
412
413else if ( key == subsequent )
414{
415if ( gMenuSelection != gMenuBottom)
416draw.f.selectionDown = 1;
417else if ( gMenuBottom < ( gMenuItemCount - 1 ) )
418draw.f.scrollUp = 1;
419}
420
421else if ( key == menu )
422{
423if ( gui.menu.draw )
424updateInfoMenu(key);
425else
426drawInfoMenu();
427}
428
429else if ( gui.menu.draw )
430{
431res = updateInfoMenu(key);
432
433if ( res == CLOSE_INFO_MENU )
434gui.menu.draw = false;
435else
436{
437shouldboot = ( res != DO_NOT_BOOT );
438
439if ( shouldboot )
440gui.menu.draw = false;
441
442switch (res)
443{
444case BOOT_NORMAL:
445gVerboseMode = false;
446gBootMode = kBootModeNormal;
447break;
448
449case BOOT_VERBOSE:
450gVerboseMode = true;
451gBootMode = kBootModeNormal;
452addBootArg(kVerboseModeFlag);
453break;
454
455case BOOT_IGNORECACHE:
456gVerboseMode = false;
457gBootMode = kBootModeNormal;
458addBootArg(kIgnoreCachesFlag);
459break;
460
461case BOOT_SINGLEUSER:
462gVerboseMode = true;
463gBootMode = kBootModeNormal;
464addBootArg(kSingleUserModeFlag);
465break;
466}
467
468}
469
470}
471
472} else {
473switch ( key )
474{
475 case 0x4800: // Up Arrow
476if ( gMenuSelection != gMenuTop )
477draw.f.selectionUp = 1;
478else if ( gMenuTop > 0 )
479draw.f.scrollDown = 1;
480break;
481
482case 0x5000: // Down Arrow
483if ( gMenuSelection != gMenuBottom )
484draw.f.selectionDown = 1;
485else if ( gMenuBottom < (gMenuItemCount - 1) )
486draw.f.scrollUp = 1;
487break;
488}
489}
490
491 if ( draw.w )
492 {
493 if ( draw.f.scrollUp )
494 {
495 scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, 1);
496 gMenuTop++; gMenuBottom++;
497gMenuStart++; gMenuEnd++;
498 draw.f.selectionDown = 1;
499 }
500
501 if ( draw.f.scrollDown )
502 {
503 scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, -1);
504 gMenuTop--; gMenuBottom--;
505 gMenuStart--; gMenuEnd--;
506 draw.f.selectionUp = 1;
507 }
508
509 if ( draw.f.selectionUp || draw.f.selectionDown )
510 {
511
512CursorState cursorState;
513
514// Set cursor at current position, and clear inverse video.
515
516if( bootArgs->Video.v_display == VGA_TEXT_MODE )
517{
518changeCursor( 0, gMenuRow + gMenuSelection - gMenuTop, kCursorTypeHidden, &cursorState );
519printMenuItem( &gMenuItems[gMenuSelection], 0 );
520}
521
522if ( draw.f.selectionUp )
523{
524gMenuSelection--;
525if(( gMenuSelection - gMenuStart) == -1 )
526{
527gMenuStart--;
528gMenuEnd--;
529}
530
531} else {
532gMenuSelection++;
533if(( gMenuSelection - ( gui.maxdevices - 1) - gMenuStart) > 0 )
534{
535gMenuStart++;
536gMenuEnd++;
537}
538 }
539
540if( bootArgs->Video.v_display == VGA_TEXT_MODE )
541 {
542moveCursor( 0, gMenuRow + gMenuSelection - gMenuTop );
543printMenuItem( &gMenuItems[gMenuSelection], 1 );
544restoreCursor( &cursorState );
545
546 } else
547
548drawDeviceList (gMenuStart, gMenuEnd, gMenuSelection);
549
550}
551
552 *paramPtr = gMenuItems[gMenuSelection].param;
553 moved = 1;
554 }
555
556return moved;
557}
558
559//==========================================================================
560
561static void skipblanks( const char ** cpp )
562{
563 while ( **(cpp) == ' ' || **(cpp) == '\t' ) ++(*cpp);
564}
565
566//==========================================================================
567
568static const char * extractKernelName( char ** cpp )
569{
570 char * kn = *cpp;
571 char * cp = *cpp;
572 char c;
573
574 // Convert char to lower case.
575
576 c = *cp | 0x20;
577
578 // Must start with a letter or a '/'.
579
580 if ( (c < 'a' || c > 'z') && ( c != '/' ) )
581 return 0;
582
583 // Keep consuming characters until we hit a separator.
584
585 while ( *cp && (*cp != '=') && (*cp != ' ') && (*cp != '\t') )
586 cp++;
587
588 // Only SPACE or TAB separator is accepted.
589 // Reject everything else.
590
591 if (*cp == '=')
592 return 0;
593
594 // Overwrite the separator, and move the pointer past
595 // the kernel name.
596
597 if (*cp != '\0') *cp++ = '\0';
598 *cpp = cp;
599
600 return kn;
601}
602
603//==========================================================================
604
605static void
606printMemoryInfo(void)
607{
608 int line;
609 int i;
610 MemoryRange *mp = bootInfo->memoryMap;
611
612 // Activate and clear page 1
613 setActiveDisplayPage(1);
614 clearScreenRows(0, 24);
615 setCursorPosition( 0, 0, 1 );
616
617 printf("BIOS reported memory ranges:\n");
618 line = 1;
619 for (i=0; i<bootInfo->memoryMapCount; i++) {
620 printf("Base 0x%08x%08x, ",
621 (unsigned long)(mp->base >> 32),
622 (unsigned long)(mp->base));
623 printf("length 0x%08x%08x, type %d\n",
624 (unsigned long)(mp->length >> 32),
625 (unsigned long)(mp->length),
626 mp->type);
627 if (line++ > 20) {
628 pause();
629 line = 0;
630 }
631 mp++;
632 }
633 if (line > 0) {
634 pause();
635 }
636
637 setActiveDisplayPage(0);
638}
639
640char *getMemoryInfoString()
641{
642 int i;
643 MemoryRange *mp = bootInfo->memoryMap;
644char *buff = malloc(sizeof(char)*1024);
645if(!buff) return 0;
646
647char info[] = "BIOS reported memory ranges:\n";
648sprintf(buff, "%s", info);
649 for (i=0; i<bootInfo->memoryMapCount; i++) {
650 sprintf( buff+strlen(buff), "Base 0x%08x%08x, ",
651 (unsigned long)(mp->base >> 32),
652 (unsigned long)(mp->base));
653 sprintf( buff+strlen(buff), "length 0x%08x%08x, type %d\n",
654 (unsigned long)(mp->length >> 32),
655 (unsigned long)(mp->length),
656 mp->type);
657 mp++;
658 }
659return buff;
660}
661
662//==========================================================================
663
664void lspci(void)
665{
666if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
667setActiveDisplayPage(1);
668clearScreenRows(0, 24);
669setCursorPosition(0, 0, 1);
670}
671
672dump_pci_dt(root_pci_dev->children);
673
674pause();
675
676if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
677setActiveDisplayPage(0);
678}
679}
680
681//==========================================================================
682
683int getBootOptions(bool firstRun)
684{
685int i;
686int key;
687int nextRow;
688int timeout;
689int bvCount;
690BVRef bvr;
691BVRef menuBVR;
692bool showPrompt, newShowPrompt, isCDROM;
693
694// Initialize default menu selection entry.
695gBootVolume = menuBVR = selectBootVolume(bvChain);
696
697if (biosDevIsCDROM(gBIOSDev)) {
698isCDROM = true;
699} else {
700isCDROM = false;
701}
702
703// ensure we're in graphics mode if gui is setup
704if (firstRun && gui.initialised && bootArgs->Video.v_display == VGA_TEXT_MODE)
705{
706setVideoMode(GRAPHICS_MODE, 0);
707}
708
709// Clear command line boot arguments
710clearBootArgs();
711
712// Allow user to override default timeout.
713if (multiboot_timeout_set) {
714timeout = multiboot_timeout;
715} else if (!getIntForKey(kTimeoutKey, &timeout, &bootInfo->chameleonConfig)) {
716/* If there is no timeout key in the file use the default timeout
717 which is different for CDs vs. hard disks. However, if not booting
718 a CD and no config file could be loaded set the timeout
719 to zero which causes the menu to display immediately.
720 This way, if no partitions can be found, that is the disk is unpartitioned
721 or simply cannot be read) then an empty menu is displayed.
722 If some partitions are found, for example a Windows partition, then
723 these will be displayed in the menu as foreign partitions.
724 */
725if (isCDROM) {
726timeout = kCDBootTimeout;
727} else {
728timeout = sysConfigValid ? kBootTimeout : 0;
729}
730}
731
732if (timeout < 0) {
733gBootMode |= kBootModeQuiet;
734}
735
736// If the user is holding down a modifier key, enter safe mode.
737if ((readKeyboardShiftFlags() & 0x0F) != 0) {
738gBootMode |= kBootModeSafe;
739}
740
741// Checking user pressed keys
742bool f8press = false, spress = false, vpress = false;
743while (readKeyboardStatus()) {
744key = bgetc ();
745if (key == 0x4200) f8press = true;
746if ((key & 0xff) == 's' || (key & 0xff) == 'S') spress = true;
747if ((key & 0xff) == 'v' || (key & 0xff) == 'V') vpress = true;
748}
749// If user typed F8, abort quiet mode, and display the menu.
750if (f8press) {
751gBootMode &= ~kBootModeQuiet;
752timeout = 0;
753}
754// If user typed 'v' or 'V', boot in verbose mode.
755if ((gBootMode & kBootModeQuiet) && firstRun && vpress) {
756addBootArg(kVerboseModeFlag);
757}
758// If user typed 's' or 'S', boot in single user mode.
759if ((gBootMode & kBootModeQuiet) && firstRun && spress) {
760addBootArg(kSingleUserModeFlag);
761}
762
763if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
764setCursorPosition(0, 0, 0);
765clearScreenRows(0, kScreenLastRow);
766if (!(gBootMode & kBootModeQuiet)) {
767// Display banner and show hardware info.
768printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
769printf(getVBEInfoString());
770}
771changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
772verbose("Scanning device %x...", gBIOSDev);
773}
774
775// When booting from CD, default to hard drive boot when possible.
776if (isCDROM && firstRun) {
777const char *val;
778char *prompt = NULL;
779char *name = NULL;
780int cnt;
781int optionKey;
782
783if (getValueForKey(kCDROMPromptKey, &val, &cnt, &bootInfo->chameleonConfig)) {
784prompt = malloc(cnt + 1);
785strncat(prompt, val, cnt);
786} else {
787name = malloc(80);
788getBootVolumeDescription(gBootVolume, name, 79, false);
789prompt = malloc(256);
790sprintf(prompt, "Press any key to start up from %s, or press F8 to enter startup options.", name);
791free(name);
792}
793
794if (getIntForKey( kCDROMOptionKey, &optionKey, &bootInfo->chameleonConfig )) {
795// The key specified is a special key.
796} else {
797// Default to F8.
798optionKey = 0x4200;
799}
800
801// If the timeout is zero then it must have been set above due to the
802// early catch of F8 which means the user wants to set boot options
803// which we ought to interpret as meaning he wants to boot the CD.
804if (timeout != 0) {
805key = countdown(prompt, kMenuTopRow, timeout);
806} else {
807key = optionKey;
808}
809
810if (prompt != NULL) {
811free(prompt);
812}
813
814clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
815
816// Hit the option key ?
817if (key == optionKey) {
818gBootMode &= ~kBootModeQuiet;
819timeout = 0;
820} else {
821key = key & 0xFF;
822
823// Try booting hard disk if user pressed 'h'
824if (biosDevIsCDROM(gBIOSDev) && key == 'h') {
825BVRef bvr;
826
827// Look at partitions hosting OS X other than the CD-ROM
828for (bvr = bvChain; bvr; bvr=bvr->next) {
829if ((bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != gBIOSDev) {
830gBootVolume = bvr;
831}
832}
833}
834goto done;
835}
836}
837
838if (gBootMode & kBootModeQuiet) {
839// No input allowed from user.
840goto done;
841}
842
843if (firstRun && timeout > 0 && countdown("Press any key to enter startup options.", kMenuTopRow, timeout) == 0) {
844// If the user is holding down a modifier key,
845// enter safe mode.
846if ((readKeyboardShiftFlags() & 0x0F) != 0) {
847gBootMode |= kBootModeSafe;
848}
849goto done;
850}
851
852if (gDeviceCount) {
853// Allocate memory for an array of menu items.
854menuItems = malloc(sizeof(MenuItem) * gDeviceCount);
855if (menuItems == NULL) {
856goto done;
857}
858
859// Associate a menu item for each BVRef.
860for (bvr=bvChain, i=gDeviceCount-1, selectIndex=0; bvr; bvr=bvr->next) {
861if (bvr->visible) {
862getBootVolumeDescription(bvr, menuItems[i].name, sizeof(menuItems[i].name) - 1, true);
863menuItems[i].param = (void *) bvr;
864if (bvr == menuBVR) {
865selectIndex = i;
866}
867i--;
868}
869}
870}
871
872if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
873// redraw the background buffer
874gui.logo.draw = true;
875drawBackground();
876gui.devicelist.draw = true;
877gui.redraw = true;
878if (!(gBootMode & kBootModeQuiet)) {
879
880// Check if "Boot Banner"=N switch is present in config file.
881getBoolForKey(kBootBannerKey, &showBootBanner, &bootInfo->chameleonConfig);
882if (showBootBanner) {
883// Display banner and show hardware info.
884gprintf(&gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024);
885}
886
887// redraw background
888memcpy(gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4);
889}
890} else {
891// Clear screen and hide the blinking cursor.
892clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
893changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
894}
895
896nextRow = kMenuTopRow;
897showPrompt = true;
898
899if (gDeviceCount) {
900if( bootArgs->Video.v_display == VGA_TEXT_MODE ) {
901printf("Use \30\31 keys to select the startup volume.");
902}
903showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
904nextRow += MIN( gDeviceCount, kMenuMaxItems ) + 3;
905}
906
907// Show the boot prompt.
908showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
909showBootPrompt( nextRow, showPrompt );
910
911do {
912if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
913// redraw background
914memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
915// reset cursor co-ords
916gui.debug.cursor = pos( gui.screen.width - 160 , 10 );
917}
918key = getchar();
919updateMenu( key, (void **) &menuBVR );
920newShowPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
921
922if (newShowPrompt != showPrompt) {
923showPrompt = newShowPrompt;
924showBootPrompt( nextRow, showPrompt );
925}
926
927if (showPrompt) {
928updateBootArgs(key);
929}
930
931switch (key) {
932case kReturnKey:
933if (gui.menu.draw) {
934key=0;
935break;
936}
937if (*gBootArgs == '?') {
938char * argPtr = gBootArgs;
939
940// Skip the leading "?" character.
941argPtr++;
942getNextArg(&argPtr, booterCommand);
943getNextArg(&argPtr, booterParam);
944
945/*
946* TODO: this needs to be refactored.
947*/
948if (strcmp( booterCommand, "video" ) == 0) {
949if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
950showInfoBox(getVBEInfoString(), getVBEModeInfoString());
951} else {
952printVBEModeInfo();
953}
954} else if ( strcmp( booterCommand, "memory" ) == 0) {
955if (bootArgs->Video.v_display != VGA_TEXT_MODE ) {
956showInfoBox("Memory Map", getMemoryInfoString());
957} else {
958printMemoryInfo();
959}
960} else if (strcmp(booterCommand, "lspci") == 0) {
961lspci();
962} else if (strcmp(booterCommand, "more") == 0) {
963showTextFile(booterParam);
964} else if (strcmp(booterCommand, "rd") == 0) {
965processRAMDiskCommand(&argPtr, booterParam);
966} else if (strcmp(booterCommand, "norescan") == 0) {
967if (gEnableCDROMRescan) {
968gEnableCDROMRescan = false;
969break;
970}
971} else {
972showHelp();
973}
974key = 0;
975showBootPrompt(nextRow, showPrompt);
976break;
977}
978gBootVolume = menuBVR;
979setRootVolume(menuBVR);
980gBIOSDev = menuBVR->biosdev;
981break;
982
983case kEscapeKey:
984clearBootArgs();
985break;
986
987//Azi:autoresolution - Reapply the patch if Graphics Mode was incorrect
988// or EDID Info was insane.
989case kF2Key:
990
991if ((gAutoResolution == true) && useGUI && map )
992{
993// get the new Graphics Mode key
994processBootOptions(); //Azi: use processBootArgument instead?
995
996//UInt32 paramsAR[4];
997paramsAR[3] = 0;
998
999getNumberArrayFromProperty(kGraphicsModeKey, paramsAR, 4);
1000
1001// user changed resolution...
1002if ((paramsAR[0] != 0) && (paramsAR[1] != 0) &&
1003(paramsAR[0] != map->currentX) && (paramsAR[1] != map->currentY))
1004{
1005//Azi: identical to "case kTabKey:"(check later)
1006if (bootArgs->Video.v_display == GRAPHICS_MODE)
1007{
1008CursorState cursorState;
1009
1010// Go back to TEXT MODE while we change the mode
1011setVideoMode(VGA_TEXT_MODE, 0);
1012
1013setCursorPosition(0, 0, 0);
1014clearScreenRows(0, kScreenLastRow);
1015changeCursor( 0, 0, kCursorTypeHidden, &cursorState );
1016
1017// Reapply patch
1018patchVbios(map, paramsAR[0], paramsAR[1], paramsAR[2], 0, 0);
1019
1020if (useGUI && (gui.initialised == true))
1021initGUI();
1022// Make sure all values are set
1023if (bootArgs->Video.v_display != GRAPHICS_MODE)
1024bootArgs->Video.v_display = GRAPHICS_MODE;
1025
1026if (!useGUI)
1027useGUI = true;
1028
1029// redraw the background buffer
1030drawBackground();
1031gui.devicelist.draw = true;
1032gui.redraw = true;
1033
1034if (showBootBanner)
1035{
1036// Display banner and show hardware info.
1037gprintf(&gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024);
1038}
1039
1040// redraw background
1041memcpy(gui.backbuffer->pixels, gui.screen.pixmap->pixels,
1042 gui.backbuffer->width * gui.backbuffer->height * 4);
1043
1044nextRow = kMenuTopRow;
1045showPrompt = true;
1046
1047if (gDeviceCount)
1048{
1049showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
1050nextRow += MIN( gDeviceCount, kMenuMaxItems ) + 3;
1051}
1052
1053// Show the boot prompt.
1054showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1055showBootPrompt( nextRow, showPrompt );
1056
1057// this is used to avoid resetting the incorrect mode while quiting the boot menu
1058//map->hasSwitched = true; (check again later!)
1059}
1060}
1061
1062clearBootArgs();
1063key = 0;
1064}
1065else // if gAutoResolution == false...
1066{
1067// ... do "nothing".(Reviewing...)
1068clearBootArgs();
1069key = 0;
1070}
1071break;
1072
1073case kF5Key:
1074// New behavior:
1075// Clear gBootVolume to restart the loop
1076// if the user enabled rescanning the optical drive.
1077// Otherwise boot the default boot volume.
1078if (gEnableCDROMRescan) {
1079gBootVolume = NULL;
1080clearBootArgs();
1081}
1082break;
1083
1084case kF10Key:
1085gScanSingleDrive = false;
1086scanDisks(gBIOSDev, &bvCount);
1087gBootVolume = NULL;
1088clearBootArgs();
1089break;
1090
1091case kTabKey:
1092// New behavior:
1093// Switch between text & graphic interfaces
1094// Only Permitted if started in graphics interface
1095if (useGUI) {
1096if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
1097setVideoMode(VGA_TEXT_MODE, 0);
1098
1099setCursorPosition(0, 0, 0);
1100clearScreenRows(0, kScreenLastRow);
1101
1102// Display banner and show hardware info.
1103printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
1104printf(getVBEInfoString());
1105
1106clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
1107changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
1108
1109nextRow = kMenuTopRow;
1110showPrompt = true;
1111
1112if (gDeviceCount) {
1113printf("Use \30\31 keys to select the startup volume.");
1114showMenu(menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems);
1115nextRow += MIN(gDeviceCount, kMenuMaxItems) + 3;
1116}
1117
1118showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1119showBootPrompt(nextRow, showPrompt);
1120//changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
1121
1122/*
1123 * AutoResolution - make sure all values are set - Azi: think! it makes some sense!!
1124 */
1125//bootArgs->Video.v_display = VGA_TEXT_MODE;
1126//useGUI = false;
1127
1128} else {
1129gui.redraw = true;
1130setVideoMode(GRAPHICS_MODE, 0);
1131
1132/*
1133 * AutoResolution - make sure all values are set - Azi: same as above...!?
1134 */
1135//bootArgs->Video.v_display = GRAPHICS_MODE;
1136//useGUI = true;
1137
1138updateVRAM();
1139 updateGraphicBootPrompt();
1140}
1141}
1142key = 0;
1143break;
1144
1145default:
1146key = 0;
1147break;
1148}
1149} while (0 == key);
1150
1151done:
1152if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
1153clearScreenRows(kMenuTopRow, kScreenLastRow);
1154changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
1155}
1156shouldboot = false;
1157gui.menu.draw = false;
1158if (menuItems) {
1159free(menuItems);
1160menuItems = NULL;
1161}
1162return 0;
1163}
1164
1165//==========================================================================
1166
1167extern unsigned char chainbootdev;
1168extern unsigned char chainbootflag;
1169
1170bool copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
1171{
1172 int argLen = argName ? strlen(argName) : 0;
1173 int len = argLen + cnt + 1; // +1 to account for space
1174
1175 if (len > *cntRemainingP) {
1176 error("Warning: boot arguments too long, truncating\n");
1177 return false;
1178 }
1179
1180 if (argName) {
1181 strncpy( *argP, argName, argLen );
1182 *argP += argLen;
1183 *argP[0] = '=';
1184 (*argP)++;
1185 len++; // +1 to account for '='
1186 }
1187 strncpy( *argP, val, cnt );
1188 *argP += cnt;
1189 *argP[0] = ' ';
1190 (*argP)++;
1191
1192 *cntRemainingP -= len;
1193 return true;
1194}
1195
1196//
1197// Returns TRUE if an argument was copied, FALSE otherwise
1198bool
1199processBootArgument(
1200 const char *argName, // The argument to search for
1201 const char *userString, // Typed-in boot arguments
1202 const char *kernelFlags, // Kernel flags from config table
1203 const char *configTable,
1204 char **argP, // Output value
1205 int *cntRemainingP, // Output count
1206 char *foundVal // found value
1207 )
1208{
1209 const char *val;
1210 int cnt;
1211 bool found = false;
1212
1213 if (getValueForBootKey(userString, argName, &val, &cnt)) {
1214 // Don't copy; these values will be copied at the end of argument processing.
1215 found = true;
1216 } else if (getValueForBootKey(kernelFlags, argName, &val, &cnt)) {
1217 // Don't copy; these values will be copied at the end of argument processing.
1218 found = true;
1219 } else if (getValueForKey(argName, &val, &cnt, &bootInfo->chameleonConfig)) {
1220 copyArgument(argName, val, cnt, argP, cntRemainingP);
1221 found = true;
1222 }
1223 if (found && foundVal) {
1224 strlcpy(foundVal, val, cnt+1);
1225 }
1226 return found;
1227}
1228
1229// Maximum config table value size
1230#define VALUE_SIZE 2048
1231
1232int
1233processBootOptions()
1234{
1235 const char * cp = gBootArgs;
1236 const char * val = 0;
1237 const char * kernel;
1238 int cnt;
1239 int userCnt;
1240 int cntRemaining;
1241 char * argP;
1242 char uuidStr[64];
1243 bool uuidSet = false;
1244 char * configKernelFlags;
1245 char * valueBuffer;
1246
1247 valueBuffer = malloc(VALUE_SIZE);
1248
1249 skipblanks( &cp );
1250
1251 // Update the unit and partition number.
1252
1253 if ( gBootVolume )
1254 {
1255 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
1256 {
1257 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
1258 (void *) 0x7c00 );
1259
1260 //
1261 // Setup edx, and signal intention to chain load the
1262 // foreign booter.
1263 //
1264
1265 chainbootdev = gBootVolume->biosdev;
1266 chainbootflag = 1;
1267
1268 return 1;
1269 }
1270
1271 setRootVolume(gBootVolume);
1272
1273 }
1274 // If no boot volume fail immediately because we're just going to fail
1275 // trying to load the config file anyway.
1276 else
1277 return -1;
1278
1279 // Load config table specified by the user, or use the default.
1280
1281 if (!getValueForBootKey(cp, "config", &val, &cnt)) {
1282 val = 0;
1283 cnt = 0;
1284 }
1285
1286 // Load com.apple.Boot.plist from the selected volume
1287 // and use its contents to override default bootConfig.
1288
1289 loadSystemConfig(&bootInfo->bootConfig);
1290 loadChameleonConfig(&bootInfo->chameleonConfig);
1291
1292 // Use the kernel name specified by the user, or fetch the name
1293 // in the config table, or use the default if not specified.
1294 // Specifying a kernel name on the command line, or specifying
1295 // a non-default kernel name in the config file counts as
1296 // overriding the kernel, which causes the kernelcache not
1297 // to be used.
1298
1299 gOverrideKernel = false;
1300 if (( kernel = extractKernelName((char **)&cp) )) {
1301 strcpy( bootInfo->bootFile, kernel );
1302 gOverrideKernel = true;
1303 } else {
1304 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1305 strlcpy( bootInfo->bootFile, val, cnt+1 );
1306 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
1307 gOverrideKernel = true;
1308 }
1309 } else {
1310 strcpy( bootInfo->bootFile, kDefaultKernel );
1311 }
1312 }
1313
1314 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1315 argP = bootArgs->CommandLine;
1316
1317 // Get config table kernel flags, if not ignored.
1318 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1319 !getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) {
1320 val = "";
1321 cnt = 0;
1322 }
1323 configKernelFlags = malloc(cnt + 1);
1324 strlcpy(configKernelFlags, val, cnt + 1);
1325
1326 if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1327 // boot-uuid was set either on the command-line
1328 // or in the config file.
1329 uuidSet = true;
1330 } else {
1331
1332 //
1333 // Try an alternate method for getting the root UUID on boot helper partitions.
1334 //
1335 if (gBootVolume->flags & kBVFlagBooter)
1336 {
1337 if((loadHelperConfig(&bootInfo->helperConfig) == 0)
1338 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
1339 {
1340 getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
1341 copyArgument(kBootUUIDKey, val, cnt, &argP, &cntRemaining);
1342 uuidSet = true;
1343 }
1344 }
1345
1346 if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid (gBootVolume, uuidStr) == 0) {
1347 verbose("Setting boot-uuid to: %s\n", uuidStr);
1348 copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining);
1349 uuidSet = true;
1350 }
1351
1352 }
1353
1354 if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) {
1355 cnt = 0;
1356 if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->chameleonConfig)) {
1357 valueBuffer[0] = '*';
1358 cnt++;
1359 strlcpy(valueBuffer + 1, val, cnt);
1360 val = valueBuffer;
1361 } else {
1362 if (uuidSet) {
1363 val = "*uuid";
1364 cnt = 5;
1365 } else {
1366 // Don't set "rd=.." if there is no boot device key
1367 // and no UUID.
1368 val = "";
1369 cnt = 0;
1370 }
1371 }
1372 if (cnt > 0) {
1373 copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1374 }
1375 strlcpy( gRootDevice, val, (cnt + 1));
1376 }
1377
1378 /*
1379 * Removed. We don't need this anymore.
1380 *
1381 if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) {
1382 getPlatformName(gPlatformName);
1383 copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining);
1384 }
1385 */
1386
1387 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1388 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
1389 if (gBootMode & kBootModeSafe) {
1390 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1391 }
1392 }
1393
1394 // Store the merged kernel flags and boot args.
1395
1396 cnt = strlen(configKernelFlags);
1397 if (cnt) {
1398 if (cnt > cntRemaining) {
1399 error("Warning: boot arguments too long, truncating\n");
1400 cnt = cntRemaining;
1401 }
1402 strncpy(argP, configKernelFlags, cnt);
1403 argP[cnt++] = ' ';
1404 cntRemaining -= cnt;
1405 }
1406 userCnt = strlen(cp);
1407 if (userCnt > cntRemaining) {
1408 error("Warning: boot arguments too long, truncating\n");
1409 userCnt = cntRemaining;
1410 }
1411 strncpy(&argP[cnt], cp, userCnt);
1412 argP[cnt+userCnt] = '\0';
1413
1414if(!shouldboot)
1415{
1416gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->chameleonConfig ) ||
1417getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->chameleonConfig );
1418
1419gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->chameleonConfig ) ) ?
1420kBootModeSafe : kBootModeNormal;
1421
1422 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->chameleonConfig ) ) {
1423 gBootMode = kBootModeSafe;
1424 }
1425}
1426
1427if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) )
1428{
1429strlcpy(gMKextName, val, cnt + 1);
1430}
1431
1432 free(configKernelFlags);
1433 free(valueBuffer);
1434
1435 return 0;
1436}
1437
1438
1439//==========================================================================
1440// Load the help file and display the file contents on the screen.
1441
1442void showTextBuffer(char *buf_orig, int size)
1443{
1444char*bp;
1445char* buf;
1446intline;
1447intline_offset;
1448intc;
1449
1450if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
1451showInfoBox( "Press q to continue, space for next page.\n",buf_orig );
1452return;
1453}
1454
1455// Create a copy so that we don't mangle the original
1456buf = malloc(size + 1);
1457memcpy(buf, buf_orig, size);
1458
1459
1460 bp = buf;
1461 while (size-- > 0) {
1462if (*bp == '\n') {
1463*bp = '\0';
1464}
1465bp++;
1466 }
1467 *bp = '\1';
1468 line_offset = 0;
1469
1470 setActiveDisplayPage(1);
1471
1472 while (1) {
1473clearScreenRows(0, 24);
1474setCursorPosition(0, 0, 1);
1475bp = buf;
1476for (line = 0; *bp != '\1' && line < line_offset; line++) {
1477while (*bp != '\0') {
1478bp++;
1479}
1480bp++;
1481}
1482for (line = 0; *bp != '\1' && line < 23; line++) {
1483setCursorPosition(0, line, 1);
1484printf("%s\n", bp);
1485while (*bp != '\0') {
1486bp++;
1487}
1488bp++;
1489}
1490
1491setCursorPosition(0, 23, 1);
1492if (*bp == '\1') {
1493printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1494} else {
1495printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1496}
1497
1498c = getchar();
1499if (c == 'q' || c == 'Q') {
1500break;
1501}
1502if ((c == 'p' || c == 'P') && line_offset > 0) {
1503line_offset -= 23;
1504}
1505if (c == ' ') {
1506if (*bp == '\1') {
1507break;
1508} else {
1509line_offset += 23;
1510}
1511}
1512 }
1513 setActiveDisplayPage(0);
1514}
1515
1516void showHelp(void)
1517{
1518if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
1519showInfoBox("Help. Press q to quit.\n", (char *)BootHelp_txt);
1520} else {
1521showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1522}
1523}
1524
1525void showTextFile(const char * filename)
1526{
1527#define MAX_TEXT_FILE_SIZE 65536
1528char*buf;
1529intfd;
1530intsize;
1531
1532if ((fd = open_bvdev("bt(0,0)", filename, 0)) < 0) {
1533printf("\nFile not found: %s\n", filename);
1534sleep(2);
1535return;
1536}
1537
1538 size = file_size(fd);
1539 if (size > MAX_TEXT_FILE_SIZE) {
1540size = MAX_TEXT_FILE_SIZE;
1541}
1542 buf = malloc(size);
1543 read(fd, buf, size);
1544 close(fd);
1545showTextBuffer(buf, size);
1546free(buf);
1547}
1548
1549// This is a very simplistic prompting scheme that just grabs two hex characters
1550// Eventually we need to do something more user-friendly like display a menu
1551// based off of the Multiboot device list
1552
1553int selectAlternateBootDevice(int bootdevice)
1554{
1555int key;
1556int newbootdevice;
1557int digitsI = 0;
1558char *end;
1559char digits[3] = {0,0,0};
1560
1561// We've already printed the current boot device so user knows what it is
1562printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1563printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1564do {
1565key = getchar();
1566switch (key & kASCIIKeyMask) {
1567case kBackspaceKey:
1568if (digitsI > 0) {
1569int x, y, t;
1570getCursorPositionAndType(&x, &y, &t);
1571// Assume x is not 0;
1572x--;
1573setCursorPosition(x,y,0); // back up one char
1574// Overwrite with space without moving cursor position
1575putca(' ', 0x07, 1);
1576digitsI--;
1577} else {
1578// TODO: Beep or something
1579}
1580break;
1581
1582case kReturnKey:
1583digits[digitsI] = '\0';
1584newbootdevice = strtol(digits, &end, 16);
1585if (end == digits && *end == '\0') {
1586// User entered empty string
1587printf("\nUsing default boot device %x\n", bootdevice);
1588key = 0;
1589} else if(end != digits && *end == '\0') {
1590bootdevice = newbootdevice;
1591printf("\n");
1592key = 0; // We gots da boot device
1593} else {
1594printf("\nCouldn't parse. try again: ");
1595digitsI = 0;
1596}
1597break;
1598
1599default:
1600if (isxdigit(key & kASCIIKeyMask) && digitsI < 2) {
1601putchar(key & kASCIIKeyMask);
1602digits[digitsI++] = key & kASCIIKeyMask;
1603} else {
1604// TODO: Beep or something
1605}
1606break;
1607};
1608} while (key != 0);
1609
1610return bootdevice;
1611}
1612
1613bool promptForRescanOption(void)
1614{
1615printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1616if (getchar() == kReturnKey) {
1617return true;
1618} else {
1619return false;
1620}
1621}
1622

Archive Download this file

Revision: 1421