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

Archive Download this file

Revision: 1023