Source to bsd/dev/ppc/FBConsole.c
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @[email protected]
*
* "Portions Copyright (c) 1999 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 1.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."
*
* @[email protected]
*/
/* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved.
*
* FBConsole.c - FrameBuffer based console implementation.
*
*
* HISTORY
* 01 Sep 92 Joe Pasqua
* Created.
* 25 Mar 97 Simon Douglas
* Rhapsodized.
*/
// TO DO:
// * Implement other cases of FlipCursor, HorizLine, VertLine, ClearWindow.
// Erase
// * Find the #defines for np and del are, then get rid of our #defines.
//
// Notes:
// * This module implements the console functionality required by the
// ConsoleSupport protocol. If you have a device which is a framebuffer
// with a depth supported by this module, then you can use this code.
// * To find things that need to be fixed, search for FIX, to find questions
// to be resolved, search for ASK, to find stuff that still needs to be
// done, search for TO DO.
#define BRINGUP 1
#import <sys/syslog.h>
#import <bsd/dev/ppc/FBConsole.h>
#import <bsd/dev/ppc/FBConsPriv.h>
#import <architecture/ascii_codes.h>
#import "BootImages.h"
#if defined(NOTINKERNEL)
#define panic(str)
#define copyin(src, dst, size) bcopy(src, dst, size)
#define kalloc(size) malloc(size)
#define kfree(ptr, size) free(ptr)
#endif
#ifdef DRIVERKIT
#else
#define IOMalloc(size) kalloc(size)
#define IOFree(ptr,size) kfree(ptr,size)
#define IOLog(s,a) printf(s,a)
#endif // DRIVERKIT
#define TEXTURE_BACKGND 1
/*
* Standard font.
*/
extern char ohlfs12[][];
#import "ohlfs12.h"
#define NIL (0)
/* Window margins */
#define BG_MARGIN 2 // pixels of background to leave as margin
#define FG_MARGIN 1 // pixels of foreground to leave as margin
#define TOTAL_MARGIN (BG_MARGIN + FG_MARGIN)
#define DROP_SHADOW 1 // pixels of dark_grey, bottom & right
#define TS_MARGIN 1 //
#define HORIZ_BORDER 32 // 40 on VGA
#define VERT_BORDER 22 // 30 on VGA
/*
* Ansi sequence state.
*/
typedef enum {
AS_NORMAL,
AS_ESCAPE,
AS_BRACKET,
AS_R
} ansi_state_t;
#define ANSI_STACK_SIZE 3
typedef struct _t_Console {
ScreenMode window_type;
IODisplayInfo display;
//
// The remaining fields are window parameters. These are only
// meaningful for text-type windows (window_type == SCM_TEXT or
// SCM_ALERT).
//
//
// Current window origin in pixels, relative to origin of screen.
//
int window_origin_x;
int window_origin_y;
//
// Window size information, in pixels and in characters.
//
int chars_per_row;
int pixels_per_row;
int chars_per_column;
int pixels_per_column;
//
// Cursor location, in characters. Origin is top
// left corner of window = {0,0}.
//
int curr_row; // in characters
int curr_column; // in characters
//
// Misc. video parameters. The background and foreground fields
// are slightly dependent on the hardware implementation; they'll
// work as long as bits per pixel <= 32.
//
unsigned int background; // bits for background pixel
unsigned int light_grey; // bits for light grey
unsigned int dark_grey; // bits for dark grey
unsigned int foreground; // bits for foreground pixel
unsigned int baseground; // bits for base color
unsigned int grayTable[4]; // bits for drawing bitmaps
boolean_t has_title;
boolean_t prettyPanelUp;
unsigned int bolding; // bold text pixel count
//
// Storage for saved region under an alert panel.
//
unsigned char *saveBits;
int saveHeight;
int saveRowBytes;
int saveBytes;
unsigned char *saveLocation;
ansi_state_t ansi_state; /* track ansi escape sequence state */
u_char ansi_stack[ANSI_STACK_SIZE];
u_char *ansi_stack_p;
} ConsoleRep, *ConsolePtr;
//
// BEGIN: Private utility routines
//
static void videoMemMove( char * dst, char * src, unsigned int len )
{
#if 1
bcopy_nc( src, dst, len );
#else
memmove( dst, src, len );
#endif
}
static unsigned int BPPToPPW(int bpp)
{
if (bpp == IO_2BitsPerPixel) return(16);
if (bpp == IO_8BitsPerPixel) return(4);
if (bpp == IO_12BitsPerPixel) return(2);
if (bpp == IO_15BitsPerPixel) return(2);
if (bpp == IO_24BitsPerPixel) return(1);
else return(-1);
}
static unsigned char *PixelAddress(ConsolePtr console, int xPix, int yPix)
{
switch (console->display.bitsPerPixel) {
case IO_8BitsPerPixel:
return ((unsigned char *)console->display.frameBuffer) +
yPix * console->display.rowBytes + xPix;
case IO_12BitsPerPixel:
case IO_15BitsPerPixel:
return ((unsigned char *)console->display.frameBuffer) +
yPix * console->display.rowBytes + xPix * 2;
case IO_24BitsPerPixel:
return ((unsigned char *)console->display.frameBuffer) +
yPix * console->display.rowBytes + xPix * 4;
default:
panic("FBConsole/PixelAddress: bogus bitsPerPixel");
}
}
static void Fill(ConsolePtr console,
unsigned char *dst, // Where to start filling
unsigned pixel, // pattern to fill
unsigned len) // in pixels
// Descritpion: Fill the framebuffer with 'pixel' starting at dst
// and for 'len' pixels.
{
switch (console->display.bitsPerPixel) {
case IO_8BitsPerPixel:
{
unsigned char *dst8 = (unsigned char *)dst;
for (; len--; dst8++)
*dst8 = pixel;
break;
}
case IO_12BitsPerPixel:
case IO_15BitsPerPixel:
{
unsigned short *dst16 = (unsigned short *)dst;
for (; len--; dst16++)
*dst16 = pixel;
break;
}
case IO_24BitsPerPixel:
{
unsigned int *dst32 = (unsigned int *)dst;
for (; len--; dst32++)
*dst32 = pixel;
break;
}
default:
panic("FBConsole/Fill: bogus bitsPerPixel");
}
}
static void FlipCursor(ConsolePtr console)
// Description: Turn cursor on/off. This just inverts every pixel at the
// character at (curr_rown, curr_column).
{
int y;
unsigned char *dst8;
unsigned short *dst16;
unsigned int *dst32;
unsigned pixel_num;
// Screen-relative pixel coordinates of bounds of current character.
int start_y = console->window_origin_y +
console->curr_row * CHAR_H;
int end_y = start_y + CHAR_H;
int start_x = console->window_origin_x +
console->curr_column * CHAR_W;
for (y=start_y; y < end_y; y++) {
switch (console->display.bitsPerPixel) {
case IO_8BitsPerPixel:
dst8 = (unsigned char *)PixelAddress(console, start_x, y);
for (pixel_num = 0; pixel_num < CHAR_W; pixel_num++) {
if ((*dst8 & PIXEL_MASK_16) ==
(console->background & PIXEL_MASK_16)) {
*dst8 = console->foreground;
}
else {
*dst8 = console->background;
}
dst8++;
}
break;
case IO_12BitsPerPixel:
case IO_15BitsPerPixel:
dst16 = (unsigned short *)PixelAddress(console, start_x, y);
for (pixel_num = 0; pixel_num < CHAR_W; pixel_num++) {
if ((*dst16 & PIXEL_MASK_16) ==
(console->background & PIXEL_MASK_16)) {
*dst16 = console->foreground;
}
else {
*dst16 = console->background;
}
dst16++;
}
break;
case IO_24BitsPerPixel:
dst32 = (unsigned int *)PixelAddress(console, start_x, y);
for (pixel_num = 0; pixel_num < CHAR_W; pixel_num++) {
if ((*dst32 & PIXEL_MASK_32) ==
(console->background & PIXEL_MASK_32)) {
*dst32 = console->foreground;
}
else {
*dst32 = console->background;
}
dst32++;
}
break;
default:
panic("FBConsole/FlipCursor: bogus bits per pixel");
}
}
}
static void SwapForegroundAndBackground(ConsolePtr console)
{
int temp_color;
temp_color = console->foreground;
console->foreground = console->background;
console->background = temp_color;
}
static void Rect(
ConsolePtr console,
int origin_x, int origin_y,
int width, int height,
unsigned pixel)
// Description: Draws a single pixel wide horizontal line
{
while (height--)
Fill(console,
PixelAddress(console, origin_x, origin_y++),
pixel, width);
}
#ifdef notdef
static void HorizLine(
ConsolePtr console,
int origin_x, int origin_y, int length,
unsigned pixel)
// Description: Draws a single pixel wide horizontal line
{
Fill(console, PixelAddress(console, origin_x, origin_y), pixel, length);
}
static void VertLine(
ConsolePtr console,
int origin_x, int origin_y, int length,
unsigned pixel)
// Description: Draws a single pixel wide vertical line
{
unsigned char *dstPixel = PixelAddress(console, origin_x, origin_y);
switch(console->display.bitsPerPixel) {
case IO_8BitsPerPixel:
{
unsigned char *dst = (unsigned char *)dstPixel;
while (length--) {
*dst = pixel;
dst += console->display.totalWidth;
}
}
break;
case IO_12BitsPerPixel:
case IO_15BitsPerPixel:
{
unsigned short *dst = (unsigned short *)dstPixel;
while (length--) {
*dst = pixel;
dst += console->display.totalWidth;
}
}
break;
case IO_24BitsPerPixel:
{
unsigned long *dst = (unsigned long *)dstPixel;
while (length--) {
*dst = pixel;
dst += console->display.totalWidth;
}
}
break;
default:
panic("FBConsole/VertLine: bogus bits per pixel");
}
}
#endif
static void ClearWindow(ConsolePtr console)
// Description: Set contents of entire current window to background.
// Preconditions:
// * Cursor is off on entry and will remain so on exit.
{
int line;
unsigned char *dstPixel = PixelAddress(
console, console->window_origin_x, console->window_origin_y);
for (line=0; line < console->pixels_per_column; line++) {
// One loop per scan line in the window.
Fill(console, dstPixel, console->background,
console->pixels_per_row);
dstPixel += console->display.rowBytes;
}
}
static void WipeScreen(ConsolePtr console, const unsigned pixel)
// Description: Fill the screen with specific pixel value.
{
static int horstArray[5] = { 5,3,2,1,1 };
int i,horst;
Rect( console, 0, 0, console->display.width, console->display.height, pixel );
// Round rect
for( i=0; i < 5; i++) {
horst = horstArray[i];
// top left
Fill(console, PixelAddress(console, 0, i), console->foreground, horst);
// bottom left
Fill(console, PixelAddress(console, 0, console->display.height - i - 1), console->foreground, horst);
// top right
Fill(console, PixelAddress(console, console->display.width - horst, i), console->foreground, horst);
// bottom right
Fill(console, PixelAddress(console, console->display.width - horst, console->display.height - i - 1),
console->foreground, horst);
}
}
static void ClearToEOL(ConsolePtr console)
// Description: Clear to end of line (within window), including current pos.
// Preconditions:
// * Cursor is 'off' on entry and will remain so on exit.
{
unsigned pixel_count;
int starting_x; // window-relative 'x' coordinate
int y;
int line;
starting_x = console->window_origin_x +
(console->curr_column * CHAR_W);
y = console->window_origin_y + (console->curr_row * CHAR_H);
pixel_count = console->pixels_per_row -
(starting_x - console->window_origin_x);
for (line=0; line < CHAR_H; line++) {
// One loop per scan line in the row.
Fill(
console, PixelAddress(console, starting_x, y++),
console->background, pixel_count);
}
}
static void Erase(ConsolePtr console)
// Description: Erase current cursor location.
{
int y;
unsigned char *dst8;
unsigned short *dst16;
unsigned int *dst32;
int x;
// Screen-relative pixel coordinates of bounds of current character.
int start_y = console->window_origin_y +
console->curr_row * CHAR_H;
int end_y = start_y + CHAR_H;
int start_x = console->window_origin_x +
console->curr_column * CHAR_W;
for (y=start_y; y<end_y; y++) {
// I think it's quicker not to use Fill() here...
switch (console->display.bitsPerPixel) {
case IO_8BitsPerPixel:
dst8 = (unsigned char *)PixelAddress(console, start_x, y);
for (x=0; x < CHAR_W; x++) {
*dst8++ = console->background;
}
break;
case IO_12BitsPerPixel:
case IO_15BitsPerPixel:
dst16 = (unsigned short *)PixelAddress(console, start_x, y);
for (x=0; x < CHAR_W; x++) {
*dst16++ = console->background;
}
break;
case IO_24BitsPerPixel:
dst32 = (unsigned int *)PixelAddress(console, start_x, y);
for (x=0; x < CHAR_W; x++) {
*dst32++ = console->background;
}
break;
default:
panic("FBConsole/Erase: bogus bits per pixel");
}
}
}
extern unsigned char appleClut8[ 768 ];
static void Expand4ToN( ConsolePtr console, int x, int y, int width, int height,
unsigned char * dataPtr, unsigned char colors[ 16 ])
{
unsigned char *dst;
int line, col, bit = 4;
unsigned int data, data8;
dst = (unsigned char *) PixelAddress(console, x, y);
for( line = 0; line < height; line++) {
for( col = 0; col < width; col++, bit ^= 4) {
if( bit)
data8 = *dataPtr++;
data = colors[ (data8 >> bit) & 15];
switch (console->display.bitsPerPixel) {
case IO_8BitsPerPixel:
if (console->display.colorSpace != IO_OneIsWhiteColorSpace)
*(dst + col) = data;
else {
data *= 3;
*(dst + col) = ((19595 * appleClut8[data] +
38470 * appleClut8[data + 1] +
7471 * appleClut8[data + 2] ) / 65536);
}
break;
case IO_24BitsPerPixel:
data *= 3;
*(((unsigned int *)dst) + col) = (appleClut8[data] << 16)
| (appleClut8[data + 1] << 8)
| appleClut8[data + 2];
break;
case IO_15BitsPerPixel:
data *= 3;
*(((unsigned short *)dst) + col) = ( (0xf8 & (appleClut8[data])) << 7)
| ( (0xf8 & (appleClut8[data + 1])) << 2)
| ( (0xf8 & (appleClut8[data + 2])) >> 3);
break;
default:
break;
}
}
dst = (unsigned char *) ((int)dst + console->display.rowBytes);
}
}
static void DrawColorRect( ConsolePtr console, int x, int y, int width, int height, unsigned char * dataPtr)
{
unsigned char *dst8;
int line,col;
unsigned int data;
dst8 = (unsigned char *) PixelAddress(console, x, y);
for( line = 0; line < height; line++) {
for( col = 0; col < width; col++) {
data = *dataPtr++;
if( data != 0x01) {
switch (console->display.bitsPerPixel) {
case IO_8BitsPerPixel:
if (console->display.colorSpace == IO_OneIsWhiteColorSpace) {
data *= 3;
*(dst8 + col) = ((19595 * appleClut8[data] +
38470 * appleClut8[data + 1] +
7471 * appleClut8[data + 2] ) / 65536);
} else {
*(dst8 + col) = data;
}
break;
case IO_24BitsPerPixel:
data *= 3;
*(((unsigned int *)dst8) + col) = (appleClut8[data] << 16)
| (appleClut8[data + 1] << 8)
| appleClut8[data + 2];
break;
case IO_15BitsPerPixel:
data *= 3;
*(((unsigned short *)dst8) + col) = ( (0xf8 & (appleClut8[data])) << 7)
| ( (0xf8 & (appleClut8[data + 1])) << 2)
| ( (0xf8 & (appleClut8[data + 2])) >> 3);
break;
default:
break;
}
}
}
dst8 = (unsigned char *) ((int)dst8 + console->display.rowBytes);
}
}
static void DrawIcon( ConsolePtr console)
{
#define ICON_WIDTH 11
#define ICON_HEIGHT 14
static unsigned char iconData[ICON_WIDTH*ICON_HEIGHT] = {
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xE3,0xE5,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0xE3,0xE5,0xE8,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0xE5,0xE8,0x01,0x01,0x01,
0x01,0x01,0xE3,0xE3,0xE5,0x01,0x01,0xE3,0xE3,0xE8,0x01,
0x01,0xE5,0x6F,0x26,0xE3,0xE3,0xE3,0xE3,0xE5,0xE6,0xE8,
0x10,0x05,0x01,0x05,0x05,0x0A,0x11,0x10,0x17,0x5E,0x01,
0x10,0x00,0x05,0x05,0x0B,0x0A,0x11,0x10,0x5F,0x01,0x01,
0x3B,0x00,0x08,0x11,0x11,0x17,0x3B,0x3B,0x65,0x01,0x01,
0x3B,0x00,0x08,0x11,0x17,0x17,0x17,0x3B,0x65,0x65,0x01,
0xD8,0x07,0x14,0xD8,0xD8,0xD8,0xD8,0xD9,0xD9,0xDB,0x8F,
0x14,0x3E,0x06,0x14,0x20,0x20,0x20,0x3E,0x3E,0x62,0x8D,
0x01,0x3E,0x3E,0x14,0x20,0x20,0x3E,0x3E,0x62,0x8D,0x8D,
0x01,0x01,0xEE,0xA3,0xA3,0xEF,0xCE,0xA3,0xCE,0xEF,0x01,
0x01,0x01,0x01,0xEF,0xEF,0x01,0x01,0xEF,0xEF,0x01,0x01
};
int x,y; // location of upper left corner of glyph
x = console->window_origin_x + console->curr_column * CHAR_W - ICON_WIDTH - 7; // left: BG_MARGIN + FG_MARGIN + 2;
y = console->window_origin_y + console->curr_row * CHAR_H - 4;
DrawColorRect( console, x, y, ICON_WIDTH, ICON_HEIGHT, &iconData[0]);
}
/*
* Expand a 1-bit PS bitmap, origin is lower left corner.
*/
#import "kmFontPriv.h"
void
BltPSBitmap(IOConsoleInfo *cso, int xpos, int ypos, bitmap_t *bmp,
const unsigned char *bits, int grayValue)
{
ConsolePtr console = (ConsolePtr)cso->priv;
int x, y;
int bitoffset;
unsigned char *pixAddr;
int fg;
pixAddr = PixelAddress(console, (console->display.width / 2) + xpos + bmp->bbx.xoff,
((console->display.height - 480) / 2) + ypos - bmp->bbx.yoff - bmp->bbx.height + 1);
fg = console->grayTable[ grayValue & 3 ];
/*
* x and y are in fb coordinate system
* xoff and yoff are in ps coordinate system
*/
for (y = 0; y < bmp->bbx.height; y++)
{
for (x = 0; x < bmp->bbx.width; x++)
{
bitoffset = bmp->bitx + y * bmp->bbx.width + x;
if( bits[bitoffset >> 3] & (0x80 >> (bitoffset & 0x7)))
switch (console->display.bitsPerPixel)
{
case IO_8BitsPerPixel:
((unsigned char *)pixAddr)[ x ] = fg;
break;
case IO_12BitsPerPixel:
case IO_15BitsPerPixel:
((unsigned short *)pixAddr)[ x ] = fg;
break;
case IO_24BitsPerPixel:
((unsigned int *)pixAddr)[ x ] = fg;
break;
}
}
pixAddr += console->display.rowBytes;
}
}
static void BltChar(ConsolePtr console, const char c)
// Description: Paint one character at (curr_column, curr_row).
{
unsigned char *glyphbase; // the glyph we're rendering
unsigned char byte;
unsigned char *pixAddr;
int x,y; // location of upper left corner of glyph
int source_y, bold;
unsigned char *dst8, fg8;
unsigned short *dst16, fg16;
unsigned int *dst32, fg32;
// Erase current contents of {curr_row, curr_column}.
Erase(console);
// Skip non-printing characters.
if (c < ENCODEBASE) {
return;
}
bold = console->bolding;
x = console->window_origin_x + console->curr_column * CHAR_W;
y = console->window_origin_y + console->curr_row * CHAR_H;
do {
glyphbase = ohlfs12[c - ENCODEBASE];
pixAddr = PixelAddress(console, x + bold, y);
switch (console->display.bitsPerPixel) {
case IO_8BitsPerPixel:
fg8 = (unsigned char) console->foreground;
dst8 = (unsigned char *) pixAddr;
for (source_y = CHAR_H; source_y != 0; source_y--) {
byte = *glyphbase++;
if (byte & 0x80) dst8[0] = fg8;
if (byte & 0x40) dst8[1] = fg8;
if (byte & 0x20) dst8[2] = fg8;
if (byte & 0x10) dst8[3] = fg8;
if (byte & 0x08) dst8[4] = fg8;
if (byte & 0x04) dst8[5] = fg8;
if (byte & 0x02) dst8[6] = fg8;
if (byte & 0x01) dst8[7] = fg8;
dst8 = (unsigned char *)
((int)dst8 + console->display.rowBytes);
}
break;
case IO_12BitsPerPixel:
case IO_15BitsPerPixel:
fg16 = (unsigned short) console->foreground;
dst16 = (unsigned short *) pixAddr;
for (source_y = CHAR_H; source_y != 0; source_y--) {
byte = *glyphbase++;
if (byte & 0x80) dst16[0] = fg16;
if (byte & 0x40) dst16[1] = fg16;
if (byte & 0x20) dst16[2] = fg16;
if (byte & 0x10) dst16[3] = fg16;
if (byte & 0x08) dst16[4] = fg16;
if (byte & 0x04) dst16[5] = fg16;
if (byte & 0x02) dst16[6] = fg16;
if (byte & 0x01) dst16[7] = fg16;
dst16 = (unsigned short *)
((int)dst16 + console->display.rowBytes);
}
break;
case IO_24BitsPerPixel:
fg32 = (unsigned int) console->foreground;
dst32 = (unsigned int *) pixAddr;
for (source_y = CHAR_H; source_y != 0; source_y--) {
byte = *glyphbase++;
if (byte & 0x80) dst32[0] = fg32;
if (byte & 0x40) dst32[1] = fg32;
if (byte & 0x20) dst32[2] = fg32;
if (byte & 0x10) dst32[3] = fg32;
if (byte & 0x08) dst32[4] = fg32;
if (byte & 0x04) dst32[5] = fg32;
if (byte & 0x02) dst32[6] = fg32;
if (byte & 0x01) dst32[7] = fg32;
dst32 = (unsigned int *)
((int)dst32 + console->display.rowBytes);
}
break;
}
} while( bold--);
console->curr_column++;
return;
}
extern void video_scroll_up(unsigned char * start, unsigned char * end, unsigned char * dest);
static void FBPutC(ConsolePtr console, char c)
// Write one character to screen. Cursor is 'on' on entry and exit.
{
int repeat;
int i;
/*
* First deal with ANSI escape sequences.
* This is a very bizarre implementation, copied from the m68k
* version.
*/
switch(console->ansi_state) {
case AS_NORMAL:
if(c == esc) {
console->ansi_state = AS_ESCAPE;
return;
}
else {
break; // continue
}
case AS_ESCAPE:
switch(c) {
case '[':
console->ansi_state = AS_BRACKET;
return;
default:
console->ansi_state = AS_NORMAL;
break; // continue
}
case AS_BRACKET:
if(c >= '0' && c <= '9') {
*console->ansi_stack_p =
*console->ansi_stack_p * 10 + (c - '0');
return;
}
else if (c == ';') {
if(console->ansi_stack_p <
&console->ansi_stack[ANSI_STACK_SIZE]) {
console->ansi_stack_p++;
}
return;
}
else {
for(i=0; i<ANSI_STACK_SIZE; i++) {
if (console->ansi_stack[i] == 0) {
console->ansi_stack[i] = 1;
}
}
repeat = *console->ansi_stack_p;
FlipCursor(console); // cursor off
switch (c) {
case 'A':
while (repeat--) {
if(console->curr_row) {
console->curr_row--;
}
}
break;
case 'B':
while (repeat--) {
console->curr_row++;
}
break;
case 'C': // non destructive space
while (repeat--) {
console->curr_column++;
}
break;
case 'D': // not in termcap
while (repeat--) {
if(console->curr_column) {
console->curr_column--;
}
}
break;
case 'E': // not in termcap
console->curr_column = 0;
while (repeat--) {
console->curr_row++;
}
break;
case 'H': // should be home
case 'f': // not in termcap
console->curr_column =
*console->ansi_stack_p - 1;
console->ansi_stack_p--;
console->curr_row =
*console->ansi_stack_p - 1;
console->ansi_stack_p--;
break;
case 'K':
ClearToEOL(console);
break;
case 'm': /* FIXME */
console->ansi_stack_p--;
console->ansi_stack_p--;
break;
}
}
console->ansi_stack_p = &console->ansi_stack[1];
for(i=0; i<ANSI_STACK_SIZE; i++)
console->ansi_stack[i] = 0;
console->ansi_state = AS_NORMAL;
goto proceed;
}
FlipCursor(console); // cursor off
switch(c) {
case '\r': // Carriage return
console->curr_column = 0;
break;
case '\n': // line feed
console->curr_column = 0;
console->curr_row++;
break;
case '\b': // backspace
if (console->curr_column == 0)
break;
console->curr_column--;
break;
case '\t':
// tab. Erase all characters up to and including the
// next tab stop.
{
int col, num_cols;
num_cols = TAB_SIZE - (console->curr_column % TAB_SIZE);
FlipCursor(console); // cursor on
for (col = 0; col<num_cols; col++) {
FBPutC(console, ' '); // cursor on at return
}
FlipCursor(console); // cursor off
break;
}
case np: // aka ff, form feed
console->curr_row = console->curr_column = 0;
ClearWindow(console);
break;
case del:
console->curr_column++;
break;
default:
// Normal case.
BltChar(console, c);
break;
}
// Cursor is off.
proceed:
if (console->curr_column >= console->chars_per_row) {
// End-of-line wrap.
console->curr_column = 0;
console->curr_row++;
}
if (console->curr_row >= console->chars_per_column) {
//
// Screen scroll. Copy the whole window down in memory
// (pixels_per_row * CHAR_H) pixels, starting at
// the first character in row 1.
//
unsigned char *src;
unsigned char *dst;
int source_y;
unsigned windowRowBytes;
console->curr_row = console->chars_per_column - 1;
switch (console->display.bitsPerPixel) {
case IO_8BitsPerPixel:
windowRowBytes = console->pixels_per_row;
break;
case IO_12BitsPerPixel:
case IO_15BitsPerPixel:
windowRowBytes = 2*console->pixels_per_row;
break;
case IO_24BitsPerPixel:
windowRowBytes = 4*console->pixels_per_row;
break;
default:
panic("FBConsole/FBPutC: bogus bitsPerPixel");
}
// Copy one row at a time, moving each one up
// CHAR_H rows. Within the loop, just increment
// pixel pointers by one row's worth of pixels.
// Source starts at the left top of row 1; destination
// starts at left top of row 0.
//
src = PixelAddress(console,
console->window_origin_x,
console->window_origin_y + CHAR_H);
dst = PixelAddress(console,
console->window_origin_x,
console->window_origin_y);
for (source_y = CHAR_H; // top, row 1
source_y < console->pixels_per_column; // bottom
source_y++) {
#ifndef notDefUseFPU
video_scroll_up( src, src + windowRowBytes, dst);
#else
videoMemMove(dst, src, windowRowBytes);
#endif
src += console->display.rowBytes;
dst += console->display.rowBytes;
}
console->curr_column = 0;
ClearToEOL(console);
}
// Cursor back on.
FlipCursor(console);
}
static void SetTitle(ConsolePtr console, const char *title)
// Description: Draw title bar if none exists, write specified title into it.
// Drawing a title bar involves snarfing up row 0 of the window
// and decreasing the usable size of the window by one row.
// Preconditions:
// * Cursor is 'on' on entry and will remain so on exit.
{
int saved_curr_row = console->curr_row;
int saved_curr_column = console->curr_column;
int saved_origin_y;
int title_len = strlen(title);
int pixel_num;
if ((title_len == 0) || (title_len > console->chars_per_row)) {
IOLog("console: Illegal title length (%d)\n", title_len);
return;
}
FlipCursor(console); // old cursor off
if (console->has_title) {
// First grow window by two rows - this absorbs the existing
// title bar.
console->window_origin_y -= CHAR_H * 2;
console->chars_per_column += 2;
console->pixels_per_column += CHAR_H * 2;
saved_curr_row += 2;
}
// Clear row 0, center new title in it.
console->curr_row = 0;
Rect(console,
console->window_origin_x - (BG_MARGIN - TS_MARGIN),
console->window_origin_y - (BG_MARGIN - TS_MARGIN),
CHAR_W * console->chars_per_row + 2 * (BG_MARGIN - TS_MARGIN),
CHAR_H * 2 - TS_MARGIN,
console->light_grey);
saved_origin_y = console->window_origin_y;
console->window_origin_y += CHAR_H / 2;
console->curr_column = (console->chars_per_row - title_len) / 2;
DrawIcon(console);
// SwapForegroundAndBackground(console);
console->bolding = 1;
console->background = console->light_grey;
FlipCursor(console); // new cursor on
while (*title) {
FBPutC(console, *title++);
}
FlipCursor(console); // new cursor off
console->background = console->grayTable[0];
console->bolding = 0;
// SwapForegroundAndBackground(console);
console->window_origin_y = saved_origin_y;
// Draw grey lines one pixel away from border of title bar.
// Origin is currently at first pixel in top line of title bar.
Rect(console, // inside top
console->window_origin_x - BG_MARGIN,
console->window_origin_y - BG_MARGIN,
console->pixels_per_row + (BG_MARGIN * 2),
TS_MARGIN,
console->background);
Rect(console, // inside bottom
console->window_origin_x - BG_MARGIN,
console->window_origin_y + CHAR_H * 2 - TOTAL_MARGIN - TS_MARGIN,
console->pixels_per_row + BG_MARGIN * 2,
TS_MARGIN,
console->dark_grey);
for (pixel_num = 0; pixel_num < TS_MARGIN; pixel_num++) {
Rect(console, // left
console->window_origin_x - BG_MARGIN + pixel_num,
console->window_origin_y - BG_MARGIN + pixel_num,
1,
CHAR_H * 2 - 1 - (pixel_num * 2),
console->background);
}
for (pixel_num = 1 + BG_MARGIN - TS_MARGIN; pixel_num <= BG_MARGIN; pixel_num++) {
Rect(console, // right
console->window_origin_x + console->pixels_per_row + pixel_num - 1,
console->window_origin_y - pixel_num,
1,
CHAR_H * 2 - 1 - (BG_MARGIN - pixel_num) * 2,
console->dark_grey);
}
Rect(console, // outside bottom
console->window_origin_x - TOTAL_MARGIN,
console->window_origin_y + CHAR_H * 2 - FG_MARGIN - BG_MARGIN,
console->pixels_per_row + TOTAL_MARGIN * 2,
FG_MARGIN,
console->foreground);
// Diminish window size by two rows.
console->window_origin_y += CHAR_H * 2;
console->chars_per_column -= 2;
console->pixels_per_column -= CHAR_H * 2;
// Restore old cursor. Careful, the y axis just changed...
console->curr_column = saved_curr_column;
if (saved_curr_row > 0) {
console->curr_row = saved_curr_row - 2;
}
else {
// New row 0 - clear it.
ClearToEOL(console);
}
FlipCursor(console); // old cursor on
console->has_title = TRUE;
}
static void UpdateWindowChars(ConsolePtr console)
// Description: Calculate window size in characters. Used when either window
// size or font changes.
{
console->chars_per_row = console->pixels_per_row / CHAR_W;
console->chars_per_column =
console->pixels_per_column / CHAR_H;
}
static void InitWindow(ConsolePtr console,
int width,
int height,
const char *title,
boolean_t initWindow,
boolean_t saveUnder)
// Description: Initialize window parameters. If initWindow is TRUE, an empty
// window is drawn in the screen, else we assume that a window
// already exists. Screen and font parameters must be valid on
// entry.
{
// Truncate specified size to integral mutliple of character size
// in both dimensions.
width /= CHAR_W; // now in chars
height /= CHAR_H;
width *= CHAR_W; // now in pixels
height *= CHAR_H;
// Ensure there's enough room for a border.
if (width > (console->display.width - HORIZ_BORDER - TOTAL_MARGIN * 2 - DROP_SHADOW))
width = console->display.width - HORIZ_BORDER - TOTAL_MARGIN * 2 - DROP_SHADOW;
if (height > (console->display.height - VERT_BORDER - TOTAL_MARGIN * 2 - DROP_SHADOW))
height = console->display.height - VERT_BORDER - TOTAL_MARGIN * 2 - DROP_SHADOW;
width &= 0xfffffffe;
//
// Init console window variables. The window is centered in the
// ! screen, minus a pixel or two to guarantee double word alignment
// ! for the first pixel of a row (until further developments...when
// ! we do alert panels, we can enumerate some cases here...).
//
console->window_origin_x = (console->display.width - width) / 2;
console->window_origin_y = (console->display.height - height) / 2;
console->pixels_per_row = width;
console->pixels_per_column = height;
(unsigned)console->window_origin_x &= 0xfffffffe;
UpdateWindowChars(console);
console->curr_column = 0;
console->has_title = FALSE;
if (initWindow) {
// Before we start drawing anything, save under if needed
if (saveUnder) {
int i, bytesPerPixel = 0;
unsigned char *save, *sp;
// Compute size of save under region in bytes and allocate
switch (console->display.bitsPerPixel) {
case IO_8BitsPerPixel: bytesPerPixel = 1; break;
case IO_12BitsPerPixel:
case IO_15BitsPerPixel: bytesPerPixel = 2; break;
case IO_24BitsPerPixel: bytesPerPixel = 4; break;
}
console->saveHeight = height + TOTAL_MARGIN * 2 + DROP_SHADOW;
console->saveRowBytes = (width + TOTAL_MARGIN * 2 + DROP_SHADOW)*bytesPerPixel;
console->saveBytes = console->saveHeight*console->saveRowBytes;
save = console->saveBits = (unsigned char *)
kalloc_noblock(console->saveBytes);
sp = console->saveLocation =
PixelAddress(console, console->window_origin_x - TOTAL_MARGIN,
console->window_origin_y - TOTAL_MARGIN);
// Copy the window contents into the save under
if( save)
for (i = console->saveHeight; i != 0; i--) {
videoMemMove(save, sp, console->saveRowBytes);
sp += console->display.rowBytes;
save += console->saveRowBytes;
}
}
// New window - cursor at origin.
console->curr_row = 0;
console->has_title = FALSE;
// Draw the border. The border goes outside of the specified
// window. Outside lines are black; inside lines are
// half-tone.
Rect(console, // outside top
console->window_origin_x - TOTAL_MARGIN,
console->window_origin_y - TOTAL_MARGIN,
width + TOTAL_MARGIN * 2,
FG_MARGIN,
console->foreground);
Rect(console, // inside top
console->window_origin_x - BG_MARGIN,
console->window_origin_y - BG_MARGIN,
width + BG_MARGIN * 2,
BG_MARGIN,
console->background);
Rect(console, // inside bottom
console->window_origin_x - BG_MARGIN,
console->window_origin_y + height,
width + BG_MARGIN * 2,
BG_MARGIN,
console->background);
Rect(console, // outside bottom
console->window_origin_x - TOTAL_MARGIN,
console->window_origin_y + height + BG_MARGIN,
width + TOTAL_MARGIN * 2,
FG_MARGIN,
console->foreground);
if( DROP_SHADOW) Rect(console, // outside bottom shadow
console->window_origin_x - TOTAL_MARGIN + DROP_SHADOW,
console->window_origin_y + height + BG_MARGIN + DROP_SHADOW,
width + TOTAL_MARGIN * 2,
DROP_SHADOW,
console->dark_grey);
Rect(console, // outside left
console->window_origin_x - TOTAL_MARGIN,
console->window_origin_y - TOTAL_MARGIN,
FG_MARGIN,
height + TOTAL_MARGIN * 2,
console->foreground);
Rect(console, // inside left
console->window_origin_x - BG_MARGIN,
console->window_origin_y - BG_MARGIN,
BG_MARGIN,
height + BG_MARGIN * 2,
console->background);
Rect(console, // inside right
console->window_origin_x + width,
console->window_origin_y - BG_MARGIN,
BG_MARGIN,
height + BG_MARGIN * 2,
console->background);
Rect(console, // outside right
console->window_origin_x + width + BG_MARGIN,
console->window_origin_y - TOTAL_MARGIN,
FG_MARGIN,
height + TOTAL_MARGIN * 2,
console->foreground);
if( DROP_SHADOW) Rect(console, // outside right shadow
console->window_origin_x + width + BG_MARGIN + DROP_SHADOW,
console->window_origin_y - TOTAL_MARGIN + DROP_SHADOW,
DROP_SHADOW,
height + TOTAL_MARGIN * 2,
console->dark_grey);
// Clear the contents of the window and draw a cursor.
ClearWindow(console);
FlipCursor(console); // cursor on
SetTitle(console, title);
}
else {
/* Leave current window contents, just updating title.
* We'll do a newline to make sure we have room for
* our font and proceed.Initial cursor will be at
* lower left corner.
*/
console->curr_row = console->chars_per_column - 1;
SetTitle(console, title);
FBPutC(console, '\n');
}
return;
}
//
// END: Private utility routines
//
//
// BEGIN: Implementation of IOConsoleInfo functions
//
static void Free(IOConsoleInfo *cso)
// Description: Free a FB Console object
{
IOFree(cso->priv, sizeof(ConsoleRep));
IOFree(cso, sizeof(IOConsoleInfo));
}
static void Init(
IOConsoleInfo *cso,
ScreenMode mode,
boolean_t initScreenOrSaveUnder,
boolean_t initWindow,
const char *title)
{
ConsolePtr console = (ConsolePtr)cso->priv;
int i;
switch (console->display.bitsPerPixel) {
case IO_8BitsPerPixel:
if (console->display.colorSpace == IO_OneIsWhiteColorSpace) {
console->baseground = (TRUE || (mode == SCM_GRAPHIC)) ? 107 : 0x55;
console->background = 0xff;
console->foreground = 0x00;
console->dark_grey = 85;
console->light_grey = 187;
} else {
console->baseground = (TRUE || (mode == SCM_GRAPHIC)) ? 0x80 : 0x7e;
console->background = 0x00;
console->foreground = 0xff;
console->dark_grey = 0xfb;
console->light_grey = 0xf7;
}
break;
case IO_15BitsPerPixel:
console->baseground = (TRUE || (mode == SCM_GRAPHIC)) ? 0x3193 : 0x295f;
console->background = 0x7fff;
console->foreground = 0x0000;
console->dark_grey = 0x294a;
console->light_grey = 0x5ef7;
break;
case IO_24BitsPerPixel:
console->baseground = (TRUE || (mode == SCM_GRAPHIC)) ? 0xff666699 : 0xff5555ff;
console->background = 0xffffffff;
console->foreground = 0xff000000;
console->dark_grey = 0xff555555;
console->light_grey = 0xffbbbbbb;
break;
}
console->grayTable[0] = console->background;
console->grayTable[1] = console->light_grey;
console->grayTable[2] = console->dark_grey;
console->grayTable[3] = console->foreground;
console->ansi_state = AS_NORMAL;
for(i=0; i<ANSI_STACK_SIZE; i++) {
console->ansi_stack[i] = 0;
}
console->ansi_stack_p = &console->ansi_stack[1]; // FIXME - why not 0?
// Initialize the screen, if appropriate.
if (initScreenOrSaveUnder && (mode != SCM_ALERT)) {
WipeScreen(console, console->baseground);
}
console->window_type = mode;
switch(console->window_type) {
case SCM_TEXT:
InitWindow(console, TEXT_WIN_WIDTH, TEXT_WIN_HEIGHT,
title, initWindow, 0 /* Don't save under */);
break;
case SCM_ALERT:
InitWindow(console, ALERT_WIN_WIDTH, ALERT_WIN_HEIGHT,
title, initWindow, initScreenOrSaveUnder );
break;
case SCM_GRAPHIC:
if( initScreenOrSaveUnder) {
int cx, cy;
cx = console->display.width / 2;
cy = console->display.height / 2;
Expand4ToN( console, cx + RIGHT_DX, cy + RIGHT_DY,
RIGHT_WIDTH, RIGHT_HEIGHT, rightData, rightBotColors );
Expand4ToN( console, cx + CENTER_DX, cy + CENTER_DY,
CENTER_WIDTH, CENTER_HEIGHT, centerData, centerColors );
Expand4ToN( console, cx + BOTTOM_DX, cy + BOTTOM_DY,
BOTTOM_WIDTH, BOTTOM_HEIGHT, bottomData, rightBotColors );
}
break;
default:
panic("FBConsole/FBInitConsole: can't init");
break;
}
return;
}
static int Restore(IOConsoleInfo *cso)
{
ConsolePtr console = (ConsolePtr)cso->priv;
unsigned char *save, *dp;
int i;
if (console->window_type != SCM_ALERT) {
IOLog("frameBuffer: bogus restore, mode %d\n", console->window_type);
return -1;
}
// Copy save under bits back onto screen
save = console->saveBits;
dp = console->saveLocation;
if( save) {
for (i = console->saveHeight; i != 0; i--) {
videoMemMove(dp, save, console->saveRowBytes);
dp += console->display.rowBytes;
save += console->saveRowBytes;
}
// Free bits
kfree(console->saveBits, console->saveBytes);
console->saveBits = 0;
}
return 0;
}
#define VIDEO_W 640
#define VIDEO_H 480
static int DrawRect(IOConsoleInfo *cso, const struct km_drawrect *km_rect)
// Description: Given a 2 bit raster, convert it to the format appropriate for
// the display. The co-ordinates passed in by these ioctls assume
// an (VIDEO_W x VIDEO_H) screen. All screen sizes are
// assumed to share a common center point. We scale the X and Y
// values to maintain a constant offset from the center point,
// so that boot animations, popup windows, and related goodies
// don't break with screens larger or smaller than the 'default'
// screen.
// Preconditions:
// * The rectangle that we are to draw must start on a 4 pixel boundary
// and should be a multiple of 4 pixels in width.
{
ConsolePtr console = (ConsolePtr)cso->priv;
int pixel; /* Starting pixel in screen */
int i, x, y;
unsigned char *data;
unsigned char value;
unsigned int * table;
struct km_drawrect *rect = (struct km_drawrect *) km_rect;
int bgX, bgY, bgH;
unsigned char * bg;
table = console->grayTable;
/* copyin is done in km */
data = rect->data.bits;
x = (rect->x & 0x1ffc) + (console->display.width - VIDEO_W)/2;
y = rect->y + (console->display.height - VIDEO_H)/2;
/* Correct the x and y values for screen size */
if( (rect->x & 3) == 3) {
DrawColorRect( console, x, y, rect->width, rect->height, data);
return 0;
}
#if TEXTURE_BACKGND
bgX = console->display.width / 2 + CENTER_DX;
bgY = console->display.height / 2 + CENTER_DY;
bgH = (y - bgY) & -2;
if( bgH > 0) {
bgY += bgH;
bg = centerData + (bgH * CENTER_WIDTH) / 2;
bgH = CENTER_HEIGHT - bgH;
} else
bg = (unsigned char *)0;
#endif
rect->x &= 0x1ffc;
/* Sanity check */
if ((x + rect->width > console->display.width)
|| (y + rect->height) > console->display.height)
return( -1 );
pixel = x + (y * console->display.totalWidth);
switch ( console->display.bitsPerPixel )
{
case IO_2BitsPerPixel: /* 2 bit pixels */
{
unsigned char *dst = (unsigned char *)console->display.frameBuffer;
unsigned char *fb;
unsigned char final_value;
dst += pixel >> 2;
for ( y = 0; y < rect->height; ++y ) {
fb = dst;
for ( x = 0; x < rect->width; x += 4) {
value = *data++;
final_value = 0;
for ( i = 0; i < 8; i += 2 ) {
final_value |= ((table[(value>>i)&3] & 3) << i);
}
*fb++ = final_value;
}
dst += console->display.rowBytes;
}
break;
}
case IO_8BitsPerPixel: /* 8 bit pixels */
{
unsigned char *dst = (unsigned char *)console->display.frameBuffer;
unsigned char *fb;
dst += pixel;
for ( y = 0; y < rect->height; ++y ) {
fb = dst;
#if TEXTURE_BACKGND
if( ((y & 1) == 0) && bg) {
Expand4ToN( console, bgX, bgY,
CENTER_WIDTH, 2, bg, centerColors );
bgY += 2;
bg += CENTER_WIDTH;
}
#endif
for ( x = 0; x < rect->width; x += 4) {
value = *data++;
if( value) {
int pix;
pix = (value >> 6) & 3;
if( pix)
fb[0] = table[pix];
pix = (value >> 4) & 3;
if( pix)
fb[1] = table[pix];
pix = (value >> 2) & 3;
if( pix)
fb[2] = table[pix];
pix = value & 3;
if( pix)
fb[3] = table[pix];
}
fb += 4;
}
dst += console->display.rowBytes;
}
break;
}
case IO_12BitsPerPixel: /* 16 bit pixels */
case IO_15BitsPerPixel: /* 16 bit pixels */
{
unsigned short *dst = (unsigned short *)console->display.frameBuffer;
unsigned short *fb;
dst += pixel;
for ( y = 0; y < rect->height; ++y ) {
fb = dst;
#if TEXTURE_BACKGND
if( ((y & 1) == 0) && bg) {
Expand4ToN( console, bgX, bgY,
CENTER_WIDTH, 2, bg, centerColors );
bgY += 2;
bg += CENTER_WIDTH;
}
#endif
for ( x = 0; x < rect->width; x += 4) {
value = *data++;
if( value) {
int pix;
pix = (value >> 6) & 3;
if( pix)
fb[0] = table[pix];
pix = (value >> 4) & 3;
if( pix)
fb[1] = table[pix];
pix = (value >> 2) & 3;
if( pix)
fb[2] = table[pix];
pix = value & 3;
if( pix)
fb[3] = table[pix];
}
fb += 4;
}
dst = (unsigned short *)(((char*)dst) +
console->display.rowBytes);
}
break;
}
case IO_24BitsPerPixel: /* 32 bit pixels */
{
unsigned int *dst = (unsigned int *) console->display.frameBuffer;
unsigned int *fb;
dst += pixel;
for ( y = 0; y < rect->height; ++y ) {
fb = dst;
#if TEXTURE_BACKGND
if( ((y & 1) == 0) && bg) {
Expand4ToN( console, bgX, bgY,
CENTER_WIDTH, 2, bg, centerColors );
bgY += 2;
bg += CENTER_WIDTH;
}
#endif
for ( x = 0; x < rect->width; x += 4) {
value = *data++;
if( value) {
int pix;
pix = (value >> 6) & 3;
if( pix)
fb[0] = table[pix];
pix = (value >> 4) & 3;
if( pix)
fb[1] = table[pix];
pix = (value >> 2) & 3;
if( pix)
fb[2] = table[pix];
pix = value & 3;
if( pix)
fb[3] = table[pix];
}
fb += 4;
}
dst = (unsigned int *)(((char*)dst) +
console->display.rowBytes);
}
break;
}
}
return 0;
}
static int EraseRect(IOConsoleInfo *cso, const struct km_drawrect *km_rect)
// Description: Erase the specified rectangle to the color specified
// in the km_rect structure.
// Preconditions:
// * The rectangle that we are to erase must start on a 4 pixel boundary
// and should be a multiple of 4 pixels in width.
{
ConsolePtr console = (ConsolePtr)cso->priv;
int pixel; // Starting pixel in screen
int x, y, w, h;
unsigned int value;
struct km_drawrect *rect = (struct km_drawrect *) km_rect;
int bgX, bgY, bgH;
unsigned char * bg;
value = console->grayTable[ rect->data.fill & 3 ];
/* Correct the x and y values for screen size */
x = rect->x + (console->display.width - VIDEO_W)/2;
y = rect->y + (console->display.height - VIDEO_H)/2;
x &= ~3; // Trunc to 4 pixel boundary
w = (rect->width) & ~3; // Round dn to 4 pixel boundary
h = rect->height;
/* Sanity check */
/* Sanity check */
if (((x + w) > console->display.width)
|| ((y + h) > console->display.height) )
return( -1 );
#if TEXTURE_BACKGND
bgX = console->display.width / 2 + CENTER_DX;
bgY = console->display.height / 2 + CENTER_DY;
bgH = (y - bgY) & -2;
if( bgH > 0) {
bgY += bgH;
bg = centerData + (bgH * CENTER_WIDTH) / 2;
bgH = CENTER_HEIGHT - bgH;
Expand4ToN( console, bgX, bgY,
CENTER_WIDTH, bgH, bg, centerColors );
}
#else
Rect( console, x, y, w, h, value);
#endif
return 0;
}
//extern void czputc( char c);
static void PutC(IOConsoleInfo *cso, char c)
// Write one character to screen. Cursor is 'on' on entry and exit.
{
FBPutC((ConsolePtr)cso->priv, c);
// czputc(c);
}
static void GetSize(IOConsoleInfo *cso, struct ConsoleSize *s)
// Return the size of the screen in pixels
{
ConsolePtr console = (ConsolePtr)cso->priv;
s->cols = console->chars_per_row;
s->rows = console->chars_per_column;
s->pixel_width = console->display.width;
s->pixel_height = console->display.height;
}
//
// END: Implementation of IOConsoleInfo functions
//
static IOConsoleInfo staticConsoleInfo;
static ConsoleRep staticConsoleRep;
static void InitializeConsole( IOConsoleInfo *cso, IODisplayInfo *display )
{
cso->Init = Init;
cso->Restore = Restore;
cso->DrawRect = DrawRect;
cso->EraseRect = EraseRect;
cso->PutC = PutC;
cso->GetSize = GetSize;
((ConsolePtr)cso->priv)->display = *display;
((ConsolePtr)cso->priv)->window_type = SCM_UNINIT;
return;
}
//
// BEGIN: Exported routines
//
static void DoNothing(IOConsoleInfo *cso)
{
}
IOConsoleInfo *BasicAllocateConsole(IODisplayInfo *display)
{
// No memory allocation. Assume non backed window.
IOConsoleInfo *cso = &staticConsoleInfo;
cso->priv = (void *)&staticConsoleRep;
InitializeConsole(cso, display);
cso->Free = DoNothing;
#if 0
printf("base:%x rowBytes:%x width:%x height:%x\n",display->frameBuffer,
display->rowBytes, display->width, display->height);
#endif
return cso;
}
IOConsoleInfo *FBAllocateConsole(IODisplayInfo *display)
{
IOConsoleInfo *cso = (IOConsoleInfo *)IOMalloc(sizeof(IOConsoleInfo));
if (cso == NIL)
return NIL;
cso->priv = (void *)IOMalloc(sizeof(ConsoleRep));
if (cso->priv == NIL)
{
IOFree(cso, sizeof(IOConsoleInfo));
return NIL;
}
InitializeConsole(cso, display);
cso->Free = Free;
return cso;
}
//
// END: Exported routines
//