]> git.saurik.com Git - apple/boot.git/blame - i386/boot2/graphics.c
boot-132.tar.gz
[apple/boot.git] / i386 / boot2 / graphics.c
CommitLineData
14c7c974 1/*
57c72a9a 2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
14c7c974
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
57c72a9a 6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
4f6e3300
A
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
57c72a9a 9 * Source License Version 2.0 (the "License"). You may not use this file
4f6e3300
A
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.
14c7c974
A
13 *
14 * The Original Code and all software distributed under the License are
4f6e3300 15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14c7c974
A
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
4f6e3300
A
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.
14c7c974
A
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * Copyright 1993 NeXT, Inc.
26 * All rights reserved.
27 */
28
14c7c974
A
29#include "boot.h"
30#include "vbe.h"
75b89a82 31#include "appleClut8.h"
f083c6c3
A
32#include "appleboot.h"
33#include "bootstruct.h"
14c7c974
A
34
35/*
75b89a82 36 * for spinning disk
14c7c974 37 */
75b89a82
A
38static int currentIndicator = 0;
39
40static unsigned long lookUpCLUTIndex( unsigned char index,
41 unsigned char depth );
42
57c72a9a 43void drawColorRectangle( unsigned short x,
75b89a82
A
44 unsigned short y,
45 unsigned short width,
46 unsigned short height,
47 unsigned char colorIndex );
48
57c72a9a 49void drawDataRectangle( unsigned short x,
75b89a82
A
50 unsigned short y,
51 unsigned short width,
52 unsigned short height,
57c72a9a
A
53 unsigned char * data );
54
bba600dd 55static void setBorderColor( unsigned char colorIndex );
57c72a9a
A
56
57int
58convertImage( unsigned short width,
59 unsigned short height,
60 const unsigned char *imageData,
61 unsigned char **newImageData );
75b89a82 62
bba600dd 63#define VIDEO(x) (bootArgs->Video.v_ ## x)
75b89a82 64
57c72a9a 65#define MIN(x, y) ((x) < (y) ? (x) : (y))
14c7c974
A
66
67//==========================================================================
75b89a82 68// printVBEInfo
14c7c974 69
75b89a82
A
70void printVBEInfo()
71{
72 VBEInfoBlock vbeInfo;
73 int err;
57c72a9a 74 int small;
75b89a82
A
75
76 // Fetch VBE Controller Info.
77
78 bzero( &vbeInfo, sizeof(vbeInfo) );
79 err = getVBEInfo( &vbeInfo );
80 if ( err != errSuccess )
81 return;
82
83 // Check presence of VESA signature.
84
bba600dd 85 if ( strncmp( (char *)vbeInfo.VESASignature, "VESA", 4 ) )
75b89a82
A
86 return;
87
88 // Announce controller properties.
89
57c72a9a
A
90 small = (vbeInfo.TotalMemory < 16);
91
92 printf("VESA v%d.%d %d%s (%s)\n",
75b89a82
A
93 vbeInfo.VESAVersion >> 8,
94 vbeInfo.VESAVersion & 0xf,
57c72a9a
A
95 small ? (vbeInfo.TotalMemory * 64) : (vbeInfo.TotalMemory / 16),
96 small ? "KB" : "MB",
75b89a82
A
97 VBEDecodeFP(const char *, vbeInfo.OEMStringPtr) );
98}
99
57c72a9a
A
100//==========================================================================
101//
102
103void
104printVBEModeInfo()
105{
106 VBEInfoBlock vbeInfo;
107 unsigned short * modePtr;
108 VBEModeInfoBlock modeInfo;
109 int err;
110 int line;
111
112 err = getVBEInfo( &vbeInfo );
113 if ( err != errSuccess )
114 return;
115
116 line = 0;
117
118 // Activate and clear page 1
119 setActiveDisplayPage(1);
120 clearScreenRows(0, 24);
121 setCursorPosition( 0, 0, 1 );
122
123 printVBEInfo();
124 printf("Video modes supported:\n", VBEDecodeFP(const char *, vbeInfo.OEMStringPtr));
125
126 // Loop through the mode list, and find the matching mode.
127
128 for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );
129 *modePtr != modeEndOfList; modePtr++ )
130 {
131 // Get mode information.
132
133 bzero( &modeInfo, sizeof(modeInfo) );
134 err = getVBEModeInfo( *modePtr, &modeInfo );
135 if ( err != errSuccess )
136 {
137 continue;
138 }
139
140 printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",
141 *modePtr, modeInfo.XResolution, modeInfo.YResolution,
142 modeInfo.BitsPerPixel, modeInfo.MemoryModel,
143 modeInfo.ModeAttributes);
144
145 if (line++ >= 20) {
146 printf("(Press a key to continue...)");
147 getc();
148 line = 0;
149 clearScreenRows(0, 24);
150 setCursorPosition( 0, 0, 1 );
151 }
152 }
153 if (line != 0) {
154 printf("(Press a key to continue...)");
155 getc();
156 }
157 setActiveDisplayPage(0);
158}
159
160
75b89a82
A
161//==========================================================================
162// getVESAModeWithProperties
163//
164// Return the VESA mode that matches the properties specified.
165// If a mode is not found, then return the "best" available mode.
166
167static unsigned short
168getVESAModeWithProperties( unsigned short width,
169 unsigned short height,
170 unsigned char bitsPerPixel,
171 unsigned short attributesSet,
172 unsigned short attributesClear,
f083c6c3
A
173 VBEModeInfoBlock * outModeInfo,
174 unsigned short * vesaVersion )
14c7c974 175{
75b89a82
A
176 VBEInfoBlock vbeInfo;
177 unsigned short * modePtr;
f083c6c3 178 VBEModeInfoBlock modeInfo;
75b89a82
A
179 unsigned char modeBitsPerPixel;
180 unsigned short matchedMode = modeEndOfList;
181 int err;
182
183 // Clear output mode info.
14c7c974 184
75b89a82 185 bzero( outModeInfo, sizeof(*outModeInfo) );
14c7c974 186
75b89a82
A
187 // Get VBE controller info containing the list of supported modes.
188
189 bzero( &vbeInfo, sizeof(vbeInfo) );
190 err = getVBEInfo( &vbeInfo );
191 if ( err != errSuccess )
192 {
193 return modeEndOfList;
194 }
195
f083c6c3
A
196 // Report the VESA major/minor version number.
197
198 if (vesaVersion) *vesaVersion = vbeInfo.VESAVersion;
199
75b89a82
A
200 // Loop through the mode list, and find the matching mode.
201
202 for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );
203 *modePtr != modeEndOfList; modePtr++ )
14c7c974 204 {
75b89a82
A
205 // Get mode information.
206
207 bzero( &modeInfo, sizeof(modeInfo) );
208 err = getVBEModeInfo( *modePtr, &modeInfo );
209 if ( err != errSuccess )
14c7c974 210 {
75b89a82 211 continue;
14c7c974 212 }
75b89a82 213
57c72a9a 214#if DEBUG
75b89a82
A
215 printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",
216 *modePtr, modeInfo.XResolution, modeInfo.YResolution,
217 modeInfo.BitsPerPixel, modeInfo.MemoryModel,
218 modeInfo.ModeAttributes);
219#endif
220
221 // Filter out unwanted modes based on mode attributes.
222
223 if ( ( ( modeInfo.ModeAttributes & attributesSet ) != attributesSet )
224 || ( ( modeInfo.ModeAttributes & attributesClear ) != 0 ) )
225 {
226 continue;
227 }
228
229 // Pixel depth in bits.
230
231 modeBitsPerPixel = modeInfo.BitsPerPixel;
232
233 if ( ( modeBitsPerPixel == 4 ) && ( modeInfo.MemoryModel == 0 ) )
234 {
235 // Text mode, 16 colors.
236 }
237 else if ( ( modeBitsPerPixel == 8 ) && ( modeInfo.MemoryModel == 4 ) )
238 {
239 // Packed pixel, 256 colors.
240 }
241 else if ( ( ( modeBitsPerPixel == 16 ) || ( modeBitsPerPixel == 15 ) )
242 && ( modeInfo.MemoryModel == 6 )
243 && ( modeInfo.RedMaskSize == 5 )
244 && ( modeInfo.GreenMaskSize == 5 )
245 && ( modeInfo.BlueMaskSize == 5 ) )
246 {
247 // Direct color, 16 bpp (1:5:5:5).
248 modeInfo.BitsPerPixel = modeBitsPerPixel = 16;
249 }
250 else if ( ( modeBitsPerPixel == 32 )
251 && ( modeInfo.MemoryModel == 6 )
252 && ( modeInfo.RedMaskSize == 8 )
253 && ( modeInfo.GreenMaskSize == 8 )
254 && ( modeInfo.BlueMaskSize == 8 ) )
255 {
256 // Direct color, 32 bpp (8:8:8:8).
257 }
258 else
259 {
260 continue; // Not a supported mode.
261 }
262
263 // Modes larger than the specified dimensions are skipped.
264
265 if ( ( modeInfo.XResolution > width ) ||
266 ( modeInfo.YResolution > height ) )
267 {
268 continue;
269 }
270
271 // Perfect match, we're done looking.
272
273 if ( ( modeInfo.XResolution == width ) &&
274 ( modeInfo.YResolution == height ) &&
275 ( modeBitsPerPixel == bitsPerPixel ) )
276 {
277 matchedMode = *modePtr;
278 bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
279 break;
280 }
281
f083c6c3 282 // Save the next "best" mode in case a perfect match is not found.
75b89a82 283
f083c6c3
A
284 if ( modeInfo.XResolution == outModeInfo->XResolution &&
285 modeInfo.YResolution == outModeInfo->YResolution &&
286 modeBitsPerPixel <= outModeInfo->BitsPerPixel )
75b89a82 287 {
f083c6c3 288 continue; // Saved mode has more depth.
75b89a82 289 }
f083c6c3
A
290 if ( modeInfo.XResolution < outModeInfo->XResolution ||
291 modeInfo.YResolution < outModeInfo->YResolution ||
57c72a9a 292 modeBitsPerPixel < outModeInfo->BitsPerPixel )
f083c6c3
A
293 {
294 continue; // Saved mode has more resolution.
295 }
296
297 matchedMode = *modePtr;
298 bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
75b89a82
A
299 }
300
301 return matchedMode;
14c7c974
A
302}
303
75b89a82
A
304//==========================================================================
305// setupPalette
306
307static void setupPalette( VBEPalette * p, const unsigned char * g )
308{
309 int i;
310 unsigned char * source = (unsigned char *) g;
311
312 for (i = 0; i < 256; i++)
313 {
314 (*p)[i] = 0;
315 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red
316 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green
317 (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue
318 }
319}
14c7c974 320
f083c6c3
A
321//==========================================================================
322// Simple decompressor for boot images encoded in RLE format.
323
57c72a9a 324char * decodeRLE( const void * rleData, int rleBlocks, int outBytes )
f083c6c3
A
325{
326 char *out, *cp;
327
328 struct RLEBlock {
329 unsigned char count;
330 unsigned char value;
331 } * bp = (struct RLEBlock *) rleData;
332
333 out = cp = (char *) malloc( outBytes );
334 if ( out == NULL ) return NULL;
335
336 while ( rleBlocks-- )
337 {
338 memset( cp, bp->value, bp->count );
339 cp += bp->count;
340 bp++;
341 }
342
343 return out;
344}
345
14c7c974 346//==========================================================================
75b89a82 347// setVESAGraphicsMode
14c7c974 348
75b89a82
A
349static int
350setVESAGraphicsMode( unsigned short width,
351 unsigned short height,
f083c6c3
A
352 unsigned char bitsPerPixel,
353 unsigned short refreshRate )
14c7c974 354{
75b89a82
A
355 VBEModeInfoBlock minfo;
356 unsigned short mode;
f083c6c3 357 unsigned short vesaVersion;
75b89a82
A
358 int err = errFuncNotSupported;
359
360 do {
361 mode = getVESAModeWithProperties( width, height, bitsPerPixel,
362 maColorModeBit |
363 maModeIsSupportedBit |
364 maGraphicsModeBit |
365 maLinearFrameBufferAvailBit,
366 0,
f083c6c3 367 &minfo, &vesaVersion );
75b89a82
A
368 if ( mode == modeEndOfList )
369 {
370 break;
371 }
372
f083c6c3
A
373 if ( (vesaVersion >> 8) >= 3 && refreshRate >= 60 &&
374 (gBootMode & kBootModeSafe) == 0 )
375 {
376 VBECRTCInfoBlock timing;
377
378 // Generate CRTC timing for given refresh rate.
379
380 generateCRTCTiming( minfo.XResolution, minfo.YResolution,
381 refreshRate, kCRTCParamRefreshRate,
382 &timing );
383
384 // Find the actual pixel clock supported by the hardware.
385
386 getVBEPixelClock( mode, &timing.PixelClock );
387
388 // Re-compute CRTC timing based on actual pixel clock.
389
390 generateCRTCTiming( minfo.XResolution, minfo.YResolution,
391 timing.PixelClock, kCRTCParamPixelClock,
392 &timing );
393
394 // Set the video mode and use specified CRTC timing.
395
396 err = setVBEMode( mode | kLinearFrameBufferBit |
397 kCustomRefreshRateBit, &timing );
398 }
399 else
400 {
401 // Set the mode with default refresh rate.
75b89a82 402
f083c6c3
A
403 err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
404 }
75b89a82
A
405 if ( err != errSuccess )
406 {
407 break;
408 }
409
410 // Set 8-bit color palette.
411
412 if ( minfo.BitsPerPixel == 8 )
413 {
414 VBEPalette palette;
415 setupPalette( &palette, appleClut8 );
416 if ((err = setVBEPalette(palette)) != errSuccess)
417 {
418 break;
419 }
420 }
421
422 // Is this required for buggy Video BIOS implementations?
423 // On which adapter?
424
425 if ( minfo.BytesPerScanline == 0 )
426 minfo.BytesPerScanline = ( minfo.XResolution *
427 minfo.BitsPerPixel ) >> 3;
14c7c974 428
75b89a82
A
429 // Update KernBootStruct using info provided by the selected
430 // VESA mode.
14c7c974 431
bba600dd
A
432 bootArgs->Video.v_display = GRAPHICS_MODE;
433 bootArgs->Video.v_width = minfo.XResolution;
434 bootArgs->Video.v_height = minfo.YResolution;
435 bootArgs->Video.v_depth = minfo.BitsPerPixel;
436 bootArgs->Video.v_rowBytes = minfo.BytesPerScanline;
437 bootArgs->Video.v_baseAddr = VBEMakeUInt32(minfo.PhysBasePtr);
57c72a9a 438
75b89a82
A
439 }
440 while ( 0 );
441
f083c6c3
A
442 return err;
443}
14c7c974 444
57c72a9a
A
445int
446convertImage( unsigned short width,
447 unsigned short height,
448 const unsigned char *imageData,
449 unsigned char **newImageData )
450{
451 int cnt;
452 unsigned char *img = 0;
453 unsigned short *img16;
454 unsigned long *img32;
455
456 switch ( VIDEO(depth) ) {
457 case 16 :
458 img16 = malloc(width * height * 2);
459 if ( !img16 ) break;
460 for (cnt = 0; cnt < (width * height); cnt++)
461 img16[cnt] = lookUpCLUTIndex(imageData[cnt], 16);
462 img = (unsigned char *)img16;
463 break;
464
465 case 32 :
466 img32 = malloc(width * height * 4);
467 if ( !img32 ) break;
468 for (cnt = 0; cnt < (width * height); cnt++)
469 img32[cnt] = lookUpCLUTIndex(imageData[cnt], 32);
470 img = (unsigned char *)img32;
471 break;
472
473 default :
474 img = malloc(width * height);
475 bcopy(imageData, img, width * height);
476 break;
477 }
478 *newImageData = img;
479 return 0;
480}
481
f083c6c3
A
482//==========================================================================
483// drawBootGraphics
14c7c974 484
57c72a9a
A
485void
486drawBootGraphics( void )
f083c6c3 487{
57c72a9a
A
488 unsigned char * imageData = 0;
489 long x, y;
f083c6c3 490 char * appleBootPict;
14c7c974 491
f083c6c3 492 do {
f083c6c3 493 // Fill the background to 75% grey (same as BootX).
75b89a82 494
57c72a9a 495 drawColorRectangle( 0, 0, VIDEO(width), VIDEO(height),
f083c6c3
A
496 0x01 /* color index */ );
497
bba600dd
A
498 setBorderColor( 0x01 /* color index */ );
499
f083c6c3
A
500 appleBootPict = decodeRLE( gAppleBootPictRLE, kAppleBootRLEBlocks,
501 kAppleBootWidth * kAppleBootHeight );
14c7c974 502
f083c6c3
A
503 // Prepare the data for the happy mac.
504
505 if ( appleBootPict )
506 {
57c72a9a 507 convertImage(kAppleBootWidth, kAppleBootHeight,
bba600dd 508 (unsigned char *)appleBootPict, &imageData);
75b89a82 509
f083c6c3
A
510 x = ( VIDEO(width) - kAppleBootWidth ) / 2;
511 y = ( VIDEO(height) - kAppleBootHeight ) / 2 + kAppleBootOffset;
512
513 // Draw the happy mac in the center of the display.
514
57c72a9a 515 if ( imageData )
f083c6c3
A
516 {
517 drawDataRectangle( x, y, kAppleBootWidth, kAppleBootHeight,
57c72a9a
A
518 imageData );
519 free( imageData );
f083c6c3 520 }
f083c6c3
A
521 free( appleBootPict );
522 }
75b89a82 523
57c72a9a 524 } while (0);
75b89a82
A
525}
526
527//==========================================================================
528// LookUpCLUTIndex
529
530static unsigned long lookUpCLUTIndex( unsigned char index,
531 unsigned char depth )
532{
f083c6c3 533 long result, red, green, blue;
75b89a82 534
f083c6c3
A
535 red = appleClut8[index * 3 + 0];
536 green = appleClut8[index * 3 + 1];
537 blue = appleClut8[index * 3 + 2];
75b89a82 538
f083c6c3 539 switch (depth) {
75b89a82
A
540 case 16 :
541 result = ((red & 0xF8) << 7) |
542 ((green & 0xF8) << 2) |
543 ((blue & 0xF8) >> 3);
544 result |= (result << 16);
545 break;
546
547 case 32 :
548 result = (red << 16) | (green << 8) | blue;
549 break;
550
551 default :
552 result = index | (index << 8);
553 result |= (result << 16);
554 break;
14c7c974 555 }
75b89a82 556
f083c6c3 557 return result;
75b89a82
A
558}
559
560//==========================================================================
561// drawColorRectangle
562
563static void * stosl(void * dst, long val, long len)
564{
bba600dd 565 asm volatile ( "rep; stosl"
75b89a82
A
566 : "=c" (len), "=D" (dst)
567 : "0" (len), "1" (dst), "a" (val)
568 : "memory" );
569
570 return dst;
571}
572
57c72a9a 573void drawColorRectangle( unsigned short x,
75b89a82
A
574 unsigned short y,
575 unsigned short width,
576 unsigned short height,
577 unsigned char colorIndex )
578{
579 long pixelBytes;
580 long color = lookUpCLUTIndex( colorIndex, VIDEO(depth) );
581 char * vram;
582
583 pixelBytes = VIDEO(depth) / 8;
584 vram = (char *) VIDEO(baseAddr) +
585 VIDEO(rowBytes) * y + pixelBytes * x;
586
57c72a9a
A
587 width = MIN(width, VIDEO(width) - x);
588 height = MIN(height, VIDEO(height) - y);
589
75b89a82 590 while ( height-- )
14c7c974 591 {
75b89a82
A
592 int rem = ( pixelBytes * width ) % 4;
593 if ( rem ) bcopy( &color, vram, rem );
594 stosl( vram + rem, color, pixelBytes * width / 4 );
595 vram += VIDEO(rowBytes);
14c7c974 596 }
75b89a82 597}
14c7c974 598
75b89a82
A
599//==========================================================================
600// drawDataRectangle
601
57c72a9a
A
602void drawDataRectangle( unsigned short x,
603 unsigned short y,
604 unsigned short width,
605 unsigned short height,
606 unsigned char * data )
75b89a82 607{
57c72a9a 608 unsigned short drawWidth;
75b89a82 609 long pixelBytes = VIDEO(depth) / 8;
57c72a9a
A
610 unsigned char * vram = (unsigned char *) VIDEO(baseAddr) +
611 VIDEO(rowBytes) * y + pixelBytes * x;
75b89a82 612
57c72a9a
A
613 drawWidth = MIN(width, VIDEO(width) - x);
614 height = MIN(height, VIDEO(height) - y);
615 while ( height-- ) {
616 bcopy( data, vram, drawWidth * pixelBytes );
75b89a82
A
617 vram += VIDEO(rowBytes);
618 data += width * pixelBytes;
619 }
14c7c974
A
620}
621
bba600dd
A
622
623//==========================================================================
624// setBorderColor
625
626static void
627setBorderColor( unsigned char colorIndex )
628{
629 long color = lookUpCLUTIndex( colorIndex, 32 );
630 VBEInfoBlock vbeInfo;
631 int err;
632
633 // Get VBE controller info.
634
635 bzero( &vbeInfo, sizeof(vbeInfo) );
636 err = getVBEInfo( &vbeInfo );
637 if ( err != errSuccess )
638 {
639 return;
640 }
641
642}
643
644
14c7c974 645//==========================================================================
75b89a82 646// setVESATextMode
14c7c974 647
75b89a82
A
648static int
649setVESATextMode( unsigned short cols,
650 unsigned short rows,
651 unsigned char bitsPerPixel )
14c7c974 652{
75b89a82
A
653 VBEModeInfoBlock minfo;
654 unsigned short mode = modeEndOfList;
655
656 if ( (cols != 80) || (rows != 25) ) // not 80x25 mode
657 {
658 mode = getVESAModeWithProperties( cols, rows, bitsPerPixel,
659 maColorModeBit |
660 maModeIsSupportedBit,
661 maGraphicsModeBit,
f083c6c3 662 &minfo, NULL );
75b89a82
A
663 }
664
f083c6c3 665 if ( ( mode == modeEndOfList ) || ( setVBEMode(mode, NULL) != errSuccess ) )
75b89a82
A
666 {
667 video_mode( 2 ); // VGA BIOS, 80x25 text mode.
668 minfo.XResolution = 80;
669 minfo.YResolution = 25;
670 }
671
672 // Update KernBootStruct using info provided by the selected
673 // VESA mode.
674
bba600dd
A
675 bootArgs->Video.v_display = VGA_TEXT_MODE;
676 bootArgs->Video.v_baseAddr = 0xb8000;
677 bootArgs->Video.v_width = minfo.XResolution;
678 bootArgs->Video.v_height = minfo.YResolution;
679 bootArgs->Video.v_depth = 8;
680 bootArgs->Video.v_rowBytes = 0x8000;
75b89a82
A
681
682 return errSuccess; // always return success
14c7c974
A
683}
684
685//==========================================================================
75b89a82
A
686// getNumberArrayFromProperty
687
688static int
689getNumberArrayFromProperty( const char * propKey,
690 unsigned long numbers[],
691 unsigned long maxArrayCount )
14c7c974 692{
f083c6c3
A
693 char * propStr;
694 unsigned long count = 0;
14c7c974 695
75b89a82 696#define _isdigit(c) ((c) >= '0' && (c) <= '9')
14c7c974 697
75b89a82
A
698 propStr = newStringForKey( (char *) propKey );
699 if ( propStr )
14c7c974 700 {
75b89a82 701 char * delimiter = propStr;
f083c6c3 702 char * p = propStr;
75b89a82 703
f083c6c3 704 while ( count < maxArrayCount && *p != '\0' )
14c7c974 705 {
f083c6c3
A
706 unsigned long val = strtoul( p, &delimiter, 10 );
707 if ( p != delimiter )
75b89a82
A
708 {
709 numbers[count++] = val;
f083c6c3 710 p = delimiter;
75b89a82 711 }
f083c6c3
A
712 while ( ( *p != '\0' ) && !_isdigit(*p) )
713 p++;
14c7c974 714 }
75b89a82
A
715
716 free( propStr );
14c7c974 717 }
75b89a82
A
718
719 return count;
720}
721
722//==========================================================================
723// setVideoMode
724//
bba600dd 725// Set the video mode to VGA_TEXT_MODE or GRAPHICS_MODE.
75b89a82
A
726
727void
728setVideoMode( int mode )
729{
f083c6c3 730 unsigned long params[4];
75b89a82
A
731 int count;
732 int err = errSuccess;
733
734 if ( mode == GRAPHICS_MODE )
735 {
f083c6c3
A
736 params[3] = 0;
737 count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 );
75b89a82
A
738 if ( count < 3 )
739 {
57c72a9a 740 params[0] = 1024; // Default graphics mode is 1024x768x32.
75b89a82 741 params[1] = 768;
57c72a9a 742 params[2] = 32;
75b89a82
A
743 }
744
745 // Map from pixel format to bits per pixel.
746
747 if ( params[2] == 256 ) params[2] = 8;
748 if ( params[2] == 555 ) params[2] = 16;
749 if ( params[2] == 888 ) params[2] = 32;
750
f083c6c3 751 err = setVESAGraphicsMode( params[0], params[1], params[2], params[3] );
75b89a82
A
752 if ( err == errSuccess )
753 {
bba600dd
A
754 if (gVerboseMode) {
755 // Tell the kernel to use text mode on a linear frame buffer display
756 bootArgs->Video.v_display = FB_TEXT_MODE;
757 } else {
758 bootArgs->Video.v_display = GRAPHICS_MODE;
57c72a9a 759 drawBootGraphics();
f083c6c3 760 }
75b89a82
A
761 }
762 }
763
bba600dd 764 if ( (mode == VGA_TEXT_MODE) || (err != errSuccess) )
75b89a82
A
765 {
766 count = getNumberArrayFromProperty( kTextModeKey, params, 2 );
767 if ( count < 2 )
768 {
769 params[0] = 80; // Default text mode is 80x25.
770 params[1] = 25;
771 }
772
773 setVESATextMode( params[0], params[1], 4 );
bba600dd 774 bootArgs->Video.v_display = VGA_TEXT_MODE;
75b89a82
A
775 }
776
f083c6c3 777 currentIndicator = 0;
75b89a82
A
778}
779
780//==========================================================================
bba600dd 781// Return the current video mode, VGA_TEXT_MODE or GRAPHICS_MODE.
75b89a82
A
782
783int getVideoMode(void)
784{
bba600dd 785 return bootArgs->Video.v_display;
14c7c974
A
786}
787
788//==========================================================================
789// Display and clear the activity indicator.
790
791static char indicator[] = {'-', '\\', '|', '/', '-', '\\', '|', '/', '\0'};
57c72a9a 792#define kNumIndicators (sizeof(indicator) - 1)
14c7c974
A
793
794// To prevent a ridiculously fast-spinning indicator,
795// ensure a minimum of 1/9 sec between animation frames.
796#define MIN_TICKS 2
797
798void
799spinActivityIndicator( void )
800{
801 static unsigned long lastTickTime = 0;
802 unsigned long currentTickTime = time18();
803 static char string[3] = {'\0', '\b', '\0'};
804
805 if (currentTickTime < lastTickTime + MIN_TICKS)
806 return;
807 else
808 lastTickTime = currentTickTime;
f083c6c3 809
bba600dd 810 if ( getVideoMode() == VGA_TEXT_MODE )
14c7c974 811 {
57c72a9a
A
812 if (currentIndicator >= kNumIndicators) currentIndicator = 0;
813 string[0] = indicator[currentIndicator++];
14c7c974 814 printf(string);
14c7c974
A
815 }
816}
817
818void
819clearActivityIndicator( void )
820{
bba600dd 821 if ( getVideoMode() == VGA_TEXT_MODE )
14c7c974
A
822 {
823 printf(" \b");
824 }
825}
57c72a9a 826