if (vga256InfoRec.dacSpeeds[2] <= 0) vga256InfoRec.dacSpeeds[2] = 135000; if (vga256InfoRec.dacSpeeds[3] <= 0) vga256InfoRec.dacSpeeds[3] = 135000; } else if (S3_TRIO_3D_2X_SERIES(s3vPriv.chip)) { if (vga256InfoRec.dacSpeeds[0] <= 0) vga256InfoRec.dacSpeeds[0] = 230000; if (vga256InfoRec.dacSpeeds[1] <= 0) vga256InfoRec.dacSpeeds[1] = 230000;
S3VProbe(){S3PCIInformation *pciInfo = NULL;unsigned char config1, config2, m, n, n1, n2, cr66, sr8;int mclk;DisplayModePtr pMode, pEnd;   if (vga256InfoRec.chipset) {      if (StrCaseCmp(vga256InfoRec.chipset,S3VIdent(0)))      return(FALSE);   }    /* Start with PCI probing, this should get us quite far already */   /* For now, we only use the PCI probing; add in later VLB */   pciInfo = s3vGetPCIInfo();   if (!pciInfo)      return FALSE;   if (pciInfo && pciInfo->MemBase && !vga256InfoRec.MemBase)      vga256InfoRec.MemBase = pciInfo->MemBase;   if (pciInfo)      if(pciInfo->ChipType != S3_ViRGE &&          pciInfo->ChipType != S3_ViRGE_VX &&	 pciInfo->ChipType != S3_ViRGE_DXGX &&	 pciInfo->ChipType != S3_ViRGE_GX2 &&	 pciInfo->ChipType != S3_ViRGE_MX &&	 pciInfo->ChipType != S3_ViRGE_MXP &&#if 0 /* not yet */	 pciInfo->ChipType != S3_SAVAGE_3D &&	 pciInfo->ChipType != S3_SAVAGE_3D_M &&#endif	 pciInfo->ChipType != S3_TRIO_3D &&	 pciInfo->ChipType != S3_TRIO_3D_2X){          if (xf86Verbose > 1)             ErrorF("%s %s: Unsupported (non-ViRGE) S3 chipset detected!\n",                 XCONFIG_PROBED, vga256InfoRec.name);          return FALSE;          }      else {         s3vPriv.chip = pciInfo->ChipType;         ErrorF("%s %s: Detected S3 %s\n",XCONFIG_PROBED,            vga256InfoRec.name, xf86TokenToString(s3vChipTable, s3vPriv.chip));         ErrorF("%s %s: using driver for chipset \"%s\"\n",XCONFIG_PROBED,             vga256InfoRec.name, S3VIdent(0));	 }   vga256InfoRec.chipset = S3VIdent(0);#ifdef __alpha__   if (xf86bpp > 16)     FatalError("%s %s: %d bpp not yet supported for Alpha/AXP\n",		XCONFIG_GIVEN, vga256InfoRec.name, xf86bpp);#endif   /* Add/enable IO ports to list: call EnterLeave */   S3VEnterLeave(ENTER);   /* Unlock sys regs */   outb(vgaCRIndex, 0x38);   outb(vgaCRReg, 0x48);    /* Next go on to detect amount of installed ram */   outb(vgaCRIndex, 0x36);              /* for register CR36 (CONFG_REG1), */   config1 = inb(vgaCRReg);              /* get amount of vram installed */   outb(vgaCRIndex, 0x37);              /* for register CR37 (CONFG_REG2), */   config2 = inb(vgaCRReg);             /* get amount of off-screen ram  */   outb(vgaCRIndex, 0x30);   s3vPriv.ChipId = inb(vgaCRReg);         /* get chip id */   outb(vgaCRIndex, 0x2e);   s3vPriv.ChipId |= (inb(vgaCRReg) << 8);   /* And compute the amount of video memory and offscreen memory */   s3vPriv.MemOffScreen = 0;   if (!vga256InfoRec.videoRam) {      if (s3vPriv.chip == S3_ViRGE_VX) {         switch((config2 & 0x60) >> 5) {         case 1:            s3vPriv.MemOffScreen = 4 * 1024;            break;         case 2:            s3vPriv.MemOffScreen = 2 * 1024;            break;         }         switch ((config1 & 0x60) >> 5) {         case 0:            vga256InfoRec.videoRam = 2 * 1024;            break;         case 1:            vga256InfoRec.videoRam = 4 * 1024;            break;         case 2:            vga256InfoRec.videoRam = 6 * 1024;            break;         case 3:            vga256InfoRec.videoRam = 8 * 1024;            break;         }         vga256InfoRec.videoRam -= s3vPriv.MemOffScreen;      }      else if (S3_TRIO_3D_2X_SERIES(s3vPriv.chip)) {         switch((config1 & 0xE0) >> 5) {         case 0:            vga256InfoRec.videoRam = 8 * 1024;            break;         case 1:    /* 32 bit interface -- yuck */         case 2:            vga256InfoRec.videoRam = 4 * 1024;            break;         case 6:            vga256InfoRec.videoRam = 2 * 1024;            break;         }      }      else if (S3_ViRGE_GX2_SERIES(s3vPriv.chip) || S3_ViRGE_MX_SERIES(s3vPriv.chip)) {         switch((config1 & 0xC0) >> 6) {         case 1:            vga256InfoRec.videoRam = 4 * 1024;            break;         case 3:            vga256InfoRec.videoRam = 2 * 1024;            break;         }      }      else if (S3_TRIO_3D_SERIES(s3vPriv.chip)) {        switch((config1 & 0xE0) >> 5) {        case 0:        case 2:           vga256InfoRec.videoRam = 4 * 1024;           break;        case 4:           vga256InfoRec.videoRam = 2 * 1024;           break;        }      }      else {         switch((config1 & 0xE0) >> 5) {         case 0:            vga256InfoRec.videoRam = 4 * 1024;            break;         case 4:            vga256InfoRec.videoRam = 2 * 1024;            break;         case 6:            vga256InfoRec.videoRam = 1 * 1024;            break;         }      }      if (xf86Verbose) {         if (s3vPriv.MemOffScreen)            ErrorF("%s %s: videoram:  %dk (plus %dk off-screen)\n",                   XCONFIG_PROBED, vga256InfoRec.name, vga256InfoRec.videoRam,                   s3vPriv.MemOffScreen);         else            ErrorF("%s %s: videoram:  %dk\n",                   XCONFIG_PROBED, vga256InfoRec.name, vga256InfoRec.videoRam);      }   } else {      if (xf86Verbose) {         ErrorF("%s %s: videoram:  %dk\n",              XCONFIG_GIVEN, vga256InfoRec.name, vga256InfoRec.videoRam);      }   }   /* reset S3 graphics engine to avoid memory corruption */   if (s3vPriv.chip != S3_ViRGE_VX) {      outb(vgaCRIndex, 0x66);      cr66 = inb(vgaCRReg);      outb(vgaCRReg, cr66 | 0x02);      usleep(10000);  /* wait a little bit... */   }   if (find_bios_string(vga256InfoRec.BIOSbase,"S3 86C325",			"MELCO WGP-VG VIDEO BIOS") != NULL) {      if (xf86Verbose)	 ErrorF("%s %s: MELCO BIOS found\n",		XCONFIG_PROBED, vga256InfoRec.name);      if (vga256InfoRec.MemClk <= 0)       vga256InfoRec.MemClk       =  74000;      if (vga256InfoRec.dacSpeeds[0] <= 0) vga256InfoRec.dacSpeeds[0] = 191500;      if (vga256InfoRec.dacSpeeds[1] <= 0) vga256InfoRec.dacSpeeds[1] = 162500;      if (vga256InfoRec.dacSpeeds[2] <= 0) vga256InfoRec.dacSpeeds[2] = 111500;      if (vga256InfoRec.dacSpeeds[3] <= 0) vga256InfoRec.dacSpeeds[3] =  83500;   }   if (s3vPriv.chip != S3_ViRGE_VX) {      outb(vgaCRIndex, 0x66);      outb(vgaCRReg, cr66 & ~0x02);  /* clear reset flag */      usleep(10000);  /* wait a little bit... */   }   /* ViRGE built-in ramdac speeds */   if (vga256InfoRec.dacSpeeds[3] <= 0 && vga256InfoRec.dacSpeeds[2] > 0)      vga256InfoRec.dacSpeeds[3] = vga256InfoRec.dacSpeeds[2];   if (s3vPriv.chip == S3_ViRGE_VX) {      if (vga256InfoRec.dacSpeeds[0] <= 0) vga256InfoRec.dacSpeeds[0] = 220000;      if (vga256InfoRec.dacSpeeds[1] <= 0) vga256InfoRec.dacSpeeds[1] = 220000;      if (vga256InfoRec.dacSpeeds[2] <= 0) vga256InfoRec.dacSpeeds[2] = 135000;      if (vga256InfoRec.dacSpeeds[3] <= 0) vga256InfoRec.dacSpeeds[3] = 135000;   }   else if (s3vPriv.chip == S3_ViRGE_DXGX || S3_ViRGE_GX2_SERIES(s3vPriv.chip)) {      if (vga256InfoRec.dacSpeeds[0] <= 0) vga256InfoRec.dacSpeeds[0] = 170000;      if (vga256InfoRec.dacSpeeds[1] <= 0) vga256InfoRec.dacSpeeds[1] = 170000;      if (vga256InfoRec.dacSpeeds[2] <= 0) vga256InfoRec.dacSpeeds[2] = 135000;      if (vga256InfoRec.dacSpeeds[3] <= 0) vga256InfoRec.dacSpeeds[3] = 135000;   }   else if (S3_ViRGE_MX_SERIES(s3vPriv.chip)) {      if (vga256InfoRec.dacSpeeds[0] <= 0) vga256InfoRec.dacSpeeds[0] = 135000;      if (vga256InfoRec.dacSpeeds[1] <= 0) vga256InfoRec.dacSpeeds[1] = 135000;      if (vga256InfoRec.dacSpeeds[2] <= 0) vga256InfoRec.dacSpeeds[2] = 100000;      if (vga256InfoRec.dacSpeeds[3] <= 0) vga256InfoRec.dacSpeeds[3] = 100000;   }   else if(S3_TRIO_3D_SERIES(s3vPriv.chip)) {      if (vga256InfoRec.dacSpeeds[0] <= 0) vga256InfoRec.dacSpeeds[0] = 230000;      if (vga256InfoRec.dacSpeeds[1] <= 0) vga256InfoRec.dacSpeeds[1] = 230000;      if (vga256InfoRec.dacSpeeds[2] <= 0) vga256InfoRec.dacSpeeds[2] = 135000;      if (vga256InfoRec.dacSpeeds[3] <= 0) vga256InfoRec.dacSpeeds[3] = 135000;   }   else {      if (vga256InfoRec.dacSpeeds[0] <= 0) vga256InfoRec.dacSpeeds[0] = 135000;      if (vga256InfoRec.dacSpeeds[1] <= 0) vga256InfoRec.dacSpeeds[1] =  95000;      if (vga256InfoRec.dacSpeeds[2] <= 0) vga256InfoRec.dacSpeeds[2] =  57000;      if (vga256InfoRec.dacSpeeds[3] <= 0) vga256InfoRec.dacSpeeds[3] =  57000;   }   if (vga256InfoRec.dacSpeedBpp <= 0)      if (xf86bpp > 24 && vga256InfoRec.dacSpeeds[3] > 0)	 vga256InfoRec.dacSpeedBpp = vga256InfoRec.dacSpeeds[3];      else if (xf86bpp >= 24 && vga256InfoRec.dacSpeeds[2] > 0)	 vga256InfoRec.dacSpeedBpp = vga256InfoRec.dacSpeeds[2];      else if (xf86bpp > 8 && xf86bpp < 24 && vga256InfoRec.dacSpeeds[1] > 0)	 vga256InfoRec.dacSpeedBpp = vga256InfoRec.dacSpeeds[1];      else if (xf86bpp <= 8 && vga256InfoRec.dacSpeeds[0] > 0)	 vga256InfoRec.dacSpeedBpp = vga256InfoRec.dacSpeeds[0];   if (xf86Verbose) {      ErrorF("%s %s: Ramdac speed: %d MHz",	     OFLG_ISSET(XCONFIG_DACSPEED, &vga256InfoRec.xconfigFlag) ?	     XCONFIG_GIVEN : XCONFIG_PROBED, vga256InfoRec.name,	     vga256InfoRec.dacSpeeds[0] / 1000);      if (vga256InfoRec.dacSpeedBpp != vga256InfoRec.dacSpeeds[0])	 ErrorF("  (%d MHz for %d bpp)",vga256InfoRec.dacSpeedBpp / 1000, xf86bpp);      ErrorF("\n");   }   /* Now set RAMDAC limits */   vga256InfoRec.maxClock = vga256InfoRec.dacSpeedBpp;   /* Detect current MCLK and print it for user */   outb(0x3c4, 0x08);   sr8 = inb(0x3c5);   outb(0x3c5, 0x06);    outb(0x3c4, 0x10);   n = inb(0x3c5);   outb(0x3c4, 0x11);   m = inb(0x3c5);   outb(0x3c4, 0x08);   outb(0x3c5, sr8);   m &= 0x7f;   n1 = n & 0x1f;   n2 = (n>>5) & 0x03;   mclk = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;   if (S3_ViRGE_MX_SERIES(s3vPriv.chip)) {      char *is_probed = XCONFIG_PROBED;      /*       * try to figure out which reference clock is used:       * Toshiba Tecra 5x0/7x0 seems to use 28.636 MHz       * Compaq Armada 7x00 uses 14.318 MHz       */      if (find_bios_string(vga256InfoRec.BIOSbase, "COMPAQ M5 BIOS", NULL) != NULL) {	 if (xf86Verbose)	    ErrorF("%s %s: COMPAQ M5 BIOS found\n", XCONFIG_PROBED, vga256InfoRec.name);	 /* s3vPriv.refclk_fact = 1.0; */      }      else if (find_bios_string(vga256InfoRec.BIOSbase, "TOSHIBA Video BIOS", NULL) != NULL) {	 if (xf86Verbose)	    ErrorF("%s %s: TOSHIBA Video BIOS found\n", XCONFIG_PROBED, vga256InfoRec.name);	 /* s3vPriv.refclk_fact = 2.0; */      }      else if (find_bios_string(vga256InfoRec.BIOSbase, "Generic M5+ BIOS", NULL) != NULL) {	 if (xf86Verbose)	    ErrorF("%s %s: Generic M5+ BIOS found\n", XCONFIG_PROBED, vga256InfoRec.name);	 /* s3vPriv.refclk_fact = 1.0; */      }      else if (find_bios_string(vga256InfoRec.BIOSbase, "M5+ BIOS", NULL) != NULL) {	 if (xf86Verbose)	    ErrorF("%s %s: M5+ BIOS found\n", XCONFIG_PROBED, vga256InfoRec.name);	 /* s3vPriv.refclk_fact = 1.0; */      }      /* else */      {  /* better always use guessed value... */	 if (mclk > 60000)	    s3vPriv.refclk_fact = 1.0;	 else	    s3vPriv.refclk_fact = 2.0;  /* don't know why ??? */      }      if (vga256InfoRec.s3RefClk != 0) {	 s3vPriv.refclk_fact = vga256InfoRec.s3RefClk / 14318.0;	 is_probed = XCONFIG_GIVEN;      }      else	 vga256InfoRec.s3RefClk = (int)(14318.18 * s3vPriv.refclk_fact);      mclk = (int)(mclk * s3vPriv.refclk_fact);      ErrorF("%s %s: assuming RefCLK value of %1.3f MHz\n",	     is_probed, vga256InfoRec.name, vga256InfoRec.s3RefClk / 1000.0);   }   ErrorF("%s %s: Detected current MCLK value of %1.3f MHz\n",XCONFIG_PROBED,       vga256InfoRec.name, mclk / 1000.0);   /* Now check if the user has specified "set_memclk" value in XConfig */   if (vga256InfoRec.MemClk > 0) {      if(vga256InfoRec.MemClk <= 150000) {         ErrorF("%s %s: Using Memory Clock value of %1.3f MHz\n",		OFLG_ISSET(XCONFIG_MEMCLOCK, &vga256InfoRec.xconfigFlag) ?		XCONFIG_GIVEN : XCONFIG_PROBED, vga256InfoRec.name, 		vga256InfoRec.MemClk/1000.0);         s3vPriv.MCLK = vga256InfoRec.MemClk;         }      else {         ErrorF("%s %s: Memory Clock value of %1.3f MHz is larger than limit of 150 MHz\n",              XCONFIG_GIVEN, vga256InfoRec.name, vga256InfoRec.MemClk/1000.0);         s3vPriv.MCLK = 0;         }      }   else s3vPriv.MCLK = 0;   if (S3_ViRGE_MX_SERIES(s3vPriv.chip) && xf86Verbose) {       int lcdclk, h_lcd, v_lcd;       if (OFLG_ISSET(XCONFIG_LCDCLOCK, &vga256InfoRec.xconfigFlag)) {	  lcdclk = vga256InfoRec.LCDClk;       } else {	  int n1, n2, sr12, sr13, sr29;          outb(0x3c4, 0x12);          sr12 = inb(0x3c5);          outb(0x3c4, 0x13);          sr13 = inb(0x3c5) & 0x7f;          outb(0x3c4, 0x29);          sr29 = inb(0x3c5);    	  n1 = sr12 & 0x1f;    	  n2 = ((sr12>>6) & 0x03) | ((sr29 & 0x01) << 2);          lcdclk = ((int)(s3vPriv.refclk_fact * 1431818 * (sr13+2)) / (n1+2) / (1 << n2) + 50) / 100;       }       outb(0x3c4, 0x61);       h_lcd = inb(0x3c5);       outb(0x3c4, 0x66);       h_lcd |= ((inb(0x3c5) & 0x02) << 7);       h_lcd = (h_lcd+1) * 8;       outb(0x3c4, 0x69);       v_lcd = inb(0x3c5);       outb(0x3c4, 0x6e);       v_lcd |= ((inb(0x3c5) & 0x70) << 4);       v_lcd++;       ErrorF("%s %s: LCD size %dx%d, clock %1.3f MHz\n"	      , OFLG_ISSET(XCONFIG_LCDCLOCK, &vga256InfoRec.xconfigFlag) ? XCONFIG_GIVEN : XCONFIG_PROBED	      , vga256InfoRec.name	      , h_lcd, v_lcd	      , lcdclk / 1000.0);   }   /* And map MMIO memory, abort if we cannot */   s3vMmioMem = xf86MapVidMem(vga256InfoRec.scrnIndex, MMIO_REGION,       (pointer)(vga256InfoRec.MemBase + S3_NEWMMIO_REGBASE), S3_NEWMMIO_REGSIZE);   if(s3vMmioMem == NULL)       FatalError("S3 ViRGE: Cannot map MMIO registers!\n");      /* Determine if we need to use the STREAMS processor */   if (vgaBitsPerPixel >= 24) s3vPriv.NeedSTREAMS = TRUE;      else s3vPriv.NeedSTREAMS = FALSE;   s3vPriv.STREAMSRunning = FALSE;   pEnd = pMode = vga256InfoRec.modes;   do {      /* Setup the Mode.Private if required */      if (!pMode->PrivSize || !pMode->Private) {	 pMode->PrivSize = S3_MODEPRIV_SIZE;	 pMode->Private = (INT32 *)xcalloc(sizeof(INT32), S3_MODEPRIV_SIZE);	 pMode->Private[0] = 0;      }            /* Set default for invert_vclk */      if (!(pMode->Private[0] & (1 << S3_INVERT_VCLK))) {	 pMode->Private[S3_INVERT_VCLK] = 0;	 pMode->Private[0] |= 1 << S3_INVERT_VCLK;      }            /* Set default for blank_delay */      if (!(pMode->Private[0] & (1 << S3_BLANK_DELAY))) {	 pMode->Private[0] |= (1 << S3_BLANK_DELAY);	 if(s3vPriv.chip == S3_ViRGE_VX)	    /* these values need to be changed once CR67_1 is set	       for gamma correction (see S3V server) ! */	    if (vgaBitsPerPixel == 8)	       pMode->Private[S3_BLANK_DELAY] = 0x00;	    else if (vgaBitsPerPixel == 16)	       pMode->Private[S3_BLANK_DELAY] = 0x00;	    else	       pMode->Private[S3_BLANK_DELAY] = 0x51;	 else	    if (vgaBitsPerPixel == 8)	       pMode->Private[S3_BLANK_DELAY] = 0x00;	    else if (vgaBitsPerPixel == 16)	       pMode->Private[S3_BLANK_DELAY] = 0x02;	    else	       pMode->Private[S3_BLANK_DELAY] = 0x04;      }            /* Set default for early_sc */      if (!(pMode->Private[0] & (1 << S3_EARLY_SC))) {	 pMode->Private[0] |= 1 << S3_EARLY_SC;	 pMode->Private[S3_EARLY_SC] = 0;      }      pMode = pMode->next;   } while (pMode != pEnd);   /* And finally set various possible option flags */   vga256InfoRec.bankedMono = FALSE;#ifdef XFreeXDGA   vga256InfoRec.directMode = XF86DGADirectPresent;#endif   OFLG_SET(CLOCK_OPTION_PROGRAMABLE, &vga256InfoRec.clockOptions);   OFLG_SET(OPTION_SLOW_EDODRAM, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_FAST_DRAM, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_SLOW_DRAM, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_FPM_VRAM, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_PCI_BURST_ON, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_FIFO_CONSERV, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_FIFO_MODERATE, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_FIFO_AGGRESSIVE, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_PCI_RETRY, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_NOACCEL, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_SW_CURSOR, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_HW_CURSOR, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_EARLY_RAS_PRECHARGE, &S3V.ChipOptionFlags);   OFLG_SET(OPTION_LATE_RAS_PRECHARGE, &S3V.ChipOptionFlags);   if (S3_ViRGE_MX_SERIES(s3vPriv.chip))     OFLG_SET(OPTION_LCD_CENTER, &S3V.ChipOptionFlags);   s3vPriv.NoPCIRetry = 1;   S3V.ChipLinearBase = vga256InfoRec.MemBase;   S3V.ChipLinearSize = vga256InfoRec.videoRam * 1024;   return TRUE;   }