Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/boot2/graphics.c

1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 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 * Copyright 1993 NeXT, Inc.
26 * All rights reserved.
27 */
28
29#include "boot.h"
30#include "graphics.h"
31#include "vbe.h"
32#include "appleClut8.h"
33#include "bootstruct.h"
34#include "modules.h"
35
36/*
37 * for spinning disk
38 */
39#if TEXT_SPINNER
40static int currentIndicator = 0;
41#endif
42
43int previewTotalSectors = 0;
44int previewLoadedSectors = 0;
45uint8_t *previewSaveunder = 0;
46
47#define VIDEO(x) (bootArgs->Video.v_ ## x)
48
49#define MIN(x, y) ((x) < (y) ? (x) : (y))
50
51#ifndef OPTION_ROM
52int
53convertImage( unsigned short width,
54 unsigned short height,
55 const unsigned char *imageData,
56 unsigned char **newImageData )
57{
58 int cnt;
59 unsigned char *img = 0;
60 unsigned short *img16;
61 unsigned long *img32;
62
63 switch ( VIDEO(depth) ) {
64case 16 :
65img16 = malloc(width * height * 2);
66if ( !img16 ) break;
67for (cnt = 0; cnt < (width * height); cnt++)
68img16[cnt] = lookUpCLUTIndex(imageData[cnt], 16);
69img = (unsigned char *)img16;
70break;
71
72case 32 :
73img32 = malloc(width * height * 4);
74if ( !img32 ) break;
75for (cnt = 0; cnt < (width * height); cnt++)
76img32[cnt] = lookUpCLUTIndex(imageData[cnt], 32);
77img = (unsigned char *)img32;
78break;
79
80default :
81img = malloc(width * height);
82bcopy(imageData, img, width * height);
83break;
84 }
85 *newImageData = img;
86 return 0;
87}
88
89//==========================================================================
90// drawDataRectangle
91
92void drawDataRectangle( unsigned short x,
93 unsigned short y,
94 unsigned short width,
95 unsigned short height,
96 unsigned char * data )
97{
98 unsigned short drawWidth;
99 long pixelBytes = VIDEO(depth) / 8;
100 unsigned char * vram = (unsigned char *) VIDEO(baseAddr) +
101VIDEO(rowBytes) * y + pixelBytes * x;
102
103 drawWidth = MIN(width, VIDEO(width) - x);
104 height = MIN(height, VIDEO(height) - y);
105 while ( height-- ) {
106 bcopy( data, vram, drawWidth * pixelBytes );
107 vram += VIDEO(rowBytes);
108 data += width * pixelBytes;
109 }
110}
111#endif
112
113//==========================================================================
114// getVESAModeWithProperties
115//
116// Return the VESA mode that matches the properties specified.
117// If a mode is not found, then return the "best" available mode.
118
119unsigned short
120getVESAModeWithProperties( unsigned short width,
121 unsigned short height,
122 unsigned char bitsPerPixel,
123 unsigned short attributesSet,
124 unsigned short attributesClear,
125 VBEModeInfoBlock * outModeInfo,
126 unsigned short * vesaVersion )
127{
128 VBEInfoBlock vbeInfo;
129 unsigned short * modePtr;
130 VBEModeInfoBlock modeInfo;
131 unsigned char modeBitsPerPixel;
132 unsigned short matchedMode = modeEndOfList;
133 int err;
134
135 // Clear output mode info.
136
137 bzero( outModeInfo, sizeof(*outModeInfo) );
138
139 // Get VBE controller info containing the list of supported modes.
140
141 bzero( &vbeInfo, sizeof(vbeInfo) );
142 strcpy( (char*)&vbeInfo, "VBE2" );
143 err = getVBEInfo( &vbeInfo );
144 if ( err != errSuccess )
145 {
146 return modeEndOfList;
147 }
148
149 // Report the VESA major/minor version number.
150
151 if (vesaVersion) *vesaVersion = vbeInfo.VESAVersion;
152
153 // Loop through the mode list, and find the matching mode.
154
155 for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );
156 *modePtr != modeEndOfList; modePtr++ )
157 {
158 // Get mode information.
159
160 bzero( &modeInfo, sizeof(modeInfo) );
161 err = getVBEModeInfo( *modePtr, &modeInfo );
162 if ( err != errSuccess )
163 {
164 continue;
165 }
166
167#if DEBUG
168 printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",
169 *modePtr, modeInfo.XResolution, modeInfo.YResolution,
170 modeInfo.BitsPerPixel, modeInfo.MemoryModel,
171 modeInfo.ModeAttributes);
172#endif
173
174 // Filter out unwanted modes based on mode attributes.
175
176 if ( ( ( modeInfo.ModeAttributes & attributesSet ) != attributesSet )
177|| ( ( modeInfo.ModeAttributes & attributesClear ) != 0 ) )
178 {
179 continue;
180 }
181
182 // Pixel depth in bits.
183
184 modeBitsPerPixel = modeInfo.BitsPerPixel;
185
186 if ( ( modeBitsPerPixel == 4 ) && ( modeInfo.MemoryModel == 0 ) )
187 {
188 // Text mode, 16 colors.
189 }
190 else if ( ( modeBitsPerPixel == 8 ) && ( modeInfo.MemoryModel == 4 ) )
191 {
192 // Packed pixel, 256 colors.
193 }
194 else if ( ( ( modeBitsPerPixel == 16 ) || ( modeBitsPerPixel == 15 ) )
195 && ( modeInfo.MemoryModel == 6 )
196 && ( modeInfo.RedMaskSize == 5 )
197 && ( modeInfo.GreenMaskSize == 5 )
198 && ( modeInfo.BlueMaskSize == 5 ) )
199 {
200 // Direct color, 16 bpp (1:5:5:5).
201 modeInfo.BitsPerPixel = modeBitsPerPixel = 16;
202 }
203 else if ( ( modeBitsPerPixel == 32 )
204 && ( modeInfo.MemoryModel == 6 )
205 && ( modeInfo.RedMaskSize == 8 )
206 && ( modeInfo.GreenMaskSize == 8 )
207 && ( modeInfo.BlueMaskSize == 8 ) )
208 {
209 // Direct color, 32 bpp (8:8:8:8).
210 }
211 else
212 {
213 continue; // Not a supported mode.
214 }
215
216 // Modes larger than the specified dimensions are skipped.
217
218 if ( ( modeInfo.XResolution > width ) ||
219( modeInfo.YResolution > height ) )
220 {
221 continue;
222 }
223
224 // Perfect match, we're done looking.
225
226 if ( ( modeInfo.XResolution == width ) &&
227( modeInfo.YResolution == height ) &&
228( modeBitsPerPixel == bitsPerPixel ) )
229 {
230 matchedMode = *modePtr;
231 bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
232 break;
233 }
234
235 // Save the next "best" mode in case a perfect match is not found.
236
237 if ( modeInfo.XResolution == outModeInfo->XResolution &&
238modeInfo.YResolution == outModeInfo->YResolution &&
239modeBitsPerPixel <= outModeInfo->BitsPerPixel )
240 {
241 continue; // Saved mode has more depth.
242 }
243 if ( modeInfo.XResolution < outModeInfo->XResolution ||
244modeInfo.YResolution < outModeInfo->YResolution ||
245modeBitsPerPixel < outModeInfo->BitsPerPixel )
246 {
247 continue; // Saved mode has more resolution.
248 }
249
250 matchedMode = *modePtr;
251 bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) );
252 }
253
254 return matchedMode;
255}
256
257//==========================================================================
258// setupPalette
259
260static void setupPalette( VBEPalette * p, const unsigned char * g )
261{
262 int i;
263 unsigned char * source = (unsigned char *) g;
264
265 for (i = 0; i < 256; i++)
266 {
267 (*p)[i] = 0;
268 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red
269 (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green
270 (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue
271
272 }
273}
274
275//==========================================================================
276// setVESAGraphicsMode
277#if UNUSED
278int setVESAGraphicsMode( unsigned short width, unsigned short height, unsigned char bitsPerPixel, unsigned short refreshRate )
279#else
280int setVESAGraphicsMode( unsigned short width, unsigned short height, unsigned char bitsPerPixel)
281#endif
282{
283 VBEModeInfoBlock minfo;
284 unsigned short mode;
285 unsigned short vesaVersion;
286 int err = errFuncNotSupported;
287
288 do {
289 mode = getVESAModeWithProperties( width, height, bitsPerPixel,
290 maColorModeBit |
291 maModeIsSupportedBit |
292 maGraphicsModeBit |
293 maLinearFrameBufferAvailBit,
294 0,
295 &minfo, &vesaVersion );
296 if ( mode == modeEndOfList )
297 {
298 break;
299 }
300#if UNUSED
301//
302// FIXME : generateCRTCTiming() causes crash.
303//
304
305// if ( (vesaVersion >> 8) >= 3 && refreshRate >= 60 &&
306// (gBootMode & kBootModeSafe) == 0 )
307// {
308// VBECRTCInfoBlock timing;
309//
310// // Generate CRTC timing for given refresh rate.
311//
312// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
313// refreshRate, kCRTCParamRefreshRate,
314// &timing );
315//
316// // Find the actual pixel clock supported by the hardware.
317//
318// getVBEPixelClock( mode, &timing.PixelClock );
319//
320// // Re-compute CRTC timing based on actual pixel clock.
321//
322// generateCRTCTiming( minfo.XResolution, minfo.YResolution,
323// timing.PixelClock, kCRTCParamPixelClock,
324// &timing );
325//
326// // Set the video mode and use specified CRTC timing.
327//
328// err = setVBEMode( mode | kLinearFrameBufferBit |
329// kCustomRefreshRateBit, &timing );
330// }
331// else
332// {
333// // Set the mode with default refresh rate.
334//
335// err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
336// }
337#endif
338 // Set the mode with default refresh rate.
339
340 err = setVBEMode( mode | kLinearFrameBufferBit, NULL );
341
342 if ( err != errSuccess )
343 {
344 break;
345 }
346
347 // Set 8-bit color palette.
348
349 if ( minfo.BitsPerPixel == 8 )
350 {
351 VBEPalette palette;
352 setupPalette( &palette, appleClut8 );
353 if ((err = setVBEPalette(palette)) != errSuccess)
354 {
355 break;
356 }
357 }
358
359 // Is this required for buggy Video BIOS implementations?
360 // On which adapter?
361
362 if ( minfo.BytesPerScanline == 0 )
363minfo.BytesPerScanline = ( minfo.XResolution *
364 minfo.BitsPerPixel ) >> 3;
365
366 // Update KernBootStruct using info provided by the selected
367 // VESA mode.
368
369 bootArgs->Video.v_display = GRAPHICS_MODE;
370 bootArgs->Video.v_width = minfo.XResolution;
371 bootArgs->Video.v_height = minfo.YResolution;
372 bootArgs->Video.v_depth = minfo.BitsPerPixel;
373 bootArgs->Video.v_rowBytes = minfo.BytesPerScanline;
374 bootArgs->Video.v_baseAddr = VBEMakeUInt32(minfo.PhysBasePtr);
375
376 }
377 while ( 0 );
378
379 return err;
380}
381
382
383#ifndef OPTION_ROM
384
385//==========================================================================
386// Simple decompressor for boot images encoded in RLE format.
387
388char * decodeRLE( const void * rleData, int rleBlocks, int outBytes )
389{
390 char *out, *cp;
391
392 struct RLEBlock {
393 unsigned char count;
394 unsigned char value;
395 } * bp = (struct RLEBlock *) rleData;
396
397 out = cp = malloc( outBytes );
398 if ( out == NULL ) return NULL;
399
400 while ( rleBlocks-- )
401 {
402 memset( cp, bp->value, bp->count );
403 cp += bp->count;
404 bp++;
405 }
406
407 return out;
408}
409
410//==========================================================================
411// LookUpCLUTIndex
412
413unsigned long lookUpCLUTIndex( unsigned char index,
414 unsigned char depth )
415{
416 long result, red, green, blue;
417
418 red = appleClut8[index * 3 + 0];
419 green = appleClut8[index * 3 + 1];
420 blue = appleClut8[index * 3 + 2];
421
422 switch (depth) {
423 case 16 :
424 result = ((red & 0xF8) << 7) |
425((green & 0xF8) << 2) |
426((blue & 0xF8) >> 3);
427 result |= (result << 16);
428 break;
429
430 case 32 :
431 result = (red << 16) | (green << 8) | blue;
432 break;
433
434 default :
435 result = index | (index << 8);
436 result |= (result << 16);
437 break;
438 }
439
440 return result;
441}
442
443//==========================================================================
444// drawColorRectangle
445
446void * stosl(void * dst, long val, long len)
447{
448 asm volatile ( "rep; stosl"
449 : "=c" (len), "=D" (dst)
450 : "0" (len), "1" (dst), "a" (val)
451 : "memory" );
452
453 return dst;
454}
455
456void drawColorRectangle( unsigned short x,
457unsigned short y,
458unsigned short width,
459unsigned short height,
460unsigned char colorIndex )
461{
462 long pixelBytes;
463 long color = lookUpCLUTIndex( colorIndex, VIDEO(depth) );
464 char * vram;
465
466 pixelBytes = VIDEO(depth) / 8;
467 vram = (char *) VIDEO(baseAddr) +
468VIDEO(rowBytes) * y + pixelBytes * x;
469
470 width = MIN(width, VIDEO(width) - x);
471 height = MIN(height, VIDEO(height) - y);
472
473 while ( height-- )
474 {
475 int rem = ( pixelBytes * width ) % 4;
476 if ( rem ) bcopy( &color, vram, rem );
477 stosl( vram + rem, color, pixelBytes * width / 4 );
478 vram += VIDEO(rowBytes);
479 }
480}
481
482#endif
483
484
485//==========================================================================
486// setVESATextMode
487
488static int
489setVESATextMode( unsigned short cols,
490unsigned short rows,
491unsigned char bitsPerPixel )
492{
493 VBEModeInfoBlock minfo;
494 unsigned short mode = modeEndOfList;
495
496 if ( (cols != 80) || (rows != 25) ) // not 80x25 mode
497 {
498 mode = getVESAModeWithProperties( cols, rows, bitsPerPixel,
499 maColorModeBit |
500 maModeIsSupportedBit,
501 maGraphicsModeBit,
502 &minfo, NULL );
503 }
504
505 if ( ( mode == modeEndOfList ) || ( setVBEMode(mode, NULL) != errSuccess ) )
506 {
507 video_mode( 2 ); // VGA BIOS, 80x25 text mode.
508 minfo.XResolution = 80;
509 minfo.YResolution = 25;
510 }
511
512 // Update KernBootStruct using info provided by the selected
513 // VESA mode.
514
515 bootArgs->Video.v_display = VGA_TEXT_MODE;
516 bootArgs->Video.v_baseAddr = 0xb8000;
517 bootArgs->Video.v_width = minfo.XResolution;
518 bootArgs->Video.v_height = minfo.YResolution;
519 bootArgs->Video.v_depth = 8;
520 bootArgs->Video.v_rowBytes = 0x8000;
521
522 return errSuccess; // always return success
523}
524
525//==========================================================================
526// getNumberArrayFromProperty
527
528int
529getNumberArrayFromProperty( const char * propKey,
530 unsigned long numbers[],
531 unsigned long maxArrayCount )
532{
533 char * propStr;
534 unsigned long count = 0;
535
536 propStr = newStringForKey( (char *) propKey , &bootInfo->bootConfig );
537 if ( propStr )
538 {
539 char * delimiter = propStr;
540 char * p = propStr;
541
542 while ( count < maxArrayCount && *p != '\0' )
543 {
544 unsigned long val = strtoul( p, &delimiter, 10 );
545 if ( p != delimiter )
546 {
547 numbers[count++] = val;
548 p = delimiter;
549 }
550 while ( ( *p != '\0' ) && !isdigit(*p) )
551 p++;
552 }
553
554 free( propStr );
555 }
556
557 return count;
558}
559
560int initGraphicsMode ()
561{
562unsigned long params[4];
563int count;
564
565params[3] = 0;
566count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 );
567
568// Try to find a resolution if "Graphics Mode" setting is not available.
569if ( count < 3 )
570{
571params[0] = DEFAULT_SCREEN_WIDTH;
572params[1] = DEFAULT_SCREEN_HEIGHT;
573params[2] = 32;
574}
575
576// Map from pixel format to bits per pixel.
577
578if ( params[2] == 256 ) params[2] = 8;
579if ( params[2] == 555 ) params[2] = 16;
580if ( params[2] == 888 ) params[2] = 32;
581#if UNUSED
582return setVESAGraphicsMode( params[0], params[1], params[2], params[3] );
583#else
584return setVESAGraphicsMode( params[0], params[1], params[2] );
585#endif
586}
587
588//==========================================================================
589// setVideoMode
590//
591// Set the video mode to VGA_TEXT_MODE or GRAPHICS_MODE.
592#if UNUSED
593void
594setVideoMode( int mode, int drawgraphics)
595#else
596void
597setVideoMode( int mode)
598#endif
599{
600 unsigned long params[4];
601 int count;
602 int err = errSuccess;
603
604 if ( mode == GRAPHICS_MODE )
605 {
606 if ( (err=initGraphicsMode ()) == errSuccess ) {
607if (gVerboseMode) {
608// Tell the kernel to use text mode on a linear frame buffer display
609bootArgs->Video.v_display = FB_TEXT_MODE;
610} else {
611bootArgs->Video.v_display = GRAPHICS_MODE;
612}
613}
614 }
615
616 if ( (mode == VGA_TEXT_MODE) || (err != errSuccess) )
617 {
618 count = getNumberArrayFromProperty( kTextModeKey, params, 2 );
619 if ( count < 2 )
620 {
621 params[0] = 80; // Default text mode is 80x25.
622 params[1] = 25;
623 }
624
625setVESATextMode( params[0], params[1], 4 );
626 bootArgs->Video.v_display = VGA_TEXT_MODE;
627 }
628
629#if TEXT_SPINNER
630 currentIndicator = 0;
631#endif
632}
633
634//==========================================================================
635// Return the current video mode, VGA_TEXT_MODE or GRAPHICS_MODE.
636
637inline int getVideoMode(void)
638{
639 return bootArgs->Video.v_display;
640}
641#if TEXT_SPINNER
642
643//==========================================================================
644// Display and clear the activity indicator.
645
646static char indicator[] = {'-', '\\', '|', '/', '-', '\\', '|', '/', '\0'};
647//static char indicator[] = {'_', ' ','\0'};
648
649// To prevent a ridiculously fast-spinning indicator,
650// ensure a minimum of 1/9 sec between animation frames.
651#define MIN_TICKS 2
652
653void
654spinActivityIndicator(int sectors)
655{
656 static unsigned long lastTickTime = 0, currentTickTime;
657
658bool doreturn = false;
659execute_hook("spinActivity_hook", &sectors, &doreturn, NULL, NULL, NULL, NULL);
660if (doreturn == true) return;
661
662currentTickTime = time18(); // late binding
663if (currentTickTime < lastTickTime + MIN_TICKS)
664{
665return;
666}
667else
668{
669lastTickTime = currentTickTime;
670}
671
672if (getVideoMode() == VGA_TEXT_MODE)
673{
674if (currentIndicator >= sizeof(indicator))
675{
676currentIndicator = 0;
677}
678putc(indicator[currentIndicator++]);
679putc('\b');
680}
681}
682
683void
684clearActivityIndicator( void )
685{
686 if ( getVideoMode() == VGA_TEXT_MODE )
687 {
688putc(' ');
689putc('\b');
690 }
691}
692
693#endif

Archive Download this file

Revision: 1119