summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2014-02-09 11:42:09 -0800
committerAaron Plattner <aplattner@nvidia.com>2014-02-09 11:42:09 -0800
commitabe140773cfba324528a5f4f9d55645037dd1d97 (patch)
treebb1a8bbce48a9ff393edde001ac758a71aa7f363
parentcb1c07a3374bfa2638e26ef7f3453e8b128e7d54 (diff)
334.16334.16
-rw-r--r--Makefile4
-rw-r--r--XF86Config-parser/Flags.c49
-rw-r--r--XF86Config-parser/Generate.c19
-rw-r--r--XF86Config-parser/xf86Parser.h19
-rw-r--r--common-utils/common-utils.c307
-rw-r--r--common-utils/common-utils.h89
-rw-r--r--common-utils/gen-manpage-opts-helper.c33
-rw-r--r--common-utils/msg.c416
-rw-r--r--common-utils/msg.h137
-rw-r--r--common-utils/src.mk2
-rw-r--r--extract_edids.c27
-rw-r--r--lscf.c9
-rw-r--r--make_usable.c12
-rw-r--r--multiple_screens.c407
-rw-r--r--nvidia-xconfig.c143
-rw-r--r--nvidia-xconfig.h6
-rw-r--r--option_table.h28
-rw-r--r--options.c34
-rw-r--r--query_gpu_info.c35
-rw-r--r--util.c43
-rw-r--r--utils.mk1
-rw-r--r--version.mk2
22 files changed, 1085 insertions, 737 deletions
diff --git a/Makefile b/Makefile
index 9b6e394..2370802 100644
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,7 @@ ifeq ($(MANPAGE_GZIP),1)
else
MANPAGE = $(MANPAGE_not_gzipped)
endif
-GEN_MANPAGE_OPTS = $(OUTPUTDIR)/gen-manpage-opts
+GEN_MANPAGE_OPTS = $(OUTPUTDIR_ABSOLUTE)/gen-manpage-opts
OPTIONS_1_INC = $(OUTPUTDIR)/options.1.inc
@@ -156,7 +156,7 @@ $(GEN_MANPAGE_OPTS): $(GEN_MANPAGE_OPTS_OBJS)
$(HOST_CFLAGS) $(HOST_LDFLAGS) $(HOST_BIN_LDFLAGS) $^ -o $@
$(OPTIONS_1_INC): $(GEN_MANPAGE_OPTS)
- @./$< > $@
+ @$< > $@
$(MANPAGE_not_gzipped): nvidia-xconfig.1.m4 $(OPTIONS_1_INC) $(VERSION_MK)
$(call quiet_cmd,M4) -D__HEADER__=$(AUTO_TEXT) -I $(OUTPUTDIR) \
diff --git a/XF86Config-parser/Flags.c b/XF86Config-parser/Flags.c
index 55720e0..3413edc 100644
--- a/XF86Config-parser/Flags.c
+++ b/XF86Config-parser/Flags.c
@@ -512,30 +512,29 @@ xconfigPrintOptionList(FILE *fp, XConfigOptionPtr list, int tabs)
* - If the extension can be enabled, this function returns NULL.
*
* - If the extension should be disabled, this function returns a
- * string that lists the conflicting options that are enabled.
+ * string that lists the conflicting options that are enabled. The string
+ * returned has to be freed by the caller.
*/
-const char *xconfigValidateComposite(XConfigPtr config,
- GenerateOptions *gop,
- int composite_specified,
- int xinerama_enabled,
- int depth,
- int overlay_enabled,
- int cioverlay_enabled,
- int ubb_enabled,
- int stereo_enabled)
+char *xconfigValidateComposite(XConfigPtr config,
+ GenerateOptions *gop,
+ int composite_specified,
+ int xinerama_enabled,
+ int depth,
+ int overlay_enabled,
+ int cioverlay_enabled,
+ int ubb_enabled,
+ int stereo_enabled)
{
- int i, n, disable_composite;
- static char err_str[256];
- int size = 256;
- char *s;
+ int i, n;
+ char *err_str;
const struct {
const char *name;
int value;
} composite_incompatible_options[] = {
- { "Xinerama", xinerama_enabled },
+ { "Xinerama", xinerama_enabled && !gop->xinerama_plus_composite_works },
{ "Overlay", overlay_enabled },
{ "CIOverlay", cioverlay_enabled },
{ "UBB", ubb_enabled },
@@ -558,34 +557,26 @@ const char *xconfigValidateComposite(XConfigPtr config,
return NULL;
}
- disable_composite = FALSE;
- s = err_str;
n = 0;
- err_str[0] = '\0';
+ err_str = NULL;
for (i = 0; i < ARRAY_LEN(composite_incompatible_options); i++) {
int value = composite_incompatible_options[i].value;
const char *name = composite_incompatible_options[i].name;
- int wrote;
if (value) {
- disable_composite = TRUE;
+ err_str = nv_prepend_to_string_list(err_str, name,
+ (n > 1) ? ", " : " or ");
n++;
-
- wrote = snprintf(s, size, "%s%s", (n > 1) ? " or " : "", name);
- if (wrote <= 0) {
- break;
- }
- size -= wrote;
- s += wrote;
}
}
/* Special case checking for depth 8 */
if (depth <= 8) {
- snprintf(s, size, "%sdepth=8", (n > 1) ? " or " : "");
+ err_str = nv_prepend_to_string_list(err_str, "depth=8",
+ (n > 1) ? ", " : " or ");
}
- return disable_composite ? err_str : NULL;
+ return err_str;
}
diff --git a/XF86Config-parser/Generate.c b/XF86Config-parser/Generate.c
index 0705b39..cdd7054 100644
--- a/XF86Config-parser/Generate.c
+++ b/XF86Config-parser/Generate.c
@@ -1321,7 +1321,8 @@ static int get_xserver_information(const char *versionString,
int *isXorg,
int *isModular,
int *autoloadsGLX,
- int *supportsExtensionSection)
+ int *supportsExtensionSection,
+ int *xineramaPlusCompositeWorks)
{
#define XSERVER_VERSION_FORMAT_1 "X Window System Version"
#define XSERVER_VERSION_FORMAT_2 "X.Org X Server"
@@ -1336,6 +1337,7 @@ static int get_xserver_information(const char *versionString,
*isModular = FALSE;
*autoloadsGLX = FALSE;
*supportsExtensionSection = FALSE;
+ *xineramaPlusCompositeWorks = FALSE;
return TRUE;
}
@@ -1400,6 +1402,17 @@ static int get_xserver_information(const char *versionString,
*autoloadsGLX = TRUE;
}
+ /*
+ * support for Xinerama and Composite at the same time works on X.Org
+ * xserver 1.15.
+ */
+
+ if ((major == 6) || (major == 7) || ((major == 1) && (minor < 15))) {
+ *xineramaPlusCompositeWorks = FALSE;
+ } else {
+ *xineramaPlusCompositeWorks = TRUE;
+ }
+
return TRUE;
} /* get_xserver_information() */
@@ -1435,6 +1448,7 @@ void xconfigGetXServerInUse(GenerateOptions *gop)
gop->supports_extension_section = FALSE;
gop->autoloads_glx = FALSE;
+ gop->xinerama_plus_composite_works = FALSE;
/* run `X -version` with a PATH that hopefully includes the X binary */
@@ -1464,7 +1478,8 @@ void xconfigGetXServerInUse(GenerateOptions *gop)
&isXorg,
&dummy, /* isModular */
&gop->autoloads_glx,
- &gop->supports_extension_section);
+ &gop->supports_extension_section,
+ &gop->xinerama_plus_composite_works);
if (found) {
if (isXorg) {
diff --git a/XF86Config-parser/xf86Parser.h b/XF86Config-parser/xf86Parser.h
index 1135ffd..89c1569 100644
--- a/XF86Config-parser/xf86Parser.h
+++ b/XF86Config-parser/xf86Parser.h
@@ -624,6 +624,7 @@ typedef struct {
int supports_extension_section;
int autoloads_glx;
+ int xinerama_plus_composite_works;
} GenerateOptions;
@@ -762,15 +763,15 @@ void xconfigGenerateLoadDefaultOptions(GenerateOptions *gop);
void xconfigGetXServerInUse(GenerateOptions *gop);
-const char *xconfigValidateComposite(XConfigPtr config,
- GenerateOptions *gop,
- int composite_enabled,
- int xinerama_enabled,
- int depth,
- int overlay_enabled,
- int cioverlay_enabled,
- int ubb_enabled,
- int stereo);
+char *xconfigValidateComposite(XConfigPtr config,
+ GenerateOptions *gop,
+ int composite_enabled,
+ int xinerama_enabled,
+ int depth,
+ int overlay_enabled,
+ int cioverlay_enabled,
+ int ubb_enabled,
+ int stereo);
/*
* check (and update, if necessary) the inputs in the specified layout
diff --git a/common-utils/common-utils.c b/common-utils/common-utils.c
index 9bd349e..f581f0d 100644
--- a/common-utils/common-utils.c
+++ b/common-utils/common-utils.c
@@ -29,8 +29,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
-#include <sys/ioctl.h>
-#include <sys/termios.h>
#include "common-utils.h"
@@ -354,311 +352,6 @@ char *nv_prepend_to_string_list(char *list, const char *item, const char *delim)
}
-/****************************************************************************/
-/* TextRows helper functions */
-/****************************************************************************/
-
-/*
- * nv_format_text_rows() - this function breaks the given string str
- * into some number of rows, where each row is not longer than the
- * specified width.
- *
- * If prefix is non-NULL, the first line is prepended with the prefix,
- * and subsequent lines are indented to line up with the prefix.
- *
- * If word_boundary is TRUE, then attempt to only break lines on
- * boundaries between words.
- */
-
-TextRows *nv_format_text_rows(const char *prefix,
- const char *str,
- int width, int word_boundary)
-{
- int len, prefix_len, z, w, i;
- char *line, *buf, *local_prefix, *a, *b, *c;
- TextRows *t;
-
- /* initialize the TextRows structure */
-
- t = (TextRows *) malloc(sizeof(TextRows));
-
- if (!t) return NULL;
-
- t->t = NULL;
- t->n = 0;
- t->m = 0;
-
- if (!str) return t;
-
- buf = strdup(str);
-
- if (!buf) return t;
-
- z = strlen(buf); /* length of entire string */
- a = buf; /* pointer to the start of the string */
-
- /* initialize the prefix fields */
-
- if (prefix) {
- prefix_len = strlen(prefix);
- local_prefix = strdup(prefix);
- } else {
- prefix_len = 0;
- local_prefix = NULL;
- }
-
- /* adjust the max width for any prefix */
-
- w = width - prefix_len;
-
- do {
- /*
- * if the string will fit on one line, point b to the end of the
- * string
- */
-
- if (z < w) b = a + z;
-
- /*
- * if the string won't fit on one line, move b to where the
- * end of the line should be, and then move b back until we
- * find a space; if we don't find a space before we back b all
- * the way up to a, just assign b to where the line should end.
- */
-
- else {
- b = a + w;
-
- if (word_boundary) {
- while ((b >= a) && (!isspace(*b))) b--;
- if (b <= a) b = a + w;
- }
- }
-
- /* look for any newline between a and b, and move b to it */
-
- for (c = a; c < b; c++) if (*c == '\n') { b = c; break; }
-
- /*
- * copy the string that starts at a and ends at b, prepending
- * with a prefix, if present
- */
-
- len = b-a;
- len += prefix_len;
- line = (char *) malloc(len+1);
- if (local_prefix) strncpy(line, local_prefix, prefix_len);
- strncpy(line + prefix_len, a, len - prefix_len);
- line[len] = '\0';
-
- /* append the new line to the array of text rows */
-
- t->t = (char **) realloc(t->t, sizeof(char *) * (t->n + 1));
- t->t[t->n] = line;
- t->n++;
-
- if (t->m < len) t->m = len;
-
- /*
- * adjust the length of the string and move the pointer to the
- * beginning of the new line
- */
-
- z -= (b - a + 1);
- a = b + 1;
-
- /* move to the first non whitespace character (excluding newlines) */
-
- if (word_boundary && isspace(*b)) {
- while ((z) && (isspace(*a)) && (*a != '\n')) a++, z--;
- } else {
- if (!isspace(*b)) z++, a--;
- }
-
- if (local_prefix) {
- for (i = 0; i < prefix_len; i++) local_prefix[i] = ' ';
- }
-
- } while (z > 0);
-
- if (local_prefix) free(local_prefix);
- free(buf);
-
- return t;
-}
-
-
-/*
- * nv_text_rows_append() - append the given msg to the existing TextRows
- */
-
-void nv_text_rows_append(TextRows *t, const char *msg)
-{
- int len;
-
- t->t = realloc(t->t, sizeof(char *) * (t->n + 1));
-
- if (msg) {
- t->t[t->n] = strdup(msg);
- len = strlen(msg);
- if (t->m < len) t->m = len;
- } else {
- t->t[t->n] = NULL;
- }
-
- t->n++;
-}
-
-/*
- * nv_concat_text_rows() - concatenate two text rows, storing the
- * result in t0
- */
-
-void nv_concat_text_rows(TextRows *t0, TextRows *t1)
-{
- int n, i;
-
- n = t0->n + t1->n;
-
- t0->t = realloc(t0->t, sizeof(char *) * n);
-
- for (i = 0; i < t1->n; i++) {
- t0->t[i + t0->n] = strdup(t1->t[i]);
- }
-
- t0->m = NV_MAX(t0->m, t1->m);
- t0->n = n;
-
-} /* nv_concat_text_rows() */
-
-
-/*
- * nv_free_text_rows() - free the TextRows data structure allocated by
- * nv_format_text_rows()
- */
-
-void nv_free_text_rows(TextRows *t)
-{
- int i;
-
- if (!t) return;
- for (i = 0; i < t->n; i++) free(t->t[i]);
- if (t->t) free(t->t);
- free(t);
-
-} /* nv_free_text_rows() */
-
-
-/****************************************************************************/
-/* printing helper functions */
-/****************************************************************************/
-
-#define DEFAULT_WIDTH 75
-
-static unsigned short __terminal_width = 0;
-
-/*
- * reset_current_terminal_width() - if new_val is zero, then use the
- * TIOCGWINSZ ioctl to get the current width of the terminal, and
- * assign it the value to __terminal_width. If the ioctl fails, use a
- * hardcoded constant. If new_val is non-zero, then use new_val.
- */
-
-void reset_current_terminal_width(unsigned short new_val)
-{
- struct winsize ws;
-
- if (new_val) {
- __terminal_width = new_val;
- return;
- }
-
- if (ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
- __terminal_width = DEFAULT_WIDTH;
- } else {
- __terminal_width = ws.ws_col - 1;
- }
-}
-
-/*
- * Call silence_fmt(1) to turn fmtout(), fmtoutp() and format() into noops.
- */
-static int __silent = 0;
-
-void silence_fmt(int val)
-{
- __silent = val;
-}
-
-
-static void vformat(FILE *stream, const int wb,
- const char *prefix, const char *buf)
-{
- int i;
- TextRows *t;
-
- if (!__terminal_width) reset_current_terminal_width(0);
-
- t = nv_format_text_rows(prefix, buf, __terminal_width, wb);
-
- for (i = 0; i < t->n; i++) fprintf(stream, "%s\n", t->t[i]);
-
- nv_free_text_rows(t);
-}
-
-
-#define NV_VFORMAT(stream, wb, prefix, fmt) \
-do { \
- char *buf; \
- NV_VSNPRINTF(buf, fmt); \
- vformat(stream, wb, prefix, buf); \
- free (buf); \
-} while(0)
-
-
-void fmtout(const char *fmt, ...)
-{
- if (__silent > 0) {
- return;
- }
- NV_VFORMAT(stdout, TRUE, NULL, fmt);
-}
-
-
-void fmtoutp(const char *prefix, const char *fmt, ...)
-{
- if (__silent > 0) {
- return;
- }
- NV_VFORMAT(stdout, TRUE, prefix, fmt);
-}
-
-
-void fmterr(const char *fmt, ...)
-{
- vformat(stderr, 0, NULL, "");
- NV_VFORMAT(stderr, TRUE, "ERROR: ", fmt);
- vformat(stderr, 0, NULL, "");
-}
-
-
-void fmtwarn(const char *fmt, ...)
-{
- vformat(stderr, 0, NULL, "");
- NV_VFORMAT(stderr, TRUE, "WARNING: ", fmt);
- vformat(stderr, 0, NULL, "");
-}
-
-
-void fmt(FILE *stream, const char *prefix, const char *fmt, ...)
-{
- if (__silent > 0) {
- return;
- }
- NV_VFORMAT(stream, TRUE, prefix, fmt);
-}
-
-
/*
* Read from the given FILE stream until a newline, EOF, or nul
* terminator is encountered, writing data into a growable buffer.
diff --git a/common-utils/common-utils.h b/common-utils/common-utils.h
index e9d505e..3db71b6 100644
--- a/common-utils/common-utils.h
+++ b/common-utils/common-utils.h
@@ -22,6 +22,8 @@
#include <sys/types.h>
#include <stdint.h>
+#include "msg.h"
+
#if !defined(TRUE)
#define TRUE 1
#endif
@@ -38,32 +40,6 @@
#define TAB " "
#define BIGTAB " "
-#define VERBOSITY_NONE 0 /* nothing */
-#define VERBOSITY_ERROR 1 /* errors only */
-#define VERBOSITY_DEPRECATED 2 /* errors, deprecation messages and warnings */
-#define VERBOSITY_WARNING 3 /* errors and warnings */
-#define VERBOSITY_ALL 4 /* errors, warnings and other info */
-
-#define VERBOSITY_DEFAULT VERBOSITY_ERROR
-
-/*
- * Define a printf format attribute macro. This definition is based on the one
- * from Xfuncproto.h, available in the 'xproto' package at
- * http://xorg.freedesktop.org/releases/individual/proto/
- */
-
-#if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)
-# define NV_ATTRIBUTE_PRINTF(x,y) __attribute__((__format__(__printf__,x,y)))
-#else /* not gcc >= 2.3 */
-# define NV_ATTRIBUTE_PRINTF(x,y)
-#endif
-
-typedef struct {
- char **t; /* the text rows */
- int n; /* number of rows */
- int m; /* maximum row length */
-} TextRows;
-
void *nvalloc(size_t size);
char *nvstrcat(const char *str, ...);
void *nvrealloc(void *ptr, size_t size);
@@ -79,22 +55,6 @@ void nvfree(void *s);
char *tilde_expansion(const char *str);
char *nv_prepend_to_string_list(char *list, const char *item, const char *delim);
-TextRows *nv_format_text_rows(const char *prefix,
- const char *str,
- int width, int word_boundary);
-void nv_text_rows_append(TextRows *t, const char *msg);
-void nv_concat_text_rows(TextRows *t0, TextRows *t1);
-void nv_free_text_rows(TextRows *t);
-
-void reset_current_terminal_width(unsigned short new_val);
-
-void silence_fmt(int val);
-void fmtout(const char *fmt, ...) NV_ATTRIBUTE_PRINTF(1, 2);
-void fmtoutp(const char *prefix, const char *fmt, ...) NV_ATTRIBUTE_PRINTF(2, 3);
-void fmterr(const char *fmt, ...) NV_ATTRIBUTE_PRINTF(1, 2);
-void fmtwarn(const char *fmt, ...) NV_ATTRIBUTE_PRINTF(1, 2);
-void fmt(FILE *stream, const char *prefix, const char *fmt, ...) NV_ATTRIBUTE_PRINTF(3, 4);
-
char *fget_next_line(FILE *fp, int *eof);
int nv_open(const char *pathname, int flags, mode_t mode);
@@ -107,51 +67,6 @@ char *nv_trim_space(char *string);
char *nv_trim_char(char *string, char trim);
char *nv_trim_char_strict(char *string, char trim);
-/*
- * NV_VSNPRINTF(): macro that assigns buf using vsnprintf(). This is
- * correct for differing semantics of the vsnprintf() return value:
- *
- * -1 when the buffer is not long enough (glibc < 2.1)
- *
- * or
- *
- * the length the string would have been if the buffer had been large
- * enough (glibc >= 2.1)
- *
- * This macro allocates memory for buf; the caller should free it when
- * done.
- */
-
-#define NV_FMT_BUF_LEN 256
-
-#define NV_VSNPRINTF(buf, fmt) \
-do { \
- if (!fmt) { \
- (buf) = NULL; \
- } else { \
- va_list ap; \
- int len, current_len = NV_FMT_BUF_LEN; \
- \
- while (1) { \
- (buf) = nvalloc(current_len); \
- \
- va_start(ap, fmt); \
- len = vsnprintf((buf), current_len, (fmt), ap); \
- va_end(ap); \
- \
- if ((len > -1) && (len < current_len)) { \
- break; \
- } else if (len > -1) { \
- current_len = len + 1; \
- } else { \
- current_len += NV_FMT_BUF_LEN; \
- } \
- \
- nvfree(buf); \
- } \
- } \
-} while (0)
-
#if defined(__GNUC__)
# define NV_INLINE __inline__
#else
diff --git a/common-utils/gen-manpage-opts-helper.c b/common-utils/gen-manpage-opts-helper.c
index 532015d..c05ef38 100644
--- a/common-utils/gen-manpage-opts-helper.c
+++ b/common-utils/gen-manpage-opts-helper.c
@@ -17,16 +17,18 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
+#include <stdlib.h>
#include "nvgetopt.h"
#include "gen-manpage-opts-helper.h"
+#include "common-utils.h"
static void print_option(const NVGetoptOption *o)
{
char scratch[64], *s;
int j, len;
- int italics, bold, omitWhiteSpace;
+ int italics, bold, omitWhiteSpace, firstchar;
/* if we are going to need the argument, process it now */
if (o->flags & NVGETOPT_HAS_ARGUMENT) {
@@ -88,13 +90,15 @@ static void print_option(const NVGetoptOption *o)
* '&' : toggles italics on and off
* '^' : toggles bold on and off
* '-' : is backslashified: "\-"
+ * '.' : must not be the first character of a line
*
- * Whitespace is omitted when italics or bold is on
+ * Trailing whitespace is omitted when italics or bold is on
*/
- italics = 0;
- bold = 0;
- omitWhiteSpace = 0;
+ italics = FALSE;
+ bold = FALSE;
+ omitWhiteSpace = FALSE;
+ firstchar = TRUE;
for (s = o->description; s && *s; s++) {
@@ -107,6 +111,7 @@ static void print_option(const NVGetoptOption *o)
}
omitWhiteSpace = italics;
italics = !italics;
+ firstchar = TRUE;
break;
case '^':
if (bold) {
@@ -116,19 +121,33 @@ static void print_option(const NVGetoptOption *o)
}
omitWhiteSpace = bold;
bold = !bold;
+ firstchar = TRUE;
break;
case '-':
printf("\\-");
- omitWhiteSpace = 0;
+ omitWhiteSpace = FALSE;
+ firstchar = FALSE;
break;
case ' ':
if (!omitWhiteSpace) {
printf(" ");
+ firstchar = FALSE;
}
break;
+ case '.':
+ if (firstchar) {
+ fprintf(stderr, "Error: *roff can't start a line with '.' "
+ "If you used '&' or '^' to format text in the "
+ "description of the '%s' option, please add some "
+ "text before the end of the sentence, so that a "
+ "valid manpage can be generated.\n", o->name);
+ exit(1);
+ }
+ /* fall through */
default:
printf("%c", *s);
- omitWhiteSpace = 0;
+ omitWhiteSpace = FALSE;
+ firstchar = FALSE;
break;
}
}
diff --git a/common-utils/msg.c b/common-utils/msg.c
new file mode 100644
index 0000000..cdd3c4f
--- /dev/null
+++ b/common-utils/msg.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2004 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses>.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#if defined(__sun)
+#include <sys/termios.h>
+#endif
+
+#include "msg.h"
+#include "common-utils.h"
+
+
+/*
+ * verbosity, controls output of errors, warnings and other
+ * information.
+ */
+
+static NvVerbosity __verbosity = NV_VERBOSITY_DEFAULT;
+
+NvVerbosity nv_get_verbosity()
+{
+ return __verbosity;
+}
+
+void nv_set_verbosity(NvVerbosity level)
+{
+ __verbosity = level;
+}
+
+
+/****************************************************************************/
+/* Formatted I/O functions */
+/****************************************************************************/
+
+#define DEFAULT_WIDTH 75
+
+static unsigned short __terminal_width = 0;
+
+/*
+ * reset_current_terminal_width() - if new_val is zero, then use the
+ * TIOCGWINSZ ioctl to get the current width of the terminal, and
+ * assign it the value to __terminal_width. If the ioctl fails, use a
+ * hardcoded constant. If new_val is non-zero, then use new_val.
+ */
+
+void reset_current_terminal_width(unsigned short new_val)
+{
+ struct winsize ws;
+
+ if (new_val) {
+ __terminal_width = new_val;
+ return;
+ }
+
+ if (ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
+ __terminal_width = DEFAULT_WIDTH;
+ } else {
+ __terminal_width = ws.ws_col - 1;
+ }
+}
+
+
+static void format(FILE *stream, const char *prefix, const char *buf,
+ const int whitespace)
+{
+ int i;
+ TextRows *t;
+
+ if (!__terminal_width) reset_current_terminal_width(0);
+
+ t = nv_format_text_rows(prefix, buf, __terminal_width, whitespace);
+
+ for (i = 0; i < t->n; i++) fprintf(stream, "%s\n", t->t[i]);
+
+ nv_free_text_rows(t);
+}
+
+
+#define NV_FORMAT(stream, prefix, fmt, whitespace) \
+do { \
+ char *buf; \
+ NV_VSNPRINTF(buf, fmt); \
+ format(stream, prefix, buf, whitespace); \
+ free (buf); \
+} while(0)
+
+
+/*
+ * nv_error_msg() - print an error message, nicely formatted using the
+ * format() function.
+ *
+ * This function should be used for all errors.
+ */
+
+void nv_error_msg(const char *fmt, ...)
+{
+ if (__verbosity < NV_VERBOSITY_ERROR) return;
+
+ format(stderr, NULL, "", TRUE);
+ NV_FORMAT(stderr, "ERROR: ", fmt, TRUE);
+ format(stderr, NULL, "", TRUE);
+} /* nv_error_msg() */
+
+
+/*
+ * nv_deprecated_msg() - print a deprecation message, nicely formatted using
+ * the format() function.
+ *
+ * This function should be used for all deprecation messages.
+ */
+
+void nv_deprecated_msg(const char *fmt, ...)
+{
+ if (__verbosity < NV_VERBOSITY_DEPRECATED) return;
+
+ format(stderr, NULL, "", TRUE);
+ NV_FORMAT(stderr, "DEPRECATED: ", fmt, TRUE);
+ format(stderr, NULL, "", TRUE);
+}
+
+
+/*
+ * nv_warning_msg() - print a warning message, nicely formatted using
+ * the format() function.
+ *
+ * This function should be used for all warnings.
+ */
+
+void nv_warning_msg(const char *fmt, ...)
+{
+ if (__verbosity < NV_VERBOSITY_WARNING) return;
+
+ format(stderr, NULL, "", TRUE);
+ NV_FORMAT(stderr, "WARNING: ", fmt, TRUE);
+ format(stderr, NULL, "", TRUE);
+} /* nv_warning_msg() */
+
+
+/*
+ * nv_info_msg() - print an info message, nicely formatted using
+ * the format() function.
+ *
+ * This function should be used to display verbose information.
+ */
+
+void nv_info_msg(const char *prefix, const char *fmt, ...)
+{
+ if (__verbosity < NV_VERBOSITY_ALL) return;
+
+ NV_FORMAT(stdout, prefix, fmt, TRUE);
+} /* nv_info_msg() */
+
+
+/*
+ * nv_info_msg_to_file() - Prints the message, just like nv_info_msg()
+ * using format() the difference is, it prints to any stream defined by
+ * the corresponding argument.
+ */
+
+void nv_info_msg_to_file(FILE *stream, const char *prefix, const char *fmt, ...)
+{
+ if (__verbosity < NV_VERBOSITY_ALL) return;
+
+ NV_FORMAT(stream, prefix, fmt, TRUE);
+} /* nv_info_msg_to_file() */
+
+
+/*
+ * nv_msg() - print a message, nicely formatted using the format()
+ * function.
+ *
+ * This function should be used to display messages independent
+ * of the verbosity level.
+ */
+
+void nv_msg(const char *prefix, const char *fmt, ...)
+{
+ NV_FORMAT(stdout, prefix, fmt, TRUE);
+} /* nv_msg() */
+
+
+/*
+ * nv_msg_preserve_whitespace() - Prints the message, just like nv_msg()
+ * using format(), the difference is, whitespace characters are not
+ * skipped during the text processing.
+ */
+
+void nv_msg_preserve_whitespace(const char *prefix, const char *fmt, ...)
+{
+ NV_FORMAT(stdout, prefix, fmt, FALSE);
+} /* nv_msg_preserve_whitespace() */
+
+
+/*
+ * XXX gcc's '-ansi' option causes vsnprintf to not be defined, so
+ * declare the prototype here.
+ */
+
+#if defined(__STRICT_ANSI__)
+int vsnprintf(char *str, size_t size, const char *format,
+ va_list ap);
+#endif
+
+
+/****************************************************************************/
+/* TextRows helper functions */
+/****************************************************************************/
+
+/*
+ * nv_format_text_rows() - this function breaks the given string str
+ * into some number of rows, where each row is not longer than the
+ * specified width.
+ *
+ * If prefix is non-NULL, the first line is prepended with the prefix,
+ * and subsequent lines are indented to line up with the prefix.
+ *
+ * If word_boundary is TRUE, then attempt to only break lines on
+ * boundaries between words.
+ */
+
+TextRows *nv_format_text_rows(const char *prefix, const char *str, int width,
+ int word_boundary)
+{
+ int len, prefix_len, z, w, i;
+ char *line, *buf, *local_prefix, *a, *b, *c;
+ TextRows *t;
+
+ /* initialize the TextRows structure */
+
+ t = (TextRows *) malloc(sizeof(TextRows));
+
+ if (!t) return NULL;
+
+ t->t = NULL;
+ t->n = 0;
+ t->m = 0;
+
+ if (!str) return t;
+
+ buf = strdup(str);
+
+ if (!buf) return t;
+
+ z = strlen(buf); /* length of entire string */
+ a = buf; /* pointer to the start of the string */
+
+ /* initialize the prefix fields */
+
+ if (prefix) {
+ prefix_len = strlen(prefix);
+ local_prefix = strdup(prefix);
+ } else {
+ prefix_len = 0;
+ local_prefix = NULL;
+ }
+
+ /* adjust the max width for any prefix */
+
+ w = width - prefix_len;
+
+ do {
+ /*
+ * if the string will fit on one line, point b to the end of the
+ * string
+ */
+
+ if (z < w) b = a + z;
+
+ /*
+ * if the string won't fit on one line, move b to where the
+ * end of the line should be, and then move b back until we
+ * find a space; if we don't find a space before we back b all
+ * the way up to a, just assign b to where the line should end.
+ */
+
+ else {
+ b = a + w;
+
+ if (word_boundary) {
+ while ((b >= a) && (!isspace(*b))) b--;
+ if (b <= a) b = a + w;
+ }
+ }
+
+ /* look for any newline between a and b, and move b to it */
+
+ for (c = a; c < b; c++) if (*c == '\n') { b = c; break; }
+
+ /*
+ * copy the string that starts at a and ends at b, prepending
+ * with a prefix, if present
+ */
+
+ len = b-a;
+ len += prefix_len;
+ line = (char *) malloc(len+1);
+ if (local_prefix) strncpy(line, local_prefix, prefix_len);
+ strncpy(line + prefix_len, a, len - prefix_len);
+ line[len] = '\0';
+
+ /* append the new line to the array of text rows */
+
+ t->t = (char **) realloc(t->t, sizeof(char *) * (t->n + 1));
+ t->t[t->n] = line;
+ t->n++;
+
+ if (t->m < len) t->m = len;
+
+ /*
+ * adjust the length of the string and move the pointer to the
+ * beginning of the new line
+ */
+
+ z -= (b - a + 1);
+ a = b + 1;
+
+ /* move to the first non whitespace character (excluding newlines) */
+
+ if (word_boundary && isspace(*b)) {
+ while ((z) && (isspace(*a)) && (*a != '\n')) a++, z--;
+ } else {
+ if (!isspace(*b)) z++, a--;
+ }
+
+ if (local_prefix) {
+ for (i = 0; i < prefix_len; i++) local_prefix[i] = ' ';
+ }
+
+ } while (z > 0);
+
+ if (local_prefix) free(local_prefix);
+ free(buf);
+
+ return t;
+}
+
+
+/*
+ * nv_text_rows_append() - append the given msg to the existing TextRows
+ */
+
+void nv_text_rows_append(TextRows *t, const char *msg)
+{
+ int len;
+
+ t->t = realloc(t->t, sizeof(char *) * (t->n + 1));
+
+ if (msg) {
+ t->t[t->n] = strdup(msg);
+ len = strlen(msg);
+ if (t->m < len) t->m = len;
+ } else {
+ t->t[t->n] = NULL;
+ }
+
+ t->n++;
+}
+
+/*
+ * nv_concat_text_rows() - concatenate two text rows, storing the
+ * result in t0
+ */
+
+void nv_concat_text_rows(TextRows *t0, TextRows *t1)
+{
+ int n, i;
+
+ n = t0->n + t1->n;
+
+ t0->t = realloc(t0->t, sizeof(char *) * n);
+
+ for (i = 0; i < t1->n; i++) {
+ t0->t[i + t0->n] = strdup(t1->t[i]);
+ }
+
+ t0->m = NV_MAX(t0->m, t1->m);
+ t0->n = n;
+
+} /* nv_concat_text_rows() */
+
+
+/*
+ * nv_free_text_rows() - free the TextRows data structure allocated by
+ * nv_format_text_rows()
+ */
+
+void nv_free_text_rows(TextRows *t)
+{
+ int i;
+
+ if (!t) return;
+ for (i = 0; i < t->n; i++) free(t->t[i]);
+ if (t->t) free(t->t);
+ free(t);
+
+} /* nv_free_text_rows() */
+
diff --git a/common-utils/msg.h b/common-utils/msg.h
new file mode 100644
index 0000000..5e32c19
--- /dev/null
+++ b/common-utils/msg.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2004 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses>.
+ */
+
+#ifndef __MSG_H__
+#define __MSG_H__
+
+#include <stdarg.h>
+#include <stdio.h>
+
+
+/*
+ * Define a printf format attribute macro. This definition is based on the one
+ * from Xfuncproto.h, available in the 'xproto' package at
+ * http://xorg.freedesktop.org/releases/individual/proto/
+ */
+
+#if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)
+# define NV_ATTRIBUTE_PRINTF(x,y) __attribute__((__format__(__printf__,x,y)))
+#else /* not gcc >= 2.3 */
+# define NV_ATTRIBUTE_PRINTF(x,y)
+#endif
+
+
+/*
+ * NV_VSNPRINTF(): macro that assigns buf using vsnprintf(). This is
+ * correct for differing semantics of the vsnprintf() return value:
+ *
+ * -1 when the buffer is not long enough (glibc < 2.1)
+ *
+ * or
+ *
+ * the length the string would have been if the buffer had been large
+ * enough (glibc >= 2.1)
+ *
+ * This macro allocates memory for buf; the caller should free it when
+ * done.
+ */
+
+#define NV_FMT_BUF_LEN 256
+
+#define NV_VSNPRINTF(buf, fmt) \
+do { \
+ if (!fmt) { \
+ (buf) = NULL; \
+ } else { \
+ va_list ap; \
+ int len, current_len = NV_FMT_BUF_LEN; \
+ \
+ while (1) { \
+ (buf) = nvalloc(current_len); \
+ \
+ va_start(ap, fmt); \
+ len = vsnprintf((buf), current_len, (fmt), ap); \
+ va_end(ap); \
+ \
+ if ((len > -1) && (len < current_len)) { \
+ break; \
+ } else if (len > -1) { \
+ current_len = len + 1; \
+ } else { \
+ current_len += NV_FMT_BUF_LEN; \
+ } \
+ \
+ nvfree(buf); \
+ } \
+ } \
+} while (0)
+
+
+/*
+ * verbosity, controls output of errors, warnings and other
+ * information.
+ */
+
+typedef enum {
+ NV_VERBOSITY_NONE = 0, /* no errors, warnings or info */
+ NV_VERBOSITY_ERROR, /* errors only */
+ NV_VERBOSITY_DEPRECATED, /* errors and deprecation messages */
+ NV_VERBOSITY_WARNING, /* errors and all warnings */
+ NV_VERBOSITY_ALL, /* errors, all warnings and other info */
+ NV_VERBOSITY_DEFAULT = NV_VERBOSITY_ALL
+} NvVerbosity;
+
+NvVerbosity nv_get_verbosity(void);
+void nv_set_verbosity(NvVerbosity level);
+
+
+/*
+ * Formatted I/O functions
+ */
+
+void reset_current_terminal_width(unsigned short new_val);
+
+void nv_error_msg(const char *fmt, ...) NV_ATTRIBUTE_PRINTF(1, 2);
+void nv_deprecated_msg(const char *fmt, ...) NV_ATTRIBUTE_PRINTF(1, 2);
+void nv_warning_msg(const char *fmt, ...) NV_ATTRIBUTE_PRINTF(1, 2);
+void nv_info_msg(const char *prefix,
+ const char *fmt, ...) NV_ATTRIBUTE_PRINTF(2, 3);
+void nv_info_msg_to_file(FILE *stream,
+ const char *prefix,
+ const char *fmt, ...) NV_ATTRIBUTE_PRINTF(3, 4);
+void nv_msg(const char *prefix, const char *fmt, ...) NV_ATTRIBUTE_PRINTF(2, 3);
+void nv_msg_preserve_whitespace(const char *prefix,
+ const char *fmt, ...) NV_ATTRIBUTE_PRINTF(2, 3);
+
+
+/*
+ * TextRows structure and helper functions
+ */
+
+typedef struct {
+ char **t; /* the text rows */
+ int n; /* number of rows */
+ int m; /* maximum row length */
+} TextRows;
+
+TextRows *nv_format_text_rows(const char *prefix, const char *str, int width,
+ int word_boundary);
+void nv_text_rows_append(TextRows *t, const char *msg);
+void nv_concat_text_rows(TextRows *t0, TextRows *t1);
+void nv_free_text_rows(TextRows *t);
+
+
+#endif /* __MSG_H__ */
diff --git a/common-utils/src.mk b/common-utils/src.mk
index 12ba143..6dbed7a 100644
--- a/common-utils/src.mk
+++ b/common-utils/src.mk
@@ -2,9 +2,11 @@
COMMON_UTILS_SRC += nvgetopt.c
COMMON_UTILS_SRC += common-utils.c
+COMMON_UTILS_SRC += msg.c
COMMON_UTILS_EXTRA_DIST += nvgetopt.h
COMMON_UTILS_EXTRA_DIST += common-utils.h
+COMMON_UTILS_EXTRA_DIST += msg.h
COMMON_UTILS_EXTRA_DIST += src.mk
# gen-manpage-opts-helper.c is listed in EXTRA_DIST, rather than SRC,
diff --git a/extract_edids.c b/extract_edids.c
index cd0569d..bcc8389 100644
--- a/extract_edids.c
+++ b/extract_edids.c
@@ -95,6 +95,7 @@
#include <strings.h> /* bzero() */
#include "nvidia-xconfig.h"
+#include "msg.h"
#define NIBBLE_TO_HEX(n) (((n) <= 9) ? ('0' + (n)) : ('a' - 0xa + (n)))
@@ -198,22 +199,22 @@ int extract_edids(Options *op)
fd = open(op->extract_edids_from_file, O_RDONLY);
if (fd == -1) {
- fmterr("Unable to open file \"%s\".", op->extract_edids_from_file);
+ nv_error_msg("Unable to open file \"%s\".", op->extract_edids_from_file);
goto done;
}
ret = fstat(fd, &stat_buf);
if (ret == -1) {
- fmterr("Unable to get length of file \"%s\".",
- op->extract_edids_from_file);
+ nv_error_msg("Unable to get length of file \"%s\".",
+ op->extract_edids_from_file);
goto done;
}
file.length = stat_buf.st_size;
if (file.length == 0) {
- fmterr("File \"%s\" is empty.", op->extract_edids_from_file);
+ nv_error_msg("File \"%s\" is empty.", op->extract_edids_from_file);
goto done;
}
@@ -223,7 +224,7 @@ int extract_edids(Options *op)
MAP_SHARED, fd, 0);
if (file.start == (void *) -1) {
- fmterr("Unable to map file \"%s\".", op->extract_edids_from_file);
+ nv_error_msg("Unable to map file \"%s\".", op->extract_edids_from_file);
goto done;
}
@@ -298,9 +299,9 @@ int extract_edids(Options *op)
* writeEdidFile; it will unique-ify from there
*/
- fmtout("");
- fmtout("Found %d EDID%s in \"%s\".",
- nEdids, (nEdids == 1) ? "": "s", op->extract_edids_from_file);
+ nv_info_msg(NULL, "");
+ nv_info_msg(NULL, "Found %d EDID%s in \"%s\".",
+ nEdids, (nEdids == 1) ? "": "s", op->extract_edids_from_file);
filename = findFileName(op->extract_edids_output_file);
@@ -317,7 +318,7 @@ int extract_edids(Options *op)
nvfree(filename);
- fmtout("");
+ nv_info_msg(NULL, "");
return funcRet;
@@ -1075,11 +1076,11 @@ static int writeEdidFile(EdidPtr pEdid, char *filename)
/* report what happened */
if (ret) {
- fmtout(" Wrote EDID for \"%s\" to \"%s\" (%d bytes).",
- pEdid->name, working_filename, pEdid->size);
+ nv_info_msg(NULL, " Wrote EDID for \"%s\" to \"%s\" (%d bytes).",
+ pEdid->name, working_filename, pEdid->size);
} else {
- fmterr("Failed to write EDID for \"%s\" to \"%s\" (%s)",
- pEdid->name, working_filename, msg);
+ nv_error_msg("Failed to write EDID for \"%s\" to \"%s\" (%s)",
+ pEdid->name, working_filename, msg);
}
nvfree(working_filename);
diff --git a/lscf.c b/lscf.c
index 19f4e72..a804148 100644
--- a/lscf.c
+++ b/lscf.c
@@ -20,6 +20,7 @@
#include <libscf.h>
+#include "msg.h"
static int lscf_init_handle(scf_handle_t **scf_handle,
scf_scope_t **scf_scope);
@@ -75,8 +76,8 @@ done:
scf_handle_destroy(scf_handle);
}
if (!status) {
- fmterr("Unable to set X server default depth through "
- "Solaris Service Management Facility");
+ nv_error_msg("Unable to set X server default depth through "
+ "Solaris Service Management Facility");
}
return status;
}
@@ -118,8 +119,8 @@ done:
scf_handle_destroy(scf_handle);
}
if (!status) {
- fmterr("Unable to get X server default depth from "
- "Solaris Service Management Facility");
+ nv_error_msg("Unable to get X server default depth from "
+ "Solaris Service Management Facility");
}
return status;
}
diff --git a/make_usable.c b/make_usable.c
index dd73347..3858b4a 100644
--- a/make_usable.c
+++ b/make_usable.c
@@ -28,6 +28,7 @@
#include "nvidia-xconfig.h"
#include "xf86Parser.h"
#include "configProcs.h"
+#include "msg.h"
static void ensure_module_loaded(XConfigPtr config, char *name);
@@ -139,7 +140,7 @@ XConfigLayoutPtr get_layout(Options *op, XConfigPtr config)
layout = xconfigFindLayout(op->layout, config->layouts);
if (!layout) {
- fmterr("Unable to find layout \"%s\".\n", op->layout);
+ nv_error_msg("Unable to find layout \"%s\".\n", op->layout);
return NULL;
}
} else {
@@ -147,7 +148,7 @@ XConfigLayoutPtr get_layout(Options *op, XConfigPtr config)
/* otherwise, use the first layout in the config file */
if (!config->layouts) {
- fmterr("unable to select ScreenLayout to use.\n");
+ nv_error_msg("unable to select ScreenLayout to use.\n");
return NULL;
}
@@ -331,9 +332,10 @@ static void update_depth(Options *op, XConfigScreenPtr screen)
int scf_depth;
if (read_scf_depth(&scf_depth) && scf_depth != screen->defaultdepth) {
- fmtwarn("The default depth of %d read from "
- "the Solaris Management Facility is set as the default "
- "depth for screen \"%s\"", scf_depth, screen->identifier);
+ nv_warning_msg("The default depth of %d read from "
+ "the Solaris Management Facility is set as the "
+ "default depth for screen \"%s\"", scf_depth,
+ screen->identifier);
screen->defaultdepth = scf_depth;
}
}
diff --git a/multiple_screens.c b/multiple_screens.c
index 295318a..25813ee 100644
--- a/multiple_screens.c
+++ b/multiple_screens.c
@@ -22,6 +22,7 @@
#include "nvidia-xconfig.h"
#include "xf86Parser.h"
+#include "msg.h"
#include <stdlib.h>
#include <string.h>
@@ -36,8 +37,8 @@ static int disable_separate_x_screens(Options *op, XConfigPtr config,
static int set_xinerama(int xinerama_enabled, XConfigLayoutPtr layout);
static XConfigDisplayPtr clone_display_list(XConfigDisplayPtr display0);
-static XConfigDevicePtr clone_device(XConfigDevicePtr device0);
-static XConfigScreenPtr clone_screen(XConfigScreenPtr screen0);
+static XConfigDevicePtr clone_device(XConfigDevicePtr device0, int idx);
+static XConfigScreenPtr clone_screen(XConfigScreenPtr screen0, int idx);
static void create_adjacencies(Options *op, XConfigPtr config,
XConfigLayoutPtr layout);
@@ -52,6 +53,199 @@ static int only_one_screen(Options *op, XConfigPtr config,
XConfigLayoutPtr layout);
/*
+ * get_screens_to_clone() - try to detect automatically how many heads has each
+ * device in order to use that number to create more than two separate X
+ * screens. If the user specifies the option --num-x-screens <quantity>, that
+ * value is used. If neither the user specifies the quantity or the number of
+ * heads can be detected automatically, it uses 2 heads (the standard
+ * behavior). This function returns an array of size nscreens with the number
+ * of screens to clone per screen candidate. The caller is responsible of
+ * freeing the memory of that array.
+ */
+static int* get_screens_to_clone(Options *op,
+ const XConfigScreenPtr *screen_candidates,
+ int nscreens)
+{
+ DevicesPtr pDevices;
+ int *screens_to_clone, *supported_screens;
+ int i, j, devs_found;
+
+ screens_to_clone = nvalloc(nscreens * sizeof(int));
+ supported_screens = nvalloc(nscreens * sizeof(int));
+
+ /* Detect the number of supported screens per screen candidate */
+ devs_found = FALSE;
+ pDevices = find_devices(op);
+ if (pDevices) {
+ for (i = 0; i < nscreens; i++) {
+ int bus, slot, scratch;
+
+ if (!screen_candidates[i]) {
+ continue;
+ }
+
+ /* parse the bus id for this candidate screen */
+ if (!xconfigParsePciBusString(screen_candidates[i]->device->busid,
+ &bus, &slot, &scratch)) {
+ continue;
+ }
+
+ for (j = 0; j < pDevices->nDevices; j++) {
+ if ((pDevices->devices[j].dev.bus == bus) &&
+ (pDevices->devices[j].dev.slot == slot)) {
+
+ if (pDevices->devices[j].crtcs > 0) {
+ supported_screens[i] = pDevices->devices[j].crtcs;
+ }
+ break;
+ }
+ }
+ }
+ free_devices(pDevices);
+ devs_found = TRUE;
+ }
+
+ /* If user has defined a number of screens per GPU, use that value */
+ if (op->num_x_screens > 0) {
+ for (i = 0; i < nscreens; i++) {
+ if (!screen_candidates[i]) {
+ continue;
+ }
+
+ /* Print error when user specifies more X screens than supported */
+ if (devs_found && op->num_x_screens > supported_screens[i]) {
+ nv_warning_msg("Number of X screens specified is higher than the "
+ "supported quantity (%d)", supported_screens[i]);
+ }
+
+ screens_to_clone[i] = op->num_x_screens;
+ }
+
+ goto done;
+ }
+
+ for (i = 0; i < nscreens; i++) {
+ if (screen_candidates[i]) {
+ if (devs_found) {
+ /* If devices found, use the supported screens number */
+ screens_to_clone[i] = supported_screens[i];
+ }
+ else {
+ /* Default behavior (2 heads per GPU) */
+ screens_to_clone[i] = 2;
+ }
+ }
+ }
+
+done:
+ nvfree(supported_screens);
+ return screens_to_clone;
+}
+
+/*
+ * clean_screen_list() - Used by enable_separate_x_screens and
+ * disable_separate_x_screens. Given the array screen_list and the config
+ * pointer, this function will leave only one screen per different busid in both
+ * screen_list array and config->screens list (i.e all the resulting screens in
+ * screen_list and config->screens will have an unique busid).
+ */
+static void clean_screen_list(XConfigScreenPtr *screen_list,
+ XConfigPtr config,
+ int nscreens)
+{
+ int i, j;
+ int *bus, *slot, scratch;
+
+ /* trim out duplicates and get the bus ids*/
+
+ bus = nvalloc(sizeof(int) * nscreens);
+ slot = nvalloc(sizeof(int) * nscreens);
+
+ for (i = 0; i < nscreens; i++) {
+ bus[i] = -1;
+ }
+
+ for (i = 0; i < nscreens; i++) {
+ if (!screen_list[i] || (bus[i] == -1 &&
+ !xconfigParsePciBusString(screen_list[i]->device->busid,
+ &bus[i], &slot[i], &scratch))) {
+ continue;
+ }
+
+ for (j = i+1; j < nscreens; j++) {
+ if (!screen_list[j] || (bus[j] == -1 &&
+ !xconfigParsePciBusString(screen_list[j]->device->busid,
+ &bus[j], &slot[j], &scratch))) {
+ continue;
+ }
+
+ if ((bus[i] == bus[j]) && (slot[i] == slot[j])) {
+ screen_list[j] = NULL;
+ }
+ }
+ }
+
+ /*
+ * for every screen in the screen list, scan through all
+ * screens; if any screen, other than *this* screen has the same
+ * busid, remove it
+ */
+
+ for (i = 0; i < nscreens; i++) {
+ XConfigScreenPtr screen, prev;
+ int bus0, slot0;
+
+ if (!screen_list[i]) {
+ continue;
+ }
+
+ screen = config->screens;
+ prev = NULL;
+
+ while (screen) {
+ if (screen_list[i] == screen) {
+ goto next_screen;
+ }
+ if (!screen->device) {
+ goto next_screen;
+ }
+ if (!screen->device->busid) {
+ goto next_screen;
+ }
+ if (!xconfigParsePciBusString(screen->device->busid,
+ &bus0, &slot0, &scratch)) {
+ goto next_screen;
+ }
+
+ if ((bus[i] == bus0) && (slot[i] == slot0)) {
+ XConfigScreenPtr next;
+
+ if (prev) {
+ prev->next = screen->next;
+ }
+ else {
+ config->screens = screen->next;
+ }
+
+ next = screen->next;
+ screen->next = NULL;
+ xconfigFreeScreenList(&screen);
+ screen = next;
+ }
+ else {
+
+ next_screen:
+
+ prev = screen;
+ screen = screen->next;
+ }
+ }
+
+ screen_list[i]->device->screen = -1;
+ }
+}
+
+/*
* apply_multi_screen_options() - there are 4 options that can affect
* multiple X screens:
*
@@ -148,17 +342,17 @@ DevicesPtr find_devices(Options *op)
nvfree(lib_path);
if (!lib_handle) {
- fmtwarn("error opening %s: %s.", __LIB_NAME, dlerror());
+ nv_warning_msg("error opening %s: %s.", __LIB_NAME, dlerror());
return NULL;
}
-#define __GET_FUNC(proc, name) \
- (proc) = dlsym(lib_handle, (name)); \
- if (!(proc)) { \
- fmtwarn("error retrieving symbol %s from %s: %s", \
- (name), __LIB_NAME, dlerror()); \
- dlclose(lib_handle); \
- return NULL; \
+#define __GET_FUNC(proc, name) \
+ (proc) = dlsym(lib_handle, (name)); \
+ if (!(proc)) { \
+ nv_warning_msg("error retrieving symbol %s from %s: %s", \
+ (name), __LIB_NAME, dlerror()); \
+ dlclose(lib_handle); \
+ return NULL; \
}
/* required functions */
@@ -275,8 +469,8 @@ DevicesPtr find_devices(Options *op)
fail:
- fmtwarn("Unable to use the nvidia-cfg library to query NVIDIA "
- "hardware.");
+ nv_warning_msg("Unable to use the nvidia-cfg library to query NVIDIA "
+ "hardware.");
for (i = 0; i < pDevices->nDevices; i++) {
/* close the opened device */
@@ -354,16 +548,13 @@ static int set_xinerama(int xinerama_enabled, XConfigLayoutPtr layout)
* step 2: assign a busID to every screen that is in the list (if
* BusIDs are not already assigned)
*
- * step 3: for every candidate screen, check if it is already one of
- * multiple screens on a gpu; if so, then it is not eligible for
- * cloning. Note that this has to check all screens in the adjacency
- * list, not just the ones in the candidate list.
+ * step 3: clean the candidate list
+ *
+ * step 4: get the number of clones per screen candidate
*
* step 4: clone each eligible screen
*
* step 5: update adjacency list (just wipe the list and restart)
- *
- * XXX we need to check that there are actually 2 CRTCs on this GPU
*/
static int enable_separate_x_screens(Options *op, XConfigPtr config,
@@ -371,16 +562,17 @@ static int enable_separate_x_screens(Options *op, XConfigPtr config,
{
XConfigScreenPtr screen, *screenlist = NULL;
XConfigAdjacencyPtr adj;
+ int* screens_to_clone = NULL;
int i, nscreens = 0;
int have_busids;
- /* build the list of screens that are candidate to be cloned */
+ /* step 1: build the list of screens that are candidate to be cloned */
if (op->screen) {
screen = xconfigFindScreen(op->screen, config->screens);
if (!screen) {
- fmterr("Unable to find screen '%s'.", op->screen);
+ nv_error_msg("Unable to find screen '%s'.", op->screen);
return FALSE;
}
@@ -400,7 +592,7 @@ static int enable_separate_x_screens(Options *op, XConfigPtr config,
if (!nscreens) return FALSE;
- /* do all screens in the list have a bus ID? */
+ /* step 2: do all screens in the list have a bus ID? */
have_busids = TRUE;
@@ -426,9 +618,9 @@ static int enable_separate_x_screens(Options *op, XConfigPtr config,
pDevices = find_devices(op);
if (!pDevices) {
- fmterr("Unable to determine number or location of "
- "GPUs in system; cannot "
- "honor '--separate-x-screens' option.");
+ nv_error_msg("Unable to determine number or location of "
+ "GPUs in system; cannot "
+ "honor '--separate-x-screens' option.");
return FALSE;
}
@@ -453,65 +645,36 @@ static int enable_separate_x_screens(Options *op, XConfigPtr config,
free_devices(pDevices);
}
-
- /*
- * step 3: for every candidate screen, check if it is already one
- * of multiple screens on a gpu; if so, then it is not eligible
- * for cloning. Note that this has to check all screens in the
- * adjacency list, not just the ones in the candidate list
- */
-
- for (i = 0; i < nscreens; i++) {
- int bus0, bus1, slot0, slot1, scratch;
- if (!screenlist[i]) continue;
-
- /* parse the bus id for this candidate screen */
- if (!xconfigParsePciBusString(screenlist[i]->device->busid,
- &bus0, &slot0, &scratch)) {
- /* parsing failed; this screen is no longer a candidate */
- screenlist[i] = NULL;
- continue;
- }
+ /* step 3 */
+ clean_screen_list(screenlist, config, nscreens);
- /*
- * scan through all the screens; if any screen, other than
- * *this* screen, have the same busid, then this screen is no
- * longer a candidate
- */
-
- for (screen = config->screens; screen; screen = screen->next) {
- if (screen == screenlist[i]) continue;
- if (!screen->device) continue;
- if (!screen->device->busid) continue;
- if (!xconfigParsePciBusString(screen->device->busid,
- &bus1, &slot1, &scratch)) continue;
- if ((bus0 == bus1) && (slot0 == slot1)) {
- screenlist[i] = NULL; /* no longer a candidate */
- break;
- }
- }
- }
+ /* step 4 */
+ screens_to_clone = get_screens_to_clone(op, screenlist, nscreens);
- /* clone each eligible screen */
+ /* step 5: clone each eligible screen */
for (i = 0; i < nscreens; i++) {
if (!screenlist[i]) continue;
- clone_screen(screenlist[i]);
+
+ while (--screens_to_clone[i] > 0) {
+ clone_screen(screenlist[i], screens_to_clone[i]);
+ }
}
+
+ nvfree(screens_to_clone);
- /*
- * wipe the existing adjacencies and recreate them
- *
- * XXX we should really only use the screens in the current
- * adjacency list, plus the new cloned screens, when building the
- * new adjacencies
- */
+ /* step 6: wipe the existing adjacencies and recreate them */
xconfigFreeAdjacencyList(&layout->adjacencies);
create_adjacencies(op, config, layout);
+ /* free unused device and monitor sections */
+
+ free_unused_devices(op, config);
+ free_unused_monitors(op, config);
+
/* free stuff */
free(screenlist);
@@ -533,27 +696,25 @@ static int enable_separate_x_screens(Options *op, XConfigPtr config,
* step 2: narrow that list down to screens that have a busid
* specified
*
- * step 3: find all other screens that have the same busid and remove
- * them
+ * step 3: clean the candidate list
*
- * step 3: recompute the adjacency list
+ * step 4: recompute the adjacency list
*/
static int disable_separate_x_screens(Options *op, XConfigPtr config,
XConfigLayoutPtr layout)
{
- XConfigScreenPtr screen, prev, next, *screenlist = NULL;
+ XConfigScreenPtr screen, *screenlist = NULL;
XConfigAdjacencyPtr adj;
- int i, j, nscreens = 0;
- int *bus, *slot, scratch;
+ int i, nscreens = 0;
- /* build the list of screens that are candidate to be de-cloned */
+ /* step 1: build the list of screens that are candidate to be de-cloned */
if (op->screen) {
screen = xconfigFindScreen(op->screen, config->screens);
if (!screen) {
- fmterr("Unable to find screen '%s'.", op->screen);
+ nv_error_msg("Unable to find screen '%s'.", op->screen);
return FALSE;
}
@@ -572,83 +733,27 @@ static int disable_separate_x_screens(Options *op, XConfigPtr config,
}
/*
- * limit the list to screens that have a BusID; parse the busIDs
+ * step 2: limit the list to screens that have a BusID; parse the busIDs
* while we're at it
*/
- bus = nvalloc(sizeof(int) * nscreens);
- slot = nvalloc(sizeof(int) * nscreens);
-
for (i = 0; i < nscreens; i++) {
+ int bus, slot, scratch;
if (screenlist[i] &&
screenlist[i]->device &&
screenlist[i]->device->busid &&
xconfigParsePciBusString(screenlist[i]->device->busid,
- &bus[i], &slot[i], &scratch)) {
+ &bus, &slot, &scratch)) {
// this screen has a valid busid
} else {
screenlist[i] = NULL;
}
}
-
- /* trim out duplicates */
-
- for (i = 0; i < nscreens; i++) {
-
- if (!screenlist[i]) continue;
-
- for (j = i+1; j < nscreens; j++) {
- if (!screenlist[j]) continue;
- if ((bus[i] == bus[j]) && (slot[i] == slot[j])) {
- screenlist[j] = NULL;
- }
- }
- }
-
- /*
- * for every screen in the de-clone list, scan through all
- * screens; if any screen, other than *this* screen has the same
- * busid, remove it
- */
-
- for (i = 0; i < nscreens; i++) {
- int bus0, slot0;
- if (!screenlist[i]) continue;
-
- screen = config->screens;
- prev = NULL;
-
- while (screen) {
- if (screenlist[i] == screen) goto next_screen;
- if (!screen->device) goto next_screen;
- if (!screen->device->busid) goto next_screen;
- if (!xconfigParsePciBusString(screen->device->busid,
- &bus0, &slot0, &scratch))
- goto next_screen;
-
- if ((bus0 == bus[i]) && (slot0 == slot[i])) {
- if (prev) {
- prev->next = screen->next;
- } else {
- config->screens = screen->next;
- }
- next = screen->next;
- screen->next = NULL;
- xconfigFreeScreenList(&screen);
- screen = next;
- } else {
-
- next_screen:
-
- prev = screen;
- screen = screen->next;
- }
- }
- screenlist[i]->device->screen = -1;
- }
+ /* step 3 */
+ clean_screen_list(screenlist, config, nscreens);
- /* wipe the existing adjacencies and recreate them */
+ /* step 4: wipe the existing adjacencies and recreate them */
xconfigFreeAdjacencyList(&layout->adjacencies);
@@ -662,8 +767,6 @@ static int disable_separate_x_screens(Options *op, XConfigPtr config,
/* free stuff */
free(screenlist);
- free(bus);
- free(slot);
return TRUE;
@@ -703,13 +806,13 @@ static XConfigDisplayPtr clone_display_list(XConfigDisplayPtr display0)
* the screen indices as approprate for multiple X screens on one GPU
*/
-static XConfigDevicePtr clone_device(XConfigDevicePtr device0)
+static XConfigDevicePtr clone_device(XConfigDevicePtr device0, int idx)
{
XConfigDevicePtr device;
device = nvalloc(sizeof(XConfigDeviceRec));
- device->identifier = nvstrcat(device0->identifier, " (2nd)", NULL);
+ device->identifier = nvasprintf("%s (%d)", device0->identifier, idx);
if (device0->vendor) device->vendor = nvstrdup(device0->vendor);
if (device0->board) device->board = nvstrdup(device0->board);
@@ -722,9 +825,9 @@ static XConfigDevicePtr clone_device(XConfigDevicePtr device0)
/* these are needed for multiple X screens on one GPU */
- device->screen = 1;
+ device->screen = idx;
device0->screen = 0;
-
+
device->chipid = -1;
device->chiprev = -1;
device->irq = -1;
@@ -743,17 +846,17 @@ static XConfigDevicePtr clone_device(XConfigDevicePtr device0)
/*
- * clone_screen() - duplicate the given screen, for use as the second
+ * clone_screen() - duplicate the given screen, for use as the ith
* X screen on one GPU
*/
-static XConfigScreenPtr clone_screen(XConfigScreenPtr screen0)
+static XConfigScreenPtr clone_screen(XConfigScreenPtr screen0, int idx)
{
XConfigScreenPtr screen = nvalloc(sizeof(XConfigScreenRec));
- screen->identifier = nvstrcat(screen0->identifier, " (2nd)", NULL);
+ screen->identifier = nvasprintf("%s (%d)", screen0->identifier, idx);
- screen->device = clone_device(screen0->device);
+ screen->device = clone_device(screen0->device, idx);
screen->device_name = nvstrdup(screen->device->identifier);
screen->monitor = screen0->monitor;
@@ -833,8 +936,8 @@ static int enable_all_gpus(Options *op, XConfigPtr config,
pDevices = find_devices(op);
if (!pDevices) {
- fmterr("Unable to determine number of GPUs in system; cannot "
- "honor '--enable-all-gpus' option.");
+ nv_error_msg("Unable to determine number of GPUs in system; cannot "
+ "honor '--enable-all-gpus' option.");
return FALSE;
}
diff --git a/nvidia-xconfig.c b/nvidia-xconfig.c
index 5f2339e..17d0eab 100644
--- a/nvidia-xconfig.c
+++ b/nvidia-xconfig.c
@@ -33,6 +33,7 @@
#include "nvidia-xconfig.h"
#include "nvgetopt.h"
+#include "msg.h"
#define TAB " "
#define BIGTAB " "
@@ -49,31 +50,31 @@ extern const char *pNV_ID;
static void print_version(void)
{
- fmtout("");
- fmtout("%s", pNV_ID);
- fmtoutp(TAB, "The NVIDIA X Configuration Tool.");
- fmtout("");
- fmtoutp(TAB, "This program is used to manipulate X configuration files, "
- "specifically to enable NVIDIA X driver functionality.");
- fmtout("");
- fmtoutp(TAB, "Copyright (C) 2005 - 2010 NVIDIA Corporation.");
- fmtout("");
-
+ nv_info_msg(NULL, "");
+ nv_info_msg(NULL, "%s", pNV_ID);
+ nv_info_msg(TAB, "The NVIDIA X Configuration Tool.");
+ nv_info_msg(NULL, "");
+ nv_info_msg(TAB, "This program is used to manipulate X configuration files, "
+ "specifically to enable NVIDIA X driver functionality.");
+ nv_info_msg(NULL, "");
+ nv_info_msg(TAB, "Copyright (C) 2005 - 2010 NVIDIA Corporation.");
+ nv_info_msg(NULL, "");
} /* print_version() */
static void print_summary(void)
{
- fmtout("");
- fmtoutp(TAB, "In its normal operation, nvidia-xconfig finds the system "
- "X configuration file (or generates a new X configuration if it "
- "cannot find the system file), makes sure the configuration is "
- "usable by the NVIDIA X driver, applies any updates requested "
- "on the commandline, and writes the new configuration to file.");
- fmtout("");
- fmtoutp(TAB, "Please see the NVIDIA README for a description of NVIDIA "
- "X configuration file options.");
- fmtout("");
+ nv_info_msg(NULL, "");
+ nv_info_msg(TAB, "In its normal operation, nvidia-xconfig finds the system "
+ "X configuration file (or generates a new X configuration "
+ "if it cannot find the system file), makes sure the "
+ "configuration is usable by the NVIDIA X driver, applies "
+ "any updates requested on the commandline, and writes the "
+ "new configuration to file.");
+ nv_info_msg(NULL, "");
+ nv_info_msg(TAB, "Please see the NVIDIA README for a description of NVIDIA "
+ "X configuration file options.");
+ nv_info_msg(NULL, "");
}
@@ -87,9 +88,9 @@ static void print_summary(void)
static void print_help_helper(const char *name, const char *description)
{
- fmtoutp(TAB, "%s", name);
- fmtoutp(BIGTAB, "%s", description);
- fmtout("");
+ nv_info_msg(TAB, "%s", name);
+ nv_info_msg(BIGTAB, "%s", description);
+ nv_info_msg(NULL, "");
}
static void print_help(int advanced)
@@ -99,9 +100,9 @@ static void print_help(int advanced)
print_version();
print_summary();
- fmtout("");
- fmtout("nvidia-xconfig [options]");
- fmtout("");
+ nv_info_msg(NULL, "");
+ nv_info_msg(NULL, "nvidia-xconfig [options]");
+ nv_info_msg(NULL, "");
if (!advanced) {
/* only print options with the ALWAYS flag */
@@ -153,7 +154,7 @@ static void parse_commandline(Options *op, int argc, char *argv[])
case 'T': op->post_tree = TRUE; break;
case 'h': print_help(FALSE); exit(0); break;
case 'A': print_help(TRUE); exit(0); break;
- case 's': silence_fmt(1); break;
+ case 's': nv_set_verbosity(NV_VERBOSITY_WARNING); break;
case 'a': op->enable_all_gpus = TRUE; break;
case '1': op->only_one_screen = TRUE; break;
@@ -602,6 +603,23 @@ static void parse_commandline(Options *op, int argc, char *argv[])
op->restore_original_backup = TRUE;
break;
+ case NUM_X_SCREENS_OPTION:
+
+ if (intval < 1) {
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Invalid number of X screens: %d.\n", intval);
+ fprintf(stderr, "\n");
+ goto fail;
+ }
+
+ /* Enable separate X screens */
+ set_boolean_option(op,
+ XCONFIG_BOOL_VAL(SEPARATE_X_SCREENS_BOOL_OPTION) -
+ XCONFIG_BOOL_OPTION_START, TRUE);
+
+ op->num_x_screens = intval;
+ break;
+
default:
goto fail;
}
@@ -639,11 +657,13 @@ static Options *load_default_options(void)
op = (Options *) nvalloc(sizeof(Options));
if (!op) return NULL;
+ op->depth = 24;
op->transparent_index = -1;
op->stereo = -1;
op->cool_bits = -1;
op->nvidia_3dvision_display_type = -1;
op->tv_over_scan = -1.0;
+ op->num_x_screens = -1;
xconfigGenerateLoadDefaultOptions(&op->gop);
@@ -687,8 +707,8 @@ static int backup_file(Options *op, const char *orig_filename,
if (access(filename, F_OK) == 0) {
if (unlink(filename) != 0) {
- fmterr("Unable to create backup file '%s' (%s)",
- filename, strerror(errno));
+ nv_error_msg("Unable to create backup file '%s' (%s)",
+ filename, strerror(errno));
goto done;
}
}
@@ -700,7 +720,7 @@ static int backup_file(Options *op, const char *orig_filename,
goto done;
}
- fmtout("Backed up file '%s' as '%s'", orig_filename, filename);
+ nv_info_msg(NULL, "Backed up file '%s' as '%s'", orig_filename, filename);
ret = TRUE;
done:
@@ -783,8 +803,8 @@ static int restore_backup(Options *op, XConfigPtr config, const char *suffix)
int ret = FALSE;
if (lstat(backup, &st) != 0) {
- fmterr("Unable to restore from original backup file '%s' (%s)",
- backup, strerror(errno));
+ nv_error_msg("Unable to restore from original backup file '%s' (%s)",
+ backup, strerror(errno));
goto done;
}
@@ -797,8 +817,8 @@ static int restore_backup(Options *op, XConfigPtr config, const char *suffix)
st.st_uid != 0 /* not owned by root*/ ||
(st.st_gid != 0 && (st.st_mode & S_IWGRP)) /* non-root group write */ ||
(st.st_mode & S_IWOTH) /* world writable */ ) {
- fmterr("The permissions of the original backup file '%s' are too loose "
- "to be trusted. The file will not be restored.", backup);
+ nv_error_msg("The permissions of the original backup file '%s' are too "
+ "loose to be trusted. The file will not be restored.", backup);
goto done;
}
@@ -809,8 +829,8 @@ static int restore_backup(Options *op, XConfigPtr config, const char *suffix)
if (st.st_size == 0) {
if (unlink(filename) != 0) {
- fmterr("Unable to remove file '%s' (%s)",
- filename, strerror(errno));
+ nv_error_msg("Unable to remove file '%s' (%s)",
+ filename, strerror(errno));
goto done;
}
} else {
@@ -826,19 +846,20 @@ static int restore_backup(Options *op, XConfigPtr config, const char *suffix)
if (access(backup, F_OK) == 0) {
if (unlink(backup) != 0) {
- fmterr("Unable to remove backup file '%s' (%s)",
- backup, strerror(errno));
+ nv_error_msg("Unable to remove backup file '%s' (%s)",
+ backup, strerror(errno));
goto done;
}
}
if (st.st_size == 0) {
- fmtout("The backup file '%s' was empty. This usually means that nvidia-"
- "xconfig did not find an X configuration file the first time it "
- "was run. The X configuration file '%s' was deleted.",
- backup, filename);
+ nv_info_msg(NULL, "The backup file '%s' was empty. This usually means "
+ "that nvidia-xconfig did not find an X configuration "
+ "file the first time it was run. The X configuration "
+ "file '%s' was deleted.",
+ backup, filename);
} else {
- fmtout("Restored backup file '%s' to '%s'", backup, filename);
+ nv_info_msg(NULL, "Restored backup file '%s' to '%s'", backup, filename);
}
ret = TRUE;
@@ -878,7 +899,7 @@ static int write_xconfig(Options *op, XConfigPtr config, int first_touch)
tmp = nvstrdup(filename);
d = dirname(tmp);
if (access(d, W_OK) != 0) {
- fmterr("Unable to write to directory '%s'.", d);
+ nv_error_msg("Unable to write to directory '%s'.", d);
goto done;
}
@@ -900,7 +921,8 @@ static int write_xconfig(Options *op, XConfigPtr config, int first_touch)
else if (first_touch) {
char *fakeorig = nvstrcat(filename, ORIG_SUFFIX, NULL);
if (!copy_file("/dev/null", fakeorig, 0644)) {
- fmtwarn("Unable to write an empty backup file \"%s\".", fakeorig);
+ nv_warning_msg("Unable to write an empty backup file \"%s\".",
+ fakeorig);
}
free(fakeorig);
}
@@ -908,14 +930,14 @@ static int write_xconfig(Options *op, XConfigPtr config, int first_touch)
/* write the config file */
if (!xconfigWriteConfigFile(filename, config)) {
- fmterr("Unable to write file \"%s\"; please use the "
- "\"--output-xconfig\" commandline "
- "option to specify an alternative output file.", filename);
+ nv_error_msg("Unable to write file \"%s\"; please use the "
+ "\"--output-xconfig\" commandline option to specify "
+ "an alternative output file.", filename);
goto done;
}
- fmtout("New X configuration file written to '%s'", filename);
- fmtout("");
+ nv_info_msg(NULL, "New X configuration file written to '%s'", filename);
+ nv_info_msg(NULL, "");
/* Set the default depth in the Solaris Management Facility
@@ -1054,10 +1076,10 @@ static XConfigPtr find_system_xconfig(Options *op)
filename = xconfigOpenConfigFile(op->xconfig, op->gop.x_project_root);
if (filename) {
- fmtout("");
- fmtout("Using X configuration file: \"%s\".", filename);
+ nv_info_msg(NULL, "");
+ nv_info_msg(NULL, "Using X configuration file: \"%s\".", filename);
} else {
- fmtwarn("Unable to locate/open X configuration file.");
+ nv_warning_msg("Unable to locate/open X configuration file.");
return NULL;
}
@@ -1136,12 +1158,12 @@ static int update_xconfig(Options *op, XConfigPtr config)
}
if (op->screen && !updated) {
- fmterr("Unable to find screen '%s'", op->screen);
+ nv_error_msg("Unable to find screen '%s'", op->screen);
return FALSE;
}
if (op->device && !updated) {
- fmterr("Unable to find device '%s'", op->device);
+ nv_error_msg("Unable to find device '%s'", op->device);
return FALSE;
}
@@ -1177,7 +1199,6 @@ int main(int argc, char *argv[])
XConfigPtr config = NULL;
int first_touch = 0;
-
/* Load defaults */
op = load_default_options();
@@ -1196,15 +1217,15 @@ int main(int argc, char *argv[])
*/
if (op->keyboard_list) {
- fmtout("\nPossible keyboard types; the short name is what should be "
- "passed to the \"--keyboard\" option.\n\n");
+ nv_info_msg(NULL, "\nPossible keyboard types; the short name is what "
+ "should be passed to the \"--keyboard\" option.\n\n");
xconfigGeneratePrintPossibleKeyboards();
return 0;
}
if (op->mouse_list) {
- fmtout("\nPossible mouse types; the short name is what should be "
- "passed to the \"--mouse\" option.\n\n");
+ nv_info_msg(NULL, "\nPossible mouse types; the short name is what should "
+ "be passed to the \"--mouse\" option.\n\n");
xconfigGeneratePrintPossibleMice();
return 0;
}
@@ -1265,7 +1286,7 @@ int main(int argc, char *argv[])
*/
if (!config) {
- fmterr("Unable to generate a usable X configuration file.");
+ nv_error_msg("Unable to generate a usable X configuration file.");
return 1;
}
diff --git a/nvidia-xconfig.h b/nvidia-xconfig.h
index 6d5b10e..85ae21e 100644
--- a/nvidia-xconfig.h
+++ b/nvidia-xconfig.h
@@ -66,8 +66,10 @@
#define PRESERVE_BUSID_BOOL_OPTION 40
#define BASE_MOSAIC_BOOL_OPTION 41
#define ALLOW_EMPTY_INITIAL_CONFIGURATION 42
+#define DELETE_UNUSED_DP12_DPYS 43
+#define INBAND_STEREO_SIGNALING 44
-#define XCONFIG_BOOL_OPTION_COUNT (ALLOW_EMPTY_INITIAL_CONFIGURATION + 1)
+#define XCONFIG_BOOL_OPTION_COUNT (INBAND_STEREO_SIGNALING + 1)
/* # of 32-bit variables needed to hold all the boolean options (bits) */
#define XCONFIG_BOOL_OPTION_SLOTS \
@@ -121,6 +123,8 @@ typedef struct __options {
int cool_bits;
int nvidia_3dvision_display_type;
+ int num_x_screens;
+
char *xconfig;
char *output_xconfig;
char *layout;
diff --git a/option_table.h b/option_table.h
index f21488f..994243f 100644
--- a/option_table.h
+++ b/option_table.h
@@ -58,6 +58,7 @@ enum {
NVIDIA_3DVISIONPRO_CONFIG_FILE_OPTION,
NVIDIA_3DVISION_DISPLAY_TYPE_OPTION,
RESTORE_ORIGINAL_BACKUP_OPTION,
+ NUM_X_SCREENS_OPTION,
};
/*
@@ -481,10 +482,21 @@ static const NVGetoptOption __options[] = {
"drive these display devices in a single X screen, or as separate X "
"screens. When the '--separate-x-screens' option is specified, each GPU "
"on which an X screen is currently configured will be updated to have "
- "two X screens configured. The '--no-separate-x-screens' option will "
- "remove the second configured X screen on each GPU. Please see the "
- "NVIDIA README description of \"Separate X Screens on One GPU\" for "
- "further details." },
+ "two or more (depending on the capabilities of that GPU) X screens "
+ "configured. The '--no-separate-x-screens' option will remove any "
+ "extra configured X screens on each GPU. Please see the NVIDIA README "
+ "description of \"Separate X Screens on One GPU\" for further details." },
+
+ { "x-screens-per-gpu", NUM_X_SCREENS_OPTION,
+ NVGETOPT_INTEGER_ARGUMENT, NULL,
+ "A GPU that supports multiple simultaneous display devices can either "
+ "drive these display devices in a single X screen, or as separate X "
+ "screens. When the '--x-screens-per-gpu=<quantity>' option is "
+ "specified, each GPU on which an X screen is currently configured will "
+ "be updated to have <quantity> X screens. <quantity> has to be greater "
+ "than 0. Setting <quantity> to 1 is equivalent to specifying the "
+ "'--no-separate-x-screens' option. Please see the NVIDIA README "
+ "description of \"Separate X Screens on One GPU\" for further details." },
{ "sli", SLI_OPTION,
NVGETOPT_STRING_ARGUMENT | NVGETOPT_ALLOW_DISABLE, NULL,
@@ -640,5 +652,13 @@ static const NVGetoptOption __options[] = {
NVGETOPT_IS_BOOLEAN, NULL, "Allow the X server to start even if no "
"connected display devices could be detected." },
+ { "delete-unused-dp12-displays", XCONFIG_BOOL_VAL(DELETE_UNUSED_DP12_DPYS),
+ NVGETOPT_IS_BOOLEAN, NULL, "Delete DisplayPort 1.2 RandR outputs that "
+ "are disconnected and not named in any MetaModes." },
+
+ { "inband-stereo-signaling", XCONFIG_BOOL_VAL(INBAND_STEREO_SIGNALING),
+ NVGETOPT_IS_BOOLEAN, NULL, "Enable or disable the "
+ "\"InbandStereoSignaling\" X configuration option." },
+
{ NULL, 0, 0, NULL, NULL },
};
diff --git a/options.c b/options.c
index 575d38e..2b7e7ec 100644
--- a/options.c
+++ b/options.c
@@ -26,6 +26,7 @@
#include "nvidia-xconfig.h"
#include "xf86Parser.h"
+#include "msg.h"
typedef struct {
@@ -68,6 +69,8 @@ static const NvidiaXConfigOption __options[] = {
{ MODE_DEBUG_BOOL_OPTION, FALSE, "ModeDebug" },
{ BASE_MOSAIC_BOOL_OPTION, FALSE, "BaseMosaic" },
{ ALLOW_EMPTY_INITIAL_CONFIGURATION, FALSE, "AllowEmptyInitialConfiguration" },
+ { DELETE_UNUSED_DP12_DPYS, FALSE, "DeleteUnusedDP12Displays" },
+ { INBAND_STEREO_SIGNALING, FALSE, "InbandStereoSignaling" },
{ 0, FALSE, NULL },
};
@@ -126,7 +129,7 @@ void validate_composite(Options *op, XConfigPtr config)
int cioverlay_enabled;
int ubb_enabled;
int stereo_enabled;
- const char *err_str;
+ char *err_str;
composite_specified = GET_BOOL_OPTION(op->boolean_options,
@@ -178,11 +181,12 @@ void validate_composite(Options *op, XConfigPtr config)
*/
if (err_str) {
- fmtwarn("The Composite X extension does not currently interact well "
- "with the %s option(s); the Composite X extension will be "
- "disabled.", err_str);
+ nv_warning_msg("The Composite X extension does not currently interact "
+ "well with the %s option(s); the Composite X extension "
+ "will be disabled.", err_str);
set_boolean_option(op, COMPOSITE_BOOL_OPTION, FALSE);
+ nvfree(err_str);
}
} /* validate_composite() */
@@ -498,7 +502,7 @@ void update_options(Options *op, XConfigScreenPtr screen)
o = get_option(i);
if (!o) {
- fmterr("Unrecognized X Config option %d", i);
+ nv_error_msg("Unrecognized X Config option %d", i);
continue;
}
@@ -509,8 +513,8 @@ void update_options(Options *op, XConfigScreenPtr screen)
}
set_option_value(screen, o->name, val);
- fmtout("Option \"%s\" \"%s\" added to "
- "Screen \"%s\".", o->name, val, screen->identifier);
+ nv_info_msg(NULL, "Option \"%s\" \"%s\" added to Screen \"%s\".",
+ o->name, val, screen->identifier);
}
}
@@ -594,14 +598,14 @@ void update_options(Options *op, XConfigScreenPtr screen)
op->metamode_orientation);
if (remove_metamode_offsets(screen,
&old_metamodes, &new_metamodes)) {
- fmtwarn("The MetaModes option contained explicit offsets, "
- "which would have overridden the specified "
- "MetaModeOrientation; in order to honor the "
- "requested MetaModeOrientation, the explicit offsets "
- "have been removed from the MetaModes option.\n\n"
- "Old MetaModes option: \"%s\"\n"
- "New MetaModes option: \"%s\".",
- old_metamodes, new_metamodes);
+ nv_warning_msg("The MetaModes option contained explicit offsets, "
+ "which would have overridden the specified "
+ "MetaModeOrientation; in order to honor the "
+ "requested MetaModeOrientation, the explicit offsets "
+ "have been removed from the MetaModes option.\n\n"
+ "Old MetaModes option: \"%s\"\n"
+ "New MetaModes option: \"%s\".",
+ old_metamodes, new_metamodes);
nvfree(old_metamodes);
nvfree(new_metamodes);
}
diff --git a/query_gpu_info.c b/query_gpu_info.c
index 17152ff..01e6152 100644
--- a/query_gpu_info.c
+++ b/query_gpu_info.c
@@ -21,6 +21,7 @@
*/
#include "nvidia-xconfig.h"
+#include "msg.h"
#include <string.h>
static char *display_device_mask_to_display_device_name(unsigned int mask);
@@ -46,32 +47,32 @@ int query_gpu_info(Options *op)
pDevices = find_devices(op);
if (!pDevices) {
- fmterr("Unable to query GPU information");
+ nv_error_msg("Unable to query GPU information");
return FALSE;
}
/* print the GPU information */
- fmtout("Number of GPUs: %d", pDevices->nDevices);
+ nv_info_msg(NULL, "Number of GPUs: %d", pDevices->nDevices);
for (i = 0; i < pDevices->nDevices; i++) {
- fmtout("");
- fmtout("GPU #%d:", i);
- fmtoutp(TAB, "Name : %s", pDevices->devices[i].name);
- fmtoutp(TAB, "UUID : %s", pDevices->devices[i].uuid);
+ nv_info_msg(NULL, "");
+ nv_info_msg(NULL, "GPU #%d:", i);
+ nv_info_msg(TAB, "Name : %s", pDevices->devices[i].name);
+ nv_info_msg(TAB, "UUID : %s", pDevices->devices[i].uuid);
memset(busid, 0, BUS_ID_STRING_LENGTH);
xconfigFormatPciBusString(busid, BUS_ID_STRING_LENGTH,
pDevices->devices[i].dev.domain,
pDevices->devices[i].dev.bus,
pDevices->devices[i].dev.slot, 0);
- fmtoutp(TAB, "PCI BusID : %s", busid);
+ nv_info_msg(TAB, "PCI BusID : %s", busid);
- fmtout("");
- fmtoutp(TAB, "Number of Display Devices: %d",
- pDevices->devices[i].nDisplayDevices);
- fmtout("");
+ nv_info_msg(NULL, "");
+ nv_info_msg(TAB, "Number of Display Devices: %d",
+ pDevices->devices[i].nDisplayDevices);
+ nv_info_msg(NULL, "");
for (j = 0; j < pDevices->devices[i].nDisplayDevices; j++) {
@@ -82,7 +83,7 @@ int query_gpu_info(Options *op)
if (!name) name = nvstrdup("Unknown");
- fmtoutp(TAB, "Display Device %d (%s):", j, name);
+ nv_info_msg(TAB, "Display Device %d (%s):", j, name);
nvfree(name);
@@ -91,9 +92,9 @@ int query_gpu_info(Options *op)
* non-zero
*/
- #define PRT(_fmt, _val) \
- if (_val) { \
- fmtoutp(BIGTAB, (_fmt), (_val)); \
+ #define PRT(_fmt, _val) \
+ if (_val) { \
+ nv_info_msg(BIGTAB, (_fmt), (_val)); \
}
if (pDisplayDevice->info_valid) {
@@ -138,10 +139,10 @@ int query_gpu_info(Options *op)
pDisplayDevice->info.physical_height);
} else {
- fmtoutp(BIGTAB, "No EDID information available.");
+ nv_info_msg(BIGTAB, "No EDID information available.");
}
- fmtout("");
+ nv_info_msg(NULL, "");
}
}
diff --git a/util.c b/util.c
index a1c1bae..e7e437b 100644
--- a/util.c
+++ b/util.c
@@ -39,6 +39,7 @@
#include <sys/termios.h>
#include "nvidia-xconfig.h"
+#include "msg.h"
Options *__op = NULL;
@@ -59,18 +60,18 @@ int copy_file(const char *srcfile, const char *dstfile, mode_t mode)
int ret = FALSE;
if ((src_fd = open(srcfile, O_RDONLY)) == -1) {
- fmterr("Unable to open '%s' for copying (%s)",
- srcfile, strerror (errno));
+ nv_error_msg("Unable to open '%s' for copying (%s)",
+ srcfile, strerror (errno));
goto done;
}
if ((dst_fd = open(dstfile, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1) {
- fmterr("Unable to create '%s' for copying (%s)",
- dstfile, strerror (errno));
+ nv_error_msg("Unable to create '%s' for copying (%s)",
+ dstfile, strerror (errno));
goto done;
}
if (fstat(src_fd, &stat_buf) == -1) {
- fmterr("Unable to determine size of '%s' (%s)",
- srcfile, strerror (errno));
+ nv_error_msg("Unable to determine size of '%s' (%s)",
+ srcfile, strerror (errno));
goto done;
}
if (stat_buf.st_size == 0) {
@@ -79,38 +80,38 @@ int copy_file(const char *srcfile, const char *dstfile, mode_t mode)
goto done;
}
if (lseek(dst_fd, stat_buf.st_size - 1, SEEK_SET) == -1) {
- fmterr("Unable to set file size for '%s' (%s)",
- dstfile, strerror (errno));
+ nv_error_msg("Unable to set file size for '%s' (%s)",
+ dstfile, strerror (errno));
goto done;
}
if (write(dst_fd, "", 1) != 1) {
- fmterr("Unable to write file size for '%s' (%s)",
- dstfile, strerror (errno));
+ nv_error_msg("Unable to write file size for '%s' (%s)",
+ dstfile, strerror (errno));
goto done;
}
if ((src = mmap(0, stat_buf.st_size, PROT_READ,
MAP_SHARED, src_fd, 0)) == (void *) -1) {
- fmterr("Unable to map source file '%s' for "
- "copying (%s)", srcfile, strerror (errno));
+ nv_error_msg("Unable to map source file '%s' for "
+ "copying (%s)", srcfile, strerror (errno));
goto done;
}
if ((dst = mmap(0, stat_buf.st_size, PROT_READ | PROT_WRITE,
MAP_SHARED, dst_fd, 0)) == (void *) -1) {
- fmterr("Unable to map destination file '%s' for "
- "copying (%s)", dstfile, strerror (errno));
+ nv_error_msg("Unable to map destination file '%s' for "
+ "copying (%s)", dstfile, strerror (errno));
goto done;
}
memcpy(dst, src, stat_buf.st_size);
if (munmap (src, stat_buf.st_size) == -1) {
- fmterr("Unable to unmap source file '%s' after "
- "copying (%s)", srcfile, strerror (errno));
+ nv_error_msg("Unable to unmap source file '%s' after "
+ "copying (%s)", srcfile, strerror (errno));
goto done;
}
if (munmap (dst, stat_buf.st_size) == -1) {
- fmterr("Unable to unmap destination file '%s' after "
- "copying (%s)", dstfile, strerror (errno));
+ nv_error_msg("Unable to unmap destination file '%s' after "
+ "copying (%s)", dstfile, strerror (errno));
goto done;
}
@@ -182,8 +183,8 @@ void xconfigPrint(MsgType t, const char *msg)
}
}
- if (newline) fmt(stream, NULL, "");
- fmt(stream, prefix, "%s", msg);
- if (newline) fmt(stream, NULL, "");
+ if (newline) nv_info_msg_to_file(stream, NULL, "");
+ nv_info_msg_to_file(stream, prefix, "%s", msg);
+ if (newline) nv_info_msg_to_file(stream, NULL, "");
} /* xconfigPrint */
diff --git a/utils.mk b/utils.mk
index ce645c7..a725f14 100644
--- a/utils.mk
+++ b/utils.mk
@@ -114,6 +114,7 @@ endif
TARGET_ARCH_ABI ?=
OUTPUTDIR ?= _out/$(TARGET_OS)_$(TARGET_ARCH)
+OUTPUTDIR_ABSOLUTE ?= $(CURDIR)/$(OUTPUTDIR)
NV_QUIET_COMMAND_REMOVED_TARGET_PREFIX ?=
diff --git a/version.mk b/version.mk
index 2bca142..591ef07 100644
--- a/version.mk
+++ b/version.mk
@@ -1 +1 @@
-NVIDIA_VERSION = 331.38
+NVIDIA_VERSION = 334.16