Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/trunkAutoResolution/i386/boot2/options.c

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

Archive Download this file

Revision: 1450