MFC: r205557, r205558, r205564, r205566, r205604, r205653

Sync. pixel mode support for VESA and VGA frame buffers with HEAD.

- Map entire video memory again.  Although we do not use them all directly,
it seems VGA renderer may access unmapped memory region and cause kernel
panic.
- Fall back to VGA palette functions if VESA function failed and DAC is
still in 6-bit mode.  Although we have to check non-VGA compatibility bit
here, it seems there are too many broken VESA BIOSes out to rely on it.
- Be careful when we determine bytes per scan line information.  We compare
mode table data against minimum value.  If the mode table does not make
sense, we set the minimum in the mode info.
- Teach VGA framebuffer about 8-bit palette format for VESA.
- Add my copyright here.
This commit is contained in:
Jung-uk Kim 2010-03-31 15:45:11 +00:00
parent 86a2d033e4
commit 7058bb70ff
2 changed files with 86 additions and 31 deletions

View file

@ -1,5 +1,6 @@
/*-
* Copyright (c) 1998 Kazutaka YOKOTA and Michael Smith
* Copyright (c) 2009-2010 Jung-uk Kim <jkim@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -188,7 +189,7 @@ static int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g,
#define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG)
static ssize_t vesa_bios_state_buf_size(void);
static int vesa_bios_save_restore(int code, void *p, size_t size);
#if 0
#ifdef MODE_TABLE_BROKEN
static int vesa_bios_get_line_length(void);
#endif
static int vesa_bios_set_line_length(int pixel, int *bytes, int *lines);
@ -199,6 +200,7 @@ static int vesa_bios_set_start(int x, int y);
static int vesa_map_gen_mode_num(int type, int color, int mode);
static int vesa_translate_flags(u_int16_t vflags);
static int vesa_translate_mmodel(u_int8_t vmodel);
static int vesa_get_bpscanline(struct vesa_mode *vmode);
static int vesa_bios_init(void);
static void vesa_clear_modes(video_info_t *info, int color);
@ -558,7 +560,7 @@ vesa_bios_save_restore(int code, void *p, size_t size)
return (regs.R_AX != 0x004f);
}
#if 0
#ifdef MODE_TABLE_BROKEN
static int
vesa_bios_get_line_length(void)
{
@ -709,6 +711,43 @@ vesa_translate_mmodel(u_int8_t vmodel)
return (V_INFO_MM_OTHER);
}
static int
vesa_get_bpscanline(struct vesa_mode *vmode)
{
int bpsl;
if ((vmode->v_modeattr & V_MODEGRAPHICS) != 0) {
/* Find the minimum length. */
switch (vmode->v_bpp / vmode->v_planes) {
case 1:
bpsl = vmode->v_width / 8;
break;
case 2:
bpsl = vmode->v_width / 4;
break;
case 4:
bpsl = vmode->v_width / 2;
break;
default:
bpsl = vmode->v_width * ((vmode->v_bpp + 7) / 8);
bpsl /= vmode->v_planes;
break;
}
/* Use VBE 3.0 information if it looks sane. */
if ((vmode->v_modeattr & V_MODELFB) != 0 &&
vesa_adp_info->v_version >= 0x0300 &&
vmode->v_linbpscanline > bpsl)
return (vmode->v_linbpscanline);
/* Return the minimum if the mode table looks absurd. */
if (vmode->v_bpscanline < bpsl)
return (bpsl);
}
return (vmode->v_bpscanline);
}
#define VESA_MAXSTR 256
#define VESA_STRCPY(dst, src) do { \
@ -733,7 +772,6 @@ vesa_bios_init(void)
void *vmbuf;
uint32_t offs;
uint16_t vers;
int bpsl;
int is_via_cle266;
int modes;
int i;
@ -858,9 +896,7 @@ vesa_bios_init(void)
}
#endif
bpsl = (vmode.v_modeattr & V_MODELFB) != 0 && vers >= 0x0300 ?
vmode.v_linbpscanline : vmode.v_bpscanline;
bsize = bpsl * vmode.v_height;
bsize = vesa_get_bpscanline(&vmode) * vmode.v_height;
if ((vmode.v_modeattr & V_MODEGRAPHICS) != 0)
bsize *= vmode.v_planes;
@ -1209,7 +1245,7 @@ vesa_set_mode(video_adapter_t *adp, int mode)
int10_set_mode(adp->va_initial_bios_mode);
if (adp->va_info.vi_flags & V_INFO_LINEAR)
pmap_unmapdev(adp->va_buffer,
adp->va_buffer_size);
vesa_adp_info->v_memsize * 64 * 1024);
/*
* Once (*prevvidsw->get_info)() succeeded,
* (*prevvidsw->set_mode)() below won't fail...
@ -1241,12 +1277,12 @@ vesa_set_mode(video_adapter_t *adp, int mode)
if ((vesa_adp_info->v_flags & V_DAC8) != 0 &&
(info.vi_flags & V_INFO_GRAPHICS) != 0 &&
(info.vi_flags & V_INFO_NONVGA) != 0 &&
vesa_bios_set_dac(8) > 6)
adp->va_flags |= V_ADP_DAC8;
if (adp->va_info.vi_flags & V_INFO_LINEAR)
pmap_unmapdev(adp->va_buffer, adp->va_buffer_size);
pmap_unmapdev(adp->va_buffer,
vesa_adp_info->v_memsize * 64 * 1024);
#if VESA_DEBUG > 0
printf("VESA: mode set!\n");
@ -1257,13 +1293,31 @@ vesa_set_mode(video_adapter_t *adp, int mode)
(info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
vesa_adp->va_crtc_addr =
(vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
vesa_adp->va_line_width = info.vi_buffer_size / info.vi_height;
if ((info.vi_flags & V_INFO_GRAPHICS) != 0)
vesa_adp->va_line_width /= info.vi_planes;
#ifdef MODE_TABLE_BROKEN
/* If VBE function returns bigger bytes per scan line, use it. */
{
int bpsl = vesa_bios_get_line_length();
if (bpsl > vesa_adp->va_line_width) {
vesa_adp->va_line_width = bpsl;
info.vi_buffer_size = bpsl * info.vi_height;
if ((info.vi_flags & V_INFO_GRAPHICS) != 0)
info.vi_buffer_size *= info.vi_planes;
}
}
#endif
if (info.vi_flags & V_INFO_LINEAR) {
#if VESA_DEBUG > 1
printf("VESA: setting up LFB\n");
#endif
vesa_adp->va_buffer =
(vm_offset_t)pmap_mapdev_attr(info.vi_buffer,
info.vi_buffer_size, PAT_WRITE_COMBINING);
vesa_adp_info->v_memsize * 64 * 1024, PAT_WRITE_COMBINING);
vesa_adp->va_window = vesa_adp->va_buffer;
vesa_adp->va_window_size = info.vi_buffer_size / info.vi_planes;
vesa_adp->va_window_gran = info.vi_buffer_size / info.vi_planes;
@ -1275,9 +1329,6 @@ vesa_set_mode(video_adapter_t *adp, int mode)
}
vesa_adp->va_buffer_size = info.vi_buffer_size;
vesa_adp->va_window_orig = 0;
vesa_adp->va_line_width = info.vi_buffer_size / info.vi_height;
if ((info.vi_flags & V_INFO_GRAPHICS) != 0)
vesa_adp->va_line_width /= info.vi_planes;
vesa_adp->va_disp_start.x = 0;
vesa_adp->va_disp_start.y = 0;
#if VESA_DEBUG > 0
@ -1322,10 +1373,10 @@ vesa_save_palette(video_adapter_t *adp, u_char *palette)
{
int bits;
if (adp == vesa_adp && VESA_MODE(adp->va_mode) &&
(adp->va_info.vi_flags & V_INFO_NONVGA) != 0) {
if (adp == vesa_adp && VESA_MODE(adp->va_mode)) {
bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6;
return (vesa_bios_save_palette(0, 256, palette, bits));
if (vesa_bios_save_palette(0, 256, palette, bits) == 0)
return (0);
}
return ((*prevvidsw->save_palette)(adp, palette));
@ -1336,10 +1387,10 @@ vesa_load_palette(video_adapter_t *adp, u_char *palette)
{
int bits;
if (adp == vesa_adp && VESA_MODE(adp->va_mode) &&
(adp->va_info.vi_flags & V_INFO_NONVGA) != 0) {
if (adp == vesa_adp && VESA_MODE(adp->va_mode)) {
bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6;
return (vesa_bios_load_palette(0, 256, palette, bits));
if (vesa_bios_load_palette(0, 256, palette, bits) == 0)
return (0);
}
return ((*prevvidsw->load_palette)(adp, palette));
@ -1544,8 +1595,6 @@ get_palette(video_adapter_t *adp, int base, int count,
return (1);
if (!VESA_MODE(adp->va_mode))
return (1);
if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0)
return (1);
bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6;
r = malloc(count * 3, M_DEVBUF, M_WAITOK);
@ -1582,8 +1631,6 @@ set_palette(video_adapter_t *adp, int base, int count,
return (1);
if (!VESA_MODE(adp->va_mode))
return (1);
if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0)
return (1);
bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6;
r = malloc(count * 3, M_DEVBUF, M_WAITOK);

View file

@ -1979,6 +1979,7 @@ vga_show_font(video_adapter_t *adp, int page)
static int
vga_save_palette(video_adapter_t *adp, u_char *palette)
{
int bits;
int i;
prologue(adp, V_ADP_PALETTE, ENODEV);
@ -1988,8 +1989,9 @@ vga_save_palette(video_adapter_t *adp, u_char *palette)
* VGA has 6 bit DAC .
*/
outb(PALRADR, 0x00);
bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 0 : 2;
for (i = 0; i < 256*3; ++i)
palette[i] = inb(PALDATA) << 2;
palette[i] = inb(PALDATA) << bits;
inb(adp->va_crtc_addr + 6); /* reset flip/flop */
return 0;
}
@ -1998,15 +2000,17 @@ static int
vga_save_palette2(video_adapter_t *adp, int base, int count,
u_char *r, u_char *g, u_char *b)
{
int bits;
int i;
prologue(adp, V_ADP_PALETTE, ENODEV);
outb(PALRADR, base);
bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 0 : 2;
for (i = 0; i < count; ++i) {
r[i] = inb(PALDATA) << 2;
g[i] = inb(PALDATA) << 2;
b[i] = inb(PALDATA) << 2;
r[i] = inb(PALDATA) << bits;
g[i] = inb(PALDATA) << bits;
b[i] = inb(PALDATA) << bits;
}
inb(adp->va_crtc_addr + 6); /* reset flip/flop */
return 0;
@ -2021,14 +2025,16 @@ vga_save_palette2(video_adapter_t *adp, int base, int count,
static int
vga_load_palette(video_adapter_t *adp, u_char *palette)
{
int bits;
int i;
prologue(adp, V_ADP_PALETTE, ENODEV);
outb(PIXMASK, 0xff); /* no pixelmask */
outb(PALWADR, 0x00);
bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 0 : 2;
for (i = 0; i < 256*3; ++i)
outb(PALDATA, palette[i] >> 2);
outb(PALDATA, palette[i] >> bits);
inb(adp->va_crtc_addr + 6); /* reset flip/flop */
outb(ATC, 0x20); /* enable palette */
return 0;
@ -2038,16 +2044,18 @@ static int
vga_load_palette2(video_adapter_t *adp, int base, int count,
u_char *r, u_char *g, u_char *b)
{
int bits;
int i;
prologue(adp, V_ADP_PALETTE, ENODEV);
outb(PIXMASK, 0xff); /* no pixelmask */
outb(PALWADR, base);
bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 0 : 2;
for (i = 0; i < count; ++i) {
outb(PALDATA, r[i] >> 2);
outb(PALDATA, g[i] >> 2);
outb(PALDATA, b[i] >> 2);
outb(PALDATA, r[i] >> bits);
outb(PALDATA, g[i] >> bits);
outb(PALDATA, b[i] >> bits);
}
inb(adp->va_crtc_addr + 6); /* reset flip/flop */
outb(ATC, 0x20); /* enable palette */