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:
parent
81d7b81146
commit
6033d8150b
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in New Issue