xfree86: Introduce OutputClass configuration

The OutputClass section provides a way to match output devices to a set
of given attributes and configure them. For now, only matching by kernel
driver name is supported. This can be used to determine what DDX module
to load for non-PCI output devices. DDX modules can ship an xorg.conf.d
snippet (e.g. in /usr/share/X11/xorg.conf.d) that looks like this:

	Section "OutputClass"
	    Identifer "NVIDIA Tegra open-source driver"
	    MatchDriver "tegra"
	    Driver "opentegra"
	EndSection

This will cause any device that's driven by the kernel driver named
"tegra" to use the "opentegra" DDX module.

See the OUTPUTCLASS section in xorg.conf(5) for more details.

Reviewed-by: Aaron Plattner <aplattner@nvidia.com>
Tested-By: Aaron Plattner <aplattner@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Tested-by: Rob Clark <robdclark@gmail.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
Thierry Reding 2014-02-13 13:42:05 +01:00 committed by Keith Packard
parent 856bb80cea
commit a270bb18ba
7 changed files with 267 additions and 0 deletions

View File

@ -171,6 +171,7 @@ The section names are:
.BR "Extensions " "Extension enabling"
.BR "InputDevice " "Input device description"
.BR "InputClass " "Input class description"
.BR "OutputClass " "Output class description"
.BR "Device " "Graphics device description"
.BR "VideoAdaptor " "Xv video adaptor description"
.BR "Monitor " "Monitor description"
@ -1190,6 +1191,82 @@ entries.
This optional entry specifies that the device should be ignored entirely,
and not added to the server. This can be useful when the device is handled
by another program and no X events should be generated.
.SH "OUTPUTCLASS SECTION"
The config file may have multiple
.B OutputClass
sections.
These sections are optional and are used to provide configuration for a
class of output devices as they are automatically added.
An output device can match more than one
.B OutputClass
section.
Each class can override settings from a previous class, so it is best to
arrange the sections with the most generic matches first.
.PP
.B OutputClass
sections have the following format:
.PP
.RS 4
.nf
.B "Section \*qOutputClass\*q"
.BI " Identifier \*q" name \*q
.I " entries"
.I " ..."
.B "EndSection"
.fi
.RE
.PP
The
.B Identifier
entry is required in all
.B OutputClass
sections.
All other entries are optional.
.PP
The
.B Identifier
entry specifies the unique name for this output class.
The
.B Driver
entry specifies the name of the driver to use for this output device.
After all classes have been examined, the
.RI \*q outputdriver \*q
module from the first
.B Driver
entry will be enabled when using the loadable server.
.PP
When an output device is automatically added, its characteristics are
checked against all
.B OutputClass
sections.
Each section can contain optional entries to narrow the match of the class.
If none of the optional entries appear, the
.B OutputClass
section is generic and will match any output device.
If more than one of these entries appear, they all must match for the
configuration to apply.
.PP
The following list of tokens can be matched against attributes of the device.
An entry can be constructed to match attributes from different devices by
separating arguments with a '|' character.
.PP
For example:
.PP
.RS 4
.nf
.B "Section \*qOutputClass\*q"
.B " Identifier \*qMy Class\*q"
.B " # kernel driver must be either foo or bar
.B " MatchDriver \*qfoo|bar\*q
.I " ..."
.B "EndSection"
.fi
.RE
.TP 7
.BI "MatchDriver \*q" matchdriver \*q
Check the case-sensitive string
.RI \*q matchdriver \*q
against the kernel driver of the device.
.SH "DEVICE SECTION"
The config file may have multiple
.B Device

View File

@ -14,6 +14,7 @@ INTERNAL_SOURCES= \
Flags.c \
Input.c \
InputClass.c \
OutputClass.c \
Layout.c \
Module.c \
Video.c \

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2014 NVIDIA Corporation. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif
#include "os.h"
#include "xf86Parser.h"
#include "xf86tokens.h"
#include "Configint.h"
static
xf86ConfigSymTabRec OutputClassTab[] = {
{ENDSECTION, "endsection"},
{IDENTIFIER, "identifier"},
{DRIVER, "driver"},
{MATCH_DRIVER, "matchdriver"},
{-1, ""},
};
#define CLEANUP xf86freeOutputClassList
#define TOKEN_SEP "|"
static void
add_group_entry(struct xorg_list *head, char **values)
{
xf86MatchGroup *group;
group = malloc(sizeof(*group));
if (group) {
group->values = values;
xorg_list_add(&group->entry, head);
}
}
XF86ConfOutputClassPtr
xf86parseOutputClassSection(void)
{
int has_ident = FALSE;
int token;
parsePrologue(XF86ConfOutputClassPtr, XF86ConfOutputClassRec)
/* Initialize MatchGroup lists */
xorg_list_init(&ptr->match_driver);
while ((token = xf86getToken(OutputClassTab)) != ENDSECTION) {
switch (token) {
case COMMENT:
ptr->comment = xf86addComment(ptr->comment, xf86_lex_val.str);
break;
case IDENTIFIER:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "Identifier");
if (has_ident == TRUE)
Error(MULTIPLE_MSG, "Identifier");
ptr->identifier = xf86_lex_val.str;
has_ident = TRUE;
break;
case DRIVER:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "Driver");
else
ptr->driver = xf86_lex_val.str;
break;
case MATCH_DRIVER:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "MatchDriver");
add_group_entry(&ptr->match_driver,
xstrtokenize(xf86_lex_val.str, TOKEN_SEP));
free(xf86_lex_val.str);
break;
case EOF_TOKEN:
Error(UNEXPECTED_EOF_MSG);
break;
default:
Error(INVALID_KEYWORD_MSG, xf86tokenString());
break;
}
}
if (!has_ident)
Error(NO_IDENT_MSG);
#ifdef DEBUG
printf("OutputClass section parsed\n");
#endif
return ptr;
}
void
xf86printOutputClassSection(FILE * cf, XF86ConfOutputClassPtr ptr)
{
const xf86MatchGroup *group;
char *const *cur;
while (ptr) {
fprintf(cf, "Section \"OutputClass\"\n");
if (ptr->comment)
fprintf(cf, "%s", ptr->comment);
if (ptr->identifier)
fprintf(cf, "\tIdentifier \"%s\"\n", ptr->identifier);
if (ptr->driver)
fprintf(cf, "\tDriver \"%s\"\n", ptr->driver);
xorg_list_for_each_entry(group, &ptr->match_driver, entry) {
fprintf(cf, "\tMatchDriver \"");
for (cur = group->values; *cur; cur++)
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
*cur);
fprintf(cf, "\"\n");
}
fprintf(cf, "EndSection\n\n");
ptr = ptr->list.next;
}
}
void
xf86freeOutputClassList(XF86ConfOutputClassPtr ptr)
{
XF86ConfOutputClassPtr prev;
while (ptr) {
xf86MatchGroup *group, *next;
char **list;
TestFree(ptr->identifier);
TestFree(ptr->comment);
TestFree(ptr->driver);
xorg_list_for_each_entry_safe(group, next, &ptr->match_driver, entry) {
xorg_list_del(&group->entry);
for (list = group->values; *list; list++)
free(*list);
free(group);
}
prev = ptr;
ptr = ptr->list.next;
free(prev);
}
}

View File

@ -57,6 +57,11 @@ XF86ConfInputClassPtr xf86parseInputClassSection(void);
void xf86printInputClassSection(FILE * f, XF86ConfInputClassPtr ptr);
void xf86freeInputClassList(XF86ConfInputClassPtr ptr);
/* OutputClass.c */
XF86ConfOutputClassPtr xf86parseOutputClassSection(void);
void xf86printOutputClassSection(FILE * f, XF86ConfOutputClassPtr ptr);
void xf86freeOutputClassList(XF86ConfOutputClassPtr ptr);
/* Layout.c */
XF86ConfLayoutPtr xf86parseLayoutSection(void);
void xf86printLayoutSection(FILE * cf, XF86ConfLayoutPtr ptr);

View File

@ -165,6 +165,12 @@ xf86readConfigFile(void)
HANDLE_LIST(conf_inputclass_lst,
xf86parseInputClassSection, XF86ConfInputClassPtr);
}
else if (xf86nameCompare(xf86_lex_val.str, "outputclass") == 0) {
free(xf86_lex_val.str);
xf86_lex_val.str = NULL;
HANDLE_LIST(conf_outputclass_lst, xf86parseOutputClassSection,
XF86ConfOutputClassPtr);
}
else if (xf86nameCompare(xf86_lex_val.str, "module") == 0) {
free(xf86_lex_val.str);
xf86_lex_val.str = NULL;

View File

@ -114,6 +114,8 @@ doWriteConfigFile(const char *filename, XF86ConfigPtr cptr)
xf86printInputClassSection(cf, cptr->conf_inputclass_lst);
xf86printOutputClassSection(cf, cptr->conf_outputclass_lst);
xf86printVideoAdaptorSection(cf, cptr->conf_videoadaptor_lst);
xf86printModesSection(cf, cptr->conf_modes_lst);

View File

@ -327,6 +327,14 @@ typedef struct {
char *comment;
} XF86ConfInputClassRec, *XF86ConfInputClassPtr;
typedef struct {
GenericListRec list;
char *identifier;
char *driver;
struct xorg_list match_driver;
char *comment;
} XF86ConfOutputClassRec, *XF86ConfOutputClassPtr;
/* Values for adj_where */
#define CONF_ADJ_OBSOLETE -1
#define CONF_ADJ_ABSOLUTE 0
@ -411,6 +419,7 @@ typedef struct {
XF86ConfScreenPtr conf_screen_lst;
XF86ConfInputPtr conf_input_lst;
XF86ConfInputClassPtr conf_inputclass_lst;
XF86ConfOutputClassPtr conf_outputclass_lst;
XF86ConfLayoutPtr conf_layout_lst;
XF86ConfVendorPtr conf_vendor_lst;
XF86ConfDRIPtr conf_dri;