1
2/**************************************************************************
3
4Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
5All Rights Reserved.
6
7Permission is hereby granted, free of charge, to any person obtaining a
8copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sub license, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice (including the
16next paragraph) shall be included in all copies or substantial portions
17of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
23ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27**************************************************************************/
28
29/*
30 * Authors:
31 *   Daryll Strauss <daryll@precisioninsight.com>
32 *
33 */
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include <string.h>
40#include <math.h>
41#include <unistd.h>
42
43/*
44 * This server does not support these XFree86 4.0 features yet
45 * DDC1 & DDC2 (requires I2C)
46 * shadowFb (if requested or acceleration is off)
47 * Overlay planes
48 * DGA
49 */
50
51/*
52 * These are X and server generic header files.
53 */
54#include "xf86.h"
55#include "xf86_OSproc.h"
56#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
57#include "xf86Resources.h"
58#include "xf86RAC.h"
59#endif
60#include "xf86cmap.h"
61
62/* If the driver uses port I/O directly, it needs: */
63
64#include "compiler.h"
65
66/* All drivers using the vgahw module need this */
67/* This driver needs to be modified to not use vgaHW for multihead operation */
68#include "vgaHW.h"
69
70/* Drivers using the mi SW cursor need: */
71
72#include "mipointer.h"
73
74/* Drivers using the mi colourmap code need: */
75
76#include "micmap.h"
77
78#include "fb.h"
79
80/* The driver's own header file: */
81
82
83#include "regionstr.h"
84
85#include "xf86xv.h"
86#include <X11/extensions/Xv.h>
87
88#include "vbe.h"
89#include "i740_dga.h"
90#include "i740.h"
91
92
93/* Required Functions: */
94static const OptionInfoRec * I740AvailableOptions(int chipid, int busid);
95
96/* Print a driver identifying message. */
97static void I740Identify(int flags);
98
99/* Identify if there is any hardware present that I know how to drive. */
100static Bool I740Probe(DriverPtr drv, int flags);
101
102/* Process the config file and see if we have a valid configuration */
103static Bool I740PreInit(ScrnInfoPtr pScrn, int flags);
104
105/* Initialize a screen */
106static Bool I740ScreenInit(SCREEN_INIT_ARGS_DECL);
107
108/* Enter from a virtual terminal */
109static Bool I740EnterVT(VT_FUNC_ARGS_DECL);
110
111/* Leave to a virtual terminal */
112static void I740LeaveVT(VT_FUNC_ARGS_DECL);
113
114/* Close down each screen we initialized */
115static Bool I740CloseScreen(CLOSE_SCREEN_ARGS_DECL);
116
117/* Change screensaver state */
118static Bool I740SaveScreen(ScreenPtr pScreen, int mode);
119
120/* Cleanup server private data */
121static void I740FreeScreen(FREE_SCREEN_ARGS_DECL);
122
123/* Check if a mode is valid on the hardware */
124static ModeStatus I740ValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode,
125				Bool verbose, int flags);
126
127/* Switch to various Display Power Management System levels */
128static void I740DisplayPowerManagementSet(ScrnInfoPtr pScrn,
129					int PowerManagermentMode, int flags);
130
131static void I740ProbeDDC(ScrnInfoPtr pScrn, int index);
132
133static Bool I740MapMem(ScrnInfoPtr pScrn);
134static Bool I740UnmapMem(ScrnInfoPtr pScrn);
135
136#define I740_VERSION 4000
137#define I740_NAME "I740"
138#define I740_DRIVER_NAME "i740"
139#define I740_MAJOR_VERSION PACKAGE_VERSION_MAJOR
140#define I740_MINOR_VERSION PACKAGE_VERSION_MINOR
141#define I740_PATCHLEVEL PACKAGE_VERSION_PATCHLEVEL
142
143_X_EXPORT DriverRec I740 = {
144  I740_VERSION,
145  I740_DRIVER_NAME,
146  I740Identify,
147  I740Probe,
148  I740AvailableOptions,
149  NULL,
150  0
151};
152
153/* Chipsets */
154static SymTabRec I740Chipsets[] = {
155  { PCI_CHIP_I740_AGP, "i740 (agp)"},
156  { PCI_CHIP_I740_PCI, "i740 (pci)"},
157  { -1, NULL }
158};
159
160static PciChipsets I740PciChipsets[] = {
161  { PCI_CHIP_I740_AGP, PCI_CHIP_I740_AGP, RES_SHARED_VGA },
162  { PCI_CHIP_I740_PCI, PCI_CHIP_I740_PCI, RES_SHARED_VGA },
163  { -1, -1, RES_UNDEFINED }
164};
165
166typedef enum {
167  OPTION_NOACCEL,
168  OPTION_SW_CURSOR,
169  OPTION_SDRAM,
170  OPTION_SGRAM,
171  OPTION_SLOW_RAM,
172  OPTION_DAC_6BIT,
173  OPTION_USE_PIO,
174  OPTION_VGACOMPAT
175} I740Opts;
176
177static const OptionInfoRec I740Options[] = {
178  { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE },
179  { OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE },
180  { OPTION_SDRAM, "SDRAM", OPTV_BOOLEAN, {0}, FALSE},
181  { OPTION_SGRAM, "SGRAM", OPTV_BOOLEAN, {0}, FALSE},
182  { OPTION_SLOW_RAM, "SlowRam", OPTV_BOOLEAN, {0}, FALSE},
183  { OPTION_DAC_6BIT, "Dac6Bit", OPTV_BOOLEAN, {0}, FALSE},
184  { OPTION_USE_PIO, "UsePIO", OPTV_BOOLEAN, {0}, FALSE},
185  { OPTION_VGACOMPAT, "VGACompat", OPTV_BOOLEAN, {0}, FALSE},
186  { -1, NULL, OPTV_NONE, {0}, FALSE}
187};
188
189#ifdef XFree86LOADER
190
191static MODULESETUPPROTO(i740Setup);
192
193static XF86ModuleVersionInfo i740VersRec =
194{
195  "i740",
196  MODULEVENDORSTRING,
197  MODINFOSTRING1,
198  MODINFOSTRING2,
199  XORG_VERSION_CURRENT,
200  I740_MAJOR_VERSION, I740_MINOR_VERSION, I740_PATCHLEVEL,
201  ABI_CLASS_VIDEODRV,
202  ABI_VIDEODRV_VERSION,
203  MOD_CLASS_VIDEODRV,
204  {0,0,0,0}
205};
206
207_X_EXPORT XF86ModuleData i740ModuleData = {&i740VersRec, i740Setup, 0};
208
209static pointer
210i740Setup(pointer module, pointer opts, int *errmaj, int *errmin)
211{
212    static Bool setupDone = FALSE;
213
214    /* This module should be loaded only once, but check to be sure. */
215
216    if (!setupDone) {
217	setupDone = TRUE;
218	xf86AddDriver(&I740, module, 0);
219
220	/*
221	 * Modules that this driver always requires may be loaded here
222	 * by calling LoadSubModule().
223	 */
224
225	/*
226	 * The return value must be non-NULL on success even though there
227	 * is no TearDownProc.
228	 */
229	return (pointer)1;
230    } else {
231	if (errmaj) *errmaj = LDR_ONCEONLY;
232	return NULL;
233    }
234}
235
236#endif
237
238/*
239 * I740GetRec and I740FreeRec --
240 *
241 * Private data for the driver is stored in the screen structure.
242 * These two functions create and destroy that private data.
243 *
244 */
245static Bool
246I740GetRec(ScrnInfoPtr pScrn) {
247  if (pScrn->driverPrivate) return TRUE;
248
249  pScrn->driverPrivate = xnfcalloc(sizeof(I740Rec), 1);
250  return TRUE;
251}
252
253static void
254I740FreeRec(ScrnInfoPtr pScrn) {
255  if (!pScrn) return;
256  free(pScrn->driverPrivate);
257  pScrn->driverPrivate=0;
258}
259
260static const OptionInfoRec *
261I740AvailableOptions(int chipid, int busid)
262{
263    return I740Options;
264}
265
266/*
267 * I740Identify --
268 *
269 * Returns the string name for the driver based on the chipset. In this
270 * case it will always be an I740, so we can return a static string.
271 *
272 */
273static void
274I740Identify(int flags) {
275  xf86PrintChipsets(I740_NAME, "Driver for Intel i740 chipset", I740Chipsets);
276}
277
278/*
279 * I740Probe --
280 *
281 * Look through the PCI bus to find cards that are I740 boards.
282 * Setup the dispatch table for the rest of the driver functions.
283 *
284 */
285static Bool
286I740Probe(DriverPtr drv, int flags) {
287  int i, numUsed, numDevSections, *usedChips;
288  GDevPtr *devSections;
289  Bool foundScreen = FALSE;
290
291  /*
292   Find the config file Device sections that match this
293   driver, and return if there are none.
294   */
295  if ((numDevSections = xf86MatchDevice(I740_DRIVER_NAME, &devSections))<=0) {
296    return FALSE;
297  }
298
299#ifndef XSERVER_LIBPCIACCESS
300  /*
301     Since these Probing is just checking the PCI data the server already
302     collected.
303  */
304  if (!xf86GetPciVideoInfo()) return FALSE;
305#endif
306
307  /* Look for Intel based chips */
308  numUsed = xf86MatchPciInstances(I740_NAME, PCI_VENDOR_INTEL,
309				  I740Chipsets, I740PciChipsets,
310				  devSections, numDevSections,
311				  drv, &usedChips);
312
313  if (numUsed > 0) {
314      if (flags & PROBE_DETECT)
315	  foundScreen = TRUE;
316      else for (i=0; i<numUsed; i++) {
317	  ScrnInfoPtr pScrn = NULL;
318	  /* Allocate new ScrnInfoRec and claim the slot */
319	  if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
320						 I740PciChipsets, 0, 0, 0, 0, 0))) {
321	      pScrn->driverVersion = I740_VERSION;
322	      pScrn->driverName = I740_DRIVER_NAME;
323	      pScrn->name = I740_NAME;
324	      pScrn->Probe = I740Probe;
325	      pScrn->PreInit = I740PreInit;
326	      pScrn->ScreenInit = I740ScreenInit;
327	      pScrn->SwitchMode = I740SwitchMode;
328	      pScrn->AdjustFrame = I740AdjustFrame;
329	      pScrn->EnterVT = I740EnterVT;
330	      pScrn->LeaveVT = I740LeaveVT;
331	      pScrn->FreeScreen = I740FreeScreen;
332	      pScrn->ValidMode = I740ValidMode;
333	      foundScreen = TRUE;
334
335	  }
336      }
337  }
338
339
340  /* Look for Real3D based chips */
341  numUsed = xf86MatchPciInstances(I740_NAME, PCI_VENDOR_REAL3D,
342				  I740Chipsets, I740PciChipsets,
343				  devSections, numDevSections,
344				  drv, &usedChips);
345
346  if (numUsed > 0) {
347      if (flags & PROBE_DETECT)
348	  foundScreen = TRUE;
349      else for (i=0; i<numUsed; i++) {
350	  ScrnInfoPtr pScrn = NULL;
351	  if ((pScrn  = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
352						  I740PciChipsets, 0, 0, 0, 0, 0))) {
353	      pScrn->driverVersion = I740_VERSION;
354	      pScrn->driverName = I740_DRIVER_NAME;
355	      pScrn->name = I740_NAME;
356	      pScrn->Probe = I740Probe;
357	      pScrn->PreInit = I740PreInit;
358	      pScrn->ScreenInit = I740ScreenInit;
359	      pScrn->SwitchMode = I740SwitchMode;
360	      pScrn->AdjustFrame = I740AdjustFrame;
361	      pScrn->EnterVT = I740EnterVT;
362	      pScrn->LeaveVT = I740LeaveVT;
363	      pScrn->FreeScreen = I740FreeScreen;
364	      pScrn->ValidMode = I740ValidMode;
365	      foundScreen = TRUE;
366	  }
367      }
368  }
369
370  free(devSections);
371  free(usedChips);
372
373  return foundScreen;
374}
375
376/* Ugh.  Can we not do this? */
377static void
378I740ProbeDDC(ScrnInfoPtr pScrn, int index)
379{
380    vbeInfoPtr pVbe;
381    if (xf86LoadSubModule(pScrn, "vbe")) {
382	pVbe = VBEInit(NULL,index);
383	ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
384	vbeFree(pVbe);
385    }
386}
387
388/*
389 * I740PreInit --
390 *
391 * Do initial setup of the board before we know what resolution we will
392 * be running at.
393 *
394 */
395static Bool
396I740PreInit(ScrnInfoPtr pScrn, int flags) {
397  I740Ptr pI740;
398  ClockRangePtr clockRanges;
399  int i;
400  MessageType from;
401  int temp;
402  int flags24;
403  rgb defaultWeight = {0, 0, 0};
404
405  if (pScrn->numEntities != 1) return FALSE;
406
407  /* Allocate driverPrivate */
408  if (!I740GetRec(pScrn)) {
409    return FALSE;
410  }
411
412  pI740 = I740PTR(pScrn);
413
414  pI740->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
415  if (pI740->pEnt->location.type != BUS_PCI) return FALSE;
416
417  /*I740ProbeDDC(pScrn, pI740->pEnt->index);*/
418  if (flags & PROBE_DETECT) {
419	I740ProbeDDC(pScrn, pI740->pEnt->index);
420	return TRUE;
421  }
422
423  /* The vgahw module should be loaded here when needed */
424  if (!xf86LoadSubModule(pScrn, "vgahw")) return FALSE;
425
426  /* Allocate a vgaHWRec */
427  if (!vgaHWGetHWRec(pScrn)) return FALSE;
428  vgaHWSetStdFuncs(VGAHWPTR(pScrn));
429
430  pI740->PciInfo = xf86GetPciInfoForEntity(pI740->pEnt->index);
431#ifndef XSERVER_LIBPCIACCESS
432  pI740->PciTag = pciTag(pI740->PciInfo->bus, pI740->PciInfo->device,
433			 pI740->PciInfo->func);
434
435  if (xf86RegisterResources(pI740->pEnt->index, 0, ResNone))
436      return FALSE;
437  if (pI740->usePIO)
438    pScrn->racIoFlags = RAC_FB | RAC_COLORMAP;
439  else
440    pScrn->racMemFlags = RAC_FB | RAC_COLORMAP;
441#endif
442  /* Set pScrn->monitor */
443  pScrn->monitor = pScrn->confScreen->monitor;
444
445
446  flags24=Support24bppFb | Support32bppFb | SupportConvert32to24;
447  if (!xf86SetDepthBpp(pScrn, 0, 0, 0, flags24)) {
448    return FALSE;
449  } else {
450    switch (pScrn->depth) {
451    case 8:
452    case 15:
453    case 16:
454    case 24:
455      break;
456    default:
457      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
458		 "Given depth (%d) is not supported by i740 driver\n",
459		 pScrn->depth);
460      return FALSE;
461    }
462  }
463  /*xf86PrintDepthBpp(pScrn);*/
464
465  if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
466    return FALSE;
467
468  if (!xf86SetDefaultVisual(pScrn, -1)) {
469    return FALSE;
470  } else {
471    /* We don't currently support DirectColor at > 8bpp */
472    if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
473      xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual"
474		 " (%s) is not supported at depth %d\n",
475		 xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
476      return FALSE;
477    }
478  }
479
480  /* We use a programamble clock */
481  pScrn->progClock = TRUE;
482
483  pI740->cpp = pScrn->bitsPerPixel/8;
484
485  /* Process the options */
486  xf86CollectOptions(pScrn, NULL);
487  if (!(pI740->Options = malloc(sizeof(I740Options))))
488    return FALSE;
489  memcpy(pI740->Options, I740Options, sizeof(I740Options));
490  xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pI740->Options);
491
492  /* 6-BIT dac isn't reasonable for modes with > 8bpp */
493  if (xf86ReturnOptValBool(pI740->Options, OPTION_DAC_6BIT, FALSE) &&
494      pScrn->bitsPerPixel>8) {
495    OptionInfoPtr ptr;
496    ptr=xf86TokenToOptinfo(pI740->Options, OPTION_DAC_6BIT);
497    ptr->found=FALSE;
498  }
499
500  if (xf86ReturnOptValBool(pI740->Options, OPTION_DAC_6BIT, FALSE))
501    pScrn->rgbBits=8;
502  else
503    pScrn->rgbBits=6;
504
505  /* We have to use PIO to probe, because we haven't mappend yet */
506  I740SetPIOAccess(pI740);
507
508  /*
509   * Set the Chipset and ChipRev, allowing config file entries to
510   * override.
511   */
512  if (pI740->pEnt->device->chipset && *pI740->pEnt->device->chipset) {
513    pScrn->chipset = pI740->pEnt->device->chipset;
514    from = X_CONFIG;
515  } else if (pI740->pEnt->device->chipID >= 0) {
516    pScrn->chipset = (char *)xf86TokenToString(I740Chipsets, pI740->pEnt->device->chipID);
517    from = X_CONFIG;
518    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
519	       pI740->pEnt->device->chipID);
520  } else {
521    from = X_PROBED;
522    pScrn->chipset = (char *)xf86TokenToString(I740Chipsets, PCI_DEV_DEVICE_ID(pI740->PciInfo));
523  }
524  if (pI740->pEnt->device->chipRev >= 0) {
525    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
526	       pI740->pEnt->device->chipRev);
527  }
528
529  xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", (pScrn->chipset!=NULL)?pScrn->chipset:"Unknown i740");
530
531  if (pI740->pEnt->device->MemBase != 0) {
532    pI740->LinearAddr = pI740->pEnt->device->MemBase;
533    from = X_CONFIG;
534  } else {
535    if (PCI_REGION_BASE(pI740->PciInfo, 0, REGION_MEM) != 0) {
536      pI740->LinearAddr = PCI_REGION_BASE(pI740->PciInfo, 0, REGION_MEM)&0xFF000000;
537      from = X_PROBED;
538    } else {
539      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
540		 "No valid FB address in PCI config space\n");
541      I740FreeRec(pScrn);
542      return FALSE;
543    }
544  }
545  xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
546	     pI740->LinearAddr);
547
548  if (pI740->pEnt->device->IOBase != 0) {
549    pI740->MMIOAddr = pI740->pEnt->device->IOBase;
550    from = X_CONFIG;
551  } else {
552    if (PCI_REGION_BASE(pI740->PciInfo, 1, REGION_MEM)) {
553      pI740->MMIOAddr = PCI_REGION_BASE(pI740->PciInfo, 1, REGION_MEM)&0xFFF80000;
554      from = X_PROBED;
555    } else {
556      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
557		 "No valid MMIO address in PCI config space\n");
558      I740FreeRec(pScrn);
559      return FALSE;
560    }
561  }
562  xf86DrvMsg(pScrn->scrnIndex, from, "IO registers at addr 0x%lX\n",
563	     pI740->MMIOAddr);
564
565  /* Calculate memory */
566  if (pI740->pEnt->device->videoRam) {
567    pScrn->videoRam = pI740->pEnt->device->videoRam;
568    from = X_CONFIG;
569  } else {
570    if ((pI740->readControl(pI740, XRX, DRAM_ROW_TYPE)&DRAM_ROW_1)==DRAM_ROW_1_SDRAM)
571      pScrn->videoRam=pI740->readControl(pI740, XRX, DRAM_ROW_BNDRY_1);
572    else
573      pScrn->videoRam=pI740->readControl(pI740, XRX, DRAM_ROW_BNDRY_0);
574    pScrn->videoRam = (pScrn->videoRam&0x0F)*1024;
575    from = X_PROBED;
576  }
577
578  temp=pI740->readControl(pI740, XRX, DRAM_ROW_CNTL_LO);
579  pI740->HasSGRAM = !((temp&DRAM_RAS_TIMING)||(temp&DRAM_RAS_PRECHARGE));
580  if (xf86IsOptionSet(pI740->Options, OPTION_SDRAM)) {
581    if (xf86IsOptionSet(pI740->Options, OPTION_SGRAM)) {
582      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
583		 "It is nonsensical to set both SDRAM and SGRAM options\n");
584      return FALSE;
585    }
586    if (xf86ReturnOptValBool(pI740->Options, OPTION_SDRAM, FALSE)) {
587      pI740->HasSGRAM = FALSE;
588    } else {
589      pI740->HasSGRAM = TRUE;
590    }
591  } else {
592    if (xf86IsOptionSet(pI740->Options, OPTION_SDRAM)) {
593      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
594		 "It is nonsensical to set both SDRAM and SGRAM options\n");
595      return FALSE;
596    }
597    if (xf86ReturnOptValBool(pI740->Options, OPTION_SGRAM, FALSE)) {
598      pI740->HasSGRAM = TRUE;
599    } else {
600      pI740->HasSGRAM = FALSE;
601    }
602  }
603
604  xf86DrvMsg(pScrn->scrnIndex, from, "Steve was here! VideoRAM: %d kByte %s\n",
605	     pScrn->videoRam, (pI740->HasSGRAM)?"SGRAM":"SDRAM");
606  pI740->FbMapSize = pScrn->videoRam*1024;
607
608  /*
609   * If the driver can do gamma correction, it should call xf86SetGamma()
610   * here.
611   */
612
613  {
614    Gamma zeros = {0.0, 0.0, 0.0};
615
616    if (!xf86SetGamma(pScrn, zeros)) {
617      return FALSE;
618    }
619  }
620
621  pI740->MaxClock = 0;
622  if (pI740->pEnt->device->dacSpeeds[0]) {
623    switch (pScrn->bitsPerPixel) {
624    case 8:
625      pI740->MaxClock = pI740->pEnt->device->dacSpeeds[DAC_BPP8];
626      break;
627    case 16:
628      pI740->MaxClock = pI740->pEnt->device->dacSpeeds[DAC_BPP16];
629      break;
630    case 24:
631      pI740->MaxClock = pI740->pEnt->device->dacSpeeds[DAC_BPP24];
632      break;
633    case 32:
634      pI740->MaxClock = pI740->pEnt->device->dacSpeeds[DAC_BPP32];
635      break;
636    }
637    if (!pI740->MaxClock)
638      pI740->MaxClock = pI740->pEnt->device->dacSpeeds[0];
639    from = X_CONFIG;
640  } else {
641    switch (pScrn->bitsPerPixel) {
642    case 8:
643      pI740->MaxClock = 203000;
644      break;
645    case 16:
646      pI740->MaxClock = 163000;
647      break;
648    case 24:
649      if (pI740->HasSGRAM)
650	pI740->MaxClock = 136000;
651      else
652	pI740->MaxClock = 128000;
653      break;
654    case 32:
655      pI740->MaxClock = 86000;
656    }
657  }
658  clockRanges = xnfcalloc(sizeof(ClockRange), 1);
659  clockRanges->next=NULL;
660  clockRanges->minClock= 12000; /* !!! What's the min clock? !!! */
661  clockRanges->maxClock=pI740->MaxClock;
662  clockRanges->clockIndex = -1;
663  clockRanges->interlaceAllowed = FALSE; /*PL*/
664  clockRanges->doubleScanAllowed = TRUE; /*PL*/
665
666  { /*PL*/
667
668   if (xf86LoadSubModule(pScrn, "ddc")) {
669     if (xf86LoadSubModule(pScrn, "i2c") ) {
670       if (I740MapMem(pScrn)) {
671	   if (I740_I2CInit(pScrn))
672	     {
673	       xf86MonPtr MonInfo;
674	       if ((MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn),pI740->rc_i2c))) {
675		 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DDC Monitor info: %p\n",
676			    MonInfo);
677		 xf86PrintEDID( MonInfo );
678		 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "end of DDC Monitor "
679			    "info\n\n");
680		 xf86SetDDCproperties(pScrn,MonInfo);
681	       }
682	     }
683	   else
684	     xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"I2C initialization failed\n");
685
686	   I740UnmapMem(pScrn);
687	 }
688     }
689   }
690  }
691
692  i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
693			pScrn->display->modes, clockRanges,
694			0, 320, 1600,
695			8, 200, 1200,
696			pScrn->display->virtualX, pScrn->display->virtualY,
697			pI740->FbMapSize, LOOKUP_BEST_REFRESH);
698
699  if (i==-1) {
700    I740FreeRec(pScrn);
701    return FALSE;
702  }
703
704  xf86PruneDriverModes(pScrn);
705
706  if (!i || !pScrn->modes) {
707    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
708    I740FreeRec(pScrn);
709    return FALSE;
710  }
711
712  xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
713
714  pScrn->currentMode = pScrn->modes;
715
716  xf86PrintModes(pScrn);
717
718  xf86SetDpi(pScrn, 0, 0);
719
720  if (!xf86LoadSubModule(pScrn, "fb")) {
721    I740FreeRec(pScrn);
722    return FALSE;
723  }
724
725  pI740->NoAccel = xf86ReturnOptValBool(pI740->Options, OPTION_NOACCEL, FALSE);
726  if (!pI740->NoAccel) {
727    if (!xf86LoadSubModule(pScrn, "xaa")) {
728      xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No acceleration available\n");
729      pI740->NoAccel = 1;
730    }
731  }
732
733  if (!xf86ReturnOptValBool(pI740->Options, OPTION_SW_CURSOR, FALSE)) {
734    if (!xf86LoadSubModule(pScrn, "ramdac")) {
735      I740FreeRec(pScrn);
736      return FALSE;
737    }
738  }
739
740  /*  We wont be using the VGA access after the probe */
741  if (!xf86ReturnOptValBool(pI740->Options, OPTION_USE_PIO, FALSE)) {
742#ifndef XSERVER_LIBPCIACCESS
743    resRange vgaio[] = { {ResShrIoBlock,0x3B0,0x3BB},
744			 {ResShrIoBlock,0x3C0,0x3DF},
745			 _END };
746    resRange vgamem[] = {{ResShrMemBlock,0xA0000,0xAFFFF},
747			 {ResShrMemBlock,0xB8000,0xBFFFF},
748			 {ResShrMemBlock,0xB0000,0xB7FFF},
749			 _END };
750#endif
751    pI740->usePIO=FALSE;
752    I740SetMMIOAccess(pI740);
753#ifndef XSERVER_LIBPCIACCESS
754    xf86SetOperatingState(vgaio, pI740->pEnt->index, ResUnusedOpr);
755    xf86SetOperatingState(vgamem, pI740->pEnt->index, ResDisableOpr);
756#endif
757  } else {
758    pI740->usePIO=TRUE;
759  }
760
761  if(xf86IsOptionSet(pI740->Options, OPTION_VGACOMPAT))
762    pI740->usevgacompat=TRUE;
763  else
764    pI740->usevgacompat=FALSE;
765
766
767
768  { /* Overlay */
769    pI740->colorKey = (1 << pScrn->offset.red) | (1 << pScrn->offset.green) |
770      (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue);
771
772    pI740->colorKey &= ((1 << pScrn->depth) - 1);
773
774    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video overlay key set to 0x%x\n", pI740->colorKey);
775  }
776
777
778  return TRUE;
779}
780
781static Bool I740MapMem(ScrnInfoPtr pScrn)
782{
783#ifndef XSERVER_LIBPCIACCESS
784  int mmioFlags;
785#endif
786  I740Ptr pI740;
787
788  pI740 = I740PTR(pScrn);
789
790#ifndef XSERVER_LIBPCIACCESS
791  mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT;
792
793  pI740->MMIOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
794				      pI740->PciTag,
795				      pI740->MMIOAddr,
796				      0x80000);
797#else
798  {
799    void** result = (void**)&pI740->MMIOBase;
800    int err = pci_device_map_range(pI740->PciInfo,
801				   pI740->MMIOAddr,
802				   0x80000,
803				   PCI_DEV_MAP_FLAG_WRITABLE,
804				   result);
805
806    if (err)
807      return FALSE;
808  }
809
810#endif
811  if (!pI740->MMIOBase) return FALSE;
812
813#ifndef XSERVER_LIBPCIACCESS
814  pI740->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
815				pI740->PciTag,
816				pI740->LinearAddr,
817				pI740->FbMapSize);
818#else
819  {
820    void** result = (void**)&pI740->FbBase;
821    int err = pci_device_map_range(pI740->PciInfo,
822				   pI740->LinearAddr,
823				   pI740->FbMapSize,
824				   PCI_DEV_MAP_FLAG_WRITABLE |
825				   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
826				   result);
827
828    if (err)
829      return FALSE;
830  }
831#endif
832  if (!pI740->FbBase) return FALSE;
833
834  return TRUE;
835}
836
837static Bool I740UnmapMem(ScrnInfoPtr pScrn)
838{
839  I740Ptr pI740;
840
841  pI740 = I740PTR(pScrn);
842
843#ifndef XSERVER_LIBPCIACCESS
844  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pI740->MMIOBase, 0x80000);
845#else
846  pci_device_unmap_range(pI740->PciInfo, pI740->MMIOBase, 0x80000);
847#endif
848  pI740->MMIOBase=0;
849
850#ifndef XSERVER_LIBPCIACCESS
851  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pI740->FbBase, pI740->FbMapSize);
852#else
853  pci_device_unmap_range(pI740->PciInfo, pI740->FbBase, pI740->FbMapSize);
854#endif
855  pI740->FbBase = 0;
856  return TRUE;
857}
858
859/*
860 * I740Save --
861 *
862 * This function saves the video state.  It reads all of the SVGA registers
863 * into the vgaI740Rec data structure.  There is in general no need to
864 * mask out bits here - just read the registers.
865 */
866static void
867DoSave(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, I740RegPtr i740Reg, Bool saveFonts)
868{
869  I740Ptr pI740;
870  vgaHWPtr hwp;
871
872  pI740 = I740PTR(pScrn);
873  hwp = VGAHWPTR(pScrn);
874
875  /*
876   * This function will handle creating the data structure and filling
877   * in the generic VGA portion.
878   */
879  if (saveFonts)
880    vgaHWSave(pScrn, vgaReg, VGA_SR_MODE|VGA_SR_FONTS);
881  else
882    vgaHWSave(pScrn, vgaReg, VGA_SR_MODE);
883
884  /*
885   * The port I/O code necessary to read in the extended registers
886   * into the fields of the vgaI740Rec structure goes here.
887   */
888
889  i740Reg->IOControl = pI740->readControl(pI740, XRX, IO_CTNL);
890  i740Reg->AddressMapping = pI740->readControl(pI740, XRX, ADDRESS_MAPPING);
891  i740Reg->BitBLTControl = pI740->readControl(pI740, XRX, BITBLT_CNTL);
892  i740Reg->VideoClk2_M = pI740->readControl(pI740, XRX, VCLK2_VCO_M);
893  i740Reg->VideoClk2_N = pI740->readControl(pI740, XRX, VCLK2_VCO_N);
894  i740Reg->VideoClk2_MN_MSBs = pI740->readControl(pI740, XRX, VCLK2_VCO_MN_MSBS);
895  i740Reg->VideoClk2_DivisorSel = pI740->readControl(pI740, XRX, VCLK2_VCO_DIV_SEL);
896  i740Reg->PLLControl = pI740->readControl(pI740, XRX, PLL_CNTL);
897
898  i740Reg->ExtVertTotal=hwp->readCrtc(hwp, EXT_VERT_TOTAL);
899  i740Reg->ExtVertDispEnd=hwp->readCrtc(hwp, EXT_VERT_DISPLAY);
900  i740Reg->ExtVertSyncStart=hwp->readCrtc(hwp, EXT_VERT_SYNC_START);
901  i740Reg->ExtVertBlankStart=hwp->readCrtc(hwp, EXT_VERT_BLANK_START);
902  i740Reg->ExtHorizTotal=hwp->readCrtc(hwp, EXT_HORIZ_TOTAL);
903  i740Reg->ExtHorizBlank=hwp->readCrtc(hwp, EXT_HORIZ_BLANK);
904  i740Reg->ExtOffset=hwp->readCrtc(hwp, EXT_OFFSET);
905  i740Reg->InterlaceControl=hwp->readCrtc(hwp, INTERLACE_CNTL);
906
907  i740Reg->PixelPipeCfg0 = pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0);
908  i740Reg->PixelPipeCfg1 = pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_1);
909  i740Reg->PixelPipeCfg2 = pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_2);
910  i740Reg->DisplayControl = pI740->readControl(pI740, XRX, DISPLAY_CNTL);
911
912  i740Reg->LMI_FIFO_Watermark = INREG(FWATER_BLC);
913}
914
915static void
916I740Save(ScrnInfoPtr pScrn)
917{
918  vgaHWPtr hwp;
919  I740Ptr pI740;
920
921  hwp = VGAHWPTR(pScrn);
922  pI740 = I740PTR(pScrn);
923  DoSave(pScrn, &hwp->SavedReg, &pI740->SavedReg, TRUE);
924}
925
926static void
927DoRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, I740RegPtr i740Reg,
928	  Bool restoreFonts) {
929  I740Ptr pI740;
930  vgaHWPtr hwp;
931  unsigned char temp;
932  unsigned int  itemp;
933
934  pI740 = I740PTR(pScrn);
935  hwp = VGAHWPTR(pScrn);
936
937  vgaHWProtect(pScrn, TRUE);
938#if 0
939  temp=hwp->readCrtc(hwp, VERT_SYNC_END);
940  hwp->writeCrtc(hwp, VERT_SYNC_END, temp&0x7F);
941#endif
942
943  temp = pI740->readControl(pI740, MRX, ACQ_CNTL_2);
944  if ((temp & FRAME_CAP_MODE) == SINGLE_CAP_MODE) {
945    temp=pI740->readControl(pI740, MRX, COL_KEY_CNTL_1);
946    temp |= BLANK_DISP_OVERLAY; /* Disable the overlay */
947    pI740->writeControl(pI740, MRX, COL_KEY_CNTL_1, temp);
948  } else {
949    temp &= ~FRAME_CAP_MODE;
950    pI740->writeControl(pI740, MRX, ACQ_CNTL_2, temp);
951  }
952  usleep(50000);
953
954  /* Turn off DRAM Refresh */
955  pI740->writeControl(pI740, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_DISABLE);
956
957  usleep(1000); /* Wait 1 ms */
958
959  /* Write the M, N and P values */
960  pI740->writeControl(pI740, XRX, VCLK2_VCO_M, i740Reg->VideoClk2_M);
961  pI740->writeControl(pI740, XRX, VCLK2_VCO_N, i740Reg->VideoClk2_N);
962  pI740->writeControl(pI740, XRX, VCLK2_VCO_MN_MSBS, i740Reg->VideoClk2_MN_MSBs);
963  pI740->writeControl(pI740, XRX, VCLK2_VCO_DIV_SEL, i740Reg->VideoClk2_DivisorSel);
964
965  /*
966   * Turn on 8 bit dac mode, if requested.  This is needed to make
967   * sure that vgaHWRestore writes the values into the DAC properly.
968   * The problem occurs if 8 bit dac mode is requested and the HW is
969   * in 6 bit dac mode.  If this happens, all the values are
970   * automatically shifted left twice by the HW and incorrect colors
971   * will be displayed on the screen.  The only time this can happen
972   * is at server startup time and when switching back from a VT.
973   */
974  temp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0);
975  temp &= 0x7F; /* Save all but the 8 bit dac mode bit */
976  temp |= (i740Reg->PixelPipeCfg0 & DAC_8_BIT);
977  pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_0, temp);
978
979  /*
980   * Code to restore any SVGA registers that have been saved/modified
981   * goes here.  Note that it is allowable, and often correct, to
982   * only modify certain bits in a register by a read/modify/write cycle.
983   *
984   * A special case - when using an external clock-setting program,
985   * this function must not change bits associated with the clock
986   * selection.  This condition can be checked by the condition:
987   *
988   *	if (restore->std.NoClock >= 0)
989   *		restore clock-select bits.
990   */
991  if (restoreFonts)
992    vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS|VGA_SR_MODE);
993  else
994    vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE);
995
996  hwp->writeCrtc(hwp, EXT_VERT_TOTAL, i740Reg->ExtVertTotal);
997  hwp->writeCrtc(hwp, EXT_VERT_DISPLAY, i740Reg->ExtVertDispEnd);
998  hwp->writeCrtc(hwp, EXT_VERT_SYNC_START, i740Reg->ExtVertSyncStart);
999  hwp->writeCrtc(hwp, EXT_VERT_BLANK_START, i740Reg->ExtVertBlankStart);
1000  hwp->writeCrtc(hwp, EXT_HORIZ_TOTAL, i740Reg->ExtHorizTotal);
1001  hwp->writeCrtc(hwp, EXT_HORIZ_BLANK, i740Reg->ExtHorizBlank);
1002  hwp->writeCrtc(hwp, EXT_OFFSET, i740Reg->ExtOffset);
1003
1004  temp=hwp->readCrtc(hwp, INTERLACE_CNTL);
1005  temp &= ~INTERLACE_ENABLE;
1006  temp |= i740Reg->InterlaceControl;
1007  hwp->writeCrtc(hwp, INTERLACE_CNTL, temp);
1008
1009  temp=pI740->readControl(pI740, XRX, ADDRESS_MAPPING);
1010  temp &= 0xE0; /* Save reserved bits 7:5 */
1011  temp |= i740Reg->AddressMapping;
1012  pI740->writeControl(pI740, XRX, ADDRESS_MAPPING, temp);
1013
1014  temp=pI740->readControl(pI740, XRX, BITBLT_CNTL);
1015  temp &= ~COLEXP_MODE;
1016  temp |= i740Reg->BitBLTControl;
1017  pI740->writeControl(pI740, XRX, BITBLT_CNTL, temp);
1018
1019  temp=pI740->readControl(pI740, XRX, DISPLAY_CNTL);
1020  temp &= ~(VGA_WRAP_MODE | GUI_MODE);
1021  temp |= i740Reg->DisplayControl;
1022  pI740->writeControl(pI740, XRX, DISPLAY_CNTL, temp);
1023
1024  temp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0);
1025  temp &= 0x64; /* Save reserved bits 6:5,2 */
1026  temp |= i740Reg->PixelPipeCfg0;
1027  pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_0, temp);
1028
1029  temp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_2);
1030  temp &= 0xF3; /* Save reserved bits 7:4,1:0 */
1031  temp |= i740Reg->PixelPipeCfg2;
1032  pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_2, temp);
1033
1034  temp=pI740->readControl(pI740, XRX, PLL_CNTL);
1035  temp = i740Reg->PLLControl; /* To fix the 2.3X BIOS problem */
1036  pI740->writeControl(pI740, XRX, PLL_CNTL, temp);
1037
1038  temp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_1);
1039  temp &= ~DISPLAY_COLOR_MODE;
1040  temp |= i740Reg->PixelPipeCfg1;
1041  pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_1, temp);
1042
1043  itemp = INREG(FWATER_BLC);
1044  itemp &= ~(LMI_BURST_LENGTH | LMI_FIFO_WATERMARK);
1045  itemp |= i740Reg->LMI_FIFO_Watermark;
1046  OUTREG(FWATER_BLC, itemp);
1047
1048  /* Turn on DRAM Refresh */
1049  pI740->writeControl(pI740, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_60HZ);
1050
1051  temp=pI740->readControl(pI740, MRX, COL_KEY_CNTL_1);
1052  temp &= ~BLANK_DISP_OVERLAY; /* Re-enable the overlay */
1053  pI740->writeControl(pI740, MRX, COL_KEY_CNTL_1, temp);
1054
1055  if (!(vgaReg->Attribute[0x10] & 0x1)) {
1056    usleep(50000);
1057    if (restoreFonts)
1058      vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS|VGA_SR_MODE);
1059    else
1060      vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE);
1061  }
1062
1063  vgaHWProtect(pScrn, FALSE);
1064  temp=pI740->readControl(pI740, XRX, IO_CTNL);
1065  temp &= ~(EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL);
1066  temp |= i740Reg->IOControl;
1067  pI740->writeControl(pI740, XRX, IO_CTNL, temp);
1068#if 0
1069  temp=hwp->readCrtc(hwp, VERT_SYNC_END);
1070  hwp->writeCrtc(hwp, VERT_SYNC_END, temp|0x80);
1071#endif
1072}
1073
1074static void
1075I740Restore(ScrnInfoPtr pScrn) {
1076  vgaHWPtr hwp;
1077  I740Ptr pI740;
1078
1079  hwp = VGAHWPTR(pScrn);
1080  pI740 = I740PTR(pScrn);
1081
1082  DoRestore(pScrn, &hwp->SavedReg, &pI740->SavedReg, TRUE);
1083}
1084
1085/*
1086 * I740CalcFIFO --
1087 *
1088 * Calculate burst length and FIFO watermark.
1089 */
1090
1091static unsigned int
1092I740CalcFIFO(ScrnInfoPtr pScrn, double freq)
1093{
1094  unsigned int wm = 0x18120000;
1095  I740Ptr pI740;
1096
1097  pI740 = I740PTR(pScrn);
1098
1099  /*
1100   * Would like to calculate these values automatically, but a generic
1101   * algorithm does not seem possible.  Note: These FIFO water mark
1102   * values were tested on several cards and seem to eliminate the
1103   * all of the snow and vertical banding, but fine adjustments will
1104   * probably be required for other cards.
1105   */
1106
1107  switch (pScrn->bitsPerPixel) {
1108  case 8:
1109    if (pI740->HasSGRAM) {
1110      if      (freq > 200) wm = 0x18120000;
1111      else if (freq > 175) wm = 0x16110000;
1112      else if (freq > 135) wm = 0x120E0000;
1113      else                 wm = 0x100D0000;
1114    } else {
1115      if      (freq > 200) wm = 0x18120000;
1116      else if (freq > 175) wm = 0x16110000;
1117      else if (freq > 135) wm = 0x120E0000;
1118      else                 wm = 0x100D0000;
1119    }
1120    break;
1121  case 16:
1122    if (pI740->HasSGRAM) {
1123      if      (freq > 140) wm = 0x2C1D0000;
1124      else if (freq > 120) wm = 0x2C180000;
1125      else if (freq > 100) wm = 0x24160000;
1126      else if (freq >  90) wm = 0x18120000;
1127      else if (freq >  50) wm = 0x16110000;
1128      else if (freq >  32) wm = 0x13100000;
1129      else                 wm = 0x120E0000;
1130    } else {
1131      if      (freq > 160) wm = 0x28200000;
1132      else if (freq > 140) wm = 0x2A1E0000;
1133      else if (freq > 130) wm = 0x2B1A0000;
1134      else if (freq > 120) wm = 0x2C180000;
1135      else if (freq > 100) wm = 0x24180000;
1136      else if (freq >  90) wm = 0x18120000;
1137      else if (freq >  50) wm = 0x16110000;
1138      else if (freq >  32) wm = 0x13100000;
1139      else                 wm = 0x120E0000;
1140    }
1141    break;
1142  case 24:
1143    if (pI740->HasSGRAM) {
1144      if      (freq > 130) wm = 0x31200000;
1145      else if (freq > 120) wm = 0x2E200000;
1146      else if (freq > 100) wm = 0x2C1D0000;
1147      else if (freq >  80) wm = 0x25180000;
1148      else if (freq >  64) wm = 0x24160000;
1149      else if (freq >  49) wm = 0x18120000;
1150      else if (freq >  32) wm = 0x16110000;
1151      else                 wm = 0x13100000;
1152    } else {
1153      if      (freq > 120) wm = 0x311F0000;
1154      else if (freq > 100) wm = 0x2C1D0000;
1155      else if (freq >  80) wm = 0x25180000;
1156      else if (freq >  64) wm = 0x24160000;
1157      else if (freq >  49) wm = 0x18120000;
1158      else if (freq >  32) wm = 0x16110000;
1159      else                 wm = 0x13100000;
1160    }
1161    break;
1162  case 32:
1163    if (pI740->HasSGRAM) {
1164      if      (freq >  80) wm = 0x2A200000;
1165      else if (freq >  60) wm = 0x281A0000;
1166      else if (freq >  49) wm = 0x25180000;
1167      else if (freq >  32) wm = 0x18120000;
1168      else                 wm = 0x16110000;
1169    } else {
1170      if      (freq >  80) wm = 0x29200000;
1171      else if (freq >  60) wm = 0x281A0000;
1172      else if (freq >  49) wm = 0x25180000;
1173      else if (freq >  32) wm = 0x18120000;
1174      else                 wm = 0x16110000;
1175    }
1176    break;
1177  }
1178
1179  return wm;
1180}
1181
1182/*
1183 * I740CalcVCLK --
1184 *
1185 * Determine the closest clock frequency to the one requested.
1186 */
1187
1188#define MAX_VCO_FREQ 450.0
1189#define TARGET_MAX_N 30
1190#define REF_FREQ 66.66666666667
1191
1192#define CALC_VCLK(m,n,p,d) \
1193    (double)m / ((double)n * (1 << p)) * (4 << (d << 1)) * REF_FREQ
1194
1195static void
1196I740CalcVCLK(ScrnInfoPtr pScrn, double freq)
1197{
1198  I740Ptr pI740;
1199  I740RegPtr i740Reg;
1200  int m, n, p, d;
1201  double f_out;
1202  double f_err;
1203  double f_vco;
1204  int m_best = 0, n_best = 0, p_best = 0, d_best = 0;
1205  double f_target = freq;
1206  double err_max = 0.005;
1207  double err_target = 0.001;
1208  double err_best = 999999.0;
1209
1210  pI740 = I740PTR(pScrn);
1211  i740Reg = &pI740->ModeReg;
1212
1213  p_best = p = log(MAX_VCO_FREQ/f_target)/log((double)2);
1214  d_best = d = 0;
1215
1216  f_vco = f_target * (1 << p);
1217
1218  n = 2;
1219  do {
1220    n++;
1221    m = f_vco / (REF_FREQ / (double)n) / (double)4.0 + 0.5;
1222    if (m < 3) m = 3;
1223    f_out = CALC_VCLK(m,n,p,d);
1224    f_err = 1.0 - (f_target/f_out);
1225    if (fabs(f_err) < err_max) {
1226      m_best = m;
1227      n_best = n;
1228      err_best = f_err;
1229    }
1230  } while ((fabs(f_err) >= err_target) &&
1231	   ((n <= TARGET_MAX_N) || (fabs(err_best) > err_max)));
1232
1233  if (fabs(f_err) < err_target) {
1234    m_best = m;
1235    n_best = n;
1236  }
1237
1238  i740Reg->VideoClk2_M          = (m_best-2) & 0xFF;
1239  i740Reg->VideoClk2_N          = (n_best-2) & 0xFF;
1240  i740Reg->VideoClk2_MN_MSBs    = ((((n_best-2) >> 4) & VCO_N_MSBS) |
1241				   (((m_best-2) >> 8) & VCO_M_MSBS));
1242  i740Reg->VideoClk2_DivisorSel = ((p_best << 4) |
1243				   (d_best ? 4 : 0) |
1244				   REF_DIV_1);
1245}
1246
1247static Bool
1248I740SetMode(ScrnInfoPtr pScrn, DisplayModePtr mode) {
1249  I740Ptr pI740;
1250  I740RegPtr i740Reg;
1251  vgaRegPtr pVga;
1252  double dclk = mode->Clock/1000.0;
1253
1254  pI740 = I740PTR(pScrn);
1255  i740Reg = &pI740->ModeReg;
1256  pVga = &VGAHWPTR(pScrn)->ModeReg;
1257
1258  switch (pScrn->bitsPerPixel) {
1259  case 8:
1260    pVga->CRTC[0x13] = pScrn->displayWidth >> 3;
1261    i740Reg->ExtOffset      = pScrn->displayWidth >> 11;
1262    i740Reg->PixelPipeCfg1 = DISPLAY_8BPP_MODE;
1263    i740Reg->BitBLTControl = COLEXP_8BPP;
1264    break;
1265  case 16:
1266    if (pScrn->weight.green == 5) {
1267      i740Reg->PixelPipeCfg1 = DISPLAY_15BPP_MODE;
1268    } else {
1269      i740Reg->PixelPipeCfg1 = DISPLAY_16BPP_MODE;
1270    }
1271    pVga->CRTC[0x13] = pScrn->displayWidth >> 2;
1272    i740Reg->ExtOffset      = pScrn->displayWidth >> 10;
1273    i740Reg->BitBLTControl = COLEXP_16BPP;
1274    break;
1275  case 24:
1276    pVga->CRTC[0x13] = (pScrn->displayWidth * 3) >> 3;
1277    i740Reg->ExtOffset      = (pScrn->displayWidth * 3) >> 11;
1278    i740Reg->PixelPipeCfg1 = DISPLAY_24BPP_MODE;
1279    i740Reg->BitBLTControl = COLEXP_24BPP;
1280    break;
1281  case 32:
1282    pVga->CRTC[0x13] = pScrn->displayWidth >> 1;
1283    i740Reg->ExtOffset      = pScrn->displayWidth >> 9;
1284    i740Reg->PixelPipeCfg1 = DISPLAY_32BPP_MODE;
1285    i740Reg->BitBLTControl = COLEXP_RESERVED; /* Not implemented on i740 */
1286    break;
1287  default:
1288    break;
1289  }
1290
1291  /* Turn on 8 bit dac if requested */
1292  if (xf86ReturnOptValBool(pI740->Options, OPTION_DAC_6BIT, FALSE))
1293    i740Reg->PixelPipeCfg0 = DAC_6_BIT;
1294  else
1295    i740Reg->PixelPipeCfg0 = DAC_8_BIT;
1296
1297  i740Reg->PixelPipeCfg2 = DISPLAY_GAMMA_ENABLE /*| OVERLAY_GAMMA_ENABLE*/;
1298
1299  /* Turn on Extended VGA Interpretation */
1300  i740Reg->IOControl = EXTENDED_CRTC_CNTL;
1301
1302  /* Turn on linear and page mapping */
1303  i740Reg->AddressMapping = LINEAR_MODE_ENABLE | PAGE_MAPPING_ENABLE;
1304
1305  /* Turn on GUI mode */
1306  i740Reg->DisplayControl = HIRES_MODE;
1307
1308  /* Set the MCLK freq */
1309  if (xf86ReturnOptValBool(pI740->Options, OPTION_SLOW_RAM, FALSE))
1310    i740Reg->PLLControl = PLL_MEMCLK__66667KHZ; /*  66 MHz */
1311  else
1312    i740Reg->PLLControl = PLL_MEMCLK_100000KHZ; /* 100 MHz -- use as default */
1313
1314  /* Calculate the extended CRTC regs */
1315  i740Reg->ExtVertTotal = (mode->CrtcVTotal - 2) >> 8;
1316  i740Reg->ExtVertDispEnd = (mode->CrtcVDisplay - 1) >> 8;
1317  i740Reg->ExtVertSyncStart = mode->CrtcVSyncStart >> 8;
1318  i740Reg->ExtVertBlankStart = mode->CrtcVBlankStart >> 8;
1319  i740Reg->ExtHorizTotal = ((mode->CrtcHTotal >> 3) - 5) >> 8;
1320  /*
1321   * the KGA fix in vgaHW.c results in the first
1322   * scanline and the first character clock (8 pixels)
1323   * of each scanline thereafter on display with an i740
1324   * to be blank. Restoring CRTC 3, 5, & 22 to their
1325   * "theoretical" values corrects the problem. KAO.
1326   */
1327  i740Reg->ExtHorizBlank = vgaHWHBlankKGA(mode, pVga, 7, 0) << 6;
1328  vgaHWVBlankKGA(mode, pVga, 8, 0);
1329
1330  /* Turn on interlaced mode if necessary */
1331  if (mode->Flags & V_INTERLACE)
1332    i740Reg->InterlaceControl = INTERLACE_ENABLE;
1333  else
1334    i740Reg->InterlaceControl = INTERLACE_DISABLE;
1335
1336  /*
1337   * Set the overscan color to 0.
1338   * NOTE: This only affects >8bpp mode.
1339   */
1340  pVga->Attribute[0x11] = 0;
1341
1342  /*
1343   * Calculate the VCLK that most closely matches the requested dot
1344   * clock.
1345   */
1346  I740CalcVCLK(pScrn, dclk);
1347
1348  /* Since we program the clocks ourselves, always use VCLK2. */
1349  pVga->MiscOutReg |= 0x0C;
1350
1351  /* Calculate the FIFO Watermark and Burst Length. */
1352  i740Reg->LMI_FIFO_Watermark = I740CalcFIFO(pScrn, dclk);
1353
1354  /*-Overlay-*/
1355  pI740->ov_offset_x=((mode->CrtcHTotal-mode->CrtcHDisplay) & ~7)-9;
1356  pI740->ov_offset_y=mode->CrtcVTotal-mode->CrtcVSyncEnd-2;
1357  /*-*/
1358
1359  return TRUE;
1360}
1361
1362static Bool
1363I740ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode_src)
1364{
1365  vgaHWPtr hwp;
1366  I740Ptr pI740;
1367  struct _DisplayModeRec mode_dst;
1368  DisplayModePtr mode=&mode_dst;
1369
1370  *mode=*mode_src;
1371
1372  hwp = VGAHWPTR(pScrn);
1373  pI740 = I740PTR(pScrn);
1374
1375  vgaHWUnlock(hwp);
1376
1377
1378  if(pI740->usevgacompat)
1379    { /* Try to get the same visual aspect as a S3 board */
1380      mode->CrtcHSyncStart+=16;
1381      mode->CrtcHSyncEnd  +=16;
1382    }
1383
1384  if (!vgaHWInit(pScrn, mode)) return FALSE;
1385
1386  pScrn->vtSema = TRUE;
1387
1388  if (!I740SetMode(pScrn, mode)) return FALSE;
1389
1390  DoRestore(pScrn, &hwp->ModeReg, &pI740->ModeReg, FALSE);
1391
1392  return TRUE;
1393}
1394
1395static void I740LoadPalette15(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual)
1396{
1397  vgaHWPtr hwp;
1398  int i, index;
1399  unsigned char r, g, b;
1400
1401  hwp = VGAHWPTR(pScrn);
1402
1403  for (i=0; i<numColors; i++)
1404    {
1405      index=indices[i/2];
1406      r=colors[index].red;
1407      b=colors[index].blue;
1408      g=colors[index].green;
1409
1410      hwp->writeDacWriteAddr(hwp, index<<2);
1411      hwp->writeDacData(hwp, r);
1412      hwp->writeDacData(hwp, g);
1413      hwp->writeDacData(hwp, b);
1414
1415      i++;
1416      hwp->writeDacWriteAddr(hwp, index<<2);
1417      hwp->writeDacData(hwp, r);
1418      hwp->writeDacData(hwp, g);
1419      hwp->writeDacData(hwp, b);
1420    }
1421}
1422
1423static void I740LoadPalette16(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual)
1424{
1425  vgaHWPtr hwp;
1426  int i, index;
1427  unsigned char r, g, b;
1428
1429  hwp = VGAHWPTR(pScrn);
1430  for (i=0; i<numColors; i++) {
1431    index=indices[i/2];
1432    r=colors[index].red;
1433    b=colors[index].blue;
1434    index=indices[i];
1435    g=colors[index].green;
1436    hwp->writeDacWriteAddr(hwp, index<<2);
1437    hwp->writeDacData(hwp, r);
1438    hwp->writeDacData(hwp, g);
1439    hwp->writeDacData(hwp, b);
1440    i++;
1441    index=indices[i];
1442    g=colors[index].green;
1443    hwp->writeDacWriteAddr(hwp, index<<2);
1444    hwp->writeDacData(hwp, r);
1445    hwp->writeDacData(hwp, g);
1446    hwp->writeDacData(hwp, b);
1447  }
1448}
1449
1450static void
1451I740LoadPalette24(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
1452		  VisualPtr pVisual) {
1453  vgaHWPtr hwp;
1454  int i, index;
1455  unsigned char r, g, b;
1456
1457  hwp = VGAHWPTR(pScrn);
1458  for (i=0; i<numColors; i++) {
1459    index=indices[i];
1460    r=colors[index].red;
1461    b=colors[index].blue;
1462    index=indices[i];
1463    g=colors[index].green;
1464    hwp->writeDacWriteAddr(hwp, index);
1465    hwp->writeDacData(hwp, r);
1466    hwp->writeDacData(hwp, g);
1467    hwp->writeDacData(hwp, b);
1468  }
1469}
1470
1471static Bool
1472I740ScreenInit(SCREEN_INIT_ARGS_DECL) {
1473  ScrnInfoPtr pScrn;
1474  vgaHWPtr hwp;
1475  I740Ptr pI740;
1476  VisualPtr visual;
1477
1478  pScrn = xf86ScreenToScrn(pScreen);
1479  pI740 = I740PTR(pScrn);
1480  hwp = VGAHWPTR(pScrn);
1481
1482  if (!I740MapMem(pScrn)) return FALSE;
1483  pScrn->memPhysBase = pI740->LinearAddr;
1484  pScrn->fbOffset = 0;
1485
1486  if (!pI740->usePIO)
1487    vgaHWSetMmioFuncs(hwp, pI740->MMIOBase, 0);
1488  vgaHWGetIOBase(hwp);
1489  if (!vgaHWMapMem(pScrn)) return FALSE;
1490
1491  I740Save(pScrn);
1492  if (!I740ModeInit(pScrn, pScrn->currentMode)) return FALSE;
1493
1494  I740SaveScreen(pScreen, SCREEN_SAVER_ON);
1495  I740AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
1496
1497  miClearVisualTypes();
1498
1499  if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
1500			pScrn->rgbBits, pScrn->defaultVisual))
1501    return FALSE;
1502	if (!miSetPixmapDepths ()) return FALSE;
1503
1504  switch (pScrn->bitsPerPixel) {
1505  case 8:
1506  case 16:
1507  case 24:
1508  case 32:
1509    if (!fbScreenInit(pScreen, pI740->FbBase,
1510		       pScrn->virtualX, pScrn->virtualY,
1511		       pScrn->xDpi, pScrn->yDpi,
1512		       pScrn->displayWidth,pScrn->bitsPerPixel))
1513      return FALSE;
1514    break;
1515  default:
1516    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1517	       "Internal error: invalid bpp (%d) in I740ScrnInit\n",
1518	       pScrn->bitsPerPixel);
1519    return FALSE;
1520  }
1521  fbPictureInit(pScreen,0,0);
1522
1523  xf86SetBlackWhitePixels(pScreen);
1524
1525  memset(&(pI740->FbMemBox), 0, sizeof(BoxRec));
1526  pI740->FbMemBox.x1=0;
1527  pI740->FbMemBox.x2=pScrn->displayWidth;
1528  pI740->FbMemBox.y1=0;
1529  pI740->FbMemBox.y2=pI740->FbMapSize/(pScrn->displayWidth*pI740->cpp);
1530
1531  I740DGAInit(pScreen);
1532
1533  if (!xf86InitFBManager(pScreen, &pI740->FbMemBox)) {
1534    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to init memory manager\n");
1535    return FALSE;
1536  }
1537
1538  if (!pI740->NoAccel) {
1539    if (!I740AccelInit(pScreen)) {
1540      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1541		 "Hardware acceleration initialization failed\n");
1542    }
1543  }
1544
1545  if (pScrn->bitsPerPixel>8) {
1546    visual = pScreen->visuals + pScreen->numVisuals;
1547    while (--visual >= pScreen->visuals) {
1548      if ((visual->class | DynamicClass) == DirectColor) {
1549	visual->offsetRed = pScrn->offset.red;
1550	visual->offsetGreen = pScrn->offset.green;
1551	visual->offsetBlue = pScrn->offset.blue;
1552	visual->redMask = pScrn->mask.red;
1553	visual->greenMask = pScrn->mask.green;
1554	visual->blueMask = pScrn->mask.blue;
1555      }
1556    }
1557  }
1558
1559  xf86SetBackingStore(pScreen);
1560  xf86SetSilkenMouse(pScreen);
1561
1562  miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1563
1564  if (!xf86ReturnOptValBool(pI740->Options, OPTION_SW_CURSOR, FALSE)) {
1565    if (!I740CursorInit(pScreen)) {
1566      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1567		 "Hardware cursor initialization failed\n");
1568    }
1569  }
1570
1571  if (!miCreateDefColormap(pScreen)) return FALSE;
1572
1573  if (pScrn->bitsPerPixel==16)
1574    {
1575      if (pScrn->weight.green == 5)
1576	{
1577	  if (!xf86HandleColormaps(pScreen, 256, 8, I740LoadPalette15, 0, CMAP_PALETTED_TRUECOLOR|CMAP_RELOAD_ON_MODE_SWITCH))
1578	    return FALSE;
1579	}
1580      else
1581	{
1582	  if (!xf86HandleColormaps(pScreen, 256, 8, I740LoadPalette16, 0, CMAP_PALETTED_TRUECOLOR|CMAP_RELOAD_ON_MODE_SWITCH))
1583	    return FALSE;
1584	}
1585    }
1586  else
1587    {
1588      if (!xf86HandleColormaps(pScreen, 256, 8, I740LoadPalette24, 0, CMAP_PALETTED_TRUECOLOR|CMAP_RELOAD_ON_MODE_SWITCH))
1589	return FALSE;
1590    }
1591
1592  xf86DPMSInit(pScreen, I740DisplayPowerManagementSet, 0);
1593
1594  pScreen->SaveScreen = I740SaveScreen;
1595  pI740->CloseScreen = pScreen->CloseScreen;
1596  pScreen->CloseScreen = I740CloseScreen;
1597
1598  if (serverGeneration == 1)
1599    xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1600
1601  /* Overlay */
1602  I740InitVideo(pScreen); pI740->OverlayStart = pI740->CursorStart + 1024;
1603
1604  return TRUE;
1605}
1606
1607Bool
1608I740SwitchMode(SWITCH_MODE_ARGS_DECL) {
1609  SCRN_INFO_PTR(arg);
1610  return I740ModeInit(pScrn, mode);
1611}
1612
1613void
1614I740AdjustFrame(ADJUST_FRAME_ARGS_DECL) {
1615  SCRN_INFO_PTR(arg);
1616  int Base;
1617  vgaHWPtr hwp;
1618
1619  hwp = VGAHWPTR(pScrn);
1620
1621  Base = (y * pScrn->displayWidth + x) >> 2;
1622  switch (pScrn->bitsPerPixel) {
1623  case  8:
1624    break;
1625  case 16:
1626    Base *= 2;
1627    break;
1628  case 24:
1629    /*
1630     * The last bit does not seem to have any effect on the start
1631     * address register in 24bpp mode, so...
1632     */
1633    Base &= 0xFFFFFFFE; /* ...ignore the last bit. */
1634    Base *= 3;
1635    break;
1636  case 32:
1637    Base *= 4;
1638    break;
1639  }
1640
1641  hwp->writeCrtc(hwp, START_ADDR_LO, Base&0xFF);
1642  hwp->writeCrtc(hwp, START_ADDR_HI, (Base&0xFF00)>>8);
1643  hwp->writeCrtc(hwp, EXT_START_ADDR_HI, (Base&0x3FC00000)>>22);
1644  hwp->writeCrtc(hwp, EXT_START_ADDR,
1645		 ((Base&0x00eF0000)>>16|EXT_START_ADDR_ENABLE));
1646}
1647
1648static Bool
1649I740EnterVT(VT_FUNC_ARGS_DECL) {
1650  SCRN_INFO_PTR(arg);
1651
1652  if (!I740ModeInit(pScrn, pScrn->currentMode)) return FALSE;
1653  I740AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
1654  return TRUE;
1655}
1656
1657static void
1658I740LeaveVT(VT_FUNC_ARGS_DECL) {
1659  SCRN_INFO_PTR(arg);
1660  vgaHWPtr hwp;
1661
1662  hwp=VGAHWPTR(pScrn);
1663  I740Restore(pScrn);
1664  vgaHWLock(hwp);
1665}
1666
1667static Bool
1668I740CloseScreen(CLOSE_SCREEN_ARGS_DECL)
1669{
1670  ScrnInfoPtr pScrn;
1671  vgaHWPtr hwp;
1672  I740Ptr pI740;
1673
1674  pScrn = xf86ScreenToScrn(pScreen);
1675  hwp = VGAHWPTR(pScrn);
1676  pI740 = I740PTR(pScrn);
1677
1678  if (pScrn->vtSema) {
1679      I740Restore(pScrn);
1680      vgaHWLock(hwp);
1681  }
1682
1683  I740UnmapMem(pScrn);
1684  vgaHWUnmapMem(pScrn);
1685#ifdef HAVE_XAA_H
1686  if (pI740->AccelInfoRec)
1687    XAADestroyInfoRec(pI740->AccelInfoRec);
1688  pI740->AccelInfoRec=0;
1689#endif
1690  if (pI740->CursorInfoRec)
1691    xf86DestroyCursorInfoRec(pI740->CursorInfoRec);
1692  pI740->CursorInfoRec=0;
1693  pScrn->vtSema=FALSE;
1694
1695  pScreen->CloseScreen = pI740->CloseScreen;
1696  return (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
1697}
1698
1699static void
1700I740FreeScreen(FREE_SCREEN_ARGS_DECL) {
1701  SCRN_INFO_PTR(arg);
1702  I740FreeRec(pScrn);
1703  if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
1704    vgaHWFreeHWRec(pScrn);
1705}
1706
1707static ModeStatus
1708I740ValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags) {
1709  SCRN_INFO_PTR(arg);
1710  if (mode->Flags & V_INTERLACE) {
1711    if (verbose) {
1712      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1713		 "Removing interlaced mode \"%s\"\n",
1714		 mode->name);
1715    }
1716    return MODE_BAD;
1717  }
1718  return MODE_OK;
1719}
1720
1721static Bool
1722I740SaveScreen(ScreenPtr pScreen, int mode)
1723{
1724#if 0
1725  Bool unblack = xf86IsUnblank(mode);
1726  if (unblack) outw(SRX, 0x0300);
1727  else outw(SRX, 0x0100);
1728#endif
1729  return vgaHWSaveScreen(pScreen, mode);
1730}
1731
1732static void
1733I740DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
1734			      int flags) {
1735  I740Ptr pI740;
1736  unsigned char SEQ01=0;
1737  int DPMSSyncSelect=0;
1738
1739  pI740 = I740PTR(pScrn);
1740  switch (PowerManagementMode) {
1741  case DPMSModeOn:
1742    /* Screen: On; HSync: On, VSync: On */
1743    SEQ01 = 0x00;
1744    DPMSSyncSelect = HSYNC_ON | VSYNC_ON;
1745    break;
1746  case DPMSModeStandby:
1747    /* Screen: Off; HSync: Off, VSync: On */
1748    SEQ01 = 0x20;
1749    DPMSSyncSelect = HSYNC_OFF | VSYNC_ON;
1750    break;
1751  case DPMSModeSuspend:
1752    /* Screen: Off; HSync: On, VSync: Off */
1753    SEQ01 = 0x20;
1754    DPMSSyncSelect = HSYNC_ON | VSYNC_OFF;
1755    break;
1756  case DPMSModeOff:
1757    /* Screen: Off; HSync: Off, VSync: Off */
1758    SEQ01 = 0x20;
1759    DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF;
1760    break;
1761  }
1762
1763  /* Turn the screen on/off */
1764  SEQ01 |= pI740->readControl(pI740, SRX, 0x01) & ~0x20;
1765  pI740->writeControl(pI740, SRX, 0x01, SEQ01);
1766
1767  /* Set the DPMS mode */
1768  pI740->writeControl(pI740, XRX, DPMS_SYNC_SELECT, DPMSSyncSelect);
1769}
1770