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

Archive Download this file

Revision: 1022