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

Archive Download this file

Revision: HEAD