1 /*
2  * Copyright 2003 by David H. Dawes.
3  * Copyright 2003 by X-Oz Technologies.
4  * All rights reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Except as contained in this notice, the name of the copyright holder(s)
25  * and author(s) shall not be used in advertising or otherwise to promote
26  * the sale, use or other dealings in this Software without prior written
27  * authorization from the copyright holder(s) and author(s).
28  *
29  * Author: David Dawes <dawes@XFree86.Org>.
30  */
31 
32 #ifdef HAVE_XORG_CONFIG_H
33 #include <xorg-config.h>
34 #endif
35 
36 #include "xf86.h"
37 #include "xf86Parser.h"
38 #include "xf86tokens.h"
39 #include "xf86Config.h"
40 #include "xf86MatchDrivers.h"
41 #include "xf86Priv.h"
42 #include "xf86_OSlib.h"
43 #include "xf86platformBus.h"
44 #include "xf86pciBus.h"
45 #ifdef __sparc__
46 #include "xf86sbusBus.h"
47 #endif
48 
49 #ifdef __sun
50 #include <sys/visual_io.h>
51 #include <ctype.h>
52 #endif
53 
54 /* Sections for the default built-in configuration. */
55 
56 #define BUILTIN_DEVICE_NAME \
57 	"\"Builtin Default %s Device %d\""
58 
59 #define BUILTIN_DEVICE_SECTION_PRE \
60 	"Section \"Device\"\n" \
61 	"\tIdentifier\t" BUILTIN_DEVICE_NAME "\n" \
62 	"\tDriver\t\"%s\"\n"
63 
64 #define BUILTIN_DEVICE_SECTION_POST \
65 	"EndSection\n\n"
66 
67 #define BUILTIN_DEVICE_SECTION \
68 	BUILTIN_DEVICE_SECTION_PRE \
69 	BUILTIN_DEVICE_SECTION_POST
70 
71 #define BUILTIN_SCREEN_NAME \
72 	"\"Builtin Default %s Screen %d\""
73 
74 #define BUILTIN_SCREEN_SECTION \
75 	"Section \"Screen\"\n" \
76 	"\tIdentifier\t" BUILTIN_SCREEN_NAME "\n" \
77 	"\tDevice\t" BUILTIN_DEVICE_NAME "\n" \
78 	"EndSection\n\n"
79 
80 #define BUILTIN_LAYOUT_SECTION_PRE \
81 	"Section \"ServerLayout\"\n" \
82 	"\tIdentifier\t\"Builtin Default Layout\"\n"
83 
84 #define BUILTIN_LAYOUT_SCREEN_LINE \
85 	"\tScreen\t" BUILTIN_SCREEN_NAME "\n"
86 
87 #define BUILTIN_LAYOUT_SECTION_POST \
88 	"EndSection\n\n"
89 
90 static const char **builtinConfig = NULL;
91 static int builtinLines = 0;
92 
93 static void listPossibleVideoDrivers(XF86MatchedDrivers *md);
94 
95 /*
96  * A built-in config file is stored as an array of strings, with each string
97  * representing a single line.  AppendToConfig() breaks up the string "s"
98  * into lines, and appends those lines it to builtinConfig.
99  */
100 
101 static void
AppendToList(const char * s,const char *** list,int * lines)102 AppendToList(const char *s, const char ***list, int *lines)
103 {
104     char *str, *newstr, *p;
105 
106     str = xnfstrdup(s);
107     for (p = strtok(str, "\n"); p; p = strtok(NULL, "\n")) {
108         (*lines)++;
109         *list = xnfreallocarray(*list, *lines + 1, sizeof(**list));
110         newstr = xnfalloc(strlen(p) + 2);
111         strcpy(newstr, p);
112         strcat(newstr, "\n");
113         (*list)[*lines - 1] = newstr;
114         (*list)[*lines] = NULL;
115     }
116     free(str);
117 }
118 
119 static void
FreeList(const char *** list,int * lines)120 FreeList(const char ***list, int *lines)
121 {
122     int i;
123 
124     for (i = 0; i < *lines; i++) {
125         free((char *) ((*list)[i]));
126     }
127     free(*list);
128     *list = NULL;
129     *lines = 0;
130 }
131 
132 static void
FreeConfig(void)133 FreeConfig(void)
134 {
135     FreeList(&builtinConfig, &builtinLines);
136 }
137 
138 static void
AppendToConfig(const char * s)139 AppendToConfig(const char *s)
140 {
141     AppendToList(s, &builtinConfig, &builtinLines);
142 }
143 
144 void
xf86AddMatchedDriver(XF86MatchedDrivers * md,const char * driver)145 xf86AddMatchedDriver(XF86MatchedDrivers *md, const char *driver)
146 {
147     int j;
148     int nmatches = md->nmatches;
149 
150     for (j = 0; j < nmatches; ++j) {
151         if (xf86NameCmp(md->matches[j], driver) == 0) {
152             // Driver already in matched drivers
153             return;
154         }
155     }
156 
157     if (nmatches < MATCH_DRIVERS_LIMIT) {
158         md->matches[nmatches] = xnfstrdup(driver);
159         md->nmatches++;
160     }
161     else {
162         xf86Msg(X_WARNING, "Too many drivers registered, can't add %s\n", driver);
163     }
164 }
165 
166 Bool
xf86AutoConfig(void)167 xf86AutoConfig(void)
168 {
169     XF86MatchedDrivers md;
170     int i;
171     const char **cp;
172     char buf[1024];
173     ConfigStatus ret;
174 
175     /* Make sure config rec is there */
176     if (xf86allocateConfig() != NULL) {
177         ret = CONFIG_OK;    /* OK so far */
178     }
179     else {
180         xf86Msg(X_ERROR, "Couldn't allocate Config record.\n");
181         return FALSE;
182     }
183 
184     listPossibleVideoDrivers(&md);
185 
186     for (i = 0; i < md.nmatches; i++) {
187         snprintf(buf, sizeof(buf), BUILTIN_DEVICE_SECTION,
188                 md.matches[i], 0, md.matches[i]);
189         AppendToConfig(buf);
190         snprintf(buf, sizeof(buf), BUILTIN_SCREEN_SECTION,
191                 md.matches[i], 0, md.matches[i], 0);
192         AppendToConfig(buf);
193     }
194 
195     AppendToConfig(BUILTIN_LAYOUT_SECTION_PRE);
196     for (i = 0; i < md.nmatches; i++) {
197         snprintf(buf, sizeof(buf), BUILTIN_LAYOUT_SCREEN_LINE,
198                 md.matches[i], 0);
199         AppendToConfig(buf);
200     }
201     AppendToConfig(BUILTIN_LAYOUT_SECTION_POST);
202 
203     for (i = 0; i < md.nmatches; i++) {
204         free(md.matches[i]);
205     }
206 
207     xf86MsgVerb(X_DEFAULT, 0,
208                 "Using default built-in configuration (%d lines)\n",
209                 builtinLines);
210 
211     xf86MsgVerb(X_DEFAULT, 3, "--- Start of built-in configuration ---\n");
212     for (cp = builtinConfig; *cp; cp++)
213         xf86ErrorFVerb(3, "\t%s", *cp);
214     xf86MsgVerb(X_DEFAULT, 3, "--- End of built-in configuration ---\n");
215 
216     xf86initConfigFiles();
217     xf86setBuiltinConfig(builtinConfig);
218     ret = xf86HandleConfigFile(TRUE);
219     FreeConfig();
220 
221     if (ret != CONFIG_OK)
222         xf86Msg(X_ERROR, "Error parsing the built-in default configuration.\n");
223 
224     return ret == CONFIG_OK;
225 }
226 
227 static void
listPossibleVideoDrivers(XF86MatchedDrivers * md)228 listPossibleVideoDrivers(XF86MatchedDrivers *md)
229 {
230     md->nmatches = 0;
231 
232 #ifdef XSERVER_PLATFORM_BUS
233     xf86PlatformMatchDriver(md);
234 #endif
235 #ifdef __sun
236     /* Check for driver type based on /dev/fb type and if valid, use
237        it instead of PCI bus probe results */
238     if (xf86Info.consoleFd >= 0) {
239         struct vis_identifier visid;
240         const char *cp;
241         int iret;
242 
243         SYSCALL(iret = ioctl(xf86Info.consoleFd, VIS_GETIDENTIFIER, &visid));
244         if (iret < 0) {
245             int fbfd;
246 
247             fbfd = open(xf86SolarisFbDev, O_RDONLY);
248             if (fbfd >= 0) {
249                 SYSCALL(iret = ioctl(fbfd, VIS_GETIDENTIFIER, &visid));
250                 close(fbfd);
251             }
252         }
253 
254         if (iret < 0) {
255             xf86Msg(X_WARNING,
256                     "could not get frame buffer identifier from %s\n",
257                     xf86SolarisFbDev);
258         }
259         else {
260             xf86Msg(X_PROBED, "console driver: %s\n", visid.name);
261 
262             /* Special case from before the general case was set */
263             if (strcmp(visid.name, "NVDAnvda") == 0) {
264                 xf86AddMatchedDriver(md, "nvidia");
265             }
266 
267             /* General case - split into vendor name (initial all-caps
268                prefix) & driver name (rest of the string). */
269             if (strcmp(visid.name, "SUNWtext") != 0) {
270                 for (cp = visid.name; (*cp != '\0') && isupper(*cp); cp++) {
271                     /* find end of all uppercase vendor section */
272                 }
273                 if ((cp != visid.name) && (*cp != '\0')) {
274                     char *vendorName = xnfstrdup(visid.name);
275 
276                     vendorName[cp - visid.name] = '\0';
277 
278                     xf86AddMatchedDriver(md, vendorName);
279                     xf86AddMatchedDriver(md, cp);
280 
281                     free(vendorName);
282                 }
283             }
284         }
285     }
286 #endif
287 #ifdef __sparc__
288     char *sbusDriver = sparcDriverName();
289 
290     if (sbusDriver)
291         xf86AddMatchedDriver(md, sbusDriver);
292 #endif
293 #ifdef XSERVER_LIBPCIACCESS
294     xf86PciMatchDriver(md);
295 #endif
296 
297 #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
298     xf86AddMatchedDriver(md, "modesetting");
299 #endif
300 
301 #if !defined(__sun)
302     /* Fallback to platform default frame buffer driver */
303 #if !defined(__linux__) && defined(__sparc__)
304     xf86AddMatchedDriver(md, "wsfb");
305 #elif defined(__linux__)
306     xf86AddMatchedDriver(md, "fbdev");
307 #elif defined(__FreeBSD__) || defined(__DragonFly__)
308     xf86AddMatchedDriver(md, "scfb");
309 #endif
310 #endif                          /* !__sun */
311 
312     /* Fallback to platform default hardware */
313 #if defined(__i386__) || defined(__amd64__) || defined(__hurd__)
314     xf86AddMatchedDriver(md, "vesa");
315 #elif defined(__sparc__) && !defined(__sun)
316     xf86AddMatchedDriver(md, "sunffb");
317 #endif
318 }
319 
320 /* copy a screen section and enter the desired driver
321  * and insert it at i in the list of screens */
322 static Bool
copyScreen(confScreenPtr oscreen,GDevPtr odev,int i,char * driver)323 copyScreen(confScreenPtr oscreen, GDevPtr odev, int i, char *driver)
324 {
325     confScreenPtr nscreen;
326     GDevPtr cptr = NULL;
327     char *identifier;
328 
329     nscreen = malloc(sizeof(confScreenRec));
330     if (!nscreen)
331         return FALSE;
332     memcpy(nscreen, oscreen, sizeof(confScreenRec));
333 
334     cptr = malloc(sizeof(GDevRec));
335     if (!cptr) {
336         free(nscreen);
337         return FALSE;
338     }
339     memcpy(cptr, odev, sizeof(GDevRec));
340 
341     if (asprintf(&identifier, "Autoconfigured Video Device %s", driver)
342         == -1) {
343         free(cptr);
344         free(nscreen);
345         return FALSE;
346     }
347     cptr->driver = driver;
348     cptr->identifier = identifier;
349 
350     xf86ConfigLayout.screens[i].screen = nscreen;
351 
352     /* now associate the new driver entry with the new screen entry */
353     xf86ConfigLayout.screens[i].screen->device = cptr;
354     cptr->myScreenSection = xf86ConfigLayout.screens[i].screen;
355 
356     return TRUE;
357 }
358 
359 GDevPtr
autoConfigDevice(GDevPtr preconf_device)360 autoConfigDevice(GDevPtr preconf_device)
361 {
362     GDevPtr ptr = NULL;
363     XF86MatchedDrivers md;
364     int num_screens = 0, i;
365     screenLayoutPtr slp;
366 
367     if (!xf86configptr) {
368         return NULL;
369     }
370 
371     /* If there's a configured section with no driver chosen, use it */
372     if (preconf_device) {
373         ptr = preconf_device;
374     }
375     else {
376         ptr = calloc(1, sizeof(GDevRec));
377         if (!ptr) {
378             return NULL;
379         }
380         ptr->chipID = -1;
381         ptr->chipRev = -1;
382         ptr->irq = -1;
383 
384         ptr->active = TRUE;
385         ptr->claimed = FALSE;
386         ptr->identifier = "Autoconfigured Video Device";
387         ptr->driver = NULL;
388     }
389     if (!ptr->driver) {
390         /* get all possible video drivers and count them */
391         listPossibleVideoDrivers(&md);
392         for (i = 0; i < md.nmatches; i++) {
393             xf86Msg(X_DEFAULT, "Matched %s as autoconfigured driver %d\n",
394                     md.matches[i], i);
395         }
396 
397         slp = xf86ConfigLayout.screens;
398         if (slp) {
399             /* count the number of screens and make space for
400              * a new screen for each additional possible driver
401              * minus one for the already existing first one
402              * plus one for the terminating NULL */
403             for (; slp[num_screens].screen; num_screens++);
404             xf86ConfigLayout.screens = xnfcalloc(num_screens + md.nmatches,
405                                                  sizeof(screenLayoutRec));
406             xf86ConfigLayout.screens[0] = slp[0];
407 
408             /* do the first match and set that for the original first screen */
409             ptr->driver = md.matches[0];
410             if (!xf86ConfigLayout.screens[0].screen->device) {
411                 xf86ConfigLayout.screens[0].screen->device = ptr;
412                 ptr->myScreenSection = xf86ConfigLayout.screens[0].screen;
413             }
414 
415             /* for each other driver found, copy the first screen, insert it
416              * into the list of screens and set the driver */
417             for (i = 1; i < md.nmatches; i++) {
418                 if (!copyScreen(slp[0].screen, ptr, i, md.matches[i]))
419                     return NULL;
420             }
421 
422             /* shift the rest of the original screen list
423              * to the end of the current screen list
424              *
425              * TODO Handle rest of multiple screen sections */
426             for (i = 1; i < num_screens; i++) {
427                 xf86ConfigLayout.screens[i + md.nmatches] = slp[i];
428             }
429             xf86ConfigLayout.screens[num_screens + md.nmatches - 1].screen =
430                 NULL;
431             free(slp);
432         }
433         else {
434             /* layout does not have any screens, not much to do */
435             ptr->driver = md.matches[0];
436             for (i = 1; i < md.nmatches; i++) {
437                 free(md.matches[i]);
438             }
439         }
440     }
441 
442     xf86Msg(X_DEFAULT, "Assigned the driver to the xf86ConfigLayout\n");
443 
444     return ptr;
445 }
446