static void
listPossibleVideoDrivers(char *matches[], int nmatches)
{
    int i;
    
    for (i = 0 ; i < nmatches ; i++) {
        matches[i] = NULL;
    }
    i = 0;

#ifdef sun
    /* Check for driver type based on /dev/fb type and if valid, use
       it instead of PCI bus probe results */
    if (xf86Info.consoleFd >= 0) {
	struct vis_identifier   visid;
	const char *cp;
	extern char xf86SolarisFbDev[PATH_MAX];
	int iret;

	SYSCALL(iret = ioctl(xf86Info.consoleFd, VIS_GETIDENTIFIER, &visid));
	if (iret < 0) {
	    int fbfd;

	    fbfd = open(xf86SolarisFbDev, O_RDONLY);
	    if (fbfd >= 0) {
		SYSCALL(iret = ioctl(fbfd, VIS_GETIDENTIFIER, &visid));
		close(fbfd);
	    }
	}

	if (iret < 0) {
	    xf86Msg(X_WARNING,
		    "could not get frame buffer identifier from %s\n",
		    xf86SolarisFbDev);
	} else {
	    xf86Msg(X_PROBED, "console driver: %s\n", visid.name);

	    /* Special case from before the general case was set */
	    if (strcmp(visid.name, "NVDAnvda") == 0) {
		matches[i++] = xnfstrdup("nvidia");
	    }

	    /* General case - split into vendor name (initial all-caps
	       prefix) & driver name (rest of the string). */
	    if (strcmp(visid.name, "SUNWtext") != 0) {
		for (cp = visid.name; (*cp != '\0') && isupper(*cp); cp++) {
		    /* find end of all uppercase vendor section */
		}
		if ((cp != visid.name) && (*cp != '\0')) {
		    char *driverName = xnfstrdup(cp);
		    char *vendorName = xnfstrdup(visid.name);
		    vendorName[cp - visid.name] = '\0';

		    matches[i++] = vendorName;
		    matches[i++] = driverName;
		}
	    }
	}
    }
#endif
#ifdef __sparc__
    {
	char *sbusDriver = sparcDriverName();
	if (sbusDriver)
	    matches[i++] = xnfstrdup(sbusDriver);
    }
#endif

    i = xf86PciMatchDriver(matches, nmatches);

    /* Fallback to platform default hardware */
    if (i < (nmatches - 1)) {
#if defined(__i386__) || defined(__amd64__) || defined(__hurd__)
	matches[i++] = xnfstrdup("vesa");
#elif defined(__sparc__) && !defined(sun)
	matches[i++] = xnfstrdup("sunffb");
#endif
    }

    /* Fallback to platform default frame buffer driver */
    if (i < (nmatches - 1)) {
#if !defined(__linux__) && defined(__sparc__)
	matches[i++] = xnfstrdup("wsfb");
#else
	matches[i++] = xnfstrdup("fbdev");
#endif
    }
}
/* This function is used to provide a workaround for binary drivers that
 * don't export their PCI ID's properly. If distros don't end up using this
 * feature it can and should be removed because the symbol-based resolution
 * scheme should be the primary one */
static void
matchDriverFromFiles (char** matches, uint16_t match_vendor, uint16_t match_chip)
{
    DIR *idsdir;
    FILE *fp;
    struct dirent *direntry;
    char *line = NULL;
    size_t len;
    ssize_t read;
    char path_name[256], vendor_str[5], chip_str[5];
    uint16_t vendor, chip;
    int i, j;

    idsdir = opendir(PCI_TXT_IDS_PATH);
    if (!idsdir)
        return;

    xf86Msg(X_INFO, "Scanning %s directory for additional PCI ID's supported by the drivers\n", PCI_TXT_IDS_PATH);
    direntry = readdir(idsdir);
    /* Read the directory */
    while (direntry) {
        if (direntry->d_name[0] == '.') {
            direntry = readdir(idsdir);
            continue;
        }
        len = strlen(direntry->d_name);
        /* A tiny bit of sanity checking. We should probably do better */
        if (strncmp(&(direntry->d_name[len-4]), ".ids", 4) == 0) {
            /* We need the full path name to open the file */
            strncpy(path_name, PCI_TXT_IDS_PATH, 256);
            strncat(path_name, "/", 1);
            strncat(path_name, direntry->d_name, (256 - strlen(path_name) - 1));
            fp = fopen(path_name, "r");
            if (fp == NULL) {
                xf86Msg(X_ERROR, "Could not open %s for reading. Exiting.\n", path_name);
                goto end;
            }
            /* Read the file */
#ifdef __GLIBC__
            while ((read = getline(&line, &len, fp)) != -1) {
#else
            while ((line = fgetln(fp, &len)) != (char *)NULL) {
#endif /* __GLIBC __ */
                xchomp(line);
                if (isdigit(line[0])) {
                    strncpy(vendor_str, line, 4);
                    vendor_str[4] = '\0';
                    vendor = (int)strtol(vendor_str, NULL, 16);
                    if ((strlen(&line[4])) == 0) {
                        chip_str[0] = '\0';
                        chip = -1;
                    } else {
                        /* Handle trailing whitespace */
                        if (isspace(line[4])) {
                            chip_str[0] = '\0';
                            chip = -1;
                        } else {
                            /* Ok, it's a real ID */
                            strncpy(chip_str, &line[4], 4);
                            chip_str[4] = '\0';
                            chip = (int)strtol(chip_str, NULL, 16);
                        }
                    }
                    if (vendor == match_vendor && chip == match_chip ) {
                        i = 0;
                        while (matches[i]) {
                            i++;
                        }
                        matches[i] = (char*)xalloc(sizeof(char) * strlen(direntry->d_name) -  3);
                        if (!matches[i]) {
                            xf86Msg(X_ERROR, "Could not allocate space for the module name. Exiting.\n");
                            goto end;
                        }
                        /* hack off the .ids suffix. This should guard
                         * against other problems, but it will end up
                         * taking off anything after the first '.' */
                        for (j = 0; j < (strlen(direntry->d_name) - 3) ; j++) {
                            if (direntry->d_name[j] == '.') {
                                matches[i][j] = '\0';
                                break;
                            } else {
                                matches[i][j] = direntry->d_name[j];
                            }
                        }
                        xf86Msg(X_INFO, "Matched %s from file name %s\n", matches[i], direntry->d_name);
                    }
                } else {
                    /* TODO Handle driver overrides here */
                }
            }
            fclose(fp);
        }
        direntry = readdir(idsdir);
    }
 end:
    xfree(line);
    closedir(idsdir);
}
#endif /* __linux__ */

static void
listPossibleVideoDrivers(char *matches[], int nmatches)
{
    struct pci_device * info = NULL;
    struct pci_device_iterator *iter;
    int i;
    
    for (i = 0 ; i < nmatches ; i++) {
        matches[i] = NULL;
    }
    i = 0;

#ifdef sun
    /* Check for driver type based on /dev/fb type and if valid, use
       it instead of PCI bus probe results */
    if (xf86Info.consoleFd >= 0) {
	struct vis_identifier   visid;
	const char *cp;
	extern char xf86SolarisFbDev[PATH_MAX];
	int iret;

	SYSCALL(iret = ioctl(xf86Info.consoleFd, VIS_GETIDENTIFIER, &visid));
	if (iret < 0) {
	    int fbfd;

	    fbfd = open(xf86SolarisFbDev, O_RDONLY);
	    if (fbfd >= 0) {
		SYSCALL(iret = ioctl(fbfd, VIS_GETIDENTIFIER, &visid));
		close(fbfd);
	    }
	}

	if (iret < 0) {
	    xf86Msg(X_WARNING,
		    "could not get frame buffer identifier from %s\n",
		    xf86SolarisFbDev);
	} else {
	    xf86Msg(X_PROBED, "console driver: %s\n", visid.name);

	    /* Special case from before the general case was set */
	    if (strcmp(visid.name, "NVDAnvda") == 0) {
		matches[i++] = xnfstrdup("nvidia");
	    }

	    /* General case - split into vendor name (initial all-caps
	       prefix) & driver name (rest of the string). */
	    if (strcmp(visid.name, "SUNWtext") != 0) {
		for (cp = visid.name; (*cp != '\0') && isupper(*cp); cp++) {
		    /* find end of all uppercase vendor section */
		}
		if ((cp != visid.name) && (*cp != '\0')) {
		    char *driverName = xnfstrdup(cp);
		    char *vendorName = xnfstrdup(visid.name);
		    vendorName[cp - visid.name] = '\0';

		    matches[i++] = vendorName;
		    matches[i++] = driverName;
		}
	    }
	}
    }
#endif
#ifdef __sparc__
    {
	char *sbusDriver = sparcDriverName();
	if (sbusDriver)
	    matches[i++] = xnfstrdup(sbusDriver);
    }
#endif

    /* Find the primary device, and get some information about it. */
    iter = pci_slot_match_iterator_create(NULL);
    while ((info = pci_device_next(iter)) != NULL) {
	if (xf86IsPrimaryPci(info)) {
	    break;
	}
    }

    pci_iterator_destroy(iter);

    if (!info) {
	ErrorF("Primary device is not PCI\n");
    }
#ifdef __linux__
    else {
	matchDriverFromFiles(matches, info->vendor_id, info->device_id);
    }
#endif /* __linux__ */

    for (i = 0; (i < nmatches) && (matches[i]); i++) {
	/* find end of matches list */
    }

    if ((info != NULL) && (i < nmatches)) {
	i += videoPtrToDriverList(info, &(matches[i]), nmatches - i);
    }

    /* Fallback to platform default hardware */
    if (i < (nmatches - 1)) {
#if defined(__i386__) || defined(__amd64__) || defined(__hurd__)
	matches[i++] = xnfstrdup("vesa");
#elif defined(__sparc__) && !defined(sun)
	matches[i++] = xnfstrdup("sunffb");
#endif
    }

    /* Fallback to platform default frame buffer driver */
    if (i < (nmatches - 1)) {
#if !defined(__linux__) && defined(__sparc__)
	matches[i++] = xnfstrdup("wsfb");
#else
	matches[i++] = xnfstrdup("fbdev");
#endif
    }
}

/* copy a screen section and enter the desired driver
 * and insert it at i in the list of screens */
static Bool
copyScreen(confScreenPtr oscreen, GDevPtr odev, int i, char *driver)
{
    GDevPtr cptr = NULL;

    xf86ConfigLayout.screens[i].screen = xnfcalloc(1, sizeof(confScreenRec));
    if(!xf86ConfigLayout.screens[i].screen)
        return FALSE;
    memcpy(xf86ConfigLayout.screens[i].screen, oscreen, sizeof(confScreenRec));

    cptr = xcalloc(1, sizeof(GDevRec));
    if (!cptr)
        return FALSE;
    memcpy(cptr, odev, sizeof(GDevRec));

    cptr->identifier = Xprintf("Autoconfigured Video Device %s", driver);
    cptr->driver = driver;

    /* now associate the new driver entry with the new screen entry */
    xf86ConfigLayout.screens[i].screen->device = cptr;
    cptr->myScreenSection = xf86ConfigLayout.screens[i].screen;

    return TRUE;
}