home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / server / ddx / x386 / x386Config.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-20  |  20.1 KB  |  829 lines

  1. /*
  2.  * $XConsortium: x386Config.c,v 1.2 91/08/20 15:08:26 gildea Exp $
  3.  *
  4.  * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of Thomas Roell not be used in
  11.  * advertising or publicity pertaining to distribution of the software without
  12.  * specific, written prior permission.  Thomas Roell makes no representations
  13.  * about the suitability of this software for any purpose.  It is provided
  14.  * "as is" without express or implied warranty.
  15.  *
  16.  * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  17.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  18.  * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  19.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  20.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  21.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  22.  * PERFORMANCE OF THIS SOFTWARE.
  23.  */
  24.  
  25. #include "X.h"
  26. #include "Xmd.h"
  27. #include "input.h"
  28. #include "servermd.h"
  29. #include "scrnintstr.h"
  30.  
  31. #include "compiler.h"
  32.  
  33. #include "x386OSD.h"
  34. #include "x386Procs.h"
  35.  
  36. #ifndef X_NOT_POSIX
  37. #ifdef _POSIX_SOURCE
  38. #include <limits.h>
  39. #else
  40. #define _POSIX_SOURCE
  41. #include <limits.h>
  42. #undef _POSIX_SOURCE
  43. #endif
  44. #endif
  45. #ifndef PATH_MAX
  46. #include <sys/param.h>
  47. #ifdef MAXPATHLEN
  48. #define PATH_MAX MAXPATHLEN
  49. #else
  50. #define PATH_MAX 1024
  51. #endif
  52. #endif
  53.  
  54. #ifndef SERVER_CONFIG_FILE
  55. #define SERVER_CONFIG_FILE "/usr/X386/Xconfig"
  56. #endif
  57.  
  58. typedef struct {
  59.   int           token;                /* id of the token */
  60.   char          *name;                /* pointer to the LOWERCASED name */
  61. } SymTabRec, *SymTabPtr;
  62.  
  63. typedef union {
  64.   int           num;                  /* returned number */
  65.   char          *str;                 /* private copy of the return-string */
  66. } LexRec, *LexPtr;
  67.  
  68. #define LOCK_TOKEN  -3
  69. #define ERROR_TOKEN -2
  70. #define NUMBER      10000                  
  71. #define STRING      10001
  72.  
  73.  
  74. #define FONTPATH   0
  75. #define RGBPATH    1
  76. #define SHAREDMON  2
  77.  
  78. #define KEYBOARD   10
  79.  
  80. #define MICROSOFT  20
  81. #define MOUSESYS   21
  82. #define MMSERIES   22
  83. #define LOGITECH   23
  84. #define BUSMOUSE   24
  85. #define XQUE       25
  86.  
  87. #define VGA256     30
  88. #define VGA16      31
  89. #define WGA        32
  90. #define XGA        33
  91.  
  92. #define MODEDB     40
  93.  
  94. static SymTabRec SymTab[] = {
  95.   { FONTPATH,   "fontpath" },
  96.   { RGBPATH,    "rgbpath" },
  97.   { SHAREDMON,  "sharedmonitor" },
  98.  
  99.   { KEYBOARD,   "keyboard" },
  100.  
  101.   { MICROSOFT,  "microsoft" },
  102.   { MOUSESYS,   "mousesystems" },
  103.   { MMSERIES,   "mmseries" },
  104.   { LOGITECH,   "logitech" }, /* that's eveybodys favourite !!! */
  105.   { MICROSOFT,  "mouseman" },
  106.   { BUSMOUSE,   "busmouse" },
  107.   { XQUE,       "xqueue" },
  108.  
  109.   { VGA256,     "vga256" },
  110.  
  111. #ifdef notyet
  112.   { VGA16,      "vga16" },
  113.   { WGA,        "wga" },
  114.   { XGA,        "xga" },
  115. #endif
  116.  
  117.   { MODEDB,     "modedb" },
  118.  
  119.   { -1,         "" },
  120. };
  121.  
  122. #define AUTOREPEAT 0
  123. #define DONTZAP    1
  124. #define SERVERNUM  2
  125. #define XLEDS      3
  126.  
  127. static SymTabRec KeyboardTab[] = {
  128.   { AUTOREPEAT, "autorepeat" },
  129.   { DONTZAP,    "dontzap" },
  130.   { SERVERNUM,  "servernumlock" },
  131.   { XLEDS,      "xleds" },
  132.   { -1,         "" },
  133. };
  134.  
  135.  
  136. #define EMULATE3   0
  137. #define BAUDRATE   1
  138. #define SAMPLERATE 2
  139.  
  140. static SymTabRec MouseTab[] = {
  141.   { BAUDRATE,   "baudrate" },
  142.   { EMULATE3,   "emulate3buttons" },
  143.   { SAMPLERATE, "samplerate" },
  144.   { -1,         "" },
  145. };
  146.  
  147.  
  148. #define STATICGRAY  0
  149. #define GRAYSCALE   1
  150. #define STATICCOLOR 2
  151. #define PSEUDOCOLOR 3
  152. #define TRUECOLOR   4
  153. #define DIRECTCOLOR 5
  154.  
  155. #define CHIPSET     10
  156. #define CLOCKS      11
  157. #define DISPLAYSIZE 12
  158. #define MODES       13
  159. #define SCREENNO    14
  160. #define VENDOR      15
  161. #define VIDEORAM    16
  162. #define VIEWPORT    17
  163. #define VIRTUAL     18
  164.  
  165. static SymTabRec GraphicsTab[] = {
  166.   { STATICGRAY, "staticgray" },
  167.   { GRAYSCALE,  "grayscale" },
  168.   { STATICCOLOR,"staticcolor" },
  169.   { PSEUDOCOLOR,"pseudocolor" },
  170.   { TRUECOLOR,  "truecolor" },
  171.   { DIRECTCOLOR,"directcolor" },
  172.  
  173.   { CHIPSET,    "chipset" },
  174.   { CLOCKS,     "clocks" },
  175.   { DISPLAYSIZE,"displaysize" },
  176.   { MODES,      "modes" },
  177.   { SCREENNO,   "screenno" },
  178.   { VENDOR,     "vendor" },
  179.   { VIDEORAM,   "videoram" },
  180.   { VIEWPORT,   "viewport" },
  181.   { VIRTUAL,    "virtual" },
  182.   { -1,         "" },
  183. };
  184.  
  185. #define INTERLACE 0
  186. #define PHSYNC    1
  187. #define NHSYNC    2
  188. #define PVSYNC    3
  189. #define NVSYNC    4
  190.  
  191. static SymTabRec TimingTab[] = {
  192.   { INTERLACE,  "interlace"},
  193.   { PHSYNC,     "+hsync"},
  194.   { NHSYNC,     "-hsync"},
  195.   { PVSYNC,     "+vsync"},
  196.   { NVSYNC,     "-vsync"},
  197.   { -1,         "" },
  198. };
  199.  
  200.  
  201. #define CONFIG_BUF_LEN     1024
  202.  
  203. static FILE * configFile   = NULL;
  204. static int    configStart  = 0;           /* start of the current token */
  205. static int    configPos    = 0;           /* current readers position */
  206. static int    configLineNo = 0;           /* linenumber */
  207. static char   *configBuf,*configRBuf;     /* buffer for lines */
  208. static char   *configPath;                /* path to config file */
  209. static int    pushToken = LOCK_TOKEN;
  210. static LexRec val;                        /* global return value */
  211.  
  212. static DisplayModePtr pModes = NULL;
  213.  
  214. static int screenno = -100;      /* some little number ... */
  215.  
  216. extern char *getenv();
  217. extern char *defaultFontPath;
  218. extern char *rgbPath;
  219.  
  220.  
  221.  
  222. /*
  223.  * getToken --
  224.  *      Read next Token form the config file. Handle the global variable
  225.  *      pushToken.
  226.  */
  227.  
  228. static int
  229. getToken(tab)
  230.      SymTabRec tab[];
  231. {
  232.   int          c, i;
  233.  
  234.   /*
  235.    * First check whether pushToken has a different value than LOCK_TOKEN.
  236.    * In this case rBuf[] contains a valid STRING/TOKEN/NUMBER. But in the other
  237.    * case the next token must be read from the input.
  238.    */
  239.   if (pushToken == EOF) return(EOF);
  240.   else if (pushToken == LOCK_TOKEN)
  241.     {
  242.       
  243.       c = configBuf[configPos];
  244.       
  245.       /*
  246.        * Get start of next Token. EOF is handled, whitespaces & comments are
  247.        * skipped. 
  248.        */
  249.       do {
  250.     if (!c)  {
  251.       if (fgets(configBuf,CONFIG_BUF_LEN-1,configFile) == NULL)
  252.         {
  253.           return( pushToken = EOF );
  254.         }
  255.       configLineNo++;
  256.       configStart = configPos = 0;
  257.     }
  258.     while (((c=configBuf[configPos++])==' ') || ( c=='\t') || ( c=='\n'));
  259.     if (c == '#') c = '\0'; 
  260.       } while (!c);
  261.       configStart = configPos;
  262.       
  263.       /*
  264.        * Numbers are returned immediately ...
  265.        */
  266.       if (isdigit(c))
  267.     {
  268.       configRBuf[0] = c; i = 1;
  269.       while (isdigit(c = configBuf[configPos++])) configRBuf[i++] = c;
  270.       configRBuf[i] = '\0';
  271.       val.num = atoi(configRBuf);
  272.       return(NUMBER);
  273.     }
  274.       
  275.       /*
  276.        * All Strings START with a \" ...
  277.        */
  278.       else if (c == '\"')
  279.     {
  280.       i = -1;
  281.       do {
  282.         configRBuf[++i] = (c = configBuf[configPos++]);
  283.       } while ((c != '\"') && (c != '\n') && (c != '\0'));
  284.       configRBuf[i] = '\0';
  285.       val.str = (char *)xalloc(strlen(configRBuf) + 1);
  286.       strcpy(val.str, configRBuf);      /* private copy ! */
  287.       return(STRING);
  288.     }
  289.       
  290.       /*
  291.        * ... and now we MUST have a valid token. Since all tokens are handled
  292.        * caseinsenitive, they are all lowercased internally. The search is
  293.        * handled later along with the pushed tokens.
  294.        */
  295.       else
  296.     {
  297.       configRBuf[0] = tolower(c); i = 0;
  298.       do {
  299.         configRBuf[++i] = tolower(c=configBuf[configPos++]);
  300.       } while ((c != ' ') && (c != '\t') && (c != '\n') && (c != '\0'));
  301.       configRBuf[i] = '\0'; i=0;
  302.     }
  303.       
  304.     }
  305.   else
  306.     {
  307.     
  308.       /*
  309.        * Here we deal with pushed tokens. Reinitialize pushToken again. If
  310.        * the pushed token was NUMBER || STRING return them again ...
  311.        */
  312.       int temp = pushToken;
  313.       pushToken = LOCK_TOKEN;
  314.     
  315.       if (temp == NUMBER || temp == STRING) return(temp);
  316.     }
  317.   
  318.   /*
  319.    * Joop, at last we have to lookup the token ...
  320.    */
  321.   if (tab)
  322.     {
  323.       i = 0;
  324.       while (tab[i].token != -1)
  325.     if (strcmp(configRBuf,tab[i].name) == 0)
  326.       return(tab[i].token);
  327.     else
  328.       i++;
  329.     }
  330.   
  331.   return(ERROR_TOKEN);       /* Error catcher */
  332. }
  333.  
  334.  
  335.  
  336. /*
  337.  * configError --
  338.  *      Print are READABLE ErrorMessage !!! All informations that are 
  339.  *      interesting are printed. Even a pointer to the erroanous place is
  340.  *      printed. Maybe my e-mails will be fewer :-)
  341.  */
  342.  
  343. static void
  344. configError(msg)
  345.      char *msg;
  346. {
  347.   int i;
  348.  
  349.   ErrorF( "\nConfig Error: %s:%d\n\n%s", configPath, configLineNo, configBuf);
  350.   for (i = 1; i < configStart; i++) ErrorF(" ");
  351.   for (i = configStart; i < configPos; i++) ErrorF("^");
  352.   ErrorF("\n%s\n", msg);
  353.   exit(-1);                 /* simple exit ... */
  354. }
  355.  
  356.  
  357. /*
  358.  * configKeyboard --
  359.  *      Configure all keyboard related parameters
  360.  */
  361.  
  362. static void
  363. configKeyboard()
  364. {
  365.   int token;
  366.  
  367.   x386Info.dontZap       = FALSE;
  368.   x386Info.serverNumLock = FALSE;
  369.   x386Info.xleds         = 0L;
  370.   x386Info.kbdDelay      = 500;
  371.   x386Info.kbdRate       = 30;
  372.  
  373.   for (;;) {
  374.     
  375.     switch (token = getToken(KeyboardTab)) {
  376.  
  377.     case AUTOREPEAT:
  378.       if (getToken(NULL) != NUMBER) configError("Autorepeat delay expected");
  379.       x386Info.kbdDelay = val.num;
  380.       if (getToken(NULL) != NUMBER) configError("Autorepeat rate expected");
  381.       x386Info.kbdRate = val.num;
  382.       break;
  383.  
  384.     case DONTZAP:
  385.       x386Info.dontZap = TRUE;
  386.       break;
  387.  
  388.     case SERVERNUM:
  389.       x386Info.serverNumLock = TRUE;
  390.       break;
  391.  
  392.     case XLEDS:
  393.       while ((token= getToken(NULL)) == NUMBER)
  394.     x386Info.xleds |= 1L << (val.num-1);
  395.       pushToken = token;
  396.       break;
  397.  
  398.     default:
  399.       pushToken = token;
  400.       return;
  401.     }
  402.   }
  403. }
  404.  
  405.  
  406. /*
  407.  * configMouse --
  408.  *      Configure all mouse related parameters
  409.  */
  410.  
  411. static void
  412. configMouse()
  413. {
  414.   int token;
  415.  
  416.   x386Info.baudRate        = 1200;
  417.   x386Info.sampleRate      = 0;
  418.   x386Info.emulate3Buttons = FALSE;
  419.  
  420.   for (;;) {
  421.  
  422.     switch (token = getToken(MouseTab)) {
  423.  
  424.     case BAUDRATE:
  425.       if (getToken(NULL) != NUMBER) configError("Baudrate expected");
  426.       x386Info.baudRate = val.num;
  427.       break;
  428.  
  429.     case SAMPLERATE:
  430.       if (getToken(NULL) != NUMBER) configError("Sample rate expected");
  431.       x386Info.sampleRate = val.num;
  432.       break;
  433.  
  434.     case EMULATE3:
  435.       x386Info.emulate3Buttons = TRUE;
  436.       break;
  437.  
  438.     default:
  439.       pushToken = token;
  440.       return;
  441.     }
  442.   }
  443. }
  444.  
  445.  
  446. /*
  447.  * configGraphics --
  448.  *      Set up all parameters for the graphics drivers. These may be changed
  449.  *      by the driver during device-probe ...
  450.  */
  451.  
  452. static void
  453. configGraphics(index)
  454.      int index;
  455. {
  456.   int token,i;
  457.   DisplayModePtr pNew, pLast;
  458.  
  459.   x386Screens[index]->configured = TRUE;
  460.   x386Screens[index]->index = screenno++;
  461.   x386Screens[index]->frameX0 = -1;
  462.   x386Screens[index]->frameY0 = -1;
  463.   x386Screens[index]->virtualX = -1;
  464.   x386Screens[index]->virtualY = -1;
  465.   x386Screens[index]->defaultVisual = -1;
  466.   x386Screens[index]->chipset = NULL;
  467.   x386Screens[index]->modes = NULL;
  468.   x386Screens[index]->vendor = NULL;
  469.   x386Screens[index]->videoRam = 0;
  470.   x386Screens[index]->width = 240;
  471.   x386Screens[index]->height = 180;
  472.  
  473.   for (;;) {
  474.  
  475.     switch (token = getToken(GraphicsTab)) {
  476.  
  477.     case STATICGRAY:
  478.     case GRAYSCALE:
  479.     case STATICCOLOR:
  480.     case PSEUDOCOLOR:
  481.     case TRUECOLOR:
  482.     case DIRECTCOLOR:
  483.       x386Screens[index]->defaultVisual = token - STATICGRAY;
  484.       break;
  485.  
  486.     case CHIPSET:
  487.       if (getToken(NULL) != STRING) configError("Chipset string expected");
  488.       x386Screens[index]->chipset = val.str;
  489.       break;
  490.  
  491.     case CLOCKS:
  492.       for (i=0; (token = getToken(NULL)) == NUMBER && i < MAXCLOCKS; i++)
  493.     x386Screens[index]->clock[i] = val.num;
  494.  
  495.       x386Screens[index]->clocks = i;
  496.       pushToken = token;
  497.       break;
  498.  
  499.     case DISPLAYSIZE:
  500.       if (getToken(NULL) != NUMBER) configError("Display Width expected");
  501.       x386Screens[index]->width = val.num;
  502.       if (getToken(NULL) != NUMBER) configError("Height expected");
  503.       x386Screens[index]->height = val.num;
  504.       break;
  505.  
  506.     case MODES:
  507.       for (pLast=NULL; (token = getToken(NULL)) == STRING; pLast = pNew)
  508.     {
  509.       pNew = (DisplayModePtr)xalloc(sizeof(DisplayModeRec));
  510.       pNew->name = val.str;
  511.  
  512.       if (pLast) 
  513.         {
  514.           pLast->next = pNew;
  515.           pNew->prev  = pLast;
  516.         }
  517.       else
  518.         x386Screens[index]->modes = pNew;
  519.     }
  520.       pNew->next = x386Screens[index]->modes;
  521.       x386Screens[index]->modes->prev = pLast;
  522.       pushToken = token;
  523.       break;
  524.  
  525.     case SCREENNO:
  526.       if (getToken(NULL) != NUMBER) configError("Screen No expected");
  527.       x386Screens[index]->index = val.num;
  528.  
  529.     case VENDOR:
  530.       if (getToken(NULL) != STRING) configError("Vendor string expected");
  531.       x386Screens[index]->vendor = val.str;
  532.       break;
  533.  
  534.     case VIDEORAM:
  535.       if (getToken(NULL) != NUMBER) configError("Video RAM size expected");
  536.       x386Screens[index]->videoRam = val.num;
  537.       break;
  538.  
  539.     case VIEWPORT:
  540.       if (getToken(NULL) != NUMBER) configError("Viewport X expected");
  541.       x386Screens[index]->frameX0 = val.num;
  542.       if (getToken(NULL) != NUMBER) configError("Viewport Y expected");
  543.       x386Screens[index]->frameY0 = val.num;
  544.       break;
  545.  
  546.     case VIRTUAL:
  547.       if (getToken(NULL) != NUMBER) configError("Virtual X expected");
  548.       x386Screens[index]->virtualX = val.num;
  549.       if (getToken(NULL) != NUMBER) configError("Virtual Y expected");
  550.       x386Screens[index]->virtualY = val.num;
  551.       break;
  552.  
  553.     default:
  554.       pushToken = token;
  555.       return;
  556.     }
  557.   }
  558. }
  559.  
  560.  
  561. /*
  562.  * x386Config --
  563.  *    Fill some internal structure with userdefined setups. Many internal
  564.  *      Structs are initialized. The drivers are selected and initialized.
  565.  */
  566.  
  567. void
  568. x386Config ()
  569. {
  570.   char           *home;
  571.   int            index = 0;
  572.   int            token;
  573.   int            i,j;
  574.   DisplayModePtr pNew, pLast;
  575.  
  576.   configBuf  = (char*)xalloc(CONFIG_BUF_LEN);
  577.   configRBuf = (char*)xalloc(CONFIG_BUF_LEN);
  578.   configPath = (char*)xalloc(PATH_MAX);
  579.   
  580.   configBuf[0] = '\0';                    /* sanity ... */
  581.   
  582.   /*
  583.    * First open if necessary the config file. Note, that every user may have
  584.    * a private Xconfig file in his home.
  585.    */
  586.   while (!configFile) {
  587.     
  588.     /*
  589.      * ~/Xconfig ...
  590.      */
  591.     if (home = getenv("HOME")) {
  592.       strcpy(configPath,home);
  593.       strcat(configPath,"/Xconfig");
  594.       if (configFile = fopen( configPath, "r" )) break;
  595.     }
  596.     
  597.     /*
  598.      * /usr/lib/X11/X386/Xconfig.<hostname>
  599.      */
  600.     strcpy(configPath, SERVER_CONFIG_FILE);
  601.     strcat(configPath, ".");
  602.     gethostname(configPath+strlen(configPath), MAXHOSTNAMELEN);
  603.     if (configFile = fopen( configPath, "r" )) break;
  604.     
  605.     /*
  606.      * /usr/lib/X11/X386/Xconfig
  607.      */
  608.     strcpy(configPath, SERVER_CONFIG_FILE);
  609.     if (configFile = fopen( configPath, "r" )) break;
  610.     
  611.     FatalError("No config file found!\n");
  612.   }
  613.  
  614.  
  615.   x386Info.sharedMonitor = FALSE;
  616.   x386Info.kbdProc = NULL;
  617.  
  618.   
  619.   while ((token = getToken(SymTab)) != EOF)
  620.     
  621.     switch (token) {
  622.       
  623.     case SHAREDMON:
  624.       x386Info.sharedMonitor = TRUE;
  625.       break;
  626.       
  627.     case FONTPATH:
  628.       if (getToken(NULL) != STRING) configError("Font path expected");
  629.       defaultFontPath = val.str;
  630.       break;
  631.       
  632.     case RGBPATH:
  633.       if (getToken(NULL) != STRING) configError("RGB path expected");
  634.       rgbPath = val.str;
  635.       break;
  636.       
  637.       
  638.     case KEYBOARD:
  639.       configKeyboard();
  640.       break;
  641.       
  642.       
  643.     case MICROSOFT:
  644.     case MOUSESYS:
  645.     case MMSERIES:
  646.     case LOGITECH:
  647.     case BUSMOUSE:
  648.       if (getToken(NULL) != STRING) configError("Mouse device expected");
  649.       x386Info.kbdProc    = x386KbdProc;
  650.       x386Info.kbdEvents  = x386KbdEvents;
  651.       x386Info.mseProc    = x386MseProc;
  652.       x386Info.mseEvents  = x386MseEvents;
  653.       x386Info.mseType    = token - MICROSOFT;
  654.       x386Info.mseDevice  = val.str;
  655.       configMouse();
  656.       break;
  657.       
  658. #ifdef XQUEUE
  659.     case XQUE:
  660.       x386Info.kbdProc   = x386XqueKbdProc;
  661.       x386Info.kbdEvents = x386XqueEvents;
  662.       x386Info.mseProc   = x386XqueMseProc;
  663.       x386Info.mseEvents = x386XqueEvents;
  664.       x386Info.xqueSema  = 0;
  665.       configKeyboard();
  666.       configMouse();
  667.       break;
  668. #endif
  669.       
  670.       
  671.     case VGA256:
  672.     case VGA16:
  673.     case WGA:
  674.     case XGA:
  675.       configGraphics(token - VGA256);
  676.       break;
  677.  
  678.  
  679.     case MODEDB:
  680.       for (pLast=NULL, token = getToken(NULL);
  681.        token == STRING || token == NUMBER;
  682.        pLast = pNew)
  683.     {
  684.       pNew = (DisplayModePtr)xalloc(sizeof(DisplayModeRec));
  685.       if (pLast) 
  686.         pLast->next = pNew;
  687.       else
  688.         pModes = pNew;
  689.       
  690.       if (token == STRING)
  691.         {
  692.           pNew->name = val.str;
  693.           if ((token = getToken(NULL)) != NUMBER)
  694.         FatalError("Dotclock expected");
  695.         }
  696.       else if (pLast)
  697.         {
  698.           pNew->name = (char *)strdup(pLast->name);
  699.         }
  700.       else
  701.         FatalError("Mode name expected");
  702.  
  703.       pNew->Flags = 0;
  704.       pNew->Clock = val.num;
  705.       
  706.       if (getToken(NULL) == NUMBER) pNew->HDisplay = val.num;
  707.       else configError("Horizontal display expected");
  708.       
  709.       if (getToken(NULL) == NUMBER) pNew->HSyncStart = val.num;
  710.       else configError("Horizontal sync start expected");
  711.       
  712.       if (getToken(NULL) == NUMBER) pNew->HSyncEnd = val.num;
  713.       else configError("Horizontal sync end expected");
  714.       
  715.       if (getToken(NULL) == NUMBER) pNew->HTotal = val.num;
  716.       else configError("Horizontal total expected");
  717.       
  718.       
  719.       if (getToken(NULL) == NUMBER) pNew->VDisplay = val.num;
  720.       else configError("Vertical display expected");
  721.       
  722.       if (getToken(NULL) == NUMBER) pNew->VSyncStart = val.num;
  723.       else configError("Vertical sync start expected");
  724.       
  725.       if (getToken(NULL) == NUMBER) pNew->VSyncEnd = val.num;
  726.       else configError("Vertical sync end expected");
  727.       
  728.       if (getToken(NULL) == NUMBER) pNew->VTotal = val.num;
  729.       else configError("Vertical total expected");
  730.  
  731.       while (((token=getToken(TimingTab)) != EOF) &&
  732.          (token != STRING) &&
  733.          (token != NUMBER))
  734.         
  735.         switch(token) {
  736.           
  737.         case INTERLACE: pNew->Flags |= V_INTERLACE;  break;
  738.         case PHSYNC:    pNew->Flags |= V_PHSYNC;     break;
  739.         case NHSYNC:    pNew->Flags |= V_NHSYNC;     break;
  740.         case PVSYNC:    pNew->Flags |= V_PVSYNC;     break;
  741.         case NVSYNC:    pNew->Flags |= V_NVSYNC;     break;
  742.         default:
  743.           configError("Videomode special flag expected");
  744.           break;
  745.         }
  746.     }
  747.       pushToken = token;
  748.       break;
  749.  
  750.     default:
  751.       configError("Keyword expected");
  752.       break;
  753.     }
  754.  
  755.   /*
  756.    * Probe all configured screens for letting them resolve their modes
  757.    */
  758.   for ( i=0; i < x386MaxScreens; i++ )
  759.     if (x386Screens[i]->configured &&
  760.     (x386Screens[i]->configured = (x386Screens[i]->Probe)()))
  761.       x386InitViewport(x386Screens[i]);
  762.  
  763.   /*
  764.    * Now sort the drivers to match the order of the ScreenNumbers
  765.    * requested by the user. (sorry, slow bubble-sort here)
  766.    * Note, that after this sorting the first driver that is not configured
  767.    * can be used as last-mark for all configured ones.
  768.    */
  769.   for ( j = 0; j < x386MaxScreens-1; j++)
  770.     for ( i=0; i < x386MaxScreens-j; i++ )
  771.       if (!x386Screens[i]->configured ||
  772.       (x386Screens[i+1]->configured &&
  773.        (x386Screens[i+1]->index < x386Screens[i]->index)))
  774.     {
  775.       ScrnInfoPtr temp = x386Screens[i+1];
  776.       x386Screens[i+1] = x386Screens[i];
  777.       x386Screens[i] = temp;
  778.     }
  779.  
  780.   /*
  781.    * free up mode info...
  782.    */
  783.   for (pLast = pModes, pNew = pModes->next;
  784.        pLast;
  785.        pLast = pNew, pNew = pNew->next)
  786.     {
  787.       Xfree(pLast->name);
  788.       Xfree(pLast);
  789.     }
  790.   
  791.   fclose(configFile);
  792.   Xfree(configBuf);
  793.   Xfree(configRBuf);
  794.   Xfree(configPath);
  795.   
  796.   if (!x386Info.kbdProc) configError("You must specify the input device(s)");
  797. }
  798.  
  799.  
  800. void 
  801. x386LookupMode(target, driver)
  802.      DisplayModePtr target;
  803.      ScrnInfoPtr    driver;
  804. {
  805.   DisplayModePtr p;
  806.   int            i;
  807.   Bool           found = FALSE;
  808.  
  809.   for (p = pModes; p != NULL; p = p->next)    /* scan list */
  810.     if (!strcmp(p->name, target->name))       /* names equal ? */
  811.       for (i=0; i < driver->clocks; i++)      /* scan clocks */
  812.     if (p->Clock == driver->clock[i])     /* clock found */
  813.       {
  814.         found = TRUE;
  815.         target->Clock      = i;
  816.         target->HDisplay   = p->HDisplay;
  817.         target->HSyncStart = p->HSyncStart;
  818.         target->HSyncEnd   = p->HSyncEnd;
  819.         target->HTotal     = p->HTotal;
  820.         target->VDisplay   = p->VDisplay;
  821.         target->VSyncStart = p->VSyncStart;
  822.         target->VSyncEnd   = p->VSyncEnd;
  823.         target->VTotal     = p->VTotal;
  824.         target->Flags      = p->Flags;
  825.       }
  826.   if (!found)
  827.     FatalError("Mode couldn't be resolved: \"%s\"\n", target->name);
  828. }
  829.