Module Name:    src
Committed By:   jmcneill
Date:           Wed Feb  9 04:37:54 UTC 2011

Modified Files:
        src/sys/arch/i386/stand/boot: version
        src/sys/arch/i386/stand/lib: biosvbe.S vbe.c vbe.h

Log Message:
Add VESA VBE/DDC EDID support for determining the monitor's preferred
video mode. "vesa on" will now select the preferred mode @ 8bpp if it can
be determined and is supported by the display adapter, otherwise it will
use 640x480 @ 8bpp.


To generate a diff of this commit:
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/i386/stand/boot/version
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/i386/stand/lib/biosvbe.S
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/i386/stand/lib/vbe.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/i386/stand/lib/vbe.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/i386/stand/boot/version
diff -u src/sys/arch/i386/stand/boot/version:1.14 src/sys/arch/i386/stand/boot/version:1.15
--- src/sys/arch/i386/stand/boot/version:1.14	Sun Feb  6 23:16:05 2011
+++ src/sys/arch/i386/stand/boot/version	Wed Feb  9 04:37:54 2011
@@ -1,4 +1,4 @@
-$NetBSD: version,v 1.14 2011/02/06 23:16:05 jmcneill Exp $
+$NetBSD: version,v 1.15 2011/02/09 04:37:54 jmcneill Exp $
 
 NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE.  The format of this
 file is important - make sure the entries are appended on end, last item
@@ -46,3 +46,4 @@
 5.6:	GUID Partition Table support.
 5.7:	Recognize 64-bit LBA from bootxx.
 5.8:	Support for splash images.
+5.9:	VESA VBE/DDC EDID support.

Index: src/sys/arch/i386/stand/lib/biosvbe.S
diff -u src/sys/arch/i386/stand/lib/biosvbe.S:1.1 src/sys/arch/i386/stand/lib/biosvbe.S:1.2
--- src/sys/arch/i386/stand/lib/biosvbe.S:1.1	Mon Feb 16 22:39:30 2009
+++ src/sys/arch/i386/stand/lib/biosvbe.S	Wed Feb  9 04:37:54 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: biosvbe.S,v 1.1 2009/02/16 22:39:30 jmcneill Exp $ */
+/* $NetBSD: biosvbe.S,v 1.2 2011/02/09 04:37:54 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2009 Jared D. McNeill <[email protected]>
@@ -254,3 +254,101 @@
 	popl	%ebx
 	popl	%ebp
 	ret
+
+/*
+ * Function 15h BL=00h - Report VBE/DDC Capabilities
+ *
+ * int biosvbe_ddc_caps(void)
+ * return: VBE/DDC capabilities
+ */
+ENTRY(biosvbe_ddc_caps)
+	pushl	%ebp
+	movl	%esp,%ebp
+	pushl	%ebx
+	pushl	%ecx
+	pushl	%edx
+	push	%esi
+	push	%edi
+
+	call	_C_LABEL(prot_to_real)
+	.code16
+
+	movw	$0x4f15, %ax	/* display identification extensions */
+	mov	$0x00, %bx	/* report DDC capabilities */
+
+	movl	$0x0000, %esi	/* ES:DI == 0:0 */
+	movl	$0x0000, %edi
+	mov	$0x00, %cx	/* controller unit number (00h = primary) */
+	int	$0x10
+
+	calll	_C_LABEL(real_to_prot)
+	.code32
+
+	movl	%eax,%ecx
+	movl	$0x0000,%eax
+	andl	$0xffff,%ecx
+	cmpl	$0x004f,%ecx
+	jne	1f
+	andl	$0xffff,%ebx
+	movl	%ebx,%eax
+1:
+
+	pop	%edi
+	pop	%esi
+	popl	%edx
+	popl	%ecx
+	popl	%ebx
+	popl	%ebp
+	ret
+
+/*
+ * Function 15h BL=01h - Read EDID
+ *
+ * int biosvbe_ddc_read_edid(int blockno, void *buf)
+ * return: VBE call status
+ */
+ENTRY(biosvbe_ddc_read_edid)
+	pushl	%ebp
+	movl	%esp,%ebp
+	pushl	%ebx
+	pushl	%ecx
+	pushl	%edx
+	push	%esi
+	push	%edi
+
+	movl	8(%ebp), %edx	/* EDID block number */
+	movl	12(%ebp), %edi	/* EDID block address */
+
+	call	_C_LABEL(prot_to_real)
+	.code16
+
+	push	%es
+
+	push	%di
+	shrl	$4, %edi
+	mov	%ds, %ax
+	add	%di, %ax
+	mov	%ax, %es
+	pop	%di
+	and	$0xf, %di	/* EDID block address now in es:di */
+
+	movw	$0x4f15, %ax	/* display identification extensions */
+	mov	$0x01, %bx	/* read EDID */
+	mov	$0x00, %cx	/* controller unit number (00h = primary) */
+	int	$0x10
+
+	pop	%es
+
+	calll	_C_LABEL(real_to_prot)
+	.code32
+
+	andl	$0xffff,%eax
+
+	pop	%edi
+	pop	%esi
+	popl	%edx
+	popl	%ecx
+	popl	%ebx
+	popl	%ebp
+	ret
+

Index: src/sys/arch/i386/stand/lib/vbe.c
diff -u src/sys/arch/i386/stand/lib/vbe.c:1.6 src/sys/arch/i386/stand/lib/vbe.c:1.7
--- src/sys/arch/i386/stand/lib/vbe.c:1.6	Fri Jun 25 15:35:08 2010
+++ src/sys/arch/i386/stand/lib/vbe.c	Wed Feb  9 04:37:54 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: vbe.c,v 1.6 2010/06/25 15:35:08 tsutsui Exp $ */
+/* $NetBSD: vbe.c,v 1.7 2011/02/09 04:37:54 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2009 Jared D. McNeill <[email protected]>
@@ -37,6 +37,8 @@
 #include "vbe.h"
 
 extern const uint8_t rasops_cmap[];
+static uint8_t *vbe_edid = NULL;
+static int vbe_edid_valid = 0;
 
 static struct _vbestate {
 	int		available;
@@ -185,7 +187,7 @@
 }
 
 static int
-vbe_parse_mode_str(char *str, int *x, int *y, int *bpp)
+vbe_parse_mode_str(char *str, int *x, int *y, int *depth)
 {
 	char *p;
 
@@ -202,11 +204,11 @@
 		return 0;
 	p = strchr(p, 'x');
 	if (!p)
-		*bpp = 8;
+		*depth = 8;
 	else {
 		++p;
-		*bpp = strtoul(p, NULL, 0);
-		if (*bpp == 0)
+		*depth = strtoul(p, NULL, 0);
+		if (*depth == 0)
 			return 0;
 	}
 
@@ -214,18 +216,14 @@
 }
 
 static int
-vbe_find_mode(char *str)
+vbe_find_mode_xyd(int x, int y, int depth)
 {
 	struct vbeinfoblock vbe;
 	struct modeinfoblock mi;
 	uint32_t farptr;
 	uint16_t mode;
-	int x, y, bpp;
 	int safety = 0;
 
-	if (!vbe_parse_mode_str(str, &x, &y, &bpp))
-		return 0;
-
 	memset(&vbe, 0, sizeof(vbe));
 	memcpy(vbe.VbeSignature, "VBE2", 4);
 	if (biosvbe_info(&vbe) != 0x004f)
@@ -249,13 +247,24 @@
 		safety = 0;
 		if (mi.XResolution == x &&
 		    mi.YResolution == y &&
-		    mi.BitsPerPixel == bpp)
+		    mi.BitsPerPixel == depth)
 			return mode;
 	}
 
 	return 0;
 }
 
+static int
+vbe_find_mode(char *str)
+{
+	int x, y, depth;
+
+	if (!vbe_parse_mode_str(str, &x, &y, &depth))
+		return 0;
+
+	return vbe_find_mode_xyd(x, y, depth);
+}
+
 static void
 vbe_dump_mode(int modenum, struct modeinfoblock *mi)
 {
@@ -263,6 +272,37 @@
 	    mi->XResolution, mi->YResolution, mi->BitsPerPixel);
 }
 
+static int
+vbe_get_edid(int *pwidth, int *pheight)
+{
+	const uint8_t magic[] = EDID_MAGIC;
+	int ddc_caps, ret;
+
+	ddc_caps = biosvbe_ddc_caps();
+	if (ddc_caps == 0) {
+		return 1;
+	}
+
+	if (vbe_edid == NULL) {
+		vbe_edid = alloc(128);
+	}
+	if (vbe_edid_valid == 0) {
+		ret = biosvbe_ddc_read_edid(0, vbe_edid);
+		if (ret != 0x004f)
+			return 1;
+		if (memcmp(vbe_edid, magic, sizeof(magic)) != 0)
+			return 1;
+		vbe_edid_valid = 1;
+	}
+
+	*pwidth = vbe_edid[EDID_DESC_BLOCK + 2] |
+	    (((int)vbe_edid[EDID_DESC_BLOCK + 4] & 0xf0) << 4);
+	*pheight = vbe_edid[EDID_DESC_BLOCK + 5] |
+	    (((int)vbe_edid[EDID_DESC_BLOCK + 7] & 0xf0) << 4);
+
+	return 0;
+}
+
 void
 vbe_modelist(void)
 {
@@ -271,10 +311,25 @@
 	uint32_t farptr;
 	uint16_t mode;
 	int nmodes = 0, safety = 0;
+	int ddc_caps, edid_width, edid_height;
 
 	if (!vbe_check())
 		return;
 
+	ddc_caps = biosvbe_ddc_caps();
+	if (ddc_caps & 3) {
+		printf("DDC");
+		if (ddc_caps & 1)
+			printf(" [DDC1]");
+		if (ddc_caps & 2)
+			printf(" [DDC2]");
+
+		if (vbe_get_edid(&edid_width, &edid_height) != 0)
+			printf(": no EDID information\n");
+		else
+			printf(": EDID %dx%d\n", edid_width, edid_height);
+	}
+
 	printf("Modes: ");
 	memset(&vbe, 0, sizeof(vbe));
 	memcpy(vbe.VbeSignature, "VBE2", 4);
@@ -317,7 +372,7 @@
 command_vesa(char *cmd)
 {
 	char arg[20];
-	int modenum;
+	int modenum, edid_width, edid_height;
 
 	if (!vbe_check())
 		return;
@@ -334,18 +389,25 @@
 		return;
 	}
 
-	if (strcmp(arg, "enabled") == 0 || strcmp(arg, "on") == 0)
-		modenum = VBE_DEFAULT_MODE;
-	else if (strncmp(arg, "0x", 2) == 0)
+	if (strcmp(arg, "enabled") == 0 || strcmp(arg, "on") == 0) {
+		if (vbe_get_edid(&edid_width, &edid_height) != 0) {
+			modenum = VBE_DEFAULT_MODE;
+		} else {
+			modenum = vbe_find_mode_xyd(edid_width, edid_height, 8);
+			if (modenum == 0)
+				modenum = VBE_DEFAULT_MODE;
+		}
+	} else if (strncmp(arg, "0x", 2) == 0) {
 		modenum = strtoul(arg, NULL, 0);
-	else if (strchr(arg, 'x') != NULL) {
+	} else if (strchr(arg, 'x') != NULL) {
 		modenum = vbe_find_mode(arg);
 		if (modenum == 0) {
 			printf("mode %s not supported by firmware\n", arg);
 			return;
 		}
-	} else
+	} else {
 		modenum = 0;
+	}
 
 	if (modenum >= 0x100) {
 		vbestate.modenum = modenum;

Index: src/sys/arch/i386/stand/lib/vbe.h
diff -u src/sys/arch/i386/stand/lib/vbe.h:1.2 src/sys/arch/i386/stand/lib/vbe.h:1.3
--- src/sys/arch/i386/stand/lib/vbe.h:1.2	Mon Sep 14 11:56:27 2009
+++ src/sys/arch/i386/stand/lib/vbe.h	Wed Feb  9 04:37:54 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: vbe.h,v 1.2 2009/09/14 11:56:27 jmcneill Exp $ */
+/* $NetBSD: vbe.h,v 1.3 2011/02/09 04:37:54 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2009 Jared D. McNeill <[email protected]>
@@ -85,12 +85,18 @@
 	uint8_t Alignment;
 } __packed;
 
+/* EDID */
+#define	EDID_MAGIC	{ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }
+#define	EDID_DESC_BLOCK	0x36
+
 /* low-level VBE calls, from biosvbe.S */
 int biosvbe_info(struct vbeinfoblock *);
 int biosvbe_set_mode(int);
 int biosvbe_get_mode_info(int, struct modeinfoblock *);
 int biosvbe_palette_format(int); 
 int biosvbe_palette_data(int, int, struct paletteentry *);
+int biosvbe_ddc_caps(void);
+int biosvbe_ddc_read_edid(int, void *);
 
 /* high-level VBE helpers, from vbe.c */
 void vbe_init(void);

Reply via email to