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