summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Willem Klok <gwk@cvs.openbsd.org>2007-02-18 19:19:03 +0000
committerGordon Willem Klok <gwk@cvs.openbsd.org>2007-02-18 19:19:03 +0000
commit45c7280ff3359e4b3a375cba281e43838cfa93e6 (patch)
tree77d8d32e08142096df90a7e2a7a50be238204f85
parent2f40e49e058a82c84ee4d4fd7f752b05906d8595 (diff)
Add currently unused functions for getting EDID information (max supported
resolution, hsync, vsync etc) from the monitor using DDC. Cleanup a whole bunch of magic, ok deraadt
-rw-r--r--sys/dev/vesa/vbe.h151
-rw-r--r--sys/dev/vesa/vesabios.c46
-rw-r--r--sys/dev/vesa/vesafb.c95
3 files changed, 247 insertions, 45 deletions
diff --git a/sys/dev/vesa/vbe.h b/sys/dev/vesa/vbe.h
new file mode 100644
index 00000000000..9196866d7a8
--- /dev/null
+++ b/sys/dev/vesa/vbe.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2007 Gordon Willem Klok <gwk@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Information taken from VESA Bios Extention (VBE) Core Functions Standard
+ * Version 3.0 found at http://www.vesa.org/public/VBE/vbe3.pdf
+ */
+#ifndef VBE_H
+#define VBE_H
+
+#define BIOS_VIDEO_INTR 0x10
+
+/* A well know address to locate a page at in the vm86 task */
+#define KVM86_CALL_TASKVA 0x2000
+
+/* Information contained in AH following a VBE function call */
+/* Low byte determins call support */
+#define VBECALL_SUPPORT(v) (v & 0xff)
+#define VBECALL_SUPPORTED 0x4f
+
+/* High byte determins call sucess */
+#define VBECALL_SUCESS(v) (v >> 8 & 0xFF)
+#define VBECALL_SUCCEDED 0x00
+#define VBECALL_FAILED 0x01
+#define VBECALL_MISMATCH 0x02 /* BIOS SUPPORTS HW DOES NOT */
+#define VBECALL_INVALID 0x03 /* INVALID IN CURRENT MODE */
+
+/* VBE Standard Function Calls */
+#define VBE_FUNC_CTRLINFO 0x4F00
+#define VBE_FUNC_MODEINFO 0x4F01
+#define VBE_FUNC_SETMODE 0x4F02
+#define VBE_FUNC_GETMODE 0x4F03
+#define VBE_FUNC_SAVEREST 0x4F04
+#define VBE_FUNC_DWC 0x4F05 /* Display window control */
+#define VBE_FUNC_LSLL 0x4F06 /* Logical Scan Line Length */
+#define VBE_FUNC_START 0x4F07 /* Set/Get Display Start */
+#define VBE_FUNC_DAC 0x4F08 /* Set/Get DAC Pallete Format */
+#define VBE_FUNC_PALETTE 0x4F09 /* Set/Get Pallete Data */
+#define VBE_FUNC_PMI 0x4F0A /* Protected Mode Interface */
+#define VBE_FUNC_PIXELCLOCK 0x4F0B
+
+/* VBE Supplemental Function Calls */
+#define VBE_FUNC_PM 0x4F10 /* Power Management Interface */
+#define VBE_FUNC_FLATPANEL 0x4F11 /* Flat Panel Interface */
+#define VBE_FUNC_AUDIO 0x4F13 /* Audio Interface */
+#define VBE_FUNC_OEM 0x4F14 /* OEM Extentions */
+#define VBE_FUNC_DDC 0x4F15 /* Display Data Channel (DDC) */
+
+#define VBE_CTRLINFO_VERSION(v) (v >> 8)
+#define VBE_CTRLINFO_REVISION(v) (v & 0xff)
+#define VBE_DDC_GET 0x01
+
+struct edid_chroma {
+ uint8_t chroma_rglow;
+ uint8_t chroma_bwlow;
+ uint8_t chroma_redx;
+ uint8_t chroma_redy;
+ uint8_t chroma_greenx;
+ uint8_t chroma_greeny;
+ uint8_t chroma_bluex;
+ uint8_t chroma_bluey;
+ uint8_t chroma_whitex;
+ uint8_t chroma_whitey;
+} __packed;
+
+struct edid_db {
+ uint16_t db_pixelclock;
+ uint8_t db_stor[16];
+} __packed;
+
+#define EDID_DB_FLAG_INTERLACED 0x80
+#define EDID_DB_FLAG_STEREO 0x10
+#define EDID_DB_POSITIVE_HSYNC 0x04
+#define EDID_DB_POSITIVE_VSYNC 0x02
+
+/* Types of Descriptor Blocks */
+#define EDID_DB_BT_MONSERIAL 0xff
+#define EDID_DB_BT_ASCIISTR 0xfe
+#define EDID_DB_BT_RANGELIMITS 0xfd
+#define EDID_DB_BT_MONITORNAME 0xfc
+#define EDID_DB_BT_COLORPOINT 0xfb
+#define EDID_DB_BT_STDTIMEDATA 0xfa
+#define EDID_DB_BT_UNDEF 0xf9
+#define EDID_DB_BT_MANUFDEF 0xf8
+
+struct edid_ranges {
+ uint8_t range_minvertfreq;
+ uint8_t range_maxvertfreq;
+ uint8_t range_minhorizfreq;
+ uint8_t range_maxhorizfreq;
+ uint8_t range_pixelclock;
+ uint16_t range_secgtftoggle;
+ uint8_t range_starthorizfreq;
+ uint8_t range_c;
+ uint16_t range_m;
+ uint16_t range_k;
+ uint16_t range_y;
+} __packed;
+
+struct edid_timing {
+ uint8_t timing_estb1;
+ uint8_t timing_estb2;
+ uint8_t timing_manu;
+ uint16_t timing_std1;
+ uint16_t timing_std2;
+ uint16_t timing_std3;
+ uint16_t timing_std4;
+ uint16_t timing_std5;
+ uint16_t timing_std6;
+ uint16_t timing_std7;
+ uint16_t timing_std8;
+} __packed;
+
+struct edid {
+ uint8_t edid_header[8];
+ uint16_t edid_manufacture;
+ uint16_t edid_product;
+ uint32_t edid_serialno;
+ uint8_t edid_week;
+ uint8_t edid_year;
+ uint8_t edid_version;
+ uint8_t edid_revision;
+ uint8_t edid_vidid;
+ uint8_t edid_maxhoriz_isize;
+ uint8_t edid_maxvert_isize;
+ uint8_t edid_gamma;
+ uint8_t edid_pmfeatures;
+ struct edid_chroma edid_chroma;
+ struct edid_timing edid_timing;
+ struct edid_db edid_db1;
+ struct edid_db edid_db2;
+ struct edid_db edid_db3;
+ struct edid_db edid_db4;
+ uint8_t edid_extblocks;
+ uint8_t edid_chksum;
+} __packed;
+
+#endif
diff --git a/sys/dev/vesa/vesabios.c b/sys/dev/vesa/vesabios.c
index 8fdde7aa962..565cb7504d3 100644
--- a/sys/dev/vesa/vesabios.c
+++ b/sys/dev/vesa/vesabios.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vesabios.c,v 1.3 2007/01/28 20:28:50 gwk Exp $ */
+/* $OpenBSD: vesabios.c,v 1.4 2007/02/18 19:19:02 gwk Exp $ */
/*
* Copyright (c) 2002, 2004
@@ -37,6 +37,7 @@
#include <dev/vesa/vesabiosvar.h>
#include <dev/vesa/vesabiosreg.h>
+#include <dev/vesa/vbe.h>
struct vbeinfoblock
{
@@ -49,7 +50,7 @@ struct vbeinfoblock
uint16_t OemSoftwareRev;
uint32_t OemVendorNamePtr, OemProductNamePtr, OemProductRevPtr;
/* data area, in total max 512 bytes for VBE 2.0 */
-} __attribute__ ((packed));
+} __packed;
#define FAR2FLATPTR(p) ((p & 0xffff) + ((p >> 12) & 0xffff0))
@@ -87,21 +88,20 @@ vbegetinfo(struct vbeinfoblock **vip)
struct trapframe tf;
int res, error;
- buf = kvm86_bios_addpage(0x2000);
- if (!buf) {
- printf("vbegetinfo: kvm86_bios_addpage(0x2000) failed\n");
+ if ((buf = kvm86_bios_addpage(KVM86_CALL_TASKVA)) == NULL) {
+ printf("vbegetinfo: kvm86_bios_addpage failed\n");
return (ENOMEM);
}
memcpy(buf, "VBE2", 4);
memset(&tf, 0, sizeof(struct trapframe));
- tf.tf_eax = 0x4f00; /* function code */
+ tf.tf_eax = VBE_FUNC_CTRLINFO;
tf.tf_vm86_es = 0;
- tf.tf_edi = 0x2000; /* buf ptr */
+ tf.tf_edi = KVM86_CALL_TASKVA;
- res = kvm86_bioscall(0x10, &tf);
- if (res || (tf.tf_eax & 0xff) != 0x4f) {
+ res = kvm86_bioscall(BIOS_VIDEO_INTR, &tf);
+ if (res || VBECALL_SUPPORT(tf.tf_eax) != VBECALL_SUPPORTED) {
printf("vbecall: res=%d, ax=%x\n", res, tf.tf_eax);
error = ENXIO;
goto out;
@@ -117,7 +117,7 @@ vbegetinfo(struct vbeinfoblock **vip)
return (0);
out:
- kvm86_bios_delpage(0x2000, buf);
+ kvm86_bios_delpage(KVM86_CALL_TASKVA, buf);
return (error);
}
@@ -125,7 +125,7 @@ void
vbefreeinfo(struct vbeinfoblock *vip)
{
- kvm86_bios_delpage(0x2000, vip);
+ kvm86_bios_delpage(KVM86_CALL_TASKVA, vip);
}
int
@@ -136,7 +136,7 @@ vbeprobe(void)
if (vbegetinfo(&vi))
return (0);
- if ((vi->VbeVersion >> 8) > 1) {
+ if (VBE_CTRLINFO_VERSION(vi->VbeVersion) > 1) {
/* VESA bios is at least version 2.0 */
found = 1;
}
@@ -190,10 +190,12 @@ vesabios_attach(struct device *parent, struct device *self, void *aux)
}
printf(": version %d.%d",
- vi->VbeVersion >> 8, vi->VbeVersion & 0xff);
+ VBE_CTRLINFO_VERSION(vi->VbeVersion),
+ VBE_CTRLINFO_REVISION(vi->VbeVersion));
+
res = kvm86_bios_read(FAR2FLATPTR(vi->OemVendorNamePtr),
- name, sizeof(name));
+ name, sizeof(name));
sc->sc_size = vi->TotalMemory * 65536;
if (res > 0) {
@@ -224,22 +226,22 @@ vesabios_attach(struct device *parent, struct device *self, void *aux)
nrastermodes = ntextmodes = 0;
- buf = kvm86_bios_addpage(0x2000);
+ buf = kvm86_bios_addpage(KVM86_CALL_TASKVA);
if (!buf) {
- printf("%s: kvm86_bios_addpage(0x2000) failed\n",
+ printf("%s: kvm86_bios_addpage failed\n",
self->dv_xname);
return;
}
for (i = 0; i < nmodes; i++) {
memset(&tf, 0, sizeof(struct trapframe));
- tf.tf_eax = 0x4f01; /* function code */
+ tf.tf_eax = VBE_FUNC_MODEINFO;
tf.tf_ecx = modes[i];
tf.tf_vm86_es = 0;
- tf.tf_edi = 0x2000; /* buf ptr */
+ tf.tf_edi = KVM86_CALL_TASKVA;
- res = kvm86_bioscall(0x10, &tf);
- if (res || (tf.tf_eax & 0xff) != 0x4f) {
+ res = kvm86_bioscall(BIOS_VIDEO_INTR, &tf);
+ if (res || VBECALL_SUPPORT(tf.tf_eax) != VBECALL_SUPPORTED) {
printf("%s: vbecall: res=%d, ax=%x\n",
self->dv_xname, res, tf.tf_eax);
printf("%s: error getting info for mode %04x\n",
@@ -278,9 +280,9 @@ vesabios_attach(struct device *parent, struct device *self, void *aux)
textmodes[ntextmodes++] = modes[i];
}
}
- kvm86_bios_delpage(0x2000, buf);
+ kvm86_bios_delpage(KVM86_CALL_TASKVA, buf);
if (nrastermodes > 0) {
- sc->sc_modes =
+ sc->sc_modes =
(uint16_t *)malloc(sizeof(uint16_t)*nrastermodes,
M_DEVBUF, M_NOWAIT);
if (sc->sc_modes == NULL) {
diff --git a/sys/dev/vesa/vesafb.c b/sys/dev/vesa/vesafb.c
index 9d0598572ce..478d3f0b65d 100644
--- a/sys/dev/vesa/vesafb.c
+++ b/sys/dev/vesa/vesafb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vesafb.c,v 1.3 2007/01/28 20:28:50 gwk Exp $ */
+/* $OpenBSD: vesafb.c,v 1.4 2007/02/18 19:19:02 gwk Exp $ */
/*-
* Copyright (c) 2006 Jared D. McNeill <jmcneill@invisible.ca>
@@ -67,6 +67,7 @@
#include <dev/vesa/vesabiosreg.h>
#include <dev/vesa/vesabiosvar.h>
+#include <dev/vesa/vbe.h>
#include <machine/frame.h>
#include <machine/kvm86.h>
@@ -77,15 +78,61 @@
#include <uvm/uvm_extern.h>
-
void vesafb_set_mode(struct vga_pci_softc *, int);
int vesafb_get_mode(struct vga_pci_softc *);
void vesafb_get_mode_info(struct vga_pci_softc *, int, struct modeinfoblock *);
void vesafb_set_palette(struct vga_pci_softc *, int, struct paletteentry);
int vesafb_putcmap(struct vga_pci_softc *, struct wsdisplay_cmap *);
int vesafb_getcmap(struct vga_pci_softc *, struct wsdisplay_cmap *);
+int vesafb_get_ddc_version(struct vga_pci_softc *);
+int vesafb_get_ddc_info(struct vga_pci_softc *, struct edid *);
+
+int
+vesafb_get_ddc_version(struct vga_pci_softc *sc)
+{
+ struct trapframe tf;
+ int res;
+
+ bzero(&tf, sizeof(struct trapframe));
+ tf.tf_eax = VBE_FUNC_DDC;
+
+ res = kvm86_bioscall(BIOS_VIDEO_INTR, &tf);
+ if (res || VBECALL_SUPPORT(tf.tf_eax) != VBECALL_SUPPORTED)
+ return 0;
+
+ return VBECALL_SUCESS(tf.tf_eax);
+}
+
+int
+vesafb_get_ddc_info(struct vga_pci_softc *sc, struct edid *info)
+{
+ struct trapframe tf;
+ unsigned char *buf;
+ int res;
+
+ if ((buf = kvm86_bios_addpage(KVM86_CALL_TASKVA)) == NULL) {
+ printf("%s: kvm86_bios_addpage failed.\n",
+ sc->sc_dev.dv_xname);
+ return 1;
+ }
+ bzero(&tf, sizeof(struct trapframe));
+ tf.tf_eax = VBE_FUNC_DDC;
+ tf.tf_ebx = VBE_DDC_GET;
+ tf.tf_vm86_es = 0;
+ tf.tf_edi = KVM86_CALL_TASKVA;
+
+ res = kvm86_bioscall(BIOS_VIDEO_INTR, &tf);
+ if (res || VBECALL_SUPPORT(tf.tf_eax) != VBECALL_SUPPORTED) {
+ kvm86_bios_delpage(KVM86_CALL_TASKVA, buf);
+ return 1;
+ }
+
+ memcpy(info, buf, sizeof(struct edid));
+ kvm86_bios_delpage(KVM86_CALL_TASKVA, buf);
+ return VBECALL_SUCESS(tf.tf_eax);
+}
int
vesafb_get_mode(struct vga_pci_softc *sc)
@@ -94,10 +141,10 @@ vesafb_get_mode(struct vga_pci_softc *sc)
int res;
bzero(&tf, sizeof(struct trapframe));
- tf.tf_eax = 0x4f03;
+ tf.tf_eax = VBE_FUNC_GETMODE;
- res = kvm86_bioscall(0x10, &tf);
- if (res || (tf.tf_eax & 0xff) != 0x4f) {
+ res = kvm86_bioscall(BIOS_VIDEO_INTR, &tf);
+ if (res || VBECALL_SUPPORT(tf.tf_eax) != VBECALL_SUPPORTED) {
printf("%s: vbecall: res=%d, ax=%x\n",
sc->sc_dev.dv_xname, res, tf.tf_eax);
}
@@ -112,27 +159,28 @@ vesafb_get_mode_info(struct vga_pci_softc *sc, int mode,
unsigned char *buf;
int res;
- if ((buf = kvm86_bios_addpage(0x2000)) == NULL) {
- printf("%s: kvm86_bios_addpage(0x2000) failed.\n");
+ if ((buf = kvm86_bios_addpage(KVM86_CALL_TASKVA)) == NULL) {
+ printf("%s: kvm86_bios_addpage failed.\n",
+ sc->sc_dev.dv_xname);
return;
}
memset(&tf, 0, sizeof(struct trapframe));
- tf.tf_eax = 0x4f01; /* function code */
+ tf.tf_eax = VBE_FUNC_MODEINFO;
tf.tf_ecx = mode;
tf.tf_vm86_es = 0;
- tf.tf_edi = 0x2000; /* buf ptr */
+ tf.tf_edi = KVM86_CALL_TASKVA;
- res = kvm86_bioscall(0x10, &tf);
- if (res || (tf.tf_eax & 0xff) != 0x4f) {
+ res = kvm86_bioscall(BIOS_VIDEO_INTR, &tf);
+ if (res || VBECALL_SUPPORT(tf.tf_eax) != VBECALL_SUPPORTED) {
printf("%s: vbecall: res=%d, ax=%x\n",
sc->sc_dev.dv_xname, res, tf.tf_eax);
printf("%s: error getting info for mode %05x\n",
sc->sc_dev.dv_xname, mode);
- kvm86_bios_delpage(0x2000, buf);
+ kvm86_bios_delpage(KVM86_CALL_TASKVA, buf);
return;
}
memcpy(mi, buf, sizeof(struct modeinfoblock));
- kvm86_bios_delpage(0x2000, buf);
+ kvm86_bios_delpage(KVM86_CALL_TASKVA, buf);
}
void
@@ -142,8 +190,9 @@ vesafb_set_palette(struct vga_pci_softc *sc, int reg, struct paletteentry pe)
int res;
char *buf;
- if ((buf = kvm86_bios_addpage(0x2000)) == NULL) {
- printf("%s: kvm86_bios_addpage(0x2000) failed.\n");
+ if ((buf = kvm86_bios_addpage(KVM86_CALL_TASKVA)) == NULL) {
+ printf("%s: kvm86_bios_addpage failed.\n",
+ sc->sc_dev.dv_xname);
return;
}
/*
@@ -158,19 +207,19 @@ vesafb_set_palette(struct vga_pci_softc *sc, int reg, struct paletteentry pe)
/* set palette */
memset(&tf, 0, sizeof(struct trapframe));
- tf.tf_eax = 0x4f09; /* function code */
+ tf.tf_eax = VBE_FUNC_PALETTE;
tf.tf_ebx = 0x0600; /* 6 bit per primary, set format */
tf.tf_ecx = 1;
tf.tf_edx = reg;
tf.tf_vm86_es = 0;
- tf.tf_edi = 0x2000;
+ tf.tf_edi = KVM86_CALL_TASKVA;
- res = kvm86_bioscall(0x10, &tf);
- if (res || (tf.tf_eax & 0xff) != 0x4f)
+ res = kvm86_bioscall(BIOS_VIDEO_INTR, &tf);
+ if (res || VBECALL_SUPPORT(tf.tf_eax) != VBECALL_SUPPORTED)
printf("%s: vbecall: res=%d, ax=%x\n",
sc->sc_dev.dv_xname, res, tf.tf_eax);
- kvm86_bios_delpage(0x2000, buf);
+ kvm86_bios_delpage(KVM86_CALL_TASKVA, buf);
return;
}
@@ -181,11 +230,11 @@ vesafb_set_mode(struct vga_pci_softc *sc, int mode)
int res;
bzero(&tf, sizeof(struct trapframe));
- tf.tf_eax = 0x4f02;
+ tf.tf_eax = VBE_FUNC_SETMODE;
tf.tf_ebx = mode | 0x4000; /* flat */
- res = kvm86_bioscall(0x10, &tf);
- if (res || (tf.tf_eax & 0xff) != 0x4f) {
+ res = kvm86_bioscall(BIOS_VIDEO_INTR, &tf);
+ if (res || VBECALL_SUPPORT(tf.tf_eax) != VBECALL_SUPPORTED) {
printf("%s: vbecall: res=%d, ax=%x\n",
sc->sc_dev.dv_xname, res, tf.tf_eax);
return;