First pass at improved video driver autoloading

This is what we're currently shipping in Debian. Enables the ability for
drivers to ship a text file listing PCI ID's they support, and have the
server read them on startup when no driver is specified. This works, but
isn't the final solution.
This commit is contained in:
David Nusinow 2007-10-09 21:17:27 -04:00
parent 81d7b81146
commit 6033d8150b
6 changed files with 232 additions and 14 deletions

View File

@ -39,6 +39,7 @@
#include "xf86Config.h"
#include "xf86Priv.h"
#include "xf86_OSlib.h"
#include "dirent.h"
/* Sections for the default built-in configuration. */
@ -287,3 +288,207 @@ xf86AutoConfig(void)
return (ret == CONFIG_OK);
}
int
xchomp(char *line)
{
size_t len = 0;
if (!line) {
return 1;
}
len = strlen(line);
if (line[len - 1] == '\n' && len > 0) {
line[len - 1] = '\0';
return 0;
}
}
GDevPtr
autoConfigDevice(GDevPtr preconf_device)
{
GDevPtr ptr = NULL;
confScreenPtr scrn = NULL;
if (!xf86configptr) {
return NULL;
}
/* If there's a configured section with no driver chosen, use it */
if (preconf_device) {
ptr = preconf_device;
} else {
ptr = (GDevPtr)xalloc(sizeof(GDevRec));
if (!ptr) {
return NULL;
}
memset((GDevPtr)ptr, 0, sizeof(GDevRec));
ptr->chipID = -1;
ptr->chipRev = -1;
ptr->irq = -1;
ptr->active = TRUE;
ptr->claimed = FALSE;
ptr->identifier = "Autoconfigured Video Device";
ptr->driver = NULL;
}
if (!ptr->driver) {
ptr->driver = chooseVideoDriver();
}
/* TODO Handle multiple screen sections */
if (xf86ConfigLayout.screens && !xf86ConfigLayout.screens->screen->device) {
xf86ConfigLayout.screens->screen->device = ptr;
ptr->myScreenSection = xf86ConfigLayout.screens->screen;
}
xf86Msg(X_DEFAULT, "Assigned the driver to the xf86ConfigLayout\n");
return ptr;
}
char*
chooseVideoDriver(void)
{
pciVideoPtr *pciptr, info = NULL;
DIR *idsdir;
FILE *fp;
struct dirent *direntry;
char *line = NULL;
char *chosen_driver = NULL;
size_t len;
ssize_t read;
char path_name[256], vendor_str[5], chip_str[5];
int vendor, chip;
int i, j;
char *matches[20]; /* If we have more than 20 drivers we're in trouble */
for (i=0 ; i<20 ; i++)
matches[i] = NULL;
/* Find the primary device, and get some information about it. */
if (xf86PciVideoInfo) {
for (pciptr = xf86PciVideoInfo; (info = *pciptr); pciptr++) {
if (xf86IsPrimaryPci(info)) {
break;
}
}
if (!info) {
ErrorF("Primary device is not PCI\n");
}
} else {
ErrorF("xf86PciVideoInfo is not set\n");
}
if (!info) {
ErrorF("Could not get primary PCI info\n");
goto end;
}
idsdir = opendir("/usr/share/xserver-xorg/pci");
if (idsdir) {
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, "/usr/share/xserver-xorg/pci/", 256);
strncat(path_name, direntry->d_name, (256 - strlen(path_name)));
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 */
while ((read = getline(&line, &len, fp)) != -1) {
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 == info->vendor &&
(chip == info->chipType || chip == -1)) {
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 in autoconfig\n", matches[i], direntry->d_name);
}
} else {
/* TODO Handle driver overrides here */
}
}
fclose(fp);
}
direntry = readdir(idsdir);
}
}
/* TODO Handle multiple drivers claiming to support the same PCI ID */
if (matches[0]) {
chosen_driver = matches[0];
} else {
#if defined __i386__ || defined __amd64__ || defined __hurd__
chosen_driver = "vesa";
#elif defined __alpha__
chosen_driver = "vga";
#elif defined __sparc__
chosen_driver = "sunffb";
#else
chosen_driver = "fbdev";
#endif
}
xf86Msg(X_DEFAULT, "Matched %s for the autoconfigured driver\n", chosen_driver);
end:
i = 0;
while (matches[i]) {
if (matches[i] != chosen_driver) {
xfree(matches[i]);
}
i++;
}
xfree(line);
closedir(idsdir);
return chosen_driver;
}

View File

@ -1940,8 +1940,10 @@ configScreen(confScreenPtr screenp, XF86ConfScreenPtr conf_screen, int scrnum,
return FALSE;
}
screenp->device = xnfcalloc(1, sizeof(GDevRec));
configDevice(screenp->device,conf_screen->scrn_device, TRUE);
screenp->device->myScreenSection = screenp;
if (configDevice(screenp->device,conf_screen->scrn_device, TRUE))
screenp->device->myScreenSection = screenp;
else
screenp->device = NULL;
screenp->options = conf_screen->scrn_option_lst;
/*
@ -2230,13 +2232,17 @@ configDevice(GDevPtr devicep, XF86ConfDevicePtr conf_device, Bool active)
{
int i;
if (!conf_device) {
return FALSE;
}
if (active)
xf86Msg(X_CONFIG, "| |-->Device \"%s\"\n",
conf_device->dev_identifier);
else
xf86Msg(X_CONFIG, "|-->Inactive Device \"%s\"\n",
conf_device->dev_identifier);
devicep->identifier = conf_device->dev_identifier;
devicep->vendor = conf_device->dev_vendor;
devicep->board = conf_device->dev_board;

View File

@ -34,6 +34,8 @@
#define _xf86_config_h
#include "xf86Optrec.h"
#include "xf86Parser.h"
#include "xf86str.h"
#ifdef HAVE_PARSER_DECLS
/*
@ -65,5 +67,8 @@ Bool xf86BuiltinInputDriver(const char *);
ConfigStatus xf86HandleConfigFile(Bool);
Bool xf86AutoConfig(void);
GDevPtr autoConfigDevice(GDevPtr preconf_device);
char* chooseVideoDriver(void);
int xchomp(char *line);
#endif /* _xf86_config_h */

View File

@ -572,6 +572,16 @@ InitOutput(ScreenInfo *pScreenInfo, int argc, char **argv)
}
/* Load all driver modules specified in the config file */
/* If there aren't any specified in the config file, autoconfig them */
/* FIXME: Does not handle multiple active screen sections, but I'm not
* sure if we really want to handle that case*/
GDevPtr configured_device = xf86ConfigLayout.screens->screen->device;
if ((!configured_device) || (!configured_device->driver)) {
if (!autoConfigDevice(configured_device)) {
xf86Msg(X_ERROR, "Automatic driver configuration failed\n");
return ;
}
}
if ((modulelist = xf86DriverlistFromConfig())) {
xf86LoadModules(modulelist, NULL);
xfree(modulelist);

View File

@ -526,15 +526,7 @@ xf86validateScreen (XF86ConfigPtr p)
}
}
device = xf86findDevice (screen->scrn_device_str, p->conf_device_lst);
if (!device)
{
xf86validationError (UNDEFINED_DEVICE_MSG,
screen->scrn_device_str, screen->scrn_identifier);
return (FALSE);
}
else
screen->scrn_device = device;
screen->scrn_device= xf86findDevice (screen->scrn_device_str, p->conf_device_lst);
adaptor = screen->scrn_adaptor_lst;
while (adaptor)

View File

@ -80,8 +80,8 @@ static xf86ConfigSymTabRec TopLevelTab[] =
static int
xf86validateConfig (XF86ConfigPtr p)
{
if (!xf86validateDevice (p))
return FALSE;
/*if (!xf86validateDevice (p))
return FALSE;*/
if (!xf86validateScreen (p))
return FALSE;
if (!xf86validateInput (p))