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