ports/116851: x11-drivers/xf86-video-mga - Xorg 7.3 mga driver
fails to read video BIOS (G450 dual-VGA)
Warren Block
wblock at wonkity.com
Fri Oct 5 10:00:13 PDT 2007
The following reply was made to PR ports/116851; it has been noted by GNATS.
From: Warren Block <wblock at wonkity.com>
To: bug-followup at FreeBSD.org
Cc:
Subject: Re: ports/116851: x11-drivers/xf86-video-mga - Xorg 7.3 mga driver
fails to read video BIOS (G450 dual-VGA)
Date: Fri, 5 Oct 2007 10:56:11 -0600 (MDT)
A Solution: Reading The Matrox BIOS As A File
The Problem
The FreeBSD xorg drivers try to map the Matrox video BIOS into a PCI
range, but fail. Something (OS? motherboard BIOS?) has mapped something
else into the available ranges, leaving none big enough to hold the
0x2000000 size wanted. xf86GetRange (in xf86Bus.c) finds conflicts [tmp
= ChkConflict(&r,Acc,SETUP);] and the user sees this message in the Xorg
log:
Requesting insufficient memory window!: start: 0xdee00000 end: 0xdfefffff size 0
x2000000
(EE) Cannot find empty range to map base to
Without the BIOS, the mga driver has limited function. This is
particularly important with the xorg 1.3 xrandr support for multihead
video boards (MGA450/550). Newer versions of the mga driver use the
BIOS to determine how many video connectors the card has; without the
BIOS, only one is found.
The Solution
Well, maybe not *the* solution, but a solution. The Linux folks fixed a
similar problem back in April of 2006:
https://bugs.freedesktop.org/show_bug.cgi?id=6751
That code appears to have been integrated into xorg-server (linuxPci.c,
Pci.h, and Pci.c).
This is a not-so-quick hack for FreeBSD based on that patch. It seemed
like a quick port of the Linux code would work. But it did not, due to
a) my inexperience with C; b) the complexity of X and multi-OS support
(lots of twisty little ARCH_INIT_OS_PCI ifdefs, all alike); c) my
inability to get pciconf to do what I wanted, and D) possibly badgers.
So I'm documenting a hack that does work in the hopes that it will help
someone else implement it correctly.
1. Copy the video BIOS from your card to a file.
Real FreeBSD xorg code should read the BIOS data directly from the card.
Maybe pciconf can do that, but I couldn't figure out how, so I read it
from a file. Use Linux to copy the BIOS to a file:
$ lspci | grep Matrox
(on my system this is 01:00.0)
$ cd /sys/bus/pci/devices/0000:01:00.0
$ echo 1 > rom
$ cat rom > /tmp/videobios.bin
$ echo 0 > rom
Save the videobios.bin file somewhere (/tmp/mga/videobios.bin is where
the patch expects it) and reboot in FreeBSD.
2. Patch xorg-server's Pci.c:
# cd /usr/ports/x11-servers/xorg-server
# copy patch-Pci.c (included at the end of this file) to files/
# make install
Of course this is wrong, the code should be in freebsdPci.c. However,
adding the changes in the Linux diff was not enough, and the #ifdefs in
Pci.h defeated my attempts. Somebody who knows what they are doing here
would probably have no trouble.
3. The Result
Using the experimental mga-1.9.99, xorg log output shows:
(II) Attempted to read BIOS 128KB from /tmp/mga/videobios.bin: got 34KB
(--) MGA(0): Video BIOS info block at offset 0x07D00
Output from xrandr 1.2:
Screen 0: minimum 320 x 200, current 1280 x 1024, maximum 2304 x 1024
VGA1 connected 1280x1024+0+0 375mm x 301mm
1280x1024 60.0*+ 59.9
1024x768 70.1 60.0
832x624 74.6
800x600 72.2 75.0 60.3 56.2
640x480 75.0 72.8 66.7 60.0
720x400 70.1
VGA2 connected 1024x768+0+0 307mm x 230mm
1024x768 60.0*+ 75.1 70.1 60.0*
832x624 74.6
800x600 72.2 75.0 60.3 56.2
640x480 75.0 72.8 66.7 60.0
720x400 70.1
The Patch
--- hw/xfree86/os-support/bus/Pci.c.orig 2007-09-05 18:48:26.000000000 -0600
+++ hw/xfree86/os-support/bus/Pci.c 2007-10-05 10:40:01.000000000 -0600
@@ -210,6 +210,12 @@
#include "xf86_OSproc.h"
#include "Pci.h"
+/* WB: start */
+#include "compiler.h"
+#include <stdio.h>
+#include "xf86_OSlib.h"
+/* WB: end */
+
#define PCI_MFDEV_SUPPORT 1 /* Include PCI multifunction device support */
#define PCI_BRIDGE_SUPPORT 1 /* Include support for PCI-to-PCI bridges */
@@ -238,6 +244,9 @@
unsigned char * buf, int len, PciBiosType BiosType );
static int (*pciOSHandleBIOS)(PCITAG Tag, int basereg, unsigned char *buf, int len);
+/* WB: start */
+static int freebsdpciOsHandleBIOS(PCITAG Tag, int basereg, unsigned char *buf, int len);
+/* WB: end */
int xf86MaxPciDevs = 0;
@@ -1324,6 +1333,13 @@
PCITAG *pTag;
int i;
+ /* WB: start */
+ /* this should be in pciOSHandleBIOS */
+ n = freebsdpciOsHandleBIOS(Tag, basereg, buf, len);
+ if (n)
+ return n;
+ /* WB: end */
+
/* fall back to the old code if the OS code fails */
if (pciOSHandleBIOS) {
n = pciOSHandleBIOS(Tag, basereg, buf, len);
@@ -1415,3 +1431,37 @@
}
#endif /* INCLUDE_XF86_NO_DOMAIN */
+
+/* WB: start */
+/* MGA BIOS read code for example only, do not use for real. Don't even look directly at it. */
+#define BIOSFILE "/tmp/mga/videobios.bin"
+
+int freebsdpciOsHandleBIOS(PCITAG Tag, int basereg, unsigned char *buf, int len)
+{
+ unsigned int fd;
+ struct stat st;
+ int ret;
+ int sofar = 0;
+
+ if (stat(BIOSFILE, &st) == 0)
+ {
+ if ((fd = open(BIOSFILE, O_RDWR)))
+ basereg = 0x0;
+
+ lseek(fd, 0, SEEK_SET);
+ do {
+ /* copy the ROM until we hit Len, EOF or read error */
+ ret = read(fd, buf+sofar, len-sofar);
+ if (ret <= 0)
+ break;
+ sofar += ret;
+ } while (sofar < len);
+
+ close(fd);
+ if (sofar < len)
+ xf86MsgVerb(X_INFO, 3, "Attempted to read BIOS %dKB from %s: got %dKB\n", len/1024, BIOSFILE, sofar/1024);
+ return sofar;
+ }
+ return 0;
+}
+/* WB: end */
-Warren Block * Rapid City, South Dakota USA
More information about the freebsd-x11
mailing list