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

Archive Download this file

Revision: 1931