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#ifdef __NetBSD__
55#if defined(__sparc__) || defined(__sparc64__)
56#include <dev/sun/fbio.h>
57extern struct sbus_devtable sbusDeviceTable[];
58#endif /* sparc / sparc64 */
59#endif /* NetBSD */
60
61/* Sections for the default built-in configuration. */
62
63#define BUILTIN_DEVICE_NAME \
64	"\"Builtin Default %s Device %d\""
65
66#define BUILTIN_DEVICE_SECTION_PRE \
67	"Section \"Device\"\n" \
68	"\tIdentifier\t" BUILTIN_DEVICE_NAME "\n" \
69	"\tDriver\t\"%s\"\n"
70
71#define BUILTIN_DEVICE_SECTION_POST \
72	"EndSection\n\n"
73
74#define BUILTIN_DEVICE_SECTION \
75	BUILTIN_DEVICE_SECTION_PRE \
76	BUILTIN_DEVICE_SECTION_POST
77
78#define BUILTIN_SCREEN_NAME \
79	"\"Builtin Default %s Screen %d\""
80
81#define BUILTIN_SCREEN_SECTION \
82	"Section \"Screen\"\n" \
83	"\tIdentifier\t" BUILTIN_SCREEN_NAME "\n" \
84	"\tDevice\t" BUILTIN_DEVICE_NAME "\n" \
85	"EndSection\n\n"
86
87#define BUILTIN_LAYOUT_SECTION_PRE \
88	"Section \"ServerLayout\"\n" \
89	"\tIdentifier\t\"Builtin Default Layout\"\n"
90
91#define BUILTIN_LAYOUT_SCREEN_LINE \
92	"\tScreen\t" BUILTIN_SCREEN_NAME "\n"
93
94#define BUILTIN_LAYOUT_SECTION_POST \
95	"EndSection\n\n"
96
97static const char **builtinConfig = NULL;
98static int builtinLines = 0;
99
100static void listPossibleVideoDrivers(XF86MatchedDrivers *md);
101
102/*
103 * A built-in config file is stored as an array of strings, with each string
104 * representing a single line.  AppendToConfig() breaks up the string "s"
105 * into lines, and appends those lines it to builtinConfig.
106 */
107
108static void
109AppendToList(const char *s, const char ***list, int *lines)
110{
111    char *str, *newstr, *p;
112
113    str = xnfstrdup(s);
114    for (p = strtok(str, "\n"); p; p = strtok(NULL, "\n")) {
115        (*lines)++;
116        *list = xnfreallocarray(*list, *lines + 1, sizeof(**list));
117        newstr = xnfalloc(strlen(p) + 2);
118        strcpy(newstr, p);
119        strcat(newstr, "\n");
120        (*list)[*lines - 1] = newstr;
121        (*list)[*lines] = NULL;
122    }
123    free(str);
124}
125
126static void
127FreeList(const char ***list, int *lines)
128{
129    int i;
130
131    for (i = 0; i < *lines; i++) {
132        free((char *) ((*list)[i]));
133    }
134    free(*list);
135    *list = NULL;
136    *lines = 0;
137}
138
139static void
140FreeConfig(void)
141{
142    FreeList(&builtinConfig, &builtinLines);
143}
144
145static void
146AppendToConfig(const char *s)
147{
148    AppendToList(s, &builtinConfig, &builtinLines);
149}
150
151void
152xf86AddMatchedDriver(XF86MatchedDrivers *md, const char *driver)
153{
154    int j;
155    int nmatches = md->nmatches;
156
157    for (j = 0; j < nmatches; ++j) {
158        if (xf86NameCmp(md->matches[j], driver) == 0) {
159            // Driver already in matched drivers
160            return;
161        }
162    }
163
164    if (nmatches < MATCH_DRIVERS_LIMIT) {
165        md->matches[nmatches] = xnfstrdup(driver);
166        md->nmatches++;
167    }
168    else {
169        xf86Msg(X_WARNING, "Too many drivers registered, can't add %s\n", driver);
170    }
171}
172
173Bool
174xf86AutoConfig(void)
175{
176    XF86MatchedDrivers md;
177    int i;
178    const char **cp;
179    char buf[1024];
180    ConfigStatus ret;
181
182    /* Make sure config rec is there */
183    if (xf86allocateConfig() != NULL) {
184        ret = CONFIG_OK;    /* OK so far */
185    }
186    else {
187        xf86Msg(X_ERROR, "Couldn't allocate Config record.\n");
188        return FALSE;
189    }
190
191    listPossibleVideoDrivers(&md);
192
193    for (i = 0; i < md.nmatches; i++) {
194        snprintf(buf, sizeof(buf), BUILTIN_DEVICE_SECTION,
195                md.matches[i], 0, md.matches[i]);
196        AppendToConfig(buf);
197        snprintf(buf, sizeof(buf), BUILTIN_SCREEN_SECTION,
198                md.matches[i], 0, md.matches[i], 0);
199        AppendToConfig(buf);
200    }
201
202    AppendToConfig(BUILTIN_LAYOUT_SECTION_PRE);
203    for (i = 0; i < md.nmatches; i++) {
204        snprintf(buf, sizeof(buf), BUILTIN_LAYOUT_SCREEN_LINE,
205                md.matches[i], 0);
206        AppendToConfig(buf);
207    }
208    AppendToConfig(BUILTIN_LAYOUT_SECTION_POST);
209
210    for (i = 0; i < md.nmatches; i++) {
211        free(md.matches[i]);
212    }
213
214    xf86MsgVerb(X_DEFAULT, 0,
215                "Using default built-in configuration (%d lines)\n",
216                builtinLines);
217
218    xf86MsgVerb(X_DEFAULT, 3, "--- Start of built-in configuration ---\n");
219    for (cp = builtinConfig; *cp; cp++)
220        xf86ErrorFVerb(3, "\t%s", *cp);
221    xf86MsgVerb(X_DEFAULT, 3, "--- End of built-in configuration ---\n");
222
223    xf86initConfigFiles();
224    xf86setBuiltinConfig(builtinConfig);
225    ret = xf86HandleConfigFile(TRUE);
226    FreeConfig();
227
228    if (ret != CONFIG_OK)
229        xf86Msg(X_ERROR, "Error parsing the built-in default configuration.\n");
230
231    return ret == CONFIG_OK;
232}
233
234static void
235listPossibleVideoDrivers(XF86MatchedDrivers *md)
236{
237    md->nmatches = 0;
238
239/* XXXMRG:  xorg-server 1.10/1.18 -- merge into xf86PlatformMatchDriver()? */
240#ifdef __NetBSD__
241#if defined(__shark)
242    xf86AddMatchedDriver(md, "chips");
243    xf86AddMatchedDriver(md, "igs");
244#elif defined(__sgimips)
245    xf86AddMatchedDriver(md, "crime");
246    xf86AddMatchedDriver(md, "newport");
247#elif defined(__sparc) || defined(__sparc64)
248    /* dig through /dev/fb* */
249    {
250    	struct fbtype fbt;
251	int j = 0, fd = 0, dev;
252	char fbpath[32];
253
254	for (j = 0; j < 10; j++) {
255	    snprintf(fbpath, 31, "/dev/fb%d", j);
256	    xf86Msg(X_ERROR,"%s: trying %s\n", __func__, fbpath);
257	    fd = open(fbpath, O_RDONLY, 0);
258	    if (fd == -1) continue;
259	    memset(&fbt, 0, sizeof(fbt));
260	    if (ioctl(fd, FBIOGTYPE, &fbt) == -1) {
261	    	close(fd);
262		continue;
263	    }
264	    close(fd);
265	    dev = 0;
266	    while ((sbusDeviceTable[dev].fbType != 0) &&
267	           (sbusDeviceTable[dev].fbType != fbt.fb_type))
268		dev++;
269	    if (sbusDeviceTable[dev].fbType == fbt.fb_type) {
270		xf86Msg(X_ERROR,"%s: found %s\n", __func__,
271		    sbusDeviceTable[dev].driverName);
272	        xf86AddMatchedDriver(md, sbusDeviceTable[dev].driverName);
273	    }
274	}
275    }
276#endif
277
278#else /* !NetBSD */
279#ifdef XSERVER_PLATFORM_BUS
280    xf86PlatformMatchDriver(md);
281#endif
282#ifdef __sun
283    /* Check for driver type based on /dev/fb type and if valid, use
284       it instead of PCI bus probe results */
285    if (xf86Info.consoleFd >= 0) {
286        struct vis_identifier visid;
287        const char *cp;
288        int iret;
289
290        SYSCALL(iret = ioctl(xf86Info.consoleFd, VIS_GETIDENTIFIER, &visid));
291        if (iret < 0) {
292            int fbfd;
293
294            fbfd = open(xf86SolarisFbDev, O_RDONLY);
295            if (fbfd >= 0) {
296                SYSCALL(iret = ioctl(fbfd, VIS_GETIDENTIFIER, &visid));
297                close(fbfd);
298            }
299        }
300
301        if (iret < 0) {
302            xf86Msg(X_WARNING,
303                    "could not get frame buffer identifier from %s\n",
304                    xf86SolarisFbDev);
305        }
306        else {
307            xf86Msg(X_PROBED, "console driver: %s\n", visid.name);
308
309            /* Special case from before the general case was set */
310            if (strcmp(visid.name, "NVDAnvda") == 0) {
311                xf86AddMatchedDriver(md, "nvidia");
312            }
313
314            /* General case - split into vendor name (initial all-caps
315               prefix) & driver name (rest of the string). */
316            if (strcmp(visid.name, "SUNWtext") != 0) {
317                for (cp = visid.name; (*cp != '\0') && isupper(*cp); cp++) {
318                    /* find end of all uppercase vendor section */
319                }
320                if ((cp != visid.name) && (*cp != '\0')) {
321                    char *vendorName = xnfstrdup(visid.name);
322
323                    vendorName[cp - visid.name] = '\0';
324
325                    xf86AddMatchedDriver(md, vendorName);
326                    xf86AddMatchedDriver(md, cp);
327
328                    free(vendorName);
329                }
330            }
331        }
332    }
333#endif
334#ifdef __sparc__
335    char *sbusDriver = sparcDriverName();
336
337    if (sbusDriver)
338        xf86AddMatchedDriver(md, sbusDriver);
339#endif
340#endif /* NetBSD */
341#ifdef XSERVER_LIBPCIACCESS
342    xf86PciMatchDriver(md);
343#endif
344
345#if defined(__linux__)
346    xf86AddMatchedDriver(md, "modesetting");
347#endif
348
349#if defined(__NetBSD__) && \
350    (defined(__aarch64__) || defined(__arm__) || \
351     defined(__i386__) || defined(__amd64__))
352    xf86AddMatchedDriver(md, "modesetting");
353#endif
354
355#if defined(__linux__)
356    xf86AddMatchedDriver(md, "fbdev");
357#endif
358
359    /* Fallback to platform default hardware */
360#if defined(__i386__) || defined(__amd64__) || defined(__hurd__)
361    xf86AddMatchedDriver(md, "vesa");
362#elif defined(__sparc__) && !defined(__sun)
363    xf86AddMatchedDriver(md, "sunffb");
364#endif
365
366#if defined(__NetBSD__)
367    xf86AddMatchedDriver(md, "wsfb");
368#endif
369}
370
371/* copy a screen section and enter the desired driver
372 * and insert it at i in the list of screens */
373static Bool
374copyScreen(confScreenPtr oscreen, GDevPtr odev, int i, char *driver)
375{
376    confScreenPtr nscreen;
377    GDevPtr cptr = NULL;
378    char *identifier;
379
380    nscreen = malloc(sizeof(confScreenRec));
381    if (!nscreen)
382        return FALSE;
383    memcpy(nscreen, oscreen, sizeof(confScreenRec));
384
385    cptr = malloc(sizeof(GDevRec));
386    if (!cptr) {
387        free(nscreen);
388        return FALSE;
389    }
390    memcpy(cptr, odev, sizeof(GDevRec));
391
392    if (asprintf(&identifier, "Autoconfigured Video Device %s", driver)
393        == -1) {
394        free(cptr);
395        free(nscreen);
396        return FALSE;
397    }
398    cptr->driver = driver;
399    cptr->identifier = identifier;
400
401    xf86ConfigLayout.screens[i].screen = nscreen;
402
403    /* now associate the new driver entry with the new screen entry */
404    xf86ConfigLayout.screens[i].screen->device = cptr;
405    cptr->myScreenSection = xf86ConfigLayout.screens[i].screen;
406
407    return TRUE;
408}
409
410GDevPtr
411autoConfigDevice(GDevPtr preconf_device)
412{
413    GDevPtr ptr = NULL;
414    XF86MatchedDrivers md;
415    int num_screens = 0, i;
416    screenLayoutPtr slp;
417
418    if (!xf86configptr) {
419        return NULL;
420    }
421
422    /* If there's a configured section with no driver chosen, use it */
423    if (preconf_device) {
424        ptr = preconf_device;
425    }
426    else {
427        ptr = calloc(1, sizeof(GDevRec));
428        if (!ptr) {
429            return NULL;
430        }
431        ptr->chipID = -1;
432        ptr->chipRev = -1;
433        ptr->irq = -1;
434
435        ptr->active = TRUE;
436        ptr->claimed = FALSE;
437        ptr->identifier = "Autoconfigured Video Device";
438        ptr->driver = NULL;
439    }
440    if (!ptr->driver) {
441        /* get all possible video drivers and count them */
442        listPossibleVideoDrivers(&md);
443        for (i = 0; i < md.nmatches; i++) {
444            xf86Msg(X_DEFAULT, "Matched %s as autoconfigured driver %d\n",
445                    md.matches[i], i);
446        }
447
448        slp = xf86ConfigLayout.screens;
449        if (slp) {
450            /* count the number of screens and make space for
451             * a new screen for each additional possible driver
452             * minus one for the already existing first one
453             * plus one for the terminating NULL */
454            for (; slp[num_screens].screen; num_screens++);
455            xf86ConfigLayout.screens = xnfcalloc(num_screens + md.nmatches,
456                                                 sizeof(screenLayoutRec));
457            xf86ConfigLayout.screens[0] = slp[0];
458
459            /* do the first match and set that for the original first screen */
460            ptr->driver = md.matches[0];
461            if (!xf86ConfigLayout.screens[0].screen->device) {
462                xf86ConfigLayout.screens[0].screen->device = ptr;
463                ptr->myScreenSection = xf86ConfigLayout.screens[0].screen;
464            }
465
466            /* for each other driver found, copy the first screen, insert it
467             * into the list of screens and set the driver */
468            for (i = 1; i < md.nmatches; i++) {
469                if (!copyScreen(slp[0].screen, ptr, i, md.matches[i]))
470                    return NULL;
471            }
472
473            /* shift the rest of the original screen list
474             * to the end of the current screen list
475             *
476             * TODO Handle rest of multiple screen sections */
477            for (i = 1; i < num_screens; i++) {
478                xf86ConfigLayout.screens[i + md.nmatches] = slp[i];
479            }
480            xf86ConfigLayout.screens[num_screens + md.nmatches - 1].screen =
481                NULL;
482            free(slp);
483        }
484        else {
485            /* layout does not have any screens, not much to do */
486            ptr->driver = md.matches[0];
487            for (i = 1; i < md.nmatches; i++) {
488                free(md.matches[i]);
489            }
490        }
491    }
492
493    xf86Msg(X_DEFAULT, "Assigned the driver to the xf86ConfigLayout\n");
494
495    return ptr;
496}
497