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