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

Archive Download this file

Revision: 1972