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

Archive Download this file

Revision: 946