summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Nusinow <dnusinow@debian.org>2007-10-09 21:17:27 -0400
committerDavid Nusinow <dnusinow@debian.org>2007-10-09 22:13:15 -0400
commit6033d8150be3a115b90226eaa42f237bb0cf3369 (patch)
treef464af75df67cfa5aca9b62335bc0f64fca4e761
parent81d7b81146224f2b83278f5e21b3f9a36f30bd56 (diff)
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.
-rw-r--r--hw/xfree86/common/xf86AutoConfig.c205
-rw-r--r--hw/xfree86/common/xf86Config.c12
-rw-r--r--hw/xfree86/common/xf86Config.h5
-rw-r--r--hw/xfree86/common/xf86Init.c10
-rw-r--r--hw/xfree86/parser/Screen.c10
-rw-r--r--hw/xfree86/parser/read.c4
6 files changed, 232 insertions, 14 deletions
diff --git a/hw/xfree86/common/xf86AutoConfig.c b/hw/xfree86/common/xf86AutoConfig.c
index 89afafc06..85fbc055a 100644
--- a/hw/xfree86/common/xf86AutoConfig.c
+++ b/hw/xfree86/common/xf86AutoConfig.c
@@ -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;
+}
diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c
index 71e008069..1b99e9556 100644
--- a/hw/xfree86/common/xf86Config.c
+++ b/hw/xfree86/common/xf86Config.c
@@ -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;
diff --git a/hw/xfree86/common/xf86Config.h b/hw/xfree86/common/xf86Config.h
index b8b5fd42a..a174e463b 100644
--- a/hw/xfree86/common/xf86Config.h
+++ b/hw/xfree86/common/xf86Config.h
@@ -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 */
diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c
index 2f1651cc7..bf577e6ad 100644
--- a/hw/xfree86/common/xf86Init.c
+++ b/hw/xfree86/common/xf86Init.c
@@ -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);
diff --git a/hw/xfree86/parser/Screen.c b/hw/xfree86/parser/Screen.c
index 79e1d24ef..4df2b0560 100644
--- a/hw/xfree86/parser/Screen.c
+++ b/hw/xfree86/parser/Screen.c
@@ -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)
diff --git a/hw/xfree86/parser/read.c b/hw/xfree86/parser/read.c
index 9f79696ac..308ee0304 100644
--- a/hw/xfree86/parser/read.c
+++ b/hw/xfree86/parser/read.c
@@ -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))