]>
Commit | Line | Data |
---|---|---|
14c7c974 | 1 | /* |
57c72a9a | 2 | * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. |
14c7c974 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
57c72a9a | 6 | * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights |
4f6e3300 A |
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 | |
57c72a9a | 9 | * Source License Version 2.0 (the "License"). You may not use this file |
4f6e3300 A |
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. | |
14c7c974 A |
13 | * |
14 | * The Original Code and all software distributed under the License are | |
4f6e3300 | 15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
14c7c974 A |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
4f6e3300 A |
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. | |
14c7c974 A |
21 | * |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | /* | |
25 | * Copyright 1993 NeXT, Inc. | |
26 | * All rights reserved. | |
27 | */ | |
28 | ||
14c7c974 A |
29 | #include "boot.h" |
30 | #include "vbe.h" | |
75b89a82 | 31 | #include "appleClut8.h" |
f083c6c3 A |
32 | #include "appleboot.h" |
33 | #include "bootstruct.h" | |
14c7c974 A |
34 | |
35 | /* | |
75b89a82 | 36 | * for spinning disk |
14c7c974 | 37 | */ |
75b89a82 A |
38 | static int currentIndicator = 0; |
39 | ||
40 | static unsigned long lookUpCLUTIndex( unsigned char index, | |
41 | unsigned char depth ); | |
42 | ||
57c72a9a | 43 | void drawColorRectangle( unsigned short x, |
75b89a82 A |
44 | unsigned short y, |
45 | unsigned short width, | |
46 | unsigned short height, | |
47 | unsigned char colorIndex ); | |
48 | ||
57c72a9a | 49 | void drawDataRectangle( unsigned short x, |
75b89a82 A |
50 | unsigned short y, |
51 | unsigned short width, | |
52 | unsigned short height, | |
57c72a9a A |
53 | unsigned char * data ); |
54 | ||
bba600dd | 55 | static void setBorderColor( unsigned char colorIndex ); |
57c72a9a A |
56 | |
57 | int | |
58 | convertImage( unsigned short width, | |
59 | unsigned short height, | |
60 | const unsigned char *imageData, | |
61 | unsigned char **newImageData ); | |
75b89a82 | 62 | |
bba600dd | 63 | #define VIDEO(x) (bootArgs->Video.v_ ## x) |
75b89a82 | 64 | |
57c72a9a | 65 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) |
14c7c974 A |
66 | |
67 | //========================================================================== | |
75b89a82 | 68 | // printVBEInfo |
14c7c974 | 69 | |
75b89a82 A |
70 | void printVBEInfo() |
71 | { | |
72 | VBEInfoBlock vbeInfo; | |
73 | int err; | |
57c72a9a | 74 | int small; |
75b89a82 A |
75 | |
76 | // Fetch VBE Controller Info. | |
77 | ||
78 | bzero( &vbeInfo, sizeof(vbeInfo) ); | |
79 | err = getVBEInfo( &vbeInfo ); | |
80 | if ( err != errSuccess ) | |
81 | return; | |
82 | ||
83 | // Check presence of VESA signature. | |
84 | ||
bba600dd | 85 | if ( strncmp( (char *)vbeInfo.VESASignature, "VESA", 4 ) ) |
75b89a82 A |
86 | return; |
87 | ||
88 | // Announce controller properties. | |
89 | ||
57c72a9a A |
90 | small = (vbeInfo.TotalMemory < 16); |
91 | ||
92 | printf("VESA v%d.%d %d%s (%s)\n", | |
75b89a82 A |
93 | vbeInfo.VESAVersion >> 8, |
94 | vbeInfo.VESAVersion & 0xf, | |
57c72a9a A |
95 | small ? (vbeInfo.TotalMemory * 64) : (vbeInfo.TotalMemory / 16), |
96 | small ? "KB" : "MB", | |
75b89a82 A |
97 | VBEDecodeFP(const char *, vbeInfo.OEMStringPtr) ); |
98 | } | |
99 | ||
57c72a9a A |
100 | //========================================================================== |
101 | // | |
102 | ||
103 | void | |
104 | printVBEModeInfo() | |
105 | { | |
106 | VBEInfoBlock vbeInfo; | |
107 | unsigned short * modePtr; | |
108 | VBEModeInfoBlock modeInfo; | |
109 | int err; | |
110 | int line; | |
111 | ||
112 | err = getVBEInfo( &vbeInfo ); | |
113 | if ( err != errSuccess ) | |
114 | return; | |
115 | ||
116 | line = 0; | |
117 | ||
118 | // Activate and clear page 1 | |
119 | setActiveDisplayPage(1); | |
120 | clearScreenRows(0, 24); | |
121 | setCursorPosition( 0, 0, 1 ); | |
122 | ||
123 | printVBEInfo(); | |
124 | printf("Video modes supported:\n", VBEDecodeFP(const char *, vbeInfo.OEMStringPtr)); | |
125 | ||
126 | // Loop through the mode list, and find the matching mode. | |
127 | ||
128 | for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr ); | |
129 | *modePtr != modeEndOfList; modePtr++ ) | |
130 | { | |
131 | // Get mode information. | |
132 | ||
133 | bzero( &modeInfo, sizeof(modeInfo) ); | |
134 | err = getVBEModeInfo( *modePtr, &modeInfo ); | |
135 | if ( err != errSuccess ) | |
136 | { | |
137 | continue; | |
138 | } | |
139 | ||
140 | printf("Mode %x: %dx%dx%d mm:%d attr:%x\n", | |
141 | *modePtr, modeInfo.XResolution, modeInfo.YResolution, | |
142 | modeInfo.BitsPerPixel, modeInfo.MemoryModel, | |
143 | modeInfo.ModeAttributes); | |
144 | ||
145 | if (line++ >= 20) { | |
146 | printf("(Press a key to continue...)"); | |
147 | getc(); | |
148 | line = 0; | |
149 | clearScreenRows(0, 24); | |
150 | setCursorPosition( 0, 0, 1 ); | |
151 | } | |
152 | } | |
153 | if (line != 0) { | |
154 | printf("(Press a key to continue...)"); | |
155 | getc(); | |
156 | } | |
157 | setActiveDisplayPage(0); | |
158 | } | |
159 | ||
160 | ||
75b89a82 A |
161 | //========================================================================== |
162 | // getVESAModeWithProperties | |
163 | // | |
164 | // Return the VESA mode that matches the properties specified. | |
165 | // If a mode is not found, then return the "best" available mode. | |
166 | ||
167 | static unsigned short | |
168 | getVESAModeWithProperties( unsigned short width, | |
169 | unsigned short height, | |
170 | unsigned char bitsPerPixel, | |
171 | unsigned short attributesSet, | |
172 | unsigned short attributesClear, | |
f083c6c3 A |
173 | VBEModeInfoBlock * outModeInfo, |
174 | unsigned short * vesaVersion ) | |
14c7c974 | 175 | { |
75b89a82 A |
176 | VBEInfoBlock vbeInfo; |
177 | unsigned short * modePtr; | |
f083c6c3 | 178 | VBEModeInfoBlock modeInfo; |
75b89a82 A |
179 | unsigned char modeBitsPerPixel; |
180 | unsigned short matchedMode = modeEndOfList; | |
181 | int err; | |
182 | ||
183 | // Clear output mode info. | |
14c7c974 | 184 | |
75b89a82 | 185 | bzero( outModeInfo, sizeof(*outModeInfo) ); |
14c7c974 | 186 | |
75b89a82 A |
187 | // Get VBE controller info containing the list of supported modes. |
188 | ||
189 | bzero( &vbeInfo, sizeof(vbeInfo) ); | |
190 | err = getVBEInfo( &vbeInfo ); | |
191 | if ( err != errSuccess ) | |
192 | { | |
193 | return modeEndOfList; | |
194 | } | |
195 | ||
f083c6c3 A |
196 | // Report the VESA major/minor version number. |
197 | ||
198 | if (vesaVersion) *vesaVersion = vbeInfo.VESAVersion; | |
199 | ||
75b89a82 A |
200 | // Loop through the mode list, and find the matching mode. |
201 | ||
202 | for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr ); | |
203 | *modePtr != modeEndOfList; modePtr++ ) | |
14c7c974 | 204 | { |
75b89a82 A |
205 | // Get mode information. |
206 | ||
207 | bzero( &modeInfo, sizeof(modeInfo) ); | |
208 | err = getVBEModeInfo( *modePtr, &modeInfo ); | |
209 | if ( err != errSuccess ) | |
14c7c974 | 210 | { |
75b89a82 | 211 | continue; |
14c7c974 | 212 | } |
75b89a82 | 213 | |
57c72a9a | 214 | #if DEBUG |
75b89a82 A |
215 | printf("Mode %x: %dx%dx%d mm:%d attr:%x\n", |
216 | *modePtr, modeInfo.XResolution, modeInfo.YResolution, | |
217 | modeInfo.BitsPerPixel, modeInfo.MemoryModel, | |
218 | modeInfo.ModeAttributes); | |
219 | #endif | |
220 | ||
221 | // Filter out unwanted modes based on mode attributes. | |
222 | ||
223 | if ( ( ( modeInfo.ModeAttributes & attributesSet ) != attributesSet ) | |
224 | || ( ( modeInfo.ModeAttributes & attributesClear ) != 0 ) ) | |
225 | { | |
226 | continue; | |
227 | } | |
228 | ||
229 | // Pixel depth in bits. | |
230 | ||
231 | modeBitsPerPixel = modeInfo.BitsPerPixel; | |
232 | ||
233 | if ( ( modeBitsPerPixel == 4 ) && ( modeInfo.MemoryModel == 0 ) ) | |
234 | { | |
235 | // Text mode, 16 colors. | |
236 | } | |
237 | else if ( ( modeBitsPerPixel == 8 ) && ( modeInfo.MemoryModel == 4 ) ) | |
238 | { | |
239 | // Packed pixel, 256 colors. | |
240 | } | |
241 | else if ( ( ( modeBitsPerPixel == 16 ) || ( modeBitsPerPixel == 15 ) ) | |
242 | && ( modeInfo.MemoryModel == 6 ) | |
243 | && ( modeInfo.RedMaskSize == 5 ) | |
244 | && ( modeInfo.GreenMaskSize == 5 ) | |
245 | && ( modeInfo.BlueMaskSize == 5 ) ) | |
246 | { | |
247 | // Direct color, 16 bpp (1:5:5:5). | |
248 | modeInfo.BitsPerPixel = modeBitsPerPixel = 16; | |
249 | } | |
250 | else if ( ( modeBitsPerPixel == 32 ) | |
251 | && ( modeInfo.MemoryModel == 6 ) | |
252 | && ( modeInfo.RedMaskSize == 8 ) | |
253 | && ( modeInfo.GreenMaskSize == 8 ) | |
254 | && ( modeInfo.BlueMaskSize == 8 ) ) | |
255 | { | |
256 | // Direct color, 32 bpp (8:8:8:8). | |
257 | } | |
258 | else | |
259 | { | |
260 | continue; // Not a supported mode. | |
261 | } | |
262 | ||
263 | // Modes larger than the specified dimensions are skipped. | |
264 | ||
265 | if ( ( modeInfo.XResolution > width ) || | |
266 | ( modeInfo.YResolution > height ) ) | |
267 | { | |
268 | continue; | |
269 | } | |
270 | ||
271 | // Perfect match, we're done looking. | |
272 | ||
273 | if ( ( modeInfo.XResolution == width ) && | |
274 | ( modeInfo.YResolution == height ) && | |
275 | ( modeBitsPerPixel == bitsPerPixel ) ) | |
276 | { | |
277 | matchedMode = *modePtr; | |
278 | bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) ); | |
279 | break; | |
280 | } | |
281 | ||
f083c6c3 | 282 | // Save the next "best" mode in case a perfect match is not found. |
75b89a82 | 283 | |
f083c6c3 A |
284 | if ( modeInfo.XResolution == outModeInfo->XResolution && |
285 | modeInfo.YResolution == outModeInfo->YResolution && | |
286 | modeBitsPerPixel <= outModeInfo->BitsPerPixel ) | |
75b89a82 | 287 | { |
f083c6c3 | 288 | continue; // Saved mode has more depth. |
75b89a82 | 289 | } |
f083c6c3 A |
290 | if ( modeInfo.XResolution < outModeInfo->XResolution || |
291 | modeInfo.YResolution < outModeInfo->YResolution || | |
57c72a9a | 292 | modeBitsPerPixel < outModeInfo->BitsPerPixel ) |
f083c6c3 A |
293 | { |
294 | continue; // Saved mode has more resolution. | |
295 | } | |
296 | ||
297 | matchedMode = *modePtr; | |
298 | bcopy( &modeInfo, outModeInfo, sizeof(modeInfo) ); | |
75b89a82 A |
299 | } |
300 | ||
301 | return matchedMode; | |
14c7c974 A |
302 | } |
303 | ||
75b89a82 A |
304 | //========================================================================== |
305 | // setupPalette | |
306 | ||
307 | static void setupPalette( VBEPalette * p, const unsigned char * g ) | |
308 | { | |
309 | int i; | |
310 | unsigned char * source = (unsigned char *) g; | |
311 | ||
312 | for (i = 0; i < 256; i++) | |
313 | { | |
314 | (*p)[i] = 0; | |
315 | (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red | |
316 | (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green | |
317 | (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue | |
318 | } | |
319 | } | |
14c7c974 | 320 | |
f083c6c3 A |
321 | //========================================================================== |
322 | // Simple decompressor for boot images encoded in RLE format. | |
323 | ||
57c72a9a | 324 | char * decodeRLE( const void * rleData, int rleBlocks, int outBytes ) |
f083c6c3 A |
325 | { |
326 | char *out, *cp; | |
327 | ||
328 | struct RLEBlock { | |
329 | unsigned char count; | |
330 | unsigned char value; | |
331 | } * bp = (struct RLEBlock *) rleData; | |
332 | ||
333 | out = cp = (char *) malloc( outBytes ); | |
334 | if ( out == NULL ) return NULL; | |
335 | ||
336 | while ( rleBlocks-- ) | |
337 | { | |
338 | memset( cp, bp->value, bp->count ); | |
339 | cp += bp->count; | |
340 | bp++; | |
341 | } | |
342 | ||
343 | return out; | |
344 | } | |
345 | ||
14c7c974 | 346 | //========================================================================== |
75b89a82 | 347 | // setVESAGraphicsMode |
14c7c974 | 348 | |
75b89a82 A |
349 | static int |
350 | setVESAGraphicsMode( unsigned short width, | |
351 | unsigned short height, | |
f083c6c3 A |
352 | unsigned char bitsPerPixel, |
353 | unsigned short refreshRate ) | |
14c7c974 | 354 | { |
75b89a82 A |
355 | VBEModeInfoBlock minfo; |
356 | unsigned short mode; | |
f083c6c3 | 357 | unsigned short vesaVersion; |
75b89a82 A |
358 | int err = errFuncNotSupported; |
359 | ||
360 | do { | |
361 | mode = getVESAModeWithProperties( width, height, bitsPerPixel, | |
362 | maColorModeBit | | |
363 | maModeIsSupportedBit | | |
364 | maGraphicsModeBit | | |
365 | maLinearFrameBufferAvailBit, | |
366 | 0, | |
f083c6c3 | 367 | &minfo, &vesaVersion ); |
75b89a82 A |
368 | if ( mode == modeEndOfList ) |
369 | { | |
370 | break; | |
371 | } | |
372 | ||
f083c6c3 A |
373 | if ( (vesaVersion >> 8) >= 3 && refreshRate >= 60 && |
374 | (gBootMode & kBootModeSafe) == 0 ) | |
375 | { | |
376 | VBECRTCInfoBlock timing; | |
377 | ||
378 | // Generate CRTC timing for given refresh rate. | |
379 | ||
380 | generateCRTCTiming( minfo.XResolution, minfo.YResolution, | |
381 | refreshRate, kCRTCParamRefreshRate, | |
382 | &timing ); | |
383 | ||
384 | // Find the actual pixel clock supported by the hardware. | |
385 | ||
386 | getVBEPixelClock( mode, &timing.PixelClock ); | |
387 | ||
388 | // Re-compute CRTC timing based on actual pixel clock. | |
389 | ||
390 | generateCRTCTiming( minfo.XResolution, minfo.YResolution, | |
391 | timing.PixelClock, kCRTCParamPixelClock, | |
392 | &timing ); | |
393 | ||
394 | // Set the video mode and use specified CRTC timing. | |
395 | ||
396 | err = setVBEMode( mode | kLinearFrameBufferBit | | |
397 | kCustomRefreshRateBit, &timing ); | |
398 | } | |
399 | else | |
400 | { | |
401 | // Set the mode with default refresh rate. | |
75b89a82 | 402 | |
f083c6c3 A |
403 | err = setVBEMode( mode | kLinearFrameBufferBit, NULL ); |
404 | } | |
75b89a82 A |
405 | if ( err != errSuccess ) |
406 | { | |
407 | break; | |
408 | } | |
409 | ||
410 | // Set 8-bit color palette. | |
411 | ||
412 | if ( minfo.BitsPerPixel == 8 ) | |
413 | { | |
414 | VBEPalette palette; | |
415 | setupPalette( &palette, appleClut8 ); | |
416 | if ((err = setVBEPalette(palette)) != errSuccess) | |
417 | { | |
418 | break; | |
419 | } | |
420 | } | |
421 | ||
422 | // Is this required for buggy Video BIOS implementations? | |
423 | // On which adapter? | |
424 | ||
425 | if ( minfo.BytesPerScanline == 0 ) | |
426 | minfo.BytesPerScanline = ( minfo.XResolution * | |
427 | minfo.BitsPerPixel ) >> 3; | |
14c7c974 | 428 | |
75b89a82 A |
429 | // Update KernBootStruct using info provided by the selected |
430 | // VESA mode. | |
14c7c974 | 431 | |
bba600dd A |
432 | bootArgs->Video.v_display = GRAPHICS_MODE; |
433 | bootArgs->Video.v_width = minfo.XResolution; | |
434 | bootArgs->Video.v_height = minfo.YResolution; | |
435 | bootArgs->Video.v_depth = minfo.BitsPerPixel; | |
436 | bootArgs->Video.v_rowBytes = minfo.BytesPerScanline; | |
437 | bootArgs->Video.v_baseAddr = VBEMakeUInt32(minfo.PhysBasePtr); | |
57c72a9a | 438 | |
75b89a82 A |
439 | } |
440 | while ( 0 ); | |
441 | ||
f083c6c3 A |
442 | return err; |
443 | } | |
14c7c974 | 444 | |
57c72a9a A |
445 | int |
446 | convertImage( unsigned short width, | |
447 | unsigned short height, | |
448 | const unsigned char *imageData, | |
449 | unsigned char **newImageData ) | |
450 | { | |
451 | int cnt; | |
452 | unsigned char *img = 0; | |
453 | unsigned short *img16; | |
454 | unsigned long *img32; | |
455 | ||
456 | switch ( VIDEO(depth) ) { | |
457 | case 16 : | |
458 | img16 = malloc(width * height * 2); | |
459 | if ( !img16 ) break; | |
460 | for (cnt = 0; cnt < (width * height); cnt++) | |
461 | img16[cnt] = lookUpCLUTIndex(imageData[cnt], 16); | |
462 | img = (unsigned char *)img16; | |
463 | break; | |
464 | ||
465 | case 32 : | |
466 | img32 = malloc(width * height * 4); | |
467 | if ( !img32 ) break; | |
468 | for (cnt = 0; cnt < (width * height); cnt++) | |
469 | img32[cnt] = lookUpCLUTIndex(imageData[cnt], 32); | |
470 | img = (unsigned char *)img32; | |
471 | break; | |
472 | ||
473 | default : | |
474 | img = malloc(width * height); | |
475 | bcopy(imageData, img, width * height); | |
476 | break; | |
477 | } | |
478 | *newImageData = img; | |
479 | return 0; | |
480 | } | |
481 | ||
f083c6c3 A |
482 | //========================================================================== |
483 | // drawBootGraphics | |
14c7c974 | 484 | |
57c72a9a A |
485 | void |
486 | drawBootGraphics( void ) | |
f083c6c3 | 487 | { |
57c72a9a A |
488 | unsigned char * imageData = 0; |
489 | long x, y; | |
f083c6c3 | 490 | char * appleBootPict; |
14c7c974 | 491 | |
f083c6c3 | 492 | do { |
f083c6c3 | 493 | // Fill the background to 75% grey (same as BootX). |
75b89a82 | 494 | |
57c72a9a | 495 | drawColorRectangle( 0, 0, VIDEO(width), VIDEO(height), |
f083c6c3 A |
496 | 0x01 /* color index */ ); |
497 | ||
bba600dd A |
498 | setBorderColor( 0x01 /* color index */ ); |
499 | ||
f083c6c3 A |
500 | appleBootPict = decodeRLE( gAppleBootPictRLE, kAppleBootRLEBlocks, |
501 | kAppleBootWidth * kAppleBootHeight ); | |
14c7c974 | 502 | |
f083c6c3 A |
503 | // Prepare the data for the happy mac. |
504 | ||
505 | if ( appleBootPict ) | |
506 | { | |
57c72a9a | 507 | convertImage(kAppleBootWidth, kAppleBootHeight, |
bba600dd | 508 | (unsigned char *)appleBootPict, &imageData); |
75b89a82 | 509 | |
f083c6c3 A |
510 | x = ( VIDEO(width) - kAppleBootWidth ) / 2; |
511 | y = ( VIDEO(height) - kAppleBootHeight ) / 2 + kAppleBootOffset; | |
512 | ||
513 | // Draw the happy mac in the center of the display. | |
514 | ||
57c72a9a | 515 | if ( imageData ) |
f083c6c3 A |
516 | { |
517 | drawDataRectangle( x, y, kAppleBootWidth, kAppleBootHeight, | |
57c72a9a A |
518 | imageData ); |
519 | free( imageData ); | |
f083c6c3 | 520 | } |
f083c6c3 A |
521 | free( appleBootPict ); |
522 | } | |
75b89a82 | 523 | |
57c72a9a | 524 | } while (0); |
75b89a82 A |
525 | } |
526 | ||
527 | //========================================================================== | |
528 | // LookUpCLUTIndex | |
529 | ||
530 | static unsigned long lookUpCLUTIndex( unsigned char index, | |
531 | unsigned char depth ) | |
532 | { | |
f083c6c3 | 533 | long result, red, green, blue; |
75b89a82 | 534 | |
f083c6c3 A |
535 | red = appleClut8[index * 3 + 0]; |
536 | green = appleClut8[index * 3 + 1]; | |
537 | blue = appleClut8[index * 3 + 2]; | |
75b89a82 | 538 | |
f083c6c3 | 539 | switch (depth) { |
75b89a82 A |
540 | case 16 : |
541 | result = ((red & 0xF8) << 7) | | |
542 | ((green & 0xF8) << 2) | | |
543 | ((blue & 0xF8) >> 3); | |
544 | result |= (result << 16); | |
545 | break; | |
546 | ||
547 | case 32 : | |
548 | result = (red << 16) | (green << 8) | blue; | |
549 | break; | |
550 | ||
551 | default : | |
552 | result = index | (index << 8); | |
553 | result |= (result << 16); | |
554 | break; | |
14c7c974 | 555 | } |
75b89a82 | 556 | |
f083c6c3 | 557 | return result; |
75b89a82 A |
558 | } |
559 | ||
560 | //========================================================================== | |
561 | // drawColorRectangle | |
562 | ||
563 | static void * stosl(void * dst, long val, long len) | |
564 | { | |
bba600dd | 565 | asm volatile ( "rep; stosl" |
75b89a82 A |
566 | : "=c" (len), "=D" (dst) |
567 | : "0" (len), "1" (dst), "a" (val) | |
568 | : "memory" ); | |
569 | ||
570 | return dst; | |
571 | } | |
572 | ||
57c72a9a | 573 | void drawColorRectangle( unsigned short x, |
75b89a82 A |
574 | unsigned short y, |
575 | unsigned short width, | |
576 | unsigned short height, | |
577 | unsigned char colorIndex ) | |
578 | { | |
579 | long pixelBytes; | |
580 | long color = lookUpCLUTIndex( colorIndex, VIDEO(depth) ); | |
581 | char * vram; | |
582 | ||
583 | pixelBytes = VIDEO(depth) / 8; | |
584 | vram = (char *) VIDEO(baseAddr) + | |
585 | VIDEO(rowBytes) * y + pixelBytes * x; | |
586 | ||
57c72a9a A |
587 | width = MIN(width, VIDEO(width) - x); |
588 | height = MIN(height, VIDEO(height) - y); | |
589 | ||
75b89a82 | 590 | while ( height-- ) |
14c7c974 | 591 | { |
75b89a82 A |
592 | int rem = ( pixelBytes * width ) % 4; |
593 | if ( rem ) bcopy( &color, vram, rem ); | |
594 | stosl( vram + rem, color, pixelBytes * width / 4 ); | |
595 | vram += VIDEO(rowBytes); | |
14c7c974 | 596 | } |
75b89a82 | 597 | } |
14c7c974 | 598 | |
75b89a82 A |
599 | //========================================================================== |
600 | // drawDataRectangle | |
601 | ||
57c72a9a A |
602 | void drawDataRectangle( unsigned short x, |
603 | unsigned short y, | |
604 | unsigned short width, | |
605 | unsigned short height, | |
606 | unsigned char * data ) | |
75b89a82 | 607 | { |
57c72a9a | 608 | unsigned short drawWidth; |
75b89a82 | 609 | long pixelBytes = VIDEO(depth) / 8; |
57c72a9a A |
610 | unsigned char * vram = (unsigned char *) VIDEO(baseAddr) + |
611 | VIDEO(rowBytes) * y + pixelBytes * x; | |
75b89a82 | 612 | |
57c72a9a A |
613 | drawWidth = MIN(width, VIDEO(width) - x); |
614 | height = MIN(height, VIDEO(height) - y); | |
615 | while ( height-- ) { | |
616 | bcopy( data, vram, drawWidth * pixelBytes ); | |
75b89a82 A |
617 | vram += VIDEO(rowBytes); |
618 | data += width * pixelBytes; | |
619 | } | |
14c7c974 A |
620 | } |
621 | ||
bba600dd A |
622 | |
623 | //========================================================================== | |
624 | // setBorderColor | |
625 | ||
626 | static void | |
627 | setBorderColor( unsigned char colorIndex ) | |
628 | { | |
629 | long color = lookUpCLUTIndex( colorIndex, 32 ); | |
630 | VBEInfoBlock vbeInfo; | |
631 | int err; | |
632 | ||
633 | // Get VBE controller info. | |
634 | ||
635 | bzero( &vbeInfo, sizeof(vbeInfo) ); | |
636 | err = getVBEInfo( &vbeInfo ); | |
637 | if ( err != errSuccess ) | |
638 | { | |
639 | return; | |
640 | } | |
641 | ||
642 | } | |
643 | ||
644 | ||
14c7c974 | 645 | //========================================================================== |
75b89a82 | 646 | // setVESATextMode |
14c7c974 | 647 | |
75b89a82 A |
648 | static int |
649 | setVESATextMode( unsigned short cols, | |
650 | unsigned short rows, | |
651 | unsigned char bitsPerPixel ) | |
14c7c974 | 652 | { |
75b89a82 A |
653 | VBEModeInfoBlock minfo; |
654 | unsigned short mode = modeEndOfList; | |
655 | ||
656 | if ( (cols != 80) || (rows != 25) ) // not 80x25 mode | |
657 | { | |
658 | mode = getVESAModeWithProperties( cols, rows, bitsPerPixel, | |
659 | maColorModeBit | | |
660 | maModeIsSupportedBit, | |
661 | maGraphicsModeBit, | |
f083c6c3 | 662 | &minfo, NULL ); |
75b89a82 A |
663 | } |
664 | ||
f083c6c3 | 665 | if ( ( mode == modeEndOfList ) || ( setVBEMode(mode, NULL) != errSuccess ) ) |
75b89a82 A |
666 | { |
667 | video_mode( 2 ); // VGA BIOS, 80x25 text mode. | |
668 | minfo.XResolution = 80; | |
669 | minfo.YResolution = 25; | |
670 | } | |
671 | ||
672 | // Update KernBootStruct using info provided by the selected | |
673 | // VESA mode. | |
674 | ||
bba600dd A |
675 | bootArgs->Video.v_display = VGA_TEXT_MODE; |
676 | bootArgs->Video.v_baseAddr = 0xb8000; | |
677 | bootArgs->Video.v_width = minfo.XResolution; | |
678 | bootArgs->Video.v_height = minfo.YResolution; | |
679 | bootArgs->Video.v_depth = 8; | |
680 | bootArgs->Video.v_rowBytes = 0x8000; | |
75b89a82 A |
681 | |
682 | return errSuccess; // always return success | |
14c7c974 A |
683 | } |
684 | ||
685 | //========================================================================== | |
75b89a82 A |
686 | // getNumberArrayFromProperty |
687 | ||
688 | static int | |
689 | getNumberArrayFromProperty( const char * propKey, | |
690 | unsigned long numbers[], | |
691 | unsigned long maxArrayCount ) | |
14c7c974 | 692 | { |
f083c6c3 A |
693 | char * propStr; |
694 | unsigned long count = 0; | |
14c7c974 | 695 | |
75b89a82 | 696 | #define _isdigit(c) ((c) >= '0' && (c) <= '9') |
14c7c974 | 697 | |
75b89a82 A |
698 | propStr = newStringForKey( (char *) propKey ); |
699 | if ( propStr ) | |
14c7c974 | 700 | { |
75b89a82 | 701 | char * delimiter = propStr; |
f083c6c3 | 702 | char * p = propStr; |
75b89a82 | 703 | |
f083c6c3 | 704 | while ( count < maxArrayCount && *p != '\0' ) |
14c7c974 | 705 | { |
f083c6c3 A |
706 | unsigned long val = strtoul( p, &delimiter, 10 ); |
707 | if ( p != delimiter ) | |
75b89a82 A |
708 | { |
709 | numbers[count++] = val; | |
f083c6c3 | 710 | p = delimiter; |
75b89a82 | 711 | } |
f083c6c3 A |
712 | while ( ( *p != '\0' ) && !_isdigit(*p) ) |
713 | p++; | |
14c7c974 | 714 | } |
75b89a82 A |
715 | |
716 | free( propStr ); | |
14c7c974 | 717 | } |
75b89a82 A |
718 | |
719 | return count; | |
720 | } | |
721 | ||
722 | //========================================================================== | |
723 | // setVideoMode | |
724 | // | |
bba600dd | 725 | // Set the video mode to VGA_TEXT_MODE or GRAPHICS_MODE. |
75b89a82 A |
726 | |
727 | void | |
728 | setVideoMode( int mode ) | |
729 | { | |
f083c6c3 | 730 | unsigned long params[4]; |
75b89a82 A |
731 | int count; |
732 | int err = errSuccess; | |
733 | ||
734 | if ( mode == GRAPHICS_MODE ) | |
735 | { | |
f083c6c3 A |
736 | params[3] = 0; |
737 | count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 ); | |
75b89a82 A |
738 | if ( count < 3 ) |
739 | { | |
57c72a9a | 740 | params[0] = 1024; // Default graphics mode is 1024x768x32. |
75b89a82 | 741 | params[1] = 768; |
57c72a9a | 742 | params[2] = 32; |
75b89a82 A |
743 | } |
744 | ||
745 | // Map from pixel format to bits per pixel. | |
746 | ||
747 | if ( params[2] == 256 ) params[2] = 8; | |
748 | if ( params[2] == 555 ) params[2] = 16; | |
749 | if ( params[2] == 888 ) params[2] = 32; | |
750 | ||
f083c6c3 | 751 | err = setVESAGraphicsMode( params[0], params[1], params[2], params[3] ); |
75b89a82 A |
752 | if ( err == errSuccess ) |
753 | { | |
bba600dd A |
754 | if (gVerboseMode) { |
755 | // Tell the kernel to use text mode on a linear frame buffer display | |
756 | bootArgs->Video.v_display = FB_TEXT_MODE; | |
757 | } else { | |
758 | bootArgs->Video.v_display = GRAPHICS_MODE; | |
57c72a9a | 759 | drawBootGraphics(); |
f083c6c3 | 760 | } |
75b89a82 A |
761 | } |
762 | } | |
763 | ||
bba600dd | 764 | if ( (mode == VGA_TEXT_MODE) || (err != errSuccess) ) |
75b89a82 A |
765 | { |
766 | count = getNumberArrayFromProperty( kTextModeKey, params, 2 ); | |
767 | if ( count < 2 ) | |
768 | { | |
769 | params[0] = 80; // Default text mode is 80x25. | |
770 | params[1] = 25; | |
771 | } | |
772 | ||
773 | setVESATextMode( params[0], params[1], 4 ); | |
bba600dd | 774 | bootArgs->Video.v_display = VGA_TEXT_MODE; |
75b89a82 A |
775 | } |
776 | ||
f083c6c3 | 777 | currentIndicator = 0; |
75b89a82 A |
778 | } |
779 | ||
780 | //========================================================================== | |
bba600dd | 781 | // Return the current video mode, VGA_TEXT_MODE or GRAPHICS_MODE. |
75b89a82 A |
782 | |
783 | int getVideoMode(void) | |
784 | { | |
bba600dd | 785 | return bootArgs->Video.v_display; |
14c7c974 A |
786 | } |
787 | ||
788 | //========================================================================== | |
789 | // Display and clear the activity indicator. | |
790 | ||
791 | static char indicator[] = {'-', '\\', '|', '/', '-', '\\', '|', '/', '\0'}; | |
57c72a9a | 792 | #define kNumIndicators (sizeof(indicator) - 1) |
14c7c974 A |
793 | |
794 | // To prevent a ridiculously fast-spinning indicator, | |
795 | // ensure a minimum of 1/9 sec between animation frames. | |
796 | #define MIN_TICKS 2 | |
797 | ||
798 | void | |
799 | spinActivityIndicator( void ) | |
800 | { | |
801 | static unsigned long lastTickTime = 0; | |
802 | unsigned long currentTickTime = time18(); | |
803 | static char string[3] = {'\0', '\b', '\0'}; | |
804 | ||
805 | if (currentTickTime < lastTickTime + MIN_TICKS) | |
806 | return; | |
807 | else | |
808 | lastTickTime = currentTickTime; | |
f083c6c3 | 809 | |
bba600dd | 810 | if ( getVideoMode() == VGA_TEXT_MODE ) |
14c7c974 | 811 | { |
57c72a9a A |
812 | if (currentIndicator >= kNumIndicators) currentIndicator = 0; |
813 | string[0] = indicator[currentIndicator++]; | |
14c7c974 | 814 | printf(string); |
14c7c974 A |
815 | } |
816 | } | |
817 | ||
818 | void | |
819 | clearActivityIndicator( void ) | |
820 | { | |
bba600dd | 821 | if ( getVideoMode() == VGA_TEXT_MODE ) |
14c7c974 A |
822 | { |
823 | printf(" \b"); | |
824 | } | |
825 | } | |
57c72a9a | 826 |