/*
 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * 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.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

#include <vc.h>

#include <console/video_console.h>
#include <kdp/kdp_udp.h>
#include <kern/debug.h>

#include "panic_image.c"
#include "rendered_numbers.c"

extern struct vc_info vinfo;
extern boolean_t panicDialogDesired;

/* panic image clut */
static const unsigned char *clut = NULL;
extern void panic_ui_initialize(const unsigned char * system_clut);

/* We use this standard MacOS clut as a fallback */
static const unsigned char appleClut8[ 256 * 3 ] = { 
// 00
	0xFF,0xFF,0xFF, 0xFF,0xFF,0xCC,	0xFF,0xFF,0x99,	0xFF,0xFF,0x66,
	0xFF,0xFF,0x33, 0xFF,0xFF,0x00,	0xFF,0xCC,0xFF,	0xFF,0xCC,0xCC,
	0xFF,0xCC,0x99, 0xFF,0xCC,0x66,	0xFF,0xCC,0x33,	0xFF,0xCC,0x00,
	0xFF,0x99,0xFF, 0xFF,0x99,0xCC,	0xFF,0x99,0x99,	0xFF,0x99,0x66,
// 10
	0xFF,0x99,0x33, 0xFF,0x99,0x00,	0xFF,0x66,0xFF,	0xFF,0x66,0xCC,
	0xFF,0x66,0x99, 0xFF,0x66,0x66,	0xFF,0x66,0x33,	0xFF,0x66,0x00,
	0xFF,0x33,0xFF, 0xFF,0x33,0xCC,	0xFF,0x33,0x99,	0xFF,0x33,0x66,
	0xFF,0x33,0x33, 0xFF,0x33,0x00,	0xFF,0x00,0xFF,	0xFF,0x00,0xCC,
// 20
	0xFF,0x00,0x99, 0xFF,0x00,0x66,	0xFF,0x00,0x33,	0xFF,0x00,0x00,
	0xCC,0xFF,0xFF, 0xCC,0xFF,0xCC,	0xCC,0xFF,0x99,	0xCC,0xFF,0x66,
	0xCC,0xFF,0x33, 0xCC,0xFF,0x00,	0xCC,0xCC,0xFF,	0xCC,0xCC,0xCC,
	0xCC,0xCC,0x99, 0xCC,0xCC,0x66,	0xCC,0xCC,0x33,	0xCC,0xCC,0x00,
// 30
	0xCC,0x99,0xFF, 0xCC,0x99,0xCC,	0xCC,0x99,0x99,	0xCC,0x99,0x66,
	0xCC,0x99,0x33, 0xCC,0x99,0x00,	0xCC,0x66,0xFF,	0xCC,0x66,0xCC,
	0xCC,0x66,0x99, 0xCC,0x66,0x66,	0xCC,0x66,0x33,	0xCC,0x66,0x00,
	0xCC,0x33,0xFF, 0xCC,0x33,0xCC,	0xCC,0x33,0x99,	0xCC,0x33,0x66,
// 40
	0xCC,0x33,0x33, 0xCC,0x33,0x00,	0xCC,0x00,0xFF,	0xCC,0x00,0xCC,
	0xCC,0x00,0x99, 0xCC,0x00,0x66,	0xCC,0x00,0x33,	0xCC,0x00,0x00,
	0x99,0xFF,0xFF, 0x99,0xFF,0xCC,	0x99,0xFF,0x99,	0x99,0xFF,0x66,
	0x99,0xFF,0x33, 0x99,0xFF,0x00,	0x99,0xCC,0xFF,	0x99,0xCC,0xCC,
// 50
	0x99,0xCC,0x99, 0x99,0xCC,0x66,	0x99,0xCC,0x33,	0x99,0xCC,0x00,
	0x99,0x99,0xFF, 0x99,0x99,0xCC,	0x99,0x99,0x99,	0x99,0x99,0x66,
	0x99,0x99,0x33, 0x99,0x99,0x00,	0x99,0x66,0xFF,	0x99,0x66,0xCC,
	0x99,0x66,0x99, 0x99,0x66,0x66,	0x99,0x66,0x33,	0x99,0x66,0x00,
// 60
	0x99,0x33,0xFF, 0x99,0x33,0xCC,	0x99,0x33,0x99,	0x99,0x33,0x66,
	0x99,0x33,0x33, 0x99,0x33,0x00,	0x99,0x00,0xFF,	0x99,0x00,0xCC,
	0x99,0x00,0x99, 0x99,0x00,0x66,	0x99,0x00,0x33,	0x99,0x00,0x00,
	0x66,0xFF,0xFF, 0x66,0xFF,0xCC,	0x66,0xFF,0x99,	0x66,0xFF,0x66,
// 70
	0x66,0xFF,0x33, 0x66,0xFF,0x00,	0x66,0xCC,0xFF,	0x66,0xCC,0xCC,
	0x66,0xCC,0x99, 0x66,0xCC,0x66,	0x66,0xCC,0x33,	0x66,0xCC,0x00,
	0x66,0x99,0xFF, 0x66,0x99,0xCC,	0x66,0x99,0x99,	0x66,0x99,0x66,
	0x66,0x99,0x33, 0x66,0x99,0x00,	0x66,0x66,0xFF,	0x66,0x66,0xCC,
// 80
	0x66,0x66,0x99, 0x66,0x66,0x66,	0x66,0x66,0x33,	0x66,0x66,0x00,
	0x66,0x33,0xFF, 0x66,0x33,0xCC,	0x66,0x33,0x99,	0x66,0x33,0x66,
	0x66,0x33,0x33, 0x66,0x33,0x00,	0x66,0x00,0xFF,	0x66,0x00,0xCC,
	0x66,0x00,0x99, 0x66,0x00,0x66,	0x66,0x00,0x33,	0x66,0x00,0x00,
// 90
	0x33,0xFF,0xFF, 0x33,0xFF,0xCC,	0x33,0xFF,0x99,	0x33,0xFF,0x66,
	0x33,0xFF,0x33, 0x33,0xFF,0x00,	0x33,0xCC,0xFF,	0x33,0xCC,0xCC,
	0x33,0xCC,0x99, 0x33,0xCC,0x66,	0x33,0xCC,0x33,	0x33,0xCC,0x00,
	0x33,0x99,0xFF, 0x33,0x99,0xCC,	0x33,0x99,0x99,	0x33,0x99,0x66,
// a0
	0x33,0x99,0x33, 0x33,0x99,0x00,	0x33,0x66,0xFF,	0x33,0x66,0xCC,
	0x33,0x66,0x99, 0x33,0x66,0x66,	0x33,0x66,0x33,	0x33,0x66,0x00,
	0x33,0x33,0xFF, 0x33,0x33,0xCC,	0x33,0x33,0x99,	0x33,0x33,0x66,
	0x33,0x33,0x33, 0x33,0x33,0x00,	0x33,0x00,0xFF,	0x33,0x00,0xCC,
// b0
	0x33,0x00,0x99, 0x33,0x00,0x66,	0x33,0x00,0x33,	0x33,0x00,0x00,
	0x00,0xFF,0xFF, 0x00,0xFF,0xCC,	0x00,0xFF,0x99,	0x00,0xFF,0x66,
	0x00,0xFF,0x33, 0x00,0xFF,0x00,	0x00,0xCC,0xFF,	0x00,0xCC,0xCC,
	0x00,0xCC,0x99, 0x00,0xCC,0x66,	0x00,0xCC,0x33,	0x00,0xCC,0x00,
// c0
	0x00,0x99,0xFF, 0x00,0x99,0xCC,	0x00,0x99,0x99,	0x00,0x99,0x66,
	0x00,0x99,0x33, 0x00,0x99,0x00,	0x00,0x66,0xFF,	0x00,0x66,0xCC,
	0x00,0x66,0x99, 0x00,0x66,0x66,	0x00,0x66,0x33,	0x00,0x66,0x00,
	0x00,0x33,0xFF, 0x00,0x33,0xCC,	0x00,0x33,0x99,	0x00,0x33,0x66,
// d0
	0x00,0x33,0x33, 0x00,0x33,0x00,	0x00,0x00,0xFF,	0x00,0x00,0xCC,
	0x00,0x00,0x99, 0x00,0x00,0x66,	0x00,0x00,0x33,	0xEE,0x00,0x00,
	0xDD,0x00,0x00, 0xBB,0x00,0x00,	0xAA,0x00,0x00,	0x88,0x00,0x00,
	0x77,0x00,0x00, 0x55,0x00,0x00,	0x44,0x00,0x00,	0x22,0x00,0x00,
// e0
	0x11,0x00,0x00, 0x00,0xEE,0x00,	0x00,0xDD,0x00,	0x00,0xBB,0x00,
	0x00,0xAA,0x00, 0x00,0x88,0x00,	0x00,0x77,0x00,	0x00,0x55,0x00,
	0x00,0x44,0x00, 0x00,0x22,0x00,	0x00,0x11,0x00,	0x00,0x00,0xEE,
	0x00,0x00,0xDD, 0x00,0x00,0xBB,	0x00,0x00,0xAA,	0x00,0x00,0x88,
// f0
	0x00,0x00,0x77, 0x00,0x00,0x55,	0x00,0x00,0x44,	0x00,0x00,0x22,
	0x00,0x00,0x11, 0xEE,0xEE,0xEE,	0xDD,0xDD,0xDD,	0xBB,0xBB,0xBB,
	0xAA,0xAA,0xAA, 0x88,0x88,0x88,	0x77,0x77,0x77,	0x55,0x55,0x55,
	0x44,0x44,0x44, 0x22,0x22,0x22,	0x11,0x11,0x11,	0x00,0x00,0x00
};


/* panic dialog and info saving */
static int mac_addr_digit_x;
static int mac_addr_digit_y;
static void blit_digit( int digit );
static boolean_t panicDialogDrawn = FALSE;

static void 
panic_blit_rect(	unsigned int x, unsigned int y,
			unsigned int width, unsigned int height,
			int transparent, unsigned char * dataPtr );
			
static void 
panic_blit_rect_8(	unsigned int x, unsigned int y,
			unsigned int width, unsigned int height,
			int transparent, unsigned char * dataPtr );
			
static void 
panic_blit_rect_16(	unsigned int x, unsigned int y,
			unsigned int width, unsigned int height,
			int transparent, unsigned char * dataPtr );
			
static void 
panic_blit_rect_32(	unsigned int x, unsigned int y,
			unsigned int width, unsigned int height,
			int transparent, unsigned char * dataPtr );

static void 
dim_screen(void);

static void 
dim_screen_16(void);

static void 
dim_screen_32(void);

static int 
decode_rle( unsigned char * dataPtr, unsigned int * quantity, unsigned int * value );

void 
panic_ui_initialize(const unsigned char * system_clut)
{
	clut = system_clut;
}

void 
draw_panic_dialog( void )
{
	int pd_x,pd_y, iconx, icony, tx_line, tx_col;
	int line_width = 1;
	int f1, f2, d1, d2, d3, rem;
	char *pair = "ff";
	int count = 0;
	char digit;
	int nibble;
	char colon = ':';
	char dot = '.';
	struct ether_addr kdp_mac_addr  = kdp_get_mac_addr();
	unsigned int ip_addr = (unsigned int) ntohl(kdp_get_ip_address());

	if (!panicDialogDrawn && panicDialogDesired)
	{
		if ( !logPanicDataToScreen )
		{

			/* dim the screen 50% before putting up panic dialog */
		  	dim_screen();

			/* set up to draw background box */
			pd_x = (vinfo.v_width/2) - panic_dialog.pd_width/2;
			pd_y = (vinfo.v_height/2) - panic_dialog.pd_height/2;
		
			/*  draw image	*/
			panic_blit_rect( pd_x, pd_y, panic_dialog.pd_width, panic_dialog.pd_height, 0, (unsigned char*) panic_dialog.image_pixel_data);
		
			/* do not display the mac and ip addresses if the machine isn't attachable. */
			/* there's no sense in possibly confusing people. */
			if (panicDebugging)
			{
		
				/* offset for mac address text */
				mac_addr_digit_x = (vinfo.v_width/2) - 130; /* use 62 if no ip */
				mac_addr_digit_y = (vinfo.v_height/2) + panic_dialog.pd_height/2 - 20;
		
				if(kdp_mac_addr.ether_addr_octet[0] || kdp_mac_addr.ether_addr_octet[1]|| kdp_mac_addr.ether_addr_octet[2]
					|| kdp_mac_addr.ether_addr_octet[3] || kdp_mac_addr.ether_addr_octet[4] || kdp_mac_addr.ether_addr_octet[5])
				{
					/* blit the digits for mac address */
					for (count = 0; count < 6; count++ )
					{
						nibble =  (kdp_mac_addr.ether_addr_octet[count] & 0xf0) >> 4;
						digit = nibble < 10 ? nibble + '0':nibble - 10 + 'a';
						blit_digit(digit);
				
						nibble =  kdp_mac_addr.ether_addr_octet[count] & 0xf;
						digit = nibble < 10 ? nibble + '0':nibble - 10 + 'a';
						blit_digit(digit);
						if( count < 5 )
							blit_digit( colon );
					}
				}
				else	/* blit the ff's */
				{
					for( count = 0; count < 6; count++ )
					{
						digit = pair[0];
						blit_digit(digit);
						digit = pair[1];
						blit_digit(digit);
						if( count < 5 )
							blit_digit( colon );
					}
				}
				/* now print the ip address */
				mac_addr_digit_x = (vinfo.v_width/2) + 10;
				if(ip_addr != 0)
				{
					/* blit the digits for ip address */
					for (count = 0; count < 4; count++ )
					{
						nibble = (ip_addr & 0xff000000 ) >> 24;
				
						d3 = (nibble % 0xa) + '0';
						nibble = nibble/0xa;
						d2 = (nibble % 0xa) + '0';
						nibble = nibble /0xa;
						d1 = (nibble % 0xa) + '0';
					
						if( d1 != '0' ) blit_digit(d1);
						blit_digit(d2);
						blit_digit(d3);
						if( count < 3 )
							blit_digit(dot);
					
						d1= d2 = d3 = 0;
						ip_addr = ip_addr << 8;
					}
				}
			}
		}
	}
	panicDialogDrawn = TRUE;
	panicDialogDesired = FALSE;

}

static void 
blit_digit( int digit )
{
	switch( digit )
	{
		case '0':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_0.num_w, num_0.num_h, 255, (unsigned char*) num_0.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_0.num_w - 1;
			break;
		}
		case '1':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_1.num_w, num_1.num_h, 255, (unsigned char*) num_1.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_1.num_w ;
			break;
		}
		case '2':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_2.num_w, num_2.num_h, 255, (unsigned char*) num_2.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_2.num_w ;
			break;
		}
		case '3':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_3.num_w, num_3.num_h, 255, (unsigned char*) num_3.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_3.num_w ;
			break;
		}
		case '4':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_4.num_w, num_4.num_h, 255, (unsigned char*) num_4.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_4.num_w ;
			break;
		}
		case '5':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_5.num_w, num_5.num_h, 255, (unsigned char*) num_5.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_5.num_w ;
			break;
		}
		case '6':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_6.num_w, num_6.num_h, 255, (unsigned char*) num_6.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_6.num_w ;
			break;
		}
		case '7':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_7.num_w, num_7.num_h, 255, (unsigned char*) num_7.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_7.num_w ;
			break;
		}
		case '8':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_8.num_w, num_8.num_h, 255, (unsigned char*) num_8.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_8.num_w ;
			break;
		}
		case '9':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_9.num_w, num_9.num_h, 255, (unsigned char*) num_9.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_9.num_w ;
			break;
		}
		case 'a':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_a.num_w, num_a.num_h, 255, (unsigned char*) num_a.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_a.num_w ;
			break;
		}
		case 'b':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_b.num_w, num_b.num_h, 255, (unsigned char*) num_b.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_b.num_w ;
			break;
		}
		case 'c':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_c.num_w, num_c.num_h, 255, (unsigned char*) num_c.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_c.num_w ;
			break;
		}
		case 'd':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_d.num_w, num_d.num_h, 255, (unsigned char*) num_d.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_d.num_w ;
			break;
		}
		case 'e':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_e.num_w, num_e.num_h, 255, (unsigned char*) num_e.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_e.num_w ;
			break;
		}
		case 'f':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_f.num_w, num_f.num_h, 255, (unsigned char*) num_f.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_f.num_w ;
			break;
		}
		case ':':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y, num_colon.num_w, num_colon.num_h, 255, (unsigned char*) num_colon.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_colon.num_w;
			break;
		}
		case '.':  {
			panic_blit_rect( mac_addr_digit_x, mac_addr_digit_y + (num_colon.num_h/2), num_colon.num_w, num_colon.num_h/2, 255, (unsigned char*) num_colon.num_pixel_data);
			mac_addr_digit_x = mac_addr_digit_x + num_colon.num_w;
			break;
		}
		default:
			break;
	
	}
}

static void 
panic_blit_rect(	unsigned int x, unsigned int y,
			unsigned int width, unsigned int height,
			int transparent, unsigned char * dataPtr )
{
	if(!vinfo.v_depth)
		return;
		
    switch( vinfo.v_depth) {
	case 8:
	    panic_blit_rect_8( x, y, width, height, transparent, dataPtr);
	    break;
	case 16:
	    panic_blit_rect_16( x, y, width, height, transparent, dataPtr);
	    break;
	case 32:
	    panic_blit_rect_32( x, y, width, height, transparent, dataPtr);
	    break;
    }
}

/* 	panic_blit_rect_8 uses the built in clut for drawing.

*/
static void 
panic_blit_rect_8(	unsigned int x, unsigned int y,
			unsigned int width, unsigned int height,
			int transparent, unsigned char * dataPtr )
{
	volatile unsigned char * dst;
	int line, col;
	unsigned int data, quantity, value;
	
	dst = (volatile unsigned char *) (vinfo.v_baseaddr +
					  (y * vinfo.v_rowbytes) +
					  x);
	
	quantity = 0;
	
	for( line = 0; line < height; line++) {
		for( col = 0; col < width; col++) {
			if (quantity == 0) {
				dataPtr += decode_rle(dataPtr, &quantity, &value);
			}
			
			data = value;
			*(dst + col) = data;
			quantity--;
		}
		
		dst = (volatile unsigned char *) (((int)dst) + vinfo.v_rowbytes);
	}
}

/* 	panic_blit_rect_16 draws using a clut.
	
        panic_blit_rect_16 decodes the RLE encoded image data on the fly, looks up the
	color by indexing into the clut, uses the top 5 bits to fill in each of the three 
	pixel values (RGB) and writes each pixel to the screen.
*/
 static void 
 panic_blit_rect_16(	unsigned int x, unsigned int y,
			 unsigned int width, unsigned int height,
			 int transparent, unsigned char * dataPtr )
 {
	 volatile unsigned short * dst;
	 int line, col;
	 unsigned int  quantity, index, value, data;

	 /* If our clut has disappeared, use the standard MacOS 8-bit clut */
	 if(!clut) {
		 clut = appleClut8; 
	 }

	 dst = (volatile unsigned short *) (vinfo.v_baseaddr +
					    (y * vinfo.v_rowbytes) +
					    (x * 2));

	 quantity = 0;

	 for( line = 0; line < height; line++) {
		 for( col = 0; col < width; col++) {

			 if (quantity == 0) {
				 dataPtr += decode_rle(dataPtr, &quantity, &value);
				 index = value * 3;
			 }

			 data = ( (unsigned short) (0xf8 & (clut[index + 0])) << 7)
				 | ( (unsigned short) (0xf8 & (clut[index + 1])) << 2)
				 | ( (unsigned short) (0xf8 & (clut[index + 2])) >> 3);

			 *(dst + col) = data;
			 quantity--;
		 }

		 dst = (volatile unsigned short *) (((int)dst) + vinfo.v_rowbytes);
	 }

 }

 /*
	 panic_blit_rect_32 decodes the RLE encoded image data on the fly, and fills
	 in each of the three pixel values from the clut (RGB) for each pixel and 
	 writes it to the screen.
 */	
 static void 
 panic_blit_rect_32(	unsigned int x, unsigned int y,
			 unsigned int width, unsigned int height,
			 int transparent, unsigned char * dataPtr )
 {
	 volatile unsigned int * dst;
	 int line, col;
	 unsigned int value, quantity, index, data;


	/* If our clut has disappeared, use the standard MacOS 8-bit clut */
	if(!clut) {
		clut = appleClut8; 
	}

	dst = (volatile unsigned int *) (vinfo.v_baseaddr +
					 (y * vinfo.v_rowbytes) +
					 (x * 4));
	
	quantity = 0;
	
	for( line = 0; line < height; line++) {
		for( col = 0; col < width; col++) {
			if (quantity == 0) {
				dataPtr += decode_rle(dataPtr, &quantity, &value);
				index = value * 3;
			}
			
			data = ( (unsigned int) clut[index + 0] << 16)
				| ( (unsigned int) clut[index + 1] << 8)
				| ( (unsigned int) clut[index + 2]);
			
			*(dst + col) = data;
			quantity--;
		}
		
		dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes);
	}
}

/* 	
        decode_rle decodes a single quantity/value pair of a "modified-RLE" encoded
        image. The encoding works as follows:
        
        The quantity and value will be described by either two or three bytes. If the
        most significant bit of the first byte is a 0, then the next seven bits are
        the quantity (run-length) and the following 8 bits are the value (index into
        a clut, in this case). If the msb of the first byte is a 1, then the next 15 bits
        are the quantity and the following 8 are the value. Visually, the two possible
        encodings are: (q = quantity, v = value)
        
          Byte 1			   Byte 2		        Byte 3
  case 1: [ 0 q6 q5 q4 q3 q2 q1 q0 ]       [ v7 v6 v5 v4 v3 v2 v1 v0 ]  [ ]
  case 2: [ 1 q14 q13 q12 a11 q10 q9 q8 ]  [ q7 q6 q5 q4 q3 q2 q1 q0 ]  [ v7 v6 v5 v4 v3 v2 v1 v0 ]
*/
static int
decode_rle( unsigned char * dataPtr, unsigned int * quantity, unsigned int * value )
{
	unsigned char byte1 = *dataPtr++;
	unsigned char byte2 = *dataPtr++;
	int num_slots = 0;
	
	/* if the most-significant bit is 0, then the first byte is quanity, the second is value */
	if ((byte1 >> 7) ==  0) {
		*quantity = (unsigned int) byte1;
		*value = (unsigned int) byte2;
		num_slots = 2;
	} else {
		/* clear the leading 1 */
		byte1 ^= 0x80;
		
		/* the first two bytes are the quantity, the third is value */
		*quantity = (unsigned int) byte1 << 8 | byte2;
		*value = *dataPtr++;
		num_slots = 3;
	}
	
	return num_slots;
}

static void 
dim_screen(void)
{
	if(!vinfo.v_depth)
		return;

    switch( vinfo.v_depth) {
	case 16:
	    dim_screen_16();
	    break;
	case 32:
	    dim_screen_32();
	    break;
    }
}

static void 
dim_screen_16(void)
{
	unsigned long *p, *endp, *row;
	int      col;
	int      rowline, rowlongs;
        unsigned long value, tmp;

	rowline = vinfo.v_rowscanbytes / 4;
	rowlongs = vinfo.v_rowbytes / 4;

	p = (unsigned long*) vinfo.v_baseaddr;
	endp = (unsigned long*) vinfo.v_baseaddr;

        endp += rowlongs * vinfo.v_height;

	for (row = p ; row < endp ; row += rowlongs) {
		for (col = 0; col < rowline; col++) {
                        value = *(row+col);
                        tmp =  ((value & 0x7C007C00) >> 1) & 0x3C003C00;
                        tmp |= ((value & 0x03E003E0) >> 1) & 0x01E001E0;
                        tmp |= ((value & 0x001F001F) >> 1) & 0x000F000F;
                        *(row+col) = tmp;		//half (dimmed)?
                }

	}

}

static void 
dim_screen_32(void)
{
	unsigned long *p, *endp, *row;
	int      col;
	int      rowline, rowlongs;
        unsigned long value, tmp;

	rowline = vinfo.v_rowscanbytes / 4;
	rowlongs = vinfo.v_rowbytes / 4;

	p = (unsigned long*) vinfo.v_baseaddr;
	endp = (unsigned long*) vinfo.v_baseaddr;

        endp += rowlongs * vinfo.v_height;

	for (row = p ; row < endp ; row += rowlongs) {
		for (col = 0; col < rowline; col++) {
                        value = *(row+col);
                        tmp =  ((value & 0x00FF0000) >> 1) & 0x007F0000;
                        tmp |= ((value & 0x0000FF00) >> 1) & 0x00007F00;
                        tmp |= (value & 0x000000FF) >> 1;
                        *(row+col) = tmp;		//half (dimmed)?
                }

	}

}
