text: /*
   * Copyright 2011-2015 The Openchrome Project
   *                     [http://www.freedesktop.org/wiki/Openchrome]
   *
   * Permission is hereby granted, free of charge, to any person obtaining a
   * copy of this software and associated documentation files (the "Software"),
   * to deal in the Software without restriction, including without limitation
   * the rights to use, copy, modify, merge, publish, distribute, sub license,
   * and/or sell copies of the Software, and to permit persons to whom the
   * Software is furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice (including the
   * next paragraph) shall be included in all copies or substantial portions
   * of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
   * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   * DEALINGS IN THE SOFTWARE.
   */
  
  #ifdef HAVE_CONFIG_H
  #include "config.h"
  #endif
  #include "xf86Crtc.h"
  #include "xf86fbman.h"
  
  #include "globals.h"
  #include "via_driver.h"
  
  static void
  ViaMMIODisable(ScrnInfoPtr pScrn)
  {
      VIAPtr pVia = VIAPTR(pScrn);
      vgaHWPtr hwp = VGAHWPTR(pScrn);
  
      switch (pVia->Chipset) {
          case VIA_K8M890:
          case VIA_CX700:
          case VIA_P4M900:
          case VIA_VX800:
          case VIA_VX855:
          case VIA_VX900:
              ViaSeqMask(hwp, 0x1A, 0x00, 0x08);
              break;
          default:
              ViaSeqMask(hwp, 0x1A, 0x00, 0x60);
              break;
      }
  }
  
  void
  VIAUnmapMem(ScrnInfoPtr pScrn)
  {
      VIAPtr pVia = VIAPTR(pScrn);
  
      DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAUnmapMem\n"));
  
      ViaMMIODisable(pScrn);
  
  #ifdef HAVE_PCIACCESS
      if (pVia->MapBase)
          pci_device_unmap_range(pVia->PciInfo, (pointer) pVia->MapBase,
                                 VIA_MMIO_REGSIZE);
  
      if (pVia->BltBase)
          pci_device_unmap_range(pVia->PciInfo, (pointer) pVia->BltBase,
                                 VIA_MMIO_BLTSIZE);
  
      if (pVia->FBBase)
          pci_device_unmap_range(pVia->PciInfo, (pointer) pVia->FBBase,
                                 pVia->videoRambytes);
  #else
      if (pVia->MapBase)
          xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pVia->MapBase,
                          VIA_MMIO_REGSIZE);
  
      if (pVia->BltBase)
          xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pVia->BltBase,
                          VIA_MMIO_BLTSIZE);
  
      if (pVia->FBBase)
          xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pVia->FBBase,
                          pVia->videoRambytes);
  #endif
  }
  
  static void
  ViaMMIOEnable(ScrnInfoPtr pScrn)
  {
      VIAPtr pVia = VIAPTR(pScrn);
      vgaHWPtr hwp = VGAHWPTR(pScrn);
  
      switch (pVia->Chipset) {
          case VIA_K8M890:
          case VIA_CX700:
          case VIA_P4M900:
          case VIA_VX800:
          case VIA_VX855:
          case VIA_VX900:
              ViaSeqMask(hwp, 0x1A, 0x08, 0x08);
              break;
          default:
              if (pVia->IsSecondary)
                  ViaSeqMask(hwp, 0x1A, 0x38, 0x38);
              else
                  ViaSeqMask(hwp, 0x1A, 0x68, 0x68);
              break;
      }
  }
  
  static Bool
  VIAMapMMIO(ScrnInfoPtr pScrn)
  {
      VIAPtr pVia = VIAPTR(pScrn);
  
  #ifdef HAVE_PCIACCESS
      pVia->MmioBase = pVia->PciInfo->regions[1].base_addr;
      int err;
  #else
      pVia->MmioBase = pVia->PciInfo->memBase[1];
  #endif
  
      DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAMapMMIO\n"));
  
      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
                 "mapping MMIO @ 0x%lx with size 0x%x\n",
                 pVia->MmioBase, VIA_MMIO_REGSIZE);
  
  #ifdef HAVE_PCIACCESS
      err = pci_device_map_range(pVia->PciInfo,
                                 pVia->MmioBase,
                                 VIA_MMIO_REGSIZE,
                                 PCI_DEV_MAP_FLAG_WRITABLE,
                                 (void **)&pVia->MapBase);
  
      if (err) {
          xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                     "Unable to map mmio BAR. %s (%d)\n", strerror(err), err);
          return FALSE;
      }
  #else
      pVia->MapBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pVia->PciTag,
                                    pVia->MmioBase, VIA_MMIO_REGSIZE);
      if (!pVia->MapBase)
          return FALSE;
  #endif
  
      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
                 "mapping BitBlt MMIO @ 0x%lx with size 0x%x\n",
                 pVia->MmioBase + VIA_MMIO_BLTBASE, VIA_MMIO_BLTSIZE);
  
  #ifdef HAVE_PCIACCESS
      err = pci_device_map_range(pVia->PciInfo,
                                 pVia->MmioBase + VIA_MMIO_BLTBASE,
                                 VIA_MMIO_BLTSIZE,
                                 PCI_DEV_MAP_FLAG_WRITABLE,
                                 (void **)&pVia->BltBase);
  
      if (err) {
          xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                     "Unable to map blt BAR. %s (%d)\n", strerror(err), err);
          return FALSE;
      }
  #else
      pVia->BltBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pVia->PciTag,
                                    pVia->MmioBase + VIA_MMIO_BLTBASE,
                                    VIA_MMIO_BLTSIZE);
      if (!pVia->BltBase)
          return FALSE;
  #endif
  
      if (!pVia->MapBase || !pVia->BltBase) {
          xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                     "BitBlit could not be mapped.\n");
          return FALSE;
      }
  
      /* Memory mapped IO for mpeg engine. */
      pVia->MpegMapBase = pVia->MapBase + 0xc00;
  
      /* Set up MMIO vgaHW. */
      {
          vgaHWPtr hwp = VGAHWPTR(pScrn);
          CARD8 val;
  
          vgaHWSetMmioFuncs(hwp, pVia->MapBase, 0x8000);
  
          val = hwp->readEnable(hwp);
          hwp->writeEnable(hwp, val | 0x01);
  
          val = hwp->readMiscOut(hwp);
          hwp->writeMiscOut(hwp, val | 0x01);
  
          /* Unlock extended IO space. */
          ViaSeqMask(hwp, 0x10, 0x01, 0x01);
  
          ViaMMIOEnable(pScrn);
  
          vgaHWSetMmioFuncs(hwp, pVia->MapBase, 0x8000);
  
          /* Unlock CRTC. */
          ViaCrtcMask(hwp, 0x47, 0x00, 0x01);
  
          vgaHWGetIOBase(hwp);
      }
      return TRUE;
  }
  
  static Bool
  VIAMapFB(ScrnInfoPtr pScrn)
  {
      VIAPtr pVia = VIAPTR(pScrn);
  
  #ifdef HAVE_PCIACCESS
      if (pVia->Chipset == VIA_VX900) {
          pVia->FrameBufferBase = pVia->PciInfo->regions[2].base_addr;
      } else {
          pVia->FrameBufferBase = pVia->PciInfo->regions[0].base_addr;
      }
      int err;
  #else
      if (pVia->Chipset == VIA_VX900) {
          pVia->FrameBufferBase = pVia->PciInfo->memBase[2];
      } else {
          pVia->FrameBufferBase = pVia->PciInfo->memBase[0];
      }
  #endif
  
      DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAMapFB\n"));
      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
                 "mapping framebuffer @ 0x%lx with size 0x%lx\n",
                 pVia->FrameBufferBase, pVia->videoRambytes);
  
      if (pVia->videoRambytes) {
  
  #ifndef HAVE_PCIACCESS
          /*
           * FIXME: This is a hack to get rid of offending wrongly sized
           * MTRR regions set up by the VIA BIOS. Should be taken care of
           * in the OS support layer.
           */
          unsigned char *tmp;
  
          tmp = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pVia->PciTag,
                              pVia->FrameBufferBase, pVia->videoRambytes);
          xf86UnMapVidMem(pScrn->scrnIndex, (pointer) tmp, pVia->videoRambytes);
  
          /*
           * And, as if this wasn't enough, 2.6 series kernels don't
           * remove MTRR regions on the first attempt. So try again.
           */
  
          tmp = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pVia->PciTag,
                              pVia->FrameBufferBase, pVia->videoRambytes);
          xf86UnMapVidMem(pScrn->scrnIndex, (pointer) tmp, pVia->videoRambytes);
  
          /*
           * End of hack.
           */
  #endif
  
  #ifdef HAVE_PCIACCESS
          err = pci_device_map_range(pVia->PciInfo, pVia->FrameBufferBase,
                                     pVia->videoRambytes,
                                     (PCI_DEV_MAP_FLAG_WRITABLE |
                                      PCI_DEV_MAP_FLAG_WRITE_COMBINE),
                                     (void **)&pVia->FBBase);
          if (err) {
              xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                         "Unable to map mmio BAR. %s (%d)\n", strerror(err), err);
              return FALSE;
          }
  #else
          pVia->FBBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
                                       pVia->PciTag, pVia->FrameBufferBase,
                                       pVia->videoRambytes);
  
          if (!pVia->FBBase) {
              xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                         "Internal error: could not map framebuffer\n");
              return FALSE;
          }
  #endif
  
          pVia->FBFreeStart = 0;
          pVia->FBFreeEnd = pVia->videoRambytes;
  
          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
                     "Frame buffer start: %p, free start: 0x%x end: 0x%x\n",
                     pVia->FBBase, pVia->FBFreeStart, pVia->FBFreeEnd);
      }
  
  #ifdef HAVE_PCIACCESS
      pScrn->memPhysBase = pVia->PciInfo->regions[0].base_addr;
  #else
      pScrn->memPhysBase = pVia->PciInfo->memBase[0];
  #endif
      pScrn->fbOffset = 0;
      if (pVia->IsSecondary)
          pScrn->fbOffset = pScrn->videoRam << 10;
  
      return TRUE;
  }
  
  /*
   * Leftover from VIA's code.
   */
  static void
  viaInitPCIe(VIAPtr pVia)
  {
      VIASETREG(0x41c, 0x00100000);
      VIASETREG(0x420, 0x680A0000);
      VIASETREG(0x420, 0x02000000);
  }
  
  static void
  viaInitAgp(VIAPtr pVia)
  {
      VIASETREG(VIA_REG_TRANSET, 0x00100000);
      VIASETREG(VIA_REG_TRANSPACE, 0x00000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x00333004);
      VIASETREG(VIA_REG_TRANSPACE, 0x60000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x61000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x62000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x63000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x64000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x7D000000);
  
      VIASETREG(VIA_REG_TRANSET, 0xfe020000);
      VIASETREG(VIA_REG_TRANSPACE, 0x00000000);
  }
  
  /*
   * Initialize the virtual command queue. Header-2 commands can be put
   * in this queue for buffering. AFAIK it doesn't handle Header-1
   * commands, which is really a pity, since it has to be idled before
   * issuing a Header-1 command.
   */
  static void
  viaEnableAgpVQ(VIAPtr pVia)
  {
     CARD32
         vqStartAddr = pVia->VQStart,
         vqEndAddr = pVia->VQEnd,
         vqStartL = 0x50000000 | (vqStartAddr & 0xFFFFFF),
         vqEndL = 0x51000000 | (vqEndAddr & 0xFFFFFF),
         vqStartEndH = 0x52000000 | ((vqStartAddr & 0xFF000000) >> 24) |
         ((vqEndAddr & 0xFF000000) >> 16),
         vqLen = 0x53000000 | (VIA_VQ_SIZE >> 3);
  
      VIASETREG(VIA_REG_TRANSET, 0x00fe0000);
      VIASETREG(VIA_REG_TRANSPACE, 0x080003fe);
      VIASETREG(VIA_REG_TRANSPACE, 0x0a00027c);
      VIASETREG(VIA_REG_TRANSPACE, 0x0b000260);
      VIASETREG(VIA_REG_TRANSPACE, 0x0c000274);
      VIASETREG(VIA_REG_TRANSPACE, 0x0d000264);
      VIASETREG(VIA_REG_TRANSPACE, 0x0e000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x0f000020);
      VIASETREG(VIA_REG_TRANSPACE, 0x1000027e);
      VIASETREG(VIA_REG_TRANSPACE, 0x110002fe);
      VIASETREG(VIA_REG_TRANSPACE, 0x200f0060);
      VIASETREG(VIA_REG_TRANSPACE, 0x00000006);
      VIASETREG(VIA_REG_TRANSPACE, 0x40008c0f);
      VIASETREG(VIA_REG_TRANSPACE, 0x44000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x45080c04);
      VIASETREG(VIA_REG_TRANSPACE, 0x46800408);
  
      VIASETREG(VIA_REG_TRANSPACE, vqStartEndH);
      VIASETREG(VIA_REG_TRANSPACE, vqStartL);
      VIASETREG(VIA_REG_TRANSPACE, vqEndL);
      VIASETREG(VIA_REG_TRANSPACE, vqLen);
  }
  
  static void
  viaEnablePCIeVQ(VIAPtr pVia)
  {
     CARD32
         vqStartAddr = pVia->VQStart,
         vqEndAddr = pVia->VQEnd,
         vqStartL = 0x70000000 | (vqStartAddr & 0xFFFFFF),
         vqEndL = 0x71000000 | (vqEndAddr & 0xFFFFFF),
         vqStartEndH = 0x72000000 | ((vqStartAddr & 0xFF000000) >> 24) |
         ((vqEndAddr & 0xFF000000) >> 16),
         vqLen = 0x73000000 | (VIA_VQ_SIZE >> 3);
  
      VIASETREG(0x41c, 0x00100000);
      VIASETREG(0x420, vqStartEndH);
      VIASETREG(0x420, vqStartL);
      VIASETREG(0x420, vqEndL);
      VIASETREG(0x420, vqLen);
      VIASETREG(0x420, 0x74301001);
      VIASETREG(0x420, 0x00000000);
  }
  
  /*
   * Disable the virtual command queue.
   */
  void
  viaDisableVQ(ScrnInfoPtr pScrn)
  {
      VIAPtr pVia = VIAPTR(pScrn);
  
      switch (pVia->Chipset) {
          case VIA_K8M890:
          case VIA_P4M900:
          case VIA_VX800:
          case VIA_VX855:
          case VIA_VX900:
              VIASETREG(0x41c, 0x00100000);
              VIASETREG(0x420, 0x74301000);
              break;
          default:
              VIASETREG(VIA_REG_TRANSET, 0x00fe0000);
              VIASETREG(VIA_REG_TRANSPACE, 0x00000004);
              VIASETREG(VIA_REG_TRANSPACE, 0x40008c0f);
              VIASETREG(VIA_REG_TRANSPACE, 0x44000000);
              VIASETREG(VIA_REG_TRANSPACE, 0x45080c04);
              VIASETREG(VIA_REG_TRANSPACE, 0x46800408);
              break;
      }
  }
  
  /*
   * Initialize the 2D engine and set the 2D context mode to the
   * current screen depth. Also enable the virtual queue.
   */
  static void
  VIAInitialize2DEngine(ScrnInfoPtr pScrn)
  {
      VIAPtr pVia = VIAPTR(pScrn);
      ViaTwodContext *tdc = &pVia->td;
      int i;
  
      /* Initialize the 2D engine registers to reset the 2D engine. */
      for (i = 0x04; i <= 0x40; i += 4) {
          VIASETREG(i, 0x0);
      }
  
      if (pVia->Chipset == VIA_VX800 ||
          pVia->Chipset == VIA_VX855 ||
          pVia->Chipset == VIA_VX900) {
          for (i = 0x44; i <= 0x5c; i += 4) {
              VIASETREG(i, 0x0);
          }
      }
  
      if (pVia->Chipset == VIA_VX900)
      {
          /*410 redefine 0x30 34 38*/
          VIASETREG(0x60, 0x0); /*already useable here*/
      }
  
      switch (pVia->Chipset) {
          case VIA_K8M890:
          case VIA_P4M900:
          case VIA_VX800:
          case VIA_VX855:
          case VIA_VX900:
              viaInitPCIe(pVia);
              break;
          default:
              viaInitAgp(pVia);
              break;
      }
  
      if (pVia->VQStart != 0) {
          switch (pVia->Chipset) {
              case VIA_K8M890:
              case VIA_P4M900:
              case VIA_VX800:
              case VIA_VX855:
              case VIA_VX900:
                  viaEnablePCIeVQ(pVia);
                  break;
              default:
                  viaEnableAgpVQ(pVia);
                  break;
          }
      } else {
          viaDisableVQ(pScrn);
      }
  
      viaAccelSetMode(pScrn->bitsPerPixel, tdc);
  }
  
  static void
  VIAInitialize3DEngine(ScrnInfoPtr pScrn)
  {
      VIAPtr pVia = VIAPTR(pScrn);
      int i;
  
      VIASETREG(VIA_REG_TRANSET, 0x00010000);
      for (i = 0; i <= 0x7D; i++)
          VIASETREG(VIA_REG_TRANSPACE, (CARD32) i << 24);
  
      VIASETREG(VIA_REG_TRANSET, 0x00020000);
      for (i = 0; i <= 0x94; i++)
          VIASETREG(VIA_REG_TRANSPACE, (CARD32) i << 24);
      VIASETREG(VIA_REG_TRANSPACE, 0x82400000);
  
      VIASETREG(VIA_REG_TRANSET, 0x01020000);
      for (i = 0; i <= 0x94; i++)
          VIASETREG(VIA_REG_TRANSPACE, (CARD32) i << 24);
      VIASETREG(VIA_REG_TRANSPACE, 0x82400000);
  
      VIASETREG(VIA_REG_TRANSET, 0xfe020000);
      for (i = 0; i <= 0x03; i++)
          VIASETREG(VIA_REG_TRANSPACE, (CARD32) i << 24);
  
      VIASETREG(VIA_REG_TRANSET, 0x00030000);
      for (i = 0; i <= 0xff; i++)
          VIASETREG(VIA_REG_TRANSPACE, 0);
  
      VIASETREG(VIA_REG_TRANSET, 0x00100000);
      VIASETREG(VIA_REG_TRANSPACE, 0x00333004);
      VIASETREG(VIA_REG_TRANSPACE, 0x10000002);
      VIASETREG(VIA_REG_TRANSPACE, 0x60000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x61000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x62000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x63000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x64000000);
  
      VIASETREG(VIA_REG_TRANSET, 0x00fe0000);
      if (pVia->Chipset == VIA_CLE266 && pVia->ChipRev >= 3)
          VIASETREG(VIA_REG_TRANSPACE, 0x40008c0f);
      else
          VIASETREG(VIA_REG_TRANSPACE, 0x4000800f);
      VIASETREG(VIA_REG_TRANSPACE, 0x44000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x45080C04);
      VIASETREG(VIA_REG_TRANSPACE, 0x46800408);
      VIASETREG(VIA_REG_TRANSPACE, 0x50000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x51000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x52000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x53000000);
  
      VIASETREG(VIA_REG_TRANSET, 0x00fe0000);
      VIASETREG(VIA_REG_TRANSPACE, 0x08000001);
      VIASETREG(VIA_REG_TRANSPACE, 0x0A000183);
      VIASETREG(VIA_REG_TRANSPACE, 0x0B00019F);
      VIASETREG(VIA_REG_TRANSPACE, 0x0C00018B);
      VIASETREG(VIA_REG_TRANSPACE, 0x0D00019B);
      VIASETREG(VIA_REG_TRANSPACE, 0x0E000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x0F000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x10000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x11000000);
      VIASETREG(VIA_REG_TRANSPACE, 0x20000000);
  }
  
  /*
   * Acceleration initialization function. Sets up offscreen memory disposition,
   * and initializes engines and acceleration method.
   */
  Bool
  UMSAccelInit(ScreenPtr pScreen)
  {
      ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
      VIAPtr pVia = VIAPTR(pScrn);
      Bool ret = FALSE;
  
      pVia->VQStart = 0;
      pVia->vq_bo = drm_bo_alloc(pScrn, VIA_VQ_SIZE, 16, TTM_PL_FLAG_VRAM);
      if (!pVia->vq_bo)
          goto err;
  
      pVia->VQStart = pVia->vq_bo->offset;
      pVia->VQEnd = pVia->vq_bo->offset + pVia->vq_bo->size;
  
      VIAInitialize2DEngine(pScrn);
      VIAInitialize3DEngine(pScrn);
  
      pVia->exa_sync_bo = drm_bo_alloc(pScrn, 32, 32, TTM_PL_FLAG_VRAM);
      if (!pVia->exa_sync_bo)
          goto err;
  
      /* Sync marker space. */
      pVia->exa_sync_bo = drm_bo_alloc(pScrn, 32, 32, TTM_PL_FLAG_VRAM);
      if (!pVia->exa_sync_bo)
          goto err;
  
      pVia->markerOffset = pVia->exa_sync_bo->offset;
      pVia->markerBuf = drm_bo_map(pScrn, pVia->exa_sync_bo);
      if (!pVia->markerBuf)
          goto err;
      pVia->curMarker = 0;
      pVia->lastMarkerRead = 0;
  
  #ifdef HAVE_DRI
      pVia->dBounce = NULL;
      pVia->scratchAddr = NULL;
  #endif /* HAVE_DRI */
      ret = TRUE;
  err:
      if (!ret) {
          if (pVia->markerBuf) {
              drm_bo_unmap(pScrn, pVia->exa_sync_bo);
              pVia->markerBuf = NULL;
          }
          if (pVia->exa_sync_bo)
              drm_bo_free(pScrn, pVia->exa_sync_bo);
          if (pVia->vq_bo)
              drm_bo_free(pScrn, pVia->vq_bo);
      }
      return ret;
  }
  
  Bool
  ums_create(ScrnInfoPtr pScrn)
  {
      ScreenPtr pScreen = pScrn->pScreen;
      VIAPtr pVia = VIAPTR(pScrn);
      unsigned long offset;
      BoxRec AvailFBArea;
      Bool ret = TRUE;
      long size;
      int maxY;
  
  #ifdef HAVE_DRI
      if (pVia->directRenderingType == DRI_1) {
          pVia->driSize = (pVia->FBFreeEnd - pVia->FBFreeStart) >> 2;
          if ((pVia->driSize > (pVia->maxDriSize * 1024)) && pVia->maxDriSize > 0)
              pVia->driSize = pVia->maxDriSize * 1024;
  
          /* In the case of DRI we handle all VRAM by the DRI ioctls */
          if (pVia->useEXA)
              return TRUE;
  
          /* XAA has to use FBManager so we have to split the space with DRI */
          maxY = pScrn->virtualY + (pVia->driSize / pVia->Bpl);
      } else
  #endif
          maxY = pVia->FBFreeEnd / pVia->Bpl;
  
      /* FBManager can't handle more than 32767 scan lines */
      if (maxY > 32767)
          maxY = 32767;
  
      AvailFBArea.x1 = 0;
      AvailFBArea.y1 = 0;
      AvailFBArea.x2 = pScrn->displayWidth;
      AvailFBArea.y2 = maxY;
      pVia->FBFreeStart = (AvailFBArea.y2 + 1) * pVia->Bpl;
  
      /*
       *   Initialization of the XFree86 framebuffer manager is done via
       *   Bool xf86InitFBManager(ScreenPtr pScreen, BoxPtr FullBox)
       *   FullBox represents the area of the framebuffer that the manager
       *   is allowed to manage. This is typically a box with a width
       *   of pScrn->displayWidth and a height of as many lines as can be fit
       *   within the total video memory
       */
      ret = xf86InitFBManager(pScreen, &AvailFBArea);
      if (ret != TRUE)
          xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86InitFBManager init failed\n");
  
      DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
              "Frame Buffer From (%d,%d) To (%d,%d)\n",
              AvailFBArea.x1, AvailFBArea.y1, AvailFBArea.x2, AvailFBArea.y2));
  
      offset = (pVia->FBFreeStart + pVia->Bpp - 1) / pVia->Bpp;
      size = pVia->FBFreeEnd / pVia->Bpp - offset;
      if (size > 0)
          xf86InitFBManagerLinear(pScreen, offset, size);
  
      DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
              "Using %d lines for offscreen memory.\n",
              AvailFBArea.y2 - pScrn->virtualY));
      return TRUE;
  }
  
  Bool
  UMSPreInit(ScrnInfoPtr pScrn)
  {
      MessageType from = X_PROBED;
      VIAPtr pVia = VIAPTR(pScrn);
      CARD8 videoRam;
      vgaHWPtr hwp;
  #ifdef HAVE_PCIACCESS
      struct pci_device *vgaDevice = pci_device_find_by_slot(0, 0, 0, 3);
      struct pci_device *bridge = pci_device_find_by_slot(0, 0, 0, 0);
  #endif
      int bMemSize = 0;
  
      if (!xf86LoadSubModule(pScrn, "vgahw"))
          return FALSE;
  
      if (!vgaHWGetHWRec(pScrn))
          return FALSE;
  
  #if 0
      /* Here we can alter the number of registers saved and restored by the
       * standard vgaHWSave and Restore routines.
       */
      vgaHWSetRegCounts(pScrn, VGA_NUM_CRTC, VGA_NUM_SEQ, VGA_NUM_GFX,
                        VGA_NUM_ATTR);
  #endif
      hwp = VGAHWPTR(pScrn);
  
      switch (pVia->Chipset) {
          case VIA_CLE266:
  #ifdef HAVE_PCIACCESS
              pci_device_cfg_read_u8(bridge, &videoRam, 0xE1);
  #else
              videoRam = pciReadByte(pciTag(0, 0, 0), 0xE1) & 0x70;
  #endif
              pScrn->videoRam = (1 << ((videoRam & 0x70) >> 4)) << 10;
              break;
          case VIA_KM400:
              /* P4M800 */
              if (DEVICE_ID(bridge) == 0x0296) {
  #ifdef HAVE_PCIACCESS
                  pci_device_cfg_read_u8(vgaDevice, &videoRam, 0xA1);
  #else
                  videoRam = pciReadByte(pciTag(0, 0, 3), 0xA1) & 0x70;
  #endif
              } else {
  #ifdef HAVE_PCIACCESS
                  pci_device_cfg_read_u8(bridge, &videoRam, 0xE1);
  #else
                  videoRam = pciReadByte(pciTag(0, 0, 0), 0xE1) & 0x70;
  #endif
              }
              pScrn->videoRam = (1 << ((videoRam & 0x70) >> 4)) << 10;
              break;
          case VIA_PM800:
          case VIA_VM800:
          case VIA_K8M800:
  #ifdef HAVE_PCIACCESS
              pci_device_cfg_read_u8(vgaDevice, &videoRam, 0xA1);
  #else
              videoRam = pciReadByte(pciTag(0, 0, 3), 0xA1) & 0x70;
  #endif
              pScrn->videoRam = (1 << ((videoRam & 0x70) >> 4)) << 10;
              break;
          case VIA_K8M890:
          case VIA_P4M890:
          case VIA_P4M900:
          case VIA_CX700:
          case VIA_VX800:
          case VIA_VX855:
          case VIA_VX900:
  #ifdef HAVE_PCIACCESS
              pci_device_cfg_read_u8(vgaDevice, &videoRam, 0xA1);
  #else
              videoRam = pciReadByte(pciTag(0, 0, 3), 0xA1) & 0x70;
  #endif
              pScrn->videoRam = (1 << ((videoRam & 0x70) >> 4)) << 12;
              break;
          default:
              if (pScrn->videoRam < 16384 || pScrn->videoRam > 65536) {
                  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
                             "Using old memory-detection method.\n");
                  bMemSize = hwp->readSeq(hwp, 0x39);
                  if (bMemSize > 16 && bMemSize <= 128)
                      pScrn->videoRam = (bMemSize + 1) << 9;
                  else if (bMemSize > 0 && bMemSize < 31)
                      pScrn->videoRam = bMemSize << 12;
                  else {
                      from = X_DEFAULT;
                      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
                                 "Memory size detection failed: using 16 MB.\n");
                      pScrn->videoRam = 16 << 10;
                  }
              } else {
                  from = X_DEFAULT;
                  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
                             "No memory-detection done. Use VideoRAM option.\n");
              }
      }
  
      /*
       * PCI BAR are limited to 256 MB.
       */
      if (pScrn->videoRam > (256 << 10)) {
          xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
                      "Cannot use more than 256 MB of VRAM.\n");
                      pScrn->videoRam = (256 << 10);
      }
  
      if (from == X_PROBED) {
          xf86DrvMsg(pScrn->scrnIndex, from,
                     "Probed amount of VideoRAM = %d kB\n", pScrn->videoRam);
      }
  
      /* Split the FB for SAMM. */
      /* FIXME: For now, split the FB into two equal sections.
       * This should be user-adjustable via a config option. */
      if (pVia->IsSecondary) {
          DevUnion *pPriv;
          VIAEntPtr pVIAEnt;
          VIAPtr pVia1;
  
          pPriv = xf86GetEntityPrivate(pScrn->entityList[0], gVIAEntityIndex);
          pVIAEnt = pPriv->ptr;
          pScrn->videoRam = pScrn->videoRam >> 1;
          pVIAEnt->pPrimaryScrn->videoRam = pScrn->videoRam;
          pVia1 = VIAPTR(pVIAEnt->pPrimaryScrn);
          pVia1->videoRambytes = pScrn->videoRam << 10;
          pVia->FrameBufferBase += (pScrn->videoRam << 10);
      }
  
      pVia->videoRambytes = pScrn->videoRam << 10;
  
      /* maybe throw in some more sanity checks here */
  #ifndef HAVE_PCIACCESS
      pVia->PciTag = pciTag(pVia->PciInfo->bus, pVia->PciInfo->device,
                            pVia->PciInfo->func);
  #endif
  
      /* Detect the amount of installed RAM */
      if (!VIAMapMMIO(pScrn))
          return FALSE;
  
      if (!VIAMapFB(pScrn))
          return FALSE;
      return TRUE;
  }
  