diff options
author | Gordon Willem Klok <gwk@cvs.openbsd.org> | 2007-02-18 19:19:03 +0000 |
---|---|---|
committer | Gordon Willem Klok <gwk@cvs.openbsd.org> | 2007-02-18 19:19:03 +0000 |
commit | 45c7280ff3359e4b3a375cba281e43838cfa93e6 (patch) | |
tree | 77d8d32e08142096df90a7e2a7a50be238204f85 | |
parent | 2f40e49e058a82c84ee4d4fd7f752b05906d8595 (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.h | 151 | ||||
-rw-r--r-- | sys/dev/vesa/vesabios.c | 46 | ||||
-rw-r--r-- | sys/dev/vesa/vesafb.c | 95 |
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; |