aboutsummaryrefslogtreecommitdiffstats
path: root/vbe.c
diff options
context:
space:
mode:
authorPascal Rigaux <pixel@mandriva.com>2005-02-23 17:33:43 +0000
committerPascal Rigaux <pixel@mandriva.com>2005-02-23 17:33:43 +0000
commitc491f8e99349e4022fac0dec6536ab4b43396507 (patch)
treedfc2f6bba4d40995ef4e0c152a533ad12ff47d1e /vbe.c
parent3b6ec4ddecee5811e38d757f15a56edfbce79b4a (diff)
downloadmonitor-edid-c491f8e99349e4022fac0dec6536ab4b43396507.tar
monitor-edid-c491f8e99349e4022fac0dec6536ab4b43396507.tar.gz
monitor-edid-c491f8e99349e4022fac0dec6536ab4b43396507.tar.bz2
monitor-edid-c491f8e99349e4022fac0dec6536ab4b43396507.tar.xz
monitor-edid-c491f8e99349e4022fac0dec6536ab4b43396507.zip
*** empty log message ***
Diffstat (limited to 'vbe.c')
-rw-r--r--vbe.c214
1 files changed, 214 insertions, 0 deletions
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 <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>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "get-edid.h"
+#include "int10/vbios.h"
+
+#ifdef __i386__
+#define cpuemu 1
+#else
+#define cpuemu 0
+#endif
+
+#include <stdarg.h>
+
+/* 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;
+}