text: #ifdef HAVE_CONFIG_H
  #include "config.h"
  #endif
  
  #include "xf86.h"
  #include "xf86_OSproc.h"
  #include "xf86Pci.h"
  #include "mga.h"
  #include "mga_reg.h"
  #include "dgaproc.h"
  
  
  static Bool MGA_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **, 
  					int *, int *, int *);
  static Bool MGA_SetMode(ScrnInfoPtr, DGAModePtr);
  static int  MGA_GetViewport(ScrnInfoPtr);
  static void MGA_SetViewport(ScrnInfoPtr, int, int, int);
  #ifdef USE_XAA
  static void MGA_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long);
  static void MGA_BlitRect(ScrnInfoPtr, int, int, int, int, int, int);
  static void MGA_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int, 
  					unsigned long);
  #endif
  
  static
  DGAFunctionRec MGA_DGAFuncs = {
     MGA_OpenFramebuffer,
     NULL,
     MGA_SetMode,
     MGA_SetViewport,
     MGA_GetViewport,
     MGAStormSync,
  #ifdef USE_XAA
     MGA_FillRect,
     MGA_BlitRect,
     MGA_BlitTransRect
  #else
     NULL, NULL, NULL
  #endif
  };
  
  
  static int
  FindSmallestPitch(
     MGAPtr pMga,
     int Bpp,
     int width
  ){
     int Pitches1[] = 
  	  {640, 768, 800, 960, 1024, 1152, 1280, 1600, 1920, 2048, 0};
     int Pitches2[] = 
  	  {512, 640, 768, 800, 832, 960, 1024, 1152, 1280, 1600, 1664, 
  		1920, 2048, 0};
     int *linePitches = NULL;
     int pitch;
          
  
     if(!pMga->NoAccel) {
  	switch(pMga->Chipset) {
  	case PCI_CHIP_MGA2064:
  	    linePitches = Pitches1;
  	    break;
  	case PCI_CHIP_MGA2164:
  	case PCI_CHIP_MGA2164_AGP:
  	case PCI_CHIP_MGA1064:
  	    linePitches = Pitches2;
  	    break;
  	}
     }
  
     pitch = pMga->Roundings[Bpp - 1] - 1;
  
     if(linePitches) {
  	while((*linePitches < width) || (*linePitches & pitch))
  	   linePitches++;
  	return *linePitches;
     } 
  
     return ((width + pitch) & ~pitch); 
  }
  
  static DGAModePtr
  MGASetupDGAMode(
     ScrnInfoPtr pScrn,
     DGAModePtr modes,
     int *num,
     int bitsPerPixel,
     int depth,
     Bool pixmap,
     int secondPitch,
     unsigned long red,
     unsigned long green,
     unsigned long blue,
     short visualClass
  ){
     DisplayModePtr firstMode, pMode;
     MGAPtr pMga = MGAPTR(pScrn);
     DGAModePtr mode, newmodes;
     int size, pitch, Bpp = bitsPerPixel >> 3;
  
  SECOND_PASS:
  
     pMode = firstMode = pScrn->modes;
  
     while(1) {
  
          
  	pitch = FindSmallestPitch(pMga, Bpp, pMode->HDisplay);
  	size = pitch * Bpp * pMode->VDisplay;
  
  	if((!secondPitch || (pitch != secondPitch)) &&
  		(size <= pMga->FbUsableSize)) {
  
  	    if(secondPitch)
  		pitch = secondPitch; 
  
  	    if(!(newmodes = realloc(modes, (*num + 1) * sizeof(DGAModeRec))))
  		break;
  
  	    modes = newmodes;
  	    mode = modes + *num;
  
  	    mode->mode = pMode;
  	    mode->flags = DGA_CONCURRENT_ACCESS;
              if(pixmap)
  		mode->flags |= DGA_PIXMAP_AVAILABLE;
  #ifdef USE_XAA
  	    if(!pMga->NoAccel) {
  		mode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT;
  		if((Bpp != 3) && (pMga->Chipset != PCI_CHIP_MGA2064))
  		    mode->flags |= DGA_BLIT_RECT_TRANS;
  	    }
  #endif
  	    if(pMode->Flags & V_DBLSCAN)
  		mode->flags |= DGA_DOUBLESCAN;
  	    if(pMode->Flags & V_INTERLACE)
  		mode->flags |= DGA_INTERLACED;
  	    mode->byteOrder = pScrn->imageByteOrder;
  	    mode->depth = depth;
  	    mode->bitsPerPixel = bitsPerPixel;
  	    mode->red_mask = red;
  	    mode->green_mask = green;
  	    mode->blue_mask = blue;
  	    mode->visualClass = visualClass;
  	    mode->viewportWidth = pMode->HDisplay;
  	    mode->viewportHeight = pMode->VDisplay;
  	    mode->xViewportStep = (3 - pMga->BppShifts[Bpp - 1]);
  	    if((Bpp == 3) && 
  		    (pMga->Chipset == PCI_CHIP_MGAG400 || pMga->Chipset == PCI_CHIP_MGAG550))
  		mode->xViewportStep <<= 1;
  	    mode->yViewportStep = 1;
  	    mode->viewportFlags = DGA_FLIP_RETRACE;
  	    mode->offset = pMga->YDstOrg * Bpp;  /* gonna need to fix that */
  	    mode->address = pMga->FbStart;
  	    mode->bytesPerScanline = pitch * Bpp;
  	    mode->imageWidth = pitch;
  	    mode->imageHeight =  pMga->FbUsableSize / mode->bytesPerScanline; 
  	    mode->pixmapWidth = pitch;
  	    switch (pMga->Chipset) {
  	    case PCI_CHIP_MGAG200_SE_A_PCI:
  	    case PCI_CHIP_MGAG200_SE_B_PCI:
  		mode->pixmapHeight = (min(pMga->FbUsableSize, 1*1024*1024)) /
  				     mode->bytesPerScanline;
  		break;
  	    default:
  		mode->pixmapHeight = (min(pMga->FbUsableSize, 16*1024*1024)) / 
  				     mode->bytesPerScanline;
  	    }
  	    mode->maxViewportX = mode->imageWidth - mode->viewportWidth;
  	    mode->maxViewportY = (pMga->FbUsableSize / mode->bytesPerScanline) -
  				 	mode->viewportHeight;
  
  	    if( (pMga->Chipset == PCI_CHIP_MGA2064) ||
  		(pMga->Chipset == PCI_CHIP_MGA2164) ||
  		(pMga->Chipset == PCI_CHIP_MGA2164_AGP)) 
  	    {
  		int tmp;
  
  		tmp = (8*1024*1024 / mode->bytesPerScanline) -
  					mode->viewportHeight;
  		if(tmp < 0) tmp = 0;
  		if(tmp < mode->maxViewportY)
  		    mode->maxViewportY = tmp;
  	    }
  
  	    (*num)++;
  	}
  
  	pMode = pMode->next;
  	if(pMode == firstMode)
  	   break;
      }
  
      if(secondPitch) {
  	secondPitch = 0;
  	goto SECOND_PASS;
      }
  
      return modes;
  }
  
  
  Bool
  MGADGAInit(ScreenPtr pScreen)
  {   
     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
     MGAPtr pMga = MGAPTR(pScrn);
     DGAModePtr modes = NULL;
     int num = 0;
  
     /* 8 */
     modes = MGASetupDGAMode (pScrn, modes, &num, 8, 8, 
  		(pScrn->bitsPerPixel == 8),
  		(pScrn->bitsPerPixel != 8) ? 0 : pScrn->displayWidth,
  		0, 0, 0, PseudoColor);
  
     /* 15 */
     modes = MGASetupDGAMode (pScrn, modes, &num, 16, 15, 
  		(pScrn->bitsPerPixel == 16),
  		(pScrn->depth != 15) ? 0 : pScrn->displayWidth,
  		0x7c00, 0x03e0, 0x001f, TrueColor);
  
     modes = MGASetupDGAMode (pScrn, modes, &num, 16, 15, 
  		(pScrn->bitsPerPixel == 16),
  		(pScrn->depth != 15) ? 0 : pScrn->displayWidth,
  		0x7c00, 0x03e0, 0x001f, DirectColor);
  
     /* 16 */
     modes = MGASetupDGAMode (pScrn, modes, &num, 16, 16, 
  		(pScrn->bitsPerPixel == 16),
  		(pScrn->depth != 16) ? 0 : pScrn->displayWidth,
  		0xf800, 0x07e0, 0x001f, TrueColor);
  
     modes = MGASetupDGAMode (pScrn, modes, &num, 16, 16, 
  		(pScrn->bitsPerPixel == 16),
  		(pScrn->depth != 16) ? 0 : pScrn->displayWidth,
  		0xf800, 0x07e0, 0x001f, DirectColor);
  
     /* 24 */
     modes = MGASetupDGAMode (pScrn, modes, &num, 24, 24, 
  		(pScrn->bitsPerPixel == 24),
  		(pScrn->bitsPerPixel != 24) ? 0 : pScrn->displayWidth,
  		0xff0000, 0x00ff00, 0x0000ff, TrueColor);
  
     modes = MGASetupDGAMode (pScrn, modes, &num, 24, 24, 
  		(pScrn->bitsPerPixel == 24),
  		(pScrn->bitsPerPixel != 24) ? 0 : pScrn->displayWidth,
  		0xff0000, 0x00ff00, 0x0000ff, DirectColor);
  
     /* 32 */
     modes = MGASetupDGAMode (pScrn, modes, &num, 32, 24, 
  		(pScrn->bitsPerPixel == 32),
  		(pScrn->bitsPerPixel != 32) ? 0 : pScrn->displayWidth,
  		0xff0000, 0x00ff00, 0x0000ff, TrueColor);
  
     modes = MGASetupDGAMode (pScrn, modes, &num, 32, 24, 
  		(pScrn->bitsPerPixel == 32),
  		(pScrn->bitsPerPixel != 32) ? 0 : pScrn->displayWidth,
  		0xff0000, 0x00ff00, 0x0000ff, DirectColor);
  
     pMga->numDGAModes = num;
     pMga->DGAModes = modes;
  
     return DGAInit(pScreen, &MGA_DGAFuncs, modes, num);  
  }
  
  
  static int 
  BitsSet(unsigned long data)
  {
     unsigned long mask;
     int set = 0;
  
     for(mask = 1; mask; mask <<= 1)
          if(mask & data) set++;   
  
     return set;
  }
  
  /*
   * This is not strictly required - but it will load a 'sane'
   * palette when starting DGA.
   */
  static void
  mgaDGASetPalette(ScrnInfoPtr pScrn)
  {
      MGAPtr pMga = MGAPTR(pScrn);
      MGARamdacPtr MGAdac = &pMga->Dac;
      unsigned char DAC[256*3];
      int i;
      
      if (!MGAdac->RestorePalette)
  	return;
      
      for (i = 0; i < 256; i++) {
  	DAC[i*3] = i;
  	DAC[i*3 + 1] = i;
  	DAC[i*3 + 2] = i;
      }
      MGAdac->RestorePalette(pScrn, DAC);
  }
  
  
  static Bool
  MGA_SetMode(
     ScrnInfoPtr pScrn,
     DGAModePtr pMode
  ){
     static MGAFBLayout SavedLayouts[MAXSCREENS];
     int index = pScrn->pScreen->myNum;
  
     MGAPtr pMga = MGAPTR(pScrn);
  
     if(!pMode) { /* restore the original mode */
        if(pMga->DGAactive)
          memcpy(&pMga->CurrentLayout, &SavedLayouts[index], sizeof(MGAFBLayout));
                  
        pScrn->currentMode = pMga->CurrentLayout.mode;
        pScrn->SwitchMode(SWITCH_MODE_ARGS(pScrn, pScrn->currentMode));
        MGAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
        pMga->DGAactive = FALSE;
     } else {
        if(!pMga->DGAactive) {  /* save the old parameters */
  	memcpy(&SavedLayouts[index], &pMga->CurrentLayout, sizeof(MGAFBLayout));
  	pMga->DGAactive = TRUE;
        }
        /* update CurrentLayout */
        pMga->CurrentLayout.bitsPerPixel = pMode->bitsPerPixel;
        pMga->CurrentLayout.depth = pMode->depth;
        pMga->CurrentLayout.displayWidth = pMode->bytesPerScanline / 
                                (pMode->bitsPerPixel >> 3);
        pMga->CurrentLayout.weight.red = BitsSet(pMode->red_mask);
        pMga->CurrentLayout.weight.green = BitsSet(pMode->green_mask);
        pMga->CurrentLayout.weight.blue = BitsSet(pMode->blue_mask);
        /* MGAModeInit() will set the mode field */
  
        pScrn->SwitchMode(SWITCH_MODE_ARGS(pScrn, pMode->mode));
        /* not strictly required but nice */
        mgaDGASetPalette(pScrn);
     }
     
     return TRUE;
  }
  
  
  
  static int  
  MGA_GetViewport(
    ScrnInfoPtr pScrn
  ){
      MGAPtr pMga = MGAPTR(pScrn);
  
      return pMga->DGAViewportStatus;
  }
  
  static void 
  MGA_SetViewport(
     ScrnInfoPtr pScrn, 
     int x, int y, 
     int flags
  ){
     MGAPtr pMga = MGAPTR(pScrn);
  
     MGAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, x, y));
     pMga->DGAViewportStatus = 0;  /* MGAAdjustFrame loops until finished */
  }
  
  #ifdef USE_XAA
  static void 
  MGA_FillRect (
     ScrnInfoPtr pScrn, 
     int x, int y, int w, int h, 
     unsigned long color
  ){
      MGAPtr pMga = MGAPTR(pScrn);
  
      if(!pMga->AccelInfoRec) return;
  
      mgaDoSetupForSolidFill(pScrn, color, GXcopy, ~0, 
  			   pMga->CurrentLayout.bitsPerPixel);
      (*pMga->AccelInfoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h);
  
      SET_SYNC_FLAG(pMga->AccelInfoRec);
  }
  
  static void 
  MGA_BlitRect(
     ScrnInfoPtr pScrn, 
     int srcx, int srcy, 
     int w, int h, 
     int dstx, int dsty
  ){
      MGAPtr pMga = MGAPTR(pScrn);
      int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
      int ydir = (srcy < dsty) ? -1 : 1;
  
      if(!pMga->AccelInfoRec) return;
  
      mgaDoSetupForScreenToScreenCopy( pScrn, xdir, ydir, GXcopy, ~0, -1,
  				     pMga->CurrentLayout.bitsPerPixel );
  
      (*pMga->AccelInfoRec->SubsequentScreenToScreenCopy)(
  		pScrn, srcx, srcy, dstx, dsty, w, h);
  
      SET_SYNC_FLAG(pMga->AccelInfoRec);
  }
  
  
  static void MGA_BlitTransRect( ScrnInfoPtr pScrn, int srcx, int srcy, 
  			       int w, int h, int dstx, int dsty,
  			       unsigned long color )
  {
      MGAPtr pMga = MGAPTR(pScrn);
  
      if( (pMga->AccelInfoRec != NULL)
  	&& (pMga->CurrentLayout.bitsPerPixel != 24)
  	&& (pMga->Chipset != PCI_CHIP_MGA2064) ) {
  	const int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
  	const int ydir = (srcy < dsty) ? -1 : 1;
  
  	pMga->DrawTransparent = TRUE;
  
  	mgaDoSetupForScreenToScreenCopy( pScrn, xdir, ydir, GXcopy, ~0, color,
  					 pMga->CurrentLayout.bitsPerPixel );
  
  	pMga->DrawTransparent = FALSE;
  
  	(*pMga->AccelInfoRec->SubsequentScreenToScreenCopy)(
  	    pScrn, srcx, srcy, dstx, dsty, w, h);
  
  	SET_SYNC_FLAG(pMga->AccelInfoRec);
      }
  }
  #endif
  
  static Bool 
  MGA_OpenFramebuffer(
     ScrnInfoPtr pScrn, 
     char **name,
     unsigned char **mem,
     int *size,
     int *offset,
     int *flags
  ){
      MGAPtr pMga = MGAPTR(pScrn);
  
      *name = NULL; 		/* no special device */
      *mem = (unsigned char*)pMga->FbAddress;
      *size = pMga->FbMapSize;
      *offset = 0;
      *flags = DGA_NEED_ROOT;
  
      return TRUE;
  }
  