summaryrefslogtreecommitdiffstats
path: root/sys/dev/fb
diff options
context:
space:
mode:
authorjkim <jkim@FreeBSD.org>2010-03-23 23:10:17 +0000
committerjkim <jkim@FreeBSD.org>2010-03-23 23:10:17 +0000
commitcd92eeec16862c96619eb77d572c969eea72eae1 (patch)
treec554ea92e2e67d73ec63f75a3e953bd3e11522f3 /sys/dev/fb
parent2a5a7617ac540d0c336b0905e991070a4e61ef86 (diff)
downloadFreeBSD-src-cd92eeec16862c96619eb77d572c969eea72eae1.zip
FreeBSD-src-cd92eeec16862c96619eb77d572c969eea72eae1.tar.gz
Be extremely careful when we determine bytes per scan line information.
First, we compare mode table data against minimum value. If the mode table does not make sense, we set the minimum in the mode info. When we actually set the mode, we try VESA BIOS function and compare it against the previous value. If it makes more sense, update the information.
Diffstat (limited to 'sys/dev/fb')
-rw-r--r--sys/dev/fb/vesa.c65
1 files changed, 54 insertions, 11 deletions
diff --git a/sys/dev/fb/vesa.c b/sys/dev/fb/vesa.c
index 1a3542d..287cc6a 100644
--- a/sys/dev/fb/vesa.c
+++ b/sys/dev/fb/vesa.c
@@ -188,9 +188,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
static int vesa_bios_get_line_length(void);
-#endif
static int vesa_bios_set_line_length(int pixel, int *bytes, int *lines);
#if 0
static int vesa_bios_get_start(int *x, int *y);
@@ -199,6 +197,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 +557,6 @@ vesa_bios_save_restore(int code, void *p, size_t size)
return (regs.R_AX != 0x004f);
}
-#if 0
static int
vesa_bios_get_line_length(void)
{
@@ -575,7 +573,6 @@ vesa_bios_get_line_length(void)
return (regs.R_BX);
}
-#endif
static int
vesa_bios_set_line_length(int pixel, int *bytes, int *lines)
@@ -709,6 +706,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 +767,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 +891,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;
@@ -1181,6 +1212,7 @@ static int
vesa_set_mode(video_adapter_t *adp, int mode)
{
video_info_t info;
+ int bpsl;
if (adp != vesa_adp)
return ((*prevvidsw->set_mode)(adp, mode));
@@ -1257,6 +1289,20 @@ 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;
+
+ /* If VBE function returns bigger bytes per scan line, use it. */
+ 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;
+ }
+
if (info.vi_flags & V_INFO_LINEAR) {
#if VESA_DEBUG > 1
printf("VESA: setting up LFB\n");
@@ -1275,9 +1321,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
OpenPOWER on IntegriCloud