Changeset View
Changeset View
Standalone View
Standalone View
stand/i386/libi386/vidconsole.c
Show All 25 Lines | |||||
* | * | ||||
* Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp | * Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <stand.h> | #include <stand.h> | ||||
#include <sys/param.h> | |||||
#include <bootstrap.h> | #include <bootstrap.h> | ||||
#include <btxv86.h> | #include <btxv86.h> | ||||
#include <machine/psl.h> | #include <gfx_fb.h> | ||||
#include <machine/cpufunc.h> | |||||
#include <teken.h> | #include <teken.h> | ||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include "vbe.h" | |||||
#include <dev/vt/hw/vga/vt_vga_reg.h> | #include <dev/vt/hw/vga/vt_vga_reg.h> | ||||
#include "libi386.h" | #include "libi386.h" | ||||
#if KEYBOARD_PROBE | #if KEYBOARD_PROBE | ||||
static int probe_keyboard(void); | static int probe_keyboard(void); | ||||
#endif | #endif | ||||
static void vidc_probe(struct console *cp); | static void vidc_probe(struct console *cp); | ||||
static int vidc_init(int arg); | static int vidc_init(int arg); | ||||
static void vidc_putchar(int c); | static void vidc_putchar(int c); | ||||
static int vidc_getchar(void); | static int vidc_getchar(void); | ||||
static int vidc_ischar(void); | static int vidc_ischar(void); | ||||
static void cons_draw_frame(teken_attr_t *); | |||||
static int vidc_started; | static int vidc_started; | ||||
static uint16_t *vgatext; | static uint16_t *vgatext; | ||||
static tf_bell_t vidc_cons_bell; | static tf_bell_t vidc_cons_bell; | ||||
static tf_cursor_t vidc_text_cursor; | static tf_cursor_t vidc_text_cursor; | ||||
static tf_cursor_t vidc_gfx_cursor; | |||||
static tf_putchar_t vidc_text_putchar; | static tf_putchar_t vidc_text_putchar; | ||||
static tf_putchar_t vidc_gfx_putchar; | |||||
static tf_fill_t vidc_text_fill; | static tf_fill_t vidc_text_fill; | ||||
static tf_fill_t vidc_gfx_fill; | |||||
static tf_copy_t vidc_text_copy; | static tf_copy_t vidc_text_copy; | ||||
static tf_copy_t vidc_gfx_copy; | |||||
static tf_param_t vidc_text_param; | static tf_param_t vidc_text_param; | ||||
static tf_param_t vidc_gfx_param; | |||||
static tf_respond_t vidc_cons_respond; | static tf_respond_t vidc_cons_respond; | ||||
static teken_funcs_t tf = { | static teken_funcs_t tf = { | ||||
.tf_bell = vidc_cons_bell, | .tf_bell = vidc_cons_bell, | ||||
.tf_cursor = vidc_text_cursor, | .tf_cursor = vidc_text_cursor, | ||||
.tf_putchar = vidc_text_putchar, | .tf_putchar = vidc_text_putchar, | ||||
.tf_fill = vidc_text_fill, | .tf_fill = vidc_text_fill, | ||||
.tf_copy = vidc_text_copy, | .tf_copy = vidc_text_copy, | ||||
.tf_param = vidc_text_param, | .tf_param = vidc_text_param, | ||||
.tf_respond = vidc_cons_respond, | .tf_respond = vidc_cons_respond, | ||||
}; | }; | ||||
teken_t teken; | static teken_funcs_t tfx = { | ||||
teken_pos_t tp; | .tf_bell = vidc_cons_bell, | ||||
.tf_cursor = vidc_gfx_cursor, | |||||
.tf_putchar = vidc_gfx_putchar, | |||||
.tf_fill = vidc_gfx_fill, | |||||
.tf_copy = vidc_gfx_copy, | |||||
.tf_param = vidc_gfx_param, | |||||
.tf_respond = vidc_cons_respond, | |||||
}; | |||||
struct text_pixel { | struct text_pixel { | ||||
teken_char_t c; | teken_char_t c; | ||||
teken_attr_t a; | teken_attr_t a; | ||||
}; | }; | ||||
static struct text_pixel *buffer; | static struct text_pixel *buffer; | ||||
#define NCOLORS 16 | |||||
/* | |||||
* Between console's palette and VGA's one: | |||||
* - blue and red are swapped (1 <-> 4) | |||||
* - yellow and cyan are swapped (3 <-> 6) | |||||
*/ | |||||
static const int cons_to_vga_colors[NCOLORS] = { | |||||
0, 4, 2, 6, 1, 5, 3, 7, | |||||
8, 12, 10, 14, 9, 13, 11, 15 | |||||
}; | |||||
#define TEXT_COLS 80 | |||||
#define TEXT_ROWS 25 | |||||
#define KEYBUFSZ 10 | #define KEYBUFSZ 10 | ||||
static uint8_t keybuf[KEYBUFSZ]; /* keybuf for extended codes */ | static uint8_t keybuf[KEYBUFSZ]; /* keybuf for extended codes */ | ||||
struct console vidconsole = { | struct console vidconsole = { | ||||
.c_name = "vidconsole", | .c_name = "vidconsole", | ||||
.c_desc = "internal video/keyboard", | .c_desc = "internal video/keyboard", | ||||
.c_flags = 0, | .c_flags = 0, | ||||
.c_probe = vidc_probe, | .c_probe = vidc_probe, | ||||
.c_init = vidc_init, | .c_init = vidc_init, | ||||
.c_out = vidc_putchar, | .c_out = vidc_putchar, | ||||
.c_in = vidc_getchar, | .c_in = vidc_getchar, | ||||
.c_ready = vidc_ischar | .c_ready = vidc_ischar | ||||
}; | }; | ||||
static int | /* | ||||
vga_get_reg(int reg, int index) | * This function is used to mark a rectangular image area so the scrolling | ||||
* will know we need to copy the data from there. | |||||
*/ | |||||
void | |||||
term_image_display(teken_gfx_t *state, const teken_rect_t *r) | |||||
{ | { | ||||
return (inb(reg + index)); | teken_pos_t p; | ||||
} | int idx; | ||||
static int | for (p.tp_row = r->tr_begin.tp_row; | ||||
vga_get_atr(int reg, int i) | p.tp_row < r->tr_end.tp_row; p.tp_row++) { | ||||
{ | for (p.tp_col = r->tr_begin.tp_col; | ||||
int ret; | p.tp_col < r->tr_end.tp_col; p.tp_col++) { | ||||
idx = p.tp_col + p.tp_row * state->tg_tp.tp_col; | |||||
(void) inb(reg + VGA_GEN_INPUT_STAT_1); | if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row) | ||||
outb(reg + VGA_AC_WRITE, i); | return; | ||||
ret = inb(reg + VGA_AC_READ); | buffer[idx].a.ta_format |= TF_IMAGE; | ||||
(void) inb(reg + VGA_GEN_INPUT_STAT_1); | |||||
return (ret); | |||||
} | } | ||||
static void | |||||
vga_set_atr(int reg, int i, int v) | |||||
{ | |||||
(void) inb(reg + VGA_GEN_INPUT_STAT_1); | |||||
outb(reg + VGA_AC_WRITE, i); | |||||
outb(reg + VGA_AC_WRITE, v); | |||||
(void) inb(reg + VGA_GEN_INPUT_STAT_1); | |||||
} | } | ||||
static void | |||||
vga_set_indexed(int reg, int indexreg, int datareg, uint8_t index, uint8_t val) | |||||
{ | |||||
outb(reg + indexreg, index); | |||||
outb(reg + datareg, val); | |||||
} | } | ||||
static int | |||||
vga_get_indexed(int reg, int indexreg, int datareg, uint8_t index) | |||||
{ | |||||
outb(reg + indexreg, index); | |||||
return (inb(reg + datareg)); | |||||
} | |||||
static int | |||||
vga_get_crtc(int reg, int i) | |||||
{ | |||||
return (vga_get_indexed(reg, VGA_CRTC_ADDRESS, VGA_CRTC_DATA, i)); | |||||
} | |||||
static void | static void | ||||
vga_set_crtc(int reg, int i, int v) | |||||
{ | |||||
vga_set_indexed(reg, VGA_CRTC_ADDRESS, VGA_CRTC_DATA, i, v); | |||||
} | |||||
static void | |||||
vidc_text_set_cursor(teken_unit_t row, teken_unit_t col, bool visible) | vidc_text_set_cursor(teken_unit_t row, teken_unit_t col, bool visible) | ||||
{ | { | ||||
uint16_t addr; | uint16_t addr; | ||||
uint8_t msl, s, e; | uint8_t msl, s, e; | ||||
msl = vga_get_crtc(VGA_REG_BASE, VGA_CRTC_MAX_SCAN_LINE) & 0x1f; | msl = vga_get_crtc(VGA_REG_BASE, VGA_CRTC_MAX_SCAN_LINE) & 0x1f; | ||||
s = vga_get_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_START) & 0xC0; | s = vga_get_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_START) & 0xC0; | ||||
e = vga_get_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_END); | e = vga_get_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_END); | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | vidc_text_cursor(void *s __unused, const teken_pos_t *p) | ||||
if (p->tp_row == TEXT_ROWS) | if (p->tp_row == TEXT_ROWS) | ||||
row = p->tp_row - 1; | row = p->tp_row - 1; | ||||
else | else | ||||
row = p->tp_row; | row = p->tp_row; | ||||
vidc_text_set_cursor(row, col, true); | vidc_text_set_cursor(row, col, true); | ||||
} | } | ||||
static void | |||||
vidc_gfx_cursor_draw(teken_gfx_t *state, const teken_pos_t *p) | |||||
{ | |||||
struct text_pixel *px; | |||||
uint32_t fg, bg; | |||||
px = buffer + p->tp_col + p->tp_row * state->tg_tp.tp_col; | |||||
fg = px->a.ta_fgcolor; | |||||
bg = px->a.ta_bgcolor; | |||||
if (px->a.ta_format & TF_BOLD) | |||||
fg |= TC_LIGHT; | |||||
if (px->a.ta_format & TF_BLINK) | |||||
bg |= TC_LIGHT; | |||||
fg = cmap[fg]; | |||||
bg = cmap[bg]; | |||||
if (px->a.ta_format & TF_REVERSE) { | |||||
uint32_t tmp; | |||||
tmp = fg; | |||||
fg = bg; | |||||
bg = tmp; | |||||
} | |||||
state->tg_cursor = *p; | |||||
gfx_bm_cursor_draw(state, p, fg, bg); | |||||
} | |||||
static void | |||||
vidc_gfx_cursor(void *arg, const teken_pos_t *p) | |||||
{ | |||||
teken_gfx_t *state = arg; | |||||
/* Switch cursor off in old location and back on in new. */ | |||||
if (state->tg_cursor_visible) { | |||||
vidc_gfx_cursor_draw(state, &state->tg_cursor); | |||||
vidc_gfx_cursor_draw(state, p); | |||||
} | |||||
} | |||||
/* | /* | ||||
* Binary searchable table for Unicode to CP437 conversion. | * Binary searchable table for Unicode to CP437 conversion. | ||||
*/ | */ | ||||
struct unicp437 { | struct unicp437 { | ||||
uint16_t unicode_base; | uint16_t unicode_base; | ||||
uint8_t cp437_base; | uint8_t cp437_base; | ||||
uint8_t length; | uint8_t length; | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | else | ||||
return (c - cp437table[mid].unicode_base + | return (c - cp437table[mid].unicode_base + | ||||
cp437table[mid].cp437_base); | cp437table[mid].cp437_base); | ||||
} | } | ||||
return ('?'); | return ('?'); | ||||
} | } | ||||
static void | static void | ||||
vidc_text_printchar(const teken_pos_t *p) | vidc_text_printchar(teken_gfx_t *state, const teken_pos_t *p) | ||||
{ | { | ||||
int i; | int idx; | ||||
uint8_t attr; | uint8_t attr; | ||||
struct text_pixel *px; | struct text_pixel *px; | ||||
teken_color_t fg, bg, tmp; | teken_color_t fg, bg, tmp; | ||||
struct cgatext { | struct cgatext { | ||||
uint8_t ch; | uint8_t ch; | ||||
uint8_t attr; | uint8_t attr; | ||||
} *addr; | } *addr; | ||||
px = buffer + p->tp_col + p->tp_row * tp.tp_col; | idx = p->tp_col + p->tp_row * state->tg_tp.tp_col; | ||||
px = &buffer[idx]; | |||||
fg = teken_256to16(px->a.ta_fgcolor); | fg = teken_256to16(px->a.ta_fgcolor); | ||||
bg = teken_256to16(px->a.ta_bgcolor); | bg = teken_256to16(px->a.ta_bgcolor); | ||||
if (px->a.ta_format & TF_BOLD) | if (px->a.ta_format & TF_BOLD) | ||||
fg |= TC_LIGHT; | fg |= TC_LIGHT; | ||||
if (px->a.ta_format & TF_BLINK) | if (px->a.ta_format & TF_BLINK) | ||||
bg |= TC_LIGHT; | bg |= TC_LIGHT; | ||||
if (px->a.ta_format & TF_REVERSE) { | if (px->a.ta_format & TF_REVERSE) { | ||||
tmp = fg; | tmp = fg; | ||||
fg = bg; | fg = bg; | ||||
bg = tmp; | bg = tmp; | ||||
} | } | ||||
attr = (cons_to_vga_colors[bg & 0xf] << 4) | | attr = (cmap[bg & 0xf] << 4) | cmap[fg & 0xf]; | ||||
cons_to_vga_colors[fg & 0xf]; | addr = (struct cgatext *)vgatext; | ||||
addr = (struct cgatext *)vgatext + p->tp_col + p->tp_row * tp.tp_col; | addr[idx].ch = vga_get_cp437(px->c); | ||||
addr->ch = vga_get_cp437(px->c); | addr[idx].attr = attr; | ||||
addr->attr = attr; | |||||
} | } | ||||
static void | static void | ||||
vidc_text_putchar(void *s __unused, const teken_pos_t *p, teken_char_t c, | vidc_text_putchar(void *s, const teken_pos_t *p, teken_char_t c, | ||||
const teken_attr_t *a) | const teken_attr_t *a) | ||||
{ | { | ||||
teken_gfx_t *state = s; | |||||
int attr, idx; | int attr, idx; | ||||
idx = p->tp_col + p->tp_row * tp.tp_col; | idx = p->tp_col + p->tp_row * state->tg_tp.tp_col; | ||||
if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row) | |||||
return; | |||||
buffer[idx].c = c; | buffer[idx].c = c; | ||||
buffer[idx].a = *a; | buffer[idx].a = *a; | ||||
vidc_text_printchar(p); | |||||
vidc_text_printchar(state, p); | |||||
} | } | ||||
/* | |||||
* Draw prepared glyph on terminal point p. | |||||
*/ | |||||
static void | static void | ||||
vidc_text_fill(void *s, const teken_rect_t *r, teken_char_t c, | vidc_gfx_printchar(teken_gfx_t *state, const teken_pos_t *p) | ||||
{ | |||||
unsigned x, y, width, height; | |||||
width = state->tg_font.vf_width; | |||||
height = state->tg_font.vf_height; | |||||
x = state->tg_origin.tp_col + p->tp_col * width; | |||||
y = state->tg_origin.tp_row + p->tp_row * height; | |||||
gfx_bm_cons_display(x, y, width, height, state->tg_glyph); | |||||
} | |||||
/* | |||||
* Store char with its attribute to buffer and put it on screen. | |||||
*/ | |||||
static void | |||||
vidc_gfx_putchar(void *arg, const teken_pos_t *p, teken_char_t c, | |||||
const teken_attr_t *a) | const teken_attr_t *a) | ||||
{ | { | ||||
teken_gfx_t *state = arg; | |||||
const uint8_t *glyph; | |||||
int idx; | |||||
idx = p->tp_col + p->tp_row * state->tg_tp.tp_col; | |||||
if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row) | |||||
return; | |||||
buffer[idx].c = c; | |||||
buffer[idx].a = *a; | |||||
/* remove the cursor */ | |||||
if (state->tg_cursor_visible) | |||||
vidc_gfx_cursor_draw(arg, &state->tg_cursor); | |||||
glyph = font_lookup(&state->tg_font, c, a); | |||||
gfx_bitblt_bitmap(state, glyph, c, a, 0xff); | |||||
vidc_gfx_printchar(state, p); | |||||
/* display the cursor */ | |||||
if (state->tg_cursor_visible) { | |||||
const teken_pos_t *c; | |||||
c = teken_get_cursor(&state->tg_teken); | |||||
vidc_gfx_cursor_draw(state, c); | |||||
} | |||||
} | |||||
static void | |||||
vidc_text_fill(void *arg, const teken_rect_t *r, teken_char_t c, | |||||
const teken_attr_t *a) | |||||
{ | |||||
teken_gfx_t *state = arg; | |||||
teken_pos_t p; | teken_pos_t p; | ||||
teken_unit_t row, col; | teken_unit_t row, col; | ||||
vidc_text_get_cursor(&row, &col); | vidc_text_get_cursor(&row, &col); | ||||
vidc_text_set_cursor(row, col, false); | vidc_text_set_cursor(row, col, false); | ||||
for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; | for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; | ||||
p.tp_row++) | p.tp_row++) | ||||
for (p.tp_col = r->tr_begin.tp_col; | for (p.tp_col = r->tr_begin.tp_col; | ||||
p.tp_col < r->tr_end.tp_col; p.tp_col++) | p.tp_col < r->tr_end.tp_col; p.tp_col++) | ||||
vidc_text_putchar(s, &p, c, a); | vidc_text_putchar(state, &p, c, a); | ||||
vidc_text_set_cursor(row, col, true); | vidc_text_set_cursor(row, col, true); | ||||
} | } | ||||
static void | |||||
vidc_gfx_fill(void *arg, const teken_rect_t *r, teken_char_t c, | |||||
const teken_attr_t *a) | |||||
{ | |||||
teken_gfx_t *state = arg; | |||||
const uint8_t *glyph; | |||||
teken_pos_t p; | |||||
struct text_pixel *row; | |||||
/* remove the cursor */ | |||||
if (state->tg_cursor_visible) | |||||
vidc_gfx_cursor_draw(state, &state->tg_cursor); | |||||
glyph = font_lookup(&state->tg_font, c, a); | |||||
gfx_bitblt_bitmap(state, glyph, c, a, 0xff); | |||||
for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; | |||||
p.tp_row++) { | |||||
row = &buffer[p.tp_row * state->tg_tp.tp_col]; | |||||
for (p.tp_col = r->tr_begin.tp_col; | |||||
p.tp_col < r->tr_end.tp_col; p.tp_col++) { | |||||
row[p.tp_col].c = c; | |||||
row[p.tp_col].a = *a; | |||||
vidc_gfx_printchar(state, &p); | |||||
} | |||||
} | |||||
/* display the cursor */ | |||||
if (state->tg_cursor_visible) { | |||||
const teken_pos_t *c; | |||||
c = teken_get_cursor(&state->tg_teken); | |||||
vidc_gfx_cursor_draw(state, c); | |||||
} | |||||
} | |||||
static bool | static bool | ||||
vidc_same_pixel(struct text_pixel *px1, struct text_pixel *px2) | vidc_same_pixel(struct text_pixel *px1, struct text_pixel *px2) | ||||
{ | { | ||||
if (px1->c != px2->c) | if (px1->c != px2->c) | ||||
return (false); | return (false); | ||||
/* Is there image stored? */ | |||||
if ((px1->a.ta_format & TF_IMAGE) || | |||||
(px2->a.ta_format & TF_IMAGE)) | |||||
return (false); | |||||
if (px1->a.ta_format != px2->a.ta_format) | if (px1->a.ta_format != px2->a.ta_format) | ||||
return (false); | return (false); | ||||
if (px1->a.ta_fgcolor != px2->a.ta_fgcolor) | if (px1->a.ta_fgcolor != px2->a.ta_fgcolor) | ||||
return (false); | return (false); | ||||
if (px1->a.ta_bgcolor != px2->a.ta_bgcolor) | if (px1->a.ta_bgcolor != px2->a.ta_bgcolor) | ||||
return (false); | return (false); | ||||
return (true); | return (true); | ||||
} | } | ||||
static void | static void | ||||
vidc_text_copy(void *ptr __unused, const teken_rect_t *r, const teken_pos_t *p) | vidc_text_copy(void *ptr, const teken_rect_t *r, const teken_pos_t *p) | ||||
{ | { | ||||
teken_gfx_t *state = ptr; | |||||
int srow, drow; | int srow, drow; | ||||
int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */ | int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */ | ||||
teken_pos_t d, s; | teken_pos_t d, s; | ||||
teken_unit_t row, col; | teken_unit_t row, col; | ||||
/* | /* | ||||
* Copying is a little tricky. We must make sure we do it in | * Copying is a little tricky. We must make sure we do it in | ||||
* correct order, to make sure we don't overwrite our own data. | * correct order, to make sure we don't overwrite our own data. | ||||
*/ | */ | ||||
nrow = r->tr_end.tp_row - r->tr_begin.tp_row; | nrow = r->tr_end.tp_row - r->tr_begin.tp_row; | ||||
ncol = r->tr_end.tp_col - r->tr_begin.tp_col; | ncol = r->tr_end.tp_col - r->tr_begin.tp_col; | ||||
vidc_text_get_cursor(&row, &col); | vidc_text_get_cursor(&row, &col); | ||||
vidc_text_set_cursor(row, col, false); | vidc_text_set_cursor(row, col, false); | ||||
if (p->tp_row < r->tr_begin.tp_row) { | if (p->tp_row < r->tr_begin.tp_row) { | ||||
/* Copy from bottom to top. */ | /* Copy from bottom to top. */ | ||||
for (y = 0; y < nrow; y++) { | for (y = 0; y < nrow; y++) { | ||||
d.tp_row = p->tp_row + y; | d.tp_row = p->tp_row + y; | ||||
s.tp_row = r->tr_begin.tp_row + y; | s.tp_row = r->tr_begin.tp_row + y; | ||||
drow = d.tp_row * tp.tp_col; | drow = d.tp_row * state->tg_tp.tp_col; | ||||
srow = s.tp_row * tp.tp_col; | srow = s.tp_row * state->tg_tp.tp_col; | ||||
for (x = 0; x < ncol; x++) { | for (x = 0; x < ncol; x++) { | ||||
d.tp_col = p->tp_col + x; | d.tp_col = p->tp_col + x; | ||||
s.tp_col = r->tr_begin.tp_col + x; | s.tp_col = r->tr_begin.tp_col + x; | ||||
if (!vidc_same_pixel( | if (!vidc_same_pixel( | ||||
&buffer[d.tp_col + drow], | &buffer[d.tp_col + drow], | ||||
&buffer[s.tp_col + srow])) { | &buffer[s.tp_col + srow])) { | ||||
buffer[d.tp_col + drow] = | buffer[d.tp_col + drow] = | ||||
buffer[s.tp_col + srow]; | buffer[s.tp_col + srow]; | ||||
vidc_text_printchar(&d); | vidc_text_printchar(state, &d); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
/* Copy from top to bottom. */ | /* Copy from top to bottom. */ | ||||
if (p->tp_col < r->tr_begin.tp_col) { | if (p->tp_col < r->tr_begin.tp_col) { | ||||
/* Copy from right to left. */ | /* Copy from right to left. */ | ||||
for (y = nrow - 1; y >= 0; y--) { | for (y = nrow - 1; y >= 0; y--) { | ||||
d.tp_row = p->tp_row + y; | d.tp_row = p->tp_row + y; | ||||
s.tp_row = r->tr_begin.tp_row + y; | s.tp_row = r->tr_begin.tp_row + y; | ||||
drow = d.tp_row * tp.tp_col; | drow = d.tp_row * state->tg_tp.tp_col; | ||||
srow = s.tp_row * tp.tp_col; | srow = s.tp_row * state->tg_tp.tp_col; | ||||
for (x = 0; x < ncol; x++) { | for (x = 0; x < ncol; x++) { | ||||
d.tp_col = p->tp_col + x; | d.tp_col = p->tp_col + x; | ||||
s.tp_col = r->tr_begin.tp_col + x; | s.tp_col = r->tr_begin.tp_col + x; | ||||
if (!vidc_same_pixel( | if (!vidc_same_pixel( | ||||
&buffer[d.tp_col + drow], | &buffer[d.tp_col + drow], | ||||
&buffer[s.tp_col + srow])) { | &buffer[s.tp_col + srow])) { | ||||
buffer[d.tp_col + drow] = | buffer[d.tp_col + drow] = | ||||
buffer[s.tp_col + srow]; | buffer[s.tp_col + srow]; | ||||
vidc_text_printchar(&d); | vidc_text_printchar(state, &d); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
/* Copy from left to right. */ | /* Copy from left to right. */ | ||||
for (y = nrow - 1; y >= 0; y--) { | for (y = nrow - 1; y >= 0; y--) { | ||||
d.tp_row = p->tp_row + y; | d.tp_row = p->tp_row + y; | ||||
s.tp_row = r->tr_begin.tp_row + y; | s.tp_row = r->tr_begin.tp_row + y; | ||||
drow = d.tp_row * tp.tp_col; | drow = d.tp_row * state->tg_tp.tp_col; | ||||
srow = s.tp_row * tp.tp_col; | srow = s.tp_row * state->tg_tp.tp_col; | ||||
for (x = ncol - 1; x >= 0; x--) { | for (x = ncol - 1; x >= 0; x--) { | ||||
d.tp_col = p->tp_col + x; | d.tp_col = p->tp_col + x; | ||||
s.tp_col = r->tr_begin.tp_col + x; | s.tp_col = r->tr_begin.tp_col + x; | ||||
if (!vidc_same_pixel( | if (!vidc_same_pixel( | ||||
&buffer[d.tp_col + drow], | &buffer[d.tp_col + drow], | ||||
&buffer[s.tp_col + srow])) { | &buffer[s.tp_col + srow])) { | ||||
buffer[d.tp_col + drow] = | buffer[d.tp_col + drow] = | ||||
buffer[s.tp_col + srow]; | buffer[s.tp_col + srow]; | ||||
vidc_text_printchar(&d); | vidc_text_printchar(state, &d); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
vidc_text_set_cursor(row, col, true); | vidc_text_set_cursor(row, col, true); | ||||
} | } | ||||
static void | static void | ||||
vidc_text_param(void *s __unused, int cmd, unsigned int value) | vidc_gfx_copy_area(teken_gfx_t *state, const teken_rect_t *s, | ||||
const teken_pos_t *d) | |||||
{ | { | ||||
unsigned sx, sy, dx, dy, width, height; | |||||
unsigned bpp, pitch; | |||||
uint8_t *fb, *src, *dst; | |||||
width = state->tg_font.vf_width; | |||||
height = state->tg_font.vf_height; | |||||
sx = state->tg_origin.tp_col + s->tr_begin.tp_col * width; | |||||
sy = state->tg_origin.tp_row + s->tr_begin.tp_row * height; | |||||
dx = state->tg_origin.tp_col + d->tp_col * width; | |||||
dy = state->tg_origin.tp_row + d->tp_row * height; | |||||
width *= (s->tr_end.tp_col - s->tr_begin.tp_col + 1); | |||||
fb = ptov((uint32_t)gfx_state.tg_fb.fb_addr & 0xffffffff); | |||||
bpp = roundup2(state->tg_fb.fb_bpp, 8) >> 3; | |||||
pitch = state->tg_fb.fb_stride * bpp; | |||||
src = fb + sx * bpp + sy * pitch; | |||||
dst = fb + dx * bpp + dy * pitch; | |||||
width *= bpp; | |||||
for (unsigned i = 0; i < height; i++) { | |||||
unsigned increment = i * pitch; | |||||
(void) memmove(dst + increment, src + increment, width); | |||||
} | |||||
} | |||||
static void | |||||
vidc_gfx_copy_line(teken_gfx_t *state, int ncol, teken_pos_t *s, teken_pos_t *d) | |||||
{ | |||||
struct text_pixel *src, *dst; | |||||
teken_rect_t sr; | |||||
teken_pos_t dp; | |||||
unsigned soffset, doffset; | |||||
bool mark = false; | |||||
int x; | |||||
soffset = s->tp_col + s->tp_row * state->tg_tp.tp_col; | |||||
doffset = d->tp_col + d->tp_row * state->tg_tp.tp_col; | |||||
for (x = 0; x < ncol; x++) { | |||||
if (vidc_same_pixel(&buffer[soffset + x], | |||||
&buffer[doffset + x])) { | |||||
if (mark) { | |||||
vidc_gfx_copy_area(state, &sr, &dp); | |||||
mark = false; | |||||
} | |||||
} else { | |||||
buffer[doffset + x] = buffer[soffset + x]; | |||||
if (mark) { | |||||
/* update end point */ | |||||
sr.tr_end.tp_col = s->tp_col + x;; | |||||
} else { | |||||
/* set up new rectangle */ | |||||
mark = true; | |||||
sr.tr_begin.tp_col = s->tp_col + x; | |||||
sr.tr_begin.tp_row = s->tp_row; | |||||
sr.tr_end.tp_col = s->tp_col + x; | |||||
sr.tr_end.tp_row = s->tp_row; | |||||
dp.tp_col = d->tp_col + x; | |||||
dp.tp_row = d->tp_row; | |||||
} | |||||
} | |||||
} | |||||
if (mark) { | |||||
vidc_gfx_copy_area(state, &sr, &dp); | |||||
} | |||||
} | |||||
static void | |||||
vidc_gfx_copy(void *arg, const teken_rect_t *r, const teken_pos_t *p) | |||||
{ | |||||
teken_gfx_t *state = arg; | |||||
unsigned doffset, soffset; | |||||
teken_pos_t d, s; | |||||
int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */ | |||||
/* | |||||
* Copying is a little tricky. We must make sure we do it in | |||||
* correct order, to make sure we don't overwrite our own data. | |||||
*/ | |||||
nrow = r->tr_end.tp_row - r->tr_begin.tp_row; | |||||
ncol = r->tr_end.tp_col - r->tr_begin.tp_col; | |||||
if (p->tp_row + nrow > state->tg_tp.tp_row || | |||||
p->tp_col + ncol > state->tg_tp.tp_col) | |||||
return; | |||||
soffset = r->tr_begin.tp_col + r->tr_begin.tp_row * state->tg_tp.tp_col; | |||||
doffset = p->tp_col + p->tp_row * state->tg_tp.tp_col; | |||||
/* remove the cursor */ | |||||
if (state->tg_cursor_visible) | |||||
vidc_gfx_cursor_draw(state, &state->tg_cursor); | |||||
/* | |||||
* Copy line by line. | |||||
*/ | |||||
if (doffset <= soffset) { | |||||
s = r->tr_begin; | |||||
d = *p; | |||||
for (y = 0; y < nrow; y++) { | |||||
s.tp_row = r->tr_begin.tp_row + y; | |||||
d.tp_row = p->tp_row + y; | |||||
vidc_gfx_copy_line(state, ncol, &s, &d); | |||||
} | |||||
} else { | |||||
for (y = nrow - 1; y >= 0; y--) { | |||||
s.tp_row = r->tr_begin.tp_row + y; | |||||
d.tp_row = p->tp_row + y; | |||||
vidc_gfx_copy_line(state, ncol, &s, &d); | |||||
} | |||||
} | |||||
/* display the cursor */ | |||||
if (state->tg_cursor_visible) { | |||||
const teken_pos_t *c; | |||||
c = teken_get_cursor(&state->tg_teken); | |||||
vidc_gfx_cursor_draw(state, c); | |||||
} | |||||
} | |||||
static void | |||||
vidc_text_param(void *arg, int cmd, unsigned int value) | |||||
{ | |||||
teken_gfx_t *state = arg; | |||||
teken_unit_t row, col; | teken_unit_t row, col; | ||||
switch (cmd) { | switch (cmd) { | ||||
case TP_SETLOCALCURSOR: | case TP_SETLOCALCURSOR: | ||||
/* | /* | ||||
* 0 means normal (usually block), 1 means hidden, and | * 0 means normal (usually block), 1 means hidden, and | ||||
* 2 means blinking (always block) for compatibility with | * 2 means blinking (always block) for compatibility with | ||||
* syscons. We don't support any changes except hiding, | * syscons. We don't support any changes except hiding, | ||||
* so must map 2 to 0. | * so must map 2 to 0. | ||||
*/ | */ | ||||
value = (value == 1) ? 0 : 1; | value = (value == 1) ? 0 : 1; | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case TP_SHOWCURSOR: | case TP_SHOWCURSOR: | ||||
vidc_text_get_cursor(&row, &col); | vidc_text_get_cursor(&row, &col); | ||||
if (value == 1) | if (value != 0) { | ||||
vidc_text_set_cursor(row, col, true); | vidc_text_set_cursor(row, col, true); | ||||
else | state->tg_cursor_visible = true; | ||||
} else { | |||||
vidc_text_set_cursor(row, col, false); | vidc_text_set_cursor(row, col, false); | ||||
state->tg_cursor_visible = false; | |||||
} | |||||
break; | break; | ||||
default: | default: | ||||
/* Not yet implemented */ | /* Not yet implemented */ | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
static void | |||||
vidc_gfx_param(void *arg, int cmd, unsigned int value) | |||||
{ | |||||
teken_gfx_t *state = arg; | |||||
const teken_pos_t *c; | |||||
switch (cmd) { | |||||
case TP_SETLOCALCURSOR: | |||||
/* | /* | ||||
* 0 means normal (usually block), 1 means hidden, and | |||||
* 2 means blinking (always block) for compatibility with | |||||
* syscons. We don't support any changes except hiding, | |||||
* so must map 2 to 0. | |||||
*/ | |||||
value = (value == 1) ? 0 : 1; | |||||
/* FALLTHROUGH */ | |||||
case TP_SHOWCURSOR: | |||||
c = teken_get_cursor(&state->tg_teken); | |||||
vidc_gfx_cursor_draw(state, c); | |||||
if (value != 0) | |||||
state->tg_cursor_visible = true; | |||||
else | |||||
state->tg_cursor_visible = false; | |||||
break; | |||||
default: | |||||
/* Not yet implemented */ | |||||
break; | |||||
} | |||||
} | |||||
/* | |||||
* Not implemented. | * Not implemented. | ||||
*/ | */ | ||||
static void | static void | ||||
vidc_cons_respond(void *s __unused, const void *buf __unused, | vidc_cons_respond(void *s __unused, const void *buf __unused, | ||||
size_t len __unused) | size_t len __unused) | ||||
{ | { | ||||
} | } | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | if (color_name_to_teken(value, &val)) { | ||||
if (errno != 0 || *end != '\0') { | if (errno != 0 || *end != '\0') { | ||||
printf("Allowed values are either ansi color name or " | printf("Allowed values are either ansi color name or " | ||||
"number from range [0-7].\n"); | "number from range [0-7].\n"); | ||||
return (CMD_OK); | return (CMD_OK); | ||||
} | } | ||||
evalue = value; | evalue = value; | ||||
} | } | ||||
ap = teken_get_defattr(&teken); | ap = teken_get_defattr(&gfx_state.tg_teken); | ||||
a = *ap; | a = *ap; | ||||
if (strcmp(ev->ev_name, "teken.fg_color") == 0) { | if (strcmp(ev->ev_name, "teken.fg_color") == 0) { | ||||
/* is it already set? */ | /* is it already set? */ | ||||
if (ap->ta_fgcolor == val) | if (ap->ta_fgcolor == val) | ||||
return (CMD_OK); | return (CMD_OK); | ||||
a.ta_fgcolor = val; | a.ta_fgcolor = val; | ||||
} | } | ||||
if (strcmp(ev->ev_name, "teken.bg_color") == 0) { | if (strcmp(ev->ev_name, "teken.bg_color") == 0) { | ||||
/* is it already set? */ | /* is it already set? */ | ||||
if (ap->ta_bgcolor == val) | if (ap->ta_bgcolor == val) | ||||
return (CMD_OK); | return (CMD_OK); | ||||
a.ta_bgcolor = val; | a.ta_bgcolor = val; | ||||
} | } | ||||
/* Improve visibility */ | /* Improve visibility */ | ||||
if (a.ta_bgcolor == TC_WHITE) | if (a.ta_bgcolor == TC_WHITE) | ||||
a.ta_bgcolor |= TC_LIGHT; | a.ta_bgcolor |= TC_LIGHT; | ||||
teken_set_defattr(&gfx_state.tg_teken, &a); | |||||
cons_draw_frame(&a); | |||||
env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL); | env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL); | ||||
teken_set_defattr(&teken, &a); | teken_input(&gfx_state.tg_teken, "\e[2J", 4); | ||||
return (CMD_OK); | return (CMD_OK); | ||||
} | } | ||||
static int | static int | ||||
env_screen_nounset(struct env_var *ev __unused) | |||||
{ | |||||
if (gfx_state.tg_fb_type == FB_TEXT) | |||||
return (0); | |||||
return (EPERM); | |||||
} | |||||
static int | |||||
vidc_load_palette(uint32_t *cmap) | |||||
{ | |||||
int i, roff, goff, boff, rc; | |||||
extern struct paletteentry *pe8; | |||||
if (pe8 == NULL) | |||||
pe8 = calloc(sizeof(*pe8), 256); | |||||
if (pe8 == NULL) | |||||
return (ENOMEM); | |||||
/* Generate VGA colors */ | |||||
roff = ffs(gfx_state.tg_fb.fb_mask_red) - 1; | |||||
goff = ffs(gfx_state.tg_fb.fb_mask_green) - 1; | |||||
boff = ffs(gfx_state.tg_fb.fb_mask_blue) - 1; | |||||
rc = generate_cons_palette((uint32_t *)pe8, COLOR_FORMAT_RGB, | |||||
gfx_state.tg_fb.fb_mask_red >> roff, roff, | |||||
gfx_state.tg_fb.fb_mask_green >> goff, goff, | |||||
gfx_state.tg_fb.fb_mask_blue >> boff, boff); | |||||
if (rc == 0) { | |||||
for (i = 0; i < 256; i++) { | |||||
rc = vbe_set_palette(&pe8[cmap[i]], i); | |||||
if (rc != 0) | |||||
break; | |||||
} | |||||
} | |||||
return (rc); | |||||
} | |||||
static void | |||||
cons_draw_frame(teken_attr_t *a) | |||||
{ | |||||
teken_attr_t attr = *a; | |||||
teken_color_t fg = a->ta_fgcolor; | |||||
attr.ta_fgcolor = attr.ta_bgcolor; | |||||
teken_set_defattr(&gfx_state.tg_teken, &attr); | |||||
gfx_fb_drawrect(0, 0, gfx_state.tg_fb.fb_width, | |||||
gfx_state.tg_origin.tp_row, 1); | |||||
gfx_fb_drawrect(0, | |||||
gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row - 1, | |||||
gfx_state.tg_fb.fb_width, gfx_state.tg_fb.fb_height, 1); | |||||
gfx_fb_drawrect(0, gfx_state.tg_origin.tp_row, | |||||
gfx_state.tg_origin.tp_col, | |||||
gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row - 1, 1); | |||||
gfx_fb_drawrect( | |||||
gfx_state.tg_fb.fb_width - gfx_state.tg_origin.tp_col - 1, | |||||
gfx_state.tg_origin.tp_row, gfx_state.tg_fb.fb_width, | |||||
gfx_state.tg_fb.fb_height, 1); | |||||
attr.ta_fgcolor = fg; | |||||
teken_set_defattr(&gfx_state.tg_teken, &attr); | |||||
} | |||||
bool | |||||
cons_update_mode(bool use_gfx_mode) | |||||
{ | |||||
const teken_attr_t *a; | |||||
teken_attr_t attr; | |||||
char env[10], *ptr; | |||||
int format, roff, goff, boff; | |||||
gfx_state.tg_tp.tp_row = TEXT_ROWS; | |||||
gfx_state.tg_tp.tp_col = TEXT_COLS; | |||||
if (use_gfx_mode) { | |||||
setup_font(&gfx_state, gfx_state.tg_fb.fb_height, | |||||
gfx_state.tg_fb.fb_width); | |||||
/* Point of origin in pixels. */ | |||||
gfx_state.tg_origin.tp_row = (gfx_state.tg_fb.fb_height - | |||||
(gfx_state.tg_tp.tp_row * gfx_state.tg_font.vf_height)) / 2; | |||||
gfx_state.tg_origin.tp_col = (gfx_state.tg_fb.fb_width - | |||||
(gfx_state.tg_tp.tp_col * gfx_state.tg_font.vf_width)) / 2; | |||||
gfx_state.tg_glyph_size = gfx_state.tg_font.vf_height * | |||||
gfx_state.tg_font.vf_width * | |||||
(roundup2(gfx_state.tg_fb.fb_bpp, 8) >> 3); | |||||
free(gfx_state.tg_glyph); | |||||
gfx_state.tg_glyph = malloc(gfx_state.tg_glyph_size); | |||||
if (gfx_state.tg_glyph == NULL) | |||||
return (false); | |||||
gfx_state.tg_functions = &tfx; | |||||
snprintf(env, sizeof (env), "%dx%d", gfx_state.tg_fb.fb_width, | |||||
gfx_state.tg_fb.fb_height); | |||||
env_setenv("kern.vt.fb.default_mode", EV_VOLATILE | EV_NOHOOK, | |||||
env, env_noset, env_screen_nounset); | |||||
snprintf(env, sizeof (env), "%d", gfx_state.tg_fb.fb_height); | |||||
env_setenv("screen.height", EV_VOLATILE | EV_NOHOOK, env, | |||||
env_noset, env_screen_nounset); | |||||
snprintf(env, sizeof (env), "%d", gfx_state.tg_fb.fb_width); | |||||
env_setenv("screen.width", EV_VOLATILE | EV_NOHOOK, env, | |||||
env_noset, env_screen_nounset); | |||||
snprintf(env, sizeof (env), "%d", gfx_state.tg_fb.fb_bpp); | |||||
env_setenv("screen.depth", EV_VOLATILE | EV_NOHOOK, env, | |||||
env_noset, env_screen_nounset); | |||||
} else { | |||||
/* Trigger loading of 8x16 font. */ | |||||
setup_font(&gfx_state, | |||||
16 * gfx_state.tg_fb.fb_height + BORDER_PIXELS, | |||||
8 * gfx_state.tg_fb.fb_width + BORDER_PIXELS); | |||||
gfx_state.tg_functions = &tf; | |||||
/* ensure the following are not set for text mode */ | |||||
unsetenv("screen.height"); | |||||
unsetenv("screen.width"); | |||||
unsetenv("screen.depth"); | |||||
unsetenv("kern.vt.fb.default_mode"); | |||||
} | |||||
free(buffer); | |||||
buffer = malloc(gfx_state.tg_tp.tp_row * gfx_state.tg_tp.tp_col * | |||||
sizeof(*buffer)); | |||||
if (buffer == NULL) | |||||
return (false); | |||||
teken_init(&gfx_state.tg_teken, gfx_state.tg_functions, &gfx_state); | |||||
if (gfx_state.tg_ctype == CT_INDEXED) | |||||
format = COLOR_FORMAT_VGA; | |||||
else | |||||
format = COLOR_FORMAT_RGB; | |||||
roff = ffs(gfx_state.tg_fb.fb_mask_red) - 1; | |||||
goff = ffs(gfx_state.tg_fb.fb_mask_green) - 1; | |||||
boff = ffs(gfx_state.tg_fb.fb_mask_blue) - 1; | |||||
(void) generate_cons_palette(cmap, format, | |||||
gfx_state.tg_fb.fb_mask_red >> roff, roff, | |||||
gfx_state.tg_fb.fb_mask_green >> goff, goff, | |||||
gfx_state.tg_fb.fb_mask_blue >> boff, boff); | |||||
if (gfx_state.tg_ctype == CT_INDEXED) | |||||
vidc_load_palette(cmap); | |||||
teken_set_winsize(&gfx_state.tg_teken, &gfx_state.tg_tp); | |||||
a = teken_get_defattr(&gfx_state.tg_teken); | |||||
attr = *a; | |||||
/* | |||||
* On first run, we set up the vidc_set_colors() | |||||
* callback. If the env is already set, we | |||||
* pick up fg and bg color values from the environment. | |||||
*/ | |||||
ptr = getenv("teken.fg_color"); | |||||
if (ptr != NULL) { | |||||
attr.ta_fgcolor = strtol(ptr, NULL, 10); | |||||
ptr = getenv("teken.bg_color"); | |||||
attr.ta_bgcolor = strtol(ptr, NULL, 10); | |||||
teken_set_defattr(&gfx_state.tg_teken, &attr); | |||||
} else { | |||||
snprintf(env, sizeof(env), "%d", attr.ta_fgcolor); | |||||
env_setenv("teken.fg_color", EV_VOLATILE, env, | |||||
vidc_set_colors, env_nounset); | |||||
snprintf(env, sizeof(env), "%d", attr.ta_bgcolor); | |||||
env_setenv("teken.bg_color", EV_VOLATILE, env, | |||||
vidc_set_colors, env_nounset); | |||||
} | |||||
/* Improve visibility */ | |||||
if (attr.ta_bgcolor == TC_WHITE) | |||||
attr.ta_bgcolor |= TC_LIGHT; | |||||
teken_set_defattr(&gfx_state.tg_teken, &attr); | |||||
snprintf(env, sizeof (env), "%u", (unsigned)gfx_state.tg_tp.tp_row); | |||||
setenv("LINES", env, 1); | |||||
snprintf(env, sizeof (env), "%u", (unsigned)gfx_state.tg_tp.tp_col); | |||||
setenv("COLUMNS", env, 1); | |||||
/* Draw frame around terminal area. */ | |||||
cons_draw_frame(&attr); | |||||
/* Erase display, this will also fill our screen buffer. */ | |||||
teken_input(&gfx_state.tg_teken, "\e[2J", 4); | |||||
gfx_state.tg_functions->tf_param(&gfx_state, TP_SHOWCURSOR, 1); | |||||
return (true); | |||||
} | |||||
static int | |||||
vidc_init(int arg) | vidc_init(int arg) | ||||
{ | { | ||||
const teken_attr_t *a; | const teken_attr_t *a; | ||||
int val; | int val; | ||||
char env[8]; | char env[8]; | ||||
if (vidc_started && arg == 0) | if (vidc_started && arg == 0) | ||||
return (0); | return (0); | ||||
vidc_started = 1; | vidc_started = 1; | ||||
vbe_init(); | |||||
/* | /* | ||||
* Check Miscellaneous Output Register (Read at 3CCh, Write at 3C2h) | * Check Miscellaneous Output Register (Read at 3CCh, Write at 3C2h) | ||||
* for bit 1 (Input/Output Address Select), which means | * for bit 1 (Input/Output Address Select), which means | ||||
* color/graphics adapter. | * color/graphics adapter. | ||||
*/ | */ | ||||
if (vga_get_reg(VGA_REG_BASE, VGA_GEN_MISC_OUTPUT_R) & VGA_GEN_MO_IOA) | if (vga_get_reg(VGA_REG_BASE, VGA_GEN_MISC_OUTPUT_R) & VGA_GEN_MO_IOA) | ||||
vgatext = (uint16_t *)PTOV(VGA_TXT_BASE); | vgatext = (uint16_t *)PTOV(VGA_TXT_BASE); | ||||
else | else | ||||
vgatext = (uint16_t *)PTOV(VGA_MEM_BASE + VGA_MEM_SIZE); | vgatext = (uint16_t *)PTOV(VGA_MEM_BASE + VGA_MEM_SIZE); | ||||
/* set 16bit colors */ | /* set 16bit colors */ | ||||
val = vga_get_atr(VGA_REG_BASE, VGA_AC_MODE_CONTROL); | val = vga_get_atr(VGA_REG_BASE, VGA_AC_MODE_CONTROL); | ||||
val &= ~VGA_AC_MC_BI; | val &= ~VGA_AC_MC_BI; | ||||
val &= ~VGA_AC_MC_ELG; | val &= ~VGA_AC_MC_ELG; | ||||
vga_set_atr(VGA_REG_BASE, VGA_AC_MODE_CONTROL, val); | vga_set_atr(VGA_REG_BASE, VGA_AC_MODE_CONTROL, val); | ||||
tp.tp_row = TEXT_ROWS; | #if defined(FRAMEBUFFER_MODE) | ||||
tp.tp_col = TEXT_COLS; | val = vbe_default_mode(); | ||||
buffer = malloc(tp.tp_row * tp.tp_col * sizeof(*buffer)); | /* if val is not legal VBE mode, use text mode */ | ||||
if (buffer == NULL) | if (VBE_VALID_MODE(val)) { | ||||
return (1); | if (vbe_set_mode(val) != 0) | ||||
bios_set_text_mode(VGA_TEXT_MODE); | |||||
} | |||||
#endif | |||||
snprintf(env, sizeof (env), "%u", tp.tp_row); | gfx_framework_init(); | ||||
setenv("LINES", env, 1); | |||||
snprintf(env, sizeof (env), "%u", tp.tp_col); | |||||
setenv("COLUMNS", env, 1); | |||||
teken_init(&teken, &tf, NULL); | if (!cons_update_mode(VBE_VALID_MODE(vbe_get_mode()))) | ||||
teken_set_winsize(&teken, &tp); | return (1); | ||||
a = teken_get_defattr(&teken); | |||||
snprintf(env, sizeof(env), "%d", a->ta_fgcolor); | |||||
env_setenv("teken.fg_color", EV_VOLATILE, env, vidc_set_colors, | |||||
env_nounset); | |||||
snprintf(env, sizeof(env), "%d", a->ta_bgcolor); | |||||
env_setenv("teken.bg_color", EV_VOLATILE, env, vidc_set_colors, | |||||
env_nounset); | |||||
/* Erase display, this will also fill our screen buffer. */ | |||||
teken_input(&teken, "\e[J", 3); | |||||
for (int i = 0; i < 10 && vidc_ischar(); i++) | for (int i = 0; i < 10 && vidc_ischar(); i++) | ||||
(void) vidc_getchar(); | (void) vidc_getchar(); | ||||
return (0); /* XXX reinit? */ | return (0); /* XXX reinit? */ | ||||
} | } | ||||
void | void | ||||
vidc_biosputchar(int c) | vidc_biosputchar(int c) | ||||
{ | { | ||||
v86.ctl = 0; | v86.ctl = 0; | ||||
v86.addr = 0x10; | v86.addr = 0x10; | ||||
v86.eax = 0xe00 | (c & 0xff); | v86.eax = 0xe00 | (c & 0xff); | ||||
v86.ebx = 0x7; | v86.ebx = 0x7; | ||||
v86int(); | v86int(); | ||||
} | } | ||||
static void | static void | ||||
vidc_putchar(int c) | vidc_putchar(int c) | ||||
{ | { | ||||
unsigned char ch = c; | unsigned char ch = c; | ||||
if (buffer != NULL) | if (buffer != NULL) | ||||
teken_input(&teken, &ch, sizeof (ch)); | teken_input(&gfx_state.tg_teken, &ch, sizeof (ch)); | ||||
else | else | ||||
vidc_biosputchar(c); | vidc_biosputchar(c); | ||||
} | } | ||||
static int | static int | ||||
vidc_getchar(void) | vidc_getchar(void) | ||||
{ | { | ||||
int i, c; | int i, c; | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | for (i = 0; i < KEYBUFSZ; i++) { | ||||
} | } | ||||
} | } | ||||
v86.ctl = V86_FLAGS; | v86.ctl = V86_FLAGS; | ||||
v86.addr = 0x16; | v86.addr = 0x16; | ||||
v86.eax = 0x100; | v86.eax = 0x100; | ||||
v86int(); | v86int(); | ||||
return (!V86_ZR(v86.efl)); | return (!V86_ZR(v86.efl)); | ||||
} | |||||
void | |||||
gfx_fb_cons_display(uint32_t x, uint32_t y, uint32_t width, uint32_t height, | |||||
void *data) | |||||
{ | |||||
gfx_bm_cons_display(x, y, width, height, data); | |||||
} | } | ||||
#if KEYBOARD_PROBE | #if KEYBOARD_PROBE | ||||
#define PROBE_MAXRETRY 5 | #define PROBE_MAXRETRY 5 | ||||
#define PROBE_MAXWAIT 400 | #define PROBE_MAXWAIT 400 | ||||
#define IO_DUMMY 0x84 | #define IO_DUMMY 0x84 | ||||
#define IO_KBD 0x060 /* 8042 Keyboard */ | #define IO_KBD 0x060 /* 8042 Keyboard */ | ||||
/* selected defines from kbdio.h */ | /* selected defines from kbdio.h */ | ||||
#define KBD_STATUS_PORT 4 /* status port, read */ | #define KBD_STATUS_PORT 4 /* status port, read */ | ||||
#define KBD_DATA_PORT 0 /* data port, read/write | #define KBD_DATA_PORT 0 /* data port, read/write | ||||
* also used as keyboard command | * also used as keyboard command | ||||
* and mouse command port | * and mouse command port | ||||
*/ | */ | ||||
#define KBDC_ECHO 0x00ee | #define KBDC_ECHO 0x00ee | ||||
#define KBDS_ANY_BUFFER_FULL 0x0001 | #define KBDS_ANY_BUFFER_FULL 0x0001 | ||||
#define KBDS_INPUT_BUFFER_FULL 0x0002 | #define KBDS_INPUT_BUFFER_FULL 0x0002 | ||||
#define KBD_ECHO 0x00ee | #define KBD_ECHO 0x00ee | ||||
/* 7 microsec delay necessary for some keyboard controllers */ | /* 7 microsec delay necessary for some keyboard controllers */ | ||||
static void | static void | ||||
delay7(void) | delay7(void) | ||||
{ | { | ||||
/* | /* | ||||
* I know this is broken, but no timer is available yet at this stage... | * I know this is broken, but no timer is available yet at this stage... | ||||
* See also comments in `delay1ms()'. | * See also comments in `delay1ms()'. | ||||
*/ | */ | ||||
inb(IO_DUMMY); inb(IO_DUMMY); | inb(IO_DUMMY); inb(IO_DUMMY); | ||||
inb(IO_DUMMY); inb(IO_DUMMY); | inb(IO_DUMMY); inb(IO_DUMMY); | ||||
inb(IO_DUMMY); inb(IO_DUMMY); | inb(IO_DUMMY); inb(IO_DUMMY); | ||||
} | } | ||||
Show All 9 Lines | |||||
static void | static void | ||||
delay1ms(void) | delay1ms(void) | ||||
{ | { | ||||
int i = 800; | int i = 800; | ||||
while (--i >= 0) | while (--i >= 0) | ||||
(void) inb(0x84); | (void) inb(0x84); | ||||
} | } | ||||
/* | /* | ||||
* We use the presence/absence of a keyboard to determine whether the internal | * We use the presence/absence of a keyboard to determine whether the internal | ||||
* console can be used for input. | * console can be used for input. | ||||
* | * | ||||
* Perform a simple test on the keyboard; issue the ECHO command and see | * Perform a simple test on the keyboard; issue the ECHO command and see | ||||
* if the right answer is returned. We don't do anything as drastic as | * if the right answer is returned. We don't do anything as drastic as | ||||
* full keyboard reset; it will be too troublesome and take too much time. | * full keyboard reset; it will be too troublesome and take too much time. | ||||
*/ | */ | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 56 Lines • Show Last 20 Lines |