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) {
945if (bootArgs->Video.v_display == GRAPHICS_MODE) {
946showInfoBox(getVBEInfoString(), getVBEModeInfoString());
947} else {
948printVBEModeInfo();
949}
950} else if ( strcmp( booterCommand, "memory" ) == 0) {
951if (bootArgs->Video.v_display == GRAPHICS_MODE ) {
952showInfoBox("Memory Map", getMemoryInfoString());
953} else {
954printMemoryInfo();
955}
956} else if (strcmp(booterCommand, "lspci") == 0) {
957lspci();
958} else if (strcmp(booterCommand, "more") == 0) {
959showTextFile(booterParam);
960} else if (strcmp(booterCommand, "rd") == 0) {
961processRAMDiskCommand(&argPtr, booterParam);
962} else if (strcmp(booterCommand, "norescan") == 0) {
963if (gEnableCDROMRescan) {
964gEnableCDROMRescan = false;
965break;
966}
967} else {
968showHelp();
969}
970key = 0;
971showBootPrompt(nextRow, showPrompt);
972break;
973}
974gBootVolume = menuBVR;
975setRootVolume(menuBVR);
976gBIOSDev = menuBVR->biosdev;
977break;
978
979case kEscapeKey:
980clearBootArgs();
981break;
982
983/*
984 * AutoResolution - Reapply the patch if Graphics Mode was incorrect
985 * or EDID Info was insane
986 */
987case kF2Key:
988
989//get the new Graphics Mode key
990processBootOptions();
991if ((gAutoResolution == TRUE) && map)
992{
993UInt32 params[4];
994params[3] = 0;
995//Has the target Resolution Changed ?
996int count = getNumberArrayFromProperty(kGraphicsModeKey, params, 4);
997if ( count < 3 )
998getResolution(params);
999
1000if ((params[0] != 0) && (params[1] != 0)
1001&&(params[0] != map->currentX) && (params[1] != map->currentY))
1002{
1003
1004//Go back to TEXT mode while we change the mode
1005if (bootArgs->Video.v_display == GRAPHICS_MODE)
1006{
1007CursorState cursorState;
1008
1009setVideoMode(VGA_TEXT_MODE, 0);
1010
1011setCursorPosition(0, 0, 0);
1012clearScreenRows(0, kScreenLastRow);
1013changeCursor( 0, 0, kCursorTypeHidden, &cursorState );
1014
1015//Reapply patch in case resolution have changed
1016
1017patchVbios(map, params[0], params[1], params[2], 0, 0);
1018
1019if (useGUI && (gui.initialised == true))
1020initGUI();
1021// Make sure all values are set
1022if (bootArgs->Video.v_display != GRAPHICS_MODE)
1023bootArgs->Video.v_display = GRAPHICS_MODE;
1024
1025if (!useGUI)
1026useGUI = true;
1027
1028// redraw the background buffer
1029drawBackground();
1030gui.devicelist.draw = true;
1031gui.redraw = true;
1032if (!(gBootMode & kBootModeQuiet))
1033{
1034
1035// Check if "Boot Banner"=N switch is present in config file.
1036getBoolForKey(kBootBannerKey, &showBootBanner, &bootInfo->bootConfig);
1037if (showBootBanner)
1038// Display banner and show hardware info.
1039gprintf(&gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024);
1040
1041// redraw background
1042memcpy(gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4);
1043}
1044
1045nextRow = kMenuTopRow;
1046showPrompt = true;
1047
1048if (gDeviceCount)
1049{
1050showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
1051nextRow += min( gDeviceCount, kMenuMaxItems ) + 3;
1052}
1053
1054// Show the boot prompt.
1055showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1056showBootPrompt( nextRow, showPrompt );
1057
1058//this is used to avoid resetting the incorrect mode while quiting the boot menu
1059map->hasSwitched = true;
1060}
1061}
1062clearBootArgs();
1063key = 0;
1064}
1065break;
1066
1067case kF5Key:
1068// New behavior:
1069// Clear gBootVolume to restart the loop
1070// if the user enabled rescanning the optical drive.
1071// Otherwise boot the default boot volume.
1072if (gEnableCDROMRescan) {
1073gBootVolume = NULL;
1074clearBootArgs();
1075}
1076break;
1077
1078case kF10Key:
1079gScanSingleDrive = false;
1080scanDisks(gBIOSDev, &bvCount);
1081gBootVolume = NULL;
1082clearBootArgs();
1083break;
1084
1085case kTabKey:
1086// New behavior:
1087// Switch between text & graphic interfaces
1088// Only Permitted if started in graphics interface
1089if (useGUI) {
1090if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1091setVideoMode(VGA_TEXT_MODE, 0);
1092
1093setCursorPosition(0, 0, 0);
1094clearScreenRows(0, kScreenLastRow);
1095
1096// Display banner and show hardware info.
1097printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
1098printf(getVBEInfoString());
1099
1100clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
1101changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
1102
1103nextRow = kMenuTopRow;
1104showPrompt = true;
1105
1106if (gDeviceCount) {
1107printf("Use \30\31 keys to select the startup volume.");
1108showMenu(menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems);
1109nextRow += min(gDeviceCount, kMenuMaxItems) + 3;
1110}
1111
1112showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1113showBootPrompt(nextRow, showPrompt);
1114//changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
1115} else {
1116gui.redraw = true;
1117setVideoMode(GRAPHICS_MODE, 0);
1118updateVRAM();
1119}
1120}
1121key = 0;
1122break;
1123
1124default:
1125key = 0;
1126break;
1127}
1128} while (0 == key);
1129
1130done:
1131if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
1132clearScreenRows(kMenuTopRow, kScreenLastRow);
1133changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
1134}
1135shouldboot = false;
1136gui.menu.draw = false;
1137if (menuItems) {
1138free(menuItems);
1139menuItems = NULL;
1140}
1141return 0;
1142}
1143
1144//==========================================================================
1145
1146extern unsigned char chainbootdev;
1147extern unsigned char chainbootflag;
1148
1149bool copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
1150{
1151 int argLen = argName ? strlen(argName) : 0;
1152 int len = argLen + cnt + 1; // +1 to account for space
1153
1154 if (len > *cntRemainingP) {
1155 error("Warning: boot arguments too long, truncating\n");
1156 return false;
1157 }
1158
1159 if (argName) {
1160 strncpy( *argP, argName, argLen );
1161 *argP += argLen;
1162 *argP[0] = '=';
1163 (*argP)++;
1164 len++; // +1 to account for '='
1165 }
1166 strncpy( *argP, val, cnt );
1167 *argP += cnt;
1168 *argP[0] = ' ';
1169 (*argP)++;
1170
1171 *cntRemainingP -= len;
1172 return true;
1173}
1174
1175//
1176// Returns TRUE if an argument was copied, FALSE otherwise
1177bool
1178processBootArgument(
1179 const char *argName, // The argument to search for
1180 const char *userString, // Typed-in boot arguments
1181 const char *kernelFlags, // Kernel flags from config table
1182 const char *configTable,
1183 char **argP, // Output value
1184 int *cntRemainingP, // Output count
1185 char *foundVal // found value
1186 )
1187{
1188 const char *val;
1189 int cnt;
1190 bool found = false;
1191
1192 if (getValueForBootKey(userString, argName, &val, &cnt)) {
1193 // Don't copy; these values will be copied at the end of argument processing.
1194 found = true;
1195 } else if (getValueForBootKey(kernelFlags, argName, &val, &cnt)) {
1196 // Don't copy; these values will be copied at the end of argument processing.
1197 found = true;
1198 } else if (getValueForKey(argName, &val, &cnt, &bootInfo->bootConfig)) {
1199 copyArgument(argName, val, cnt, argP, cntRemainingP);
1200 found = true;
1201 }
1202 if (found && foundVal) {
1203 strlcpy(foundVal, val, cnt+1);
1204 }
1205 return found;
1206}
1207
1208// Maximum config table value size
1209#define VALUE_SIZE 2048
1210
1211int
1212processBootOptions()
1213{
1214 const char * cp = gBootArgs;
1215 const char * val = 0;
1216 const char * kernel;
1217 int cnt;
1218 int userCnt;
1219 int cntRemaining;
1220 char * argP;
1221 char uuidStr[64];
1222 bool uuidSet = false;
1223 char * configKernelFlags;
1224 char * valueBuffer;
1225
1226 valueBuffer = malloc(VALUE_SIZE);
1227
1228 skipblanks( &cp );
1229
1230 // Update the unit and partition number.
1231
1232 if ( gBootVolume )
1233 {
1234 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
1235 {
1236 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
1237 (void *) 0x7c00 );
1238
1239 //
1240 // Setup edx, and signal intention to chain load the
1241 // foreign booter.
1242 //
1243
1244 chainbootdev = gBootVolume->biosdev;
1245 chainbootflag = 1;
1246
1247 return 1;
1248 }
1249
1250 setRootVolume(gBootVolume);
1251
1252 }
1253 // If no boot volume fail immediately because we're just going to fail
1254 // trying to load the config file anyway.
1255 else
1256 return -1;
1257
1258// Moved here to enable search for override Boot.plist on OS specific folders.
1259// Find out which Mac OS version we're booting.
1260getOSVersion(gMacOSVersion);
1261
1262//Azi: implemented at loadOverrideConfig.
1263 // Load config table specified by the user, or use the default.
1264 //if (!getValueForBootKey(cp, "config", &val, &cnt)) {
1265 // val = 0;
1266 // cnt = 0;
1267 //}
1268
1269 // Load com.apple.Boot.plist from the selected volume
1270 // and use its contents to override default bootConfig.
1271 // This is not a mandatory operation anymore.
1272
1273 loadOverrideConfig(&bootInfo->overrideConfig);
1274
1275 // Use the kernel name specified by the user, or fetch the name
1276 // in the config table, or use the default if not specified.
1277 // Specifying a kernel name on the command line, or specifying
1278 // a non-default kernel name in the config file counts as
1279 // overriding the kernel, which causes the kernelcache not
1280 // to be used.
1281
1282 gOverrideKernel = false;
1283 if (( kernel = extractKernelName((char **)&cp) )) {
1284 strcpy( bootInfo->bootFile, kernel );
1285 gOverrideKernel = true;
1286 } else {
1287 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1288 strlcpy( bootInfo->bootFile, val, cnt+1 );
1289 if (strcmp( bootInfo->bootFile, kDefaultKernelName ) != 0) {
1290 gOverrideKernel = true;
1291 }
1292 } else {
1293 strcpy( bootInfo->bootFile, kDefaultKernelName );
1294 }
1295 }
1296
1297 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1298 argP = bootArgs->CommandLine;
1299
1300 // Get config table kernel flags, if not ignored.
1301 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1302 !getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) {
1303 val = "";
1304 cnt = 0;
1305 }
1306 configKernelFlags = malloc(cnt + 1);
1307 strlcpy(configKernelFlags, val, cnt + 1);
1308
1309 if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1310 // boot-uuid was set either on the command-line
1311 // or in the config file.
1312 uuidSet = true;
1313 } else {
1314
1315 //
1316 // Try an alternate method for getting the root UUID on boot helper partitions.
1317 //
1318 if (gBootVolume->flags & kBVFlagBooter)
1319 {
1320 if((loadHelperConfig(&bootInfo->helperConfig) == 0)
1321 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
1322 {
1323 getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
1324 copyArgument(kBootUUIDKey, val, cnt, &argP, &cntRemaining);
1325 uuidSet = true;
1326 }
1327 }
1328
1329 if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid (gBootVolume, uuidStr) == 0) {
1330 verbose("Setting boot-uuid to: %s\n", uuidStr);
1331 copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining);
1332 uuidSet = true;
1333 }
1334 }
1335
1336 if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) {
1337 cnt = 0;
1338 if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->bootConfig)) {
1339 valueBuffer[0] = '*';
1340 cnt++;
1341 strlcpy(valueBuffer + 1, val, cnt);
1342 val = valueBuffer;
1343 } else {
1344 if (uuidSet) {
1345 val = "*uuid";
1346 cnt = 5;
1347 } else {
1348 // Don't set "rd=.." if there is no boot device key
1349 // and no UUID.
1350 val = "";
1351 cnt = 0;
1352 }
1353 }
1354 if (cnt > 0) {
1355 copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1356 }
1357 strlcpy( gRootDevice, val, (cnt + 1));
1358 }
1359
1360 /*
1361 * Removed. We don't need this anymore.
1362 *
1363 if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) {
1364 getPlatformName(gPlatformName);
1365 copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining);
1366 }
1367 */
1368
1369 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1370 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
1371 if (gBootMode & kBootModeSafe) {
1372 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1373 }
1374 }
1375
1376 // Store the merged kernel flags and boot args.
1377
1378 cnt = strlen(configKernelFlags);
1379 if (cnt) {
1380 if (cnt > cntRemaining) {
1381 error("Warning: boot arguments too long, truncating\n");
1382 cnt = cntRemaining;
1383 }
1384 strncpy(argP, configKernelFlags, cnt);
1385 argP[cnt++] = ' ';
1386 cntRemaining -= cnt;
1387 }
1388 userCnt = strlen(cp);
1389 if (userCnt > cntRemaining) {
1390 error("Warning: boot arguments too long, truncating\n");
1391 userCnt = cntRemaining;
1392 }
1393 strncpy(&argP[cnt], cp, userCnt);
1394 argP[cnt+userCnt] = '\0';
1395
1396if(!shouldboot)
1397{
1398gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) ||
1399getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig );
1400
1401gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ?
1402kBootModeSafe : kBootModeNormal;
1403
1404 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->bootConfig ) ) {
1405 gBootMode = kBootModeSafe;
1406 }
1407}
1408
1409if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) )
1410{
1411strlcpy(gMKextName, val, cnt + 1);
1412}
1413
1414 free(configKernelFlags);
1415 free(valueBuffer);
1416
1417 return 0;
1418}
1419
1420static bool getOSVersion(char *str) //Azi: moved from boot.c
1421{
1422bool valid = false;
1423config_file_t systemVersion;
1424const char *val;
1425int len;
1426
1427if (!loadConfigFile("/System/Library/CoreServices/SystemVersion.plist", &systemVersion))
1428{ //Azi: so, is this path on selected or current volume??
1429valid = true;
1430}
1431else if (!loadConfigFile("/System/Library/CoreServices/ServerVersion.plist", &systemVersion))
1432{
1433valid = true;
1434}
1435
1436if (valid)
1437{
1438if (getValueForKey(kProductVersion, &val, &len, &systemVersion))
1439{
1440// getValueForKey uses const char for val
1441// so copy it and trim
1442*str = '\0';
1443strncat(str, val, min(len, 4));
1444}
1445else
1446valid = false;
1447}
1448
1449return valid;
1450}
1451
1452//==========================================================================
1453// Load the help file and display the file contents on the screen.
1454
1455static void showTextBuffer(char *buf, int size)
1456{
1457char*bp;
1458intline;
1459intline_offset;
1460intc;
1461
1462if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1463showInfoBox( "Press q to quit\n",buf );
1464return;
1465}
1466
1467 bp = buf;
1468 while (size-- > 0) {
1469if (*bp == '\n') {
1470*bp = '\0';
1471}
1472bp++;
1473 }
1474 *bp = '\1';
1475 line_offset = 0;
1476
1477 setActiveDisplayPage(1);
1478
1479 while (1) {
1480clearScreenRows(0, 24);
1481setCursorPosition(0, 0, 1);
1482bp = buf;
1483for (line = 0; *bp != '\1' && line < line_offset; line++) {
1484while (*bp != '\0') {
1485bp++;
1486}
1487bp++;
1488}
1489for (line = 0; *bp != '\1' && line < 23; line++) {
1490setCursorPosition(0, line, 1);
1491printf("%s\n", bp);
1492while (*bp != '\0') {
1493bp++;
1494}
1495bp++;
1496}
1497
1498setCursorPosition(0, 23, 1);
1499if (*bp == '\1') {
1500printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1501} else {
1502printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1503}
1504
1505c = getc();
1506if (c == 'q' || c == 'Q') {
1507break;
1508}
1509if ((c == 'p' || c == 'P') && line_offset > 0) {
1510line_offset -= 23;
1511}
1512if (c == ' ') {
1513if (*bp == '\1') {
1514break;
1515} else {
1516line_offset += 23;
1517}
1518}
1519 }
1520 setActiveDisplayPage(0);
1521}
1522
1523void showHelp(void)
1524{
1525if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1526showInfoBox("Help. Press q to quit.\n", (char *)BootHelp_txt);
1527} else {
1528showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1529}
1530}
1531
1532void showTextFile(const char * filename)
1533{
1534#define MAX_TEXT_FILE_SIZE 65536
1535char*buf;
1536intfd;
1537intsize;
1538
1539if ((fd = open_bvdev("bt(0,0)", filename, 0)) < 0) {
1540printf("\nFile not found: %s\n", filename);
1541sleep(2);
1542return;
1543}
1544
1545 size = file_size(fd);
1546 if (size > MAX_TEXT_FILE_SIZE) {
1547size = MAX_TEXT_FILE_SIZE;
1548}
1549 buf = malloc(size);
1550 read(fd, buf, size);
1551 close(fd);
1552showTextBuffer(buf, size);
1553free(buf);
1554}
1555
1556// This is a very simplistic prompting scheme that just grabs two hex characters
1557// Eventually we need to do something more user-friendly like display a menu
1558// based off of the Multiboot device list
1559
1560int selectAlternateBootDevice(int bootdevice)
1561{
1562int key;
1563int newbootdevice;
1564int digitsI = 0;
1565char *end;
1566char digits[3] = {0,0,0};
1567
1568// We've already printed the current boot device so user knows what it is
1569printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1570printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1571do {
1572key = getc();
1573switch (key & kASCIIKeyMask) {
1574case kBackspaceKey:
1575if (digitsI > 0) {
1576int x, y, t;
1577getCursorPositionAndType(&x, &y, &t);
1578// Assume x is not 0;
1579x--;
1580setCursorPosition(x,y,0); // back up one char
1581// Overwrite with space without moving cursor position
1582putca(' ', 0x07, 1);
1583digitsI--;
1584} else {
1585// TODO: Beep or something
1586}
1587break;
1588
1589case kReturnKey:
1590digits[digitsI] = '\0';
1591newbootdevice = strtol(digits, &end, 16);
1592if (end == digits && *end == '\0') {
1593// User entered empty string
1594printf("\nUsing default boot device %x\n", bootdevice);
1595key = 0;
1596} else if(end != digits && *end == '\0') {
1597bootdevice = newbootdevice;
1598printf("\n");
1599key = 0; // We gots da boot device
1600} else {
1601printf("\nCouldn't parse. try again: ");
1602digitsI = 0;
1603}
1604break;
1605
1606default:
1607if (isxdigit(key & kASCIIKeyMask) && digitsI < 2) {
1608putc(key & kASCIIKeyMask);
1609digits[digitsI++] = key & kASCIIKeyMask;
1610} else {
1611// TODO: Beep or something
1612}
1613break;
1614};
1615} while (key != 0);
1616
1617return bootdevice;
1618}
1619
1620bool promptForRescanOption(void)
1621{
1622printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1623if (getc() == kReturnKey) {
1624return true;
1625} else {
1626return false;
1627}
1628}
1629

Archive Download this file

Revision: 508