diff --git a/config/10-nvidia.conf.in b/config/10-nvidia.conf.in new file mode 100644 index 000000000..ff7236289 --- /dev/null +++ b/config/10-nvidia.conf.in @@ -0,0 +1,16 @@ +# This xorg.conf.d configuration snippet configures the X server to +# automatically load the nvidia X driver and nvidia GLX libraries +# when it detects a device driven by nvidia-drm.ko kernel module. +# Please note that this works on Linux kernels version 6.12 or higher +# with CONFIG_DRM enabled, and only if the nvidia-drm.ko kernel module +# is loaded before the X server is started. + +Section "OutputClass" + Identifier "NVidia" + MatchDriver "nvidia-drm" + Driver "nvidia" + Module "glx" + Module "glxserver_nvidia" + Option "AllowEmptyInitialConfiguration" + ModulePath "@libdir@/nvidia/xorg" +EndSection diff --git a/config/meson.build b/config/meson.build index 15f21a053..a4f73c7cd 100644 --- a/config/meson.build +++ b/config/meson.build @@ -26,6 +26,14 @@ endif if build_xorg install_data('10-quirks.conf', install_dir: join_paths(get_option('datadir'), 'X11/xorg.conf.d')) + nvidia_conf = configuration_data() + nvidia_conf.set('libdir', join_paths(get_option('prefix'),get_option('libdir'))) + configure_file( + input: '10-nvidia.conf.in', + output: '10-nvidia.conf', + configuration: nvidia_conf, + install_dir: join_paths(get_option('datadir'), 'X11/xorg.conf.d'), + ) endif libxserver_config = static_library('xserver_config', diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c index cd1cddb96..92e316e84 100644 --- a/hw/xfree86/common/xf86Init.c +++ b/hw/xfree86/common/xf86Init.c @@ -329,7 +329,7 @@ InitOutput(int argc, char **argv) LoaderInit(); /* Tell the loader the default module search path */ - LoaderSetPath(xf86ModulePath); + LoaderSetPath(NULL, xf86ModulePath); if (xf86Info.ignoreABI) { LoaderSetIgnoreAbi(); @@ -749,6 +749,8 @@ CloseInput(void) { config_fini(); mieqFini(); + /* strictly speaking the below is not related to input, but ... */ + LoaderClose(); } /* diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c index 19588d76c..91721bd5e 100644 --- a/hw/xfree86/common/xf86platformBus.c +++ b/hw/xfree86/common/xf86platformBus.c @@ -197,9 +197,11 @@ xf86OutputClassDriverList(int index, XF86MatchedDrivers *md) LogMessageVerb(X_INFO, 1, "Applying OutputClass \"%s\" to %s\n", cl->identifier, path); - LogMessageVerb(X_NONE, 1, "\tloading driver: %s\n", cl->driver); - - xf86AddMatchedDriver(md, cl->driver); + if (cl->driver != NULL && *(cl->driver)) { + LogMessageVerb(X_NONE, 1, "\tloading driver: %s\n", cl->driver); + xf86AddMatchedDriver(md, cl->driver); + } else + LogMessageVerb(X_NONE, 1, "\tno driver specified\n"); } } } @@ -261,7 +263,8 @@ xf86platformProbe(void) Bool pci = TRUE; XF86ConfOutputClassPtr cl, cl_head = (xf86configptr) ? xf86configptr->conf_outputclass_lst : NULL; - char *old_path, *path = NULL; + char *driver_path, *path = NULL; + char *curr, *next, *copy; config_odev_probe(xf86PlatformDeviceProbe); @@ -284,19 +287,85 @@ xf86platformProbe(void) if (!OutputClassMatches(cl, &xf86_platform_devices[i])) continue; - if (cl->modulepath && xf86ModPathFrom != X_CMDLINE) { - old_path = path; - XNFasprintf(&path, "%s,%s", cl->modulepath, - path ? path : xf86ModulePath); - free(old_path); - LogMessageVerb(X_CONFIG, 1, "OutputClass \"%s\" ModulePath extended to \"%s\"\n", - cl->identifier, path); - LoaderSetPath(path); + if (xf86ModPathFrom != X_CMDLINE) { + if (cl->driver) { + if (cl->modulepath) { + if (*(cl->modulepath)) { + XNFasprintf(&driver_path, "%s,%s", cl->modulepath, xf86ModulePath); + LogMessageVerb(X_CONFIG, 1, "OutputClass \"%s\" ModulePath for driver %s overridden with \"%s\"\n", + cl->identifier, cl->driver, driver_path); + } else { + XNFasprintf(&driver_path, "%s", xf86ModulePath); + LogMessageVerb(X_CONFIG, 1, "OutputClass \"%s\" ModulePath for driver %s reset to standard \"%s\"\n", + cl->identifier, cl->driver, driver_path); + } + } else { + driver_path = NULL; + LogMessageVerb(X_CONFIG, 1, "OutputClass \"%s\" ModulePath for driver %s reset to default\n", + cl->identifier, cl->driver); + } + if (*(cl->driver)) LoaderSetPath(cl->driver, driver_path); + if (cl->modules) { + LogMessageVerb(X_CONFIG, 1, " and for modules \"%s\" as well\n", + cl->modules); + XNFasprintf(©, "%s", cl->modules); + curr = copy; + while ((curr = strtok_r(curr, ",", &next))) { + if (*curr) LoaderSetPath(curr, driver_path); + curr = NULL; + } + free(copy); + } + free(driver_path); + } + else if (cl->modules) { + if (cl->modulepath) { + if (*(cl->modulepath)) { + XNFasprintf(&driver_path, "%s,%s", cl->modulepath, xf86ModulePath); + LogMessageVerb(X_CONFIG, 1, "OutputClass \"%s\" ModulePath for modules %s overridden with \"%s\"\n", + cl->identifier, cl->modules, driver_path); + } else { + XNFasprintf(&driver_path, "%s", xf86ModulePath); + LogMessageVerb(X_CONFIG, 1, "OutputClass \"%s\" ModulePath for modules %s reset to standard \"%s\"\n", + cl->identifier, cl->modules, driver_path); + } + } else { + driver_path = NULL; + LogMessageVerb(X_CONFIG, 1, "OutputClass \"%s\" ModulePath for modules %s reset to default\n", + cl->identifier, cl->modules); + } + XNFasprintf(©, "%s", cl->modules); + curr = copy; + while ((curr = strtok_r(curr, ",", &next))) { + if (*curr) LoaderSetPath(curr, driver_path); + curr = NULL; + } + free(copy); + } else { + driver_path = path; /* Reuse for temporary storage */ + if (*(cl->modulepath)) { + XNFasprintf(&path, "%s,%s", cl->modulepath, + path ? path : xf86ModulePath); + LogMessageVerb(X_CONFIG, 1, "OutputClass \"%s\" default ModulePath extended to \"%s\"\n", + cl->identifier, path); + } else { + XNFasprintf(&path, "%s", xf86ModulePath); + LogMessageVerb(X_CONFIG, 1, "OutputClass \"%s\" default ModulePath reset to standard \"%s\"\n", + cl->identifier, path); + } + } + /* Otherwise global module search path is left unchanged */ } } } - free(path); + if (xf86ModPathFrom != X_CMDLINE) { + if (path) { + LoaderSetPath(NULL, path); + free(path); + } else + LoaderSetPath(NULL, xf86ModulePath); + } /* First see if there is an OutputClass match marking a device as primary */ for (i = 0; i < xf86_num_platform_devices; i++) { diff --git a/hw/xfree86/doc/ddxDesign.xml b/hw/xfree86/doc/ddxDesign.xml index 08009ad11..92d222483 100644 --- a/hw/xfree86/doc/ddxDesign.xml +++ b/hw/xfree86/doc/ddxDesign.xml @@ -4779,15 +4779,16 @@ XFree86 common layer.
diff --git a/hw/xfree86/loader/loader.c b/hw/xfree86/loader/loader.c index a54c7440a..4089910e6 100644 --- a/hw/xfree86/loader/loader.c +++ b/hw/xfree86/loader/loader.c @@ -87,6 +87,14 @@ LoaderInit(void) LogMessageVerb(X_NONE, 2, "\t%s : %d.%d\n", ABI_CLASS_EXTENSION, GET_ABI_MAJOR(LoaderVersionInfo.extensionVersion), GET_ABI_MINOR(LoaderVersionInfo.extensionVersion)); + + LoaderInitPath(); +} + +void +LoaderClose(void) +{ + LoaderClosePath(); } /* Public Interface to the loader. */ diff --git a/hw/xfree86/loader/loaderProcs.h b/hw/xfree86/loader/loaderProcs.h index fc96be2d3..a73be90b4 100644 --- a/hw/xfree86/loader/loaderProcs.h +++ b/hw/xfree86/loader/loaderProcs.h @@ -69,11 +69,15 @@ typedef struct module_desc { /* External API for the loader */ void LoaderInit(void); +void LoaderClose(void); ModuleDescPtr LoadModule(const char *, void *, const XF86ModReqInfo *, int *); ModuleDescPtr DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent); void UnloadDriver(ModuleDescPtr); -void LoaderSetPath(const char *path); + +void LoaderSetPath(const char *driver, const char *path); +void LoaderInitPath(void); +void LoaderClosePath(void); void LoaderUnload(const char *, void *); unsigned long LoaderGetModuleVersion(ModuleDescPtr mod); diff --git a/hw/xfree86/loader/loadmod.c b/hw/xfree86/loader/loadmod.c index 89aad901e..dca684f98 100644 --- a/hw/xfree86/loader/loadmod.c +++ b/hw/xfree86/loader/loadmod.c @@ -101,6 +101,32 @@ FreeStringList(char **paths) static char **defaultPathList = NULL; +typedef struct { + struct xorg_list entry; + char *name; + char **paths; +} LoaderModulePathListItem; + +struct xorg_list modulePathLists; + +void LoaderInitPath(void) { + /* defaultPathList is already set in xf86Init */ + xorg_list_init(&modulePathLists); +} + +void LoaderClosePath(void) { + LoaderModulePathListItem *item, *next; + xorg_list_for_each_entry_safe(item, next, &modulePathLists, entry) { + xorg_list_del(&item->entry); + free(item->name); + if (item->paths) + FreeStringList(item->paths); + free(item); + } + xorg_list_del(&modulePathLists); + FreeStringList(defaultPathList); +} + static Bool PathIsAbsolute(const char *path) { @@ -163,14 +189,72 @@ InitPathList(const char *path) return list; } +/* + * Set a default search path or a search path for a specific driver + */ void -LoaderSetPath(const char *path) +LoaderSetPath(const char *driver, const char *path) { - if (!path) - return; + LoaderModulePathListItem *item; - FreeStringList(defaultPathList); - defaultPathList = InitPathList(path); + if (!driver) { + if (path) { + FreeStringList(defaultPathList); + defaultPathList = InitPathList(path); + } + return; + } + + xorg_list_for_each_entry(item, &modulePathLists, entry) { + if (!strcmp(item->name, driver)) { + FreeStringList(item->paths); + if (path) + item->paths = InitPathList(path); + else + item->paths = NULL; + return; + } + } + + item = malloc(sizeof(LoaderModulePathListItem)); + if (item) { + item->name = strdup(driver); + if (path) + item->paths = InitPathList(path); + else + item->paths = NULL; + } + if (item && item->name && (!path || item->paths)) + xorg_list_add(&item->entry, &modulePathLists); + else { + LogMessage(X_ERROR, "Failed to store module search path \"%s\" for module %s\n", path, driver); + if (item) { + if (item->name) free(item->name); + if (item->paths) FreeStringList(item->paths); + free(item); + } + } +} + +/* + * Get a default search path or a search path for a specific driver + * and make it effective + */ +static char ** +LoaderGetPath(const char *module) +{ + LoaderModulePathListItem *item; + + xorg_list_for_each_entry(item, &modulePathLists, entry) { + if (!strcmp(item->name, module)) { + if (item->paths) + return item->paths; + else + return defaultPathList; + } + } + + return defaultPathList; } /* Standard set of module subdirectories to search, in order of preference */ @@ -725,7 +809,7 @@ LoadModule(const char *module, void *options, const XF86ModReqInfo *modreq, goto LoadModule_fail; } - pathlist = defaultPathList; + pathlist = LoaderGetPath(name); if (!pathlist) { /* This could be a calloc failure too */ if (errmaj) diff --git a/hw/xfree86/man/xorg.conf.man b/hw/xfree86/man/xorg.conf.man index fa06e87c2..a4b3975fe 100644 --- a/hw/xfree86/man/xorg.conf.man +++ b/hw/xfree86/man/xorg.conf.man @@ -435,7 +435,7 @@ searches for loadable modules loading in the order specified. Multiple .B ModulePath entries may be specified, and they will be concatenated to build the -module search path used by the server. The default module path is +module search path used by the server. The standard default module path is .PP .RS 11 @modulepath@ @@ -1327,11 +1327,11 @@ When an output device has been matched to the .B OutputClass section, any .B Option -entries are applied to the device. One +entries are applied to the device. Two .B OutputClass -specific +specific kinds of .B Option -is recognized. See the +are recognized. See the .B Device section below for a description of the remaining .B Option @@ -1356,21 +1356,90 @@ If multiple output devices match an section with the .B HotplugDriver option, the first one enumerated becomes the hotplug driver. -A +.RE +.PP +.TP 7 +An .B OutputClass -Section may contain -.B ModulePath -entries. When an output device matches an +section may contain multiple +.TP 7 +.BI "ModulePath \*q" path \*q +entries. When an output device with DRM enabled matches an .B OutputClass -section, any +section and +.B Driver +.I \*qdriver\*q +is set, then for this driver module, and all modules loaded until the next driver +for a DRM-enabled GPU, a search path is created by prepending all .B ModulePath entries in that .B OutputClass -are pre-pended to the search path for loadable Xorg server modules. See +to the +.I standard +search path \(lq@modulepath@\(rq for loadable Xorg server modules (not the +.I effective +default set path, which can undergo changes, see below). If there is a single +.PP +.RS 11 +.nf +.B " ModulePath \*q\*q +.fi +.RE +.PP +.RS 7 +entry in an +.B OutputClass +for a +.I driver +, then only the +.I standard +path \(lq@modulepath@\(rq is searched from now on. It there no +.B ModulePath +entries at all, then the +.I effective +default search path (set globally) becomes active. Note that each +.B OutputClass +.I overrides +search path for a +.I driver +, not +.I extends +it. +.PP +If a matching +.B OutputClass +contains +.B ModulePath +entries, but not a +.B Driver +entry, then paths are +.I prepended +to the +.I effective +default search path, which initially is standard \(lq@modulepath@\(rq, thus extending it. +.PP +These entries have no effect if a search path for loadable modules is set through command line. See .B ModulePath in the .B Files section for more info. +.RE +.PP +.B OutputClass +section may contain an arbitrary number of +.PP +.RS 4 +.nf +.BI " Module \*q" module\*q +.fi +.RE +.PP +entries, which are quite equivalent to +.B Driver +except that +.I \*qmodule\*q +is not added to the list of autoconfigured video drivers. This may be useful to extend +ABI version ignoring and special search paths to modules like "glx". .SH "DEVICE SECTION" The config file may have multiple .B Device diff --git a/hw/xfree86/parser/OutputClass.c b/hw/xfree86/parser/OutputClass.c index ab65ce59f..ffabdf2d3 100644 --- a/hw/xfree86/parser/OutputClass.c +++ b/hw/xfree86/parser/OutputClass.c @@ -38,6 +38,7 @@ static const xf86ConfigSymTabRec OutputClassTab[] = { {ENDSECTION, "endsection"}, {IDENTIFIER, "identifier"}, {DRIVER, "driver"}, + {MODULE, "module"}, {MODULEPATH, "modulepath"}, {OPTION, "option"}, {MATCH_DRIVER, "matchdriver"}, @@ -53,6 +54,7 @@ xf86freeOutputClassList(XF86ConfOutputClassPtr ptr) TestFree(ptr->identifier); TestFree(ptr->comment); TestFree(ptr->driver); + TestFree(ptr->modules); TestFree(ptr->modulepath); xf86freeMatchGroupList(&ptr->match_driver); @@ -99,6 +101,19 @@ xf86parseOutputClassSection(void) else ptr->driver = xf86_lex_val.str; break; + case MODULE: + if (xf86getSubToken(&(ptr->comment)) != XF86_TOKEN_STRING) + Error(QUOTE_MSG, "Module"); + if (ptr->modules) { + char *path; + XNFasprintf(&path, "%s,%s", ptr->modules, xf86_lex_val.str); + free(xf86_lex_val.str); + free(ptr->modules); + ptr->modules = path; + } else { + ptr->modules = xf86_lex_val.str; + } + break; case MODULEPATH: if (xf86getSubToken(&(ptr->comment)) != XF86_TOKEN_STRING) Error(QUOTE_MSG, "ModulePath"); @@ -159,6 +174,10 @@ xf86printOutputClassSection(FILE * cf, XF86ConfOutputClassPtr ptr) fprintf(cf, "\tIdentifier \"%s\"\n", ptr->identifier); if (ptr->driver) fprintf(cf, "\tDriver \"%s\"\n", ptr->driver); + if (ptr->modules) + fprintf(cf, "\tModule \"%s\"\n", ptr->modules); + if (ptr->modulepath) + fprintf(cf, "\tModulePath \"%s\"\n", ptr->modulepath); xorg_list_for_each_entry(group, &ptr->match_driver, entry) { fprintf(cf, "\tMatchDriver \""); diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h index 8dd4a5d2b..3b9b868a5 100644 --- a/hw/xfree86/parser/xf86Parser.h +++ b/hw/xfree86/parser/xf86Parser.h @@ -359,6 +359,7 @@ typedef struct { GenericListRec list; char *identifier; char *driver; + char *modules; char *modulepath; struct xorg_list match_driver; XF86OptionPtr option_lst; diff --git a/hw/xfree86/parser/xf86tokens.h b/hw/xfree86/parser/xf86tokens.h index 11d0fa041..39b6de04b 100644 --- a/hw/xfree86/parser/xf86tokens.h +++ b/hw/xfree86/parser/xf86tokens.h @@ -255,6 +255,9 @@ typedef enum { NOMATCH_DRIVER, NOMATCH_TAG, NOMATCH_LAYOUT, + + /* OutputClass Tokens */ + MODULE, } ParserTokens; #endif /* _xf86_tokens_h */- void LoaderSetPath(const char *path); + void LoaderSetPath(const char *driver, const char *path); - The LoaderSetPath() function initialises a default - module search path. This must be called if calls to other functions - are to be made without explicitly specifying a module search path. - The search pathpath must be a string of one or more - comma separated absolute paths. Modules are expected to be located - below these paths, possibly in subdirectories of these paths. + TheLoaderSetPath() function initialises a search path + fordriver module, if it is non-NULL, + or a default module search path otherwise. This must be called if calls + to other functions are to be made without explicitly specifying a module + search path. The search pathpath must be a string + of one or more comma separated absolute paths. Modules are expected to be + located below these paths, possibly in subdirectories of these paths.