/* * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 2.0 (the "License"). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ * * Copyright 1993 NeXT, Inc. All rights reserved. * */ #include "boot.h" #include "vbe.h" #include "appleClut8.h" #include "gui.h" #include "IOHibernatePrivate.h" /* * for spinning disk */ static int currentIndicator = 0; int previewTotalSectors = 0; int previewLoadedSectors = 0; uint8_t *previewSaveunder = 0; #define VIDEO(x) (bootArgs->Video.v_ ## x) //========================================================================== // getVBEVideoRam uint32_t getVBEVideoRam() { VBEInfoBlock vbeInfo; int err, small; bzero( &vbeInfo, sizeof(vbeInfo) ); strcpy( (char*)&vbeInfo, "VBE2" ); err = getVBEInfo( &vbeInfo ); if (err != errSuccess) return 0; if ( strncmp( (char *)vbeInfo.VESASignature, "VESA", 4 ) ) return 0; small = (vbeInfo.TotalMemory < 16); return vbeInfo.TotalMemory * 64 * 1024; } //========================================================================== // getVBEInfoString char *getVBEInfoString() { VBEInfoBlock vbeInfo; int err, small; char* buff = NULL; bzero( &vbeInfo, sizeof(vbeInfo) ); strcpy( (char*)&vbeInfo, "VBE2" ); err = getVBEInfo( &vbeInfo ); if (err != errSuccess) { return 0; } if ( strncmp( (char *)vbeInfo.VESASignature, "VESA", 4 ) ) { return 0; } buff = malloc(sizeof(char) * 256); if (!buff) { return 0; } small = (vbeInfo.TotalMemory < 16); snprintf(buff, 256, "VESA v%d.%d %d%s (%s)\n", vbeInfo.VESAVersion >> 8, vbeInfo.VESAVersion & 0xf, small ? (vbeInfo.TotalMemory * 64) : (vbeInfo.TotalMemory / 16), small ? "KB" : "MB", VBEDecodeFP(const char *, vbeInfo.OEMStringPtr) ); return buff; } //========================================================================== // void printVBEModeInfo() { VBEInfoBlock vbeInfo; unsigned short * modePtr; VBEModeInfoBlock modeInfo; int err; int line; char* vbeInfoString = NULL; bzero( &vbeInfo, sizeof(vbeInfo) ); strcpy( (char*)&vbeInfo, "VBE2" ); err = getVBEInfo( &vbeInfo ); if ( err != errSuccess ) { return; } line = 0; // Activate and clear page 1 setActiveDisplayPage(1); clearScreenRows(0, 24); setCursorPosition( 0, 0, 1 ); vbeInfoString = getVBEInfoString(); if (!vbeInfoString) { printf("Error: getVBEInfoString failed\n"); return; } printf("%s", vbeInfoString); free(vbeInfoString); vbeInfoString = NULL; printf("Video modes supported:\n", VBEDecodeFP(const char *, vbeInfo.OEMStringPtr)); // Loop through the mode list, and find the matching mode. for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr ); *modePtr != modeEndOfList; modePtr++ ) { // Get mode information. bzero( &modeInfo, sizeof(modeInfo) ); err = getVBEModeInfo( *modePtr, &modeInfo ); if ( err != errSuccess ) { continue; } printf("Mode %x: %dx%dx%d mm:%d attr:%x\n", *modePtr, modeInfo.XResolution, modeInfo.YResolution, modeInfo.BitsPerPixel, modeInfo.MemoryModel, modeInfo.ModeAttributes); if (line++ >= 20) { pause(); line = 0; clearScreenRows(0, 24); setCursorPosition( 0, 0, 1 ); } } if (line != 0) { pause(); } setActiveDisplayPage(0); } //============================================================================== char *getVBEModeInfoString() { VBEInfoBlock vbeInfo; unsigned short * modePtr; VBEModeInfoBlock modeInfo; int err; bzero( &vbeInfo, sizeof(vbeInfo) ); strcpy( (char*)&vbeInfo, "VBE2" ); err = getVBEInfo( &vbeInfo ); if ( err != errSuccess ) { return 0; } char *buff=malloc(sizeof(char)*3072); if(!buff) { return 0; } int bufflen = 0; // Loop through the mode list, and find the matching mode. for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr ); (*modePtr != modeEndOfList) && (bufflen < 3072); /* prevent buffer overrun */ modePtr++ ) { // Get mode information. bzero( &modeInfo, sizeof(modeInfo) ); err = getVBEModeInfo( *modePtr, &modeInfo ); if ( err != errSuccess ) { continue; } bufflen += snprintf(buff+bufflen, 3072-bufflen, "Mode %x: %dx%dx%d mm:%d attr:%x\n", *modePtr, modeInfo.XResolution, modeInfo.YResolution, modeInfo.BitsPerPixel, modeInfo.MemoryModel, modeInfo.ModeAttributes); } return buff; } //========================================================================== // getVESAModeWithProperties // // Return the VESA mode that matches the properties specified. // If a mode is not found, then return the "best" available mode. static unsigned short getVESAModeWithProperties( unsigned short width, unsigned short height, unsigned char bitsPerPixel, unsigned short attributesSet, unsigned short attributesClear, VBEModeInfoBlock *outModeInfo, unsigned short *vesaVersion ) { VBEInfoBlock vbeInfo; unsigned short * modePtr; VBEModeInfoBlock modeInfo; unsigned char modeBitsPerPixel; unsigned short matchedMode = modeEndOfList; int err; // Clear output mode info. bzero( outModeInfo, sizeof(*outModeInfo) ); // Get VBE controller info containing the list of supported modes. bzero( &vbeInfo, sizeof(vbeInfo) ); strcpy( (char*)&vbeInfo, "VBE2" ); err = getVBEInfo( &vbeInfo ); if ( err != errSuccess ) { return modeEndOfList; } // Report the VESA major/minor version number. if (vesaVersion) { *vesaVersion = vbeInfo.VESAVersion; } // Loop through the mode list, and find the matching mode. for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr ); *modePtr != modeEndOfList; modePtr++ ) { // Get mode information. bzero( &modeInfo, sizeof(modeInfo) ); err = getVBEModeInfo( *modePtr, &modeInfo ); if ( err != errSuccess ) { continue; } #if DEBUG printf("Mode %x: %dx%dx%d mm:%d attr:%x\n", *modePtr, modeInfo.XResolution, modeInfo.YResolution, modeInfo.BitsPerPixel, modeInfo.MemoryModel, modeInfo.ModeAttributes); #endif // Filter out unwanted modes based on mode attributes. if (((modeInfo.ModeAttributes & attributesSet) != attributesSet) || ((modeInfo.ModeAttributes & attributesClear) != 0)) { continue; } // Pixel depth in bits. modeBitsPerPixel = modeInfo.BitsPerPixel; if ((modeBitsPerPixel == 4) && (modeInfo.MemoryModel == 0)) { // Text mode, 16 colors. } else if ((modeBitsPerPixel == 8) && (modeInfo.MemoryModel == 4)) { // Packed pixel, 256 colors. } else if (((modeBitsPerPixel == 16) || (modeBitsPerPixel == 15)) && (modeInfo.MemoryModel == 6) && (modeInfo.RedMaskSize == 5) && (modeInfo.GreenMaskSize == 5) && (modeInfo.BlueMaskSize == 5)) { // Direct color, 16 bpp (1:5:5:5). modeInfo.BitsPerPixel = modeBitsPerPixel = 16; } else if ((modeBitsPerPixel == 32) && (modeInfo.MemoryModel == 6) && (modeInfo.RedMaskSize == 8) && (modeInfo.GreenMaskSize == 8) && (modeInfo.BlueMaskSize == 8)) { // Direct color, 32 bpp (8:8:8:8). } else { continue; // Not a supported mode. } // Modes larger than the specified dimensions are skipped. if ((modeInfo.XResolution > width) || (modeInfo.YResolution > height)) { continue; } // Perfect match, we're done looking. if (modeInfo.XResolution == width && modeInfo.YResolution == height && modeBitsPerPixel == bitsPerPixel) { matchedMode = *modePtr; bcopy(&modeInfo, outModeInfo, sizeof(modeInfo)); break; } // Save the next "best" mode in case a perfect match is not found. if (modeInfo.XResolution == outModeInfo->XResolution && modeInfo.YResolution == outModeInfo->YResolution && modeBitsPerPixel <= outModeInfo->BitsPerPixel) { continue; // Saved mode has more depth. } if (modeInfo.XResolution < outModeInfo->XResolution || modeInfo.YResolution < outModeInfo->YResolution || modeBitsPerPixel < outModeInfo->BitsPerPixel) { continue; // Saved mode has more resolution. } matchedMode = *modePtr; bcopy(&modeInfo, outModeInfo, sizeof(modeInfo)); } return matchedMode; } //========================================================================== // setupPalette static void setupPalette( VBEPalette *p, const unsigned char *g ) { int i; unsigned char * source = (unsigned char *) g; for (i = 0; i < 256; i++) { (*p)[i] = 0; (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 16; // Red (*p)[i] |= ((unsigned long)((*source++) >> 2)) << 8; // Green (*p)[i] |= ((unsigned long)((*source++) >> 2)); // Blue } } //========================================================================== // Simple decompressor for boot images encoded in RLE format. char *decodeRLE( const void *rleData, int rleBlocks, int outBytes ) { char *out, *cp; struct RLEBlock { unsigned char count; unsigned char value; } * bp = (struct RLEBlock *) rleData; out = cp = malloc( outBytes ); if ( out == NULL ) return NULL; while ( rleBlocks-- ) { memset( cp, bp->value, bp->count ); cp += bp->count; bp++; } return out; } //========================================================================== // setVESAGraphicsMode static int setVESAGraphicsMode( unsigned short width, unsigned short height, unsigned char bitsPerPixel, unsigned short refreshRate ) { VBEModeInfoBlock minfo; unsigned short mode = 280; // Default to 1024 * 768 * 32 (1920 * 1200 * 32 would be 330) unsigned short vesaVersion; int err = errFuncNotSupported; do { mode = getVESAModeWithProperties( width, height, bitsPerPixel, maColorModeBit | maModeIsSupportedBit | maGraphicsModeBit | maLinearFrameBufferAvailBit, 0, &minfo, &vesaVersion ); if ( mode == modeEndOfList ) { break; } // Set the mode with default refresh rate. err = setVBEMode(mode | kLinearFrameBufferBit, NULL); if (err != errSuccess) { break; } // Is this required for buggy Video BIOS implementations? If so for which adapter? if ( minfo.BitsPerPixel == 8 ) { VBEPalette palette; // A switch is needed for the two clut way... if ( ( MacOSVerCurrent >= MacOSVer2Int("10.10") ) && ( FlagBlackOption ) ) // Yosemite and Up! { setupPalette( &palette, AppleLogoBlackClut ); } else { setupPalette( &palette, AppleLogoClut ); } if ((err = setVBEPalette(palette)) != errSuccess) { break; } } // Is this required for buggy Video BIOS implementations? // On which adapter? if ( minfo.BytesPerScanline == 0 ) { minfo.BytesPerScanline = ( minfo.XResolution * minfo.BitsPerPixel ) >> 3; } // Update KernBootStruct using info provided by the selected // VESA mode. bootArgs->Video.v_display = GRAPHICS_MODE; bootArgs->Video.v_width = minfo.XResolution; /* 1920 or 1600 */ bootArgs->Video.v_height = minfo.YResolution; /* 1200 or 900 */ bootArgs->Video.v_depth = minfo.BitsPerPixel; /* 32 */ bootArgs->Video.v_rowBytes = minfo.BytesPerScanline; /* 7680 or 6400 */ bootArgs->Video.v_baseAddr = VBEMakeUInt32(minfo.PhysBasePtr); } while ( 0 ); return err; } //============================================================================== int convertImage( unsigned short width, unsigned short height, const unsigned char *imageData, unsigned char **newImageData ) { int index = 0; int size = (width * height); // 16384 int depth = VIDEO(depth); unsigned char *img = 0; unsigned long *img32; switch (depth) { case 32: img32 = malloc(size * 4); if (!img32) { break; } for (; index < size; index++) { img32[index] = lookUpCLUTIndex(imageData[index]); } img = (unsigned char *)img32; break; } *newImageData = img; return 0; } //============================================================================== int loadPngImage(const char *filename, uint16_t *width, uint16_t *height, uint8_t **imageData) { uint8_t *pngData = NULL; int pngFile = 0, pngSize; PNG_info_t *info; int error = 0; pngFile = open_bvdev("bt(0,0)", filename, 0); if (pngFile == -1) { error = -1; goto failed; } pngSize = file_size(pngFile); if (!pngSize) { error = -1; goto failed; } pngData = malloc(pngSize); if (read(pngFile, (char *) pngData, pngSize) != pngSize) { error = -1; goto failed; } PNG_error = -1; info = PNG_decode(pngData, pngSize); if (PNG_error != 0) { error = PNG_error; goto failed; } else if ((info->width > 0xffff) || (info->height > 0xffff)) { error = -1; goto failed; } else if ((info->width * info->height * 4) != info->image->size) { error = -1; goto failed; } uint8_t *result = malloc(info->width*4*info->height); *width = info->width; *height = info->height; memcpy(result, info->image->data, info->width*4*info->height); *imageData = result; failed: png_alloc_free_all(); if (pngData) free(pngData); if (pngFile != -1) close(pngFile); return error; } //============================================================================== int loadEmbeddedPngImage(uint8_t *pngData, int pngSize, uint16_t *width, uint16_t *height, uint8_t **imageData) { PNG_info_t *info; int error = 0; PNG_error = -1; info = PNG_decode(pngData, pngSize); if (PNG_error != 0) { error = PNG_error; goto failed; } else if ((info->width > 0xffff) || (info->height > 0xffff)) { error = -1; goto failed; } else if ((info->width * info->height * 4) != info->image->size) { error = -1; goto failed; } uint8_t *result = malloc(info->width*4*info->height); *width = info->width; *height = info->height; memcpy(result, info->image->data, info->width*4*info->height); *imageData = result; failed: png_alloc_free_all(); return error; } //============================================================================== void blendImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t *data) { uint16_t drawWidth; uint8_t *vram = (uint8_t *) VIDEO(baseAddr) + VIDEO(rowBytes) * y + 4 * x; drawWidth = MIN(width, VIDEO(width) - x); height = MIN(height, VIDEO(height) - y); while (height--) { switch (VIDEO (depth)) { case 32: /* Optimized version*/ { uint32_t s; uint32_t* d; // Source (img) and destination (bkgd) pixels uint32_t a; // Alpha uint32_t dstrb, dstg, srcrb, srcg, drb, dg, rb, g, tempB; // Intermediate variables uint16_t pos; for (pos = 0; pos < drawWidth * 4; pos += 4) { // Fast pseudo-vector alpha blending, adapted from: http://www.stereopsis.com/doubleblend.html s = *((uint32_t*) (data + pos)); d = (uint32_t*) (vram + pos); // Flip B and R in source // TODO: use XCHG and inline assembly to do this in a faster, saner way tempB = (s & 0xFF0000); // save B s = (s & 0xFF00FFFF) | ((s & 0xFF) << 16); // put R in B s = (s & 0xFFFFFF00) | (tempB >> 16); // put B in R a = (s >> 24) + 1; dstrb = *d & 0xFF00FF; dstg = *d & 0xFF00; srcrb = s & 0xFF00FF; srcg = s & 0xFF00; drb = srcrb - dstrb; dg = srcg - dstg; drb *= a; dg *= a; drb >>= 8; dg >>= 8; rb = (drb + dstrb) & 0xFF00FF; g = (dg + dstg) & 0xFF00; *d = rb | g; } } break; default: /*Universal version*/ { uint32_t s; uint32_t a; // Alpha uint32_t dr, dg, db, sr, sg, sb; // Intermediate variables uint16_t pos; int bpp = (VIDEO (depth) + 7)/8; for (pos = 0; pos < drawWidth; pos ++) { // Fast pseudo-vector alpha blending, adapted from: http://www.stereopsis.com/doubleblend.html s = *((uint32_t*) (data + 4*pos)); sb = (s & 0xFF0000) >> 16; sg = (s & 0xFF00) >> 8; sr = (s & 0xFF); a = (s >> 24) + 1; switch (VIDEO (depth)) { case 24: db = ((*(uint32_t *)(vram + bpp*pos))&0xff); dg = ((*(uint32_t *)(vram + bpp*pos))&0xff00)>>8; dr = ((*(uint32_t *)(vram + bpp*pos))&0xff0000)>>16; break; case 16://16-bit seems to be 15-bit /* db = ((*(uint16_t *)(vram + bpp*pos))&0x1f)<<3; dg = ((*(uint16_t *)(vram + bpp*pos))&0x07e0)>>3; dr = ((*(uint16_t *)(vram + bpp*pos))&0xf800)>>8; break; */ case 15: db = ((*(uint16_t *)(vram + bpp*pos))&0x1f)<<3; dg = ((*(uint16_t *)(vram + bpp*pos))&0x03e0)>>2; dr = ((*(uint16_t *)(vram + bpp*pos))&0x7c00)>>7; break; default: return; } dr = (((sr - dr) * a) >> 8) + dr; dg = (((sg - dg) * a) >> 8) + dg; db = (((sb - db) * a) >> 8) + db; switch (VIDEO (depth)) { case 24: *(uint32_t *)(vram + bpp*pos) = (*(uint32_t *)(vram + bpp*pos) &0xff000000) | (db&0xff) | ((dg&0xff)<<8) | ((dr&0xff)<<16); break; case 16: // *(uint16_t *)(vram + bpp*pos) = ((db&0xf8)>>3) | ((dg&0xfc)<<3) | ((dr&0xf8)<<8); // break; case 15: *(uint16_t *)(vram + bpp*pos) = ((db&0xf8)>>3) | ((dg&0xf8)<<2) | ((dr&0xf8)<<7); break; } } } break; } vram += VIDEO(rowBytes); data += width * 4; } } //============================================================================== // ProgressBar void drawCheckerBoard() { uint32_t *vram = (uint32_t *) VIDEO(baseAddr); uint16_t x, y; uint8_t color; for (y = 0; y < VIDEO(height); y++, vram += VIDEO(width)) { for (x = 0; x < VIDEO(width); x++) { color = 204 + 51 * (((x / 8) % 2) == ((y / 8) % 2)); vram[x] = (color << 16) | (color << 8) | color; } } } //========================================================================== // LookUpCLUTIndex unsigned long lookUpCLUTIndex( unsigned char index ) { long colorIndex = (index * 3); long red; long green; long blue; if ( ( MacOSVerCurrent >= MacOSVer2Int("10.10") ) && ( FlagBlackOption ) ) // Yosemite and Up! { // BlackMode red = AppleLogoBlackClut[ colorIndex ]; green = AppleLogoBlackClut[ colorIndex++ ]; blue = AppleLogoBlackClut[ colorIndex++ ]; } else { red = AppleLogoClut[ colorIndex ]; green = AppleLogoClut[ colorIndex++ ]; blue = AppleLogoClut[ colorIndex++ ]; } return (red << 16) | (green << 8) | blue; } //========================================================================== void *stosl(void *dst, long val, long len) { asm volatile ( "rep; stosl" : "=c" (len), "=D" (dst) : "0" (len), "1" (dst), "a" (val) : "memory" ); return dst; } //============================================================================== void setBackgroundColor( uint32_t color ) { long pixelBytes = VIDEO(depth) / 8; char *vram = (char *) VIDEO(baseAddr) + VIDEO(rowBytes) + pixelBytes; int width = VIDEO(width); int height = VIDEO(height); int rem = ( pixelBytes * width ) % 4; int length = pixelBytes * width / 4; bcopy( &color, vram, rem ); while ( height-- ) { stosl( vram + rem, color, length ); vram += VIDEO(rowBytes); } } //========================================================================== // drawDataRectangle void drawDataRectangle( unsigned short x, unsigned short y, unsigned short width, unsigned short height, unsigned char *data ) { unsigned short drawWidth; long pixelBytes = VIDEO(depth) / 8; unsigned char * vram = (unsigned char *) VIDEO(baseAddr) + VIDEO(rowBytes) * y + pixelBytes * x; drawWidth = MIN(width, VIDEO(width) - x); height = MIN(height, VIDEO(height) - y); while ( height-- ) { bcopy( data, vram, width * pixelBytes ); vram += VIDEO(rowBytes); data += width * pixelBytes; } } //============================================================================== void loadImageScale (void *input, int iw, int ih, int ip, void *output, int ow, int oh, int op, int or) { int x, y, off; int red = 0x7f, green = 0x7f, blue = 0x7f; for ( x = 0; x < ow; x++) for ( y = 0; y < oh; y++ ) { off = ( x * iw ) / ow +( ( y * ih ) / oh ) * iw; switch (ip) { case 16: { uint16_t val; val=((uint16_t *)input)[off]; red=(val>>7)&0xf8; green=(val>>2)&0xf8; blue=(val<<3)&0xf8; break; } case 32: { uint32_t val; val=((uint32_t *)input)[off]; red=(val>>16)&0xff; green=(val>>8)&0xff; blue=(val)&0xff; break; } } char *ptr=(char *)output+x*(op/8)+y*or; switch (op) { case 16: *((uint16_t *)ptr) = ((red & 0xF8) << 7) | ((green & 0xF8) << 2) | ((blue & 0xF8) >> 3); break; case 32 : *((uint32_t *)ptr) = (red << 16) | (green << 8) | blue; break; } } } //============================================================================== DECLARE_IOHIBERNATEPROGRESSALPHA void drawPreview(void *src, uint8_t *saveunder) { uint8_t *screen; uint32_t rowBytes, pixelShift; uint32_t x, y; int32_t blob; uint32_t alpha, in, color, result; uint8_t *out; void *uncomp; int origwidth, origheight, origbpx; uint32_t saveindex[kIOHibernateProgressCount] = { 0 }; if (src && (uncomp=DecompressData(src, &origwidth, &origheight, &origbpx))) { if (!setVESAGraphicsMode(origwidth, origheight, origbpx, 0)) if (initGraphicsMode () != errSuccess) { return; } screen = (uint8_t *) VIDEO (baseAddr); rowBytes = VIDEO (rowBytes); loadImageScale (uncomp, origwidth, origheight, origbpx, screen, VIDEO(width), VIDEO(height), VIDEO(depth), VIDEO (rowBytes)); } else { if (initGraphicsMode () != errSuccess) { return; } screen = (uint8_t *) VIDEO (baseAddr); rowBytes = VIDEO (rowBytes); if ( ( MacOSVerCurrent >= MacOSVer2Int("10.10") ) && ( FlagBlackOption ) ) // Yosemite and Up! { // BlackMode setBackgroundColor(0xff000000); } else { // Set the screen to 75% grey. setBackgroundColor(0xffbfbfbf); } } pixelShift = VIDEO (depth) >> 4; if (pixelShift < 1) { return; } screen += ((VIDEO (width) - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1)) + (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes; for (y = 0; y < kIOHibernateProgressHeight; y++) { out = screen + y * rowBytes; for (blob = 0; blob < kIOHibernateProgressCount; blob++) { color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray; for (x = 0; x < kIOHibernateProgressWidth; x++) { alpha = gIOHibernateProgressAlpha[y][x]; result = color; if (alpha) { if (0xff != alpha) { if (1 == pixelShift) { in = *((uint16_t *)out) & 0x1f; // 16 in = (in << 3) | (in >> 2); } else { in = *((uint32_t *)out) & 0xff; // 32 } saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in; result = ((255 - alpha) * in + alpha * result + 0xff) >> 8; } if (1 == pixelShift) { result >>= 3; *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16 } else { *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32 } } out += (1 << pixelShift); } out += (kIOHibernateProgressSpacing << pixelShift); } } } //============================================================================== void updateProgressBar(uint8_t *saveunder, int32_t firstBlob, int32_t select) { uint8_t *screen; uint32_t rowBytes, pixelShift; uint32_t x, y; int32_t blob, lastBlob; uint32_t alpha, in, color, result; uint8_t *out; uint32_t saveindex[kIOHibernateProgressCount] = { 0 }; pixelShift = VIDEO(depth) >> 4; if (pixelShift < 1) return; screen = (uint8_t *) VIDEO (baseAddr); rowBytes = VIDEO (rowBytes); screen += ((VIDEO (width) - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1)) + (VIDEO (height) - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes; lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1); screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift; for (y = 0; y < kIOHibernateProgressHeight; y++) { out = screen + y * rowBytes; for (blob = firstBlob; blob <= lastBlob; blob++) { color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray; for (x = 0; x < kIOHibernateProgressWidth; x++) { alpha = gIOHibernateProgressAlpha[y][x]; result = color; if (alpha) { if (0xff != alpha) { in = saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++]; result = ((255 - alpha) * in + alpha * result + 0xff) / 255; } if (1 == pixelShift) { result >>= 3; *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16 } else { *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32 } } out += (1 << pixelShift); } out += (kIOHibernateProgressSpacing << pixelShift); } } } //========================================================================== // setVESATextMode static int setVESATextMode( unsigned short cols, unsigned short rows, unsigned char bitsPerPixel ) { VBEModeInfoBlock minfo; unsigned short mode = modeEndOfList; if ( (cols != 80) || (rows != 25) ) // not 80x25 mode { mode = getVESAModeWithProperties( cols, rows, bitsPerPixel, maColorModeBit | maModeIsSupportedBit, maGraphicsModeBit, &minfo, NULL ); } if ( ( mode == modeEndOfList ) || ( setVBEMode(mode, NULL) != errSuccess ) ) { video_mode( 2 ); // VGA BIOS, 80x25 text mode. minfo.XResolution = 80; minfo.YResolution = 25; } // Update KernBootStruct using info provided by the selected // VESA mode. bootArgs->Video.v_display = VGA_TEXT_MODE; bootArgs->Video.v_baseAddr = 0xb8000; bootArgs->Video.v_width = minfo.XResolution; bootArgs->Video.v_height = minfo.YResolution; bootArgs->Video.v_depth = 8; bootArgs->Video.v_rowBytes = 0x8000; return errSuccess; // always return success } //========================================================================== // getNumberArrayFromProperty static int getNumberArrayFromProperty( const char *propKey, unsigned long numbers[], unsigned long maxArrayCount ) { char *propStr; unsigned long count = 0; propStr = newStringForKey((char *)propKey , &bootInfo->chameleonConfig); if (propStr) { char *delimiter = propStr; char *p = propStr; while ((count < maxArrayCount) && (*p != '\0')) { unsigned long val = strtoul(p, &delimiter, 10); if (p != delimiter) { numbers[count++] = val; p = delimiter; } while ((*p != '\0') && !isdigit(*p)) p++; } free(propStr); } return count; } //============================================================================== int initGraphicsMode () { unsigned long params[4]; int count; params[3] = 0; count = getNumberArrayFromProperty( kGraphicsModeKey, params, 4 ); // Try to find a resolution if "Graphics Mode" setting is not available. if ( count < 3 ) { // Use the default resolution if we don't have an initialized GUI. if (gui.screen.width == 0 || gui.screen.height == 0) { gui.screen.width = DEFAULT_SCREEN_WIDTH; gui.screen.height = DEFAULT_SCREEN_HEIGHT; } params[0] = gui.screen.width; params[1] = gui.screen.height; params[2] = 32; } // Map from pixel format to bits per pixel. if ( params[2] == 256 ) params[2] = 8; if ( params[2] == 555 ) params[2] = 16; if ( params[2] == 888 ) params[2] = 32; return setVESAGraphicsMode( params[0], params[1], params[2], params[3] ); } //========================================================================== // setVideoMode // // Set the video mode to VGA_TEXT_MODE or GRAPHICS_MODE. void setVideoMode( int mode ) { unsigned long params[4]; int err = errSuccess; if ( mode == GRAPHICS_MODE ) { if ( (err = initGraphicsMode()) == errSuccess ) { // Tell the kernel to use text mode on a linear frame buffer display bootArgs->Video.v_display = (gVerboseMode) ? /* 2 */ FB_TEXT_MODE : /* 1 */ GRAPHICS_MODE; } } if ( (mode == VGA_TEXT_MODE) || (err != errSuccess) ) { params[0] = 80; // Default text mode is 80x25. params[1] = 25; setVESATextMode(params[0], params[1], 4); bootArgs->Video.v_display = VGA_TEXT_MODE; } } //============================================================================== void getGraphicModeParams(unsigned long params[]) { params[3] = 0; VBEModeInfoBlock minfo; unsigned short vesaVersion; unsigned short mode = modeEndOfList; getNumberArrayFromProperty(kGraphicsModeKey, params, 4); mode = getVESAModeWithProperties(params[0], params[1], params[2], maColorModeBit | maModeIsSupportedBit | maGraphicsModeBit | maLinearFrameBufferAvailBit, 0, &minfo, &vesaVersion); params[0] = minfo.XResolution; params[1] = minfo.YResolution; params[2] = 32; } //========================================================================== // Return the current video mode, VGA_TEXT_MODE or GRAPHICS_MODE. int getVideoMode(void) { return bootArgs->Video.v_display; } //========================================================================== // Display and clear the activity indicator. // BASIC Indicator static char indicator[] = {'-', '\\', '|', '/', '\0'}; // To prevent a ridiculously fast-spinning indicator, // ensure a minimum of 1/9 sec between animation frames. #define MIN_TICKS 2 //============================================================================== void spinActivityIndicator(int sectors) { static unsigned long lastTickTime = 0, currentTickTime; if (previewTotalSectors && previewSaveunder) { int blob, lastBlob; lastBlob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors; previewLoadedSectors+=sectors; blob = (previewLoadedSectors * kIOHibernateProgressCount) / previewTotalSectors; if (blob!=lastBlob) { updateProgressBar (previewSaveunder, lastBlob, blob); } return; } currentTickTime = time18(); // late binding if (currentTickTime < lastTickTime + MIN_TICKS) { return; } else { lastTickTime = currentTickTime; } if (getVideoMode() == VGA_TEXT_MODE) { if (currentIndicator >= sizeof(indicator)) { currentIndicator = 0; } putchar(indicator[currentIndicator++]); putchar('\b'); } } //============================================================================== void clearActivityIndicator( void ) { if ( getVideoMode() == VGA_TEXT_MODE ) { putchar(' '); putchar('\b'); } } //==============================================================================