2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Portions Copyright (c) 1999 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 1.1 (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
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
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright 1993 NeXT, Inc.
26 * All rights reserved.
31 #include "appleClut8.h"
32 #include "appleboot.h"
33 #include "bootstruct.h"
38 static int currentIndicator
= 0;
40 static unsigned long lookUpCLUTIndex( unsigned char index
,
41 unsigned char depth
);
43 static void drawColorRectangle( unsigned short x
,
46 unsigned short height
,
47 unsigned char colorIndex
);
49 static void drawDataRectangle( unsigned short x
,
52 unsigned short height
,
53 unsigned char * data
);
55 #define VIDEO(x) (bootArgs->video.v_ ## x)
58 //==========================================================================
66 // Fetch VBE Controller Info.
68 bzero( &vbeInfo
, sizeof(vbeInfo
) );
69 err
= getVBEInfo( &vbeInfo
);
70 if ( err
!= errSuccess
)
73 // Check presence of VESA signature.
75 if ( strncmp( vbeInfo
.VESASignature
, "VESA", 4 ) )
78 // Announce controller properties.
80 printf("VESA v%d.%d %dMB (%s)\n",
81 vbeInfo
.VESAVersion
>> 8,
82 vbeInfo
.VESAVersion
& 0xf,
83 vbeInfo
.TotalMemory
/ 16,
84 VBEDecodeFP(const char *, vbeInfo
.OEMStringPtr
) );
87 //==========================================================================
88 // getVESAModeWithProperties
90 // Return the VESA mode that matches the properties specified.
91 // If a mode is not found, then return the "best" available mode.
94 getVESAModeWithProperties( unsigned short width
,
95 unsigned short height
,
96 unsigned char bitsPerPixel
,
97 unsigned short attributesSet
,
98 unsigned short attributesClear
,
99 VBEModeInfoBlock
* outModeInfo
,
100 unsigned short * vesaVersion
)
102 VBEInfoBlock vbeInfo
;
103 unsigned short * modePtr
;
104 VBEModeInfoBlock modeInfo
;
105 unsigned char modeBitsPerPixel
;
106 unsigned short matchedMode
= modeEndOfList
;
109 // Clear output mode info.
111 bzero( outModeInfo
, sizeof(*outModeInfo
) );
113 // Get VBE controller info containing the list of supported modes.
115 bzero( &vbeInfo
, sizeof(vbeInfo
) );
116 err
= getVBEInfo( &vbeInfo
);
117 if ( err
!= errSuccess
)
119 return modeEndOfList
;
122 // Report the VESA major/minor version number.
124 if (vesaVersion
) *vesaVersion
= vbeInfo
.VESAVersion
;
126 // Loop through the mode list, and find the matching mode.
128 for ( modePtr
= VBEDecodeFP( unsigned short *, vbeInfo
.VideoModePtr
);
129 *modePtr
!= modeEndOfList
; modePtr
++ )
131 // Get mode information.
133 bzero( &modeInfo
, sizeof(modeInfo
) );
134 err
= getVBEModeInfo( *modePtr
, &modeInfo
);
135 if ( err
!= errSuccess
)
141 printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",
142 *modePtr
, modeInfo
.XResolution
, modeInfo
.YResolution
,
143 modeInfo
.BitsPerPixel
, modeInfo
.MemoryModel
,
144 modeInfo
.ModeAttributes
);
147 // Filter out unwanted modes based on mode attributes.
149 if ( ( ( modeInfo
.ModeAttributes
& attributesSet
) != attributesSet
)
150 || ( ( modeInfo
.ModeAttributes
& attributesClear
) != 0 ) )
155 // Pixel depth in bits.
157 modeBitsPerPixel
= modeInfo
.BitsPerPixel
;
159 if ( ( modeBitsPerPixel
== 4 ) && ( modeInfo
.MemoryModel
== 0 ) )
161 // Text mode, 16 colors.
163 else if ( ( modeBitsPerPixel
== 8 ) && ( modeInfo
.MemoryModel
== 4 ) )
165 // Packed pixel, 256 colors.
167 else if ( ( ( modeBitsPerPixel
== 16 ) || ( modeBitsPerPixel
== 15 ) )
168 && ( modeInfo
.MemoryModel
== 6 )
169 && ( modeInfo
.RedMaskSize
== 5 )
170 && ( modeInfo
.GreenMaskSize
== 5 )
171 && ( modeInfo
.BlueMaskSize
== 5 ) )
173 // Direct color, 16 bpp (1:5:5:5).
174 modeInfo
.BitsPerPixel
= modeBitsPerPixel
= 16;
176 else if ( ( modeBitsPerPixel
== 32 )
177 && ( modeInfo
.MemoryModel
== 6 )
178 && ( modeInfo
.RedMaskSize
== 8 )
179 && ( modeInfo
.GreenMaskSize
== 8 )
180 && ( modeInfo
.BlueMaskSize
== 8 ) )
182 // Direct color, 32 bpp (8:8:8:8).
186 continue; // Not a supported mode.
189 // Modes larger than the specified dimensions are skipped.
191 if ( ( modeInfo
.XResolution
> width
) ||
192 ( modeInfo
.YResolution
> height
) )
197 // Perfect match, we're done looking.
199 if ( ( modeInfo
.XResolution
== width
) &&
200 ( modeInfo
.YResolution
== height
) &&
201 ( modeBitsPerPixel
== bitsPerPixel
) )
203 matchedMode
= *modePtr
;
204 bcopy( &modeInfo
, outModeInfo
, sizeof(modeInfo
) );
208 // Save the next "best" mode in case a perfect match is not found.
210 if ( modeInfo
.XResolution
== outModeInfo
->XResolution
&&
211 modeInfo
.YResolution
== outModeInfo
->YResolution
&&
212 modeBitsPerPixel
<= outModeInfo
->BitsPerPixel
)
214 continue; // Saved mode has more depth.
216 if ( modeInfo
.XResolution
< outModeInfo
->XResolution
||
217 modeInfo
.YResolution
< outModeInfo
->YResolution
||
218 modeBitsPerPixel
< 16 )
220 continue; // Saved mode has more resolution.
223 matchedMode
= *modePtr
;
224 bcopy( &modeInfo
, outModeInfo
, sizeof(modeInfo
) );
230 //==========================================================================
233 static void setupPalette( VBEPalette
* p
, const unsigned char * g
)
236 unsigned char * source
= (unsigned char *) g
;
238 for (i
= 0; i
< 256; i
++)
241 (*p
)[i
] |= ((unsigned long)((*source
++) >> 2)) << 16; // Red
242 (*p
)[i
] |= ((unsigned long)((*source
++) >> 2)) << 8; // Green
243 (*p
)[i
] |= ((unsigned long)((*source
++) >> 2)); // Blue
247 //==========================================================================
248 // Simple decompressor for boot images encoded in RLE format.
250 static char * decodeRLE( const void * rleData
, int rleBlocks
, int outBytes
)
257 } * bp
= (struct RLEBlock
*) rleData
;
259 out
= cp
= (char *) malloc( outBytes
);
260 if ( out
== NULL
) return NULL
;
262 while ( rleBlocks
-- )
264 memset( cp
, bp
->value
, bp
->count
);
272 //==========================================================================
273 // setVESAGraphicsMode
276 setVESAGraphicsMode( unsigned short width
,
277 unsigned short height
,
278 unsigned char bitsPerPixel
,
279 unsigned short refreshRate
)
281 VBEModeInfoBlock minfo
;
283 unsigned short vesaVersion
;
284 int err
= errFuncNotSupported
;
287 mode
= getVESAModeWithProperties( width
, height
, bitsPerPixel
,
289 maModeIsSupportedBit
|
291 maLinearFrameBufferAvailBit
,
293 &minfo
, &vesaVersion
);
294 if ( mode
== modeEndOfList
)
299 if ( (vesaVersion
>> 8) >= 3 && refreshRate
>= 60 &&
300 (gBootMode
& kBootModeSafe
) == 0 )
302 VBECRTCInfoBlock timing
;
304 // Generate CRTC timing for given refresh rate.
306 generateCRTCTiming( minfo
.XResolution
, minfo
.YResolution
,
307 refreshRate
, kCRTCParamRefreshRate
,
310 // Find the actual pixel clock supported by the hardware.
312 getVBEPixelClock( mode
, &timing
.PixelClock
);
314 // Re-compute CRTC timing based on actual pixel clock.
316 generateCRTCTiming( minfo
.XResolution
, minfo
.YResolution
,
317 timing
.PixelClock
, kCRTCParamPixelClock
,
320 // Set the video mode and use specified CRTC timing.
322 err
= setVBEMode( mode
| kLinearFrameBufferBit
|
323 kCustomRefreshRateBit
, &timing
);
327 // Set the mode with default refresh rate.
329 err
= setVBEMode( mode
| kLinearFrameBufferBit
, NULL
);
331 if ( err
!= errSuccess
)
336 // Set 8-bit color palette.
338 if ( minfo
.BitsPerPixel
== 8 )
341 setupPalette( &palette
, appleClut8
);
342 if ((err
= setVBEPalette(palette
)) != errSuccess
)
348 // Is this required for buggy Video BIOS implementations?
351 if ( minfo
.BytesPerScanline
== 0 )
352 minfo
.BytesPerScanline
= ( minfo
.XResolution
*
353 minfo
.BitsPerPixel
) >> 3;
355 // Update KernBootStruct using info provided by the selected
358 bootArgs
->graphicsMode
= GRAPHICS_MODE
;
359 bootArgs
->video
.v_width
= minfo
.XResolution
;
360 bootArgs
->video
.v_height
= minfo
.YResolution
;
361 bootArgs
->video
.v_depth
= minfo
.BitsPerPixel
;
362 bootArgs
->video
.v_rowBytes
= minfo
.BytesPerScanline
;
363 bootArgs
->video
.v_baseAddr
= VBEMakeUInt32(minfo
.PhysBasePtr
);
370 //==========================================================================
374 drawBootGraphics( unsigned short width
,
375 unsigned short height
,
376 unsigned char bitsPerPixel
,
377 unsigned short refreshRate
)
379 VBEModeInfoBlock minfo
;
381 unsigned short vesaVersion
;
382 int err
= errFuncNotSupported
;
384 char * appleBoot
= 0;
388 char * appleBootPict
;
391 mode
= getVESAModeWithProperties( width
, height
, bitsPerPixel
,
393 maModeIsSupportedBit
|
395 maLinearFrameBufferAvailBit
,
397 &minfo
, &vesaVersion
);
398 if ( mode
== modeEndOfList
)
403 // Fill the background to 75% grey (same as BootX).
405 drawColorRectangle( 0, 0, minfo
.XResolution
, minfo
.YResolution
,
406 0x01 /* color index */ );
408 appleBootPict
= decodeRLE( gAppleBootPictRLE
, kAppleBootRLEBlocks
,
409 kAppleBootWidth
* kAppleBootHeight
);
411 // Prepare the data for the happy mac.
415 switch ( VIDEO(depth
) )
418 appleBoot16
= malloc(kAppleBootWidth
* kAppleBootHeight
* 2);
419 if ( !appleBoot16
) break;
420 for (cnt
= 0; cnt
< (kAppleBootWidth
* kAppleBootHeight
); cnt
++)
421 appleBoot16
[cnt
] = lookUpCLUTIndex(appleBootPict
[cnt
], 16);
422 appleBoot
= (char *) appleBoot16
;
426 appleBoot32
= malloc(kAppleBootWidth
* kAppleBootHeight
* 4);
427 if ( !appleBoot32
) break;
428 for (cnt
= 0; cnt
< (kAppleBootWidth
* kAppleBootHeight
); cnt
++)
429 appleBoot32
[cnt
] = lookUpCLUTIndex(appleBootPict
[cnt
], 32);
430 appleBoot
= (char *) appleBoot32
;
434 appleBoot
= (char *) appleBootPict
;
438 x
= ( VIDEO(width
) - kAppleBootWidth
) / 2;
439 y
= ( VIDEO(height
) - kAppleBootHeight
) / 2 + kAppleBootOffset
;
441 // Draw the happy mac in the center of the display.
445 drawDataRectangle( x
, y
, kAppleBootWidth
, kAppleBootHeight
,
449 free( appleBootPict
);
456 //==========================================================================
459 static unsigned long lookUpCLUTIndex( unsigned char index
,
460 unsigned char depth
)
462 long result
, red
, green
, blue
;
464 red
= appleClut8
[index
* 3 + 0];
465 green
= appleClut8
[index
* 3 + 1];
466 blue
= appleClut8
[index
* 3 + 2];
470 result
= ((red
& 0xF8) << 7) |
471 ((green
& 0xF8) << 2) |
472 ((blue
& 0xF8) >> 3);
473 result
|= (result
<< 16);
477 result
= (red
<< 16) | (green
<< 8) | blue
;
481 result
= index
| (index
<< 8);
482 result
|= (result
<< 16);
489 //==========================================================================
490 // drawColorRectangle
492 static void * stosl(void * dst
, long val
, long len
)
495 : "=c" (len
), "=D" (dst
)
496 : "0" (len
), "1" (dst
), "a" (val
)
502 static void drawColorRectangle( unsigned short x
,
504 unsigned short width
,
505 unsigned short height
,
506 unsigned char colorIndex
)
509 long color
= lookUpCLUTIndex( colorIndex
, VIDEO(depth
) );
512 pixelBytes
= VIDEO(depth
) / 8;
513 vram
= (char *) VIDEO(baseAddr
) +
514 VIDEO(rowBytes
) * y
+ pixelBytes
* x
;
518 int rem
= ( pixelBytes
* width
) % 4;
519 if ( rem
) bcopy( &color
, vram
, rem
);
520 stosl( vram
+ rem
, color
, pixelBytes
* width
/ 4 );
521 vram
+= VIDEO(rowBytes
);
525 //==========================================================================
528 static void drawDataRectangle( unsigned short x
,
530 unsigned short width
,
531 unsigned short height
,
532 unsigned char * data
)
534 long pixelBytes
= VIDEO(depth
) / 8;
535 char * vram
= (char *) VIDEO(baseAddr
) +
536 VIDEO(rowBytes
) * y
+ pixelBytes
* x
;
540 bcopy( data
, vram
, width
* pixelBytes
);
541 vram
+= VIDEO(rowBytes
);
542 data
+= width
* pixelBytes
;
546 //==========================================================================
550 setVESATextMode( unsigned short cols
,
552 unsigned char bitsPerPixel
)
554 VBEModeInfoBlock minfo
;
555 unsigned short mode
= modeEndOfList
;
557 if ( (cols
!= 80) || (rows
!= 25) ) // not 80x25 mode
559 mode
= getVESAModeWithProperties( cols
, rows
, bitsPerPixel
,
561 maModeIsSupportedBit
,
566 if ( ( mode
== modeEndOfList
) || ( setVBEMode(mode
, NULL
) != errSuccess
) )
568 video_mode( 2 ); // VGA BIOS, 80x25 text mode.
569 minfo
.XResolution
= 80;
570 minfo
.YResolution
= 25;
573 // Update KernBootStruct using info provided by the selected
576 bootArgs
->graphicsMode
= TEXT_MODE
;
577 bootArgs
->video
.v_baseAddr
= 0xb8000;
578 bootArgs
->video
.v_width
= minfo
.XResolution
;
579 bootArgs
->video
.v_height
= minfo
.YResolution
;
580 bootArgs
->video
.v_depth
= 8;
581 bootArgs
->video
.v_rowBytes
= 0x8000;
583 return errSuccess
; // always return success
586 //==========================================================================
587 // getNumberArrayFromProperty
590 getNumberArrayFromProperty( const char * propKey
,
591 unsigned long numbers
[],
592 unsigned long maxArrayCount
)
595 unsigned long count
= 0;
597 #define _isdigit(c) ((c) >= '0' && (c) <= '9')
599 propStr
= newStringForKey( (char *) propKey
);
602 char * delimiter
= propStr
;
605 while ( count
< maxArrayCount
&& *p
!= '\0' )
607 unsigned long val
= strtoul( p
, &delimiter
, 10 );
608 if ( p
!= delimiter
)
610 numbers
[count
++] = val
;
613 while ( ( *p
!= '\0' ) && !_isdigit(*p
) )
623 //==========================================================================
626 // Set the video mode to TEXT_MODE or GRAPHICS_MODE.
629 setVideoMode( int mode
)
631 unsigned long params
[4];
633 int err
= errSuccess
;
635 if ( mode
== GRAPHICS_MODE
)
638 count
= getNumberArrayFromProperty( kGraphicsModeKey
, params
, 4 );
641 params
[0] = 1024; // Default graphics mode is 1024x768x16.
646 // Map from pixel format to bits per pixel.
648 if ( params
[2] == 256 ) params
[2] = 8;
649 if ( params
[2] == 555 ) params
[2] = 16;
650 if ( params
[2] == 888 ) params
[2] = 32;
652 err
= setVESAGraphicsMode( params
[0], params
[1], params
[2], params
[3] );
653 if ( err
== errSuccess
)
655 // If this boolean is set to true, then the console driver
656 // in the kernel will show the animated color wheel on the
657 // upper left corner.
659 bootArgs
->video
.v_display
= !gVerboseMode
;
662 drawBootGraphics( params
[0], params
[1], params
[2], params
[3] );
667 if ( (mode
== TEXT_MODE
) || (err
!= errSuccess
) )
669 count
= getNumberArrayFromProperty( kTextModeKey
, params
, 2 );
672 params
[0] = 80; // Default text mode is 80x25.
676 setVESATextMode( params
[0], params
[1], 4 );
677 bootArgs
->video
.v_display
= 0;
680 currentIndicator
= 0;
683 //==========================================================================
684 // Return the current video mode, TEXT_MODE or GRAPHICS_MODE.
686 int getVideoMode(void)
688 return bootArgs
->graphicsMode
;
691 //==========================================================================
692 // Display and clear the activity indicator.
694 static char indicator
[] = {'-', '\\', '|', '/', '-', '\\', '|', '/', '\0'};
696 // To prevent a ridiculously fast-spinning indicator,
697 // ensure a minimum of 1/9 sec between animation frames.
701 spinActivityIndicator( void )
703 static unsigned long lastTickTime
= 0;
704 unsigned long currentTickTime
= time18();
705 static char string
[3] = {'\0', '\b', '\0'};
707 if (currentTickTime
< lastTickTime
+ MIN_TICKS
)
710 lastTickTime
= currentTickTime
;
712 if ( getVideoMode() == TEXT_MODE
)
714 string
[0] = indicator
[currentIndicator
];
716 if (indicator
[++currentIndicator
] == 0)
717 currentIndicator
= 0;
722 clearActivityIndicator( void )
724 if ( getVideoMode() == TEXT_MODE
)