From c491f8e99349e4022fac0dec6536ab4b43396507 Mon Sep 17 00:00:00 2001 From: Pascal Rigaux Date: Wed, 23 Feb 2005 17:33:43 +0000 Subject: *** empty log message *** --- vbe.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 vbe.c (limited to 'vbe.c') diff --git a/vbe.c b/vbe.c new file mode 100644 index 0000000..eb6c918 --- /dev/null +++ b/vbe.c @@ -0,0 +1,214 @@ +#include +#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "get-edid.h" +#include "int10/vbios.h" + +#ifdef __i386__ +#define cpuemu 1 +#else +#define cpuemu 0 +#endif + +#include + +/* used by libint10 */ +void log_err(char *format, ...) +{ + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); +} + +#ifdef DEBUG +/* Record returned by int 0x10, function 0x4f, subfunction 0x00. */ +struct vbe_info { + unsigned int version; + unsigned int oem_version; + unsigned int memory_size; + char *oem_name; + char *vendor_name; + char *product_name; + char *product_revision; + unsigned int modes; + unsigned int mode_list[0x100]; +}; + +/* + * Create a 'canonical' version, i.e. no spaces at start and end. + * + * Note: removes chars >= 0x80 as well (due to (char *))! This + * is currently considered a feature. + */ +static char *canon_str(char *s, int len) +{ + char *m2, *m1, *m0 = malloc(len + 1); + int i; + + for(m1 = m0, i = 0; i < len; i++) { + if(m1 == m0 && s[i] <= ' ') continue; + *m1++ = s[i]; + } + *m1 = 0; + while(m1 > m0 && m1[-1] <= ' ') { + *--m1 = 0; + } + + m2 = strdup(m0); + free(m0); + + return m2; +} + +static unsigned segofs2addr(unsigned char *segofs) +{ + return segofs[0] + (segofs[1] << 8) + (segofs[2] << 4)+ (segofs[3] << 12); +} + + +static unsigned get_data(unsigned char *buf, unsigned buf_size, unsigned addr) +{ + unsigned bufferaddr = 0x7e00; + unsigned len; + + *buf = 0; + len = 0; + + if(addr >= bufferaddr && addr < bufferaddr + 0x200) { + len = bufferaddr + 0x200 - addr; + if(len >= buf_size) len = buf_size - 1; + memcpy(buf, addr + (char *) 0, len); + } + else if(addr >= 0x0c0000 && addr < 0x100000) { + len = 0x100000 - addr; + if(len >= buf_size) len = buf_size - 1; + memcpy(buf, addr + (char *) 0, len); + } + + buf[len] = 0; + + return len; +} +#endif + +#define GET_WORD(ADDR, OFS) ((ADDR)[OFS] + ((ADDR)[(OFS) + 1] << 8)) + +int vbe_check_vbe_info(void) +{ + int i; + unsigned char v[0x200]; + int ax, bx, cx; + + /* Setup registers for the interrupt call */ + ax = 0x4f00; + bx = 0; + cx = 0; + memset(v, 0, sizeof(v)); + strcpy(v, "VBE2"); + + /* Get VBE block */ + i = CallInt10(&ax, &bx, &cx, v, sizeof(v), cpuemu) & 0xffff; + if (i != 0x4f) { +#ifdef DEBUG + log_err("VBE: Error (0x4f00): 0x%04x\n", i); +#endif + return 0; + } + +#ifdef DEBUG + { + int l, u; + unsigned char tmp[1024]; + struct vbe_info vbe; + + /* Parse VBE block */ + vbe.version = GET_WORD(v, 0x04); + vbe.oem_version = GET_WORD(v, 0x14); + vbe.memory_size = GET_WORD(v, 0x12) << 16; + log_err("version = %u.%u, oem version = %u.%u\n", + vbe.version >> 8, vbe.version & 0xff, vbe.oem_version >> 8, vbe.oem_version & 0xff); + log_err("memory = %uk\n", vbe.memory_size >> 10); + + l = get_data(tmp, sizeof tmp, u = segofs2addr(v + 0x06)); + vbe.oem_name = canon_str(tmp, l); + log_err("oem name [0x%05x] = \"%s\"\n", u, vbe.oem_name); + + l = get_data(tmp, sizeof tmp, u = segofs2addr(v + 0x16)); + vbe.vendor_name = canon_str(tmp, l); + log_err("vendor name [0x%05x] = \"%s\"\n", u, vbe.vendor_name); + + l = get_data(tmp, sizeof tmp, u = segofs2addr(v + 0x1a)); + vbe.product_name = canon_str(tmp, l); + log_err("product name [0x%05x] = \"%s\"\n", u, vbe.product_name); + + l = get_data(tmp, sizeof tmp, u = segofs2addr(v + 0x1e)); + vbe.product_revision = canon_str(tmp, l); + log_err("product revision [0x%05x] = \"%s\"\n", u, vbe.product_revision); + + l = get_data(tmp, sizeof tmp, u = segofs2addr(v + 0x0e)) >> 1; + for(i = vbe.modes = 0; i < l && i < sizeof vbe.mode_list / sizeof *vbe.mode_list; i++) { + u = GET_WORD(tmp, 2 * i); + if(u != 0xffff) + vbe.mode_list[vbe.modes++] = u; + else + break; + } + log_err("%u video modes\n", vbe.modes); + } +#endif + return 1; +} + +/* Get EDID info. */ +int vbe_get_edid_info(char *edid) +{ + int i; + int ax, bx, cx; + + /* Setup registers for the interrupt call */ + ax = 0x4f15; + bx = 1; + cx = 0; + + /* Get EDID block */ + i = CallInt10(&ax, &bx, &cx, edid, 256, cpuemu) & 0xffff; + if (i != 0x4f) { +#ifdef DEBUG + log_err("EDID: Error (0x4f15): 0x%04x\n", i); +#endif + return 0; + } + + return 1; +} + +int get_edid(char *edid) +{ + int pci_config_type = 1; /* Determine PCI configuration type */ + int ok; + + /* Initialize Int10 */ + ok = InitInt10(pci_config_type) == 0; + + if (ok) { + ok = + vbe_check_vbe_info() && + vbe_get_edid_info(edid); + + FreeInt10(); + } + + return ok ? 128 : 0; +} -- cgit v1.2.1