summaryrefslogtreecommitdiff
path: root/samples/nv-control-dpy.c
diff options
context:
space:
mode:
Diffstat (limited to 'samples/nv-control-dpy.c')
-rw-r--r--samples/nv-control-dpy.c1394
1 files changed, 1241 insertions, 153 deletions
diff --git a/samples/nv-control-dpy.c b/samples/nv-control-dpy.c
index b37bfe7..f74d4ec 100644
--- a/samples/nv-control-dpy.c
+++ b/samples/nv-control-dpy.c
@@ -2,7 +2,7 @@
* nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
* and Linux systems.
*
- * Copyright (C) 2004 NVIDIA Corporation.
+ * Copyright (C) 2006 NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of Version 2 of the GNU General Public
@@ -24,14 +24,17 @@
/*
- * nv-control-dpy.c - NV-CONTROL client that demonstrates how to
- * configure display devices using NV-CONTROL.
+ * nv-control-dpy.c - This sample NV-CONTROL client demonstrates how
+ * to configure display devices using NV-CONTROL. This client
+ * demonstrates many different pieces of display configuration
+ * functionality, controlled through commandline options.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <X11/Xlib.h>
@@ -39,45 +42,13 @@
#include "NVCtrlLib.h"
-
-
-/*
- * display_device_name() - return the display device name correspoding
- * to the display device mask.
- */
-
-char *display_device_name(int mask)
-{
- switch (mask) {
- case (1 << 0): return "CRT-0"; break;
- case (1 << 1): return "CRT-1"; break;
- case (1 << 2): return "CRT-2"; break;
- case (1 << 3): return "CRT-3"; break;
- case (1 << 4): return "CRT-4"; break;
- case (1 << 5): return "CRT-5"; break;
- case (1 << 6): return "CRT-6"; break;
- case (1 << 7): return "CRT-7"; break;
-
- case (1 << 8): return "TV-0"; break;
- case (1 << 9): return "TV-1"; break;
- case (1 << 10): return "TV-2"; break;
- case (1 << 11): return "TV-3"; break;
- case (1 << 12): return "TV-4"; break;
- case (1 << 13): return "TV-5"; break;
- case (1 << 14): return "TV-6"; break;
- case (1 << 15): return "TV-7"; break;
-
- case (1 << 16): return "DFP-0"; break;
- case (1 << 17): return "DFP-1"; break;
- case (1 << 18): return "DFP-2"; break;
- case (1 << 19): return "DFP-3"; break;
- case (1 << 20): return "DFP-4"; break;
- case (1 << 21): return "DFP-5"; break;
- case (1 << 22): return "DFP-6"; break;
- case (1 << 23): return "DFP-7"; break;
- default: return "Unknown";
- }
-} /* display_device_name() */
+static char *display_device_name(int mask);
+static unsigned int display_device_mask(char *str);
+static char *remove_whitespace(char *str);
+static int count_bits(unsigned int mask);
+static void parse_mode_string(char *modeString, char **modeName, int *mask);
+static char *find_modeline(char *modeString, char *pModeLines,
+ int ModeLineLen);
@@ -87,10 +58,11 @@ int main(int argc, char *argv[])
Display *dpy;
Bool ret;
int screen, display_devices, mask, major, minor, len, j;
- char *str, *start;
+ char *str, *start, *str0, *str1;
char *displayDeviceNames[8];
int nDisplayDevice;
+
/*
* Open a display connection, and make sure the NV-CONTROL X
* extension is present on the screen we want to use.
@@ -98,7 +70,7 @@ int main(int argc, char *argv[])
dpy = XOpenDisplay(NULL);
if (!dpy) {
- fprintf(stderr, "Cannot open display '%s'.\n", XDisplayName(NULL));
+ fprintf(stderr, "Cannot open display '%s'.\n\n", XDisplayName(NULL));
return 1;
}
@@ -106,42 +78,44 @@ int main(int argc, char *argv[])
if (!XNVCTRLIsNvScreen(dpy, screen)) {
fprintf(stderr, "The NV-CONTROL X not available on screen "
- "%d of '%s'.\n", screen, XDisplayName(NULL));
+ "%d of '%s'.\n\n", screen, XDisplayName(NULL));
return 1;
}
ret = XNVCTRLQueryVersion(dpy, &major, &minor);
if (ret != True) {
- fprintf(stderr, "The NV-CONTROL X extension does not exist on '%s'.\n",
- XDisplayName(NULL));
+ fprintf(stderr, "The NV-CONTROL X extension does not exist "
+ "on '%s'.\n\n", XDisplayName(NULL));
return 1;
}
+
+ printf("\nUsing NV-CONTROL extension %d.%d on %s\n",
+ major, minor, XDisplayName(NULL));
+
+ /*
+ * query the connected display devices on this X screen and print
+ * basic information about each X screen
+ */
+
ret = XNVCTRLQueryAttribute(dpy, screen, 0,
- NV_CTRL_ENABLED_DISPLAYS, &display_devices);
+ NV_CTRL_CONNECTED_DISPLAYS, &display_devices);
if (!ret) {
- fprintf(stderr, "Failed to query the enabled Display Devices.\n");
+ fprintf(stderr, "Failed to query the enabled Display Devices.\n\n");
return 1;
}
- /* print basic information about what display devices are present */
-
-
- printf("\n");
- printf("Using NV-CONTROL extension %d.%d on %s\n",
- major, minor, XDisplayName(NULL));
- printf("Display Devices:\n");
+ printf("Connected Display Devices:\n");
nDisplayDevice = 0;
for (mask = 1; mask < (1 << 24); mask <<= 1) {
-
+
if (display_devices & mask) {
- XNVCTRLQueryStringAttribute
- (dpy, screen, mask,
- NV_CTRL_STRING_DISPLAY_DEVICE_NAME,
- &str);
+ XNVCTRLQueryStringAttribute(dpy, screen, mask,
+ NV_CTRL_STRING_DISPLAY_DEVICE_NAME,
+ &str);
displayDeviceNames[nDisplayDevice++] = str;
@@ -149,50 +123,236 @@ int main(int argc, char *argv[])
display_device_name(mask), mask, str);
}
}
-
printf("\n");
- /* now, parse the commandline and perform the requested action */
+
+ /*
+ * perform the requested action, based on the specified
+ * commandline option
+ */
+
+ if (argc <= 1) goto printHelp;
- if (argc <= 1) goto printHelp;
+ /*
+ * for each connected display device on this X screen, query the
+ * list of modelines in the mode pool using
+ * NV_CTRL_BINARY_DATA_MODELINES, then print the results
+ */
- if (strcmp(argv[1], "-l") == 0) {
-
- /* get list of modelines, per display device */
+ if (strcmp(argv[1], "--print-modelines") == 0) {
nDisplayDevice = 0;
for (mask = 1; mask < (1 << 24); mask <<= 1) {
- if (display_devices & mask) {
-
- XNVCTRLQueryBinaryData(dpy, screen, mask,
- NV_CTRL_BINARY_DATA_MODELINES,
- (void *) &str, &len);
+ if (!(display_devices & mask)) continue;
+
+ ret = XNVCTRLQueryBinaryData(dpy, screen, mask,
+ NV_CTRL_BINARY_DATA_MODELINES,
+ (void *) &str, &len);
- printf("Modelines for %s:\n",
- displayDeviceNames[nDisplayDevice++]);
+ if (!ret) {
+ fprintf(stderr, "Failed to query ModeLines.\n\n");
+ return 1;
+ }
+
+ /*
+ * the returned data is in the form:
+ *
+ * "ModeLine 1\0ModeLine 2\0ModeLine 3\0Last ModeLine\0\0"
+ *
+ * so walk from one "\0" to the next to print each ModeLine.
+ */
+
+ printf("Modelines for %s:\n",
+ displayDeviceNames[nDisplayDevice++]);
- start = str;
- for (j = 0; j < len; j++) {
- if (str[j] == '\0') {
- printf(" %s\n", start);
- start = &str[j+1];
+ start = str;
+ for (j = 0; j < len; j++) {
+ if (str[j] == '\0') {
+ printf(" %s\n", start);
+ start = &str[j+1];
}
- }
+ }
+
+ XFree(str);
+ }
+ }
+
+
+ /*
+ * for each connected display device on this X screen, query the
+ * current modeline using NV_CTRL_STRING_CURRENT_MODELINE
+ */
+
+ else if (strcmp(argv[1], "--print-current-modeline") == 0) {
+
+ nDisplayDevice = 0;
+
+ for (mask = 1; mask < (1 << 24); mask <<= 1) {
+
+ if (!(display_devices & mask)) continue;
+
+ ret =
+ XNVCTRLQueryStringAttribute(dpy, screen, mask,
+ NV_CTRL_STRING_CURRENT_MODELINE,
+ &str);
- XFree(str);
+ if (!ret) {
+ fprintf(stderr, "Failed to query current ModeLine.\n\n");
+ return 1;
}
+
+ printf("Current Modeline for %s:\n",
+ displayDeviceNames[nDisplayDevice++]);
+ printf(" %s\n\n", str);
+ }
+ }
+
+
+ /*
+ * add the specified modeline to the mode pool for the specified
+ * display device, using NV_CTRL_STRING_ADD_MODELINE
+ */
+
+ else if ((strcmp(argv[1], "--add-modeline") == 0) &&
+ argv[2] && argv[3]) {
+
+ mask = strtol(argv[2], NULL, 0);
+
+ ret = XNVCTRLSetStringAttribute(dpy,
+ screen,
+ mask,
+ NV_CTRL_STRING_ADD_MODELINE,
+ argv[3]);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to add the modeline \"%s\" to %s's "
+ "mode pool.\n\n", argv[3], display_device_name(mask));
+ return 1;
+ }
+
+ printf("Added modeline \"%s\" to %s's mode pool.\n\n",
+ argv[3], display_device_name(mask));
+ }
+
+
+ /*
+ * delete the specified modeline from the mode pool for the
+ * specified display device, using NV_CTRL_STRING_DELETE_MODELINE
+ */
+
+ else if ((strcmp(argv[1], "--delete-modeline") == 0) &&
+ argv[2] && argv[3]) {
+
+ mask = strtol(argv[2], NULL, 0);
+
+ ret = XNVCTRLSetStringAttribute(dpy,
+ screen,
+ mask,
+ NV_CTRL_STRING_DELETE_MODELINE,
+ argv[3]);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to delete the mode \"%s\" from %s's "
+ "mode pool.\n\n", argv[3], display_device_name(mask));
+ return 1;
}
- } else if (strcmp(argv[1], "-m") == 0) {
+ printf("Deleted modeline \"%s\" from %s's mode pool.\n\n",
+ argv[3], display_device_name(mask));
+ }
+
+
+ /*
+ * generate a GTF modeline using NV_CTRL_STRING_OPERATION_GTF_MODELINE
+ */
+
+ else if ((strcmp(argv[1], "--generate-gtf-modeline") == 0) &&
+ argv[2] && argv[3] && argv[4]) {
+
+ char pGtfString[128];
+ char *pOut;
+
+ snprintf(pGtfString, 128, "width=%s, height=%s, refreshrate=%s",
+ argv[2], argv[3], argv[4]);
+
+ ret = XNVCTRLStringOperation(dpy,
+ NV_CTRL_TARGET_TYPE_X_SCREEN,
+ screen,
+ 0,
+ NV_CTRL_STRING_OPERATION_GTF_MODELINE,
+ pGtfString,
+ &pOut);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to generate GTF ModeLine from "
+ "\"%s\".\n\n", pGtfString);
+ return 1;
+ }
+
+ printf("GTF ModeLine from \"%s\": %s\n\n", pGtfString, pOut);
+ }
+
+
+ /*
+ * generate a CVT modeline using NV_CTRL_STRING_OPERATION_CVT_MODELINE
+ */
+
+ else if ((strcmp(argv[1], "--generate-cvt-modeline") == 0) &&
+ argv[2] && argv[3] && argv[4] && argv[5]) {
+
+ char pCvtString[128];
+ char *pOut;
+
+ snprintf(pCvtString, 128, "width=%s, height=%s, refreshrate=%s, "
+ "reduced-blanking=%s",
+ argv[2], argv[3], argv[4], argv[5]);
+
+ ret = XNVCTRLStringOperation(dpy,
+ NV_CTRL_TARGET_TYPE_X_SCREEN,
+ screen,
+ 0,
+ NV_CTRL_STRING_OPERATION_CVT_MODELINE,
+ pCvtString,
+ &pOut);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to generate CVT ModeLine from "
+ "\"%s\".\n\n", pCvtString);
+ return 1;
+ }
+
+ printf("CVT ModeLine from \"%s\": %s\n\n", pCvtString, pOut);
+ }
+
+
+ /*
+ * query the MetaModes for the X screen, using
+ * NV_CTRL_BINARY_DATA_METAMODES.
+ */
+
+ else if (strcmp(argv[1], "--print-metamodes") == 0) {
/* get list of metamodes */
- XNVCTRLQueryBinaryData(dpy, screen, 0, // n/a
- NV_CTRL_BINARY_DATA_METAMODES,
- (void *) &str, &len);
+ ret = XNVCTRLQueryBinaryData(dpy, screen, 0, // n/a
+ NV_CTRL_BINARY_DATA_METAMODES,
+ (void *) &str, &len);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to query MetaModes.\n\n");
+ return 1;
+ }
+
+ /*
+ * the returned data is in the form:
+ *
+ * "MetaMode 1\0MetaMode 2\0MetaMode 3\0Last MetaMode\0\0"
+ *
+ * so walk from one "\0" to the next to print each MetaMode.
+ */
printf("MetaModes:\n");
@@ -205,24 +365,97 @@ int main(int argc, char *argv[])
}
XFree(str);
-
- } else if ((strcmp(argv[1], "-M") == 0) && (argv[2])) {
+ }
+
+
+ /*
+ * query the currently in use MetaMode. Note that an alternative
+ * way to accomplish this is to use XRandR to query the current
+ * mode's refresh rate, and then match the refresh rate to the id
+ * reported in the returned NV_CTRL_BINARY_DATA_METAMODES data.
+ */
+
+ else if (strcmp(argv[1], "--print-current-metamode") == 0) {
- ret = XNVCTRLSetStringAttribute(dpy,
- screen,
- 0,
- NV_CTRL_STRING_ADD_METAMODE,
- argv[2]);
+ ret = XNVCTRLQueryStringAttribute(dpy, screen, mask,
+ NV_CTRL_STRING_CURRENT_METAMODE,
+ &str);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to query the current MetaMode.\n\n");
+ return 1;
+ }
+
+ printf("current metamode: \"%s\"\n\n", str);
+ }
+
+
+ /*
+ * add the given MetaMode to X screen's list of MetaModes, using
+ * NV_CTRL_STRING_OPERATION_ADD_METAMODE; example MetaMode string:
+ *
+ * "nvidia-auto-select, nvidia-auto-select"
+ *
+ * The output string will contain "id=#" which indicates the
+ * unique identifier for this MetaMode. You can then use XRandR
+ * to switch to this mode by matching the identifier with the
+ * refresh rate reported via XRandR.
+ *
+ * For example:
+ *
+ * $ ./nv-control-dpy --add-metamode \
+ * "nvidia-auto-select, nvidia-auto-select"
+ *
+ * Using NV-CONTROL extension 1.12 on :0
+ * Connected Display Devices:
+ * CRT-0 (0x00000001): EIZO F931
+ * CRT-1 (0x00000002): ViewSonic P815-4
+ *
+ * Added MetaMode "nvidia-auto-select, nvidia-auto-select";
+ * pOut: "id=52"
+ *
+ * $ xrandr -q
+ * SZ: Pixels Physical Refresh
+ * 0 3200 x 1200 ( 821mm x 302mm ) 51 52
+ * *1 1600 x 600 ( 821mm x 302mm ) *50
+ * Current rotation - normal
+ * Current reflection - none
+ * Rotations possible - normal
+ * Reflections possible - none
+ *
+ * $ xrandr -s 0 -r 52
+ */
+
+ else if ((strcmp(argv[1], "--add-metamode") == 0) && (argv[2])) {
+
+ char *pOut;
+
+ ret = XNVCTRLStringOperation(dpy,
+ NV_CTRL_TARGET_TYPE_X_SCREEN,
+ screen,
+ 0,
+ NV_CTRL_STRING_OPERATION_ADD_METAMODE,
+ argv[2],
+ &pOut);
if (!ret) {
- fprintf(stderr, "Failed to add the MetaMode.\n");
+ fprintf(stderr, "Failed to add the MetaMode \"%s\".\n\n",
+ argv[2]);
return 1;
}
- printf("Uploaded MetaMode \"%s\"; magicID: %d\n",
- argv[2], ret);
+ printf("Added MetaMode \"%s\"; pOut: \"%s\"\n\n", argv[2], pOut);
+
+ XFree(pOut);
+ }
+
+
+ /*
+ * delete the given MetaMode from the X screen's list of
+ * MetaModes, using NV_CTRL_STRING_DELETE_METAMODE
+ */
- } else if ((strcmp(argv[1], "-D") == 0) && (argv[1])) {
+ else if ((strcmp(argv[1], "--delete-metamode") == 0) && (argv[1])) {
ret = XNVCTRLSetStringAttribute(dpy,
screen,
@@ -231,51 +464,152 @@ int main(int argc, char *argv[])
argv[2]);
if (!ret) {
- fprintf(stderr, "Failed to delete the MetaMode.\n");
+ fprintf(stderr, "Failed to delete the MetaMode.\n\n");
return 1;
}
- } else if (strcmp(argv[1], "-c") == 0) {
+ printf("Deleted MetaMode \"%s\".\n\n", argv[2]);
+ }
+
+
+ /*
+ * query the valid frequency ranges for each display device, using
+ * NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES and
+ * NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES
+ */
+
+ else if (strcmp(argv[1], "--get-valid-freq-ranges") == 0) {
- ret = XNVCTRLQueryStringAttribute
- (dpy, screen, mask,
- NV_CTRL_STRING_CURRENT_METAMODE,
- &str);
+ nDisplayDevice = 0;
- if (!ret) {
- fprintf(stderr, "Failed to query the current MetaMode.\n");
- return 1;
+ for (mask = 1; mask < (1 << 24); mask <<= 1) {
+
+ if (!(display_devices & mask)) continue;
+
+ ret = XNVCTRLQueryStringAttribute
+ (dpy, screen, mask,
+ NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES,
+ &str0);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to query HorizSync for %s.\n\n",
+ display_device_name(mask));
+ return 1;
+ }
+
+
+ ret = XNVCTRLQueryStringAttribute
+ (dpy, screen, mask,
+ NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES,
+ &str1);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to query VertRefresh for %s.\n\n",
+ display_device_name(mask));
+ return 1;
+ }
+
+ printf("frequency information for %s:\n",
+ displayDeviceNames[nDisplayDevice++]);
+ printf(" HorizSync : \"%s\"\n", str0);
+ printf(" VertRefresh : \"%s\"\n\n", str1);
+
+ XFree(str0);
+ XFree(str1);
}
+ }
+
+
+ /*
+ * attempt to build the modepool for each display device; this
+ * will fail for any display device that already has a modepool
+ */
+
+ else if (strcmp(argv[1], "--build-modepool") == 0) {
- printf("current metamode: \"%s\"\n", str);
+ for (mask = 1; mask < (1 << 24); mask <<= 1) {
+
+ if (!(display_devices & mask)) continue;
+
+ ret = XNVCTRLStringOperation
+ (dpy,
+ NV_CTRL_TARGET_TYPE_X_SCREEN,
+ screen,
+ mask,
+ NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL,
+ argv[2],
+ &str0);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to build modepool for %s (it most "
+ "likely already has a modepool).\n\n",
+ display_device_name(mask));
+ } else {
+ printf("Built modepool for %s.\n\n",
+ display_device_name(mask));
+ }
+ }
+ }
- } else if ((strcmp(argv[1], "-L") == 0) && argv[2] && argv[3]) {
+
+ /*
+ * query the associated display devices on this X screen; these
+ * are the display devices that are available to the X screen for
+ * use by MetaModes.
+ */
+
+ else if (strcmp(argv[1], "--get-associated-dpys") == 0) {
- ret = XNVCTRLSetStringAttribute(dpy,
- screen,
- strtol(argv[2], NULL, 0),
- NV_CTRL_STRING_ADD_MODELINE,
- argv[3]);
+ ret = XNVCTRLQueryAttribute(dpy,
+ screen,
+ 0,
+ NV_CTRL_ASSOCIATED_DISPLAY_DEVICES,
+ &mask);
- if (!ret) {
- fprintf(stderr, "Failed to add the modeline \"%s\".\n", argv[3]);
+ if (ret) {
+ printf("associated display device mask: 0x%08x\n\n", mask);
+ } else {
+ fprintf(stderr, "failed to query the associated display device "
+ "mask.\n\n");
return 1;
}
-
- } else if ((strcmp(argv[1], "-d") == 0) && argv[2] && argv[3]) {
- ret = XNVCTRLSetStringAttribute(dpy,
- screen,
- strtol(argv[2], NULL, 0),
- NV_CTRL_STRING_DELETE_MODELINE,
- argv[3]);
+ }
+
+
+ /*
+ * assign the associated display device mask for this X screen;
+ * these are the display devices that are available to the X
+ * screen for use by MetaModes.
+ */
+
+ else if ((strcmp(argv[1], "--set-associated-dpys") == 0) && (argv[2])) {
+
+ mask = strtol(argv[2], NULL, 0);
+
+ ret = XNVCTRLSetAttributeAndGetStatus
+ (dpy,
+ screen,
+ 0,
+ NV_CTRL_ASSOCIATED_DISPLAY_DEVICES,
+ mask);
- if (!ret) {
- fprintf(stderr, "Failed to delete the mode \"%s\".\n", argv[3]);
+ if (ret) {
+ printf("set the associated display device mask to 0x%08x\n\n",
+ mask);
+ } else {
+ fprintf(stderr, "failed to set the associated display device "
+ "mask to 0x%08x\n\n", mask);
return 1;
}
-
- } else if (strcmp(argv[1], "-g") == 0) {
+ }
+
+
+ /*
+ * query information about the GPUs in the system
+ */
+
+ else if (strcmp(argv[1], "--query-gpus") == 0) {
int num_gpus, num_screens, i;
unsigned int *pData;
@@ -283,17 +617,20 @@ int main(int argc, char *argv[])
printf("GPU Information:\n");
/* Get the number of gpus in the system */
- ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_GPU, &num_gpus);
+
+ ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_GPU,
+ &num_gpus);
if (!ret) {
- fprintf(stderr, "Failed to query number of gpus\n");
+ fprintf(stderr, "Failed to query number of gpus.\n\n");
return 1;
}
- printf("\n");
printf(" number of GPUs: %d\n", num_gpus);
/* List the X screen number of all X screens driven by each gpu */
+
for (i = 0; i < num_gpus; i++) {
+
ret = XNVCTRLQueryTargetBinaryData
(dpy,
NV_CTRL_TARGET_TYPE_GPU,
@@ -302,16 +639,17 @@ int main(int argc, char *argv[])
NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU,
(unsigned char **) &pData,
&len);
+
if (!ret) {
fprintf(stderr, "Failed to query list of X Screens\n");
return 1;
}
printf(" number of X screens using GPU %d: %d\n", i, pData[0]);
-
+
/* List X Screen number of all X Screens driven by this GPU. */
-
- printf(" X screens using GPU %d: ", i);
+
+ printf(" Indices of X screens using GPU %d: ", i);
for (j = 1; j <= pData[0]; j++) {
printf(" %d", pData[j]);
@@ -326,19 +664,22 @@ int main(int argc, char *argv[])
* where as querying the screen count information from
* NV-CONTROL will return the number of underlying X Screens.
*/
+
ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN,
&num_screens);
if (!ret) {
- fprintf(stderr, "Failed to query number of X Screens\n");
+ fprintf(stderr, "Failed to query number of X Screens\n\n");
return 1;
}
printf("\n");
- printf(" number of X screens (ScreenCount): %d\n", ScreenCount(dpy));
- printf("\n");
- printf(" number of X screens (NV-CONTROL): %d\n", num_screens);
+ printf(" number of X screens (ScreenCount): %d\n",
+ ScreenCount(dpy));
+ printf(" number of X screens (NV-CONTROL): %d\n\n",
+ num_screens);
for (i = 0; i < num_screens; i++) {
+
ret = XNVCTRLQueryTargetBinaryData
(dpy,
NV_CTRL_TARGET_TYPE_X_SCREEN,
@@ -347,16 +688,18 @@ int main(int argc, char *argv[])
NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN,
(unsigned char **) &pData,
&len);
+
if (!ret) {
- fprintf(stderr, "Failed to query list of gpus\n");
+ fprintf(stderr, "Failed to query list of gpus\n\n");
return 1;
}
- printf(" number of GPUs used by X screen %d: %d\n", i, pData[0]);
+ printf(" number of GPUs used by X screen %d: %d\n", i,
+ pData[0]);
/* List gpu number of all gpus driven by this X screen */
- printf(" GPUs used by X screen %d: ", i);
+ printf(" Indices of GPUs used by X screen %d: ", i);
for (j = 1; j <= pData[0]; j++) {
printf(" %d", pData[j]);
}
@@ -364,26 +707,771 @@ int main(int argc, char *argv[])
}
printf("\n");
-
- } else {
+
+ }
+
+
+ /*
+ * probe for any newly connected display devices
+ */
+
+ else if (strcmp(argv[1], "--probe-dpys") == 0) {
+
+ int num_gpus, i;
+
+ printf("Display Device Probed Information:\n\n");
+
+ /* Get the number of gpus in the system */
- printHelp:
+ ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_GPU,
+ &num_gpus);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to query number of gpus\n\n");
+ return 1;
+ }
+
+ printf(" number of GPUs: %d\n", num_gpus);
+
+ /* Probe and list the Display devices */
+
+ for (i = 0; i < num_gpus; i++) {
+
+ /* Get the gpu name */
+
+ ret = XNVCTRLQueryTargetStringAttribute
+ (dpy, NV_CTRL_TARGET_TYPE_GPU, i, 0,
+ NV_CTRL_STRING_PRODUCT_NAME, &str);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to query gpu name\n\n");
+ return 1;
+ }
+
+ /* Probe the GPU for new/old display devices */
+
+ ret = XNVCTRLQueryTargetAttribute(dpy,
+ NV_CTRL_TARGET_TYPE_GPU, i,
+ 0,
+ NV_CTRL_PROBE_DISPLAYS,
+ &display_devices);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to probe the enabled Display "
+ "Devices on GPU-%d (%s).\n\n", i, str);
+ return 1;
+ }
+
+ printf(" display devices on GPU-%d (%s):\n", i, str);
+ XFree(str);
+
+ /* Report results */
+
+ for (mask = 1; mask < (1 << 24); mask <<= 1) {
+
+ if (display_devices & mask) {
+
+ XNVCTRLQueryTargetStringAttribute
+ (dpy, NV_CTRL_TARGET_TYPE_GPU, i, mask,
+ NV_CTRL_STRING_DISPLAY_DEVICE_NAME,
+ &str);
+
+ printf(" %s (0x%08x): %s\n",
+ display_device_name(mask), mask, str);
+ }
+ }
+
+ printf("\n");
+ }
- printf("usage:\n");
- printf("-l: print the modelines in the ModePool "
- "for each Display Device.\n");
- printf("-L [dpy mask] [modeline]: add new modeline.\n");
- printf("-d [dpy mask] [modename]: delete modeline with modename\n");
- printf("-m: print the current MetaModes\n");
- printf("-M [metamode]: add the specified MetaMode to the "
- "server's list of MetaModes.\n");
- printf("-D [metamode]: delete the specified MEtaMode from the "
- "server's list of MetaModes.\n");
- printf("-c: print the current MetaMode\n");
- printf("-g: print GPU information\n");
printf("\n");
}
+
+
+ /*
+ * query the TwinViewXineramaInfoOrder
+ */
+
+ else if (strcmp(argv[1], "--query-twinview-xinerama-info-order") == 0) {
+
+ ret = XNVCTRLQueryTargetStringAttribute
+ (dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, screen, 0,
+ NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER, &str);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to query "
+ "TwinViewXineramaInfoOrder.\n\n");
+ return 1;
+ }
+
+ printf("TwinViewXineramaInfoOrder: %s\n\n", str);
+ }
+
+
+ /*
+ * assign the TwinViewXineramaInfoOrder
+ */
+
+ else if ((strcmp(argv[1], "--assign-twinview-xinerama-info-order")== 0)
+ && argv[2]) {
+
+ ret = XNVCTRLSetStringAttribute
+ (dpy,
+ screen,
+ 0,
+ NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER,
+ argv[2]);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to assign "
+ "TwinViewXineramaInfoOrder = \"%s\".\n\n", argv[2]);
+ return 1;
+ }
+
+ printf("assigned TwinViewXineramaInfoOrder: \"%s\"\n\n",
+ argv[2]);
+ }
+
+
+ /*
+ * use NV_CTRL_MAX_SCREEN_WIDTH and NV_CTRL_MAX_SCREEN_HEIGHT to
+ * query the maximum screen dimensions on each GPU in the system
+ */
+
+ else if (strcmp(argv[1], "--max-screen-size") == 0) {
+
+ int num_gpus, i, width, height;
+
+ /* Get the number of gpus in the system */
+
+ ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_GPU,
+ &num_gpus);
+ if (!ret) {
+ fprintf(stderr, "Failed to query number of gpus.\n\n");
+ return 1;
+ }
+
+ for (i = 0; i < num_gpus; i++) {
+
+ ret = XNVCTRLQueryTargetAttribute(dpy,
+ NV_CTRL_TARGET_TYPE_GPU,
+ i,
+ 0,
+ NV_CTRL_MAX_SCREEN_WIDTH,
+ &width);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to query the maximum screen "
+ "width on GPU-%d\n\n", i);
+ return 1;
+ }
+
+ ret = XNVCTRLQueryTargetAttribute(dpy,
+ NV_CTRL_TARGET_TYPE_GPU,
+ i,
+ 0,
+ NV_CTRL_MAX_SCREEN_HEIGHT,
+ &height);
+
+ if (!ret) {
+ fprintf(stderr, "Failed to query the maximum screen "
+ "height on GPU-%d.\n\n", i);
+ return 1;
+ }
+
+ printf("GPU-%d: maximum X screen size: %d x %d.\n\n",
+ i, width, height);
+ }
+ }
+
+
+ /*
+ * demonstrate how to use NV-CONTROL to query what modelines are
+ * used by the MetaModes of the X screen: we first query all the
+ * MetaModes, parse out the display device names and mode names,
+ * and then lookup the modelines associated with those mode names
+ * on those display devices
+ *
+ * this could be implemented much more efficiently, but
+ * demonstrates the general idea
+ */
+
+ else if (strcmp(argv[1], "--print-used-modelines") == 0) {
+
+ char *pMetaModes, *pModeLines[8], *tmp, *modeString;
+ char *modeLine, *modeName, *noWhiteSpace;
+ int MetaModeLen, ModeLineLen[8];
+ unsigned int thisMask;
+
+ /* first, we query the MetaModes on this X screen */
+
+ XNVCTRLQueryBinaryData(dpy, screen, 0, // n/a
+ NV_CTRL_BINARY_DATA_METAMODES,
+ (void *) &pMetaModes, &MetaModeLen);
+
+ /*
+ * then, we query the ModeLines for each display device on
+ * this X screen; we'll need these later
+ */
+
+ nDisplayDevice = 0;
+
+ for (mask = 1; mask < (1 << 24); mask <<= 1) {
+
+ if (!(display_devices & mask)) continue;
+
+ XNVCTRLQueryBinaryData(dpy, screen, mask,
+ NV_CTRL_BINARY_DATA_MODELINES,
+ (void *) &str, &len);
+
+ pModeLines[nDisplayDevice] = str;
+ ModeLineLen[nDisplayDevice] = len;
+
+ nDisplayDevice++;
+ }
+
+ /* now, parse each MetaMode */
+
+ str = start = pMetaModes;
+
+ for (j = 0; j < MetaModeLen; j++) {
+
+ /*
+ * if we found the end of a line, treat the string from
+ * start to str[j] as a MetaMode
+ */
+
+ if ((str[j] == '\0') && (str[j+1] != '\0')) {
+
+ printf("MetaMode: %s\n", start);
+
+ /*
+ * remove any white space from the string to make
+ * parsing easier
+ */
+
+ noWhiteSpace = remove_whitespace(start);
+
+ /*
+ * the MetaMode may be preceded with "token=value"
+ * pairs, separated by the main MetaMode with "::"; if
+ * "::" exists in the string, skip past it
+ */
+
+ tmp = strstr(noWhiteSpace, "::");
+ if (tmp) {
+ tmp += 2;
+ } else {
+ tmp = noWhiteSpace;
+ }
+
+ /* split the MetaMode string by comma */
+
+ for (modeString = strtok(tmp, ",");
+ modeString;
+ modeString = strtok(NULL, ",")) {
+
+ /*
+ * retrieve the modeName and display device mask
+ * for this segment of the Metamode
+ */
+
+ parse_mode_string(modeString, &modeName, &thisMask);
+
+ /* lookup the modeline that matches */
+
+ nDisplayDevice = 0;
+
+ if (thisMask) {
+ for (mask = 1; mask < (1 << 24); mask <<= 1) {
+ if (!(display_devices & mask)) continue;
+ if (thisMask & mask) break;
+ nDisplayDevice++;
+ }
+ }
+
+
+ modeLine = find_modeline(modeName,
+ pModeLines[nDisplayDevice],
+ ModeLineLen[nDisplayDevice]);
+
+ printf(" %s: %s\n",
+ display_device_name(thisMask), modeLine);
+ }
+
+ printf("\n");
+
+ free(noWhiteSpace);
+
+ /* move to the next MetaMode */
+
+ start = &str[j+1];
+ }
+ }
+ }
+
+
+ /*
+ * demonstrate how to programmatically transition into TwinView
+ * using NV-CONTROL and XRandR; the process is roughly:
+ *
+ * - probe for new display devices
+ *
+ * - if we found any new display devices, create a mode pool for
+ * the new display devices
+ *
+ * - associate any new display devices to the X screen, so that
+ * they are available for MetaMode assignment.
+ *
+ * - add a new MetaMode
+ *
+ * We have skipped error checking, and checking for things like if
+ * we are already using multiple display devices, but this gives
+ * the general idea.
+ */
+
+ else if (strcmp(argv[1], "--dynamic-twinview") == 0) {
+
+ char *pOut;
+ int id;
+
+ /*
+ * first, probe for new display devices; while
+ * NV_CTRL_CONNECTED_DISPLAYS reports what the NVIDIA X driver
+ * believes is currently connected to the GPU,
+ * NV_CTRL_PROBE_DISPLAYS forces the driver to redetect what
+ * is connected.
+ */
+
+ XNVCTRLQueryAttribute(dpy,
+ screen,
+ 0,
+ NV_CTRL_PROBE_DISPLAYS,
+ &display_devices);
+
+ /*
+ * if we don't have atleast two display devices, there is
+ * nothing to do
+ */
+
+ printf("probed display device mask: 0x%08x\n\n", display_devices);
+
+ if (count_bits(display_devices) < 2) {
+ printf("only one display device found; cannot enable "
+ "TwinView.\n\n");
+ return 1;
+ }
+
+
+ /*
+ * next, make sure all display devices have a modepool; a more
+ * sophisticated client could use
+ * NV_CTRL_BINARY_DATA_MODELINES to query if a pool of
+ * modelines already exist on each display device we care
+ * about.
+ */
+
+ for (mask = 1; mask < (1 << 24); mask <<= 1) {
+
+ if (!(display_devices & mask)) continue;
+
+ XNVCTRLStringOperation(dpy,
+ NV_CTRL_TARGET_TYPE_X_SCREEN,
+ screen,
+ mask,
+ NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL,
+ NULL,
+ NULL);
+ }
+
+ printf("all display devices should now have a mode pool.\n\n");
+
+
+ /*
+ * associate all the probed display devices to the X screen;
+ * this makes the display devices available for MetaMode
+ * assignment
+ */
+
+ ret =
+ XNVCTRLSetAttributeAndGetStatus(dpy,
+ screen,
+ 0,
+ NV_CTRL_ASSOCIATED_DISPLAY_DEVICES,
+ display_devices);
+
+ if (!ret) {
+ printf("unable to assign the associated display devices to "
+ "0x%08x.\n\n", display_devices);
+ return 1;
+ }
+
+ printf("associated display devices 0x%08x.\n\n", display_devices);
+
+
+ /*
+ * next, we add a new MetaMode; a more sophisticated client
+ * would actually select a modeline from
+ * NV_CTRL_BINARY_DATA_MODELINES on each display device, but
+ * for demonstration purposes, we assume that
+ * "nvidia-auto-select" is a valid mode on each display
+ * device.
+ */
+
+ pOut = NULL;
+
+ ret = XNVCTRLStringOperation(dpy,
+ NV_CTRL_TARGET_TYPE_X_SCREEN,
+ screen,
+ 0,
+ NV_CTRL_STRING_OPERATION_ADD_METAMODE,
+ "nvidia-auto-select, nvidia-auto-select",
+ &pOut);
+
+ if (!ret || !pOut) {
+ printf("failed to add MetaMode; this may be because the MetaMode "
+ "already exists for this X screen.\n\n");
+ return 1;
+ }
+
+ /*
+ * retrieve the id of the added MetaMode from the return
+ * string; a more sophisticated client should do actual
+ * parsing of the returned string, which is defined to be a
+ * comma-separated list of "token=value" pairs as output.
+ * Currently, the only output token is "id", which indicates
+ * the id that was assigned to the MetaMode.
+ */
+
+ sscanf(pOut, "id=%d", &id);
+
+ XFree(pOut);
+
+
+ /*
+ * we have added a new MetaMode for this X screen, and we know
+ * it's id. The last step is to use the XRandR extension to
+ * switch to this mode; see the Xrandr(3) manpage for details.
+ *
+ * For demonstration purposes, just use the xrandr commandline
+ * utility to switch to the mode with the refreshrate that
+ * matches the id.
+ */
+
+ printf("The id of the new MetaMode is %d; use xrandr to "
+ "switch to it.\n\n", id);
+ }
+
+
+ /*
+ * print help information
+ */
+
+ else {
+
+ printHelp:
+
+ printf("\nnv-control-dpy [options]:\n\n");
+
+
+ printf(" ModeLine options:\n\n");
+
+ printf(" --print-modelines: print the modelines in the mode pool "
+ "for each Display Device.\n\n");
+
+ printf(" --print-current-modeline: print the current modeline "
+ "for each Display Device.\n\n");
+
+ printf(" --add-modeline [dpy mask] [modeline]: "
+ "add new modeline.\n\n");
+
+ printf(" --delete-modeline [dpy mask] [modename]: "
+ "delete modeline with modename.\n\n");
+
+ printf(" --generate-gtf-modeline [width] [height] [refreshrate]:"
+ " use the GTF formula"
+ " to generate a modeline for the specified parameters.\n\n");
+
+ printf(" --generate-cvt-modeline [width] [height] [refreshrate]"
+ " [reduced-blanking]: use the CVT formula"
+ " to generate a modeline for the specified parameters.\n\n");
+
+
+ printf(" MetaMode options:\n\n");
+
+ printf(" --print-metamodes: print the current MetaModes for the "
+ "X screen\n\n");
+
+ printf(" --add-metamode [metamode]: add the specified "
+ "MetaMode to the X screen's list of MetaModes.\n\n");
+
+ printf(" --delete-metamode [metamode]: delete the specified MetaMode "
+ "from the X screen's list of MetaModes.\n\n");
+
+ printf(" --print-current-metamode: print the current MetaMode.\n\n");
+
+
+ printf(" Misc options:\n\n");
+
+ printf(" --get-valid-freq-ranges: query the valid frequency "
+ "information for each display device.\n\n");
+
+ printf(" --build-modepool: build a modepool for any display device "
+ "that does not already have one.\n\n");
+
+ printf(" --get-associated-dpys: query the associated display device "
+ "mask for this X screen\n\n");
+
+ printf(" --set-associated-dpys [mask]: set the associated display "
+ "device mask for this X screen\n\n");
+
+ printf(" --query-gpus: print GPU information and relationship to "
+ "X screens.\n\n");
+
+ printf(" --probe-dpys: probe GPUs for new display devices\n\n");
+
+ printf(" --query-twinview-xinerama-info-order: query the "
+ "TwinViewXineramaInfoOrder.\n\n");
+
+ printf(" --assign-twinview-xinerama-info-order [order]: assign the "
+ "TwinViewXineramaInfoOrder.\n\n");
+
+ printf(" --max-screen-size: query the maximum screen size "
+ "on all GPUs in the system\n\n");
+
+ printf(" --print-used-modelines: print the modeline for each display "
+ "device for each MetaMode on the X screen.\n\n");
+
+ printf(" --dynamic-twinview: demonstrates the process of "
+ "dynamically transitioning into TwinView.\n\n");
+ }
return 0;
}
+
+
+
+/*****************************************************************************/
+/* utility functions */
+/*****************************************************************************/
+
+
+/*
+ * display_device_name() - return the display device name correspoding
+ * to the specified display device mask.
+ */
+
+static char *display_device_name(int mask)
+{
+ switch (mask) {
+ case (1 << 0): return "CRT-0"; break;
+ case (1 << 1): return "CRT-1"; break;
+ case (1 << 2): return "CRT-2"; break;
+ case (1 << 3): return "CRT-3"; break;
+ case (1 << 4): return "CRT-4"; break;
+ case (1 << 5): return "CRT-5"; break;
+ case (1 << 6): return "CRT-6"; break;
+ case (1 << 7): return "CRT-7"; break;
+
+ case (1 << 8): return "TV-0"; break;
+ case (1 << 9): return "TV-1"; break;
+ case (1 << 10): return "TV-2"; break;
+ case (1 << 11): return "TV-3"; break;
+ case (1 << 12): return "TV-4"; break;
+ case (1 << 13): return "TV-5"; break;
+ case (1 << 14): return "TV-6"; break;
+ case (1 << 15): return "TV-7"; break;
+
+ case (1 << 16): return "DFP-0"; break;
+ case (1 << 17): return "DFP-1"; break;
+ case (1 << 18): return "DFP-2"; break;
+ case (1 << 19): return "DFP-3"; break;
+ case (1 << 20): return "DFP-4"; break;
+ case (1 << 21): return "DFP-5"; break;
+ case (1 << 22): return "DFP-6"; break;
+ case (1 << 23): return "DFP-7"; break;
+ default: return "Unknown";
+ }
+
+} /* display_device_name() */
+
+
+
+/*
+ * display_device_mask() - given a display device name, translate to
+ * the display device mask
+ */
+
+static unsigned int display_device_mask(char *str)
+{
+ if (strcmp(str, "CRT-0") == 0) return (1 << 0);
+ if (strcmp(str, "CRT-1") == 0) return (1 << 1);
+ if (strcmp(str, "CRT-2") == 0) return (1 << 2);
+ if (strcmp(str, "CRT-3") == 0) return (1 << 3);
+ if (strcmp(str, "CRT-4") == 0) return (1 << 4);
+ if (strcmp(str, "CRT-5") == 0) return (1 << 5);
+ if (strcmp(str, "CRT-6") == 0) return (1 << 6);
+ if (strcmp(str, "CRT-7") == 0) return (1 << 7);
+
+ if (strcmp(str, "TV-0") == 0) return (1 << 8);
+ if (strcmp(str, "TV-1") == 0) return (1 << 9);
+ if (strcmp(str, "TV-2") == 0) return (1 << 10);
+ if (strcmp(str, "TV-3") == 0) return (1 << 11);
+ if (strcmp(str, "TV-4") == 0) return (1 << 12);
+ if (strcmp(str, "TV-5") == 0) return (1 << 13);
+ if (strcmp(str, "TV-6") == 0) return (1 << 14);
+ if (strcmp(str, "TV-7") == 0) return (1 << 15);
+
+ if (strcmp(str, "DFP-0") == 0) return (1 << 16);
+ if (strcmp(str, "DFP-1") == 0) return (1 << 17);
+ if (strcmp(str, "DFP-2") == 0) return (1 << 18);
+ if (strcmp(str, "DFP-3") == 0) return (1 << 19);
+ if (strcmp(str, "DFP-4") == 0) return (1 << 20);
+ if (strcmp(str, "DFP-5") == 0) return (1 << 21);
+ if (strcmp(str, "DFP-6") == 0) return (1 << 22);
+ if (strcmp(str, "DFP-7") == 0) return (1 << 23);
+
+ return 0;
+
+} /* display_device_mask() */
+
+
+
+/*
+ * remove_whitespace() - return an allocated copy of the given string,
+ * with any whitespace removed
+ */
+
+static char *remove_whitespace(char *str)
+{
+ int len;
+ char *ret, *s, *d;
+
+ len = strlen(str);
+
+ ret = malloc(len+1);
+
+ for (s = str, d = ret; *s; s++) {
+ if (!isspace(*s)) {
+ *d = *s;
+ d++;
+ }
+ }
+
+ *d = '\0';
+
+ return ret;
+
+} /* remove_whitespace() */
+
+
+
+/*
+ * count the number of bits set in the specified mask
+ */
+
+static int count_bits(unsigned int mask)
+{
+ int n = 0;
+
+ while (mask) {
+ n++;
+ mask &= (mask - 1) ;
+ }
+
+ return n;
+
+} /* count_bits() */
+
+
+
+/*
+ * parse_mode_string() - extract the modeName and the display device
+ * mask for the per-display device MetaMode string in 'modeString'
+ */
+
+static void parse_mode_string(char *modeString, char **modeName, int *mask)
+{
+ char *colon, *s, tmp;
+
+ colon = strchr(modeString, ':');
+
+ if (colon) {
+
+ *colon = '\0';
+ *mask = display_device_mask(modeString);
+ *colon = ':';
+
+ modeString = colon + 1;
+ } else {
+ *mask = 0;
+ }
+
+ /*
+ * find the modename; trim off any panning domain or
+ * offsets
+ */
+
+ for (s = modeString; *s; s++) {
+ if (*s == '@') break;
+ if ((*s == '+') && isdigit(s[1])) break;
+ if ((*s == '-') && isdigit(s[1])) break;
+ }
+
+ tmp = *s;
+ *s = '\0';
+ *modeName = strdup(modeString);
+ *s = tmp;
+
+} /* parse_mode_string() */
+
+
+
+/*
+ * find_modeline() - search the pModeLines list of ModeLines for the
+ * mode named 'modeName'; return a pointer to the matching ModeLine,
+ * or NULL if no match is found
+ */
+
+static char *find_modeline(char *modeName, char *pModeLines, int ModeLineLen)
+{
+ char *start, *beginQuote, *endQuote;
+ int j, match = 0;
+
+ start = pModeLines;
+
+ for (j = 0; j < ModeLineLen; j++) {
+ if (pModeLines[j] == '\0') {
+
+ /*
+ * the modeline will contain the modeName in quotes; find
+ * the begin and end of the quoted modeName, so that we
+ * can compare it to modeName
+ */
+
+ beginQuote = strchr(start, '"');
+ endQuote = beginQuote ? strchr(beginQuote+1, '"') : NULL;
+
+ if (beginQuote && endQuote) {
+ *endQuote = '\0';
+
+ match = (strcmp(modeName, beginQuote+1) == 0);
+
+ *endQuote = '"';
+
+ /*
+ * if we found a match, return a pointer to the start
+ * of this modeLine
+ */
+
+ if (match) return start;
+ }
+
+ start = &pModeLines[j+1];
+ }
+ }
+
+ return NULL;
+
+} /* find_modeline() */