2
* nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
5
* Copyright (C) 2004 NVIDIA Corporation.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of Version 2 of the GNU General Public
9
* License as published by the Free Software Foundation.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2
14
* of the GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the:
19
* Free Software Foundation, Inc.
20
* 59 Temple Place - Suite 330
21
* Boston, MA 02111-1307, USA
26
* query-assign.c - this source file contains functions for querying
27
* and assigning attributes, as specified on the command line. Some
28
* of this functionality is also shared with the config file
38
#include "query-assign.h"
40
/* local prototypes */
42
static int process_attribute_queries(int, char**, const char *);
44
static int process_attribute_assignments(int, char**, const char *);
46
static int query_all(const char *);
48
static void print_valid_values(char *, NVCTRLAttributeValidValuesRec);
50
static int validate_value(CtrlHandles *h, ParsedAttribute *a, uint32 d,
51
int screen, char *whence);
54
* nv_process_assignments_and_queries() - process any assignments or
55
* queries specified on the commandline. If an error occurs, return
56
* NV_FALSE. On success return NV_TRUE.
59
int nv_process_assignments_and_queries(Options *op)
63
if (op->num_queries) {
64
ret = process_attribute_queries(op->num_queries,
65
op->queries, op->ctrl_display);
66
if (!ret) return NV_FALSE;
69
if (op->num_assignments) {
70
ret = process_attribute_assignments(op->num_assignments,
73
if (!ret) return NV_FALSE;
78
} /* nv_process_assignments_and_queries() */
83
* nv_get_enabled_display_devices() - allocate an array of unsigned
84
* ints of length n, and query the X server for each screen's enabled
85
* display device mask, saving each X screen's display mask into the
86
* appropriate index in the array.
88
* This is just an optimization to avoid redundant round trips to the
89
* X server later in NvCtrlProcessParsedAttribute().
91
* On success a freshly malloc'ed array of length n is returned (it is
92
* the caller's responsibility to free this memory). On error an
93
* error message is printed and NULL is returned.
96
uint32 *nv_get_enabled_display_devices(int n, NvCtrlAttributeHandle **h)
102
d = malloc(sizeof(uint32) * n);
104
for (screen = 0; screen < n; screen++) {
110
status = NvCtrlGetAttribute(h[screen], NV_CTRL_ENABLED_DISPLAYS,
112
if (status != NvCtrlSuccess) {
113
nv_error_msg("Error querying enabled displays on "
114
"screen %d (%s).", screen,
115
NvCtrlAttributesStrError(status));
123
} /* nv_get_enabled_display_devices() */
128
* nv_alloc_ctrl_handles() - allocate a new CtrlHandles structure,
129
* connect to the X server identified by display, and initialize an
130
* NvCtrlAttributeHandle for each X screen.
133
CtrlHandles *nv_alloc_ctrl_handles(const char *display)
138
h = malloc(sizeof(CtrlHandles));
140
if (display) h->display = strdup(display);
141
else h->display = NULL;
143
h->dpy = XOpenDisplay(h->display);
147
h->num_screens = ScreenCount(h->dpy);
149
h->h = malloc(h->num_screens * sizeof(NvCtrlAttributeHandle *));
150
h->screen_names = malloc(h->num_screens * sizeof(char *));
152
for (i = 0; i < h->num_screens; i++) {
153
h->h[i] = NvCtrlAttributeInit
154
(h->dpy, i, NV_CTRL_ATTRIBUTES_ALL_SUBSYSTEMS);
155
h->screen_names[i] = NvCtrlGetDisplayName(h->h[i]);
158
h->d = nv_get_enabled_display_devices(h->num_screens, h->h);
162
nv_error_msg("Cannot open display '%s'.", XDisplayName(h->display));
167
h->screen_names = NULL;
172
} /* nv_alloc_ctrl_handles() */
176
* nv_free_ctrl_handles() - free the CtrlHandles structure allocated
177
* by nv_alloc_ctrl_handles()
180
void nv_free_ctrl_handles(CtrlHandles *h)
186
if (h->display) free(h->display);
190
for (i = 0; i < h->num_screens; i++) {
191
NvCtrlAttributeClose(h->h[i]);
192
if (h->screen_names[i]) free(h->screen_names[i]);
195
if (h->d) free(h->d);
196
if (h->h) free(h->h);
197
if (h->screen_names) free(h->screen_names);
199
XCloseDisplay(h->dpy);
204
} /* nv_free_ctrl_handles() */
209
* process_attribute_queries() - parse the list of queries, and
210
* call NvCtrlProcessParsedAttribute() to process each query.
212
* If any errors are encountered, an error message is printed and
213
* NV_FALSE is returned. Otherwise, NV_TRUE is returned.
215
* XXX rather than call nv_alloc_ctrl_handles()/nv_free_ctrl_handles()
216
* for every query, we should share the code in
217
* process_config_file_attributes() to collapse the list of handles.
220
static int process_attribute_queries(int num, char **queries,
221
const char *display_name)
229
/* loop over each requested query */
231
for (query = 0; query < num; query++) {
233
/* special case the "all" query */
235
if (nv_strcasecmp(queries[query], "all")) {
236
query_all(display_name);
240
/* call the parser to parse queries[query] */
242
ret = nv_parse_attribute_string(queries[query], NV_PARSER_QUERY, &a);
243
if (ret != NV_PARSER_STATUS_SUCCESS) {
244
nv_error_msg("Error parsing query '%s' (%s).",
245
queries[query], nv_parse_strerror(ret));
249
/* make sure we have a display */
251
nv_assign_default_display(&a, display_name);
253
/* allocate the CtrlHandles */
255
h = nv_alloc_ctrl_handles(a.display);
257
/* call the processing engine to process the parsed query */
259
ret = nv_process_parsed_attribute(&a, h, NV_FALSE, NV_FALSE,
260
"in query '%s'", queries[query]);
261
/* free the CtrlHandles */
263
nv_free_ctrl_handles(h);
265
if (ret == NV_FALSE) goto done;
275
} /* process_attribute_queries() */
280
* process_attribute_assignments() - parse the list of
281
* assignments, and call nv_process_parsed_attribute() to process
284
* If any errors are encountered, an error message is printed and
285
* NV_FALSE is returned. Otherwise, NV_TRUE is returned.
287
* XXX rather than call nv_alloc_ctrl_handles()/nv_free_ctrl_handles()
288
* for every assignment, we should share the code in
289
* process_config_file_attributes() to collapse the list of handles.
292
static int process_attribute_assignments(int num, char **assignments,
293
const char *display_name)
295
int assignment, ret, val;
301
/* loop over each requested assignment */
303
for (assignment = 0; assignment < num; assignment++) {
305
/* call the parser to parse assignments[assignment] */
307
ret = nv_parse_attribute_string(assignments[assignment],
308
NV_PARSER_ASSIGNMENT, &a);
310
if (ret != NV_PARSER_STATUS_SUCCESS) {
311
nv_error_msg("Error parsing assignment '%s' (%s).",
312
assignments[assignment], nv_parse_strerror(ret));
316
/* make sure we have a display */
318
nv_assign_default_display(&a, display_name);
320
/* allocate the CtrlHandles */
322
h = nv_alloc_ctrl_handles(a.display);
324
/* call the processing engine to process the parsed assignment */
326
ret = nv_process_parsed_attribute(&a, h, NV_TRUE, NV_TRUE,
327
"in assignment '%s'",
328
assignments[assignment]);
329
/* free the CtrlHandles */
331
nv_free_ctrl_handles(h);
333
if (ret == NV_FALSE) goto done;
343
} /* nv_process_attribute_assignments() */
348
* validate_value() - query the valid values for the specified
349
* attribute, and check that the value to be assigned is valid.
352
static int validate_value(CtrlHandles *h, ParsedAttribute *a, uint32 d,
353
int screen, char *whence)
355
int bad_val = NV_FALSE;
356
NVCTRLAttributeValidValuesRec valid;
361
status = NvCtrlGetValidDisplayAttributeValues(h->h[screen], d,
364
if (status != NvCtrlSuccess) {
365
nv_error_msg("Unable to query valid values for attribute %s (%s).",
366
a->name, NvCtrlAttributesStrError(status));
370
if (valid.permissions & ATTRIBUTE_TYPE_DISPLAY) {
371
tmp_d_str = display_device_mask_to_display_device_name(d);
372
sprintf(d_str, ", display device: %s", tmp_d_str);
378
switch (valid.type) {
379
case ATTRIBUTE_TYPE_INTEGER:
380
case ATTRIBUTE_TYPE_BITMASK:
381
/* don't do any checks on integer or bitmask values */
383
case ATTRIBUTE_TYPE_BOOL:
384
if ((a->val < 0) || (a->val > 1)) {
388
case ATTRIBUTE_TYPE_RANGE:
389
if ((a->val < valid.u.range.min) || (a->val > valid.u.range.max)) {
393
case ATTRIBUTE_TYPE_INT_BITS:
394
if ((a->val > 31) || (a->val < 0) ||
395
((valid.u.bits.ints & (1<<a->val)) == 0)) {
405
nv_warning_msg("The value %d for attribute '%s' (%s%s) "
406
"specified %s is invalid.",
407
a->val, a->name, h->screen_names[screen],
409
print_valid_values(a->name, valid);
414
} /* validate_value() */
419
* print_valid_values() - prints the valid values for the specified
423
static void print_valid_values(char *name, NVCTRLAttributeValidValuesRec valid)
425
int bit, first, last;
431
switch (valid.type) {
432
case ATTRIBUTE_TYPE_INTEGER:
433
nv_msg(INDENT, "'%s' is an integer attribute.", name);
436
case ATTRIBUTE_TYPE_BITMASK:
437
nv_msg(INDENT, "'%s' is a bitmask attribute.", name);
440
case ATTRIBUTE_TYPE_BOOL:
441
nv_msg(INDENT, "'%s' is a boolean attribute; valid values are: "
442
"1 (on/true) and 0 (off/false).", name);
445
case ATTRIBUTE_TYPE_RANGE:
446
nv_msg(INDENT, "The valid values for '%s' are in the range "
447
"%d - %d (inclusive).", name,
448
valid.u.range.min, valid.u.range.max);
451
case ATTRIBUTE_TYPE_INT_BITS:
454
/* scan through the bitmask once to get first and last */
456
for (bit = 0; bit < 32; bit++) {
457
if (valid.u.bits.ints & (1 << bit)) {
458
if (first == -1) first = bit;
463
/* now, scan through the bitmask again, building the string */
467
for (bit = 0; bit < 32; bit++) {
468
if (valid.u.bits.ints & (1 << bit)) {
470
c += sprintf (c, "%d", bit);
471
} else if (bit == last) {
472
c += sprintf (c, " and %d", bit);
474
c += sprintf (c, ", %d", bit);
479
nv_msg(INDENT, "Valid values for '%s' are: %s.", name, str);
483
if (!(valid.permissions & ATTRIBUTE_TYPE_WRITE)) {
484
nv_msg(INDENT, "'%s' is a read-only attribute.", name);
487
if (valid.permissions & ATTRIBUTE_TYPE_DISPLAY) {
488
nv_msg(INDENT, "'%s' is display device specific.", name);
493
} /* print_valid_values() */
498
* query_all() - loop through all screens, and query all attributes
499
* for those screens. The current attribute values for all display
500
* devices on all screens are printed, along with the valid values for
503
* If an error occurs, an error message is printed and NV_FALSE is
504
* returned; if successful, NV_TRUE is returned.
507
static int query_all(const char *display_name)
509
int bit, entry, screen, val;
512
AttributeTableEntry *a;
514
const char *fmt, *fmt_display;
515
NVCTRLAttributeValidValuesRec valid;
518
static const char *__fmt_str_int =
519
"Attribute '%s' (screen: %s): %d.";
520
static const char *__fmt_str_int_display =
521
"Attribute '%s' (screen: %s; display: %s): %d.";
522
static const char *__fmt_str_hex =
523
"Attribute '%s' (screen: %s): 0x%08x.";
524
static const char *__fmt_str_hex_display =
525
"Attribute '%s' (screen: %s; display: %s): 0x%08x.";
527
h = nv_alloc_ctrl_handles(display_name);
531
for (screen = 0; screen < h->num_screens; screen++) {
533
if (!h->h[screen]) continue;
535
nv_msg(NULL, "Attributes for %s:", h->screen_names[screen]);
537
for (entry = 0; attributeTable[entry].name; entry++) {
539
a = &attributeTable[entry];
541
/* skip the color attributes */
543
if (a->flags & NV_PARSER_TYPE_COLOR_ATTRIBUTE) continue;
545
for (bit = 0; bit < 24; bit++) {
548
if ((h->d[screen] & mask) == 0x0) continue;
551
NvCtrlGetValidDisplayAttributeValues(h->h[screen], mask,
554
if (status == NvCtrlAttributeNotAvailable) goto exit_bit_loop;
556
if (status != NvCtrlSuccess) {
557
nv_error_msg("Error while querying valid values for "
558
"attribute '%s' on %s (%s).",
559
a->name, h->screen_names[screen],
560
NvCtrlAttributesStrError(status));
564
status = NvCtrlGetDisplayAttribute(h->h[screen], mask,
567
if (status == NvCtrlAttributeNotAvailable) goto exit_bit_loop;
569
if (status != NvCtrlSuccess) {
570
nv_error_msg("Error while querying attribute '%s' "
572
a->name, h->screen_names[screen],
573
NvCtrlAttributesStrError(status));
577
if (valid.type == ATTRIBUTE_TYPE_BITMASK) {
579
fmt_display = __fmt_str_hex_display;
582
fmt_display = __fmt_str_int_display;
585
if (valid.permissions & ATTRIBUTE_TYPE_DISPLAY) {
588
display_device_mask_to_display_device_name(mask);
590
nv_msg(INDENT, fmt_display, a->name,
591
h->screen_names[screen], tmp_d_str, val);
595
print_valid_values(a->name, valid);
600
nv_msg(INDENT, fmt, a->name, h->screen_names[screen], val);
602
print_valid_values(a->name, valid);
604
/* fall through to exit_bit_loop */
609
bit = 25; /* XXX force us out of the display device loop */
619
nv_free_ctrl_handles(h);
628
* process_parsed_attribute_internal() - this function does the
629
* actually attribute processing for NvCtrlProcessParsedAttribute().
631
* If an error occurs, an error message is printed and NV_FALSE is
632
* returned; if successful, NV_TRUE is returned.
635
static int process_parsed_attribute_internal(CtrlHandles *h,
636
ParsedAttribute *a, uint32 d,
637
int screen, int assign,
638
int verbose, char *whence,
639
NVCTRLAttributeValidValuesRec
643
char str[32], *tmp_d_str;
646
if (valid.permissions & ATTRIBUTE_TYPE_DISPLAY) {
647
tmp_d_str = display_device_mask_to_display_device_name(d);
648
sprintf(str, ", display device: %s", tmp_d_str);
655
ret = validate_value(h, a, d, screen, whence);
656
if (!ret) return NV_FALSE;
658
status = NvCtrlSetDisplayAttribute(h->h[screen], d, a->attr, a->val);
659
if (status != NvCtrlSuccess) {
660
nv_error_msg("Error assigning value %d to attribute '%s' "
661
"(%s%s) as specified %s (%s).",
662
a->val, a->name, h->screen_names[screen], str, whence,
663
NvCtrlAttributesStrError(status));
668
nv_msg(" ", "Attribute '%s' (%s%s) assigned value %d.",
669
a->name, h->screen_names[screen], str, a->val);
674
status = NvCtrlGetDisplayAttribute(h->h[screen], d, a->attr, &a->val);
676
if (status == NvCtrlAttributeNotAvailable) {
677
nv_warning_msg("Error querying attribute '%s' specified %s; "
678
"'%s' is not available on %s%s.",
679
a->name, whence, a->name,
680
h->screen_names[screen], str);
681
} else if (status != NvCtrlSuccess) {
682
nv_error_msg("Error while querying attribute '%s' "
683
"(%s%s) specified %s (%s).",
684
a->name, h->screen_names[screen], str, whence,
685
NvCtrlAttributesStrError(status));
688
nv_msg(" ", "Attribute '%s' (%s%s): %d.",
689
a->name, h->screen_names[screen], str, a->val);
690
print_valid_values(a->name, valid);
696
} /* process_parsed_attribute_internal() */
701
* nv_process_parsed_attribute() - this is the processing engine for
702
* all parsed attributes.
704
* A parsed attribute may or may not specify an X screen; if an X
705
* screen was specified, we validate that screen and process the
706
* attribute just for that screen. If a screen was not specified, we
707
* process the attribute for all valid screens.
709
* A parsed attribute may or may not specify one or more display
710
* devices. For attributes that require that a display device be
711
* specified: if a display device mask is specified, we validate it
712
* and process the attribute just for the display devices in the mask.
713
* If a display device mask was not specified, then we process the
714
* attribute for all enabled display devices on each of the screens
715
* that have been requested.
717
* "Processing" a parsed attribute means either querying for the
718
* current value of the attribute on all requested screens and display
719
* devices (see above), or assigning the attribute on all requested
720
* screens and display devices (see above).
722
* The majority of the work (determining which screens, which display
723
* devices) is the same, regardless of what sort of processing we
724
* actually need to do (thus this shared function).
726
* To accomodate the differences in processing needed for each of the
727
* callers of this function, the paramenters 'assign' and 'verbose'
728
* are used; if assign is TRUE, then the attribute will be assigned
729
* during processing, otherwise it will be queried. If verbose is
730
* TRUE, then a message will be printed out during each assignment (or
733
* The CtrlHandles argument contains an array of
734
* NvCtrlAttributeHandle's (one per X screen on this X server), as
735
* well as the number of X screens, an array of enabled display
736
* devices for each screen, and a string description of each screen.
738
* The whence_fmt and following varargs are used by the callee to
739
* describe where the attribute came from. A whence string should be
740
* something like "on line 12 of config file ~/.nvidia-settings-rc" or
741
* "in query ':0.0/fsaa'". Whence is used in the case of error to
742
* indicate where the error came from.
744
* If successful, the processing determined by 'assign' and 'verbose'
745
* will be done and NV_TRUE will be returned. If an error occurs, an
746
* error message will be printed and NV_FALSE will be returned.
749
int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h,
750
int assign, int verbose,
751
char *whence_fmt, ...)
753
int screen, start_screen, end_screen, bit, ret, val;
754
char *whence, *tmp_d_str0, *tmp_d_str1;
755
uint32 display_devices, mask;
758
NVCTRLAttributeValidValuesRec valid;
762
/* build the description */
764
va_start(ap, whence_fmt);
765
whence = nv_build_vararg_string(whence_fmt, ap);
768
if (!whence) whence = strdup("\0");
770
/* if we don't have a Display connection, abort now */
773
nv_error_msg("Unable to %s attribute %s specified %s (no Display "
774
"connection).", assign ? "assign" : "query",
779
/* if a screen was specified, make sure it is valid */
781
if (a->flags & NV_PARSER_HAS_X_SCREEN) {
783
if (a->screen >= h->num_screens) {
784
if (h->num_screens == 1) {
785
nv_error_msg("Invalid X screen %d specified %s "
786
"(there is only 1 screen on this Display).",
789
nv_error_msg("Invalid X screen %d specified %s "
790
"(there are only %d screens on this Display).",
791
a->screen, whence, h->num_screens);
796
if (!h->h[a->screen]) {
797
nv_error_msg("Invalid screen %d specified %s "
798
"(NV-CONTROL extension not supported on "
799
"screen %d).", a->screen, whence, a->screen);
803
* assign start_screen and end_screen such that the screen
804
* loop only uses this screen.
807
start_screen = a->screen;
808
end_screen = a->screen + 1;
812
* no screen was specified; assign start_screen and end_screen
813
* such that we loop over all the screens
817
end_screen = h->num_screens;
820
/* loop over the requested screens */
822
for (screen = start_screen; screen < end_screen; screen++) {
824
if (!h->h[screen]) continue; /* no handle on this screen; skip */
826
if (a->flags & NV_PARSER_HAS_DISPLAY_DEVICE) {
828
/* Expand any wildcards in the display device mask */
830
display_devices = expand_display_device_mask_wildcards
831
(a->display_device_mask, h->d[screen]);
833
if ((display_devices == 0) || (display_devices & ~h->d[screen])) {
836
* use a->display_device_mask rather than
837
* display_devices when building the string (so that
838
* display_device_mask_to_display_device_name() can
839
* use wildcards if present).
842
tmp_d_str0 = display_device_mask_to_display_device_name
843
(a->display_device_mask);
844
tmp_d_str1 = display_device_mask_to_display_device_name
847
nv_error_msg("Invalid display device %s specified "
848
"%s (the currently enabled display devices "
850
tmp_d_str0, whence, tmp_d_str1,
851
h->screen_names[screen]);
860
display_devices = h->d[screen];
863
/* special case the color attributes */
865
if (a->flags & NV_PARSER_TYPE_COLOR_ATTRIBUTE) {
868
nv_error_msg("Cannot query attribute '%s'", a->name);
873
* assign fval to all values in the array; a->attr will
874
* tell NvCtrlSetColorAttributes() which indices in the
878
v[0] = v[1] = v[2] = a->fval;
880
status = NvCtrlSetColorAttributes(h->h[screen], v, v, v, a->attr);
881
if (status != NvCtrlSuccess) {
882
nv_error_msg("Error assigning %f to attribute '%s' on %s "
883
"specified %s (%s)", a->fval, a->name,
884
h->screen_names[screen], whence,
885
NvCtrlAttributesStrError(status));
892
for (bit = 0; bit < 24; bit++) {
896
if ((mask & display_devices) == 0x0) continue;
898
status = NvCtrlGetValidDisplayAttributeValues(h->h[screen], mask,
900
if (status != NvCtrlSuccess) {
901
nv_error_msg("Error querying valid values for attribute "
902
"'%s' on %s specified %s (%s).",
903
a->name, h->screen_names[screen], whence,
904
NvCtrlAttributesStrError(status));
909
* if this attribute is going to be assigned, then check
910
* that the attribute is writable; if it's not, give up
913
if ((assign) && (!(valid.permissions & ATTRIBUTE_TYPE_WRITE))) {
914
nv_error_msg("The attribute '%s' specified %s cannot be "
915
"assigned (it is a read-only attribute).",
920
ret = process_parsed_attribute_internal(h, a, mask, screen,
923
if (ret == NV_FALSE) goto done;
925
if (!(valid.permissions & ATTRIBUTE_TYPE_DISPLAY)) bit = 25;
934
if (whence) free(whence);
937
} /* nv_process_parsed_attribute() */