#include <kern/spl.h>
#include <machine/machparam.h>
#include "iso_scan_font.h"
#include <pexpert/pexpert.h>
#include <pexpert/i386/boot.h>
#include <kern/time_out.h>
#include <kern/lock.h>
#include "video_console.h"
#define CHARWIDTH 8
#define CHARHEIGHT 16
#define ATTR_NONE 0
#define ATTR_BOLD 1
#define ATTR_UNDER 2
#define ATTR_REVERSE 4
enum vt100state_e {
ESnormal,
ESesc,
ESsquare,
ESgetpars,
ESgotpars,
ESfunckey,
EShash,
ESsetG0,
ESsetG1,
ESask,
EScharsize,
ESignore
} vt100state = ESnormal;
static struct vc_info vinfo;
#define IS_TEXT_MODE (vinfo.v_type == TEXT_MODE)
static int vc_wrap_mode = 1, vc_relative_origin = 0;
static int vc_charset_select = 0, vc_save_charset_s = 0;
static int vc_charset[2] = { 0, 0 };
static int vc_charset_save[2] = { 0, 0 };
#define MAXPARS 16
static int x = 0, y = 0, savex, savey;
static int par[MAXPARS], numpars, hanging_cursor, attr, saveattr;
static char tab_stops[255];
static int scrreg_top, scrreg_bottom;
void vc_flush_forward_buffer(void);
void vc_store_char(unsigned char);
unsigned char vc_color_index_table[33] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
unsigned long vc_color_depth_masks[4] =
{ 0x000000FF, 0x00007FFF, 0x00FFFFFF };
unsigned long vc_colors[8][3] = {
{ 0xFFFFFFFF, 0x00000000, 0x00000000 },
{ 0x23232323, 0x7C007C00, 0x00FF0000 },
{ 0xb9b9b9b9, 0x03e003e0, 0x0000FF00 },
{ 0x05050505, 0x7FE07FE0, 0x00FFFF00 },
{ 0xd2d2d2d2, 0x001f001f, 0x000000FF},
{ 0x18181818, 0x7C1F7C1F, 0x00FF00FF },
{ 0xb4b4b4b4, 0x03FF03FF, 0x0000FFFF },
{ 0x00000000, 0x7FFF7FFF, 0x00FFFFFF }
};
unsigned long vc_color_mask = 0;
unsigned long vc_color_fore = 0;
unsigned long vc_color_back = 0;
int vc_normal_background = 1;
#define VC_MAX_FORWARD_SIZE (80*22)
#define VC_CONSOLE_UPDATE_TIMEOUT 5
static unsigned char vc_forward_buffer[VC_MAX_FORWARD_SIZE];
static long vc_forward_buffer_size = 0;
decl_simple_lock_data(,vc_forward_lock)
static int vc_initialized = 0;
static struct {
void (*initialize)(struct vc_info * vinfo_p);
void (*paintchar)(unsigned char c, int x, int y, int attrs);
void (*scrolldown)(int num);
void (*scrollup)(int num);
void (*clear_screen)(int xx, int yy, int which);
void (*show_cursor)(int x, int y);
void (*hide_cursor)(int x, int y);
void (*update_color)(int color, int fore);
} vc_ops;
#define REN_MAX_DEPTH 32
#define REN_MAX_SIZE (128L*1024)
unsigned char renderedFont[REN_MAX_SIZE];
unsigned long vc_rendered_font_size = REN_MAX_SIZE;
long vc_rendered_error = 0;
short vc_one_bit_reversed = 0;
int vc_rendered_char_size = 0;
#define VC_RESET_BACKGROUND 40
#define VC_RESET_FOREGROUND 37
static void vc_color_set(int color)
{
if (vinfo.v_depth < 8)
return;
if (color >= 30 && color <= 37) {
vc_color_fore = vc_colors[color-30][vc_color_index_table[vinfo.v_depth]];
if ( vc_ops.update_color ) vc_ops.update_color(color - 30, 1);
}
if (color >= 40 && color <= 47) {
vc_color_back = vc_colors[color-40][vc_color_index_table[vinfo.v_depth]];
if ( vc_ops.update_color ) vc_ops.update_color(color - 40, 0);
vc_normal_background = color == 40;
}
}
static void vc_render_font(short olddepth, short newdepth)
{
int charIndex;
union {
unsigned char *charptr;
unsigned short *shortptr;
unsigned long *longptr;
} current;
unsigned char *theChar;
if (olddepth == newdepth)
return;
vc_rendered_font_size = REN_MAX_SIZE;
if (newdepth == 1) {
vc_rendered_char_size = 16;
if (!vc_one_bit_reversed) {
int i;
for (i = 0; i < ((ISO_CHAR_MAX-ISO_CHAR_MIN+1) * vc_rendered_char_size); i++) {
if (iso_font[i]) {
unsigned char mask1 = 0x80;
unsigned char mask2 = 0x01;
unsigned char val = 0;
while (mask1) {
if (iso_font[i] & mask1)
val |= mask2;
mask1 >>= 1;
mask2 <<= 1;
}
renderedFont[i] = ~val;
} else renderedFont[i] = 0xff;
}
vc_one_bit_reversed = 1;
}
return;
}
{
long csize = newdepth / 8;
vc_rendered_char_size = csize ? CHARHEIGHT * (csize * CHARWIDTH) :
CHARHEIGHT * (CHARWIDTH/(6-newdepth));
csize = (ISO_CHAR_MAX-ISO_CHAR_MIN+1) * vc_rendered_char_size;
if (csize > vc_rendered_font_size) {
vc_rendered_error = csize;
return;
} else
vc_rendered_font_size = csize;
}
current.charptr = renderedFont;
theChar = iso_font;
for (charIndex = ISO_CHAR_MIN; charIndex <= ISO_CHAR_MAX; charIndex++) {
int line;
for (line = 0; line < CHARHEIGHT; line++) {
unsigned char mask = 1;
do {
switch (newdepth) {
case 2: {
unsigned char value = 0;
if (*theChar & mask) value |= 0xC0; mask <<= 1;
if (*theChar & mask) value |= 0x30; mask <<= 1;
if (*theChar & mask) value |= 0x0C; mask <<= 1;
if (*theChar & mask) value |= 0x03;
value = ~value;
*current.charptr++ = value;
}
break;
case 4:
{
unsigned char value = 0;
if (*theChar & mask) value |= 0xF0; mask <<= 1;
if (*theChar & mask) value |= 0x0F;
value = ~value;
*current.charptr++ = value;
}
break;
case 8:
*current.charptr++ = (*theChar & mask) ? 0xff : 0;
break;
case 16:
*current.shortptr++ = (*theChar & mask) ? 0xFFFF : 0;
break;
case 32:
*current.longptr++ = (*theChar & mask) ? 0xFFFFFFFF : 0;
break;
}
mask <<= 1;
} while (mask);
theChar++;
}
}
}
static void vc_paint_char1(unsigned char ch, int xx, int yy, int attrs)
{
unsigned char *theChar;
unsigned char *where;
int i;
theChar = (unsigned char*)(renderedFont + (ch * vc_rendered_char_size));
where = (unsigned char*)(vinfo.v_baseaddr +
(yy * CHARHEIGHT * vinfo.v_rowbytes) +
(xx));
if (!attrs) for (i = 0; i < CHARHEIGHT; i++) {
*where = *theChar++;
where = (unsigned char*)(((unsigned char*)where)+vinfo.v_rowbytes);
} else for (i = 0; i < CHARHEIGHT; i++) {
unsigned char val = *theChar++, save = val;
if (attrs & ATTR_BOLD) {
unsigned char mask1 = 0xC0, mask2 = 0x40;
int bit = 0;
for (bit = 0; bit < 7; bit++) {
if ((save & mask1) == mask2)
val &= ~mask2;
mask1 >>= 1;
mask2 >>= 1;
}
}
if (attrs & ATTR_REVERSE) val = ~val;
if (attrs & ATTR_UNDER && i == CHARHEIGHT-1) val = ~val;
*where = val;
where = (unsigned char*)(((unsigned char*)where)+vinfo.v_rowbytes);
}
}
static void vc_paint_char2(unsigned char ch, int xx, int yy, int attrs)
{
unsigned short *theChar;
unsigned short *where;
int i;
theChar = (unsigned short*)(renderedFont + (ch * vc_rendered_char_size));
where = (unsigned short*)(vinfo.v_baseaddr +
(yy * CHARHEIGHT * vinfo.v_rowbytes) +
(xx * 2));
if (!attrs) for (i = 0; i < CHARHEIGHT; i++) {
*where = *theChar++;
where = (unsigned short*)(((unsigned char*)where)+vinfo.v_rowbytes);
} else for (i = 0; i < CHARHEIGHT; i++) {
unsigned short val = *theChar++, save = val;
if (attrs & ATTR_BOLD) {
unsigned short mask1 = 0xF000, mask2 = 0x3000;
int bit = 0;
for (bit = 0; bit < 7; bit++) {
if ((save & mask1) == mask2)
val &= ~mask2;
mask1 >>= 2;
mask2 >>= 2;
}
}
if (attrs & ATTR_REVERSE) val = ~val;
if (attrs & ATTR_UNDER && i == CHARHEIGHT-1) val = ~val;
*where = val;
where = (unsigned short*)(((unsigned char*)where)+vinfo.v_rowbytes);
}
}
static void vc_paint_char4(unsigned char ch, int xx, int yy, int attrs)
{
unsigned long *theChar;
unsigned long *where;
int i;
theChar = (unsigned long*)(renderedFont + (ch * vc_rendered_char_size));
where = (unsigned long*)(vinfo.v_baseaddr +
(yy * CHARHEIGHT * vinfo.v_rowbytes) +
(xx * 4));
if (!attrs) for (i = 0; i < CHARHEIGHT; i++) {
*where = *theChar++;
where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);
} else for (i = 0; i < CHARHEIGHT; i++) {
unsigned long val = *theChar++, save = val;
if (attrs & ATTR_BOLD) {
unsigned long mask1 = 0xff000000, mask2 = 0x0F000000;
int bit = 0;
for (bit = 0; bit < 7; bit++) {
if ((save & mask1) == mask2)
val &= ~mask2;
mask1 >>= 4;
mask2 >>= 4;
}
}
if (attrs & ATTR_REVERSE) val = ~val;
if (attrs & ATTR_UNDER && i == CHARHEIGHT-1) val = ~val;
*where = val;
where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);
}
}
static void vc_paint_char8c(unsigned char ch, int xx, int yy, int attrs)
{
unsigned long *theChar;
unsigned long *where;
int i;
theChar = (unsigned long*)(renderedFont + (ch * vc_rendered_char_size));
where = (unsigned long*)(vinfo.v_baseaddr +
(yy * CHARHEIGHT * vinfo.v_rowbytes) +
(xx * CHARWIDTH));
if (!attrs) for (i = 0; i < CHARHEIGHT; i++) {
unsigned long *store = where;
int x;
for (x = 0; x < 2; x++) {
unsigned long val = *theChar++;
val = (vc_color_back & ~val) | (vc_color_fore & val);
*store++ = val;
}
where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);
} else for (i = 0; i < CHARHEIGHT; i++) {
unsigned long *store = where, lastpixel = 0;
int x;
for (x = 0 ; x < 2; x++) {
unsigned long val = *theChar++, save = val;
if (attrs & ATTR_BOLD) {
if (lastpixel && !(save & 0xFF000000))
val |= 0xff000000;
if ((save & 0xFFFF0000) == 0xFF000000)
val |= 0x00FF0000;
if ((save & 0x00FFFF00) == 0x00FF0000)
val |= 0x0000FF00;
if ((save & 0x0000FFFF) == 0x0000FF00)
val |= 0x000000FF;
}
if (attrs & ATTR_REVERSE) val = ~val;
if (attrs & ATTR_UNDER && i == CHARHEIGHT-1) val = ~val;
val = (vc_color_back & ~val) | (vc_color_fore & val);
*store++ = val;
lastpixel = save & 0xff;
}
where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);
}
}
static void vc_paint_char16c(unsigned char ch, int xx, int yy, int attrs)
{
unsigned long *theChar;
unsigned long *where;
int i;
theChar = (unsigned long*)(renderedFont + (ch * vc_rendered_char_size));
where = (unsigned long*)(vinfo.v_baseaddr +
(yy * CHARHEIGHT * vinfo.v_rowbytes) +
(xx * CHARWIDTH * 2));
if (!attrs) for (i = 0; i < CHARHEIGHT; i++) {
unsigned long *store = where;
int x;
for (x = 0; x < 4; x++) {
unsigned long val = *theChar++;
val = (vc_color_back & ~val) | (vc_color_fore & val);
*store++ = val;
}
where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);
} else for (i = 0; i < CHARHEIGHT; i++) {
unsigned long *store = where, lastpixel = 0;
int x;
for (x = 0 ; x < 4; x++) {
unsigned long val = *theChar++, save = val;
if (attrs & ATTR_BOLD) {
if (save == 0xFFFF0000) val |= 0xFFFF;
else if (lastpixel && !(save & 0xFFFF0000))
val |= 0xFFFF0000;
}
if (attrs & ATTR_REVERSE) val = ~val;
if (attrs & ATTR_UNDER && i == CHARHEIGHT-1) val = ~val;
val = (vc_color_back & ~val) | (vc_color_fore & val);
*store++ = val;
lastpixel = save & 0x7fff;
}
where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);
}
}
static void vc_paint_char32c(unsigned char ch, int xx, int yy, int attrs)
{
unsigned long *theChar;
unsigned long *where;
int i;
theChar = (unsigned long*)(renderedFont + (ch * vc_rendered_char_size));
where = (unsigned long*)(vinfo.v_baseaddr +
(yy * CHARHEIGHT * vinfo.v_rowbytes) +
(xx * CHARWIDTH * 4));
if (!attrs) for (i = 0; i < CHARHEIGHT; i++) {
unsigned long *store = where;
int x;
for (x = 0; x < 8; x++) {
unsigned long val = *theChar++;
val = (vc_color_back & ~val) | (vc_color_fore & val);
*store++ = val;
}
where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);
} else for (i = 0; i < CHARHEIGHT; i++) {
unsigned long *store = where, lastpixel = 0;
int x;
for (x = 0 ; x < 8; x++) {
unsigned long val = *theChar++, save = val;
if (attrs & ATTR_BOLD) {
if (lastpixel && !save)
val = 0xFFFFFFFF;
}
if (attrs & ATTR_REVERSE) val = ~val;
if (attrs & ATTR_UNDER && i == CHARHEIGHT-1) val = ~val;
val = (vc_color_back & ~val) | (vc_color_fore & val);
*store++ = val;
lastpixel = save;
}
where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);
}
}
static void reversecursor(int xx, int yy)
{
union {
unsigned char *charptr;
unsigned short *shortptr;
unsigned long *longptr;
} where;
int line, col;
where.longptr = (unsigned long*)(vinfo.v_baseaddr +
(y * CHARHEIGHT * vinfo.v_rowbytes) +
(x * vinfo.v_depth));
for (line = 0; line < CHARHEIGHT; line++) {
switch (vinfo.v_depth) {
case 1:
*where.charptr = ~*where.charptr;
break;
case 2:
*where.shortptr = ~*where.shortptr;
break;
case 4:
*where.longptr = ~*where.longptr;
break;
#if 1
case 8:
where.longptr[0] = ~where.longptr[0];
where.longptr[1] = ~where.longptr[1];
break;
case 16:
for (col = 0; col < 4; col++)
where.longptr[col] = ~where.longptr[col];
break;
case 32:
for (col = 0; col < 8; col++)
where.longptr[col] = ~where.longptr[col];
break;
#else
case 8:
for (col = 0; col < 8; col++)
where.charptr[col] = where.charptr[col] != (vc_color_fore & vc_color_mask) ?
vc_color_fore & vc_color_mask : vc_color_back & vc_color_mask;
break;
case 16:
for (col = 0; col < 8; col++)
where.shortptr[col] = where.shortptr[col] != (vc_color_fore & vc_color_mask) ?
vc_color_fore & vc_color_mask : vc_color_back & vc_color_mask;
break;
case 32:
for (col = 0; col < 8; col++)
where.longptr[col] = where.longptr[col] != (vc_color_fore & vc_color_mask) ?
vc_color_fore & vc_color_mask : vc_color_back & vc_color_mask;
break;
#endif
}
where.charptr += vinfo.v_rowbytes;
}
}
static void
scrollup(int num)
{
unsigned long *from, *to, linelongs, i, line, rowline, rowscanline;
linelongs = vinfo.v_rowbytes * CHARHEIGHT / 4;
rowline = vinfo.v_rowbytes / 4;
rowscanline = vinfo.v_rowscanbytes / 4;
to = (unsigned long *) vinfo.v_baseaddr + (scrreg_top * linelongs);
from = to + (linelongs * num);
i = (scrreg_bottom - scrreg_top) - num;
while (i-- > 0) {
for (line = 0; line < CHARHEIGHT; line++) {
#if 1
bcopy((unsigned int) from, (unsigned int) to,
vinfo.v_rowscanbytes);
#else
video_scroll_up((unsigned int) from,
(unsigned int) (from+(vinfo.v_rowscanbytes/4)),
(unsigned int) to);
#endif
from += rowline;
to += rowline;
}
}
to = ((unsigned long *) vinfo.v_baseaddr + (scrreg_top * linelongs))
+ ((scrreg_bottom - scrreg_top - num) * linelongs);
for (linelongs = CHARHEIGHT * num; linelongs-- > 0;) {
from = to;
for (i = 0; i < rowscanline; i++)
*to++ = vc_color_back;
to = from + rowline;
}
}
static void
scrolldown(int num)
{
unsigned long *from, *to, linelongs, i, line, rowline, rowscanline;
linelongs = vinfo.v_rowbytes * CHARHEIGHT / 4;
rowline = vinfo.v_rowbytes / 4;
rowscanline = vinfo.v_rowscanbytes / 4;
to = (unsigned long *) vinfo.v_baseaddr + (linelongs * scrreg_bottom)
- (rowline - rowscanline);
from = to - (linelongs * num);
i = (scrreg_bottom - scrreg_top) - num;
while (i-- > 0) {
for (line = 0; line < CHARHEIGHT; line++) {
#if 1
bcopy(from-(vinfo.v_rowscanbytes/4), to,
vinfo.v_rowscanbytes);
#else
video_scroll_down((unsigned int) from,
(unsigned int) (from-(vinfo.v_rowscanbytes/4)),
(unsigned int) to);
#endif
from -= rowline;
to -= rowline;
}
}
to = (unsigned long *) vinfo.v_baseaddr + (linelongs * scrreg_top);
for (line = CHARHEIGHT * num; line > 0; line--) {
from = to;
for (i = 0; i < rowscanline; i++)
*(to++) = vc_color_back;
to = from + rowline;
}
}
static void
clear_line(int which)
{
int start, end, i;
switch (which) {
case 0:
start = x;
end = vinfo.v_columns-1;
break;
case 1:
start = 0;
end = x;
break;
default:
case 2:
start = 0;
end = vinfo.v_columns-1;
break;
}
for (i = start; i <= end; i++) {
vc_ops.paintchar(' ', i, y, ATTR_NONE);
}
}
static void
clear_screen(int xx, int yy, int which)
{
unsigned long *p, *endp, *row;
int linelongs, col;
int rowline, rowlongs;
rowline = vinfo.v_rowscanbytes / 4;
rowlongs = vinfo.v_rowbytes / 4;
p = (unsigned long*) vinfo.v_baseaddr;;
endp = (unsigned long*) vinfo.v_baseaddr;
linelongs = vinfo.v_rowbytes * CHARHEIGHT / 4;
switch (which) {
case 0:
clear_line(0);
if (y < vinfo.v_rows - 1) {
p += (y + 1) * linelongs;
endp += rowlongs * vinfo.v_height;
}
break;
case 1:
clear_line(1);
if (y > 1) {
endp += (y + 1) * linelongs;
}
break;
case 2:
endp += rowlongs * vinfo.v_height;
break;
}
for (row = p ; row < endp ; row += rowlongs) {
for (col = 0; col < rowline; col++)
*(row+col) = vc_color_back;
}
}
static void
reset_tabs(void)
{
int i;
for (i = 0; i<= vinfo.v_columns; i++) {
tab_stops[i] = ((i % 8) == 0);
}
}
static void
vt100_reset(void)
{
reset_tabs();
scrreg_top = 0;
scrreg_bottom = vinfo.v_rows;
attr = ATTR_NONE;
vc_charset[0] = vc_charset[1] = 0;
vc_charset_select = 0;
vc_wrap_mode = 1;
vc_relative_origin = 0;
vc_color_set(VC_RESET_BACKGROUND);
vc_color_set(VC_RESET_FOREGROUND);
}
static void
putc_normal(unsigned char ch)
{
switch (ch) {
case '\a':
{
if ( FALSE && !IS_TEXT_MODE ) {
unsigned long *ptr;
int i, j;
for (i = 0; i < 2 ; i++) {
for (ptr = (unsigned long*)vinfo.v_baseaddr;
ptr < (unsigned long*)(vinfo.v_baseaddr +
(vinfo.v_height * vinfo.v_rowbytes));
ptr += (vinfo.v_rowbytes /
sizeof (unsigned long*)))
for (j = 0;
j < vinfo.v_rowscanbytes /
sizeof (unsigned long*);
j++)
*(ptr+j) =~*(ptr+j);
}
}
}
break;
case 127:
case '\b':
if (hanging_cursor) {
hanging_cursor = 0;
} else
if (x > 0) {
x--;
}
break;
case '\t':
while (x < vinfo.v_columns && !tab_stops[++x]);
if (x >= vinfo.v_columns)
x = vinfo.v_columns-1;
break;
case 0x0b:
case 0x0c:
case '\n':
if (y >= scrreg_bottom -1 ) {
vc_ops.scrollup(1);
y = scrreg_bottom - 1;
} else {
y++;
}
case '\r':
x = 0;
hanging_cursor = 0;
break;
case 0x0e:
vc_charset_select = 1;
break;
case 0x0f:
vc_charset_select = 0;
break;
case 0x18 :
case 0x1A :
break;
case '\033':
vt100state = ESesc;
hanging_cursor = 0;
break;
default:
if (ch >= ' ') {
if (hanging_cursor) {
x = 0;
if (y >= scrreg_bottom -1 ) {
vc_ops.scrollup(1);
y = scrreg_bottom - 1;
} else {
y++;
}
hanging_cursor = 0;
}
vc_ops.paintchar((ch >= 0x60 && ch <= 0x7f) ? ch + vc_charset[vc_charset_select]
: ch, x, y, attr);
if (x == vinfo.v_columns - 1) {
hanging_cursor = vc_wrap_mode;
} else {
x++;
}
}
break;
}
}
static void
putc_esc(unsigned char ch)
{
vt100state = ESnormal;
switch (ch) {
case '[':
vt100state = ESsquare;
break;
case 'c':
vt100_reset();
vc_ops.clear_screen(x, y, 2);
x = y = 0;
break;
case 'D':
case 'E':
if (y >= scrreg_bottom -1) {
vc_ops.scrollup(1);
y = scrreg_bottom - 1;
} else {
y++;
}
if (ch == 'E') x = 0;
break;
case 'H':
tab_stops[x] = 1;
break;
case 'M':
if (y <= scrreg_top) {
vc_ops.scrolldown(1);
y = scrreg_top;
} else {
y--;
}
break;
case '>':
vt100_reset();
break;
case '7':
savex = x;
savey = y;
saveattr = attr;
vc_save_charset_s = vc_charset_select;
vc_charset_save[0] = vc_charset[0];
vc_charset_save[1] = vc_charset[1];
break;
case '8':
x = savex;
y = savey;
attr = saveattr;
vc_charset_select = vc_save_charset_s;
vc_charset[0] = vc_charset_save[0];
vc_charset[1] = vc_charset_save[1];
break;
case 'Z':
break;
case '#':
vt100state = EScharsize;
break;
case '(':
vt100state = ESsetG0;
break;
case ')':
vt100state = ESsetG1;
break;
case '=':
break;
default:
break;
}
}
static void
putc_askcmd(unsigned char ch)
{
if (ch >= '0' && ch <= '9') {
par[numpars] = (10*par[numpars]) + (ch-'0');
return;
}
vt100state = ESnormal;
switch (par[0]) {
case 6:
vc_relative_origin = ch == 'h';
break;
case 7:
vc_wrap_mode = ch == 'h';
break;
default:
break;
}
}
static void
putc_charsizecmd(unsigned char ch)
{
vt100state = ESnormal;
switch (ch) {
case '3' :
case '4' :
case '5' :
case '6' :
break;
case '8' :
{
int xx, yy;
for (yy = 0; yy < vinfo.v_rows; yy++)
for (xx = 0; xx < vinfo.v_columns; xx++)
vc_ops.paintchar('E', xx, yy, ATTR_NONE);
}
break;
}
}
static void
putc_charsetcmd(int charset, unsigned char ch)
{
vt100state = ESnormal;
switch (ch) {
case 'A' :
case 'B' :
default:
vc_charset[charset] = 0;
break;
case '0' :
case '2' :
vc_charset[charset] = 0x21;
break;
}
}
static void
putc_gotpars(unsigned char ch)
{
int i;
if (ch < ' ') {
putc_normal(ch);
vt100state = ESgotpars;
return;
}
vt100state = ESnormal;
switch (ch) {
case 'A':
y -= par[0] ? par[0] : 1;
if (y < scrreg_top)
y = scrreg_top;
break;
case 'B':
y += par[0] ? par[0] : 1;
if (y >= scrreg_bottom)
y = scrreg_bottom - 1;
break;
case 'C':
x += par[0] ? par[0] : 1;
if (x >= vinfo.v_columns)
x = vinfo.v_columns-1;
break;
case 'D':
x -= par[0] ? par[0] : 1;
if (x < 0)
x = 0;
break;
case 'H':
case 'f':
x = par[1] ? par[1] - 1 : 0;
y = par[0] ? par[0] - 1 : 0;
if (vc_relative_origin)
y += scrreg_top;
hanging_cursor = 0;
break;
case 'X':
if (numpars) {
int i;
for (i = x; i < x + par[0]; i++)
vc_ops.paintchar(' ', i, y, ATTR_NONE);
}
break;
case 'J':
vc_ops.clear_screen(x, y, par[0]);
break;
case 'K':
clear_line(par[0]);
break;
case 'g':
switch (par[0]) {
case 1:
case 2:
break;
case 3:
{
int i;
for (i = 0; i <= vinfo.v_columns; i++)
tab_stops[i] = 0;
}
break;
case 0:
tab_stops[x] = 0;
break;
}
break;
case 'm':
for (i = 0; i < numpars; i++) {
switch (par[i]) {
case 0:
attr = ATTR_NONE;
vc_color_set(VC_RESET_BACKGROUND);
vc_color_set(VC_RESET_FOREGROUND);
break;
case 1:
attr |= ATTR_BOLD;
break;
case 4:
attr |= ATTR_UNDER;
break;
case 7:
attr |= ATTR_REVERSE;
break;
case 22:
attr &= ~ATTR_BOLD;
break;
case 24:
attr &= ~ATTR_UNDER;
break;
case 27:
attr &= ~ATTR_REVERSE;
break;
case 5:
case 25:
break;
default:
vc_color_set(par[i]);
break;
}
}
break;
case 'r':
x = y = 0;
if ((numpars > 0) && (par[0] < vinfo.v_rows)) {
scrreg_top = par[0] ? par[0] - 1 : 0;
if (scrreg_top < 0)
scrreg_top = 0;
} else {
scrreg_top = 0;
}
if ((numpars > 1) && (par[1] <= vinfo.v_rows) && (par[1] > par[0])) {
scrreg_bottom = par[1];
if (scrreg_bottom > vinfo.v_rows)
scrreg_bottom = vinfo.v_rows;
} else {
scrreg_bottom = vinfo.v_rows;
}
if (vc_relative_origin)
y = scrreg_top;
break;
}
}
static void
putc_getpars(unsigned char ch)
{
if (ch == '?') {
vt100state = ESask;
return;
}
if (ch == '[') {
vt100state = ESnormal;
return;
}
if (ch == ';' && numpars < MAXPARS - 1) {
numpars++;
} else
if (ch >= '0' && ch <= '9') {
par[numpars] *= 10;
par[numpars] += ch - '0';
} else {
numpars++;
vt100state = ESgotpars;
putc_gotpars(ch);
}
}
static void
putc_square(unsigned char ch)
{
int i;
for (i = 0; i < MAXPARS; i++) {
par[i] = 0;
}
numpars = 0;
vt100state = ESgetpars;
putc_getpars(ch);
}
void
vc_putchar(char ch)
{
if (!ch) {
return;
}
switch (vt100state) {
default:vt100state = ESnormal;
case ESnormal:
putc_normal(ch);
break;
case ESesc:
putc_esc(ch);
break;
case ESsquare:
putc_square(ch);
break;
case ESgetpars:
putc_getpars(ch);
break;
case ESgotpars:
putc_gotpars(ch);
break;
case ESask:
putc_askcmd(ch);
break;
case EScharsize:
putc_charsizecmd(ch);
break;
case ESsetG0:
putc_charsetcmd(0, ch);
break;
case ESsetG1:
putc_charsetcmd(1, ch);
break;
}
if (x >= vinfo.v_columns) {
x = vinfo.v_columns - 1;
}
if (x < 0) {
x = 0;
}
if (y >= vinfo.v_rows) {
y = vinfo.v_rows - 1;
}
if (y < 0) {
y = 0;
}
}
void vc_flush_forward_buffer(void)
{
if (vc_forward_buffer_size) {
int start = 0;
vc_ops.hide_cursor(x, y);
do {
int i;
int plaintext = 1;
int drawlen = start;
int jump = 0;
int param = 0, changebackground = 0;
enum vt100state_e vtState = vt100state;
for (i = start; i < vc_forward_buffer_size && plaintext; i++) {
drawlen++;
switch (vtState) {
case ESnormal:
switch (vc_forward_buffer[i]) {
case '\033':
vtState = ESesc;
break;
case '\n':
jump++;
break;
}
break;
case ESesc:
switch (vc_forward_buffer[i]) {
case '[':
vtState = ESgetpars;
param = 0;
changebackground = 0;
break;
default:
plaintext = 0;
break;
}
break;
case ESgetpars:
if ((vc_forward_buffer[i] >= '0' &&
vc_forward_buffer[i] <= '9') ||
vc_forward_buffer[i] == ';') {
if (vc_forward_buffer[i] >= '0' &&
vc_forward_buffer[i] <= '9')
param = (param*10)+(vc_forward_buffer[i]-'0');
else {
if (param >= 40 && param <= 47)
changebackground = 1;
if (!vc_normal_background &&
!param)
changebackground = 1;
param = 0;
}
break;
}
vtState = ESgotpars;
case ESgotpars:
switch (vc_forward_buffer[i]) {
case 'm':
vtState = ESnormal;
if (param >= 40 && param <= 47)
changebackground = 1;
if (!vc_normal_background &&
!param)
changebackground = 1;
if (changebackground) {
plaintext = 0;
jump = 0;
}
break;
default:
plaintext = 0;
break;
}
break;
default:
plaintext = 0;
break;
}
}
if (jump && (scrreg_bottom - scrreg_top) > 2) {
jump -= scrreg_bottom - y - 1;
if (jump > 0 ) {
if (jump >= scrreg_bottom - scrreg_top)
jump = scrreg_bottom - scrreg_top -1;
y -= jump;
vc_ops.scrollup(jump);
}
}
for (i = start; i < drawlen; i++)
vc_putchar(vc_forward_buffer[start++]);
for (i = start; i < vc_forward_buffer_size &&
vt100state != ESnormal ; i++)
vc_putchar(vc_forward_buffer[start++]);
} while (start < vc_forward_buffer_size);
vc_forward_buffer_size = 0;
vc_ops.show_cursor(x, y);
}
}
int
vcputc(int l, int u, int c)
{
if ( vc_initialized )
{
vc_store_char(c);
vc_flush_forward_buffer();
}
return 0;
}
void cnputc(char ch)
{
vcputc(0, 0, ch);
}
void
vc_store_char(unsigned char c)
{
vc_forward_buffer[vc_forward_buffer_size++] = (unsigned char)c;
switch (vc_forward_buffer_size) {
case 1:
break;
case VC_MAX_FORWARD_SIZE:
vc_flush_forward_buffer();
break;
default:
break;
}
}
static void
vc_initialize(struct vc_info * vinfo_p)
{
vinfo.v_rows = vinfo.v_height / CHARHEIGHT;
vinfo.v_columns = vinfo.v_width / CHARWIDTH;
if (vinfo.v_depth >= 8) {
vinfo.v_rowscanbytes = (vinfo.v_depth / 8) * vinfo.v_width;
} else {
vinfo.v_rowscanbytes = vinfo.v_width / (8 / vinfo.v_depth);
}
vc_render_font(1, vinfo.v_depth);
vc_color_mask = vc_color_depth_masks[vc_color_index_table[vinfo.v_depth]];
vt100_reset();
switch (vinfo.v_depth) {
default:
case 1:
vc_ops.paintchar = vc_paint_char1;
break;
case 2:
vc_ops.paintchar = vc_paint_char2;
break;
case 4:
vc_ops.paintchar = vc_paint_char4;
break;
case 8:
vc_ops.paintchar = vc_paint_char8c;
break;
case 16:
vc_ops.paintchar = vc_paint_char16c;
break;
case 32:
vc_ops.paintchar = vc_paint_char32c;
break;
}
}
void
vcattach(void)
{
if (vinfo.v_depth >= 8)
printf("\033[31mC\033[32mO\033[33mL\033[34mO\033[35mR\033[0m ");
printf("video console at 0x%lx (%ldx%ldx%ld)\n", vinfo.v_baseaddr,
vinfo.v_width, vinfo.v_height, vinfo.v_depth);
#if 0 // XXX - FIXME
simple_lock_init(&vc_forward_lock, ETAP_IO_TTY);
vc_forward_buffer_enabled = 1;
#else // FIXME TOO!!!
simple_lock_init(&vc_forward_lock, ETAP_IO_TTY);
#endif
}
struct vc_progress_element {
unsigned int version;
unsigned int flags;
unsigned int time;
unsigned char count;
unsigned char res[3];
int width;
int height;
int dx;
int dy;
int transparent;
unsigned int res2[3];
unsigned char data[0];
};
typedef struct vc_progress_element vc_progress_element;
static vc_progress_element * vc_progress;
static const unsigned char * vc_progress_data;
static const unsigned char * vc_progress_alpha;
static boolean_t vc_progress_enable;
static const unsigned char * vc_clut;
static const unsigned char * vc_clut8;
static unsigned int vc_progress_tick;
static boolean_t vc_graphics_mode;
static boolean_t vc_acquired;
static boolean_t vc_need_clear;
static boolean_t vc_needsave;
static vm_address_t vc_saveunder;
static vm_size_t vc_saveunder_len;
void vc_blit_rect_8c( int x, int y,
int width, int height,
const unsigned char * dataPtr, const unsigned char * alphaPtr,
unsigned char * backPtr, boolean_t save )
{
volatile unsigned char * dst;
int line, col;
unsigned char data;
dst = (unsigned char *)(vinfo.v_baseaddr +
(y * vinfo.v_rowbytes) +
(x));
dst = (unsigned char *)(vinfo.v_baseaddr +
(y * vinfo.v_rowbytes) +
(x));
for( line = 0; line < height; line++) {
for( col = 0; col < width; col++)
*(dst + col) = *dataPtr++;
dst = (volatile unsigned char *) (((int)dst) + vinfo.v_rowbytes);
}
}
void vc_blit_rect_16( int x, int y,
int width, int height,
const unsigned char * dataPtr, const unsigned char * alphaPtr,
unsigned short * backPtr, boolean_t save )
{
volatile unsigned short * dst;
int line, col;
unsigned int data, index, alpha, back;
dst = (volatile unsigned short *)(vinfo.v_baseaddr +
(y * vinfo.v_rowbytes) +
(x * 2));
for( line = 0; line < height; line++) {
for( col = 0; col < width; col++) {
index = *dataPtr++;
index *= 3;
if( alphaPtr && backPtr && (alpha = *alphaPtr++)) {
data = 0;
if( vc_clut[index + 0] > alpha)
data |= (((vc_clut[index + 0] - alpha) & 0xf8) << 7);
if( vc_clut[index + 1] > alpha)
data |= (((vc_clut[index + 1] - alpha) & 0xf8) << 2);
if( vc_clut[index + 2] > alpha)
data |= (((vc_clut[index + 2] - alpha) & 0xf8) >> 3);
if( save) {
back = *(dst + col);
alpha >>= 3;
back = (((((back & 0x7c1f) * alpha) + 0x7c1f) >> 5) & 0x7c1f)
| (((((back & 0x03e0) * alpha) + 0x03e0) >> 5) & 0x03e0);
*backPtr++ = back;
} else
back = *backPtr++;
data += back;
} else
data = ( (0xf8 & (vc_clut[index + 0])) << 7)
| ( (0xf8 & (vc_clut[index + 1])) << 2)
| ( (0xf8 & (vc_clut[index + 2])) >> 3);
*(dst + col) = data;
}
dst = (volatile unsigned short *) (((int)dst) + vinfo.v_rowbytes);
}
}
void vc_blit_rect_32( unsigned int x, unsigned int y,
unsigned int width, unsigned int height,
const unsigned char * dataPtr, const unsigned char * alphaPtr,
unsigned int * backPtr, boolean_t save )
{
volatile unsigned int * dst;
int line, col;
unsigned int data, index, alpha, back;
dst = (volatile unsigned int *) (vinfo.v_baseaddr +
(y * vinfo.v_rowbytes) +
(x * 4));
for( line = 0; line < height; line++) {
for( col = 0; col < width; col++) {
index = *dataPtr++;
index *= 3;
if( alphaPtr && backPtr && (alpha = *alphaPtr++)) {
data = 0;
if( vc_clut[index + 0] > alpha)
data |= ((vc_clut[index + 0] - alpha) << 16);
if( vc_clut[index + 1] > alpha)
data |= ((vc_clut[index + 1] - alpha) << 8);
if( vc_clut[index + 2] > alpha)
data |= ((vc_clut[index + 2] - alpha));
if( save) {
back = *(dst + col);
back = (((((back & 0x00ff00ff) * alpha) + 0x00ff00ff) >> 8) & 0x00ff00ff)
| (((((back & 0x0000ff00) * alpha) + 0x0000ff00) >> 8) & 0x0000ff00);
*backPtr++ = back;
} else
back = *backPtr++;
data += back;
} else
data = (vc_clut[index + 0] << 16)
| (vc_clut[index + 1] << 8)
| (vc_clut[index + 2]);
*(dst + col) = data;
}
dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes);
}
}
void vc_blit_rect( unsigned int x, unsigned int y,
unsigned int width, unsigned int height,
const unsigned char * dataPtr, const unsigned char * alphaPtr,
vm_address_t backBuffer, boolean_t save )
{
if(!vinfo.v_baseaddr)
return;
switch( vinfo.v_depth) {
case 8:
if( vc_clut8 == vc_clut)
vc_blit_rect_8c( x, y, width, height, dataPtr, alphaPtr, (unsigned char *) backBuffer, save );
break;
case 16:
vc_blit_rect_16( x, y, width, height, dataPtr, alphaPtr, (unsigned short *) backBuffer, save );
break;
case 32:
vc_blit_rect_32( x, y, width, height, dataPtr, alphaPtr, (unsigned int *) backBuffer, save );
break;
}
}
void vc_progress_task( void * arg )
{
spl_t s;
int count = (int) arg;
int x, y, width, height;
const unsigned char * data;
s = splhigh();
simple_lock(&vc_forward_lock);
if( vc_progress_enable) {
count++;
if( count >= vc_progress->count)
count = 0;
width = vc_progress->width;
height = vc_progress->height;
x = vc_progress->dx;
y = vc_progress->dy;
data = vc_progress_data;
data += count * width * height;
if( 1 & vc_progress->flags) {
x += ((vinfo.v_width - width) / 2);
y += ((vinfo.v_height - height) / 2);
}
vc_blit_rect( x, y, width, height,
data, vc_progress_alpha, vc_saveunder, vc_needsave );
vc_needsave = FALSE;
timeout( vc_progress_task, (void *) count,
vc_progress_tick );
}
simple_unlock(&vc_forward_lock);
splx(s);
}
void vc_display_icon( vc_progress_element * desc,
const unsigned char * data )
{
int x, y, width, height;
if( vc_acquired && vc_graphics_mode && vc_clut) {
width = desc->width;
height = desc->height;
x = desc->dx;
y = desc->dy;
if( 1 & desc->flags) {
x += ((vinfo.v_width - width) / 2);
y += ((vinfo.v_height - height) / 2);
}
vc_blit_rect( x, y, width, height, data, NULL, (vm_address_t) NULL, FALSE );
}
}
boolean_t
vc_progress_set( boolean_t enable, unsigned int initial_tick )
{
spl_t s;
vm_address_t saveBuf = 0;
vm_size_t saveLen = 0;
if( !vc_progress)
return( FALSE );
if( enable) {
saveLen = vc_progress->width * vc_progress->height * vinfo.v_depth / 8;
saveBuf = kalloc( saveLen );
}
s = splhigh();
simple_lock(&vc_forward_lock);
if( vc_progress_enable != enable) {
vc_progress_enable = enable;
if( enable) {
vc_needsave = TRUE;
vc_saveunder = saveBuf;
vc_saveunder_len = saveLen;
saveBuf = 0;
saveLen = 0;
timeout(vc_progress_task, (void *) 0,
initial_tick );
}
else {
if( vc_saveunder) {
saveBuf = vc_saveunder;
saveLen = vc_saveunder_len;
vc_saveunder = 0;
vc_saveunder_len = 0;
}
untimeout( vc_progress_task, (void *) 0 );
}
}
simple_unlock(&vc_forward_lock);
splx(s);
if( saveBuf)
kfree( saveBuf, saveLen );
return( TRUE );
}
boolean_t
vc_progress_initialize( vc_progress_element * desc,
const unsigned char * data,
const unsigned char * clut )
{
if( (!clut) || (!desc) || (!data))
return( FALSE );
vc_clut = clut;
vc_clut8 = clut;
vc_progress = desc;
vc_progress_data = data;
if( 2 & vc_progress->flags)
vc_progress_alpha = vc_progress_data
+ vc_progress->count * vc_progress->width * vc_progress->height;
else
vc_progress_alpha = NULL;
vc_progress_tick = vc_progress->time * hz / 1000;
return( TRUE );
}
extern int disableConsoleOutput;
void vc_clear_screen( void )
{
vc_ops.hide_cursor(x, y);
vt100_reset();
x = y = 0;
vc_ops.clear_screen(x, y, 2);
vc_ops.show_cursor(x, y);
};
void
initialize_screen(Boot_Video * boot_vinfo, int op)
{
if ( boot_vinfo )
{
vinfo.v_width = boot_vinfo->v_width;
vinfo.v_height = boot_vinfo->v_height;
vinfo.v_depth = boot_vinfo->v_depth;
vinfo.v_rowbytes = boot_vinfo->v_rowBytes;
vinfo.v_baseaddr = boot_vinfo->v_baseAddr;
vinfo.v_type = boot_vinfo->v_display;
if ( IS_TEXT_MODE )
{
vc_ops.initialize = tc_initialize;
vc_ops.paintchar = tc_putchar;
vc_ops.scrolldown = tc_scrolldown;
vc_ops.scrollup = tc_scrollup;
vc_ops.clear_screen = tc_clear_screen;
vc_ops.hide_cursor = tc_hide_cursor;
vc_ops.show_cursor = tc_show_cursor;
vc_ops.update_color = tc_update_color;
}
else
{
vc_ops.initialize = vc_initialize;
vc_ops.paintchar = 0;
vc_ops.scrolldown = scrolldown;
vc_ops.scrollup = scrollup;
vc_ops.clear_screen = clear_screen;
vc_ops.hide_cursor = reversecursor;
vc_ops.show_cursor = reversecursor;
vc_ops.update_color = 0;
}
vc_ops.initialize(&vinfo);
vc_initialized = 1;
}
switch ( op ) {
case kPEGraphicsMode:
vc_graphics_mode = TRUE;
disableConsoleOutput = TRUE;
vc_acquired = TRUE;
break;
case kPETextMode:
vc_graphics_mode = FALSE;
disableConsoleOutput = FALSE;
vc_acquired = TRUE;
vc_clear_screen();
break;
case kPETextScreen:
vc_progress_set( FALSE, 0 );
disableConsoleOutput = FALSE;
if( vc_need_clear) {
vc_need_clear = FALSE;
vc_clear_screen();
}
break;
case kPEEnableScreen:
if ( vc_acquired) {
if( vc_graphics_mode)
vc_progress_set( TRUE, vc_progress_tick );
else
vc_clear_screen();
}
break;
case kPEDisableScreen:
vc_progress_set( FALSE, 0 );
break;
case kPEAcquireScreen:
vc_need_clear = (FALSE == vc_acquired);
vc_acquired = TRUE;
vc_progress_set( vc_graphics_mode, vc_need_clear ? 2 * hz : 0 );
disableConsoleOutput = vc_graphics_mode;
if( vc_need_clear && !vc_graphics_mode) {
vc_need_clear = FALSE;
vc_clear_screen();
}
break;
case kPEReleaseScreen:
vc_acquired = FALSE;
vc_progress_set( FALSE, 0 );
vc_clut8 = NULL;
disableConsoleOutput = TRUE;
break;
}
}