[syslinux:master] vesa: allow arbitrary resolutions on some Intel chipsets

syslinux-bot for H. Peter Anvin hpa at zytor.com
Tue Feb 16 15:15:08 PST 2010


Commit-ID:  5d4ade0221c2387345d0a82422866bb8b937cb09
Gitweb:     http://syslinux.zytor.com/commit/5d4ade0221c2387345d0a82422866bb8b937cb09
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Fri, 22 Jan 2010 12:21:37 -0800
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Fri, 22 Jan 2010 17:36:04 -0800

vesa: allow arbitrary resolutions on some Intel chipsets

Add some code from the tool "915resolution" to allow arbitrary
resolutions to be set on some Intel chipsets.

Signed-off-by: H. Peter Anvin <hpa at zytor.com>


---
 com32/lib/Makefile                  |    1 +
 com32/lib/sys/vesa/i915resolution.c |  803 +++++++++++++++++++++++++++++++++++
 com32/lib/sys/vesa/initvesa.c       |    9 +-
 com32/lib/sys/vesa/video.h          |    2 +
 4 files changed, 813 insertions(+), 2 deletions(-)

diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index ff5887b..bee7e8a 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -64,6 +64,7 @@ LIBOBJS = \
 	sys/vesacon_write.o sys/vesaserial_write.o			\
 	sys/vesa/initvesa.o sys/vesa/drawtxt.o	sys/vesa/background.o	\
 	sys/vesa/alphatbl.o sys/vesa/screencpy.o sys/vesa/fmtpixel.o	\
+	sys/vesa/i915resolution.o					\
 	\
 	pci/cfgtype.o pci/scan.o					\
 	pci/readb.o pci/readw.o pci/readl.o pci/readbios.o		\
diff --git a/com32/lib/sys/vesa/i915resolution.c b/com32/lib/sys/vesa/i915resolution.c
new file mode 100644
index 0000000..a9b28cc
--- /dev/null
+++ b/com32/lib/sys/vesa/i915resolution.c
@@ -0,0 +1,803 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2010 Intel Corporation; author: H. Peter Anvin
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *   
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *   
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Based on:
+ * 
+ * 915 resolution by steve tomljenovic
+ *
+ * This was tested only on Sony VGN-FS550.  Use at your own risk
+ *
+ * This code is based on the techniques used in :
+ *
+ *   - 855patch.  Many thanks to Christian Zietz (czietz gmx net)
+ *     for demonstrating how to shadow the VBIOS into system RAM
+ *     and then modify it.
+ *
+ *   - 1280patch by Andrew Tipton (andrewtipton null li).
+ *
+ *   - 855resolution by Alain Poirier
+ *
+ * This source code is into the public domain.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#define __USE_GNU
+#include <string.h>
+#include <sys/io.h>
+#include <sys/cpu.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdbool.h>
+#include "video.h"
+#include "debug.h"
+
+#define VBIOS_START         0xc0000
+#define VBIOS_SIZE          0x10000
+
+#define MODE_TABLE_OFFSET_845G 617
+
+#define VERSION "0.5.3"
+
+#define ATI_SIGNATURE1 "ATI MOBILITY RADEON"
+#define ATI_SIGNATURE2 "ATI Technologies Inc"
+#define NVIDIA_SIGNATURE "NVIDIA Corp"
+#define INTEL_SIGNATURE "Intel Corp"
+
+typedef unsigned char * address;
+
+typedef enum {
+    CT_UNKWN, CT_830, CT_845G, CT_855GM, CT_865G, CT_915G, CT_915GM,
+    CT_945G, CT_945GM, CT_946GZ, CT_G965, CT_Q965, CT_945GME,
+    CHIPSET_TYPES
+} chipset_type;
+
+typedef enum {
+    BT_UNKWN, BT_1, BT_2, BT_3
+} bios_type;
+
+static int freqs[] = { 60, 75, 85 };
+
+typedef struct {
+    uint8_t mode;
+    uint8_t bits_per_pixel;
+    uint16_t resolution;
+    uint8_t unknown;
+} __attribute__((packed)) vbios_mode;
+
+typedef struct {
+    uint16_t clock;		/* Clock frequency in 10 kHz */
+    uint8_t x1;
+    uint8_t x_total;
+    uint8_t x2;
+    uint8_t y1;
+    uint8_t y_total;
+    uint8_t y2;
+} __attribute__((packed)) vbios_resolution_type1;
+
+typedef struct {
+    uint32_t clock;
+
+    uint16_t x1;
+    uint16_t htotal;
+    uint16_t x2;
+    uint16_t hblank;
+    uint16_t hsyncstart;
+    uint16_t hsyncend;
+
+    uint16_t y1;
+    uint16_t vtotal;
+    uint16_t y2;
+    uint16_t vblank;
+    uint16_t vsyncstart;
+    uint16_t vsyncend;
+} __attribute__((packed)) vbios_modeline_type2;
+
+typedef struct {
+    uint8_t xchars;
+    uint8_t ychars;
+    uint8_t unknown[4];
+
+    vbios_modeline_type2 modelines[];
+} __attribute__((packed)) vbios_resolution_type2;
+
+typedef struct {
+    uint32_t clock;
+
+    uint16_t x1;
+    uint16_t htotal;
+    uint16_t x2;
+    uint16_t hblank;
+    uint16_t hsyncstart;
+    uint16_t hsyncend;
+
+    uint16_t y1;
+    uint16_t vtotal;
+    uint16_t y2;
+    uint16_t vblank;
+    uint16_t vsyncstart;
+    uint16_t vsyncend;
+
+    uint16_t timing_h;
+    uint16_t timing_v;
+
+    uint8_t unknown[6];
+} __attribute__((packed)) vbios_modeline_type3;
+
+typedef struct {
+    unsigned char unknown[6];
+
+    vbios_modeline_type3 modelines[];
+} __attribute__((packed)) vbios_resolution_type3;
+
+
+typedef struct {
+    unsigned int chipset_id;
+    chipset_type chipset;
+    bios_type bios;
+    
+    address bios_ptr;
+
+    vbios_mode * mode_table;
+    unsigned int mode_table_size;
+
+    uint8_t b1, b2;
+
+    bool unlocked;
+} vbios_map;
+
+#if 0				/* Debugging hacks */
+static void good_marker(int x)
+{
+    ((uint16_t *)0xb8000)[x] = 0x2f30 - ((x & 0xf0) << 4) + (x & 0x0f);
+}
+
+static void bad_marker(int x)
+{
+    ((uint16_t *)0xb8000)[x] = 0x4f30 - ((x & 0xf0) << 4) + (x & 0x0f);
+}
+
+static void status(const char *fmt, ...)
+{
+    va_list ap;
+    char msg[81], *p;
+    int i;
+    uint16_t *q;
+
+    memset(msg, 0, sizeof msg);
+    va_start(ap, fmt);
+    vsnprintf(msg, sizeof msg, fmt, ap);
+    va_end(ap);
+    p = msg;
+    q = (uint16_t *)0xb8000 + 80;
+    for (i = 0; i < 80; i++)
+	*q++ = *p++ + 0x1f00;
+}
+#else
+static inline void good_marker(int x) { (void)x; }
+static inline void bad_marker(int x) { (void)x; }
+static inline void status(const char *fmt, ...) { (void)fmt; }
+#endif
+
+static unsigned int get_chipset_id(void) {
+    outl(0x80000000, 0xcf8);
+    return inl(0xcfc);
+}
+
+static chipset_type get_chipset(unsigned int id) {
+    chipset_type type;
+
+    switch (id) {
+    case 0x35758086:
+        type = CT_830;
+        break;
+
+    case 0x25608086:
+        type = CT_845G;
+        break;
+        
+    case 0x35808086:
+        type = CT_855GM;
+        break;
+        
+    case 0x25708086:
+        type = CT_865G;
+        break;
+
+    case 0x25808086:
+	type = CT_915G;
+	break;
+
+    case 0x25908086:
+        type = CT_915GM;
+        break;
+
+    case 0x27708086:
+        type = CT_945G;
+        break;
+
+    case 0x27a08086:
+        type = CT_945GM;
+        break;
+
+    case 0x29708086:
+        type = CT_946GZ;
+        break;
+
+    case 0x29a08086:
+	type = CT_G965;
+	break;
+
+    case 0x29908086:
+        type = CT_Q965;
+        break;
+
+    case 0x27ac8086:
+	type = CT_945GME;
+	break;
+
+    default:
+        type = CT_UNKWN;
+        break;
+    }
+
+    return type;
+}
+
+
+static vbios_resolution_type1 * map_type1_resolution(vbios_map * map,
+						     uint16_t res)
+{
+    vbios_resolution_type1 * ptr = ((vbios_resolution_type1*)(map->bios_ptr + res)); 
+    return ptr;
+}
+
+static vbios_resolution_type2 * map_type2_resolution(vbios_map * map,
+						     uint16_t res)
+{
+    vbios_resolution_type2 * ptr = ((vbios_resolution_type2*)(map->bios_ptr + res)); 
+    return ptr;
+}
+
+static vbios_resolution_type3 * map_type3_resolution(vbios_map * map,
+						     uint16_t res)
+{
+    vbios_resolution_type3 * ptr = ((vbios_resolution_type3*)(map->bios_ptr + res)); 
+    return ptr;
+}
+
+
+static bool detect_bios_type(vbios_map * map, int entry_size)
+{
+    unsigned int i;
+    uint16_t r1, r2;
+    
+    r1 = r2 = 32000;
+
+    for (i = 0; i < map->mode_table_size; i++) {
+        if (map->mode_table[i].resolution <= r1) {
+            r1 = map->mode_table[i].resolution;
+    	} else if (map->mode_table[i].resolution <= r2) {
+	    r2 = map->mode_table[i].resolution;
+    	}
+    }
+    
+    return ((r2-r1-6) % entry_size) == 0;
+}
+
+static inline void close_vbios(vbios_map *map)
+{
+    (void)map;
+}
+
+static vbios_map * open_vbios(void)
+{
+    static vbios_map _map;
+    vbios_map * const map = &_map;
+
+    memset(&_map, 0, sizeof _map);
+
+    /*
+     * Determine chipset
+     */
+    map->chipset_id = get_chipset_id();
+    good_marker(0x10);
+    map->chipset = get_chipset(map->chipset_id);
+    good_marker(0x11);
+
+    /*
+     *  Map the video bios to memory
+     */
+    map->bios_ptr = (void *)VBIOS_START;
+
+    /*
+     * check if we have ATI Radeon
+     */
+    
+    if (memmem(map->bios_ptr, VBIOS_SIZE, ATI_SIGNATURE1, strlen(ATI_SIGNATURE1)) ||
+        memmem(map->bios_ptr, VBIOS_SIZE, ATI_SIGNATURE2, strlen(ATI_SIGNATURE2)) ) {
+        debug("ATI chipset detected.  915resolution only works with Intel 800/900 series graphic chipsets.\r\n");
+	return NULL;
+    }
+
+    /*
+     * check if we have NVIDIA
+     */
+    
+    if (memmem(map->bios_ptr, VBIOS_SIZE, NVIDIA_SIGNATURE, strlen(NVIDIA_SIGNATURE))) {
+        debug("NVIDIA chipset detected.  915resolution only works with Intel 800/900 series graphic chipsets.\r\n");
+	return NULL;
+    }
+
+    /*
+     * check if we have Intel
+     */
+    
+    if (map->chipset == CT_UNKWN && memmem(map->bios_ptr, VBIOS_SIZE, INTEL_SIGNATURE, strlen(INTEL_SIGNATURE))) {
+        debug("Intel chipset detected.  However, 915resolution was unable to determine the chipset type.\r\n");
+
+        debug("Chipset Id: %x\r\n", map->chipset_id);
+
+        debug("Please report this problem to stomljen at yahoo.com\r\n");
+        
+        close_vbios(map);
+	return NULL;
+    }
+
+    /*
+     * check for others
+     */
+
+    if (map->chipset == CT_UNKWN) {
+        debug("Unknown chipset type and unrecognized bios.\r\n");
+        debug("915resolution only works with Intel 800/900 series graphic chipsets.\r\n");
+
+        debug("Chipset Id: %x\r\n", map->chipset_id);
+        close_vbios(map);
+	return NULL;
+    }
+
+    /*
+     * Figure out where the mode table is 
+     */
+    good_marker(0x12);
+
+    {
+        address p = map->bios_ptr + 16;
+        address limit = map->bios_ptr + VBIOS_SIZE - (3 * sizeof(vbios_mode));
+        
+        while (p < limit && map->mode_table == 0) {
+            vbios_mode * mode_ptr = (vbios_mode *) p;
+            
+            if (((mode_ptr[0].mode & 0xf0) == 0x30) && ((mode_ptr[1].mode & 0xf0) == 0x30) &&
+                ((mode_ptr[2].mode & 0xf0) == 0x30) && ((mode_ptr[3].mode & 0xf0) == 0x30)) {
+
+                map->mode_table = mode_ptr;
+            }
+            
+            p++;
+        }
+
+        if (map->mode_table == 0) {
+            debug("Unable to locate the mode table.\r\n");
+            close_vbios(map);
+	    return NULL;
+        }
+    }
+    good_marker(0x13);
+
+    /*
+     * Determine size of mode table
+     */
+    
+    {
+        vbios_mode * mode_ptr = map->mode_table;
+        
+        while (mode_ptr->mode != 0xff) {
+            map->mode_table_size++;
+            mode_ptr++;
+        }
+    }
+    good_marker(0x14);
+    status("mode_table_size = %d", map->mode_table_size);
+
+    /*
+     * Figure out what type of bios we have
+     *  order of detection is important
+     */
+
+    if (detect_bios_type(map, sizeof(vbios_modeline_type3))) {
+        map->bios = BT_3;
+    }
+    else if (detect_bios_type(map, sizeof(vbios_modeline_type2))) {
+        map->bios = BT_2;
+    }
+    else if (detect_bios_type(map, sizeof(vbios_resolution_type1))) {
+        map->bios = BT_1;
+    }
+    else {
+        debug("Unable to determine bios type.\r\n");
+        debug("Mode Table Offset: $C0000 + $%x\r\n", ((unsigned int)map->mode_table) - ((unsigned int)map->bios_ptr));
+        debug("Mode Table Entries: %u\r\n", map->mode_table_size);
+	bad_marker(0x15);
+	return NULL;
+    }
+    good_marker(0x15);
+
+    return map;
+}
+
+static void unlock_vbios(vbios_map * map)
+{
+    assert(!map->unlocked);
+
+    map->unlocked = true;
+    
+    switch (map->chipset) {
+    case CT_UNKWN:
+    case CHIPSET_TYPES:		/* Shut up gcc */
+        break;
+    case CT_830:
+    case CT_855GM:
+        outl(0x8000005a, 0xcf8);
+        map->b1 = inb(0xcfe);
+        
+        outl(0x8000005a, 0xcf8);
+        outb(0x33, 0xcfe);
+        break;
+    case CT_845G:
+    case CT_865G:
+    case CT_915G:
+    case CT_915GM:
+    case CT_945G:
+    case CT_945GM:
+    case CT_945GME:
+    case CT_946GZ:
+    case CT_G965:
+    case CT_Q965:
+        outl(0x80000090, 0xcf8);
+        map->b1 = inb(0xcfd);
+        map->b2 = inb(0xcfe);
+        
+        outl(0x80000090, 0xcf8);
+        outb(0x33, 0xcfd);
+        outb(0x33, 0xcfe);
+        break;
+    }
+
+#if DEBUG
+    {
+        unsigned int t = inl(0xcfc);
+        debug("unlock PAM: (0x%08x)\r\n", t);
+    }
+#endif
+}
+
+static void relock_vbios(vbios_map * map)
+{
+    assert(map->unlocked);
+    map->unlocked = false;
+    
+    switch (map->chipset) {
+    case CT_UNKWN:
+    case CHIPSET_TYPES:		/* Shut up gcc */
+        break;
+    case CT_830:
+    case CT_855GM:
+        outl(0x8000005a, 0xcf8);
+        outb(map->b1, 0xcfe);
+        break;
+    case CT_845G:
+    case CT_865G:
+    case CT_915G:
+    case CT_915GM:
+    case CT_945G:
+    case CT_945GM:
+    case CT_945GME:
+    case CT_946GZ:
+    case CT_G965:
+    case CT_Q965:
+        outl(0x80000090, 0xcf8);
+        outb(map->b1, 0xcfd);
+        outb(map->b2, 0xcfe);
+        break;
+    }
+
+#if DEBUG
+    {
+        unsigned int t = inl(0xcfc);
+        debug("relock PAM: (0x%08x)\r\n", t);
+    }
+#endif
+}
+
+#if 0
+static void list_modes(vbios_map *map, unsigned int raw)
+{
+    unsigned int i, x, y;
+
+    for (i=0; i < map->mode_table_size; i++) {
+        switch(map->bios) {
+        case BT_1:
+            {
+                vbios_resolution_type1 * res = map_type1_resolution(map, map->mode_table[i].resolution);
+                
+                x = ((((unsigned int) res->x2) & 0xf0) << 4) | res->x1;
+                y = ((((unsigned int) res->y2) & 0xf0) << 4) | res->y1;
+                
+                if (x != 0 && y != 0) {
+                    debug("Mode %02x : %dx%d, %d bits/pixel\r\n", map->mode_table[i].mode, x, y, map->mode_table[i].bits_per_pixel);
+                }
+
+		if (raw)
+		{
+                    debug("Mode %02x (raw) :\r\n\t%02x %02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n", map->mode_table[i].mode, res->unknow1[0],res->unknow1[1], res->x1,res->x_total,res->x2,res->y1,res->y_total,res->y2);
+		}
+
+            }
+            break;
+        case BT_2:
+            {
+                vbios_resolution_type2 * res = map_type2_resolution(map, map->mode_table[i].resolution);
+                
+                x = res->modelines[0].x1+1;
+                y = res->modelines[0].y1+1;
+
+                if (x != 0 && y != 0) {
+                    debug("Mode %02x : %dx%d, %d bits/pixel\r\n", map->mode_table[i].mode, x, y, map->mode_table[i].bits_per_pixel);
+                }
+            }
+            break;
+        case BT_3:
+            {
+                vbios_resolution_type3 * res = map_type3_resolution(map, map->mode_table[i].resolution);
+                
+                x = res->modelines[0].x1+1;
+                y = res->modelines[0].y1+1;
+                
+                if (x != 0 && y != 0) {
+                    debug("Mode %02x : %dx%d, %d bits/pixel\r\n", map->mode_table[i].mode, x, y, map->mode_table[i].bits_per_pixel);
+                }
+            }
+            break;
+        case BT_UNKWN:
+            break;
+        }
+    }
+}
+#endif
+
+static void gtf_timings(int x, int y, int freq,	uint32_t *clock,
+        uint16_t *hsyncstart, uint16_t *hsyncend, uint16_t *hblank,
+        uint16_t *vsyncstart, uint16_t *vsyncend, uint16_t *vblank)
+{
+    int hbl, vbl, vfreq;
+
+    vbl = y + (y+1)/(20000.0/(11*freq) - 1) + 1.5;
+    vfreq = vbl * freq;
+    hbl = 16 * (int)(x * (30.0 - 300000.0 / vfreq) /
+            (70.0 + 300000.0 / vfreq) / 16.0 + 0.5);
+
+    *vsyncstart = y;
+    *vsyncend = y + 3;
+    *vblank = vbl - 1;
+    *hsyncstart = x + hbl / 2 - (x + hbl + 50) / 100 * 8 - 1;
+    *hsyncend = x + hbl / 2 - 1;
+    *hblank = x + hbl - 1;
+    *clock = (x + hbl) * vfreq / 1000;
+}
+
+static int set_mode(vbios_map * map, unsigned int mode,
+		     unsigned int x, unsigned int y, unsigned int bp,
+		     unsigned int htotal, unsigned int vtotal)
+{
+    int xprev, yprev;
+    unsigned int i, j;
+    int rv = -1;
+
+    for (i=0; i < map->mode_table_size; i++) {
+        if (map->mode_table[i].mode == mode) {
+            switch(map->bios) {
+            case BT_1:
+                {
+                    vbios_resolution_type1 * res = map_type1_resolution(map, map->mode_table[i].resolution);
+		    uint32_t clock;
+		    uint16_t hsyncstart, hsyncend, hblank;
+		    uint16_t vsyncstart, vsyncend, vblank;
+                    
+                    if (bp) {
+                        map->mode_table[i].bits_per_pixel = bp;
+                    }
+
+		    gtf_timings(x, y, freqs[0], &clock,
+				&hsyncstart, &hsyncend, &hblank,
+				&vsyncstart, &vsyncend, &vblank);
+		    
+		    status("x = %d, y = %d, clock = %lu, h = %d %d %d, v = %d %d %d\n",
+			  x, y, clock,
+			  hsyncstart, hsyncend, hblank,
+			  vsyncstart, vsyncend, vblank);
+
+		    htotal = htotal ? htotal : (unsigned int)hblank+1;
+		    vtotal = vtotal ? vtotal : (unsigned int)vblank+1;
+
+		    res->clock = clock/10; /* Units appear to be 10 kHz */
+                    res->x2 = (((htotal-x) >> 8) & 0x0f) | ((x >> 4) & 0xf0);
+                    res->x1 = (x & 0xff);
+                    
+                    res->y2 = (((vtotal-y) >> 8) & 0x0f) | ((y >> 4) & 0xf0);
+                    res->y1 = (y & 0xff);
+		    if (htotal)
+			res->x_total = ((htotal-x) & 0xff);
+
+		    if (vtotal)
+			res->y_total = ((vtotal-y) & 0xff);
+
+		    rv = 0;
+                }
+                break;
+            case BT_2:
+                {
+                    vbios_resolution_type2 * res = map_type2_resolution(map, map->mode_table[i].resolution);
+
+                    res->xchars = x / 8;
+                    res->ychars = y / 16 - 1;
+                    xprev = res->modelines[0].x1;
+                    yprev = res->modelines[0].y1;
+
+                    for(j=0; j < 3; j++) {
+                        vbios_modeline_type2 * modeline = &res->modelines[j];
+                        
+                        if (modeline->x1 == xprev && modeline->y1 == yprev) {
+                            modeline->x1 = modeline->x2 = x-1;
+                            modeline->y1 = modeline->y2 = y-1;
+
+                            gtf_timings(x, y, freqs[j], &modeline->clock,
+                                    &modeline->hsyncstart, &modeline->hsyncend,
+                                    &modeline->hblank, &modeline->vsyncstart,
+                                    &modeline->vsyncend, &modeline->vblank);
+
+                            if (htotal)
+                                modeline->htotal = htotal;
+                            else
+                                modeline->htotal = modeline->hblank;
+
+                            if (vtotal)
+                                modeline->vtotal = vtotal;
+                            else
+                                modeline->vtotal = modeline->vblank;
+                        }
+                    }
+
+		    rv = 0;
+                }
+                break;
+            case BT_3:
+                {
+                    vbios_resolution_type3 * res = map_type3_resolution(map, map->mode_table[i].resolution);
+                    
+                    xprev = res->modelines[0].x1;
+                    yprev = res->modelines[0].y1;
+
+                    for (j=0; j < 3; j++) {
+                        vbios_modeline_type3 * modeline = &res->modelines[j];
+                        
+                        if (modeline->x1 == xprev && modeline->y1 == yprev) {
+                            modeline->x1 = modeline->x2 = x-1;
+                            modeline->y1 = modeline->y2 = y-1;
+                            
+                            gtf_timings(x, y, freqs[j], &modeline->clock,
+                                    &modeline->hsyncstart, &modeline->hsyncend,
+                                    &modeline->hblank, &modeline->vsyncstart,
+                                    &modeline->vsyncend, &modeline->vblank);
+                            if (htotal)
+                                modeline->htotal = htotal;
+                            else
+                                modeline->htotal = modeline->hblank;
+                            if (vtotal)
+                                modeline->vtotal = vtotal;
+                            else
+                                modeline->vtotal = modeline->vblank;
+
+                            modeline->timing_h   = y-1;
+                            modeline->timing_v   = x-1;
+                        }
+                    }
+
+		    rv = 0;
+                }
+                break;
+            case BT_UNKWN:
+                break;
+            }
+        }
+    }
+
+    return rv;
+}   
+
+static inline void display_map_info(vbios_map * map) {
+#ifdef DEBUG
+    static const char * bios_type_names[] =
+	{"UNKNOWN", "TYPE 1", "TYPE 2", "TYPE 3"};
+    static const char * chipset_type_names[] = {
+	"UNKNOWN", "830", "845G", "855GM", "865G", "915G", "915GM", "945G",
+	"945GM", "946GZ", "G965", "Q965", "945GME"
+    };
+
+    debug("Chipset: %s\r\n", chipset_type_names[map->chipset]);
+    debug("BIOS: %s\r\n", bios_type_names[map->bios]);
+
+    debug("Mode Table Offset: $C0000 + $%x\r\n",
+	  ((unsigned int)map->mode_table) - ((unsigned int)map->bios_ptr));
+    debug("Mode Table Entries: %u\r\n", map->mode_table_size);
+#endif
+    (void)map;
+}
+
+int __vesacon_i915resolution(int x, int y)
+{
+    vbios_map * map;
+    unsigned int mode = 0x52;	/* 800x600x32 mode in known BIOSes */
+    unsigned int bp = 32;	/* 32 bits per pixel */
+    int rv = 0;
+
+    good_marker(0);
+
+    map = open_vbios();
+    if (!map)
+	return -1;
+
+    good_marker(1);
+
+    display_map_info(map);
+
+    debug("\r\n");
+
+    if (mode && x && y) {
+	good_marker(2);
+	cli();
+	good_marker(3);
+	unlock_vbios(map);
+	good_marker(4);
+        rv = set_mode(map, mode, x, y, bp, 0, 0);
+	if (rv)
+	    bad_marker(5);
+	else
+	    good_marker(5);
+	relock_vbios(map);
+	good_marker(6);
+	sti();
+        
+        debug("Patch mode %02x to resolution %dx%d complete\r\n", mode, x, y);
+    }
+    close_vbios(map);
+    
+    return rv;
+}
diff --git a/com32/lib/sys/vesa/initvesa.c b/com32/lib/sys/vesa/initvesa.c
index f1224a1..0a436f4 100644
--- a/com32/lib/sys/vesa/initvesa.c
+++ b/com32/lib/sys/vesa/initvesa.c
@@ -318,8 +318,13 @@ int __vesacon_init(int x, int y)
 	return 10;
 
     rv = vesacon_set_mode(x, y);
-    if (rv)
-	return rv;
+    if (rv) {
+	/* Try to see if we can just patch the BIOS... */
+	if (__vesacon_i915resolution(x, y))
+	    return rv;
+	if (vesacon_set_mode(x, y))
+	    return rv;
+    }
 
     init_text_display();
 
diff --git a/com32/lib/sys/vesa/video.h b/com32/lib/sys/vesa/video.h
index 764228a..d14494b 100644
--- a/com32/lib/sys/vesa/video.h
+++ b/com32/lib/sys/vesa/video.h
@@ -92,4 +92,6 @@ void __vesacon_set_cursor(int, int, bool);
 void __vesacon_copy_to_screen(size_t, const uint32_t *, size_t);
 void __vesacon_init_copy_to_screen(void);
 
+int __vesacon_i915resolution(int x, int y);
+
 #endif /* LIB_SYS_VESA_VIDEO_H */



More information about the Syslinux-commits mailing list