diff options
Diffstat (limited to 'tools/ddcprobe/vbe.c')
-rw-r--r-- | tools/ddcprobe/vbe.c | 604 |
1 files changed, 153 insertions, 451 deletions
diff --git a/tools/ddcprobe/vbe.c b/tools/ddcprobe/vbe.c index a67e56d0b..b710c79bb 100644 --- a/tools/ddcprobe/vbe.c +++ b/tools/ddcprobe/vbe.c @@ -1,5 +1,7 @@ #include <sys/types.h> +#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__) #include <sys/io.h> +#endif #include <sys/mman.h> #include <netinet/in.h> #include <stdlib.h> @@ -8,331 +10,173 @@ #include <assert.h> #include <limits.h> #include <ctype.h> -#include "lrmi.h" +#include <fcntl.h> +#include <unistd.h> #include "vesamode.h" #include "vbe.h" -#ident "$Id$" - -/* Return information about a particular video mode. */ -struct vbe_mode_info *vbe_get_mode_info(u_int16_t mode) -{ - struct LRMI_regs regs; - char *mem; - struct vbe_mode_info *ret = NULL; - - /* Initialize LRMI. */ - if(LRMI_init() == 0) { - return NULL; - } - - /* Allocate a chunk of memory. */ - mem = LRMI_alloc_real(sizeof(struct vbe_mode_info)); - if(mem == NULL) { - return NULL; - } - memset(mem, 0, sizeof(struct vbe_mode_info)); - - memset(®s, 0, sizeof(regs)); - regs.eax = 0x4f01; - regs.ecx = mode; - regs.es = ((u_int32_t)mem) >> 4; - regs.edi = ((u_int32_t)mem) & 0x0f; - - /* Do it. */ - iopl(3); - ioperm(0, 0x400, 1); - - if(LRMI_int(0x10, ®s) == 0) { - LRMI_free_real(mem); - return NULL; - } - - /* Check for successful return. */ - if((regs.eax & 0xffff) != 0x004f) { - LRMI_free_real(mem); - return NULL; - } - - /* Get memory for return. */ - ret = malloc(sizeof(struct vbe_mode_info)); - if(ret == NULL) { - LRMI_free_real(mem); - return NULL; - } +#ifdef HAVE_VBE +#include "int10/vbios.h" +#endif - /* Copy the buffer for return. */ - memcpy(ret, mem, sizeof(struct vbe_mode_info)); +#define DEBUG 0 +#if DEBUG +#define bug printf +#define D(X) X +#else +#define D(X) +#endif - /* Clean up and return. */ - LRMI_free_real(mem); - return ret; -} +#ifdef __i386__ +#define cpuemu 1 +#else +#define cpuemu 0 +#endif -/* Get VBE info. */ -struct vbe_info *vbe_get_vbe_info() +#ifdef HAVE_VBE +/* + * 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) { - struct LRMI_regs regs; - unsigned char *mem; - struct vbe_info *ret = NULL; - int i; - - /* Initialize LRMI. */ - if(LRMI_init() == 0) { - return NULL; - } - - /* Allocate a chunk of memory. */ - mem = LRMI_alloc_real(sizeof(struct vbe_mode_info)); - if(mem == NULL) { - return NULL; - } - memset(mem, 0, sizeof(struct vbe_mode_info)); - - /* Set up registers for the interrupt call. */ - memset(®s, 0, sizeof(regs)); - regs.eax = 0x4f00; - regs.es = ((u_int32_t)mem) >> 4; - regs.edi = ((u_int32_t)mem) & 0x0f; - memcpy(mem, "VBE2", 4); - - /* Do it. */ - iopl(3); - ioperm(0, 0x400, 1); - - if(LRMI_int(0x10, ®s) == 0) { - LRMI_free_real(mem); - return NULL; - } - - /* Check for successful return code. */ - if((regs.eax & 0xffff) != 0x004f) { - LRMI_free_real(mem); - return NULL; - } - - /* Get memory to return the information. */ - ret = malloc(sizeof(struct vbe_info)); - if(ret == NULL) { - LRMI_free_real(mem); - return NULL; - } - memcpy(ret, mem, sizeof(struct vbe_info)); - - /* Set up pointers to usable memory. */ - ret->mode_list.list = (u_int16_t*) ((ret->mode_list.addr.seg << 4) + - (ret->mode_list.addr.ofs)); - ret->oem_name.string = (char*) ((ret->oem_name.addr.seg << 4) + - (ret->oem_name.addr.ofs)); - - /* Snip, snip. */ - mem = strdup(ret->oem_name.string); /* leak */ - while(((i = strlen(mem)) > 0) && isspace(mem[i - 1])) { - mem[i - 1] = '\0'; - } - ret->oem_name.string = mem; - - /* Set up pointers for VESA 3.0+ strings. */ - if(ret->version[1] >= 3) { - - /* Vendor name. */ - ret->vendor_name.string = (char*) - ((ret->vendor_name.addr.seg << 4) - + (ret->vendor_name.addr.ofs)); - - mem = strdup(ret->vendor_name.string); /* leak */ - while(((i = strlen(mem)) > 0) && isspace(mem[i - 1])) { - mem[i - 1] = '\0'; - } - ret->vendor_name.string = mem; - - /* Product name. */ - ret->product_name.string = (char*) - ((ret->product_name.addr.seg << 4) - + (ret->product_name.addr.ofs)); - - mem = strdup(ret->product_name.string); /* leak */ - while(((i = strlen(mem)) > 0) && isspace(mem[i - 1])) { - mem[i - 1] = '\0'; - } - ret->product_name.string = mem; - - /* Product revision. */ - ret->product_revision.string = (char*) - ((ret->product_revision.addr.seg << 4) - + (ret->product_revision.addr.ofs)); - - mem = strdup(ret->product_revision.string); /* leak */ - while(((i = strlen(mem)) > 0) && isspace(mem[i - 1])) { - mem[i - 1] = '\0'; - } - ret->product_revision.string = mem; - } - - /* Cleanup. */ - LRMI_free_real(mem); - return ret; + 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; } -/* Check if EDID queries are suorted. */ -int vbe_get_edid_supported() +static unsigned segofs2addr(unsigned char *segofs) { - struct LRMI_regs regs; - int ret = 0; - - /* Initialize LRMI. */ - if(LRMI_init() == 0) { - return 0; - } - - memset(®s, 0, sizeof(regs)); - regs.eax = 0x4f15; - regs.ebx = 0x0000; - regs.es = 0x3000; - regs.edi = 0x3000; - - /* Do it. */ - iopl(3); - ioperm(0, 0x400, 1); - - if(LRMI_int(0x10, ®s) == 0) { - return 0; - } - - /* Check for successful return. */ - if((regs.eax & 0xff) == 0x4f) { - /* Supported. */ - ret = 1; - } else { - /* Not supported. */ - ret = 0; - } - - /* Clean up and return. */ - return ret; + return segofs[0] + (segofs[1] << 8) + (segofs[2] << 4)+ (segofs[3] << 12); } -/* Get EDID info. */ -struct vbe_edid1_info *vbe_get_edid_info() -{ - struct LRMI_regs regs; - unsigned char *mem; - struct vbe_edid1_info *ret = NULL; - u_int16_t man; - - /* Initialize LRMI. */ - if(LRMI_init() == 0) { - return NULL; - } - - /* Allocate a chunk of memory. */ - mem = LRMI_alloc_real(sizeof(struct vbe_edid1_info)); - if(mem == NULL) { - return NULL; - } - memset(mem, 0, sizeof(struct vbe_edid1_info)); - - memset(®s, 0, sizeof(regs)); - regs.eax = 0x4f15; - regs.ebx = 0x0001; - regs.es = ((u_int32_t)mem) >> 4; - regs.edi = ((u_int32_t)mem) & 0x0f; - /* Do it. */ - iopl(3); - ioperm(0, 0x400, 1); - - if(LRMI_int(0x10, ®s) == 0) { - LRMI_free_real(mem); - return NULL; - } - -#if 0 - /* Check for successful return. */ - if((regs.eax & 0xffff) != 0x004f) { - LRMI_free_real(mem); - return NULL; - } -#elseif - /* Check for successful return. */ - if((regs.eax & 0xff) != 0x4f) { - LRMI_free_real(mem); - return NULL; - } -#endif - - /* Get memory for return. */ - ret = malloc(sizeof(struct vbe_edid1_info)); - if(ret == NULL) { - LRMI_free_real(mem); - return NULL; - } - - /* Copy the buffer for return. */ - memcpy(ret, mem, sizeof(struct vbe_edid1_info)); - - memcpy(&man, &ret->manufacturer_name, 2); - man = ntohs(man); - memcpy(&ret->manufacturer_name, &man, 2); - - LRMI_free_real(mem); - return ret; -} - -/* Figure out what the current video mode is. */ -int32_t vbe_get_mode() +static unsigned get_data(unsigned char *buf, unsigned buf_size, unsigned addr) { - struct LRMI_regs regs; - int32_t ret = -1; - - /* Initialize LRMI. */ - if(LRMI_init() == 0) { - return -1; - } - - memset(®s, 0, sizeof(regs)); - regs.eax = 0x4f03; + 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; +} - /* Do it. */ - iopl(3); - ioperm(0, 0x400, 1); +#define GET_WORD(ADDR, OFS) ((ADDR)[OFS] + ((ADDR)[(OFS) + 1] << 8)) - if(LRMI_int(0x10, ®s) == 0) { - return -1; - } - - /* Save the returned value. */ - if((regs.eax & 0xffff) == 0x004f) { - ret = regs.ebx & 0xffff; - } else { - ret = -1; - } - - /* Clean up and return. */ - return ret; +int vbe_get_vbe_info(struct vbe_info *vbe) +{ + int i, l, u; + unsigned char v[0x200]; + unsigned char tmp[1024]; + int ax, bx, cx; + + if (vbe == NULL) + return 0; + + /* 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) { + D(bug("VBE: Error (0x4f00): 0x%04x\n", i)); + return 0; + } + + /* Parse VBE block */ + vbe->version = GET_WORD(v, 0x04); + vbe->oem_version = GET_WORD(v, 0x14); + vbe->memory_size = GET_WORD(v, 0x12) << 16; + D(bug("version = %u.%u, oem version = %u.%u\n", + vbe->version >> 8, vbe->version & 0xff, vbe->oem_version >> 8, vbe->oem_version & 0xff)); + D(bug("memory = %uk\n", vbe->memory_size >> 10)); + + l = get_data(tmp, sizeof tmp, u = segofs2addr(v + 0x06)); + vbe->oem_name = canon_str(tmp, l); + D(bug("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); + D(bug("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); + D(bug("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); + D(bug("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; + } + D(bug("%u video modes\n", vbe->modes)); + + return 1; } -/* Set the video mode. */ -void vbe_set_mode(u_int16_t mode) +/* Get EDID info. */ +int vbe_get_edid_info(struct vbe_edid1_info *edid) { - struct LRMI_regs regs; - - /* Initialize LRMI. */ - if(LRMI_init() == 0) { - return; - } - - memset(®s, 0, sizeof(regs)); - regs.eax = 0x4f02; - regs.ebx = mode; - - /* Do it. */ - iopl(3); - ioperm(0, 0x400, 1); - LRMI_int(0x10, ®s); - - /* Return. */ - return; + int i; + int ax, bx, cx; + + if (edid == NULL) + return 0; + + /* Setup registers for the interrupt call */ + ax = 0x4f15; + bx = 1; + cx = 0; + + /* Get EDID block */ + i = CallInt10(&ax, &bx, &cx, (unsigned char *)edid, sizeof *edid, cpuemu) & 0xffff; + if (i != 0x4f) { + D(bug("EDID: Error (0x4f15): 0x%04x\n", i)); + return 0; + } + + edid->manufacturer_name.p = ntohs(edid->manufacturer_name.p); + return 1; } +#endif /* Just read ranges from the EDID. */ void vbe_get_edid_ranges(struct vbe_edid1_info *edid, @@ -364,16 +208,14 @@ static int compare_vbe_modelines(const void *m1, const void *m2) return 0; } -struct vbe_modeline *vbe_get_edid_modelines() +struct vbe_modeline *vbe_get_edid_modelines(struct vbe_edid1_info *edid) { - struct vbe_edid1_info *edid; struct vbe_modeline *ret; char buf[LINE_MAX]; int modeline_count = 0, i, j; - if((edid = vbe_get_edid_info()) == NULL) { - return NULL; - } + if (edid == NULL) + return NULL; memcpy(buf, &edid->established_timings, sizeof(edid->established_timings)); @@ -567,143 +409,3 @@ struct vbe_modeline *vbe_get_edid_modelines() return ret; } - -const void *vbe_save_svga_state() -{ - struct LRMI_regs regs; - unsigned char *mem; - u_int16_t block_size; - void *data; - - /* Initialize LRMI. */ - if(LRMI_init() == 0) { - return NULL; - } - - memset(®s, 0, sizeof(regs)); - regs.eax = 0x4f04; - regs.ecx = 0xffff; - regs.edx = 0; - - iopl(3); - ioperm(0, 0x400, 1); - - if(LRMI_int(0x10, ®s) == 0) { - return NULL; - } - - if((regs.eax & 0xff) != 0x4f) { - fprintf(stderr, "Get SuperVGA Video State not supported.\n"); - return NULL; - } - - if((regs.eax & 0xffff) != 0x004f) { - fprintf(stderr, "Get SuperVGA Video State Info failed.\n"); - return NULL; - } - - block_size = 64 * (regs.ebx & 0xffff); - - /* Allocate a chunk of memory. */ - mem = LRMI_alloc_real(block_size); - if(mem == NULL) { - return NULL; - } - memset(mem, 0, sizeof(block_size)); - - memset(®s, 0, sizeof(regs)); - regs.eax = 0x4f04; - regs.ecx = 0x000f; - regs.edx = 0x0001; - regs.es = ((u_int32_t)mem) >> 4; - regs.ebx = ((u_int32_t)mem) & 0x0f; - memset(mem, 0, block_size); - iopl(3); - ioperm(0, 0x400, 1); - - if(LRMI_int(0x10, ®s) == 0) { - LRMI_free_real(mem); - return NULL; - } - - if((regs.eax & 0xffff) != 0x004f) { - fprintf(stderr, "Get SuperVGA Video State Save failed.\n"); - return NULL; - } - - data = malloc(block_size); - if(data == NULL) { - LRMI_free_real(mem); - return NULL; - } - - /* Clean up and return. */ - memcpy(data, mem, block_size); - LRMI_free_real(mem); - return data; -} - -void vbe_restore_svga_state(const void *state) -{ - struct LRMI_regs regs; - unsigned char *mem; - u_int16_t block_size; - - /* Initialize LRMI. */ - if(LRMI_init() == 0) { - return; - } - - memset(®s, 0, sizeof(regs)); - regs.eax = 0x4f04; - regs.ecx = 0x000f; - regs.edx = 0; - - /* Find out how much memory we need. */ - iopl(3); - ioperm(0, 0x400, 1); - - if(LRMI_int(0x10, ®s) == 0) { - return; - } - - if((regs.eax & 0xff) != 0x4f) { - fprintf(stderr, "Get SuperVGA Video State not supported.\n"); - return; - } - - if((regs.eax & 0xffff) != 0x004f) { - fprintf(stderr, "Get SuperVGA Video State Info failed.\n"); - return; - } - - block_size = 64 * (regs.ebx & 0xffff); - - /* Allocate a chunk of memory. */ - mem = LRMI_alloc_real(block_size); - if(mem == NULL) { - return; - } - memset(mem, 0, sizeof(block_size)); - - memset(®s, 0, sizeof(regs)); - regs.eax = 0x4f04; - regs.ecx = 0x000f; - regs.edx = 0x0002; - regs.es = 0x2000; - regs.ebx = 0x0000; - memcpy(mem, state, block_size); - - iopl(3); - ioperm(0, 0x400, 1); - - if(LRMI_int(0x10, ®s) == 0) { - LRMI_free_real(mem); - return; - } - - if((regs.eax & 0xffff) != 0x004f) { - fprintf(stderr, "Get SuperVGA Video State Restore failed.\n"); - return; - } -} |