Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 511