以下のようなパッチを xorg-x11-drv-mga に当てた。
diff -ur xf86-video-mga-1.4.13.orig/src/mga.h xf86-video-mga-1.4.13/src/mga.h --- xf86-video-mga-1.4.13.orig/src/mga.h 2012-02-08 02:36:22.062533733 -0500 +++ xf86-video-mga-1.4.13/src/mga.h 2012-02-07 21:50:14.572730442 -0500 @@ -337,6 +337,13 @@ int mastervideoRam; int slavevideoRam; Bool directRenderingEnabled; + + void * mappedIOBase; + int mappedIOUsage; + + void * mappedILOADBase; + int mappedILOADUsage; + ScrnInfoPtr pScrn_1; ScrnInfoPtr pScrn_2; } MGAEntRec, *MGAEntPtr; diff -ur xf86-video-mga-1.4.13.orig/src/mga_driver.c xf86-video-mga-1.4.13/src/mga_driver.c --- xf86-video-mga-1.4.13.orig/src/mga_driver.c 2012-02-08 02:36:22.091533731 -0500 +++ xf86-video-mga-1.4.13/src/mga_driver.c 2012-02-07 21:51:58.448335431 -0500 @@ -1374,6 +1374,9 @@ xf86SetDDCproperties(pScrn, MonInfo); + /* MGARestore(pScrn); */ + /* MGAUnmapMem(pScrn); */ + return MonInfo; } @@ -2674,30 +2677,51 @@ #ifdef XSERVER_LIBPCIACCESS struct pci_device *const dev = pMga->PciInfo; struct pci_mem_region *region; - void **memory[2]; - int i, err; + int err; #endif if (!pMga->FBDev) { #ifdef XSERVER_LIBPCIACCESS - memory[pMga->io_bar] = &pMga->IOBase; - memory[pMga->framebuffer_bar] = &pMga->FbBase; - for (i = 0; i < 2; i++) { - region = &dev->regions[i]; - err = pci_device_map_range(dev, - region->base_addr, region->size, - PCI_DEV_MAP_FLAG_WRITABLE, - memory[i]); + pciaddr_t fbaddr = pMga->FbAddress; + pciaddr_t fbsize = pMga->FbMapSize; + err = pci_device_map_range(dev, + fbaddr, fbsize, + PCI_DEV_MAP_FLAG_WRITABLE, + (void **)&pMga->FbBase); - if (err) { + if (err) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Unable to map BAR %i. %s (%d)\n", - i, strerror(err), err); + "Unable to map Framebuffer %08llX %llx. %s (%d)\n", (long long)fbaddr, (long long)fbsize, + strerror(err), err); return FALSE; - } - } + } + else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "MAPPED Framebuffer %08llX %llx to %p.\n", (long long)fbaddr, (long long)fbsize, pMga->FbBase); + + + + if(pMga->entityPrivate->mappedIOUsage == 0) + { + region = &dev->regions[pMga->io_bar]; + err = pci_device_map_range(dev, + region->base_addr, region->size, + PCI_DEV_MAP_FLAG_WRITABLE, + &pMga->entityPrivate->mappedIOBase); + + if (err) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unable to map IO Region %i. %s (%d)\n", + pMga->io_bar, strerror(err), err); + return FALSE; + } + } + + pMga->entityPrivate->mappedIOUsage ++; + pMga->IOBase = pMga->entityPrivate->mappedIOBase; + #else /* * For Alpha, we need to map SPARSE memory, since we need @@ -2748,16 +2772,23 @@ if (pMga->iload_bar != -1) { #ifdef XSERVER_LIBPCIACCESS region = &dev->regions[pMga->iload_bar]; - err = pci_device_map_range(dev, + + if(pMga->entityPrivate->mappedILOADUsage == 0) + { + err = pci_device_map_range(dev, region->base_addr, region->size, PCI_DEV_MAP_FLAG_WRITABLE, - (void *) &pMga->ILOADBase); - if (err) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Unable to map BAR 2 (ILOAD region). %s (%d)\n", - strerror(err), err); - return FALSE; + (void *) &pMga->entityPrivate->mappedILOADBase); + if (err) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unable to map BAR 2 (ILOAD region). %s (%d)\n", + strerror(err), err); + return FALSE; + } } + + pMga->ILOADBase = pMga->entityPrivate->mappedILOADBase; + pMga->entityPrivate->mappedILOADUsage ++; #else pMga->ILOADBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO | VIDMEM_MMIO_32BIT | @@ -2787,10 +2818,17 @@ if (!pMga->FBDev) { #ifdef XSERVER_LIBPCIACCESS - pci_device_unmap_range(dev, pMga->IOBase, - dev->regions[pMga->io_bar].size); + pMga->entityPrivate->mappedIOUsage --; + if(pMga->entityPrivate->mappedIOUsage == 0) + { + pci_device_unmap_range(dev, pMga->IOBase, + dev->regions[pMga->io_bar].size); + pMga->entityPrivate->mappedIOBase = NULL; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "UNMAPPING framebuffer 0x%08llX, %p.\n", (long long)pMga->FbBase, pMga->FbMapSize); pci_device_unmap_range(dev, pMga->FbBase, - dev->regions[pMga->framebuffer_bar].size); + pMga->FbMapSize); #else xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->IOBase, 0x4000); xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->FbBase, pMga->FbMapSize); @@ -2803,8 +2841,14 @@ if ((pMga->iload_bar != -1) && (pMga->ILOADBase != NULL)) { #ifdef XSERVER_LIBPCIACCESS - pci_device_unmap_range(dev, pMga->ILOADBase, + pMga->entityPrivate->mappedILOADUsage --; + if(pMga->entityPrivate->mappedILOADUsage == 0) + { + pci_device_unmap_range(dev, pMga->ILOADBase, dev->regions[pMga->iload_bar].size); + pMga->entityPrivate->mappedILOADBase = NULL; + } + #else pMga->ILOADBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO | VIDMEM_MMIO_32BIT | @@ -2787,10 +2818,17 @@ if (!pMga->FBDev) { #ifdef XSERVER_LIBPCIACCESS - pci_device_unmap_range(dev, pMga->IOBase, - dev->regions[pMga->io_bar].size); + pMga->entityPrivate->mappedIOUsage --; + if(pMga->entityPrivate->mappedIOUsage == 0) + { + pci_device_unmap_range(dev, pMga->IOBase, + dev->regions[pMga->io_bar].size); + pMga->entityPrivate->mappedIOBase = NULL; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "UNMAPPING framebuffer 0x%08llX, %p.\n", (long long)pMga->FbBase, pMga->FbMapSize); pci_device_unmap_range(dev, pMga->FbBase, - dev->regions[pMga->framebuffer_bar].size); + pMga->FbMapSize); #else xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->IOBase, 0x4000); xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->FbBase, pMga->FbMapSize); @@ -2803,8 +2841,14 @@ if ((pMga->iload_bar != -1) && (pMga->ILOADBase != NULL)) { #ifdef XSERVER_LIBPCIACCESS - pci_device_unmap_range(dev, pMga->ILOADBase, + pMga->entityPrivate->mappedILOADUsage --; + if(pMga->entityPrivate->mappedILOADUsage == 0) + { + pci_device_unmap_range(dev, pMga->ILOADBase, dev->regions[pMga->iload_bar].size); + pMga->entityPrivate->mappedILOADBase = NULL; + } + #else xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->ILOADBase, 0x800000); #endif
ちなみにタイムゾーンが -0500 (EST) になっていることに対するツッコミはなしで。
/etc/X11/xorg.conf
Section "Monitor" Identifier "Monitor0" VendorName "CPQ" ModelName "P110" Option "DPMS" "On" HorizSync 30-107 VertRefresh 60,75,85 EndSection Section "Monitor" Identifier "Monitor1" VendorName "SAMSUNG" Option "DPMS" "On" ModelName "SyncMaster 740BX" VertRefresh 60 EndSection Section "Screen" Identifier "Screen0" Device "Videocard0" Monitor "Monitor0" DefaultDepth 24 SubSection "Display" Viewport 0 0 Depth 24 Modes "1600x1200" "1280x1024" "1024x768" "800x600" "640x480" EndSubSection EndSection Section "Screen" Identifier "Screen1" Device "Videocard1" Monitor "Monitor1" DefaultDepth 24 SubSection "Display" Viewport 0 0 Depth 24 Modes "1280x1024" "1024x768" "800x600" "640x480" EndSubSection EndSection Section "Device" Identifier "Videocard0" Driver "mga" Screen 0 BusID "PCI:1:0:0" EndSection Section "Device" Identifier "Videocard1" Driver "mga" Screen 1 BusID "PCI:1:0:0" EndSection Section "ServerLayout" Option "Xinerama" "on" Screen 0 "Screen0" 0 0 Screen 1 "Screen1" Rightof "Screen0" Identifier "DualHead" EndSection
これで動いている (正確に言えば P110 は 1280x1024 モードになっている *1 ) けど、このパッチは
- Launchpad の記事で対象になっている Ubuntu でも Merge されていない (少なくとも Natty (11.04) では変更されている様子はなかった)
- 一応 Bugfix であるが
- このパッチだけではデュアルディスプレイにできない (RandR に対応していない)
- よって xorg.conf を書かない限り認識しない
- 高解像度デュアルディスプレイは不可 (前述)
- RandR を無効にするので一部のソフトが動かなくなる (わりと深刻)
- ほとんどのアプリ (gtk?) を起動する際に「Xサーバーの RandR が無効です!」と警告がでる。
ので、Momonga への Merge も保留にしておく。
*1:ドライバの制限でデュアルディスプレイ時は (?) 高解像度が利用できないと書かれている記事を見つけたけど見失った